[Bf-blender-cvs] [271f34f77e0] master: Geometry Nodes: initial socket inspection

Jacques Lucke noreply at git.blender.org
Wed Jul 14 11:22:37 CEST 2021


Commit: 271f34f77e056611e5e227b60823dd94f76340df
Author: Jacques Lucke
Date:   Wed Jul 14 11:16:43 2021 +0200
Branches: master
https://developer.blender.org/rB271f34f77e056611e5e227b60823dd94f76340df

Geometry Nodes: initial socket inspection

Socket inspection helps with debugging a geometry node group.
Now, when hovering over a socket, a tooltip will appear that provides
information about the data in the socket. Note, socket inspection only
works for sockets that have been computed already. Nodes that are not
connected to an output are not computed.

Future improvements can include ui changes to make the tooltip look
more like in the original design (T85251). Furthermore, additional
information could be shown if necessary.

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

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

M	source/blender/editors/space_node/node_draw.cc
M	source/blender/nodes/NOD_geometry_nodes_eval_log.hh
M	source/blender/nodes/intern/geometry_nodes_eval_log.cc

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

diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index d4f178603b8..7eca5c0c933 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -45,6 +45,7 @@
 #include "BLT_translation.h"
 
 #include "BKE_context.h"
+#include "BKE_idtype.h"
 #include "BKE_lib_id.h"
 #include "BKE_main.h"
 #include "BKE_node.h"
@@ -826,6 +827,149 @@ void node_socket_color_get(
   }
 }
 
+struct SocketTooltipData {
+  bNodeTree *ntree;
+  bNode *node;
+  bNodeSocket *socket;
+};
+
+static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log,
+                                                       std::stringstream &ss)
+{
+  auto id_to_inspection_string = [&](ID *id) {
+    ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(GS(id->name))
+       << ")";
+  };
+
+  const GPointer value = value_log.value();
+  if (value.is_type<int>()) {
+    ss << *value.get<int>() << TIP_(" (Integer)");
+  }
+  else if (value.is_type<float>()) {
+    ss << *value.get<float>() << TIP_(" (Float)");
+  }
+  else if (value.is_type<blender::float3>()) {
+    ss << *value.get<blender::float3>() << TIP_(" (Vector)");
+  }
+  else if (value.is_type<bool>()) {
+    ss << (*value.get<bool>() ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+  }
+  else if (value.is_type<std::string>()) {
+    ss << *value.get<std::string>() << TIP_(" (String)");
+  }
+  else if (value.is_type<Object *>()) {
+    id_to_inspection_string((ID *)*value.get<Object *>());
+  }
+  else if (value.is_type<Material *>()) {
+    id_to_inspection_string((ID *)*value.get<Material *>());
+  }
+  else if (value.is_type<Tex *>()) {
+    id_to_inspection_string((ID *)*value.get<Tex *>());
+  }
+  else if (value.is_type<Collection *>()) {
+    id_to_inspection_string((ID *)*value.get<Collection *>());
+  }
+}
+
+static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
+                                                  std::stringstream &ss)
+{
+  Span<GeometryComponentType> component_types = value_log.component_types();
+  if (component_types.is_empty()) {
+    ss << TIP_("Empty Geometry");
+    return;
+  }
+
+  auto to_string = [](int value) {
+    char str[16];
+    BLI_str_format_int_grouped(str, value);
+    return std::string(str);
+  };
+
+  ss << TIP_("Geometry:\n");
+  for (GeometryComponentType type : component_types) {
+    const char *line_end = (type == component_types.last()) ? "" : ".\n";
+    switch (type) {
+      case GEO_COMPONENT_TYPE_MESH: {
+        const geo_log::GeometryValueLog::MeshInfo &mesh_info = *value_log.mesh_info;
+        char line[256];
+        BLI_snprintf(line,
+                     sizeof(line),
+                     TIP_("\u2022 Mesh: %s vertices, %s edges, %s faces"),
+                     to_string(mesh_info.tot_verts).c_str(),
+                     to_string(mesh_info.tot_edges).c_str(),
+                     to_string(mesh_info.tot_faces).c_str());
+        ss << line << line_end;
+        break;
+      }
+      case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+        const geo_log::GeometryValueLog::PointCloudInfo &pointcloud_info =
+            *value_log.pointcloud_info;
+        char line[256];
+        BLI_snprintf(line,
+                     sizeof(line),
+                     TIP_("\u2022 Point Cloud: %s points"),
+                     to_string(pointcloud_info.tot_points).c_str());
+        ss << line << line_end;
+        break;
+      }
+      case GEO_COMPONENT_TYPE_CURVE: {
+        const geo_log::GeometryValueLog::CurveInfo &curve_info = *value_log.curve_info;
+        char line[256];
+        BLI_snprintf(line,
+                     sizeof(line),
+                     TIP_("\u2022 Curve: %s splines"),
+                     to_string(curve_info.tot_splines).c_str());
+        ss << line << line_end;
+        break;
+      }
+      case GEO_COMPONENT_TYPE_INSTANCES: {
+        const geo_log::GeometryValueLog::InstancesInfo &instances_info = *value_log.instances_info;
+        char line[256];
+        BLI_snprintf(line,
+                     sizeof(line),
+                     TIP_("\u2022 Instances: %s"),
+                     to_string(instances_info.tot_instances).c_str());
+        ss << line << line_end;
+        break;
+      }
+      case GEO_COMPONENT_TYPE_VOLUME: {
+        ss << TIP_("\u2022 Volume") << line_end;
+        break;
+      }
+    }
+  }
+}
+
+static std::optional<std::string> create_socket_inspection_string(bContext *C,
+                                                                  bNodeTree &UNUSED(ntree),
+                                                                  bNode &node,
+                                                                  bNodeSocket &socket)
+{
+  SpaceNode *snode = CTX_wm_space_node(C);
+  const geo_log::SocketLog *socket_log = geo_log::ModifierLog::find_socket_by_node_editor_context(
+      *snode, node, socket);
+  if (socket_log == nullptr) {
+    return {};
+  }
+  const geo_log::ValueLog *value_log = socket_log->value();
+  if (value_log == nullptr) {
+    return {};
+  }
+
+  std::stringstream ss;
+  if (const geo_log::GenericValueLog *generic_value_log =
+          dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
+    create_inspection_string_for_generic_value(*generic_value_log, ss);
+  }
+  else if (const geo_log::GeometryValueLog *geo_value_log =
+               dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
+    create_inspection_string_for_geometry(*geo_value_log, ss);
+  }
+
+  return ss.str();
+}
+
 static void node_socket_draw_nested(const bContext *C,
                                     bNodeTree *ntree,
                                     PointerRNA *node_ptr,
@@ -855,6 +999,55 @@ static void node_socket_draw_nested(const bContext *C,
                    shape_id,
                    size_id,
                    outline_col_id);
+
+  if (ntree->type != NTREE_GEOMETRY) {
+    /* Only geometry nodes has socket value tooltips currently. */
+    return;
+  }
+
+  bNode *node = (bNode *)node_ptr->data;
+  uiBlock *block = node->block;
+
+  /* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
+   * button on top of them for the tooltip. */
+  const eUIEmbossType old_emboss = UI_block_emboss_get(block);
+  UI_block_emboss_set(block, UI_EMBOSS_NONE);
+  uiBut *but = uiDefIconBut(block,
+                            UI_BTYPE_BUT,
+                            0,
+                            ICON_NONE,
+                            sock->locx - size / 2,
+                            sock->locy - size / 2,
+                            size,
+                            size,
+                            nullptr,
+                            0,
+                            0,
+                            0,
+                            0,
+                            nullptr);
+
+  SocketTooltipData *data = (SocketTooltipData *)MEM_mallocN(sizeof(SocketTooltipData), __func__);
+  data->ntree = ntree;
+  data->node = (bNode *)node_ptr->data;
+  data->socket = sock;
+
+  UI_but_func_tooltip_set(
+      but,
+      [](bContext *C, void *argN, const char *UNUSED(tip)) {
+        SocketTooltipData *data = (SocketTooltipData *)argN;
+        std::optional<std::string> str = create_socket_inspection_string(
+            C, *data->ntree, *data->node, *data->socket);
+        if (str.has_value()) {
+          return BLI_strdup(str->c_str());
+        }
+        return BLI_strdup(TIP_("The socket value has not been computed yet"));
+      },
+      data,
+      MEM_freeN);
+  /* Disable the button so that clicks on it are ignored the the link operator still works. */
+  UI_but_flag_enable(but, UI_BUT_DISABLED);
+  UI_block_emboss_set(block, old_emboss);
 }
 
 /**
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 1c4590f96ac..b85862a0176 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -90,6 +90,24 @@ class GeometryValueLog : public ValueLog {
   std::unique_ptr<GeometrySet> full_geometry_;
 
  public:
+  struct MeshInfo {
+    int tot_verts, tot_edges, tot_faces;
+  };
+  struct CurveInfo {
+    int tot_splines;
+  };
+  struct PointCloudInfo {
+    int tot_points;
+  };
+  struct InstancesInfo {
+    int tot_instances;
+  };
+
+  std::optional<MeshInfo> mesh_info;
+  std::optional<CurveInfo> curve_info;
+  std::optional<PointCloudInfo> pointcloud_info;
+  std::optional<InstancesInfo> instances_info;
+
   GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry);
 
   Span<GeometryAttributeInfo> attributes() const
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 85182b67c8a..3024cc51cad 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -150,6 +150,37 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
       8);
   for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
     component_types_.append(component->type());
+    switch (component->type()) {
+      case GEO_COMPONENT_TYPE_MESH: {
+        const MeshComponent &mesh_component = *(const MeshComponent *)component;
+        MeshInfo &info = this->mesh_info.emplace();
+        info.tot_verts = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+        info.tot_edges = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+        info.tot_faces = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE);
+        break;
+      }
+      case GEO_COMPONENT_TYPE_CURVE: {
+        const CurveComponent &curve_component = *(const CurveComponent *)component;
+        CurveInfo &info = this->curve_info.emplace();
+        info.tot_splines = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+        break;
+      }
+      case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+        const PointCloudComponent &poi

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list