Blender V4.5
node_geo_remove_attribute.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include <fmt/format.h>
8
9#include "NOD_rna_define.hh"
10
11#include "UI_interface.hh"
12#include "UI_resources.hh"
13
15
16enum class PatternMode {
19};
20
22{
23 b.use_custom_socket_order();
24 b.allow_any_socket_order();
25 b.add_default_layout();
26 b.add_input<decl::Geometry>("Geometry");
27 b.add_output<decl::Geometry>("Geometry").propagate_all().align_with_previous();
28 b.add_input<decl::String>("Name").is_attribute_name().hide_label();
29}
30
31static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
32{
33 layout->prop(ptr, "pattern_mode", UI_ITEM_NONE, "", ICON_NONE);
34}
35
37{
38 GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
39 const std::string pattern = params.extract_input<std::string>("Name");
40 if (pattern.empty()) {
41 params.set_output("Geometry", std::move(geometry_set));
42 return;
43 }
44 const bNode &node = params.node();
45 PatternMode pattern_mode = PatternMode(node.custom1);
46 if (pattern_mode == PatternMode::Wildcard) {
47 const int wildcard_count = Span(pattern.c_str(), pattern.size()).count('*');
48 if (wildcard_count == 0) {
49 pattern_mode = PatternMode::Exact;
50 }
51 else if (wildcard_count >= 2) {
52 params.error_message_add(NodeWarningType::Info,
53 TIP_("Only one * is supported in the pattern"));
54 params.set_output("Geometry", std::move(geometry_set));
55 return;
56 }
57 }
58
59 StringRef wildcard_prefix;
60 StringRef wildcard_suffix;
61 if (pattern_mode == PatternMode::Wildcard) {
62 const int wildcard_index = pattern.find('*');
63 wildcard_prefix = StringRef(pattern).substr(0, wildcard_index);
64 wildcard_suffix = StringRef(pattern).substr(wildcard_index + 1);
65 }
66
67 Mutex attribute_log_mutex;
68 Set<std::string> removed_attributes;
69 Set<std::string> failed_attributes;
70
71 geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
72 for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
73 GeometryComponent::Type::PointCloud,
74 GeometryComponent::Type::Curve,
75 GeometryComponent::Type::Instance,
76 GeometryComponent::Type::GreasePencil})
77 {
78 if (!geometry_set.has(type)) {
79 continue;
80 }
81 /* First check if the attribute exists before getting write access,
82 * to avoid potentially expensive unnecessary copies. */
83 const GeometryComponent &read_only_component = *geometry_set.get_component(type);
84 Vector<std::string> attributes_to_remove;
85 switch (pattern_mode) {
86 case PatternMode::Exact: {
87 if (read_only_component.attributes()->contains(pattern)) {
88 attributes_to_remove.append(pattern);
89 }
90 break;
91 }
93 read_only_component.attributes()->foreach_attribute([&](const bke::AttributeIter &iter) {
94 const StringRef attribute_name = iter.name;
95 if (bke::attribute_name_is_anonymous(attribute_name)) {
96 return;
97 }
98 if (attribute_name.startswith(wildcard_prefix) &&
99 attribute_name.endswith(wildcard_suffix))
100 {
101 attributes_to_remove.append(attribute_name);
102 }
103 });
104
105 break;
106 }
107 }
108 if (attributes_to_remove.is_empty()) {
109 break;
110 }
111
112 GeometryComponent &component = geometry_set.get_component_for_write(type);
113 for (const StringRef attribute_name : attributes_to_remove) {
114 if (!bke::allow_procedural_attribute_access(attribute_name)) {
115 continue;
116 }
117 if (component.attributes_for_write()->remove(attribute_name)) {
118 std::lock_guard lock{attribute_log_mutex};
119 removed_attributes.add(attribute_name);
120 }
121 else {
122 std::lock_guard lock{attribute_log_mutex};
123 failed_attributes.add(attribute_name);
124 }
125 }
126 }
127 });
128
129 for (const StringRef attribute_name : removed_attributes) {
130 params.used_named_attribute(attribute_name, NamedAttributeUsage::Remove);
131 }
132
133 if (!failed_attributes.is_empty()) {
134 Vector<std::string> quoted_attribute_names;
135 for (const StringRef attribute_name : failed_attributes) {
136 quoted_attribute_names.append(fmt::format("\"{}\"", attribute_name));
137 }
138 const std::string message = fmt::format(
139 fmt::runtime(TIP_("Cannot remove built-in attributes: {}")),
140 fmt::join(quoted_attribute_names, ", "));
141 params.error_message_add(NodeWarningType::Warning, message);
142 }
143 else if (removed_attributes.is_empty() && pattern_mode == PatternMode::Exact) {
144 const std::string message = fmt::format(fmt::runtime(TIP_("Attribute does not exist: \"{}\"")),
145 pattern);
146 params.error_message_add(NodeWarningType::Warning, message);
147 }
148
149 params.set_output("Geometry", std::move(geometry_set));
150}
151
152static void node_rna(StructRNA *srna)
153{
154 static const EnumPropertyItem pattern_mode_items[] = {
155 {int(PatternMode::Exact),
156 "EXACT",
157 0,
158 "Exact",
159 "Remove the one attribute with the given name"},
161 "WILDCARD",
162 0,
163 "Wildcard",
164 "Remove all attributes that match the pattern which is allowed to contain a single "
165 "wildcard (*)"},
166 {0, nullptr, 0, nullptr, nullptr},
167 };
169 "pattern_mode",
170 "Pattern Mode",
171 "How the attributes to remove are chosen",
172 pattern_mode_items,
174}
175
176static void node_register()
177{
178 static blender::bke::bNodeType ntype;
179
180 geo_node_type_base(&ntype, "GeometryNodeRemoveAttribute", GEO_NODE_REMOVE_ATTRIBUTE);
181 ntype.ui_name = "Remove Named Attribute";
182 ntype.ui_description =
183 "Delete an attribute with a specified name from a geometry. Typically used to optimize "
184 "performance";
185 ntype.enum_name_legacy = "REMOVE_ATTRIBUTE";
187 ntype.declare = node_declare;
189 bke::node_type_size(ntype, 170, 100, 700);
192
193 node_rna(ntype.rna_ext.srna);
194}
196
197} // namespace blender::nodes::node_geo_remove_attribute_cc
#define NODE_CLASS_ATTRIBUTE
Definition BKE_node.hh:448
#define GEO_NODE_REMOVE_ATTRIBUTE
#define TIP_(msgid)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
#define UI_ITEM_NONE
volatile int lock
bool add(const Key &key)
Definition BLI_set.hh:248
bool is_empty() const
Definition BLI_set.hh:595
constexpr int64_t count(const T &value) const
Definition BLI_span.hh:300
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr bool startswith(StringRef prefix) const
constexpr bool endswith(StringRef suffix) const
void append(const T &value)
bool is_empty() const
virtual std::optional< AttributeAccessor > attributes() const
virtual std::optional< MutableAttributeAccessor > attributes_for_write()
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
bool attribute_name_is_anonymous(const StringRef name)
bool allow_procedural_attribute_access(StringRef attribute_name)
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5573
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
std::mutex Mutex
Definition BLI_mutex.hh:47
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
StructRNA * srna
Definition RNA_types.hh:909
int16_t custom1
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
bool has(const GeometryComponent::Type component_type) const
const GeometryComponent * get_component(GeometryComponent::Type component_type) const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:347
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:355
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
PointerRNA * ptr
Definition wm_files.cc:4227