Blender  V2.93
node_util.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <ctype.h>
25 #include <limits.h>
26 #include <string.h>
27 
28 #include "DNA_node_types.h"
29 
30 #include "BLI_listbase.h"
31 #include "BLI_string.h"
32 #include "BLI_utildefines.h"
33 
34 #include "BLT_translation.h"
35 
36 #include "BKE_colortools.h"
37 #include "BKE_node.h"
38 
39 #include "RNA_access.h"
40 #include "RNA_enum_types.h"
41 
42 #include "MEM_guardedalloc.h"
43 
44 #include "node_util.h"
45 
46 /* -------------------------------------------------------------------- */
51 {
52  BKE_curvemapping_free(node->storage);
53 }
54 
56 {
57  if (node->storage) {
58  MEM_freeN(node->storage);
59  }
60 }
61 
62 void node_copy_curves(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
63 {
64  dest_node->storage = BKE_curvemapping_copy(src_node->storage);
65 }
66 
68  bNode *dest_node,
69  const bNode *src_node)
70 {
71  dest_node->storage = MEM_dupallocN(src_node->storage);
72 }
73 
75  bNode *node,
77 {
78  BKE_curvemapping_init(node->storage);
79  return NULL; /* unused return */
80 }
81 
84 /* -------------------------------------------------------------------- */
88 void node_sock_label(bNodeSocket *sock, const char *name)
89 {
90  BLI_strncpy(sock->label, name, MAX_NAME);
91 }
92 
94 {
95  if (sock->label[0] != '\0') {
96  sock->label[0] = '\0';
97  }
98 }
99 
101 {
102  bNodeSocket *sock1 = BLI_findlink(&node->inputs, 0);
103  bNodeSocket *sock2 = BLI_findlink(&node->inputs, 1);
104  bNodeSocket *sock3 = BLI_findlink(&node->inputs, 2);
106  !ELEM(node->custom1,
122  !ELEM(node->custom1,
128  NODE_MATH_TANH));
130  ELEM(node->custom1,
136 
137  node_sock_label_clear(sock1);
138  node_sock_label_clear(sock2);
139  node_sock_label_clear(sock3);
140 
141  switch (node->custom1) {
142  case NODE_MATH_WRAP:
143  node_sock_label(sock2, "Max");
144  node_sock_label(sock3, "Min");
145  break;
147  node_sock_label(sock2, "Multiplier");
148  node_sock_label(sock3, "Addend");
149  break;
150  case NODE_MATH_LESS_THAN:
152  node_sock_label(sock2, "Threshold");
153  break;
154  case NODE_MATH_PINGPONG:
155  node_sock_label(sock2, "Scale");
156  break;
157  case NODE_MATH_SNAP:
158  node_sock_label(sock2, "Increment");
159  break;
160  case NODE_MATH_POWER:
161  node_sock_label(sock1, "Base");
162  node_sock_label(sock2, "Exponent");
163  break;
164  case NODE_MATH_LOGARITHM:
165  node_sock_label(sock2, "Base");
166  break;
167  case NODE_MATH_DEGREES:
168  node_sock_label(sock1, "Radians");
169  break;
170  case NODE_MATH_RADIANS:
171  node_sock_label(sock1, "Degrees");
172  break;
173  case NODE_MATH_COMPARE:
174  node_sock_label(sock3, "Epsilon");
175  break;
178  node_sock_label(sock3, "Distance");
179  break;
180  }
181 }
182 
185 /* -------------------------------------------------------------------- */
189 void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
190 {
191  const char *name;
192  bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
193  if (!enum_label) {
194  name = "Unknown";
195  }
196  BLI_strncpy(label, IFACE_(name), maxlen);
197 }
198 
199 void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
200 {
201  /* If there is no loaded image, return an empty string,
202  * and let nodeLabel() fill in the proper type translation. */
203  BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen);
204 }
205 
206 void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
207 {
208  const char *name;
209  bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
210  if (!enum_label) {
211  name = "Unknown";
212  }
213  BLI_strncpy(label, IFACE_(name), maxlen);
214 }
215 
217 {
218  const char *name;
219  bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
220  if (!enum_label) {
221  name = "Unknown";
222  }
223  BLI_strncpy(label, IFACE_(name), maxlen);
224 }
225 
226 void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
227 {
228  const char *name;
229  bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
230  if (!enum_label) {
231  name = "Unknown";
232  }
233  BLI_strncpy(label, IFACE_(name), maxlen);
234 }
235 
238 /* -------------------------------------------------------------------- */
242 static bool node_link_socket_match(const bNodeSocket *a, const bNodeSocket *b)
243 {
244  /* Check if sockets are of the same type. */
245  if (a->typeinfo != b->typeinfo) {
246  return false;
247  }
248 
249  /* Test if alphabetic prefix matches, allowing for imperfect matches, such as numeric suffixes
250  * like Color1/Color2. */
251  int prefix_len = 0;
252  const char *ca = a->name, *cb = b->name;
253  for (; *ca != '\0' && *cb != '\0'; ca++, cb++) {
254  /* End of common prefix? */
255  if (*ca != *cb) {
256  /* Prefix delimited by non-alphabetic char. */
257  if (isalpha(*ca) || isalpha(*cb)) {
258  return false;
259  }
260  break;
261  }
262  prefix_len++;
263  }
264  return prefix_len > 0;
265 }
266 
267 static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
268 {
269  int count = 0;
270  LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
271  if (ELEM(socket, link->fromsock, link->tosock)) {
272  count++;
273  }
274  }
275  return count;
276 }
277 
279  bNode *node,
280  bNodeSocket *to_socket)
281 {
282  bNodeSocket *first = to_socket->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
283 
284  /* Wrap around the list end. */
285  bNodeSocket *socket_iter = to_socket->next ? to_socket->next : first;
286  while (socket_iter != to_socket) {
287  if (!nodeSocketIsHidden(socket_iter) && node_link_socket_match(socket_iter, to_socket)) {
288  const int link_count = node_count_links(ntree, socket_iter);
289  /* Add one to account for the new link being added. */
290  if (link_count + 1 <= nodeSocketLinkLimit(socket_iter)) {
291  return socket_iter; /* Found a valid free socket we can swap to. */
292  }
293  }
294  socket_iter = socket_iter->next ? socket_iter->next : first; /* Wrap around the list end. */
295  }
296 
297  return NULL;
298 }
299 
306 {
307  bNodeSocket *socket = link->tosock;
308 
309  if (node != link->tonode) {
310  return;
311  }
312 
313  /* If we're not at the link limit of the target socket, we can skip
314  * trying to move existing links to another socket. */
315  const int to_link_limit = nodeSocketLinkLimit(socket);
316  if (socket->total_inputs + 1 < to_link_limit) {
317  return;
318  }
319 
321  if (socket == to_link->tosock) {
322  bNodeSocket *new_socket = node_find_linkable_socket(ntree, node, socket);
323  if (new_socket && new_socket != socket) {
324  /* Attempt to redirect the existing link to the new socket. */
325  to_link->tosock = new_socket;
326  return;
327  }
328 
329  if (new_socket == NULL) {
330  /* No possible replacement, remove the existing link. */
331  nodeRemLink(ntree, to_link);
332  return;
333  }
334  }
335  }
336 }
337 
340 /* -------------------------------------------------------------------- */
351 {
352  switch (to) {
353  case SOCK_RGBA:
354  switch (from) {
355  case SOCK_RGBA:
356  return 4;
357  case SOCK_FLOAT:
358  return 3;
359  case SOCK_INT:
360  return 2;
361  case SOCK_BOOLEAN:
362  return 1;
363  default:
364  return -1;
365  }
366  case SOCK_VECTOR:
367  switch (from) {
368  case SOCK_VECTOR:
369  return 4;
370  case SOCK_FLOAT:
371  return 3;
372  case SOCK_INT:
373  return 2;
374  case SOCK_BOOLEAN:
375  return 1;
376  default:
377  return -1;
378  }
379  case SOCK_FLOAT:
380  switch (from) {
381  case SOCK_FLOAT:
382  return 5;
383  case SOCK_INT:
384  return 4;
385  case SOCK_BOOLEAN:
386  return 3;
387  case SOCK_RGBA:
388  return 2;
389  case SOCK_VECTOR:
390  return 1;
391  default:
392  return -1;
393  }
394  case SOCK_INT:
395  switch (from) {
396  case SOCK_INT:
397  return 5;
398  case SOCK_FLOAT:
399  return 4;
400  case SOCK_BOOLEAN:
401  return 3;
402  case SOCK_RGBA:
403  return 2;
404  case SOCK_VECTOR:
405  return 1;
406  default:
407  return -1;
408  }
409  case SOCK_BOOLEAN:
410  switch (from) {
411  case SOCK_BOOLEAN:
412  return 5;
413  case SOCK_INT:
414  return 4;
415  case SOCK_FLOAT:
416  return 3;
417  case SOCK_RGBA:
418  return 2;
419  case SOCK_VECTOR:
420  return 1;
421  default:
422  return -1;
423  }
424  case SOCK_SHADER:
425  switch (from) {
426  case SOCK_SHADER:
427  return 1;
428  default:
429  return -1;
430  }
431  case SOCK_STRING:
432  switch (from) {
433  case SOCK_STRING:
434  return 1;
435  default:
436  return -1;
437  }
438  case SOCK_OBJECT: {
439  switch (from) {
440  case SOCK_OBJECT:
441  return 1;
442  default:
443  return -1;
444  }
445  }
446  case SOCK_GEOMETRY: {
447  switch (from) {
448  case SOCK_GEOMETRY:
449  return 1;
450  default:
451  return -1;
452  }
453  }
454  case SOCK_COLLECTION: {
455  switch (from) {
456  case SOCK_COLLECTION:
457  return 1;
458  default:
459  return -1;
460  }
461  }
462  default:
463  return -1;
464  }
465 }
466 
467 /* select a suitable input socket for an output */
469 {
470  bNodeSocket *selected = NULL, *input;
471  int i;
472  int sel_priority = -1;
473  bool sel_is_linked = false;
474 
475  for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
476  int priority = node_datatype_priority(input->type, output->type);
477  bool is_linked = (input->link != NULL);
478  bool preferred;
479 
480  if (nodeSocketIsHidden(input) || /* ignore hidden sockets */
481  input->flag &
482  SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */
483  priority < 0 || /* ignore incompatible types */
484  priority < sel_priority) /* ignore if we already found a higher priority input */
485  {
486  continue;
487  }
488 
489  /* determine if this input is preferred over the currently selected */
490  preferred = (priority > sel_priority) || /* prefer higher datatype priority */
491  (is_linked && !sel_is_linked); /* prefer linked over unlinked */
492 
493  if (preferred) {
494  selected = input;
495  sel_is_linked = is_linked;
496  sel_priority = priority;
497  }
498  }
499 
500  return selected;
501 }
502 
504 {
505  bNodeLink *link;
506  bNodeSocket *output, *input;
507 
508  /* sanity check */
509  if (!ntree) {
510  return;
511  }
512 
513  /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */
514  for (output = node->outputs.first; output; output = output->next) {
515  output->link = NULL;
516  }
517 
518  for (link = ntree->links.first; link; link = link->next) {
519  if (nodeLinkIsHidden(link)) {
520  continue;
521  }
522 
523  output = link->fromsock;
524  if (link->fromnode != node || output->link) {
525  continue;
526  }
528  continue;
529  }
530  output->link = link; /* not really used, just for tagging handled sockets */
531 
532  /* look for suitable input */
534 
535  if (input) {
536  bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link");
537  ilink->fromnode = node;
538  ilink->fromsock = input;
539  ilink->tonode = node;
540  ilink->tosock = output;
541  /* internal link is always valid */
542  ilink->flag |= NODE_LINK_VALID;
543  BLI_addtail(&node->internal_links, ilink);
544  }
545  }
546 
547  /* clean up */
548  for (output = node->outputs.first; output; output = output->next) {
549  output->link = NULL;
550  }
551 }
552 
555 /* -------------------------------------------------------------------- */
560 {
561  PointerRNA ptr;
563  return RNA_float_get(&ptr, "default_value");
564 }
565 
567 {
568  PointerRNA ptr;
570  RNA_float_set(&ptr, "default_value", value);
571 }
572 
574 {
575  PointerRNA ptr;
577  RNA_float_get_array(&ptr, "default_value", value);
578 }
579 
581  bNode *UNUSED(node),
582  bNodeSocket *sock,
583  const float *value)
584 {
585  PointerRNA ptr;
587  RNA_float_set_array(&ptr, "default_value", value);
588 }
589 
591 {
592  PointerRNA ptr;
594  RNA_float_get_array(&ptr, "default_value", value);
595 }
596 
598  bNode *UNUSED(node),
599  bNodeSocket *sock,
600  const float *value)
601 {
602  PointerRNA ptr;
604  RNA_float_set_array(&ptr, "default_value", value);
605 }
606 
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1200
struct CurveMapping * BKE_curvemapping_copy(const struct CurveMapping *cumap)
void BKE_curvemapping_free(struct CurveMapping *cumap)
Definition: colortools.c:119
void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3726
bool nodeLinkIsHidden(const struct bNodeLink *link)
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link)
Definition: node.cc:2231
int nodeSocketIsHidden(const struct bNodeSocket *sock)
int nodeSocketLinkLimit(const struct bNodeSocket *sock)
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define UNUSED(x)
#define ELEM(...)
#define IFACE_(msgid)
#define MAX_NAME
Definition: DNA_defs.h:62
@ NODE_MATH_SINH
@ NODE_MATH_SMOOTH_MIN
@ NODE_MATH_TRUNC
@ NODE_MATH_COSH
@ NODE_MATH_SIGN
@ NODE_MATH_DEGREES
@ NODE_MATH_ABSOLUTE
@ NODE_MATH_SINE
@ NODE_MATH_ARCCOSINE
@ NODE_MATH_MULTIPLY_ADD
@ NODE_MATH_POWER
@ NODE_MATH_WRAP
@ NODE_MATH_ARCTANGENT
@ NODE_MATH_SQRT
@ NODE_MATH_CEIL
@ NODE_MATH_TANH
@ NODE_MATH_GREATER_THAN
@ NODE_MATH_FRACTION
@ NODE_MATH_EXPONENT
@ NODE_MATH_LESS_THAN
@ NODE_MATH_ARCSINE
@ NODE_MATH_LOGARITHM
@ NODE_MATH_COMPARE
@ NODE_MATH_INV_SQRT
@ NODE_MATH_PINGPONG
@ NODE_MATH_ROUND
@ NODE_MATH_FLOOR
@ NODE_MATH_COSINE
@ NODE_MATH_SNAP
@ NODE_MATH_TANGENT
@ NODE_MATH_SMOOTH_MAX
@ NODE_MATH_RADIANS
#define NODE_LINK_VALID
@ SOCK_IN
@ SOCK_NO_INTERNAL_LINK
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_SHADER
@ SOCK_FLOAT
@ SOCK_COLLECTION
@ SOCK_GEOMETRY
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
Read Guarded memory(de)allocation.
StructRNA RNA_NodeSocket
#define output
OperationNode * node
StackEntry * from
const char * label
bNodeTree * ntree
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static unsigned a[3]
Definition: RandGen.cpp:92
void node_sock_label_clear(bNodeSocket *sock)
Definition: node_util.c:93
void node_sock_label(bNodeSocket *sock, const char *name)
Definition: node_util.c:88
void node_copy_curves(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:62
void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
Definition: node_util.c:189
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:67
void node_free_standard_storage(bNode *node)
Definition: node_util.c:55
void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
Definition: node_util.c:206
void node_socket_set_vector(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, const float *value)
Definition: node_util.c:597
void node_socket_get_color(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float *value)
Definition: node_util.c:573
void * node_initexec_curves(bNodeExecContext *UNUSED(context), bNode *node, bNodeInstanceKey UNUSED(key))
Definition: node_util.c:74
static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
Definition: node_util.c:267
void node_free_curves(bNode *node)
Definition: node_util.c:50
void node_socket_set_float(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float value)
Definition: node_util.c:566
void node_math_update(bNodeTree *UNUSED(ntree), bNode *node)
Definition: node_util.c:100
float node_socket_get_float(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock)
Definition: node_util.c:559
void node_socket_get_vector(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float *value)
Definition: node_util.c:590
void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
Definition: node_util.c:226
static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype to)
Definition: node_util.c:350
static bNodeSocket * select_internal_link_input(bNode *node, bNodeSocket *output)
Definition: node_util.c:468
void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition: node_util.c:305
static bool node_link_socket_match(const bNodeSocket *a, const bNodeSocket *b)
Definition: node_util.c:242
void node_update_internal_links_default(bNodeTree *ntree, bNode *node)
Definition: node_util.c:503
static bNodeSocket * node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *to_socket)
Definition: node_util.c:278
void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
Definition: node_util.c:216
void node_socket_set_color(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, const float *value)
Definition: node_util.c:580
void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
Definition: node_util.c:199
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:6366
bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name)
Definition: rna_access.c:1854
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
const EnumPropertyItem rna_enum_ramp_blend_items[]
Definition: rna_material.c:37
const EnumPropertyItem rna_enum_node_math_items[]
Definition: rna_nodetree.c:145
const EnumPropertyItem rna_enum_node_vec_math_items[]
Definition: rna_nodetree.c:214
const EnumPropertyItem rna_enum_node_filter_items[]
Definition: rna_nodetree.c:349
struct SELECTID_Context context
Definition: select_engine.c:47
Definition: DNA_ID.h:273
void * first
Definition: DNA_listBase.h:47
char name[64]
struct bNodeSocket * next
struct bNodeSocketType * typeinfo
short total_inputs
char label[64]
ListBase links
void * storage
PointerRNA * ptr
Definition: wm_files.c:3157