diff options
author | Charlie Jolly <charlie> | 2021-03-16 22:11:54 +0300 |
---|---|---|
committer | Charlie Jolly <mistajolly@gmail.com> | 2021-03-17 14:54:16 +0300 |
commit | 266cd7bb82ce4bfed20a3d61a84f25e2bacfca2b (patch) | |
tree | 963a983f902f5368669c1d93312b53262592e4dc /source/blender/blenkernel/intern | |
parent | 20bf736ff81c6fb79558796b74d50d4e7a9c8ef6 (diff) |
Nodes: Add support to mute node wires
This patch adds the ability to mute individual wires in the node editor.
This is invoked like the cut links operator but with a new shortcut.
Mute = Ctrl + Alt
Cut = Ctrl
Dragging over wires will toggle the mute state for that wire.
The muted wires are drawn in red with a bar across the center.
Red is used in the nodes context to indicate invalid links, muted links and internal links.
When a wire is muted it exposes the original node buttons which are normally hidden when a wire is connected.
Downstream and upstream links connected using reroute nodes are also muted.
Outside scope of patch:
- Add support for pynodes e.g. Animation Nodes
- Requires minor change to check for muted links using the `is_muted` link property or the `is_linked` socket property.
Maniphest Tasks: T52659
Differential Revision: https://developer.blender.org/D2807
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/node.cc | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index bbc655d7fc8..ca973bd9d65 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -107,6 +107,9 @@ static void node_free_node(bNodeTree *ntree, bNode *node); static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool do_id_user); +static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree, + struct bNode *node, + const bool mute); static void ntree_init_data(ID *id) { @@ -2215,6 +2218,106 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link) } } +/* Check if all output links are muted or not. */ +static bool nodeMuteFromSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock) +{ + int tot = 0; + int muted = 0; + LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) { + if (link->fromsock == sock) { + tot++; + if (link->flag & NODE_LINK_MUTED) { + muted++; + } + } + } + return tot == muted; +} + +static void nodeMuteLink(bNodeLink *link) +{ + link->flag |= NODE_LINK_MUTED; + link->flag |= NODE_LINK_TEST; + if (!(link->tosock->flag & SOCK_MULTI_INPUT)) { + link->tosock->flag &= ~SOCK_IN_USE; + } +} + +static void nodeUnMuteLink(bNodeLink *link) +{ + link->flag &= ~NODE_LINK_MUTED; + link->flag |= NODE_LINK_TEST; + link->tosock->flag |= SOCK_IN_USE; +} + +/* Upstream muting. Always happens when unmuting but checks when muting. O(n^2) algorithm.*/ +static void nodeMuteRerouteInputLinks(bNodeTree *ntree, bNode *node, const bool mute) +{ + if (node->type != NODE_REROUTE) { + return; + } + if (!mute || nodeMuteFromSocketLinks(ntree, (bNodeSocket *)node->outputs.first)) { + bNodeSocket *sock = (bNodeSocket *)node->inputs.first; + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { + if (!(link->flag & NODE_LINK_VALID) || (link->tosock != sock)) { + continue; + } + if (mute) { + nodeMuteLink(link); + } + else { + nodeUnMuteLink(link); + } + nodeMuteRerouteInputLinks(ntree, link->fromnode, mute); + } + } +} + +/* Downstream muting propagates when reaching reroute nodes. O(n^2) algorithm.*/ +static void nodeMuteRerouteOutputLinks(bNodeTree *ntree, bNode *node, const bool mute) +{ + if (node->type != NODE_REROUTE) { + return; + } + bNodeSocket *sock; + sock = (bNodeSocket *)node->outputs.first; + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { + if (!(link->flag & NODE_LINK_VALID) || (link->fromsock != sock)) { + continue; + } + if (mute) { + nodeMuteLink(link); + } + else { + nodeUnMuteLink(link); + } + nodeMuteRerouteOutputLinks(ntree, link->tonode, mute); + } +} + +void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link) +{ + if (link->tosock) { + bool mute = !(link->flag & NODE_LINK_MUTED); + if (mute) { + nodeMuteLink(link); + } + else { + nodeUnMuteLink(link); + } + if (link->tonode->type == NODE_REROUTE) { + nodeMuteRerouteOutputLinks(ntree, link->tonode, mute); + } + if (link->fromnode->type == NODE_REROUTE) { + nodeMuteRerouteInputLinks(ntree, link->fromnode, mute); + } + } + + if (ntree) { + ntree->update |= NTREE_UPDATE_LINKS; + } +} + void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { @@ -2257,6 +2360,10 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node) link->flag &= ~NODE_LINK_VALID; } + if (fromlink->flag & NODE_LINK_MUTED) { + link->flag |= NODE_LINK_MUTED; + } + ntree->update |= NTREE_UPDATE_LINKS; } else { @@ -4014,7 +4121,9 @@ void ntreeTagUsedSockets(bNodeTree *ntree) LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { link->fromsock->flag |= SOCK_IN_USE; - link->tosock->flag |= SOCK_IN_USE; + if (!(link->flag & NODE_LINK_MUTED)) { + link->tosock->flag |= SOCK_IN_USE; + } } } |