diff options
Diffstat (limited to 'source/blender/editors/space_node/node_relationships.cc')
-rw-r--r-- | source/blender/editors/space_node/node_relationships.cc | 360 |
1 files changed, 183 insertions, 177 deletions
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 3a8bb56bc5e..067c01dcc58 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -11,6 +11,7 @@ #include "DNA_node_types.h" #include "BLI_easing.h" +#include "BLI_stack.hh" #include "BKE_anim_data.h" #include "BKE_context.h" @@ -52,11 +53,6 @@ #include "node_intern.hh" /* own include */ -struct bNodeListItem { - struct bNodeListItem *next, *prev; - struct bNode *node; -}; - struct NodeInsertOfsData { bNodeTree *ntree; bNode *insert; /* inserted node */ @@ -77,6 +73,8 @@ static void clear_picking_highlight(ListBase *links) namespace blender::ed::space_node { +void update_multi_input_indices_for_removed_links(bNode &node); + /* -------------------------------------------------------------------- */ /** \name Add Node * \{ */ @@ -107,11 +105,9 @@ static void pick_link( nldrag.links.append(link); nodeRemLink(snode.edittree, &link_to_pick); - + snode.edittree->ensure_topology_cache(); BLI_assert(nldrag.last_node_hovered_while_dragging_a_link != nullptr); - - sort_multi_input_socket_links( - snode, *nldrag.last_node_hovered_while_dragging_a_link, nullptr, nullptr); + update_multi_input_indices_for_removed_links(*nldrag.last_node_hovered_while_dragging_a_link); /* Send changed event to original link->tonode. */ if (node) { @@ -125,10 +121,8 @@ static void pick_input_link_by_link_intersect(const bContext &C, const float2 &cursor) { SpaceNode *snode = CTX_wm_space_node(&C); - const ARegion *region = CTX_wm_region(&C); - const View2D *v2d = ®ion->v2d; - float drag_start[2]; + float2 drag_start; RNA_float_get_array(op.ptr, "drag_start", drag_start); bNode *node; bNodeSocket *socket; @@ -137,26 +131,16 @@ static void pick_input_link_by_link_intersect(const bContext &C, /* Distance to test overlapping of cursor on link. */ const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC; - const int resolution = NODE_LINK_RESOL; - bNodeLink *link_to_pick = nullptr; clear_picking_highlight(&snode->edittree->links); LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { if (link->tosock == socket) { /* Test if the cursor is near a link. */ - float vec[4][2]; - node_link_bezier_handles(v2d, snode, *link, vec); - - float data[NODE_LINK_RESOL * 2 + 2]; - BKE_curve_forward_diff_bezier( - vec[0][0], vec[1][0], vec[2][0], vec[3][0], data, resolution, sizeof(float[2])); - BKE_curve_forward_diff_bezier( - vec[0][1], vec[1][1], vec[2][1], vec[3][1], data + 1, resolution, sizeof(float[2])); - - for (int i = 0; i < resolution * 2; i += 2) { - float *l1 = &data[i]; - float *l2 = &data[i + 2]; - float distance = dist_squared_to_line_segment_v2(cursor, l1, l2); + std::array<float2, NODE_LINK_RESOL + 1> coords; + node_link_bezier_points_evaluated(*link, coords); + + for (const int i : IndexRange(coords.size() - 1)) { + const float distance = dist_squared_to_line_segment_v2(cursor, coords[i], coords[i + 1]); if (distance < cursor_link_touch_distance) { link_to_pick = link; nldrag.last_picked_multi_input_socket_link = link_to_pick; @@ -308,35 +292,24 @@ struct LinkAndPosition { float2 multi_socket_position; }; -void sort_multi_input_socket_links(SpaceNode &snode, - bNode &node, - bNodeLink *drag_link, - const float2 *cursor) +static void sort_multi_input_socket_links_with_drag(bNode &node, + bNodeLink &drag_link, + const float2 &cursor) { - LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) { - if (!(socket->flag & SOCK_MULTI_INPUT)) { + for (bNodeSocket *socket : node.input_sockets()) { + if (!socket->is_multi_input()) { continue; } - Vector<LinkAndPosition, 8> links; + const float2 &socket_location = {socket->locx, socket->locy}; - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (link->tosock == socket) { - links.append( - {link, - node_link_calculate_multi_input_position({link->tosock->locx, link->tosock->locy}, - link->multi_input_socket_index, - link->tosock->total_inputs)}); - } - } + Vector<LinkAndPosition, 8> links; + for (bNodeLink *link : socket->directly_linked_links()) { + const float2 location = node_link_calculate_multi_input_position( + socket_location, link->multi_input_socket_index, link->tosock->total_inputs); + links.append({link, location}); + }; - if (drag_link) { - LinkAndPosition link_and_position{}; - link_and_position.link = drag_link; - if (cursor) { - link_and_position.multi_socket_position = *cursor; - } - links.append(link_and_position); - } + links.append({&drag_link, cursor}); std::sort(links.begin(), links.end(), [](const LinkAndPosition a, const LinkAndPosition b) { return a.multi_socket_position.y < b.multi_socket_position.y; @@ -348,6 +321,23 @@ void sort_multi_input_socket_links(SpaceNode &snode, } } +void update_multi_input_indices_for_removed_links(bNode &node) +{ + for (bNodeSocket *socket : node.input_sockets()) { + if (!socket->is_multi_input()) { + continue; + } + Vector<bNodeLink *, 8> links = socket->directly_linked_links(); + std::sort(links.begin(), links.end(), [](const bNodeLink *a, const bNodeLink *b) { + return a->multi_input_socket_index < b->multi_input_socket_index; + }); + + for (const int i : links.index_range()) { + links[i]->multi_input_socket_index = i; + } + } +} + static void snode_autoconnect(SpaceNode &snode, const bool allow_multiple, const bool replace) { bNodeTree *ntree = snode.edittree; @@ -637,7 +627,8 @@ static int link_socket_to_viewer(const bContext &C, if (viewer_bnode == nullptr) { /* Create a new viewer node if none exists. */ const int viewer_type = get_default_viewer_type(&C); - const float2 location{bsocket_to_view.locx + 100, bsocket_to_view.locy}; + const float2 location{bsocket_to_view.locx / UI_DPI_FAC + 100, + bsocket_to_view.locy / UI_DPI_FAC}; viewer_bnode = add_static_node(C, viewer_type, location); if (viewer_bnode == nullptr) { return OPERATOR_CANCELLED; @@ -942,6 +933,7 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur if (nldrag->in_out == SOCK_OUT) { bNode *tnode; bNodeSocket *tsock = nullptr; + snode.edittree->ensure_topology_cache(); if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { for (bNodeLink *link : nldrag->links) { /* skip if socket is on the same node as the fromsock */ @@ -968,19 +960,19 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur continue; } if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) { - sort_multi_input_socket_links(snode, *tnode, link, &cursor); + sort_multi_input_socket_links_with_drag(*tnode, *link, cursor); } } } else { for (bNodeLink *link : nldrag->links) { - if (nldrag->last_node_hovered_while_dragging_a_link) { - sort_multi_input_socket_links( - snode, *nldrag->last_node_hovered_while_dragging_a_link, nullptr, &cursor); - } link->tonode = nullptr; link->tosock = nullptr; } + if (nldrag->last_node_hovered_while_dragging_a_link) { + update_multi_input_indices_for_removed_links( + *nldrag->last_node_hovered_while_dragging_a_link); + } } } else { @@ -1177,7 +1169,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) bool detach = RNA_boolean_get(op->ptr, "detach"); - int mval[2]; + int2 mval; WM_event_drag_start_mval(event, ®ion, mval); float2 cursor; @@ -1317,28 +1309,6 @@ void NODE_OT_link_make(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Node Link Intersect - * \{ */ - -static bool node_links_intersect(bNodeLink &link, const float mcoords[][2], int tot) -{ - float coord_array[NODE_LINK_RESOL + 1][2]; - - if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) { - for (int i = 0; i < tot - 1; i++) { - for (int b = 0; b < NODE_LINK_RESOL; b++) { - if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) { - return true; - } - } - } - } - return false; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Cut Link Operator * \{ */ @@ -1346,56 +1316,63 @@ static int cut_links_exec(bContext *C, wmOperator *op) { Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - ARegion ®ion = *CTX_wm_region(C); + const ARegion ®ion = *CTX_wm_region(C); - int i = 0; - float mcoords[256][2]; + Vector<float2> path; 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) { + float2 loc_region; + RNA_float_get_array(&itemptr, "loc", loc_region); + float2 loc_view; + UI_view2d_region_to_view(®ion.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y); + path.append(loc_view); + if (path.size() >= 256) { break; } } RNA_END; - if (i > 1) { - bool found = false; + if (path.is_empty()) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + bool found = false; - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; - } + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - if (node_links_intersect(*link, mcoords, i)) { + bNodeTree &node_tree = *snode.edittree; - if (found == false) { - /* TODO(sergey): Why did we kill jobs twice? */ - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - found = true; - } + Set<bNode *> affected_nodes; - bNode *to_node = link->tonode; - nodeRemLink(snode.edittree, link); - sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr); - } + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node_tree.links) { + if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { + continue; } - ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); - if (found) { - return OPERATOR_FINISHED; + if (link_path_intersection(*link, path)) { + + if (!found) { + /* TODO(sergey): Why did we kill jobs twice? */ + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + found = true; + } + + bNode *to_node = link->tonode; + nodeRemLink(snode.edittree, link); + affected_nodes.add(to_node); } + } - return OPERATOR_CANCELLED; + node_tree.ensure_topology_cache(); + for (bNode *node : affected_nodes) { + update_multi_input_indices_for_removed_links(*node); } - return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); + if (found) { + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; } void NODE_OT_links_cut(wmOperatorType *ot) @@ -1429,69 +1406,99 @@ void NODE_OT_links_cut(wmOperatorType *ot) /** \name Mute Links Operator * \{ */ +static bool all_links_muted(const bNodeSocket &socket) +{ + for (const bNodeLink *link : socket.directly_linked_links()) { + if (!(link->flag & NODE_LINK_MUTED)) { + return false; + } + } + return true; +} + static int mute_links_exec(bContext *C, wmOperator *op) { Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); - ARegion ®ion = *CTX_wm_region(C); + const ARegion ®ion = *CTX_wm_region(C); + bNodeTree &ntree = *snode.edittree; - int i = 0; - float mcoords[256][2]; + Vector<float2> path; 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) { + float2 loc_region; + RNA_float_get_array(&itemptr, "loc", loc_region); + float2 loc_view; + UI_view2d_region_to_view(®ion.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y); + path.append(loc_view); + if (path.size() >= 256) { break; } } RNA_END; - if (i > 1) { - ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + if (path.is_empty()) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } - /* Count intersected links and clear test flag. */ - int tot = 0; - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; - } - link->flag &= ~NODE_LINK_TEST; - if (node_links_intersect(*link, mcoords, i)) { - tot++; - } + ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); + + ntree.ensure_topology_cache(); + + Set<bNodeLink *> affected_links; + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { + continue; } - if (tot == 0) { - return OPERATOR_CANCELLED; + if (!link_path_intersection(*link, path)) { + continue; } + affected_links.add(link); + } - /* Mute links. */ - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link) || (link->flag & NODE_LINK_TEST)) { - continue; - } + if (affected_links.is_empty()) { + return OPERATOR_CANCELLED; + } - if (node_links_intersect(*link, mcoords, i)) { - nodeMuteLinkToggle(snode.edittree, link); + bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree}; + + for (bNodeLink *link : affected_links) { + nodeLinkSetMute(&ntree, link, !(link->flag & NODE_LINK_MUTED)); + const bool muted = link->flag & NODE_LINK_MUTED; + + /* Propagate mute status downsteam past reroute nodes. */ + if (link->tonode->is_reroute()) { + Stack<bNodeLink *> links; + links.push_multiple(link->tonode->output_sockets().first()->directly_linked_links()); + while (!links.is_empty()) { + bNodeLink *link = links.pop(); + nodeLinkSetMute(&ntree, link, muted); + if (!link->tonode->is_reroute()) { + continue; + } + links.push_multiple(link->tonode->output_sockets().first()->directly_linked_links()); } } - - /* Clear remaining test flags. */ - LISTBASE_FOREACH (bNodeLink *, link, &snode.edittree->links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; + /* Propagate mute status upstream past reroutes, but only if all outputs are muted. */ + if (link->fromnode->is_reroute()) { + if (!muted || all_links_muted(*link->fromsock)) { + Stack<bNodeLink *> links; + links.push_multiple(link->fromnode->input_sockets().first()->directly_linked_links()); + while (!links.is_empty()) { + bNodeLink *link = links.pop(); + nodeLinkSetMute(&ntree, link, muted); + if (!link->fromnode->is_reroute()) { + continue; + } + if (!muted || all_links_muted(*link->fromsock)) { + links.push_multiple(link->fromnode->input_sockets().first()->directly_linked_links()); + } + } } - link->flag &= ~NODE_LINK_TEST; } - - ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); - return OPERATOR_FINISHED; } - return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); + return OPERATOR_FINISHED; } void NODE_OT_links_mute(wmOperatorType *ot) @@ -1707,11 +1714,11 @@ void NODE_OT_join(wmOperatorType *ot) static bNode *node_find_frame_to_attach(ARegion ®ion, const bNodeTree &ntree, - const int mouse_xy[2]) + const int2 mouse_xy) { /* convert mouse coordinates to v2d space */ - float cursor[2]; - UI_view2d_region_to_view(®ion.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]); + float2 cursor; + UI_view2d_region_to_view(®ion.v2d, mouse_xy.x, mouse_xy.y, &cursor.x, &cursor.y); LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) { /* skip selected, those are the nodes we want to attach */ @@ -1935,6 +1942,7 @@ static bool ed_node_link_conditions(ScrArea *area, void ED_node_link_intersect_test(ScrArea *area, int test) { + using namespace blender; using namespace blender::ed::space_node; bNode *select; @@ -1958,36 +1966,34 @@ void ED_node_link_intersect_test(ScrArea *area, int test) bNodeLink *selink = nullptr; float dist_best = FLT_MAX; LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - float coord_array[NODE_LINK_RESOL + 1][2]; if (node_link_is_hidden_or_dimmed(region->v2d, *link)) { continue; } - if (node_link_bezier_points(nullptr, nullptr, *link, coord_array, NODE_LINK_RESOL)) { - float dist = FLT_MAX; + std::array<float2, NODE_LINK_RESOL + 1> coords; + node_link_bezier_points_evaluated(*link, coords); + float dist = FLT_MAX; - /* loop over link coords to find shortest dist to - * upper left node edge of a intersected line segment */ - for (int i = 0; i < NODE_LINK_RESOL; i++) { - /* Check if the node rectangle intersects the line from this point to next one. */ - if (BLI_rctf_isect_segment(&select->totr, coord_array[i], coord_array[i + 1])) { - /* store the shortest distance to the upper left edge - * of all intersections found so far */ - const float node_xy[] = {select->totr.xmin, select->totr.ymax}; + /* loop over link coords to find shortest dist to + * upper left node edge of a intersected line segment */ + for (int i = 0; i < NODE_LINK_RESOL; i++) { + /* Check if the node rectangle intersects the line from this point to next one. */ + if (BLI_rctf_isect_segment(&select->totr, coords[i], coords[i + 1])) { + /* store the shortest distance to the upper left edge + * of all intersections found so far */ + const float node_xy[] = {select->totr.xmin, select->totr.ymax}; - /* to be precise coord_array should be clipped by select->totr, - * but not done since there's no real noticeable difference */ - dist = min_ff( - dist_squared_to_line_segment_v2(node_xy, coord_array[i], coord_array[i + 1]), dist); - } + /* to be precise coords should be clipped by select->totr, + * but not done since there's no real noticeable difference */ + dist = min_ff(dist_squared_to_line_segment_v2(node_xy, coords[i], coords[i + 1]), dist); } + } - /* we want the link with the shortest distance to node center */ - if (dist < dist_best) { - dist_best = dist; - selink = link; - } + /* we want the link with the shortest distance to node center */ + if (dist < dist_best) { + dist_best = dist; + selink = link; } } |