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