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:
authorCharlie Jolly <charlie>2021-03-16 22:11:54 +0300
committerCharlie Jolly <mistajolly@gmail.com>2021-03-17 14:54:16 +0300
commit266cd7bb82ce4bfed20a3d61a84f25e2bacfca2b (patch)
tree963a983f902f5368669c1d93312b53262592e4dc
parent20bf736ff81c6fb79558796b74d50d4e7a9c8ef6 (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
-rw-r--r--intern/cycles/blender/blender_shader.cpp3
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py1
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py1
-rw-r--r--release/scripts/startup/bl_ui/space_node.py1
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/node.cc111
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.cc3
-rw-r--r--source/blender/editors/space_node/drawnode.c53
-rw-r--r--source/blender/editors/space_node/node_intern.h1
-rw-r--r--source/blender/editors/space_node/node_ops.c1
-rw-r--r--source/blender/editors/space_node/node_relationships.c111
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl14
-rw-r--r--source/blender/makesdna/DNA_node_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c5
-rw-r--r--source/blender/nodes/intern/node_exec.c5
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc3
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c4
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c26
-rw-r--r--source/blender/windowmanager/wm_cursors.h1
19 files changed, 324 insertions, 22 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index a1ab5277744..72328333732 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -1234,7 +1234,8 @@ static void add_nodes(Scene *scene,
for (BL::NodeLink &b_link : b_ntree.links) {
/* Ignore invalid links to avoid unwanted cycles created in graph.
* Also ignore links with unavailable sockets. */
- if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled())) {
+ if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled()) ||
+ b_link.is_muted()) {
continue;
}
/* get blender link data */
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 3471a8d0db0..feba4e3bd09 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -1844,6 +1844,7 @@ def km_node_editor(params):
("node.resize", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("node.add_reroute", {"type": 'EVT_TWEAK_L' if params.legacy else 'EVT_TWEAK_R', "value": 'ANY', "shift": True}, None),
("node.links_cut", {"type": 'EVT_TWEAK_L' if params.legacy else 'EVT_TWEAK_R', "value": 'ANY', "ctrl": True}, None),
+ ("node.links_mute", {"type": 'EVT_TWEAK_R', "value": 'ANY', "ctrl": True, "alt": True}, None),
("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("node.backimage_move", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "alt": True}, None),
("node.backimage_zoom", {"type": 'V', "value": 'PRESS', "repeat": True},
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index c8fc6abe10a..91f153a0f42 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -1113,6 +1113,7 @@ def km_node_editor(params):
("node.resize", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("node.add_reroute", {"type": params.action_tweak, "value": 'ANY', "shift": True}, None),
("node.links_cut", {"type": params.action_tweak, "value": 'ANY', "ctrl": True}, None),
+ ("node.links_mute", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("node.backimage_fit", {"type": 'A', "value": 'PRESS', "alt": True}, None),
("node.backimage_sample", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, None),
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index a9934850acd..7f66cdd3d74 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -331,6 +331,7 @@ class NODE_MT_node(Menu):
layout.operator("node.link_make", text="Make and Replace Links").replace = True
layout.operator("node.links_cut")
layout.operator("node.links_detach")
+ layout.operator("node.links_mute")
layout.separator()
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index ced76e65ada..04a9855de68 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -627,6 +627,7 @@ struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
struct bNodeSocket *tosock);
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link);
void nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
+void nodeMuteLinkToggle(struct bNodeTree *ntree, struct bNodeLink *link);
bool nodeLinkIsHidden(const struct bNodeLink *link);
void nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node);
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;
+ }
}
}
diff --git a/source/blender/compositor/intern/COM_NodeGraph.cc b/source/blender/compositor/intern/COM_NodeGraph.cc
index f932acfa49e..d8220099f1f 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.cc
+++ b/source/blender/compositor/intern/COM_NodeGraph.cc
@@ -188,7 +188,8 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink
if (!(b_nodelink->flag & NODE_LINK_VALID)) {
return;
}
- if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL)) {
+ if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL) ||
+ (b_nodelink->flag & NODE_LINK_MUTED)) {
return;
}
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 0f2b2b435bc..1354c06305c 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3751,17 +3751,21 @@ bool node_link_bezier_points(const View2D *v2d,
#define LINK_WIDTH (2.5f * UI_DPI_FAC)
#define ARROW_SIZE (7 * UI_DPI_FAC)
+/* Reroute arrow shape and mute bar. These are expanded here and shrunk in the glsl code.
+ * See: gpu_shader_2D_nodelink_vert.glsl */
static float arrow_verts[3][2] = {{-1.0f, 1.0f}, {0.0f, 0.0f}, {-1.0f, -1.0f}};
static float arrow_expand_axis[3][2] = {{0.7071f, 0.7071f}, {M_SQRT2, 0.0f}, {0.7071f, -0.7071f}};
+static float mute_verts[3][2] = {{0.7071f, 1.0f}, {0.7071f, 0.0f}, {0.7071f, -1.0f}};
+static float mute_expand_axis[3][2] = {{1.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, -0.0f}};
static struct {
GPUBatch *batch; /* for batching line together */
GPUBatch *batch_single; /* for single line */
GPUVertBuf *inst_vbo;
uint p0_id, p1_id, p2_id, p3_id;
- uint colid_id;
+ uint colid_id, muted_id;
GPUVertBufRaw p0_step, p1_step, p2_step, p3_step;
- GPUVertBufRaw colid_step;
+ GPUVertBufRaw colid_step, muted_step;
uint count;
bool enabled;
} g_batch_link = {0};
@@ -3774,6 +3778,8 @@ static void nodelink_batch_reset(void)
GPU_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p3_id, &g_batch_link.p3_step);
GPU_vertbuf_attr_get_raw_data(
g_batch_link.inst_vbo, g_batch_link.colid_id, &g_batch_link.colid_step);
+ GPU_vertbuf_attr_get_raw_data(
+ g_batch_link.inst_vbo, g_batch_link.muted_id, &g_batch_link.muted_step);
g_batch_link.count = 0;
}
@@ -3801,6 +3807,8 @@ static void nodelink_batch_init(void)
int vcount = LINK_RESOL * 2; /* curve */
vcount += 2; /* restart strip */
vcount += 3 * 2; /* arrow */
+ vcount += 2; /* restart strip */
+ vcount += 3 * 2; /* mute */
vcount *= 2; /* shadow */
vcount += 2; /* restart strip */
GPU_vertbuf_data_alloc(vbo, vcount);
@@ -3844,6 +3852,25 @@ static void nodelink_batch_init(void)
}
/* restart */
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+ uv[0] = 127;
+ uv[1] = 0;
+ copy_v2_v2(pos, mute_verts[0]);
+ copy_v2_v2(exp, mute_expand_axis[0]);
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+ /* bar */
+ for (int i = 0; i < 3; ++i) {
+ uv[1] = 0;
+ copy_v2_v2(pos, mute_verts[i]);
+ copy_v2_v2(exp, mute_expand_axis[i]);
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+ uv[1] = 255;
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+ }
+
+ /* restart */
if (k == 0) {
set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
}
@@ -3867,6 +3894,8 @@ static void nodelink_batch_init(void)
&format_inst, "P3", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
g_batch_link.colid_id = GPU_vertformat_attr_add(
&format_inst, "colid_doarrow", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ g_batch_link.muted_id = GPU_vertformat_attr_add(
+ &format_inst, "domuted", GPU_COMP_U8, 2, GPU_FETCH_INT);
g_batch_link.inst_vbo = GPU_vertbuf_create_with_format_ex(&format_inst, GPU_USAGE_STREAM);
/* Alloc max count but only draw the range we need. */
GPU_vertbuf_data_alloc(g_batch_link.inst_vbo, NODELINK_GROUP_SIZE);
@@ -3941,12 +3970,13 @@ static void nodelink_batch_add_link(const SpaceNode *snode,
int th_col1,
int th_col2,
int th_col3,
- bool drawarrow)
+ bool drawarrow,
+ bool drawmuted)
{
/* Only allow these colors. If more is needed, you need to modify the shader accordingly. */
BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
BLI_assert(ELEM(th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
- BLI_assert(ELEM(th_col3, TH_WIRE, -1));
+ BLI_assert(ELEM(th_col3, TH_WIRE, TH_REDALERT, -1));
g_batch_link.count++;
copy_v2_v2(GPU_vertbuf_raw_step(&g_batch_link.p0_step), p0);
@@ -3958,6 +3988,8 @@ static void nodelink_batch_add_link(const SpaceNode *snode,
colid[1] = nodelink_get_color_id(th_col2);
colid[2] = nodelink_get_color_id(th_col3);
colid[3] = drawarrow;
+ char *muted = GPU_vertbuf_raw_step(&g_batch_link.muted_step);
+ muted[0] = drawmuted;
if (g_batch_link.count == NODELINK_GROUP_SIZE) {
nodelink_batch_draw(snode);
@@ -3977,7 +4009,7 @@ void node_draw_link_bezier(const View2D *v2d,
if (node_link_bezier_handles(v2d, snode, link, vec)) {
int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
(link->fromnode && (link->fromnode->type == NODE_REROUTE)));
-
+ int drawmuted = (link->flag & NODE_LINK_MUTED);
if (g_batch_link.batch == NULL) {
nodelink_batch_init();
}
@@ -3985,7 +4017,7 @@ void node_draw_link_bezier(const View2D *v2d,
if (g_batch_link.enabled && !highlighted) {
/* Add link to batch. */
nodelink_batch_add_link(
- snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow);
+ snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow, drawmuted);
}
else {
/* Draw single link. */
@@ -4009,6 +4041,7 @@ void node_draw_link_bezier(const View2D *v2d,
GPU_batch_uniform_1f(batch, "expandSize", snode->runtime->aspect * LINK_WIDTH);
GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
+ GPU_batch_uniform_1i(batch, "doMuted", drawmuted);
GPU_batch_draw(batch);
}
}
@@ -4041,8 +4074,11 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
if (link->flag & NODE_LINKFLAG_HILITE) {
th_col1 = th_col2 = TH_ACTIVE;
}
+ else if (link->flag & NODE_LINK_MUTED) {
+ th_col1 = th_col2 = TH_REDALERT;
+ }
else {
- /* regular link */
+ /* Regular link, highlight if connected to selected node. */
if (link->fromnode && link->fromnode->flag & SELECT) {
th_col1 = TH_EDGE_SELECT;
}
@@ -4052,7 +4088,8 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
}
}
else {
- th_col1 = th_col2 = TH_REDALERT;
+ /* Invalid link. */
+ th_col1 = th_col2 = th_col3 = TH_REDALERT;
// th_col3 = -1; /* no shadow */
}
}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 1840ec93f6f..21a36ff9683 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -234,6 +234,7 @@ void NODE_OT_link(struct wmOperatorType *ot);
void NODE_OT_link_make(struct wmOperatorType *ot);
void NODE_OT_links_cut(struct wmOperatorType *ot);
void NODE_OT_links_detach(struct wmOperatorType *ot);
+void NODE_OT_links_mute(struct wmOperatorType *ot);
void NODE_OT_parent_set(struct wmOperatorType *ot);
void NODE_OT_join(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index ef28cfe8a8b..e35b444aa11 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -68,6 +68,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_link_make);
WM_operatortype_append(NODE_OT_links_cut);
WM_operatortype_append(NODE_OT_links_detach);
+ WM_operatortype_append(NODE_OT_links_mute);
WM_operatortype_append(NODE_OT_add_reroute);
WM_operatortype_append(NODE_OT_group_make);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index ee07ec7a55c..2cc44d72c72 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -1227,8 +1227,8 @@ void NODE_OT_link_make(wmOperatorType *ot)
ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links");
}
-/* ********************** Cut Link operator ***************** */
-static bool cut_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
+/* ********************** Node Link Intersect ***************** */
+static bool node_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
{
float coord_array[NODE_LINK_RESOL + 1][2];
@@ -1244,6 +1244,7 @@ static bool cut_links_intersect(bNodeLink *link, const float mcoords[][2], int t
return 0;
}
+/* ********************** Cut Link operator ***************** */
static int cut_links_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1276,7 +1277,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
continue;
}
- if (cut_links_intersect(link, mcoords, i)) {
+ if (node_links_intersect(link, mcoords, i)) {
if (found == false) {
/* TODO(sergey): Why did we kill jobs twice? */
@@ -1335,6 +1336,110 @@ void NODE_OT_links_cut(wmOperatorType *ot)
RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
+/* ********************** Mute links operator ***************** */
+
+static int mute_links_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+ ARegion *region = CTX_wm_region(C);
+ bool do_tag_update = false;
+
+ int i = 0;
+ float mcoords[256][2];
+ RNA_BEGIN (op->ptr, itemptr, "path") {
+ float loc[2];
+
+ RNA_float_get_array(&itemptr, "loc", loc);
+ UI_view2d_region_to_view(
+ &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
+ i++;
+ if (i >= 256) {
+ break;
+ }
+ }
+ RNA_END;
+
+ if (i > 1) {
+ ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+
+ /* Count intersected links and clear test flag. */
+ int tot = 0;
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (nodeLinkIsHidden(link)) {
+ continue;
+ }
+ link->flag &= ~NODE_LINK_TEST;
+ if (node_links_intersect(link, mcoords, i)) {
+ tot++;
+ }
+ }
+ if (tot == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Mute links. */
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (nodeLinkIsHidden(link) || (link->flag & NODE_LINK_TEST)) {
+ continue;
+ }
+
+ if (node_links_intersect(link, mcoords, i)) {
+ do_tag_update |= (do_tag_update ||
+ node_connected_to_output(bmain, snode->edittree, link->tonode));
+
+ snode_update(snode, link->tonode);
+ nodeMuteLinkToggle(snode->edittree, link);
+ }
+ }
+
+ /* Clear remaining test flags. */
+ LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
+ if (nodeLinkIsHidden(link)) {
+ continue;
+ }
+ link->flag &= ~NODE_LINK_TEST;
+ }
+
+ do_tag_update |= ED_node_is_geometry(snode);
+
+ ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+ snode_notify(C, snode);
+ if (do_tag_update) {
+ snode_dag_update(C, snode);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+}
+
+void NODE_OT_links_mute(wmOperatorType *ot)
+{
+ ot->name = "Mute Links";
+ ot->idname = "NODE_OT_links_mute";
+ ot->description = "Use the mouse to mute links";
+
+ ot->invoke = WM_gesture_lines_invoke;
+ ot->modal = WM_gesture_lines_modal;
+ ot->exec = mute_links_exec;
+ ot->cancel = WM_gesture_lines_cancel;
+
+ ot->poll = ED_operator_node_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* internal */
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_MUTE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+}
+
/* ********************** Detach links operator ***************** */
static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
index 4567429f645..9ce2a1be015 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
@@ -2,7 +2,7 @@
* 2D Quadratic Bezier thick line drawing
*/
-#define MID_VERTEX 57
+#define MID_VERTEX 65
/* u is position along the curve, defining the tangent space.
* v is "signed" distance (compressed to [0..1] range) from the pos in expand direction */
@@ -17,6 +17,7 @@ in vec2 P1;
in vec2 P2;
in vec2 P3;
in ivec4 colid_doarrow;
+in ivec2 domuted;
uniform vec4 colors[6];
@@ -24,6 +25,7 @@ uniform vec4 colors[6];
# define colEnd colors[colid_doarrow[1]]
# define colShadow colors[colid_doarrow[2]]
# define doArrow (colid_doarrow[3] != 0)
+# define doMuted (domuted[0] != 0)
#else
/* Single curve drawcall, use uniform. */
@@ -36,6 +38,7 @@ uniform vec2 bezierPts[4];
uniform vec4 colors[3];
uniform bool doArrow;
+uniform bool doMuted;
# define colShadow colors[0]
# define colStart colors[1]
@@ -90,13 +93,18 @@ void main(void)
/* Second pass */
finalColor = mix(colStart, colEnd, uv.x);
expand_dist *= 0.5;
+ if (doMuted) {
+ finalColor[3] = 0.65;
+ }
}
/* Expand into a line */
gl_Position.xy += exp_axis * expandSize * expand_dist;
- /* if arrow */
- if (expand.y != 1.0 && !doArrow) {
+ /* If the link is not muted or is not a reroute arrow the points are squashed to the center of
+ * the line. Magic numbers are defined in drawnode.c */
+ if ((expand.x == 1.0 && !doMuted) ||
+ (expand.y != 1.0 && (pos.x < 0.70 || pos.x > 0.71) && !doArrow)) {
gl_Position.xy *= 0.0;
}
}
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 06ee22b1452..acbe9da45fd 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -402,6 +402,7 @@ typedef struct bNodeLink {
#define NODE_LINK_VALID (1 << 1)
#define NODE_LINK_TEST (1 << 2) /* free test flag, undefined */
#define NODE_LINK_TEMP_HIGHLIGHT (1 << 3) /* Link is highlighted for picking. */
+#define NODE_LINK_MUTED (1 << 4) /* Link is muted. */
/* tree->edit_quality/tree->render_quality */
#define NTREE_QUALITY_HIGH 0
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 04ff181d9b5..fc1f692a8bf 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -10872,6 +10872,11 @@ static void rna_def_node_link(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Valid", "Link is valid");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL);
+ prop = RNA_def_property(srna, "is_muted", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_LINK_MUTED);
+ RNA_def_struct_ui_text(srna, "Muted", "Link is muted and can be ignored");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL);
+
prop = RNA_def_property(srna, "from_node", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "fromnode");
RNA_def_property_struct_type(prop, "Node");
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 6207a1bf024..dd9d0b6796a 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -71,7 +71,8 @@ void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack
static void node_init_input_index(bNodeSocket *sock, int *index)
{
/* Only consider existing link if from socket is valid! */
- if (sock->link && sock->link->fromsock && sock->link->fromsock->stack_index >= 0) {
+ if (sock->link && !(sock->link->flag & NODE_LINK_MUTED) && sock->link->fromsock &&
+ sock->link->fromsock->stack_index >= 0) {
sock->stack_index = sock->link->fromsock->stack_index;
}
else {
@@ -131,7 +132,7 @@ static struct bNodeStack *setup_stack(bNodeStack *stack,
}
/* don't mess with remote socket stacks, these are initialized by other nodes! */
- if (sock->link) {
+ if (sock->link && !(sock->link->flag & NODE_LINK_MUTED)) {
return ns;
}
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index a66b7b1d2fe..8d979ffac9c 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -77,6 +77,9 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
}
LISTBASE_FOREACH (bNodeLink *, blink, &btree->links) {
+ if (blink->flag & NODE_LINK_MUTED) {
+ continue;
+ }
OutputSocketRef &from_socket = this->find_output_socket(
node_mapping, blink->fromnode, blink->fromsock);
InputSocketRef &to_socket = this->find_input_socket(
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index a385cb7039f..3fb4d10979d 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -388,7 +388,7 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
if (is_group || is_group_output) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->link != NULL) {
+ if (socket->link != NULL && !(socket->link->flag & NODE_LINK_MUTED)) {
bNodeLink *link = socket->link;
/* Fix the case where the socket is actually converting the data. (see T71374)
* We only do the case of lossy conversion to float.*/
@@ -557,7 +557,7 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
/* Non-cycles node is used as an output. */
return false;
}
- if (displacement->link != NULL) {
+ if ((displacement->link != NULL) && !(displacement->link->flag & NODE_LINK_MUTED)) {
*r_node = displacement->link->fromnode;
*r_socket = displacement->link->fromsock;
*r_link = displacement->link;
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index d6e4a93f6a6..cdb7b591907 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -520,13 +520,37 @@ void wm_init_cursor_data(void)
BlenderCursor[WM_CURSOR_WAIT] = &WaitCursor;
END_CURSOR_BLOCK;
+ /********************** Mute Cursor ***********************/
+ BEGIN_CURSOR_BLOCK;
+ static char mute_bitmap[] = {
+ 0x00, 0x00, 0x22, 0x00, 0x14, 0x00, 0x08, 0x03, 0x14, 0x03, 0x22,
+ 0x03, 0x00, 0x03, 0x00, 0x03, 0xf8, 0x7c, 0xf8, 0x7c, 0x00, 0x03,
+ 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00,
+ };
+
+ static char mute_mask[] = {
+ 0x63, 0x00, 0x77, 0x00, 0x3e, 0x03, 0x1c, 0x03, 0x3e, 0x03, 0x77,
+ 0x03, 0x63, 0x03, 0x80, 0x07, 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0x07,
+ 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
+ };
+
+ static BCursor MuteCursor = {
+ mute_bitmap,
+ mute_mask,
+ 9,
+ 8,
+ true,
+ };
+
+ BlenderCursor[WM_CURSOR_MUTE] = &MuteCursor;
+ END_CURSOR_BLOCK;
+
/****************** Normal Cross Cursor ************************/
BEGIN_CURSOR_BLOCK;
static char cross_bitmap[] = {
0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
0x01, 0x00, 0x00, 0x3e, 0x7c, 0x3e, 0x7c, 0x00, 0x00, 0x80, 0x01,
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00,
-
};
static char cross_mask[] = {
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index b85616deda5..2842538ebf1 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -72,6 +72,7 @@ typedef enum WMCursorType {
WM_CURSOR_ZOOM_OUT,
WM_CURSOR_NONE,
+ WM_CURSOR_MUTE,
/* --- ALWAYS LAST ----- */
WM_CURSOR_NUM,