diff options
author | Hans Goudey <h.goudey@me.com> | 2022-09-03 22:12:55 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-09-03 22:19:09 +0300 |
commit | 56193eccf646e9e6e56c232d390ed6680ce1370c (patch) | |
tree | cba72095f93530c42f070d070b6ae98ea985ef4b /source/blender/editors/space_node | |
parent | 4b818b151329516df55b5d9a1fbcc21ec3b73e7a (diff) |
Cleanup: Refactor node add reroute operator
Use C++ Map that supports the duplication natively. Use vectors instead
of linked lists, and adjust naming. Also remove combination of reroutes
for input sockets, which doesn't make sense since a reroute isn't
allowed to combine multiple input links into one output.
Diffstat (limited to 'source/blender/editors/space_node')
-rw-r--r-- | source/blender/editors/space_node/node_add.cc | 231 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_edit.cc | 16 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_group.cc | 3 |
3 files changed, 85 insertions, 165 deletions
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index c5a9df54a82..79d8b4fe52e 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -5,6 +5,8 @@ * \ingroup spnode */ +#include <numeric> + #include "MEM_guardedalloc.h" #include "DNA_collection_types.h" @@ -20,6 +22,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -101,195 +104,113 @@ bNode *add_static_node(const bContext &C, int type, const float2 &location) /** \name Add Reroute Operator * \{ */ -static bool add_reroute_intersect_check(const bNodeLink &link, - float mcoords[][2], - int tot, - float2 &result) +static std::optional<float2> path_link_intersection(const bNodeLink &link, const Span<float2> path) { std::array<float2, NODE_LINK_RESOL + 1> coords; node_link_bezier_points_evaluated(link, coords); - for (int i = 0; i < tot - 1; i++) { - for (int b = 0; b < NODE_LINK_RESOL; b++) { - if (isect_seg_seg_v2_point(mcoords[i], mcoords[i + 1], coords[b], coords[b + 1], result) > - 0) { - return true; + for (const int i : path.index_range().drop_back(1)) { + for (const int j : IndexRange(NODE_LINK_RESOL)) { + float2 result; + if (isect_seg_seg_v2_point(path[i], path[i + 1], coords[j], coords[j + 1], result) > 0) { + return result; } } } - return false; + return std::nullopt; } -struct bNodeSocketLink { - struct bNodeSocketLink *next, *prev; - - bNodeSocket *sock; - bNodeLink *link; - float2 point; +struct RerouteCutsForSocket { + /* The output socket's owner node. */ + bNode *from_node; + /* Intersected links connected to the socket and their path intersection locations. */ + Map<bNodeLink *, float2> links; }; -static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb, - bNodeSocket *sock, - bNodeLink *link, - const float2 &point) +static int add_reroute_exec(bContext *C, wmOperator *op) { - bNodeSocketLink *socklink, *prev; - - socklink = MEM_cnew<bNodeSocketLink>("socket link"); - socklink->sock = sock; - socklink->link = link; - copy_v2_v2(socklink->point, point); + const ARegion ®ion = *CTX_wm_region(C); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; - for (prev = (bNodeSocketLink *)lb->last; prev; prev = prev->prev) { - if (prev->sock == sock) { + Vector<float2> path; + RNA_BEGIN (op->ptr, itemptr, "path") { + 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; } } - BLI_insertlinkafter(lb, prev, socklink); - return socklink; -} - -static bNodeSocketLink *add_reroute_do_socket_section(bContext *C, - bNodeSocketLink *socklink, - int in_out) -{ - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; - bNode *reroute_node = nullptr; - bNodeSocket *cursock = socklink->sock; - float2 insert_point{0.0f, 0.0f}; - int num_links; - - num_links = 0; - - while (socklink && socklink->sock == cursock) { - if (!(socklink->link->flag & NODE_LINK_TEST)) { - socklink->link->flag |= NODE_LINK_TEST; - - /* create the reroute node for this cursock */ - if (!reroute_node) { - reroute_node = nodeAddStaticNode(C, ntree, NODE_REROUTE); - - /* add a single link to/from the reroute node to replace multiple links */ - if (in_out == SOCK_OUT) { - nodeAddLink(ntree, - socklink->link->fromnode, - socklink->link->fromsock, - reroute_node, - (bNodeSocket *)reroute_node->inputs.first); - } - else { - nodeAddLink(ntree, - reroute_node, - (bNodeSocket *)reroute_node->outputs.first, - socklink->link->tonode, - socklink->link->tosock); - } - } - - /* insert the reroute node into the link */ - if (in_out == SOCK_OUT) { - socklink->link->fromnode = reroute_node; - socklink->link->fromsock = (bNodeSocket *)reroute_node->outputs.first; - } - else { - socklink->link->tonode = reroute_node; - socklink->link->tosock = (bNodeSocket *)reroute_node->inputs.first; - } + RNA_END; - insert_point += socklink->point; - num_links++; - } - socklink = socklink->next; + if (path.is_empty()) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } - if (num_links > 0) { - /* average cut point from shared links */ - mul_v2_fl(insert_point, 1.0f / num_links); - - reroute_node->locx = insert_point[0] / UI_DPI_FAC; - reroute_node->locy = insert_point[1] / UI_DPI_FAC; - - LISTBASE_FOREACH_BACKWARD (bNode *, frame_node, &ntree->nodes) { - if (frame_node->type == NODE_FRAME && BLI_rctf_isect_pt_v(&frame_node->totr, insert_point)) { - nodeAttachNode(reroute_node, frame_node); - break; - } - } - } + ntree.ensure_topology_cache(); + const Vector<bNode *> frame_nodes = ntree.nodes_by_type("NodeFrame"); - return socklink; -} + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + node_deselect_all(snode); -static int add_reroute_exec(bContext *C, wmOperator *op) -{ - SpaceNode &snode = *CTX_wm_space_node(C); - ARegion ®ion = *CTX_wm_region(C); - bNodeTree &ntree = *snode.edittree; - float mcoords[256][2]; - int i = 0; + /* All link "cuts" that start at a particular output socket. Deduplicating new reroutes per + * output socket is useful because it allows reusing reroutes for connected intersections. + * Further deduplication using the second map means we only have one cut per link.*/ + Map<bNodeSocket *, RerouteCutsForSocket> cuts_per_socket; - /* Get the cut path */ - RNA_BEGIN (op->ptr, itemptr, "path") { - float2 loc; - RNA_float_get_array(&itemptr, "loc", loc); - UI_view2d_region_to_view(®ion.v2d, loc.x, loc.y, &mcoords[i][0], &mcoords[i][1]); - i++; - if (i >= 256) { - break; + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { + continue; + } + const std::optional<float2> intersection = path_link_intersection(*link, path); + if (!intersection) { + continue; } + RerouteCutsForSocket &from_cuts = cuts_per_socket.lookup_or_add_default(link->fromsock); + from_cuts.from_node = link->fromnode; + from_cuts.links.add(link, *intersection); } - RNA_END; - if (i > 1) { - ListBase output_links, input_links; - bNodeSocketLink *socklink; + for (const auto item : cuts_per_socket.items()) { + const Map<bNodeLink *, float2> &cuts = item.value.links; - /* always first */ - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + bNode *reroute = nodeAddStaticNode(C, &ntree, NODE_REROUTE); - node_deselect_all(snode); + nodeAddLink(&ntree, + item.value.from_node, + item.key, + reroute, + static_cast<bNodeSocket *>(reroute->inputs.first)); - /* Find cut links and sort them by sockets */ - BLI_listbase_clear(&output_links); - BLI_listbase_clear(&input_links); - - LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { - if (node_link_is_hidden_or_dimmed(region.v2d, *link)) { - continue; - } - float2 insert_point; - if (add_reroute_intersect_check(*link, mcoords, i, insert_point)) { - add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point); - add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point); - - /* Clear flag */ - link->flag &= ~NODE_LINK_TEST; - } + /* Reconnect links from the original output socket to the new reroute. */ + for (bNodeLink *link : cuts.keys()) { + link->fromnode = reroute; + link->fromsock = static_cast<bNodeSocket *>(reroute->outputs.first); + BKE_ntree_update_tag_link_changed(&ntree); } - /* Create reroute nodes for intersected links. - * Only one reroute if links share the same input/output socket. - */ - socklink = (bNodeSocketLink *)output_links.first; - while (socklink) { - socklink = add_reroute_do_socket_section(C, socklink, SOCK_OUT); - } - socklink = (bNodeSocketLink *)input_links.first; - while (socklink) { - socklink = add_reroute_do_socket_section(C, socklink, SOCK_IN); + /* Place the new reroute at the average location of all connected cuts. */ + const float2 loc = std::accumulate(cuts.values().begin(), cuts.values().end(), float2(0)) / + cuts.size() / UI_DPI_FAC; + reroute->locx = loc.x; + reroute->locy = loc.y; + + /* Attach the reroute node to frame nodes behind it. */ + for (const int i : frame_nodes.index_range()) { + bNode *frame_node = frame_nodes.last(i); + if (BLI_rctf_isect_pt_v(&frame_node->totr, loc)) { + nodeAttachNode(reroute, frame_node); + break; + } } - - BLI_freelistN(&output_links); - BLI_freelistN(&input_links); - - /* always last */ - ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); - 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_add_reroute(wmOperatorType *ot) diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index c3dea0b8a57..5f92e514385 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -1367,7 +1367,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) bNode *lastnode = (bNode *)ntree->nodes.last; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { - bNode *new_node = blender::bke::node_copy_with_mapping( + bNode *new_node = bke::node_copy_with_mapping( ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); node_map.add_new(node, new_node); changed = true; @@ -2234,12 +2234,12 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) if (node->flag & SELECT) { /* No ID refcounting, this node is virtual, * detached from any actual Blender data currently. */ - bNode *new_node = blender::bke::node_copy_with_mapping(nullptr, - *node, - LIB_ID_CREATE_NO_USER_REFCOUNT | - LIB_ID_CREATE_NO_MAIN, - false, - socket_map); + bNode *new_node = bke::node_copy_with_mapping(nullptr, + *node, + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_MAIN, + false, + socket_map); node_map.add_new(node, new_node); } } @@ -2372,7 +2372,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) /* copy nodes from clipboard */ LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { - bNode *new_node = blender::bke::node_copy_with_mapping( + bNode *new_node = bke::node_copy_with_mapping( ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); node_map.add_new(node, new_node); } diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 0edeac574df..482b2864d58 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -462,8 +462,7 @@ static bool node_group_separate_selected( bNode *newnode; if (make_copy) { /* make a copy */ - newnode = blender::bke::node_copy_with_mapping( - &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + newnode = bke::node_copy_with_mapping(&ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map); node_map.add_new(node, newnode); } else { |