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