Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/intern/node_util.cc')
-rw-r--r--source/blender/nodes/intern/node_util.cc415
1 files changed, 415 insertions, 0 deletions
diff --git a/source/blender/nodes/intern/node_util.cc b/source/blender/nodes/intern/node_util.cc
new file mode 100644
index 00000000000..17be20b4e4b
--- /dev/null
+++ b/source/blender/nodes/intern/node_util.cc
@@ -0,0 +1,415 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2007 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup nodes
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+
+#include "DNA_node_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_colortools.h"
+#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
+
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+#include "RNA_prototypes.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "NOD_common.h"
+
+#include "node_util.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Storage Data
+ * \{ */
+
+void node_free_curves(bNode *node)
+{
+ BKE_curvemapping_free(static_cast<CurveMapping *>(node->storage));
+}
+
+void node_free_standard_storage(bNode *node)
+{
+ if (node->storage) {
+ MEM_freeN(node->storage);
+ }
+}
+
+void node_copy_curves(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
+{
+ dest_node->storage = BKE_curvemapping_copy(static_cast<CurveMapping *>(src_node->storage));
+}
+
+void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
+{
+ dest_node->storage = MEM_dupallocN(src_node->storage);
+}
+
+void *node_initexec_curves(bNodeExecContext *UNUSED(context),
+ bNode *node,
+ bNodeInstanceKey UNUSED(key))
+{
+ BKE_curvemapping_init(static_cast<CurveMapping *>(node->storage));
+ return NULL; /* unused return */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Updates
+ * \{ */
+
+void node_sock_label(bNodeSocket *sock, const char *name)
+{
+ BLI_strncpy(sock->label, name, MAX_NAME);
+}
+
+void node_sock_label_clear(bNodeSocket *sock)
+{
+ if (sock->label[0] != '\0') {
+ sock->label[0] = '\0';
+ }
+}
+
+void node_math_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock1 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 0));
+ bNodeSocket *sock2 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1));
+ bNodeSocket *sock3 = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2));
+ nodeSetSocketAvailability(ntree,
+ sock2,
+ !ELEM(node->custom1,
+ NODE_MATH_SQRT,
+ NODE_MATH_SIGN,
+ NODE_MATH_CEIL,
+ NODE_MATH_SINE,
+ NODE_MATH_ROUND,
+ NODE_MATH_FLOOR,
+ NODE_MATH_COSINE,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_RADIANS,
+ NODE_MATH_DEGREES,
+ NODE_MATH_FRACTION,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT) &&
+ !ELEM(node->custom1,
+ NODE_MATH_INV_SQRT,
+ NODE_MATH_TRUNC,
+ NODE_MATH_EXPONENT,
+ NODE_MATH_COSH,
+ NODE_MATH_SINH,
+ NODE_MATH_TANH));
+ nodeSetSocketAvailability(ntree,
+ sock3,
+ ELEM(node->custom1,
+ NODE_MATH_COMPARE,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_WRAP,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX));
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (node->custom1) {
+ case NODE_MATH_WRAP:
+ node_sock_label(sock2, "Max");
+ node_sock_label(sock3, "Min");
+ break;
+ case NODE_MATH_MULTIPLY_ADD:
+ node_sock_label(sock2, "Multiplier");
+ node_sock_label(sock3, "Addend");
+ break;
+ case NODE_MATH_LESS_THAN:
+ case NODE_MATH_GREATER_THAN:
+ node_sock_label(sock2, "Threshold");
+ break;
+ case NODE_MATH_PINGPONG:
+ node_sock_label(sock2, "Scale");
+ break;
+ case NODE_MATH_SNAP:
+ node_sock_label(sock2, "Increment");
+ break;
+ case NODE_MATH_POWER:
+ node_sock_label(sock1, "Base");
+ node_sock_label(sock2, "Exponent");
+ break;
+ case NODE_MATH_LOGARITHM:
+ node_sock_label(sock2, "Base");
+ break;
+ case NODE_MATH_DEGREES:
+ node_sock_label(sock1, "Radians");
+ break;
+ case NODE_MATH_RADIANS:
+ node_sock_label(sock1, "Degrees");
+ break;
+ case NODE_MATH_COMPARE:
+ node_sock_label(sock3, "Epsilon");
+ break;
+ case NODE_MATH_SMOOTH_MAX:
+ case NODE_MATH_SMOOTH_MIN:
+ node_sock_label(sock3, "Distance");
+ break;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Labels
+ * \{ */
+
+void node_blend_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+void node_image_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
+{
+ /* If there is no loaded image, return an empty string,
+ * and let nodeLabel() fill in the proper type translation. */
+ BLI_strncpy(label, (node->id) ? node->id->name + 2 : "", maxlen);
+}
+
+void node_math_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, name), maxlen);
+}
+
+void node_vector_math_label(const bNodeTree *UNUSED(ntree),
+ const bNode *node,
+ char *label,
+ int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+void node_filter_label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode)
+{
+ bNodeSocket *sock1 = (bNodeSocket *)sockets->first;
+ bNodeSocket *sock2 = sock1->next;
+ bNodeSocket *sock3 = sock2->next;
+
+ node_sock_label_clear(sock1);
+ node_sock_label_clear(sock2);
+ node_sock_label_clear(sock3);
+
+ switch (mode) {
+ case NODE_COMBSEP_COLOR_RGB:
+ node_sock_label(sock1, "Red");
+ node_sock_label(sock2, "Green");
+ node_sock_label(sock3, "Blue");
+ break;
+ case NODE_COMBSEP_COLOR_HSL:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Lightness");
+ break;
+ case NODE_COMBSEP_COLOR_HSV:
+ node_sock_label(sock1, "Hue");
+ node_sock_label(sock2, "Saturation");
+ node_sock_label(sock3, "Value");
+ break;
+ default: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Link Insertion
+ * \{ */
+
+static bool node_link_socket_match(const bNodeSocket *a, const bNodeSocket *b)
+{
+ /* Check if sockets are of the same type. */
+ if (a->typeinfo != b->typeinfo) {
+ return false;
+ }
+
+ /* Test if alphabetic prefix matches, allowing for imperfect matches, such as numeric suffixes
+ * like Color1/Color2. */
+ int prefix_len = 0;
+ const char *ca = a->name, *cb = b->name;
+ for (; *ca != '\0' && *cb != '\0'; ca++, cb++) {
+ /* End of common prefix? */
+ if (*ca != *cb) {
+ /* Prefix delimited by non-alphabetic char. */
+ if (isalpha(*ca) || isalpha(*cb)) {
+ return false;
+ }
+ break;
+ }
+ prefix_len++;
+ }
+ return prefix_len > 0;
+}
+
+static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
+{
+ int count = 0;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (ELEM(socket, link->fromsock, link->tosock)) {
+ count++;
+ }
+ }
+ return count;
+}
+
+static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree,
+ bNode *node,
+ bNodeSocket *to_socket)
+{
+ bNodeSocket *first = to_socket->in_out == SOCK_IN ?
+ static_cast<bNodeSocket *>(node->inputs.first) :
+ static_cast<bNodeSocket *>((node->outputs.first));
+
+ /* Wrap around the list end. */
+ bNodeSocket *socket_iter = to_socket->next ? to_socket->next : first;
+ while (socket_iter != to_socket) {
+ if (!nodeSocketIsHidden(socket_iter) && node_link_socket_match(socket_iter, to_socket)) {
+ const int link_count = node_count_links(ntree, socket_iter);
+ /* Add one to account for the new link being added. */
+ if (link_count + 1 <= nodeSocketLinkLimit(socket_iter)) {
+ return socket_iter; /* Found a valid free socket we can swap to. */
+ }
+ }
+ socket_iter = socket_iter->next ? socket_iter->next : first; /* Wrap around the list end. */
+ }
+
+ return NULL;
+}
+
+void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
+{
+ bNodeSocket *socket = link->tosock;
+
+ if (node != link->tonode) {
+ return;
+ }
+
+ /* If we're not at the link limit of the target socket, we can skip
+ * trying to move existing links to another socket. */
+ const int to_link_limit = nodeSocketLinkLimit(socket);
+ if (socket->total_inputs + 1 < to_link_limit) {
+ return;
+ }
+
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, to_link, &ntree->links) {
+ if (socket == to_link->tosock) {
+ bNodeSocket *new_socket = node_find_linkable_socket(ntree, node, socket);
+ if (new_socket && new_socket != socket) {
+ /* Attempt to redirect the existing link to the new socket. */
+ to_link->tosock = new_socket;
+ return;
+ }
+
+ if (new_socket == NULL) {
+ /* No possible replacement, remove the existing link. */
+ nodeRemLink(ntree, to_link);
+ return;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Default value RNA access
+ * \{ */
+
+float node_socket_get_float(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock)
+{
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ return RNA_float_get(&ptr, "default_value");
+}
+
+void node_socket_set_float(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float value)
+{
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ RNA_float_set(&ptr, "default_value", value);
+}
+
+void node_socket_get_color(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float *value)
+{
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ RNA_float_get_array(&ptr, "default_value", value);
+}
+
+void node_socket_set_color(bNodeTree *ntree,
+ bNode *UNUSED(node),
+ bNodeSocket *sock,
+ const float *value)
+{
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ RNA_float_set_array(&ptr, "default_value", value);
+}
+
+void node_socket_get_vector(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, float *value)
+{
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ RNA_float_get_array(&ptr, "default_value", value);
+}
+
+void node_socket_set_vector(bNodeTree *ntree,
+ bNode *UNUSED(node),
+ bNodeSocket *sock,
+ const float *value)
+{
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+ RNA_float_set_array(&ptr, "default_value", value);
+}
+
+/** \} */