Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-04-14 17:31:09 +0300
committerJacques Lucke <jacques@blender.org>2022-04-14 17:31:09 +0300
commitc71013082d096968d33ba977a0fdbcfbfb0690d1 (patch)
treedf09bab6e0405ab79779fe74a21991381ed137e6 /source/blender
parenta9b94e5f81ced89381033fd8d13ef6e3489e2665 (diff)
Geometry Nodes: show used named attributes in nodes
This adds a new node editor overlay that helps users to see where named attributes are used. This is important, because named attributes can have name collisions between independent node groups which can lead to hard to find issues. Differential Revision: https://developer.blender.org/D14618
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenloader/intern/versioning_300.c12
-rw-r--r--source/blender/editors/space_node/node_draw.cc164
-rw-r--r--source/blender/makesdna/DNA_space_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_space.c7
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh3
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc4
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc14
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc10
11 files changed, 229 insertions, 18 deletions
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 95851c0e9ff..ec60183218c 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -2677,5 +2677,17 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Enable named attributes overlay in node editor. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
+ if (space->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)space;
+ snode->overlay.flag |= SN_OVERLAY_SHOW_NAMED_ATTRIBUTES;
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 013413adfe9..692940d405c 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -75,6 +75,7 @@
using blender::GPointer;
using blender::fn::GField;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
+using geo_log::NamedAttributeUsage;
extern "C" {
/* XXX interface.h */
@@ -1684,10 +1685,127 @@ static std::string node_get_execution_time_label(const SpaceNode &snode, const b
struct NodeExtraInfoRow {
std::string text;
- const char *tooltip;
int icon;
+ const char *tooltip = nullptr;
+
+ uiButToolTipFunc tooltip_fn = nullptr;
+ void *tooltip_fn_arg = nullptr;
+ void (*tooltip_fn_free_arg)(void *) = nullptr;
+};
+
+struct NamedAttributeTooltipArg {
+ Map<std::string, NamedAttributeUsage> usage_by_attribute;
};
+static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
+{
+ NamedAttributeTooltipArg &arg = *static_cast<NamedAttributeTooltipArg *>(argN);
+
+ std::stringstream ss;
+ ss << TIP_("Accessed attribute names:\n");
+ Vector<std::pair<StringRefNull, NamedAttributeUsage>> sorted_used_attribute;
+ for (auto &&item : arg.usage_by_attribute.items()) {
+ sorted_used_attribute.append({item.key, item.value});
+ }
+ std::sort(sorted_used_attribute.begin(), sorted_used_attribute.end());
+ for (const std::pair<StringRefNull, NamedAttributeUsage> &attribute : sorted_used_attribute) {
+ const StringRefNull name = attribute.first;
+ const NamedAttributeUsage usage = attribute.second;
+ ss << " \u2022 \"" << name << "\": ";
+ Vector<std::string> usages;
+ if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
+ usages.append(TIP_("read"));
+ }
+ if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
+ usages.append(TIP_("write"));
+ }
+ if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
+ usages.append(TIP_("remove"));
+ }
+ for (const int i : usages.index_range()) {
+ ss << usages[i];
+ if (i < usages.size() - 1) {
+ ss << ", ";
+ }
+ }
+ ss << "\n";
+ }
+ ss << "\n";
+ ss << TIP_(
+ "Attributes with these names used within the group may conflict with existing attributes");
+ return BLI_strdup(ss.str().c_str());
+}
+
+static NodeExtraInfoRow row_from_used_named_attribute(
+ const Map<std::string, NamedAttributeUsage> &usage_by_attribute_name)
+{
+ NodeExtraInfoRow row;
+ row.text = TIP_("Attributes");
+ row.icon = ICON_SPREADSHEET;
+ row.tooltip_fn = named_attribute_tooltip;
+ row.tooltip_fn_arg = new NamedAttributeTooltipArg{usage_by_attribute_name};
+ row.tooltip_fn_free_arg = [](void *arg) { delete static_cast<NamedAttributeTooltipArg *>(arg); };
+ return row;
+}
+
+static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const SpaceNode &snode,
+ const bNode &node)
+{
+ if (node.type == NODE_GROUP) {
+ const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context(
+ snode);
+ if (root_tree_log == nullptr) {
+ return std::nullopt;
+ }
+ const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node.name);
+ if (tree_log == nullptr) {
+ return std::nullopt;
+ }
+
+ Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
+ for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
+ usage_by_attribute.lookup_or_add_as(used_attribute.name,
+ used_attribute.usage) |= used_attribute.usage;
+ }
+ });
+ if (usage_by_attribute.is_empty()) {
+ return std::nullopt;
+ }
+
+ return row_from_used_named_attribute(usage_by_attribute);
+ }
+ if (ELEM(node.type,
+ GEO_NODE_STORE_NAMED_ATTRIBUTE,
+ GEO_NODE_REMOVE_ATTRIBUTE,
+ GEO_NODE_INPUT_NAMED_ATTRIBUTE)) {
+ /* Only show the overlay when the name is passed in from somewhere else. */
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
+ if (STREQ(socket->name, "Name")) {
+ if ((socket->flag & SOCK_IN_USE) == 0) {
+ return std::nullopt;
+ }
+ }
+ }
+ const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context(
+ snode, node.name);
+ if (node_log == nullptr) {
+ return std::nullopt;
+ }
+ Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ for (const geo_log::UsedNamedAttribute &used_attribute : node_log->used_named_attributes()) {
+ usage_by_attribute.lookup_or_add_as(used_attribute.name,
+ used_attribute.usage) |= used_attribute.usage;
+ }
+ if (usage_by_attribute.is_empty()) {
+ return std::nullopt;
+ }
+ return row_from_used_named_attribute(usage_by_attribute);
+ }
+
+ return std::nullopt;
+}
+
static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, const bNode &node)
{
Vector<NodeExtraInfoRow> rows;
@@ -1718,6 +1836,14 @@ static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode &snode, cons
rows.append(std::move(row));
}
}
+
+ if (snode.overlay.flag & SN_OVERLAY_SHOW_NAMED_ATTRIBUTES &&
+ snode.edittree->type == NTREE_GEOMETRY) {
+ if (std::optional<NodeExtraInfoRow> row = node_get_accessed_attributes_row(snode, node)) {
+ rows.append(std::move(*row));
+ }
+ }
+
return rows;
}
@@ -1727,20 +1853,20 @@ static void node_draw_extra_info_row(const bNode &node,
const int row,
const NodeExtraInfoRow &extra_info_row)
{
- uiBut *but_timing = uiDefBut(&block,
- UI_BTYPE_LABEL,
- 0,
- extra_info_row.text.c_str(),
- (int)(rect.xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f),
- (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
- (short)(rect.xmax - rect.xmin),
- (short)NODE_DY,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "");
+ uiBut *but_text = uiDefBut(&block,
+ UI_BTYPE_LABEL,
+ 0,
+ extra_info_row.text.c_str(),
+ (int)(rect.xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f),
+ (int)(rect.ymin + row * (20.0f * U.dpi_fac)),
+ (short)(rect.xmax - rect.xmin),
+ (short)NODE_DY,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
UI_block_emboss_set(&block, UI_EMBOSS_NONE);
uiBut *but_icon = uiDefIconBut(&block,
UI_BTYPE_BUT,
@@ -1756,9 +1882,15 @@ static void node_draw_extra_info_row(const bNode &node,
0,
0,
extra_info_row.tooltip);
+ if (extra_info_row.tooltip_fn != NULL) {
+ UI_but_func_tooltip_set(but_icon,
+ extra_info_row.tooltip_fn,
+ extra_info_row.tooltip_fn_arg,
+ extra_info_row.tooltip_fn_free_arg);
+ }
UI_block_emboss_set(&block, UI_EMBOSS);
if (node.flag & NODE_MUTED) {
- UI_but_flag_enable(but_timing, UI_BUT_INACTIVE);
+ UI_but_flag_enable(but_text, UI_BUT_INACTIVE);
UI_but_flag_enable(but_icon, UI_BUT_INACTIVE);
}
}
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 1b70d8497b6..838213dd2f3 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1513,6 +1513,7 @@ typedef enum eSpaceNodeOverlay_Flag {
SN_OVERLAY_SHOW_WIRE_COLORS = (1 << 2),
SN_OVERLAY_SHOW_TIMINGS = (1 << 3),
SN_OVERLAY_SHOW_PATH = (1 << 4),
+ SN_OVERLAY_SHOW_NAMED_ATTRIBUTES = (1 << 5),
} eSpaceNodeOverlay_Flag;
typedef struct SpaceNode {
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index d2b8eb203aa..c40a2ed9260 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -7143,6 +7143,13 @@ static void rna_def_space_node_overlay(BlenderRNA *brna)
RNA_def_property_boolean_default(prop, true);
RNA_def_property_ui_text(prop, "Show Tree Path", "Display breadcrumbs for the editor's context");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
+ prop = RNA_def_property(srna, "show_named_attributes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_NAMED_ATTRIBUTES);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(
+ prop, "Show Named Attributes", "Show when nodes are using named attributes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
}
static void rna_def_space_node(BlenderRNA *brna)
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 96a1904abdd..bac4d0165e9 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -40,6 +40,7 @@ using fn::FieldInput;
using fn::FieldOperation;
using fn::GField;
using fn::ValueOrField;
+using geometry_nodes_eval_log::NamedAttributeUsage;
using geometry_nodes_eval_log::NodeWarningType;
/**
@@ -342,6 +343,8 @@ class GeoNodeExecParams {
void set_default_remaining_outputs();
+ void used_named_attribute(std::string attribute_name, NamedAttributeUsage usage);
+
private:
/* Utilities for detecting common errors at when using this class. */
void check_input_access(StringRef identifier, const CPPType *requested_type = nullptr) const;
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 16332be5179..1ad859aa47b 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -170,6 +170,24 @@ struct ValueOfSockets {
destruct_ptr<ValueLog> value;
};
+enum class NamedAttributeUsage {
+ None = 0,
+ Read = 1 << 0,
+ Write = 1 << 1,
+ Remove = 1 << 2,
+};
+ENUM_OPERATORS(NamedAttributeUsage, NamedAttributeUsage::Remove);
+
+struct UsedNamedAttribute {
+ std::string name;
+ NamedAttributeUsage usage;
+};
+
+struct NodeWithUsedNamedAttribute {
+ DNode node;
+ UsedNamedAttribute attribute;
+};
+
class GeoLogger;
class ModifierLog;
@@ -186,6 +204,7 @@ class LocalGeoLogger {
Vector<NodeWithWarning> node_warnings_;
Vector<NodeWithExecutionTime> node_exec_times_;
Vector<NodeWithDebugMessage> node_debug_messages_;
+ Vector<NodeWithUsedNamedAttribute> used_named_attributes_;
friend ModifierLog;
@@ -199,6 +218,7 @@ class LocalGeoLogger {
void log_multi_value_socket(DSocket socket, Span<GPointer> values);
void log_node_warning(DNode node, NodeWarningType type, std::string message);
void log_execution_time(DNode node, std::chrono::microseconds exec_time);
+ void log_used_named_attribute(DNode node, std::string attribute_name, NamedAttributeUsage usage);
/**
* Log a message that will be displayed in the node editor next to the node.
* This should only be used for debugging purposes and not to display information to users.
@@ -278,6 +298,7 @@ class NodeLog {
Vector<SocketLog> output_logs_;
Vector<NodeWarning, 0> warnings_;
Vector<std::string, 0> debug_messages_;
+ Vector<UsedNamedAttribute, 0> used_named_attributes_;
std::chrono::microseconds exec_time_;
friend ModifierLog;
@@ -307,6 +328,11 @@ class NodeLog {
return debug_messages_;
}
+ Span<UsedNamedAttribute> used_named_attributes() const
+ {
+ return used_named_attributes_;
+ }
+
std::chrono::microseconds execution_time() const
{
return exec_time_;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
index f6e2be9119c..6cb9ca642ef 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
@@ -81,11 +81,13 @@ static void node_geo_exec(GeoNodeExecParams params)
const std::string name = params.extract_input<std::string>("Name");
- if (!U.experimental.use_named_attribute_nodes) {
+ if (!U.experimental.use_named_attribute_nodes || name.empty()) {
params.set_default_remaining_outputs();
return;
}
+ params.used_named_attribute(name, NamedAttributeUsage::Read);
+
switch (data_type) {
case CD_PROP_FLOAT:
params.set_output("Attribute_Float", AttributeFieldInput::Create<float>(std::move(name)));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
index 202241affeb..f46b70c91a9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
@@ -32,6 +32,8 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
+ params.used_named_attribute(name, NamedAttributeUsage::Remove);
+
std::atomic<bool> attribute_exists = false;
std::atomic<bool> cannot_delete = false;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
index 1d1446ce1bd..92614d1a31d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
@@ -127,11 +127,13 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
std::string name = params.extract_input<std::string>("Name");
- if (!U.experimental.use_named_attribute_nodes) {
+ if (!U.experimental.use_named_attribute_nodes || name.empty()) {
params.set_output("Geometry", std::move(geometry_set));
return;
}
+ params.used_named_attribute(name, NamedAttributeUsage::Write);
+
const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node());
const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 13f38c3352e..378bac894e8 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -62,6 +62,13 @@ ModifierLog::ModifierLog(GeoLogger &logger)
NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, debug_message.node);
node_log.debug_messages_.append(debug_message.message);
}
+
+ for (NodeWithUsedNamedAttribute &node_with_attribute_name :
+ local_logger.used_named_attributes_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context,
+ node_with_attribute_name.node);
+ node_log.used_named_attributes_.append(std::move(node_with_attribute_name.attribute));
+ }
}
}
@@ -486,6 +493,13 @@ void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds ex
node_exec_times_.append({node, exec_time});
}
+void LocalGeoLogger::log_used_named_attribute(DNode node,
+ std::string attribute_name,
+ NamedAttributeUsage usage)
+{
+ used_named_attributes_.append({node, {std::move(attribute_name), usage}});
+}
+
void LocalGeoLogger::log_debug_message(DNode node, std::string message)
{
node_debug_messages_.append({node, std::move(message)});
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index d63a6d11eda..cea3084a418 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -23,6 +23,16 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
local_logger.log_node_warning(provider_->dnode, type, std::move(message));
}
+void GeoNodeExecParams::used_named_attribute(std::string attribute_name,
+ const NamedAttributeUsage usage)
+{
+ if (provider_->logger == nullptr) {
+ return;
+ }
+ LocalGeoLogger &local_logger = provider_->logger->local();
+ local_logger.log_used_named_attribute(provider_->dnode, std::move(attribute_name), usage);
+}
+
void GeoNodeExecParams::check_input_geometry_set(StringRef identifier,
const GeometrySet &geometry_set) const
{