GSOC 2013 paint
[blender-staging.git] / source / blender / nodes / intern / node_util.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Nathan Letwory.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/nodes/intern/node_util.c
29  *  \ingroup nodes
30  */
31
32 #include <limits.h>
33 #include <string.h>
34
35 #include "DNA_node_types.h"
36
37 #include "BLI_listbase.h"
38 #include "BLI_string.h"
39 #include "BLI_utildefines.h"
40
41 #include "BLF_translation.h"
42
43 #include "BKE_colortools.h"
44 #include "BKE_node.h"
45
46 #include "RNA_access.h"
47 #include "RNA_enum_types.h"
48
49 #include "MEM_guardedalloc.h"
50
51 #include "node_util.h"
52
53 /**** Storage Data ****/
54
55 void node_free_curves(bNode *node)
56 {
57         curvemapping_free(node->storage);
58 }
59
60 void node_free_standard_storage(bNode *node)
61 {
62         if (node->storage) {
63                 MEM_freeN(node->storage);
64         }
65 }
66
67 void node_copy_curves(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
68 {
69         dest_node->storage = curvemapping_copy(src_node->storage);
70 }
71
72 void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
73 {
74         dest_node->storage = MEM_dupallocN(src_node->storage);
75 }
76
77 void *node_initexec_curves(bNodeExecContext *UNUSED(context), bNode *node, bNodeInstanceKey UNUSED(key))
78 {
79         curvemapping_initialize(node->storage);
80         return NULL;  /* unused return */
81 }
82
83
84 /**** Labels ****/
85
86 void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
87 {
88         const char *name;
89         RNA_enum_name(ramp_blend_items, node->custom1, &name);
90         BLI_strncpy(label, IFACE_(name), maxlen);
91 }
92
93 void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
94 {
95         const char *name;
96         RNA_enum_name(node_math_items, node->custom1, &name);
97         BLI_strncpy(label, IFACE_(name), maxlen);
98 }
99
100 void node_vect_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
101 {
102         const char *name;
103         RNA_enum_name(node_vec_math_items, node->custom1, &name);
104         BLI_strncpy(label, IFACE_(name), maxlen);
105 }
106
107 void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
108 {
109         const char *name;
110         RNA_enum_name(node_filter_items, node->custom1, &name);
111         BLI_strncpy(label, IFACE_(name), maxlen);
112 }
113
114
115 /**** Internal Links (mute and disconnect) ****/
116
117 /* common datatype priorities, works for compositor, shader and texture nodes alike
118  * defines priority of datatype connection based on output type (to):
119  *   < 0  : never connect these types
120  *   >= 0 : priority of connection (higher values chosen first)
121  */
122 static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype to)
123 {
124         switch (to) {
125                 case SOCK_RGBA:
126                         switch (from) {
127                                 case SOCK_RGBA:     return 4;
128                                 case SOCK_FLOAT:    return 3;
129                                 case SOCK_INT:      return 2;
130                                 case SOCK_BOOLEAN:  return 1;
131                                 default: return -1;
132                         }
133                 case SOCK_VECTOR:
134                         switch (from) {
135                                 case SOCK_VECTOR:   return 4;
136                                 case SOCK_FLOAT:    return 3;
137                                 case SOCK_INT:      return 2;
138                                 case SOCK_BOOLEAN:  return 1;
139                                 default:            return -1;
140                         }
141                 case SOCK_FLOAT:
142                         switch (from) {
143                                 case SOCK_FLOAT:    return 5;
144                                 case SOCK_INT:      return 4;
145                                 case SOCK_BOOLEAN:  return 3;
146                                 case SOCK_RGBA:     return 2;
147                                 case SOCK_VECTOR:   return 1;
148                                 default:            return -1;
149                         }
150                 case SOCK_INT:
151                         switch (from) {
152                                 case SOCK_INT:      return 5;
153                                 case SOCK_FLOAT:    return 4;
154                                 case SOCK_BOOLEAN:  return 3;
155                                 case SOCK_RGBA:     return 2;
156                                 case SOCK_VECTOR:   return 1;
157                                 default:            return -1;
158                         }
159                 case SOCK_BOOLEAN:
160                         switch (from) {
161                                 case SOCK_BOOLEAN:  return 5;
162                                 case SOCK_INT:      return 4;
163                                 case SOCK_FLOAT:    return 3;
164                                 case SOCK_RGBA:     return 2;
165                                 case SOCK_VECTOR:   return 1;
166                                 default:            return -1;
167                         }
168                 case SOCK_SHADER:
169                         switch (from) {
170                                 case SOCK_SHADER:   return 1;
171                                 default:            return -1;
172                         }
173                 case SOCK_STRING:
174                         switch (from) {
175                                 case SOCK_STRING:   return 1;
176                                 default:            return -1;
177                         }
178                 default: return -1;
179         }
180 }
181
182 /* select a suitable input socket for an output */
183 static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
184 {
185         bNodeSocket *selected = NULL, *input;
186         int i;
187         int sel_priority = -1;
188         bool sel_is_linked = false;
189         
190         for (input = node->inputs.first, i = 0; input; input = input->next, ++i) {
191                 int priority = node_datatype_priority(input->type, output->type);
192                 bool is_linked = (input->link != NULL);
193                 bool preferred;
194                 
195                 if (nodeSocketIsHidden(input) ||                /* ignore hidden sockets */
196                     input->flag & SOCK_NO_INTERNAL_LINK ||      /* ignore if input is not allowed for internal connections */
197                     priority < 0 ||                             /* ignore incompatible types */
198                     priority < sel_priority)                    /* ignore if we already found a higher priority input */
199                 {
200                         continue;
201                 }
202                 
203                 /* determine if this input is preferred over the currently selected */
204                 preferred = (priority > sel_priority) ||    /* prefer higher datatype priority */
205                             (is_linked && !sel_is_linked);  /* prefer linked over unlinked */
206                 
207                 if (preferred) {
208                         selected = input;
209                         sel_is_linked = is_linked;
210                         sel_priority = priority;
211                 }
212         }
213         
214         return selected;
215 }
216
217 void node_update_internal_links_default(bNodeTree *ntree, bNode *node)
218 {
219         bNodeLink *link;
220         bNodeSocket *output, *input;
221         
222         /* sanity check */
223         if (!ntree)
224                 return;
225         
226         /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */
227         for (output = node->outputs.first; output; output = output->next)
228                 output->link = NULL;
229         
230         for (link = ntree->links.first; link; link = link->next) {
231                 if (nodeLinkIsHidden(link))
232                         continue;
233                 
234                 output = link->fromsock;
235                 if (link->fromnode != node || output->link)
236                         continue;
237                 if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK)
238                         continue;
239                 output->link = link; /* not really used, just for tagging handled sockets */
240                 
241                 /* look for suitable input */
242                 input = select_internal_link_input(node, output);
243                 
244                 if (input) {
245                         bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link");
246                         ilink->fromnode = node;
247                         ilink->fromsock = input;
248                         ilink->tonode = node;
249                         ilink->tosock = output;
250                         /* internal link is always valid */
251                         ilink->flag |= NODE_LINK_VALID;
252                         BLI_addtail(&node->internal_links, ilink);
253                 }
254         }
255         
256         /* clean up */
257         for (output = node->outputs.first; output; output = output->next)
258                 output->link = NULL;
259 }
260
261
262 /**** Default value RNA access ****/
263
264 float node_socket_get_float(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock)
265 {
266         PointerRNA ptr;
267         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
268         return RNA_float_get(&ptr, "default_value");
269 }
270
271 void node_socket_set_float(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float value)
272 {
273         PointerRNA ptr;
274         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
275         RNA_float_set(&ptr, "default_value", value);
276 }
277
278 void node_socket_get_color(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float *value)
279 {
280         PointerRNA ptr;
281         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
282         RNA_float_get_array(&ptr, "default_value", value);
283 }
284
285 void node_socket_set_color(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, const float *value)
286 {
287         PointerRNA ptr;
288         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
289         RNA_float_set_array(&ptr, "default_value", value);
290 }
291
292 void node_socket_get_vector(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float *value)
293 {
294         PointerRNA ptr;
295         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
296         RNA_float_get_array(&ptr, "default_value", value);
297 }
298
299 void node_socket_set_vector(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, const float *value)
300 {
301         PointerRNA ptr;
302         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
303         RNA_float_set_array(&ptr, "default_value", value);
304 }