Blender V5.0
node_geo_store_named_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
5#include <atomic>
6
8#include "UI_resources.hh"
9
10#include "RNA_access.hh"
11#include "RNA_enum_types.hh"
12
14#include "BKE_instances.hh"
15#include "BKE_mesh.hh"
17
18#include "NOD_rna_define.hh"
20
22
23#include "node_geometry_util.hh"
24
25#include <fmt/format.h>
26
28
30
32{
33 b.use_custom_socket_order();
34 b.allow_any_socket_order();
35 b.add_default_layout();
36 const bNode *node = b.node_or_null();
37
38 b.add_input<decl::Geometry>("Geometry")
39 .description("Geometry to store a new attribute with the given name on");
40 b.add_output<decl::Geometry>("Geometry").propagate_all().align_with_previous();
41 b.add_input<decl::Bool>("Selection").default_value(true).hide_value().field_on_all();
42 b.add_input<decl::String>("Name").is_attribute_name().optional_label();
43
44 if (node != nullptr) {
45 const NodeGeometryStoreNamedAttribute &storage = node_storage(*node);
46 const eCustomDataType data_type = eCustomDataType(storage.data_type);
47 b.add_input(data_type, "Value").field_on_all();
48 }
49}
50
51static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
52{
53 layout->use_property_split_set(true);
54 layout->use_property_decorate_set(false);
55 layout->prop(ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
56 layout->prop(ptr, "domain", UI_ITEM_NONE, "", ICON_NONE);
57}
58
59static void node_init(bNodeTree * /*tree*/, bNode *node)
60{
62 data->data_type = CD_PROP_FLOAT;
63 data->domain = int8_t(AttrDomain::Point);
64 node->storage = data;
65}
66
68{
69 const NodeDeclaration &declaration = *params.node_type().static_declaration;
72
73 if (params.in_out() == SOCK_IN) {
74 const std::optional<eCustomDataType> type = bke::socket_type_to_custom_data_type(
75 eNodeSocketDatatype(params.other_socket().type));
76 if (type && *type != CD_PROP_STRING) {
77 /* The input and output sockets have the same name. */
78 params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
79 bNode &node = params.add_node("GeometryNodeStoreNamedAttribute");
80 node_storage(node).data_type = *type;
81 params.update_and_connect_available_socket(node, "Value");
82 });
83 }
84 }
85}
86
88{
89 GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
90 const std::string name = params.extract_input<std::string>("Name");
91
92 if (name.empty()) {
93 params.set_output("Geometry", std::move(geometry_set));
94 return;
95 }
98 params.set_output("Geometry", std::move(geometry_set));
99 return;
100 }
102 params.error_message_add(NodeWarningType::Info,
103 TIP_("Anonymous attributes cannot be created here"));
104 params.set_output("Geometry", std::move(geometry_set));
105 return;
106 }
107
108 params.used_named_attribute(name, NamedAttributeUsage::Write);
109
110 const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node());
111 const eCustomDataType cd_type = eCustomDataType(storage.data_type);
112 const bke::AttrType data_type = *bke::custom_data_type_to_attr_type(cd_type);
113 const AttrDomain domain = AttrDomain(storage.domain);
114
115 const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
116
117 GField field = params.extract_input<GField>("Value");
120 std::move(field), bke::attribute_type_to_cpp_type(data_type));
121 }
122
123 std::atomic<bool> failure = false;
124
125 /* Run on the instances component separately to only affect the top level of instances. */
126 if (domain == AttrDomain::Instance) {
127 if (geometry_set.has_instances()) {
128 GeometryComponent &component = geometry_set.get_component_for_write(
129 GeometryComponent::Type::Instance);
130
131 if (name == "position" && data_type == bke::AttrType::Float3) {
132 /* Special case for "position" which is no longer an attribute on instances. */
133 bke::Instances &instances = *geometry_set.get_instances_for_write();
134 bke::InstancesFieldContext context(instances);
135 fn::FieldEvaluator evaluator{context, instances.instances_num()};
136 evaluator.set_selection(selection);
138 evaluator.evaluate();
139 }
140 else {
141 if (!bke::try_capture_field_on_geometry(component, name, domain, selection, field)) {
142 if (component.attribute_domain_size(domain) != 0) {
143 failure.store(true);
144 }
145 }
146 }
147 }
148 }
149 else {
150 geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) {
151 for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh,
152 GeometryComponent::Type::PointCloud,
153 GeometryComponent::Type::Curve,
154 GeometryComponent::Type::GreasePencil})
155 {
156 if (geometry_set.has(type)) {
157 GeometryComponent &component = geometry_set.get_component_for_write(type);
158 if (bke::try_capture_field_on_geometry(component, name, domain, selection, field)) {
159 if (component.type() == GeometryComponent::Type::Mesh) {
160 Mesh &mesh = *geometry_set.get_mesh_for_write();
162 }
163 }
164 else if (component.attribute_domain_size(domain) != 0) {
165 failure.store(true);
166 }
167 }
168 }
169 });
170 }
171
172 if (failure) {
173 const char *domain_name = nullptr;
175 const char *type_name = nullptr;
177 const std::string message = fmt::format(
178 fmt::runtime(
179 TIP_("Failed to write to attribute \"{}\" with domain \"{}\" and type \"{}\"")),
180 name,
181 TIP_(domain_name),
182 TIP_(type_name));
183 params.error_message_add(NodeWarningType::Warning, message);
184 }
185
186 params.set_output("Geometry", std::move(geometry_set));
187}
188
189static void node_rna(StructRNA *srna)
190{
192 srna,
193 "data_type",
194 "Data Type",
195 "Type of data stored in attribute",
199 [](bContext * /*C*/, PointerRNA * /*ptr*/, PropertyRNA * /*prop*/, bool *r_free) {
200 *r_free = true;
203 });
204
206 "domain",
207 "Domain",
208 "Which domain to store the data in",
211 int(AttrDomain::Point));
212}
213
214static void node_register()
215{
216 static blender::bke::bNodeType ntype;
217
218 geo_node_type_base(&ntype, "GeometryNodeStoreNamedAttribute", GEO_NODE_STORE_NAMED_ATTRIBUTE);
219 ntype.ui_name = "Store Named Attribute";
220 ntype.ui_description =
221 "Store the result of a field on a geometry as an attribute with the specified name";
222 ntype.enum_name_legacy = "STORE_NAMED_ATTRIBUTE";
225 "NodeGeometryStoreNamedAttribute",
228 blender::bke::node_type_size(ntype, 140, 100, 700);
229 ntype.initfunc = node_init;
230 ntype.declare = node_declare;
235
236 node_rna(ntype.rna_ext.srna);
237}
239
240} // namespace blender::nodes::node_geo_store_named_attribute_cc
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define NODE_CLASS_ATTRIBUTE
Definition BKE_node.hh:462
#define GEO_NODE_STORE_NAMED_ATTRIBUTE
#define ELEM(...)
#define TIP_(msgid)
#define IFACE_(msgid)
@ CD_PROP_FLOAT
@ CD_PROP_STRING
@ SOCK_IN
eNodeSocketDatatype
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
#define UI_ITEM_NONE
BMesh const char void * data
GVArray try_convert(GVArray varray, const CPPType &to_type) const
int attribute_domain_size(AttrDomain domain) const
int instances_num() const
Definition instances.cc:393
void set_selection(Field< bool > selection)
Definition FN_field.hh:383
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:738
Vector< SocketDeclaration * > inputs
Vector< SocketDeclaration * > outputs
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
bool attribute_name_is_anonymous(const StringRef name)
const DataTypeConversions & get_implicit_type_conversions()
bool allow_procedural_attribute_access(StringRef attribute_name)
std::optional< AttrType > custom_data_type_to_attr_type(eCustomDataType data_type)
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5384
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
const char * no_procedural_access_message
bool try_capture_field_on_geometry(MutableAttributeAccessor attributes, const fn::FieldContext &field_context, const StringRef attribute_id, AttrDomain domain, const fn::Field< bool > &selection, const fn::GField &field)
void mesh_ensure_default_color_attribute_on_add(Mesh &mesh, StringRef id, AttrDomain domain, bke::AttrType data_type)
VMutableArray< float3 > instance_position_varray_for_write(Instances &instances)
Definition instances.cc:535
const CPPType & attribute_type_to_cpp_type(AttrType type)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
std::optional< eCustomDataType > socket_type_to_custom_data_type(eNodeSocketDatatype type)
Definition node.cc:5144
void foreach_real_geometry(bke::GeometrySet &geometry, FunctionRef< void(bke::GeometrySet &geometry_set)> fn)
bool generic_attribute_type_supported(const EnumPropertyItem &item)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
void search_link_ops_for_declarations(GatherLinkSearchOpParams &params, Span< SocketDeclaration * > declarations)
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)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
const char * name
bool RNA_enum_name_from_value(const EnumPropertyItem *item, int value, const char **r_name)
const EnumPropertyItem rna_enum_attribute_domain_items[]
const EnumPropertyItem rna_enum_attribute_type_items[]
StructRNA * srna
void * storage
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
Instances * get_instances_for_write()
bool has(const GeometryComponent::Type component_type) const
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
void use_property_decorate_set(bool is_sep)
void use_property_split_set(bool value)
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:4238