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
This commit is contained in:
parent
20bf736ff8
commit
266cd7bb82
|
@ -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 */
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -3843,6 +3851,25 @@ static void nodelink_batch_init(void)
|
|||
set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
®ion->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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -72,6 +72,7 @@ typedef enum WMCursorType {
|
|||
WM_CURSOR_ZOOM_OUT,
|
||||
|
||||
WM_CURSOR_NONE,
|
||||
WM_CURSOR_MUTE,
|
||||
|
||||
/* --- ALWAYS LAST ----- */
|
||||
WM_CURSOR_NUM,
|
||||
|
|
Loading…
Reference in New Issue