Blender V4.5
geometry_nodes_execute.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
8
9#include "BLI_listbase.h"
10#include "BLI_math_euler.hh"
11#include "BLI_string.h"
12
13#include "NOD_geometry.hh"
17#include "NOD_socket.hh"
18
21#include "BKE_geometry_set.hh"
22#include "BKE_idprop.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_node_enum.hh"
25#include "BKE_node_runtime.hh"
27
29
30#include "UI_resources.hh"
31
34
35namespace blender::nodes {
36
41
42bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
43{
44 node_tree.ensure_interface_cache();
45 const bke::bNodeSocketType *typeinfo =
46 node_tree.interface_inputs()[socket_index]->socket_typeinfo();
47 if (ELEM(typeinfo->type, SOCK_MENU)) {
48 return false;
49 }
50
51 BLI_assert(node_tree.runtime->field_inferencing_interface);
52 const FieldInferencingInterface &field_interface =
53 *node_tree.runtime->field_inferencing_interface;
54 return field_interface.inputs[socket_index] != InputSocketFieldType::None;
55}
56
58 IDPropertyUIDataInt *ui_data)
59{
60 int idprop_items_num = 0;
61 IDPropertyUIDataEnumItem *idprop_items = nullptr;
62
63 if (value->enum_items && !value->enum_items->items.is_empty()) {
64 const Span<bke::RuntimeNodeEnumItem> items = value->enum_items->items;
65 idprop_items_num = items.size();
66 idprop_items = MEM_calloc_arrayN<IDPropertyUIDataEnumItem>(items.size(), __func__);
67 for (const int i : items.index_range()) {
68 const bke::RuntimeNodeEnumItem &item = items[i];
69 IDPropertyUIDataEnumItem &idprop_item = idprop_items[i];
70 idprop_item.value = item.identifier;
71 /* TODO: The name may not be unique!
72 * We require a unique identifier string for IDProperty and RNA enums,
73 * so node enums should probably have this too. */
74 idprop_item.identifier = BLI_strdup_null(item.name.c_str());
75 idprop_item.name = BLI_strdup_null(item.name.c_str());
76 idprop_item.description = BLI_strdup_null(item.description.c_str());
77 idprop_item.icon = ICON_NONE;
78 }
79 }
80
81 /* Fallback: if no items are defined, use a dummy item so the id property is not shown as a plain
82 * int value. */
83 if (idprop_items_num == 0) {
84 idprop_items_num = 1;
85 idprop_items = MEM_calloc_arrayN<IDPropertyUIDataEnumItem>(1, __func__);
86 idprop_items->value = 0;
87 idprop_items->identifier = BLI_strdup("DUMMY");
88 idprop_items->name = BLI_strdup("");
89 idprop_items->description = BLI_strdup("");
90 idprop_items->icon = ICON_NONE;
91 }
92
93 /* Node enum definitions should already be valid. */
94 BLI_assert(IDP_EnumItemsValidate(idprop_items, idprop_items_num, nullptr));
95 ui_data->enum_items = idprop_items;
96 ui_data->enum_items_num = idprop_items_num;
97}
98
99static std::unique_ptr<IDProperty, bke::idprop::IDPropertyDeleter> id_name_or_value_prop(
100 const StringRefNull identifier, ID *id, const ID_Type id_type, const bool use_name_for_ids)
101{
102 if (use_name_for_ids) {
103 return bke::idprop::create(identifier, id ? id->name + 2 : "");
104 }
105 auto prop = bke::idprop::create(identifier, id);
107 ui_data->id_type = id_type;
108 return prop;
109}
110
111std::unique_ptr<IDProperty, bke::idprop::IDPropertyDeleter> id_property_create_from_socket(
112 const bNodeTreeInterfaceSocket &socket,
113 const nodes::StructureType structure_type,
114 const bool use_name_for_ids)
115{
116 if (structure_type == StructureType::Grid) {
117 /* Grids currently aren't exposed as properties. */
118 return nullptr;
119 }
120 const StringRefNull identifier = socket.identifier;
121 const bke::bNodeSocketType *typeinfo = socket.socket_typeinfo();
122 const eNodeSocketDatatype type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
123 switch (type) {
124 case SOCK_FLOAT: {
125 const bNodeSocketValueFloat *value = static_cast<const bNodeSocketValueFloat *>(
126 socket.socket_data);
127 auto property = bke::idprop::create(identifier, value->value);
129 ui_data->base.rna_subtype = value->subtype;
130 ui_data->soft_min = double(value->min);
131 ui_data->soft_max = double(value->max);
132 ui_data->default_value = value->value;
133 return property;
134 }
135 case SOCK_INT: {
136 const bNodeSocketValueInt *value = static_cast<const bNodeSocketValueInt *>(
137 socket.socket_data);
138 auto property = bke::idprop::create(identifier, value->value);
139 IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get());
140 ui_data->base.rna_subtype = value->subtype;
141 ui_data->soft_min = value->min;
142 ui_data->soft_max = value->max;
143 ui_data->default_value = value->value;
144 return property;
145 }
146 case SOCK_VECTOR: {
147 const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>(
148 socket.socket_data);
149 auto property = bke::idprop::create(
150 identifier,
151 Span<float>{value->value[0], value->value[1], value->value[2], value->value[3]}
152 .take_front(value->dimensions));
154 ui_data->base.rna_subtype = value->subtype;
155 ui_data->soft_min = double(value->min);
156 ui_data->soft_max = double(value->max);
157 ui_data->default_array = MEM_malloc_arrayN<double>(value->dimensions, "mod_prop_default");
158 ui_data->default_array_len = value->dimensions;
159 for (const int i : IndexRange(value->dimensions)) {
160 ui_data->default_array[i] = double(value->value[i]);
161 }
162 return property;
163 }
164 case SOCK_RGBA: {
165 const bNodeSocketValueRGBA *value = static_cast<const bNodeSocketValueRGBA *>(
166 socket.socket_data);
167 auto property = bke::idprop::create(
168 identifier,
169 Span<float>{value->value[0], value->value[1], value->value[2], value->value[3]});
171 ui_data->base.rna_subtype = PROP_COLOR;
172 ui_data->default_array = MEM_malloc_arrayN<double>(4, __func__);
173 ui_data->default_array_len = 4;
174 ui_data->min = 0.0;
175 ui_data->max = FLT_MAX;
176 ui_data->soft_min = 0.0;
177 ui_data->soft_max = 1.0;
178 for (const int i : IndexRange(4)) {
179 ui_data->default_array[i] = double(value->value[i]);
180 }
181 return property;
182 }
183 case SOCK_BOOLEAN: {
184 if (is_layer_selection_field(socket)) {
185 /* We can't use the value from the socket here since it doesn't storing a string. */
186 return bke::idprop::create(identifier, "");
187 }
188 const bNodeSocketValueBoolean *value = static_cast<const bNodeSocketValueBoolean *>(
189 socket.socket_data);
190 auto property = bke::idprop::create_bool(identifier, value->value);
192 ui_data->default_value = value->value != 0;
193 return property;
194 }
195 case SOCK_ROTATION: {
196 const bNodeSocketValueRotation *value = static_cast<const bNodeSocketValueRotation *>(
197 socket.socket_data);
198 auto property = bke::idprop::create(
199 identifier,
200 Span<float>{value->value_euler[0], value->value_euler[1], value->value_euler[2]});
201 IDPropertyUIDataFloat *ui_data = reinterpret_cast<IDPropertyUIDataFloat *>(
202 IDP_ui_data_ensure(property.get()));
203 ui_data->base.rna_subtype = PROP_EULER;
204 return property;
205 }
206 case SOCK_STRING: {
207 const bNodeSocketValueString *value = static_cast<const bNodeSocketValueString *>(
208 socket.socket_data);
209 auto property = bke::idprop::create(identifier, value->value);
211 property.get());
212 ui_data->default_value = BLI_strdup(value->value);
213 ui_data->base.rna_subtype = value->subtype;
214 return property;
215 }
216 case SOCK_MENU: {
217 const bNodeSocketValueMenu *value = static_cast<const bNodeSocketValueMenu *>(
218 socket.socket_data);
219 auto property = bke::idprop::create(identifier, value->value);
220 IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get());
221 id_property_int_update_enum_items(value, ui_data);
222 ui_data->default_value = value->value;
223 return property;
224 }
225 case SOCK_OBJECT: {
226 const bNodeSocketValueObject *value = static_cast<const bNodeSocketValueObject *>(
227 socket.socket_data);
228 ID *id = reinterpret_cast<ID *>(value->value);
229 auto property = id_name_or_value_prop(identifier, id, ID_OB, use_name_for_ids);
230 return property;
231 }
232 case SOCK_COLLECTION: {
233 const bNodeSocketValueCollection *value = static_cast<const bNodeSocketValueCollection *>(
234 socket.socket_data);
235 ID *id = reinterpret_cast<ID *>(value->value);
236 return id_name_or_value_prop(identifier, id, ID_GR, use_name_for_ids);
237 }
238 case SOCK_TEXTURE: {
239 const bNodeSocketValueTexture *value = static_cast<const bNodeSocketValueTexture *>(
240 socket.socket_data);
241 ID *id = reinterpret_cast<ID *>(value->value);
242 return id_name_or_value_prop(identifier, id, ID_TE, use_name_for_ids);
243 }
244 case SOCK_IMAGE: {
245 const bNodeSocketValueImage *value = static_cast<const bNodeSocketValueImage *>(
246 socket.socket_data);
247 ID *id = reinterpret_cast<ID *>(value->value);
248 return id_name_or_value_prop(identifier, id, ID_IM, use_name_for_ids);
249 }
250 case SOCK_MATERIAL: {
251 const bNodeSocketValueMaterial *value = static_cast<const bNodeSocketValueMaterial *>(
252 socket.socket_data);
253 ID *id = reinterpret_cast<ID *>(value->value);
254 return id_name_or_value_prop(identifier, id, ID_MA, use_name_for_ids);
255 }
256 case SOCK_MATRIX:
257 case SOCK_CUSTOM:
258 case SOCK_GEOMETRY:
259 case SOCK_SHADER:
260 case SOCK_BUNDLE:
261 case SOCK_CLOSURE:
262 return nullptr;
263 }
264 return nullptr;
265}
266
268 IDProperty *new_property)
269{
270 if (old_property.type != IDP_INT) {
271 return false;
272 }
273 if (new_property) {
274 BLI_assert(new_property->type == IDP_INT);
275 IDP_Int(new_property) = IDP_Int(&old_property);
276 }
277 return true;
278}
279
281 const IDProperty &old_property, IDProperty *new_property, const int len)
282{
283 if (!(old_property.type == IDP_ARRAY &&
284 ELEM(old_property.subtype, IDP_INT, IDP_FLOAT, IDP_DOUBLE)))
285 {
286 return false;
287 }
288
289 if (new_property) {
290 BLI_assert(new_property->type == IDP_ARRAY && new_property->subtype == IDP_FLOAT);
291
292 switch (old_property.subtype) {
293 case IDP_DOUBLE: {
294 double *const old_value = static_cast<double *const>(IDP_Array(&old_property));
295 float *new_value = static_cast<float *>(new_property->data.pointer);
296 for (int i = 0; i < len; i++) {
297 if (i < old_property.len) {
298 new_value[i] = float(old_value[i]);
299 }
300 else {
301 new_value[i] = 0.0f;
302 }
303 }
304 break;
305 }
306 case IDP_INT: {
307 int *const old_value = static_cast<int *const>(IDP_Array(&old_property));
308 float *new_value = static_cast<float *>(new_property->data.pointer);
309 for (int i = 0; i < len; i++) {
310 if (i < old_property.len) {
311 new_value[i] = float(old_value[i]);
312 }
313 else {
314 new_value[i] = 0.0f;
315 }
316 }
317 break;
318 }
319 case IDP_FLOAT: {
320 float *const old_value = static_cast<float *const>(IDP_Array(&old_property));
321 float *new_value = static_cast<float *>(new_property->data.pointer);
322 for (int i = 0; i < len; i++) {
323 if (i < old_property.len) {
324 new_value[i] = old_value[i];
325 }
326 else {
327 new_value[i] = 0.0f;
328 }
329 }
330 break;
331 }
332 }
333 }
334 return true;
335}
336
338 const IDProperty &old_property, IDProperty *new_property)
339{
340 if (old_property.type != IDP_STRING || old_property.subtype != IDP_STRING_SUB_UTF8) {
341 return false;
342 }
343 if (new_property) {
344 BLI_assert(new_property->type == IDP_STRING && new_property->subtype == IDP_STRING_SUB_UTF8);
345 IDP_AssignString(new_property, IDP_String(&old_property));
346 }
347 return true;
348}
349
359 const bNodeTreeInterfaceSocket &socket,
360 const IDProperty &old_property,
361 IDProperty *new_property,
362 const bool use_name_for_ids)
363{
364 const bke::bNodeSocketType *typeinfo = socket.socket_typeinfo();
365 const eNodeSocketDatatype type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
366 switch (type) {
367 case SOCK_FLOAT:
368 if (!ELEM(old_property.type, IDP_FLOAT, IDP_INT, IDP_DOUBLE)) {
369 return false;
370 }
371 if (new_property) {
372 BLI_assert(new_property->type == IDP_FLOAT);
373 switch (old_property.type) {
374 case IDP_DOUBLE:
375 IDP_Float(new_property) = float(IDP_Double(&old_property));
376 break;
377 case IDP_INT:
378 IDP_Float(new_property) = float(IDP_Int(&old_property));
379 break;
380 case IDP_FLOAT:
381 IDP_Float(new_property) = IDP_Float(&old_property);
382 break;
383 }
384 }
385 return true;
386 case SOCK_INT:
387 return old_id_property_type_matches_socket_convert_to_new_int(old_property, new_property);
388 case SOCK_VECTOR: {
389 const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>(
390 socket.socket_data);
392 old_property, new_property, value->dimensions);
393 }
394 case SOCK_ROTATION:
396 old_property, new_property, 3);
397 case SOCK_RGBA:
399 old_property, new_property, 4);
400 case SOCK_BOOLEAN:
401 if (is_layer_selection_field(socket)) {
403 new_property);
404 }
405 if (!ELEM(old_property.type, IDP_BOOLEAN, IDP_INT)) {
406 return false;
407 }
408 /* Exception: Do conversion from old Integer property (for versioning from older data model),
409 * but do not consider int idprop as a valid input for a bool socket. */
410 if (new_property) {
411 BLI_assert(new_property->type == IDP_BOOLEAN);
412 switch (old_property.type) {
413 case IDP_INT:
414 IDP_Bool(new_property) = bool(IDP_Int(&old_property));
415 break;
416 case IDP_BOOLEAN:
417 IDP_Bool(new_property) = IDP_Bool(&old_property);
418 break;
419 }
420 }
421 return old_property.type == IDP_BOOLEAN;
422 case SOCK_STRING:
423 return old_id_property_type_matches_socket_convert_to_new_string(old_property, new_property);
424 case SOCK_MENU:
425 return old_id_property_type_matches_socket_convert_to_new_int(old_property, new_property);
426 case SOCK_OBJECT:
427 case SOCK_COLLECTION:
428 case SOCK_TEXTURE:
429 case SOCK_IMAGE:
430 case SOCK_MATERIAL:
431 if (use_name_for_ids) {
433 new_property);
434 }
435 if (old_property.type != IDP_ID) {
436 return false;
437 }
438 if (new_property) {
439 BLI_assert(new_property->type == IDP_ID);
440 ID *id = IDP_Id(&old_property);
441 new_property->data.pointer = id;
442 id_us_plus(id);
443 }
444 return true;
445 case SOCK_CUSTOM:
446 case SOCK_MATRIX:
447 case SOCK_GEOMETRY:
448 case SOCK_SHADER:
449 case SOCK_BUNDLE:
450 case SOCK_CLOSURE:
451 return false;
452 }
454 return false;
455}
456
458 const IDProperty &property,
459 const bool use_name_for_ids)
460{
462 socket, property, nullptr, use_name_for_ids);
463}
464
466{
467 if (!properties) {
468 return {};
469 }
471 set.reserve(BLI_listbase_count(&properties->data.group));
472 LISTBASE_FOREACH (IDProperty *, prop, &properties->data.group) {
473 set.add_new(prop);
474 }
475 return set;
476}
477
479 const eNodeSocketDatatype socket_value_type,
480 void *r_value)
481{
482 switch (socket_value_type) {
483 case SOCK_FLOAT: {
484 float value = 0.0f;
485 if (property.type == IDP_FLOAT) {
486 value = IDP_Float(&property);
487 }
488 else if (property.type == IDP_DOUBLE) {
489 value = float(IDP_Double(&property));
490 }
491 new (r_value) bke::SocketValueVariant(value);
492 break;
493 }
494 case SOCK_INT: {
495 int value = IDP_Int(&property);
496 new (r_value) bke::SocketValueVariant(value);
497 break;
498 }
499 case SOCK_VECTOR: {
500 const void *property_array = IDP_Array(&property);
501 BLI_assert(property.len >= 2 && property.len <= 4);
502
503 float4 values = float4(0.0f);
504 if (property.subtype == IDP_FLOAT) {
505 for (int i = 0; i < property.len; i++) {
506 values[i] = static_cast<const float *>(property_array)[i];
507 }
508 }
509 else if (property.subtype == IDP_INT) {
510 for (int i = 0; i < property.len; i++) {
511 values[i] = float(static_cast<const int *>(property_array)[i]);
512 }
513 }
514 else if (property.subtype == IDP_DOUBLE) {
515 for (int i = 0; i < property.len; i++) {
516 values[i] = float(static_cast<const double *>(property_array)[i]);
517 }
518 }
519 else {
521 }
522
523 /* Only float3 vectors are supported for now. */
524 new (r_value) bke::SocketValueVariant(float3(values));
525 break;
526 }
527 case SOCK_RGBA: {
528 const void *property_array = IDP_Array(&property);
529 float4 vec;
530 if (property.subtype == IDP_FLOAT) {
531 vec = float4(static_cast<const float *>(property_array));
532 }
533 else if (property.subtype == IDP_INT) {
534 vec = float4(int4(static_cast<const int *>(property_array)));
535 }
536 else {
537 BLI_assert(property.subtype == IDP_DOUBLE);
538 vec = float4(double4(static_cast<const double *>(property_array)));
539 }
540 ColorGeometry4f value(vec);
541 new (r_value) bke::SocketValueVariant(value);
542 break;
543 }
544 case SOCK_BOOLEAN: {
545 const bool value = IDP_Bool(&property);
546 new (r_value) bke::SocketValueVariant(value);
547 break;
548 }
549 case SOCK_ROTATION: {
550 const void *property_array = IDP_Array(&property);
551 float3 vec;
552 if (property.subtype == IDP_FLOAT) {
553 vec = float3(static_cast<const float *>(property_array));
554 }
555 else if (property.subtype == IDP_INT) {
556 vec = float3(int3(static_cast<const int *>(property_array)));
557 }
558 else {
559 BLI_assert(property.subtype == IDP_DOUBLE);
560 vec = float3(double3(static_cast<const double *>(property_array)));
561 }
562 const math::EulerXYZ euler_value = math::EulerXYZ(vec);
563 new (r_value) bke::SocketValueVariant(math::to_quaternion(euler_value));
564 break;
565 }
566 case SOCK_STRING: {
567 std::string value = IDP_String(&property);
568 new (r_value) bke::SocketValueVariant(std::move(value));
569 break;
570 }
571 case SOCK_MENU: {
572 int value = IDP_Int(&property);
573 new (r_value) bke::SocketValueVariant(std::move(value));
574 break;
575 }
576 case SOCK_OBJECT: {
577 ID *id = IDP_Id(&property);
578 Object *object = (id && GS(id->name) == ID_OB) ? (Object *)id : nullptr;
579 *(Object **)r_value = object;
580 break;
581 }
582 case SOCK_COLLECTION: {
583 ID *id = IDP_Id(&property);
584 Collection *collection = (id && GS(id->name) == ID_GR) ? (Collection *)id : nullptr;
585 *(Collection **)r_value = collection;
586 break;
587 }
588 case SOCK_TEXTURE: {
589 ID *id = IDP_Id(&property);
590 Tex *texture = (id && GS(id->name) == ID_TE) ? (Tex *)id : nullptr;
591 *(Tex **)r_value = texture;
592 break;
593 }
594 case SOCK_IMAGE: {
595 ID *id = IDP_Id(&property);
596 Image *image = (id && GS(id->name) == ID_IM) ? (Image *)id : nullptr;
597 *(Image **)r_value = image;
598 break;
599 }
600 case SOCK_MATERIAL: {
601 ID *id = IDP_Id(&property);
602 Material *material = (id && GS(id->name) == ID_MA) ? (Material *)id : nullptr;
603 *(Material **)r_value = material;
604 break;
605 }
606 default: {
608 break;
609 }
610 }
611}
612
613std::optional<StringRef> input_attribute_name_get(const PropertiesVectorSet &properties,
614 const bNodeTreeInterfaceSocket &io_input)
615{
616 IDProperty *use_attribute = properties.lookup_key_default_as(
617 io_input.identifier + input_use_attribute_suffix, nullptr);
618 if (!use_attribute) {
619 return std::nullopt;
620 }
621 if (use_attribute->type == IDP_INT) {
622 if (IDP_Int(use_attribute) == 0) {
623 return std::nullopt;
624 }
625 }
626 if (use_attribute->type == IDP_BOOLEAN) {
627 if (!IDP_Bool(use_attribute)) {
628 return std::nullopt;
629 }
630 }
631
632 const IDProperty *property_attribute_name = properties.lookup_key_default_as(
633 io_input.identifier + input_attribute_name_suffix, nullptr);
634
635 return IDP_String(property_attribute_name);
636}
637
639 const PropertiesVectorSet &properties,
640 const int input_index,
641 void *r_value)
642{
643 const bNodeTreeInterfaceSocket &io_input = *tree.interface_inputs()[input_index];
644 const bke::bNodeSocketType *typeinfo = io_input.socket_typeinfo();
645 const eNodeSocketDatatype socket_data_type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
646 const IDProperty *property = properties.lookup_key_default_as(io_input.identifier, nullptr);
647 if (property == nullptr) {
648 typeinfo->get_geometry_nodes_cpp_value(io_input.socket_data, r_value);
649 return;
650 }
651 if (!id_property_type_matches_socket(io_input, *property)) {
652 typeinfo->get_geometry_nodes_cpp_value(io_input.socket_data, r_value);
653 return;
654 }
655
656 if (!input_has_attribute_toggle(tree, input_index)) {
657 init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
658 return;
659 }
660
661 const std::optional<StringRef> attribute_name = input_attribute_name_get(properties, io_input);
662 if (attribute_name && bke::allow_procedural_attribute_access(*attribute_name)) {
663 fn::GField attribute_field = bke::AttributeFieldInput::Create(*attribute_name,
664 *typeinfo->base_cpp_type);
665 new (r_value) bke::SocketValueVariant(std::move(attribute_field));
666 }
667 else if (is_layer_selection_field(io_input)) {
668 const IDProperty *property_layer_name = properties.lookup_key_as(io_input.identifier);
669 StringRef layer_name = IDP_String(property_layer_name);
670 const fn::GField selection_field(
671 std::make_shared<bke::NamedLayerSelectionFieldInput>(layer_name), 0);
672 new (r_value) bke::SocketValueVariant(std::move(selection_field));
673 }
674 else {
675 init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
676 }
677}
678
683
690
696 const bNodeTree &tree,
697 const PropertiesVectorSet &properties,
698 Span<GMutablePointer> output_values)
699{
700 const bNode &output_node = *tree.group_output_node();
702 for (const bNodeSocket *socket : output_node.input_sockets().drop_front(1).drop_back(1)) {
704 continue;
705 }
706
707 const std::string prop_name = socket->identifier + input_attribute_name_suffix;
708 const IDProperty *prop = properties.lookup_key_default_as(prop_name, nullptr);
709 if (prop == nullptr) {
710 continue;
711 }
712 const StringRefNull attribute_name = IDP_String(prop);
713 if (attribute_name.is_empty()) {
714 continue;
715 }
716 if (!bke::allow_procedural_attribute_access(attribute_name)) {
717 continue;
718 }
719
720 const int index = socket->index();
721 bke::SocketValueVariant &value_variant = *output_values[index].get<bke::SocketValueVariant>();
722 const fn::GField field = value_variant.get<fn::GField>();
723
724 const bNodeTreeInterfaceSocket *interface_socket = tree.interface_outputs()[index];
725 const bke::AttrDomain domain = bke::AttrDomain(interface_socket->attribute_domain);
726 OutputAttributeInfo output_info;
727 output_info.field = std::move(field);
728 output_info.name = attribute_name;
729 outputs_by_domain.add(domain, std::move(output_info));
730 }
731 return outputs_by_domain;
732}
733
741 const bool do_instances)
742{
743 Vector<OutputAttributeToStore> attributes_to_store;
744 for (const auto component_type : {bke::GeometryComponent::Type::Mesh,
748 {
749 if (!geometry.has(component_type)) {
750 continue;
751 }
752 if (!do_instances && component_type == bke::GeometryComponent::Type::Instance) {
753 continue;
754 }
755 const bke::GeometryComponent &component = *geometry.get_component(component_type);
756 const bke::AttributeAccessor attributes = *component.attributes();
757 for (const auto item : outputs_by_domain.items()) {
758 const bke::AttrDomain domain = item.key;
759 const Span<OutputAttributeInfo> outputs_info = item.value;
760 if (!attributes.domain_supported(domain)) {
761 continue;
762 }
763 const int domain_size = attributes.domain_size(domain);
764 bke::GeometryFieldContext field_context{component, domain};
765 fn::FieldEvaluator field_evaluator{field_context, domain_size};
766 for (const OutputAttributeInfo &output_info : outputs_info) {
767 const CPPType &type = output_info.field.cpp_type();
768 const bke::AttributeValidator validator = attributes.lookup_validator(output_info.name);
769
771 component_type,
772 domain,
773 output_info.name,
774 GMutableSpan{type,
775 MEM_mallocN_aligned(type.size * domain_size, type.alignment, __func__),
776 domain_size}};
777 fn::GField field = validator.validate_field_if_necessary(output_info.field);
778 field_evaluator.add_with_destination(std::move(field), store.data);
779 attributes_to_store.append(store);
780 }
781 field_evaluator.evaluate();
782 }
783 }
784 return attributes_to_store;
785}
786
788 bke::GeometrySet &geometry, const Span<OutputAttributeToStore> attributes_to_store)
789{
790 for (const OutputAttributeToStore &store : attributes_to_store) {
791 bke::GeometryComponent &component = geometry.get_component_for_write(store.component_type);
792 bke::MutableAttributeAccessor attributes = *component.attributes_for_write();
793
794 const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(store.data.type());
795 const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(
796 store.name);
797
798 /* Attempt to remove the attribute if it already exists but the domain and type don't match.
799 * Removing the attribute won't succeed if it is built in and non-removable. */
800 if (meta_data.has_value() &&
801 (meta_data->domain != store.domain || meta_data->data_type != data_type))
802 {
803 attributes.remove(store.name);
804 }
805
806 /* Try to create the attribute reusing the stored buffer. This will only succeed if the
807 * attribute didn't exist before, or if it existed but was removed above. */
808 if (attributes.add(store.name,
809 store.domain,
810 bke::cpp_type_to_custom_data_type(store.data.type()),
811 bke::AttributeInitMoveArray(store.data.data())))
812 {
813 continue;
814 }
815
816 bke::GAttributeWriter attribute = attributes.lookup_or_add_for_write(
817 store.name, store.domain, data_type);
818 if (attribute) {
819 attribute.varray.set_all(store.data.data());
820 attribute.finish();
821 }
822
823 /* We were unable to reuse the data, so it must be destructed and freed. */
824 store.data.type().destruct_n(store.data.data(), store.data.size());
825 MEM_freeN(store.data.data());
826 }
827}
828
830 const bNodeTree &tree,
831 const PropertiesVectorSet &properties,
832 Span<GMutablePointer> output_values)
833{
834 /* All new attribute values have to be computed before the geometry is actually changed. This is
835 * necessary because some fields might depend on attributes that are overwritten. */
837 find_output_attributes_to_store(tree, properties, output_values);
838 if (outputs_by_domain.size() == 0) {
839 return;
840 }
841 const bool only_instance_attributes = outputs_by_domain.size() == 1 &&
842 *outputs_by_domain.keys().begin() ==
844 if (only_instance_attributes) {
845 /* No need to call #modify_geometry_sets when only adding attributes to top-level instances.
846 * This avoids some unnecessary data copies currently if some sub-geometries are not yet owned
847 * by the geometry set, i.e. they use #GeometryOwnershipType::Editable/ReadOnly. */
849 geometry, outputs_by_domain, true);
850 store_computed_output_attributes(geometry, attributes_to_store);
851 return;
852 }
853
854 geometry.modify_geometry_sets([&](bke::GeometrySet &instance_geometry) {
855 /* Instance attributes should only be created for the top-level geometry. */
856 const bool do_instances = &geometry == &instance_geometry;
858 instance_geometry, outputs_by_domain, do_instances);
859 store_computed_output_attributes(instance_geometry, attributes_to_store);
860 });
861}
862
864 const PropertiesVectorSet &properties_set,
865 const ComputeContext &base_compute_context,
866 GeoNodesCallData &call_data,
867 bke::GeometrySet input_geometry)
868{
869 const GeometryNodesLazyFunctionGraphInfo &lf_graph_info =
871 const GeometryNodesGroupFunction &function = lf_graph_info.function;
872 const lf::LazyFunction &lazy_function = *function.function;
873 const int num_inputs = lazy_function.inputs().size();
874 const int num_outputs = lazy_function.outputs().size();
875
876 Array<GMutablePointer> param_inputs(num_inputs);
877 Array<GMutablePointer> param_outputs(num_outputs);
878 Array<std::optional<lf::ValueUsage>> param_input_usages(num_inputs);
879 Array<lf::ValueUsage> param_output_usages(num_outputs);
880 Array<bool> param_set_outputs(num_outputs, false);
881
882 /* We want to evaluate the main outputs, but don't care about which inputs are used for now. */
883 param_output_usages.as_mutable_span().slice(function.outputs.main).fill(lf::ValueUsage::Used);
884 param_output_usages.as_mutable_span()
885 .slice(function.outputs.input_usages)
887
888 GeoNodesUserData user_data;
889 user_data.call_data = &call_data;
890 call_data.root_ntree = &btree;
891
892 user_data.compute_context = &base_compute_context;
893
894 LinearAllocator<> allocator;
895 Vector<GMutablePointer> inputs_to_destruct;
896
897 btree.ensure_interface_cache();
898
899 /* Prepare main inputs. */
900 for (const int i : btree.interface_inputs().index_range()) {
901 const bNodeTreeInterfaceSocket &interface_socket = *btree.interface_inputs()[i];
902 const bke::bNodeSocketType *typeinfo = interface_socket.socket_typeinfo();
903 const eNodeSocketDatatype socket_type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
904 if (socket_type == SOCK_GEOMETRY && i == 0) {
905 param_inputs[function.inputs.main[0]] = &input_geometry;
906 continue;
907 }
908
909 const CPPType *type = typeinfo->geometry_nodes_cpp_type;
910 BLI_assert(type != nullptr);
911 void *value = allocator.allocate(*type);
912 initialize_group_input(btree, properties_set, i, value);
913 param_inputs[function.inputs.main[i]] = {type, value};
914 inputs_to_destruct.append({type, value});
915 }
916
917 /* Prepare used-outputs inputs. */
918 Array<bool> output_used_inputs(btree.interface_outputs().size(), true);
919 for (const int i : btree.interface_outputs().index_range()) {
920 param_inputs[function.inputs.output_usages[i]] = &output_used_inputs[i];
921 }
922
923 /* No anonymous attributes have to be propagated. */
924 Array<bke::GeometryNodesReferenceSet> references_to_propagate(
926 for (const int i : references_to_propagate.index_range()) {
927 param_inputs[function.inputs.references_to_propagate.range[i]] = &references_to_propagate[i];
928 }
929
930 /* Prepare memory for output values. */
931 for (const int i : IndexRange(num_outputs)) {
932 const lf::Output &lf_output = lazy_function.outputs()[i];
933 const CPPType &type = *lf_output.type;
934 void *buffer = allocator.allocate(type);
935 param_outputs[i] = {type, buffer};
936 }
937
938 GeoNodesLocalUserData local_user_data(user_data);
939
940 lf::Context lf_context(lazy_function.init_storage(allocator), &user_data, &local_user_data);
941 lf::BasicParams lf_params{lazy_function,
942 param_inputs,
943 param_outputs,
944 param_input_usages,
945 param_output_usages,
946 param_set_outputs};
947 {
949 lazy_function.execute(lf_params, lf_context);
950 }
951 lazy_function.destruct_storage(lf_context.storage);
952
953 for (GMutablePointer &ptr : inputs_to_destruct) {
954 ptr.destruct();
955 }
956
957 bke::GeometrySet output_geometry = std::move(*param_outputs[0].get<bke::GeometrySet>());
958 store_output_attributes(output_geometry, btree, properties_set, param_outputs);
959
960 for (const int i : IndexRange(num_outputs)) {
961 if (param_set_outputs[i]) {
962 GMutablePointer &ptr = param_outputs[i];
963 ptr.destruct();
964 }
965 }
966
967 return output_geometry;
968}
969
971 const IDProperty *old_properties,
972 IDProperty &properties,
973 const bool use_name_for_ids)
974{
975 tree.ensure_interface_cache();
976 const Span<const bNodeTreeInterfaceSocket *> tree_inputs = tree.interface_inputs();
977 const Span<nodes::StructureType> input_structure_types =
978 tree.runtime->structure_type_interface->inputs;
979 for (const int i : tree_inputs.index_range()) {
980 const bNodeTreeInterfaceSocket &socket = *tree_inputs[i];
981 const StringRefNull socket_identifier = socket.identifier;
982 const bke::bNodeSocketType *typeinfo = socket.socket_typeinfo();
983 const eNodeSocketDatatype socket_type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
985 socket, input_structure_types[i], use_name_for_ids)
986 .release();
987 if (new_prop == nullptr) {
988 continue;
989 }
990
992 if (socket.description && socket.description[0] != '\0') {
993 IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop);
994 ui_data->description = BLI_strdup(socket.description);
995 }
996 IDP_AddToGroup(&properties, new_prop);
997
998 if (old_properties != nullptr) {
999 const IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket_identifier);
1000 if (old_prop != nullptr) {
1001 /* Re-use the value (and only the value!) from the old property if possible, handling
1002 * conversion to new property's type as needed. */
1004 socket, *old_prop, new_prop, use_name_for_ids);
1005 }
1006 }
1007
1009 const std::string use_attribute_id = socket_identifier + input_use_attribute_suffix;
1010 const std::string attribute_name_id = socket_identifier + input_attribute_name_suffix;
1011
1012 IDProperty *use_attribute_prop = bke::idprop::create_bool(use_attribute_id, false).release();
1014 IDP_AddToGroup(&properties, use_attribute_prop);
1015
1016 IDProperty *attribute_prop = bke::idprop::create(attribute_name_id, "").release();
1018 IDP_AddToGroup(&properties, attribute_prop);
1019
1020 if (old_properties == nullptr) {
1021 if (socket.default_attribute_name && socket.default_attribute_name[0] != '\0') {
1023 IDP_Int(use_attribute_prop) = 1;
1024 }
1025 }
1026 else {
1027 IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties,
1028 use_attribute_id);
1029 if (old_prop_use_attribute != nullptr) {
1030 IDP_CopyPropertyContent(use_attribute_prop, old_prop_use_attribute);
1031 }
1032
1033 IDProperty *old_attribute_name_prop = IDP_GetPropertyFromGroup(old_properties,
1034 attribute_name_id);
1035 if (old_attribute_name_prop != nullptr) {
1036 IDP_CopyPropertyContent(attribute_prop, old_attribute_name_prop);
1037 }
1038 }
1039 }
1040 }
1041}
1042
1044 const IDProperty *old_properties,
1045 IDProperty &properties)
1046{
1047 tree.ensure_topology_cache();
1048 const Span<const bNodeTreeInterfaceSocket *> tree_outputs = tree.interface_outputs();
1049 for (const int i : tree_outputs.index_range()) {
1050 const bNodeTreeInterfaceSocket &socket = *tree_outputs[i];
1051 const StringRefNull socket_identifier = socket.identifier;
1052 const bke::bNodeSocketType *typeinfo = socket.socket_typeinfo();
1053 const eNodeSocketDatatype socket_type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
1054 if (!socket_type_has_attribute_toggle(socket_type)) {
1055 continue;
1056 }
1057
1058 const std::string idprop_name = socket_identifier + input_attribute_name_suffix;
1059 IDProperty *new_prop = IDP_NewStringMaxSize("", MAX_NAME, idprop_name);
1060 if (socket.description && socket.description[0] != '\0') {
1061 IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop);
1062 ui_data->description = BLI_strdup(socket.description);
1063 }
1064 IDP_AddToGroup(&properties, new_prop);
1065
1066 if (old_properties == nullptr) {
1067 if (socket.default_attribute_name && socket.default_attribute_name[0] != '\0') {
1069 }
1070 }
1071 else {
1072 IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, idprop_name);
1073 if (old_prop != nullptr) {
1074 /* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
1075 * want to replace the values). So release it temporarily and replace it after. */
1076 IDPropertyUIData *ui_data = new_prop->ui_data;
1077 new_prop->ui_data = nullptr;
1078 IDP_CopyPropertyContent(new_prop, old_prop);
1079 if (new_prop->ui_data != nullptr) {
1080 IDP_ui_data_free(new_prop);
1081 }
1082 new_prop->ui_data = ui_data;
1083 }
1084 }
1085 }
1086}
1087
1089 const PropertiesVectorSet &properties,
1090 ResourceScope &scope,
1091 MutableSpan<GPointer> r_values)
1092{
1093 /* Assume that all inputs have unknown values by default. */
1094 r_values.fill(nullptr);
1095
1096 btree.ensure_interface_cache();
1097 for (const int input_i : btree.interface_inputs().index_range()) {
1098 const bNodeTreeInterfaceSocket &io_input = *btree.interface_inputs()[input_i];
1099 const bke::bNodeSocketType *stype = io_input.socket_typeinfo();
1100 if (!stype) {
1101 continue;
1102 }
1103 const eNodeSocketDatatype socket_type = stype->type;
1104 if (!stype->base_cpp_type || !stype->geometry_nodes_cpp_type) {
1105 continue;
1106 }
1107 const IDProperty *property = properties.lookup_key_default_as(io_input.identifier, nullptr);
1108 if (!property) {
1109 continue;
1110 }
1111 if (!id_property_type_matches_socket(io_input, *property)) {
1112 continue;
1113 }
1114 if (input_attribute_name_get(properties, io_input).has_value()) {
1115 /* Attributes don't have a single base value, so ignore them here. */
1116 continue;
1117 }
1118 if (is_layer_selection_field(io_input)) {
1119 /* Can't get a single value for layer selections. */
1120 continue;
1121 }
1122
1123 void *value_buffer = scope.allocate_owned(*stype->geometry_nodes_cpp_type);
1124 init_socket_cpp_value_from_property(*property, socket_type, value_buffer);
1125 if (stype->geometry_nodes_cpp_type == stype->base_cpp_type) {
1126 r_values[input_i] = {stype->base_cpp_type, value_buffer};
1127 continue;
1128 }
1130 const bke::SocketValueVariant &socket_value = *static_cast<const bke::SocketValueVariant *>(
1131 value_buffer);
1132 if (!socket_value.is_single()) {
1133 continue;
1134 }
1135 const GPointer single_value = socket_value.get_single_ptr();
1136 BLI_assert(single_value.type() == stype->base_cpp_type);
1137 r_values[input_i] = single_value;
1138 continue;
1139 }
1140 }
1141}
1142
1143} // namespace blender::nodes
void IDP_ui_data_free(IDProperty *prop)
Definition idprop.cc:1199
#define IDP_Float(prop)
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, blender::StringRef name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:766
bool IDP_EnumItemsValidate(const IDPropertyUIDataEnumItem *items, int items_num, void(*error_fn)(const char *))
Definition idprop.cc:480
#define IDP_Int(prop)
void IDP_CopyPropertyContent(IDProperty *dst, const IDProperty *src) ATTR_NONNULL()
Definition idprop.cc:878
#define IDP_Id(prop)
#define IDP_Bool(prop)
void IDP_AssignString(IDProperty *prop, const char *st) ATTR_NONNULL()
Definition idprop.cc:431
void IDP_AssignStringMaxSize(IDProperty *prop, const char *st, size_t st_maxncpy) ATTR_NONNULL()
Definition idprop.cc:413
#define IDP_String(prop)
#define IDP_Double(prop)
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:725
IDProperty * IDP_NewStringMaxSize(const char *st, size_t st_maxncpy, blender::StringRef name, eIDPropertyFlag flags={}) ATTR_WARN_UNUSED_RESULT
Definition idprop.cc:355
IDPropertyUIData * IDP_ui_data_ensure(IDProperty *prop)
Definition idprop.cc:1751
#define IDP_Array(prop)
void id_us_plus(ID *id)
Definition lib_id.cc:353
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.cc:46
#define ELEM(...)
ID_Type
@ ID_TE
@ ID_IM
@ ID_MA
@ ID_GR
@ ID_OB
@ IDP_STRING_SUB_UTF8
@ IDP_DOUBLE
@ IDP_FLOAT
@ IDP_STRING
@ IDP_BOOLEAN
@ IDP_INT
@ IDP_ARRAY
@ IDP_ID
@ IDP_FLAG_STATIC_TYPE
@ IDP_FLAG_OVERRIDABLE_LIBRARY
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_TEXTURE
@ SOCK_VECTOR
@ SOCK_CLOSURE
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_CUSTOM
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
@ PROP_COLOR
Definition RNA_types.hh:248
@ PROP_EULER
Definition RNA_types.hh:254
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
IndexRange index_range() const
Definition BLI_array.hh:349
static const CPPType & get()
const CPPType * type() const
void set_all(const void *src)
void * allocate(const int64_t size, const int64_t alignment)
MapType::KeyIterator keys() const
MapType::ItemIterator items() const
void add(const Key &key, const Value &value)
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
void * allocate_owned(const CPPType &type)
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:193
constexpr bool is_empty() const
const Key & lookup_key_as(const ForwardKey &key) const
void reserve(const int64_t n)
Key lookup_key_default_as(const ForwardKey &key, ForwardDefault &&...default_key) const
void add_new(const Key &key)
int64_t size() const
void append(const T &value)
AttributeValidator lookup_validator(const StringRef attribute_id) const
bool domain_supported(const AttrDomain domain) const
int domain_size(const AttrDomain domain) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
static fn::GField Create(std::string name, const CPPType &type, std::optional< std::string > socket_inspection_name=std::nullopt)
virtual std::optional< AttributeAccessor > attributes() const
virtual std::optional< MutableAttributeAccessor > attributes_for_write()
GAttributeWriter lookup_or_add_for_write(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:738
virtual void * init_storage(LinearAllocator<> &allocator) const
virtual void destruct_storage(void *storage) const
void execute(Params &params, const Context &context) const
KDTree_3d * tree
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define MAX_NAME
#define GS(a)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
std::unique_ptr< IDProperty, IDPropertyDeleter > create_bool(StringRef prop_name, bool value, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_BOOLEAN, set its name and value.
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRef prop_name, int32_t value, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_INT, set its name and value.
bool allow_procedural_attribute_access(StringRef attribute_name)
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
EulerXYZBase< float > EulerXYZ
static void store_computed_output_attributes(bke::GeometrySet &geometry, const Span< OutputAttributeToStore > attributes_to_store)
static bool old_id_property_type_matches_socket_convert_to_new_string(const IDProperty &old_property, IDProperty *new_property)
bke::GeometrySet execute_geometry_nodes_on_geometry(const bNodeTree &btree, const PropertiesVectorSet &properties_set, const ComputeContext &base_compute_context, GeoNodesCallData &call_data, bke::GeometrySet input_geometry)
std::unique_ptr< IDProperty, bke::idprop::IDPropertyDeleter > id_property_create_from_socket(const bNodeTreeInterfaceSocket &socket, const nodes::StructureType structure_type, const bool use_name_for_ids)
PropertiesVectorSet build_properties_vector_set(const IDProperty *properties)
void update_input_properties_from_node_tree(const bNodeTree &tree, const IDProperty *old_properties, IDProperty &properties, const bool use_name_for_ids)
bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
static void initialize_group_input(const bNodeTree &tree, const PropertiesVectorSet &properties, const int input_index, void *r_value)
static std::unique_ptr< IDProperty, bke::idprop::IDPropertyDeleter > id_name_or_value_prop(const StringRefNull identifier, ID *id, const ID_Type id_type, const bool use_name_for_ids)
static void id_property_int_update_enum_items(const bNodeSocketValueMenu *value, IDPropertyUIDataInt *ui_data)
bool id_property_type_matches_socket(const bNodeTreeInterfaceSocket &socket, const IDProperty &property, const bool use_name_for_ids)
CustomIDVectorSet< IDProperty *, IDPropNameGetter, 16 > PropertiesVectorSet
const GeometryNodesLazyFunctionGraphInfo * ensure_geometry_nodes_lazy_function_graph(const bNodeTree &btree)
static void store_output_attributes(bke::GeometrySet &geometry, const bNodeTree &tree, const PropertiesVectorSet &properties, Span< GMutablePointer > output_values)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
static Vector< OutputAttributeToStore > compute_attributes_to_store(const bke::GeometrySet &geometry, const MultiValueMap< bke::AttrDomain, OutputAttributeInfo > &outputs_by_domain, const bool do_instances)
void update_output_properties_from_node_tree(const bNodeTree &tree, const IDProperty *old_properties, IDProperty &properties)
static MultiValueMap< bke::AttrDomain, OutputAttributeInfo > find_output_attributes_to_store(const bNodeTree &tree, const PropertiesVectorSet &properties, Span< GMutablePointer > output_values)
static bool old_id_property_type_matches_socket_convert_to_new_float_vec(const IDProperty &old_property, IDProperty *new_property, const int len)
void get_geometry_nodes_input_base_values(const bNodeTree &btree, const PropertiesVectorSet &properties, ResourceScope &scope, MutableSpan< GPointer > r_values)
static void init_socket_cpp_value_from_property(const IDProperty &property, const eNodeSocketDatatype socket_value_type, void *r_value)
bool socket_type_has_attribute_toggle(const eNodeSocketDatatype type)
constexpr StringRef input_attribute_name_suffix
constexpr StringRef input_use_attribute_suffix
static bool old_id_property_type_matches_socket_convert_to_new(const bNodeTreeInterfaceSocket &socket, const IDProperty &old_property, IDProperty *new_property, const bool use_name_for_ids)
static bool old_id_property_type_matches_socket_convert_to_new_int(const IDProperty &old_property, IDProperty *new_property)
std::optional< StringRef > input_attribute_name_get(const PropertiesVectorSet &properties, const bNodeTreeInterfaceSocket &io_input)
VecBase< int32_t, 4 > int4
VecBase< float, 4 > float4
VecBase< int32_t, 3 > int3
VecBase< double, 3 > double3
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
VecBase< double, 4 > double4
bool is_layer_selection_field(const bNodeTreeInterfaceSocket &socket)
#define FLT_MAX
Definition stdcycles.h:14
ListBase group
Definition DNA_ID.h:138
void * pointer
Definition DNA_ID.h:137
int8_t default_value
Definition DNA_ID.h:96
double * default_array
Definition DNA_ID.h:102
IDPropertyUIData base
Definition DNA_ID.h:101
IDPropertyUIData base
Definition DNA_ID.h:74
IDPropertyUIDataEnumItem * enum_items
Definition DNA_ID.h:86
IDPropertyUIData base
Definition DNA_ID.h:118
char * description
Definition DNA_ID.h:51
short flag
Definition DNA_ID.h:153
int len
Definition DNA_ID.h:165
IDPropertyUIData * ui_data
Definition DNA_ID.h:173
IDPropertyData data
Definition DNA_ID.h:159
char subtype
Definition DNA_ID.h:151
char type
Definition DNA_ID.h:146
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
struct Collection * value
const RuntimeNodeEnumItemsHandle * enum_items
bNodeTreeRuntimeHandle * runtime
fn::GField validate_field_if_necessary(const fn::GField &field) const
Defines a socket type.
Definition BKE_node.hh:152
const blender::CPPType * geometry_nodes_cpp_type
Definition BKE_node.hh:203
eNodeSocketDatatype type
Definition BKE_node.hh:187
SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value
Definition BKE_node.hh:205
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:199
struct blender::nodes::GeometryNodesGroupFunction::@311217322151273055243347055333132220230004041004 inputs
struct blender::nodes::GeometryNodesGroupFunction::@311217322151273055243347055333132220230004041004::@376313040076355172126342102314323105254352264056 references_to_propagate
struct blender::nodes::GeometryNodesGroupFunction::@132153240164066211264033224237254060060001355126 outputs
i
Definition text_draw.cc:230
wmTimer * timer
uint len
PointerRNA * ptr
Definition wm_files.cc:4226