Blender  V3.3
node_geo_store_named_attribute.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <atomic>
4 
5 #include "UI_interface.h"
6 #include "UI_resources.h"
7 
8 #include "RNA_enum_types.h"
9 
11 
12 #include "BKE_type_conversions.hh"
13 
14 #include "node_geometry_util.hh"
15 
17 
19 
21 {
22  b.add_input<decl::Geometry>(N_("Geometry"));
23  b.add_input<decl::String>(N_("Name")).is_attribute_name();
24  b.add_input<decl::Vector>(N_("Value"), "Value_Vector").supports_field();
25  b.add_input<decl::Float>(N_("Value"), "Value_Float").supports_field();
26  b.add_input<decl::Color>(N_("Value"), "Value_Color").supports_field();
27  b.add_input<decl::Bool>(N_("Value"), "Value_Bool").supports_field();
28  b.add_input<decl::Int>(N_("Value"), "Value_Int").supports_field();
29 
30  b.add_output<decl::Geometry>(N_("Geometry"));
31 }
32 
33 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
34 {
35  uiLayoutSetPropSep(layout, true);
36  uiLayoutSetPropDecorate(layout, false);
37  uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
38  uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
39 }
40 
42 {
43  NodeGeometryStoreNamedAttribute *data = MEM_cnew<NodeGeometryStoreNamedAttribute>(__func__);
44  data->data_type = CD_PROP_FLOAT;
45  data->domain = ATTR_DOMAIN_POINT;
46  node->storage = data;
47 }
48 
50 {
51  const NodeGeometryStoreNamedAttribute &storage = node_storage(*node);
52  const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
53 
54  bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
55  bNodeSocket *socket_name = socket_geometry->next;
56  bNodeSocket *socket_vector = socket_name->next;
57  bNodeSocket *socket_float = socket_vector->next;
58  bNodeSocket *socket_color4f = socket_float->next;
59  bNodeSocket *socket_boolean = socket_color4f->next;
60  bNodeSocket *socket_int32 = socket_boolean->next;
61 
62  nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3);
63  nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT);
65  ntree, socket_color4f, ELEM(data_type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR));
66  nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL);
67  nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32);
68 }
69 
71 {
72  const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
73  search_link_ops_for_declarations(params, declaration.inputs().take_front(2));
74 
75  if (params.in_out() == SOCK_IN) {
76  const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
77  static_cast<eNodeSocketDatatype>(params.other_socket().type));
78  if (type && *type != CD_PROP_STRING) {
79  /* The input and output sockets have the same name. */
80  params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
81  bNode &node = params.add_node("GeometryNodeStoreNamedAttribute");
82  node_storage(node).data_type = *type;
83  params.update_and_connect_available_socket(node, "Value");
84  });
85  }
86  }
87 }
88 
90  const StringRef name,
91  const eAttrDomain domain,
92  const GField &field,
93  std::atomic<bool> &r_failure)
94 {
95  MutableAttributeAccessor attributes = *component.attributes_for_write();
96  const int domain_size = attributes.domain_size(domain);
97  if (domain_size == 0) {
98  return;
99  }
100 
101  GeometryComponentFieldContext field_context{component, domain};
102  const IndexMask mask{IndexMask(domain_size)};
103 
104  const CPPType &type = field.cpp_type();
106 
107  /* Could avoid allocating a new buffer if:
108  * - We are writing to an attribute that exists already with the correct domain and type.
109  * - The field does not depend on that attribute (we can't easily check for that yet). */
110  void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
111 
112  fn::FieldEvaluator evaluator{field_context, &mask};
113  evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size});
114  evaluator.evaluate();
115 
116  if (GAttributeWriter attribute = attributes.lookup_for_write(name)) {
117  if (attribute.domain == domain && attribute.varray.type() == type) {
118  attribute.varray.set_all(buffer);
119  attribute.finish();
120  type.destruct_n(buffer, domain_size);
121  MEM_freeN(buffer);
122  return;
123  }
124  }
125  attributes.remove(name);
126  if (attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) {
127  return;
128  }
129 
130  /* If the name corresponds to a builtin attribute, removing the attribute might fail if
131  * it's required, and adding the attribute might fail if the domain or type is incorrect. */
132  type.destruct_n(buffer, domain_size);
133  MEM_freeN(buffer);
134  r_failure = true;
135 }
136 
138 {
139  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
140  std::string name = params.extract_input<std::string>("Name");
141 
142  if (name.empty()) {
143  params.set_output("Geometry", std::move(geometry_set));
144  return;
145  }
148  params.set_output("Geometry", std::move(geometry_set));
149  return;
150  }
151 
152  params.used_named_attribute(name, eNamedAttrUsage::Write);
153 
154  const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node());
155  const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
156  const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
157 
158  GField field;
159  switch (data_type) {
160  case CD_PROP_FLOAT:
161  field = params.get_input<Field<float>>("Value_Float");
162  break;
163  case CD_PROP_FLOAT3:
164  field = params.get_input<Field<float3>>("Value_Vector");
165  break;
166  case CD_PROP_COLOR:
167  field = params.get_input<Field<ColorGeometry4f>>("Value_Color");
168  break;
169  case CD_PROP_BYTE_COLOR: {
170  field = params.get_input<Field<ColorGeometry4f>>("Value_Color");
172  CPPType::get<ColorGeometry4b>());
173  break;
174  }
175  case CD_PROP_BOOL:
176  field = params.get_input<Field<bool>>("Value_Bool");
177  break;
178  case CD_PROP_INT32:
179  field = params.get_input<Field<int>>("Value_Int");
180  break;
181  default:
182  break;
183  }
184 
185  std::atomic<bool> failure = false;
186 
187  /* Run on the instances component separately to only affect the top level of instances. */
188  if (domain == ATTR_DOMAIN_INSTANCE) {
189  if (geometry_set.has_instances()) {
192  try_capture_field_on_geometry(component, name, domain, field, failure);
193  }
194  }
195  else {
196  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
197  for (const GeometryComponentType type :
199  if (geometry_set.has(type)) {
200  GeometryComponent &component = geometry_set.get_component_for_write(type);
201  try_capture_field_on_geometry(component, name, domain, field, failure);
202  }
203  }
204  });
205  }
206 
207  if (failure) {
208  const char *domain_name = nullptr;
210  const char *type_name = nullptr;
212  char *message = BLI_sprintfN(
213  TIP_("Failed to write to attribute \"%s\" with domain \"%s\" and type \"%s\""),
214  name.c_str(),
215  TIP_(domain_name),
216  TIP_(type_name));
217  params.error_message_add(NodeWarningType::Warning, message);
218  MEM_freeN(message);
219  }
220 
221  params.set_output("Geometry", std::move(geometry_set));
222 }
223 
224 } // namespace blender::nodes::node_geo_store_named_attribute_cc
225 
227 {
229  static bNodeType ntype;
230 
232  &ntype, GEO_NODE_STORE_NAMED_ATTRIBUTE, "Store Named Attribute", NODE_CLASS_ATTRIBUTE);
233  node_type_storage(&ntype,
234  "NodeGeometryStoreNamedAttribute",
237  node_type_size(&ntype, 140, 100, 700);
244  nodeRegisterType(&ntype);
245 }
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_INSTANCE
Definition: BKE_attribute.h:32
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_INSTANCES
@ GEO_COMPONENT_TYPE_CURVE
#define GEO_NODE_STORE_NAMED_ATTRIBUTE
Definition: BKE_node.h:1497
void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition: node.cc:4396
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3664
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
#define NODE_CLASS_ATTRIBUTE
Definition: BKE_node.h:360
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
size_t size_t char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define UNUSED(x)
#define ELEM(...)
#define TIP_(msgid)
#define IFACE_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
eCustomDataType
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_COLOR
@ CD_PROP_INT32
@ CD_PROP_BOOL
@ CD_PROP_STRING
@ SOCK_IN
eNodeSocketDatatype
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
in reality light always falls off quadratically Particle Info
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
int domain_size(const eAttrDomain domain) const
GVArray try_convert(GVArray varray, const CPPType &to_type) const
bool add(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id)
bool remove(const AttributeIDRef &attribute_id)
const CPPType & cpp_type() const
Definition: FN_field.hh:122
Span< SocketDeclarationPtr > inputs() const
OperationNode * node
void * tree
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
const DataTypeConversions & get_implicit_type_conversions()
bool allow_procedural_attribute_access(StringRef attribute_name)
const char * no_procedural_access_message
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
Definition: customdata.cc:5337
static void node_update(bNodeTree *ntree, bNode *node)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void try_capture_field_on_geometry(GeometryComponent &component, const StringRef name, const eAttrDomain domain, const GField &field, std::atomic< bool > &r_failure)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
std::optional< eCustomDataType > node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
void search_link_ops_for_declarations(GatherLinkSearchOpParams &params, Span< SocketDeclarationPtr > declarations)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
void register_node_type_geo_store_named_attribute()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
bool RNA_enum_name_from_value(const EnumPropertyItem *item, int value, const char **r_name)
Definition: rna_access.c:5106
const EnumPropertyItem rna_enum_attribute_domain_items[]
Definition: rna_attribute.c:70
const EnumPropertyItem rna_enum_attribute_type_items[]
Definition: rna_attribute.c:26
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
bool has(const GeometryComponentType component_type) const
bool has_instances() const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
struct bNodeSocket * next
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition: BKE_node.h:335
void(* updatefunc)(struct bNodeTree *ntree, struct bNode *node)
Definition: BKE_node.h:265
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480