[Bf-blender-cvs] [8f707a72e81] master: UI: Multi-input node socket spacing and interaction

Fabian Schempp noreply at git.blender.org
Thu Feb 11 08:16:33 CET 2021


Commit: 8f707a72e81833bb835324ddc635b29dfbe87a9f
Author: Fabian Schempp
Date:   Thu Feb 11 01:16:17 2021 -0600
Branches: master
https://developer.blender.org/rB8f707a72e81833bb835324ddc635b29dfbe87a9f

UI: Multi-input node socket spacing and interaction

This commit makes links connected to multi-input sockets spread verticaly
along the socket. Sockets grow if more links are connected and the node
layout updates accordingly. Links are sorted by their incoming angle
to avoid crossing links. Also, link picking is updated to work with
spread links and bezier links.

Currently the multi-input sockets are used in the join geometry node.

The mutli-input sockets look like a vertical rounded rectangle.
Currently they do not support the other custom socket shapes.

Reviewed By Hans Goudey, with cleanup and additional edits

Differential Revision: https://developer.blender.org/D10181

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

M	source/blender/blenkernel/intern/node.cc
M	source/blender/editors/space_node/drawnode.c
M	source/blender/editors/space_node/node_draw.c
M	source/blender/editors/space_node/node_edit.c
M	source/blender/editors/space_node/node_intern.h
M	source/blender/editors/space_node/node_relationships.c
M	source/blender/makesdna/DNA_node_types.h

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

diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index ed8dd84a9bb..e34afd1ce17 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -573,6 +573,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
   sock->typeinfo = nullptr;
   BLO_read_data_address(reader, &sock->storage);
   BLO_read_data_address(reader, &sock->default_value);
+  sock->total_inputs = 0; /* Clear runtime data set before drawing. */
   sock->cache = nullptr;
 }
 
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 2d65302c656..4716f1c29ea 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3560,10 +3560,10 @@ void draw_nodespace_back_pix(const bContext *C,
 }
 
 /* return quadratic beziers points for a given nodelink and clip if v2d is not NULL. */
-static bool node_link_bezier_handles(const View2D *v2d,
-                                     const SpaceNode *snode,
-                                     const bNodeLink *link,
-                                     float vec[4][2])
+bool node_link_bezier_handles(const View2D *v2d,
+                              const SpaceNode *snode,
+                              const bNodeLink *link,
+                              float vec[4][2])
 {
   float cursor[2] = {0.0f, 0.0f};
 
@@ -3591,6 +3591,9 @@ static bool node_link_bezier_handles(const View2D *v2d,
   if (link->tosock) {
     vec[3][0] = link->tosock->locx;
     vec[3][1] = link->tosock->locy;
+    if (!(link->tonode->flag & NODE_HIDDEN) && link->tosock->flag & SOCK_MULTI_INPUT) {
+      node_link_calculate_multi_input_position(link, vec[3]);
+    }
     toreroute = (link->tonode && link->tonode->type == NODE_REROUTE);
   }
   else {
@@ -3902,7 +3905,7 @@ void node_draw_link_bezier(const View2D *v2d,
                            int th_col3)
 {
   float vec[4][2];
-
+  const bool highlighted = link->flag & NODE_LINK_TEMP_HIGHLIGHT;
   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)));
@@ -3911,7 +3914,7 @@ void node_draw_link_bezier(const View2D *v2d,
       nodelink_batch_init();
     }
 
-    if (g_batch_link.enabled) {
+    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);
@@ -3925,6 +3928,12 @@ void node_draw_link_bezier(const View2D *v2d,
       UI_GetThemeColor4fv(th_col1, colors[1]);
       UI_GetThemeColor4fv(th_col2, colors[2]);
 
+      if (highlighted) {
+        float link_preselection_highlight_color[4];
+        UI_GetThemeColor4fv(TH_SELECT, link_preselection_highlight_color);
+        copy_v4_v4(colors[2], link_preselection_highlight_color);
+      }
+
       GPUBatch *batch = g_batch_link.batch_single;
       GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
       GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 4dd945c4cf1..9ef914af75b 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -22,6 +22,8 @@
  * \brief higher level node drawing for the node editor.
  */
 
+#include "MEM_guardedalloc.h"
+
 #include "DNA_light_types.h"
 #include "DNA_linestyle_types.h"
 #include "DNA_material_types.h"
@@ -500,6 +502,16 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
     PointerRNA sockptr;
     RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr);
 
+    /* Add the half the height of a multi-input socket to cursor Y
+     * to account for the increased height of the taller sockets. */
+    float multi_input_socket_offset = 0.0f;
+    if (nsock->flag & SOCK_MULTI_INPUT) {
+      if (nsock->total_inputs > 2) {
+        multi_input_socket_offset = (nsock->total_inputs - 2) * NODE_MULTI_INPUT_LINK_GAP;
+      }
+    }
+    dy -= multi_input_socket_offset * 0.5f;
+
     uiLayout *layout = UI_block_layout(node->block,
                                        UI_LAYOUT_VERTICAL,
                                        UI_LAYOUT_PANEL,
@@ -533,7 +545,7 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node)
     /* place the socket circle in the middle of the layout */
     nsock->locy = 0.5f * (dy + buty);
 
-    dy = buty;
+    dy = buty - multi_input_socket_offset * 0.5;
     if (nsock->next) {
       dy -= NODE_SOCKDY;
     }
@@ -751,6 +763,27 @@ static void node_socket_draw(const bNodeSocket *sock,
   immVertex2f(pos_id, locx, locy);
 }
 
+static void node_socket_draw_multi_input(const float color[4],
+                                         const float color_outline[4],
+                                         const float width,
+                                         const float height,
+                                         const int locx,
+                                         const int locy)
+{
+  const float outline_width = 1.0f;
+  /* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */
+  const rctf rect = {
+      .xmin = locx - width + outline_width * 0.5f,
+      .xmax = locx + width - outline_width * 0.5f,
+      .ymin = locy - height + outline_width * 0.5f,
+      .ymax = locy + height - outline_width * 0.5f,
+  };
+
+  UI_draw_roundbox_corner_set(UI_CNR_ALL);
+  UI_draw_roundbox_4fv_ex(
+      &rect, color, NULL, 1.0f, color_outline, outline_width, width - outline_width * 0.5f);
+}
+
 static void node_socket_outline_color_get(bool selected, float r_outline_color[4])
 {
   if (selected) {
@@ -1006,6 +1039,10 @@ void node_draw_sockets(const View2D *v2d,
       selected_input_len++;
       continue;
     }
+    /* Don't draw multi-input sockets here since they are drawn in a different batch. */
+    if (sock->flag & SOCK_MULTI_INPUT) {
+      continue;
+    }
 
     node_socket_draw_nested(C,
                             ntree,
@@ -1115,6 +1152,28 @@ void node_draw_sockets(const View2D *v2d,
 
   GPU_program_point_size(false);
   GPU_blend(GPU_BLEND_NONE);
+
+  /* Draw multi-nput sockets after the others because they are drawn with "UI_roundbox"
+   * rather than with GL_POINT. */
+  LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+    if (nodeSocketIsHidden(socket)) {
+      continue;
+    }
+    if (!(socket->flag & SOCK_MULTI_INPUT)) {
+      continue;
+    }
+
+    const bool is_node_hidden = (node->flag & NODE_HIDDEN);
+    const float width = NODE_SOCKSIZE;
+    float height = is_node_hidden ? width : node_socket_calculate_height(socket) - width;
+
+    float color[4];
+    float outline_color[4];
+    node_socket_color_get((bContext *)C, ntree, &node_ptr, socket, color);
+    node_socket_outline_color_get(selected, outline_color);
+
+    node_socket_draw_multi_input(color, outline_color, width, height, socket->locx, socket->locy);
+  }
 }
 
 static void node_draw_basis(const bContext *C,
@@ -1590,17 +1649,67 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
   }
 }
 
+static void count_mutli_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
+{
+  LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+    LISTBASE_FOREACH (struct bNodeSocket *, socket, &node->inputs) {
+      if (socket->flag & SOCK_MULTI_INPUT) {
+        socket->total_inputs = 0;
+        LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+          if (link->tosock == socket) {
+            socket->total_inputs++;
+          }
+        }
+        /* Count temporary links going into this socket. */
+        LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) {
+          LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
+            bNodeLink *link = (bNodeLink *)linkdata->data;
+            if (link->tosock == socket) {
+              socket->total_inputs++;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
 void node_update_nodetree(const bContext *C, bNodeTree *ntree)
 {
   /* make sure socket "used" tags are correct, for displaying value buttons */
+  SpaceNode *snode = CTX_wm_space_node(C);
   ntreeTagUsedSockets(ntree);
 
+  count_mutli_input_socket_links(ntree, snode);
+
   /* update nodes front to back, so children sizes get updated before parents */
   LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
     node_update(C, ntree, node);
   }
 }
 
+static int compare_link_by_angle_to_node(const void *a, const void *b)
+{
+  const bNodeLink *link_a = *(const bNodeLink **)a;
+  const bNodeLink *link_b = *(const bNodeLink **)b;
+
+  BLI_assert(link_a->tosock == link_b->tosock);
+  const float socket_location[2] = {link_a->tosock->locx, link_a->tosock->locy};
+  const float up_direction[2] = {0.0f, 1.0f};
+
+  float delta_a[2] = {link_a->fromsock->locx - socket_location[0],
+                      link_a->fromsock->locy - socket_location[1]};
+  normalize_v2(delta_a);
+  const float angle_a = angle_normalized_v2v2(up_direction, delta_a);
+
+  float delta_b[2] = {link_b->fromsock->locx - socket_location[0],
+                      link_b->fromsock->locy - socket_location[1]};
+  normalize_v2(delta_b);
+  const float angle_b = angle_normalized_v2v2(up_direction, delta_b);
+
+  return angle_a < angle_b ? 1 : -1;
+}
+
 static void node_draw(const bContext *C,
                       ARegion *region,
                       SpaceNode *snode,
@@ -1615,6 +1724,46 @@ static void node_draw(const bContext *C,
 
 #define USE_DRAW_TOT_UPDATE
 
+/**
+ * Automatically sort the input links to multi-input sockets to avoid crossing noodles.
+ */
+static void sort_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode)
+{
+  LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+    LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+      if (socket->flag & SOCK_MULTI_INPUT) {
+        /* The total is calculated in #node_update_nodetree, w

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list