diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2015-12-03 14:51:29 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-12-03 15:04:04 +0300 |
commit | 7f759ec547a563284f29f7a80b96316854b37ae5 (patch) | |
tree | 2205f1a7d6c8a7f31691b227858ad165be070dde /source/blender/nodes/intern | |
parent | 762aad37779e9e0654b4746df35710f850438329 (diff) |
Node callback for handling link insertion and swapping of occupied inputs.
Nodes have a feature for moving existing links to unoccupied sockets when connecting
to an already used input. This is based on the standard legacy socket types (value/float,
vector, color/rgba) and works reasonably well for shader, compositor and texture nodes.
For new pynode systems, however, the hardcoded nature of that feature has major drawbacks:
* It does not take different type systems into account, leading to meaningless connections
when sockets are swapped and making the feature useless or outright debilitating.
* Advanced socket behaviors would be possible with a registerable callback, e.g. creating
extensible input lists that move existing connections down to make room for a new link.
Now any handling of new links is done via the 'insert_links' callback, which can also be
registered through the RNA API. For the legacy shader/compo/tex nodes the behavior is the
same, using a C callback.
Note on the 'use_swap' flag: this has been removed because it was meaningless anyway:
It was disabled only for the insert-node-on-link feature, which works only for
completely unconnected nodes anyway, so there would be nothing to swap in the first place.
Diffstat (limited to 'source/blender/nodes/intern')
-rw-r--r-- | source/blender/nodes/intern/node_util.c | 90 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_util.h | 3 |
2 files changed, 93 insertions, 0 deletions
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 3a301f55487..dd5715891d5 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -29,6 +29,7 @@ * \ingroup nodes */ +#include <ctype.h> #include <limits.h> #include <string.h> @@ -112,6 +113,95 @@ void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int m } +/*** Link Insertion ***/ + +/* test if two sockets are interchangeable */ +static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b) +{ + /* tests if alphabetic prefix matches + * this allows for imperfect matches, such as numeric suffixes, + * like Color1/Color2 + */ + int prefix_len = 0; + 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(bNodeTree *ntree, bNodeSocket *sock) +{ + bNodeLink *link; + int count = 0; + for (link = ntree->links.first; link; link = link->next) { + if (link->fromsock == sock) + ++count; + if (link->tosock == sock) + ++count; + } + return count; +} + +/* find an eligible socket for linking */ +static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur) +{ + /* link swapping: try to find a free slot with a matching name */ + + bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first; + bNodeSocket *sock; + + sock = cur->next ? cur->next : first; /* wrap around the list end */ + while (sock != cur) { + if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) { + int link_count = node_count_links(ntree, sock); + /* take +1 into account since we would add a new link */ + if (link_count + 1 <= sock->limit) + return sock; /* found a valid free socket we can swap to */ + } + + sock = sock->next ? sock->next : first; /* wrap around the list end */ + } + return NULL; +} + +void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) +{ + bNodeSocket *sock = link->tosock; + bNodeLink *tlink, *tlink_next; + + /* inputs can have one link only, outputs can have unlimited links */ + if (node != link->tonode) + return; + + for (tlink = ntree->links.first; tlink; tlink = tlink_next) { + bNodeSocket *new_sock; + tlink_next = tlink->next; + + if (sock != tlink->tosock) + continue; + + new_sock = node_find_linkable_socket(ntree, node, sock); + if (new_sock && new_sock != sock) { + /* redirect existing link */ + tlink->tosock = new_sock; + } + else if (!new_sock) { + /* no possible replacement, remove tlink */ + nodeRemLink(ntree, tlink); + tlink = NULL; + } + } +} + + /**** Internal Links (mute and disconnect) ****/ /* common datatype priorities, works for compositor, shader and texture nodes alike diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 64b2028874b..2e20a8e79d4 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -76,6 +76,9 @@ void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, i void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); + +/*** Link Handling */ +void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); void node_update_internal_links_default(struct bNodeTree *ntree, struct bNode *node); float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); |