[Bf-blender-cvs] [56193eccf64] master: Cleanup: Refactor node add reroute operator

Hans Goudey noreply at git.blender.org
Sun Sep 4 06:50:06 CEST 2022


Commit: 56193eccf646e9e6e56c232d390ed6680ce1370c
Author: Hans Goudey
Date:   Sat Sep 3 14:12:55 2022 -0500
Branches: master
https://developer.blender.org/rB56193eccf646e9e6e56c232d390ed6680ce1370c

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.

===================================================================

M	source/blender/editors/space_node/node_add.cc
M	source/blender/editors/space_node/node_edit.cc
M	source/blender/editors/space_node/node_group.cc

===================================================================

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 &region = *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(&region.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 &region = *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(&region.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_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list