Blender  V3.3
MOD_nodes.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2005 Blender Foundation. All rights reserved. */
3 
8 #include <cstring>
9 #include <iostream>
10 #include <string>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_array.hh"
15 #include "BLI_listbase.h"
16 #include "BLI_math_vec_types.hh"
17 #include "BLI_multi_value_map.hh"
18 #include "BLI_set.hh"
19 #include "BLI_string.h"
20 #include "BLI_string_search.h"
21 #include "BLI_utildefines.h"
22 
23 #include "DNA_collection_types.h"
24 #include "DNA_curves_types.h"
25 #include "DNA_defaults.h"
26 #include "DNA_material_types.h"
27 #include "DNA_mesh_types.h"
28 #include "DNA_meshdata_types.h"
29 #include "DNA_modifier_types.h"
30 #include "DNA_node_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_pointcloud_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_space_types.h"
37 
38 #include "BKE_attribute_math.hh"
39 #include "BKE_customdata.h"
40 #include "BKE_geometry_fields.hh"
42 #include "BKE_global.h"
43 #include "BKE_idprop.h"
44 #include "BKE_lib_id.h"
45 #include "BKE_lib_query.h"
46 #include "BKE_main.h"
47 #include "BKE_mesh.h"
48 #include "BKE_modifier.h"
49 #include "BKE_node_runtime.hh"
50 #include "BKE_node_tree_update.h"
51 #include "BKE_object.h"
52 #include "BKE_pointcloud.h"
53 #include "BKE_screen.h"
54 #include "BKE_simulation.h"
55 #include "BKE_workspace.h"
56 
57 #include "BLO_read_write.h"
58 
59 #include "UI_interface.h"
60 #include "UI_interface.hh"
61 #include "UI_resources.h"
62 
63 #include "BLT_translation.h"
64 
65 #include "WM_types.h"
66 
67 #include "RNA_access.h"
68 #include "RNA_enum_types.h"
69 #include "RNA_prototypes.h"
70 
71 #include "DEG_depsgraph_build.h"
72 #include "DEG_depsgraph_query.h"
73 
74 #include "MOD_modifiertypes.h"
75 #include "MOD_nodes.h"
76 #include "MOD_nodes_evaluator.hh"
77 #include "MOD_ui_common.h"
78 
79 #include "ED_object.h"
80 #include "ED_screen.h"
81 #include "ED_spreadsheet.h"
82 #include "ED_undo.h"
83 
84 #include "NOD_derived_node_tree.hh"
85 #include "NOD_geometry.h"
87 #include "NOD_node_declaration.hh"
88 
89 #include "FN_field.hh"
90 #include "FN_field_cpp_type.hh"
91 #include "FN_multi_function.hh"
92 
93 using blender::Array;
95 using blender::CPPType;
97 using blender::float3;
101 using blender::GPointer;
102 using blender::GVArray;
103 using blender::IndexRange;
104 using blender::Map;
107 using blender::Set;
108 using blender::Span;
109 using blender::StringRef;
111 using blender::Vector;
113 using blender::fn::Field;
114 using blender::fn::GField;
121 using namespace blender::fn::multi_function_types;
125 
126 static void initData(ModifierData *md)
127 {
129 
130  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(nmd, modifier));
131 
133 }
134 
135 static void add_used_ids_from_sockets(const ListBase &sockets, Set<ID *> &ids)
136 {
137  LISTBASE_FOREACH (const bNodeSocket *, socket, &sockets) {
138  switch (socket->type) {
139  case SOCK_OBJECT: {
140  if (Object *object = ((bNodeSocketValueObject *)socket->default_value)->value) {
141  ids.add(&object->id);
142  }
143  break;
144  }
145  case SOCK_COLLECTION: {
146  if (Collection *collection =
147  ((bNodeSocketValueCollection *)socket->default_value)->value) {
148  ids.add(&collection->id);
149  }
150  break;
151  }
152  case SOCK_MATERIAL: {
153  if (Material *material = ((bNodeSocketValueMaterial *)socket->default_value)->value) {
154  ids.add(&material->id);
155  }
156  break;
157  }
158  case SOCK_TEXTURE: {
159  if (Tex *texture = ((bNodeSocketValueTexture *)socket->default_value)->value) {
160  ids.add(&texture->id);
161  }
162  break;
163  }
164  case SOCK_IMAGE: {
165  if (Image *image = ((bNodeSocketValueImage *)socket->default_value)->value) {
166  ids.add(&image->id);
167  }
168  break;
169  }
170  }
171  }
172 }
173 
181 {
182  if (node.type == GEO_NODE_COLLECTION_INFO) {
183  const NodeGeometryCollectionInfo &storage = *static_cast<const NodeGeometryCollectionInfo *>(
184  node.storage);
186  }
187 
188  if (node.type == GEO_NODE_OBJECT_INFO) {
189  const NodeGeometryObjectInfo &storage = *static_cast<const NodeGeometryObjectInfo *>(
190  node.storage);
192  }
193 
195  return true;
196  }
197 
198  return false;
199 }
200 
202  Set<ID *> &ids,
203  bool &r_needs_own_transform_relation)
204 {
205  Set<const bNodeTree *> handled_groups;
206 
207  LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
208  add_used_ids_from_sockets(node->inputs, ids);
209  add_used_ids_from_sockets(node->outputs, ids);
210 
211  if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
212  const bNodeTree *group = (bNodeTree *)node->id;
213  if (group != nullptr && handled_groups.add(group)) {
214  process_nodes_for_depsgraph(*group, ids, r_needs_own_transform_relation);
215  }
216  }
217  r_needs_own_transform_relation |= node_needs_own_transform_relation(*node);
218  }
219 }
220 
222 {
224  settings.properties,
226  [](IDProperty *property, void *user_data) {
227  Set<ID *> *ids = (Set<ID *> *)user_data;
228  ID *id = IDP_Id(property);
229  if (id != nullptr) {
230  ids->add(id);
231  }
232  },
233  &ids);
234 }
235 
236 /* We don't know exactly what attributes from the other object we will need. */
242 
244  Collection &collection)
245 {
246  DEG_add_collection_geometry_relation(ctx->node, &collection, "Nodes Modifier");
248 }
249 
251 {
252  DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
253  if (&(ID &)object != &ctx->object->id) {
254  if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
255  add_collection_relation(ctx, *object.instance_collection);
256  }
257  else if (DEG_object_has_geometry_component(&object)) {
258  DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
260  }
261  }
262 }
263 
265 {
266  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
267  if (nmd->node_group == nullptr) {
268  return;
269  }
270 
271  DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
272 
273  bool needs_own_transform_relation = false;
274  Set<ID *> used_ids;
275  find_used_ids_from_settings(nmd->settings, used_ids);
276  process_nodes_for_depsgraph(*nmd->node_group, used_ids, needs_own_transform_relation);
277 
278  if (ctx->object->type == OB_CURVES) {
279  Curves *curves_id = static_cast<Curves *>(ctx->object->data);
280  if (curves_id->surface != nullptr) {
281  used_ids.add(&curves_id->surface->id);
282  }
283  }
284 
285  for (ID *id : used_ids) {
286  switch ((ID_Type)GS(id->name)) {
287  case ID_OB: {
288  Object *object = reinterpret_cast<Object *>(id);
289  add_object_relation(ctx, *object);
290  break;
291  }
292  case ID_GR: {
293  Collection *collection = reinterpret_cast<Collection *>(id);
294  add_collection_relation(ctx, *collection);
295  break;
296  }
297  case ID_IM:
298  case ID_TE: {
299  DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier");
300  }
301  default: {
302  /* Purposefully don't add relations for materials. While there are material sockets,
303  * the pointers are only passed around as handles rather than dereferenced. */
304  break;
305  }
306  }
307  }
308 
309  if (needs_own_transform_relation) {
310  DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier");
311  }
312 }
313 
315  Set<const bNodeTree *> &r_checked_trees)
316 {
317  if (!r_checked_trees.add(&tree)) {
318  return false;
319  }
320  LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
321  if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
322  return true;
323  }
324  if (node->type == NODE_GROUP) {
325  const bNodeTree *sub_tree = reinterpret_cast<const bNodeTree *>(node->id);
326  if (sub_tree && check_tree_for_time_node(*sub_tree, r_checked_trees)) {
327  return true;
328  }
329  }
330  }
331  return false;
332 }
333 
334 static bool dependsOnTime(struct Scene *UNUSED(scene), ModifierData *md)
335 {
336  const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
337  const bNodeTree *tree = nmd->node_group;
338  if (tree == nullptr) {
339  return false;
340  }
341  Set<const bNodeTree *> checked_trees;
342  return check_tree_for_time_node(*tree, checked_trees);
343 }
344 
345 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
346 {
347  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
348  walk(userData, ob, (ID **)&nmd->node_group, IDWALK_CB_USER);
349 
350  struct ForeachSettingData {
351  IDWalkFunc walk;
352  void *userData;
353  Object *ob;
354  } settings = {walk, userData, ob};
355 
357  nmd->settings.properties,
359  [](IDProperty *id_prop, void *user_data) {
360  ForeachSettingData *settings = (ForeachSettingData *)user_data;
361  settings->walk(
362  settings->userData, settings->ob, (ID **)&id_prop->data.pointer, IDWALK_CB_USER);
363  },
364  &settings);
365 }
366 
367 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
368 {
369  walk(userData, ob, md, "texture");
370 }
371 
372 static bool isDisabled(const struct Scene *UNUSED(scene),
373  ModifierData *md,
374  bool UNUSED(useRenderParams))
375 {
376  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
377 
378  if (nmd->node_group == nullptr) {
379  return true;
380  }
381 
382  return false;
383 }
384 
385 static bool logging_enabled(const ModifierEvalContext *ctx)
386 {
387  if (!DEG_is_active(ctx->depsgraph)) {
388  return false;
389  }
390  if ((ctx->flag & MOD_APPLY_ORCO) != 0) {
391  return false;
392  }
393  return true;
394 }
395 
396 static const std::string use_attribute_suffix = "_use_attribute";
397 static const std::string attribute_name_suffix = "_attribute_name";
398 
403 {
405 }
406 
411 static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
412 {
413  BLI_assert(node_tree.runtime->field_inferencing_interface);
414  const FieldInferencingInterface &field_interface =
415  *node_tree.runtime->field_inferencing_interface;
416  return field_interface.inputs[socket_index] != InputSocketFieldType::None;
417 }
418 
420 {
421  switch (socket.type) {
422  case SOCK_FLOAT: {
424  IDPropertyTemplate idprop = {0};
425  idprop.f = value->value;
426  IDProperty *property = IDP_New(IDP_FLOAT, &idprop, socket.identifier);
428  ui_data->base.rna_subtype = value->subtype;
429  ui_data->min = ui_data->soft_min = (double)value->min;
430  ui_data->max = ui_data->soft_max = (double)value->max;
431  ui_data->default_value = value->value;
432  return property;
433  }
434  case SOCK_INT: {
436  IDPropertyTemplate idprop = {0};
437  idprop.i = value->value;
438  IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier);
440  ui_data->base.rna_subtype = value->subtype;
441  ui_data->min = ui_data->soft_min = value->min;
442  ui_data->max = ui_data->soft_max = value->max;
443  ui_data->default_value = value->value;
444  return property;
445  }
446  case SOCK_VECTOR: {
447  bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value;
448  IDPropertyTemplate idprop = {0};
449  idprop.array.len = 3;
450  idprop.array.type = IDP_FLOAT;
451  IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier);
452  copy_v3_v3((float *)IDP_Array(property), value->value);
454  ui_data->base.rna_subtype = value->subtype;
455  ui_data->min = ui_data->soft_min = (double)value->min;
456  ui_data->max = ui_data->soft_max = (double)value->max;
457  ui_data->default_array = (double *)MEM_mallocN(sizeof(double[3]), "mod_prop_default");
458  ui_data->default_array_len = 3;
459  for (const int i : IndexRange(3)) {
460  ui_data->default_array[i] = double(value->value[i]);
461  }
462  return property;
463  }
464  case SOCK_RGBA: {
465  bNodeSocketValueRGBA *value = (bNodeSocketValueRGBA *)socket.default_value;
466  IDPropertyTemplate idprop = {0};
467  idprop.array.len = 4;
468  idprop.array.type = IDP_FLOAT;
469  IDProperty *property = IDP_New(IDP_ARRAY, &idprop, socket.identifier);
470  copy_v4_v4((float *)IDP_Array(property), value->value);
472  ui_data->base.rna_subtype = PROP_COLOR;
473  ui_data->default_array = (double *)MEM_mallocN(sizeof(double[4]), __func__);
474  ui_data->default_array_len = 4;
475  ui_data->min = 0.0;
476  ui_data->max = FLT_MAX;
477  ui_data->soft_min = 0.0;
478  ui_data->soft_max = 1.0;
479  for (const int i : IndexRange(4)) {
480  ui_data->default_array[i] = double(value->value[i]);
481  }
482  return property;
483  }
484  case SOCK_BOOLEAN: {
485  bNodeSocketValueBoolean *value = (bNodeSocketValueBoolean *)socket.default_value;
486  IDPropertyTemplate idprop = {0};
487  idprop.i = value->value != 0;
488  IDProperty *property = IDP_New(IDP_INT, &idprop, socket.identifier);
490  ui_data->min = ui_data->soft_min = 0;
491  ui_data->max = ui_data->soft_max = 1;
492  ui_data->default_value = value->value != 0;
493  return property;
494  }
495  case SOCK_STRING: {
496  bNodeSocketValueString *value = (bNodeSocketValueString *)socket.default_value;
497  IDProperty *property = IDP_NewString(
498  value->value, socket.identifier, BLI_strnlen(value->value, sizeof(value->value)) + 1);
500  ui_data->default_value = BLI_strdup(value->value);
501  return property;
502  }
503  case SOCK_OBJECT: {
504  bNodeSocketValueObject *value = (bNodeSocketValueObject *)socket.default_value;
505  IDPropertyTemplate idprop = {0};
506  idprop.id = (ID *)value->value;
507  return IDP_New(IDP_ID, &idprop, socket.identifier);
508  }
509  case SOCK_COLLECTION: {
510  bNodeSocketValueCollection *value = (bNodeSocketValueCollection *)socket.default_value;
511  IDPropertyTemplate idprop = {0};
512  idprop.id = (ID *)value->value;
513  return IDP_New(IDP_ID, &idprop, socket.identifier);
514  }
515  case SOCK_TEXTURE: {
516  bNodeSocketValueTexture *value = (bNodeSocketValueTexture *)socket.default_value;
517  IDPropertyTemplate idprop = {0};
518  idprop.id = (ID *)value->value;
519  return IDP_New(IDP_ID, &idprop, socket.identifier);
520  }
521  case SOCK_IMAGE: {
522  bNodeSocketValueImage *value = (bNodeSocketValueImage *)socket.default_value;
523  IDPropertyTemplate idprop = {0};
524  idprop.id = (ID *)value->value;
525  return IDP_New(IDP_ID, &idprop, socket.identifier);
526  }
527  case SOCK_MATERIAL: {
528  bNodeSocketValueMaterial *value = (bNodeSocketValueMaterial *)socket.default_value;
529  IDPropertyTemplate idprop = {0};
530  idprop.id = (ID *)value->value;
531  return IDP_New(IDP_ID, &idprop, socket.identifier);
532  }
533  }
534  return nullptr;
535 }
536 
537 static bool id_property_type_matches_socket(const bNodeSocket &socket, const IDProperty &property)
538 {
539  switch (socket.type) {
540  case SOCK_FLOAT:
541  return ELEM(property.type, IDP_FLOAT, IDP_DOUBLE);
542  case SOCK_INT:
543  return property.type == IDP_INT;
544  case SOCK_VECTOR:
545  return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 3;
546  case SOCK_RGBA:
547  return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 4;
548  case SOCK_BOOLEAN:
549  return property.type == IDP_INT;
550  case SOCK_STRING:
551  return property.type == IDP_STRING;
552  case SOCK_OBJECT:
553  case SOCK_COLLECTION:
554  case SOCK_TEXTURE:
555  case SOCK_IMAGE:
556  case SOCK_MATERIAL:
557  return property.type == IDP_ID;
558  }
560  return false;
561 }
562 
564  const eNodeSocketDatatype socket_value_type,
565  void *r_value)
566 {
567  switch (socket_value_type) {
568  case SOCK_FLOAT: {
569  float value = 0.0f;
570  if (property.type == IDP_FLOAT) {
571  value = IDP_Float(&property);
572  }
573  else if (property.type == IDP_DOUBLE) {
574  value = (float)IDP_Double(&property);
575  }
576  new (r_value) ValueOrField<float>(value);
577  break;
578  }
579  case SOCK_INT: {
580  int value = IDP_Int(&property);
581  new (r_value) ValueOrField<int>(value);
582  break;
583  }
584  case SOCK_VECTOR: {
585  float3 value;
586  copy_v3_v3(value, (const float *)IDP_Array(&property));
587  new (r_value) ValueOrField<float3>(value);
588  break;
589  }
590  case SOCK_RGBA: {
592  copy_v4_v4((float *)value, (const float *)IDP_Array(&property));
593  new (r_value) ValueOrField<ColorGeometry4f>(value);
594  break;
595  }
596  case SOCK_BOOLEAN: {
597  bool value = IDP_Int(&property) != 0;
598  new (r_value) ValueOrField<bool>(value);
599  break;
600  }
601  case SOCK_STRING: {
602  std::string value = IDP_String(&property);
603  new (r_value) ValueOrField<std::string>(std::move(value));
604  break;
605  }
606  case SOCK_OBJECT: {
607  ID *id = IDP_Id(&property);
608  Object *object = (id && GS(id->name) == ID_OB) ? (Object *)id : nullptr;
609  *(Object **)r_value = object;
610  break;
611  }
612  case SOCK_COLLECTION: {
613  ID *id = IDP_Id(&property);
614  Collection *collection = (id && GS(id->name) == ID_GR) ? (Collection *)id : nullptr;
615  *(Collection **)r_value = collection;
616  break;
617  }
618  case SOCK_TEXTURE: {
619  ID *id = IDP_Id(&property);
620  Tex *texture = (id && GS(id->name) == ID_TE) ? (Tex *)id : nullptr;
621  *(Tex **)r_value = texture;
622  break;
623  }
624  case SOCK_IMAGE: {
625  ID *id = IDP_Id(&property);
626  Image *image = (id && GS(id->name) == ID_IM) ? (Image *)id : nullptr;
627  *(Image **)r_value = image;
628  break;
629  }
630  case SOCK_MATERIAL: {
631  ID *id = IDP_Id(&property);
632  Material *material = (id && GS(id->name) == ID_MA) ? (Material *)id : nullptr;
633  *(Material **)r_value = material;
634  break;
635  }
636  default: {
638  break;
639  }
640  }
641 }
642 
644 {
645  if (nmd->node_group == nullptr) {
646  if (nmd->settings.properties) {
648  nmd->settings.properties = nullptr;
649  }
650  return;
651  }
652 
653  IDProperty *old_properties = nmd->settings.properties;
654  {
655  IDPropertyTemplate idprop = {0};
656  nmd->settings.properties = IDP_New(IDP_GROUP, &idprop, "Nodes Modifier Settings");
657  }
658 
659  int socket_index;
660  LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
661  IDProperty *new_prop = id_property_create_from_socket(*socket);
662  if (new_prop == nullptr) {
663  /* Out of the set of supported input sockets, only
664  * geometry sockets aren't added to the modifier. */
665  BLI_assert(socket->type == SOCK_GEOMETRY);
666  continue;
667  }
668 
669  new_prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY;
670  if (socket->description[0] != '\0') {
671  IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop);
672  ui_data->description = BLI_strdup(socket->description);
673  }
674  IDP_AddToGroup(nmd->settings.properties, new_prop);
675 
676  if (old_properties != nullptr) {
677  IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket->identifier);
678  if (old_prop != nullptr && id_property_type_matches_socket(*socket, *old_prop)) {
679  /* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
680  * want to replace the values). So release it temporarily and replace it after. */
681  IDPropertyUIData *ui_data = new_prop->ui_data;
682  new_prop->ui_data = nullptr;
683  IDP_CopyPropertyContent(new_prop, old_prop);
684  if (new_prop->ui_data != nullptr) {
685  IDP_ui_data_free(new_prop);
686  }
687  new_prop->ui_data = ui_data;
688  }
689  }
690 
691  if (socket_type_has_attribute_toggle(*socket)) {
692  const std::string use_attribute_id = socket->identifier + use_attribute_suffix;
693  const std::string attribute_name_id = socket->identifier + attribute_name_suffix;
694 
695  IDPropertyTemplate idprop = {0};
696  IDProperty *use_attribute_prop = IDP_New(IDP_INT, &idprop, use_attribute_id.c_str());
697  IDP_AddToGroup(nmd->settings.properties, use_attribute_prop);
698 
699  IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str());
700  IDP_AddToGroup(nmd->settings.properties, attribute_prop);
701 
702  if (old_properties == nullptr) {
703  if (socket->default_attribute_name && socket->default_attribute_name[0] != '\0') {
704  IDP_AssignString(attribute_prop, socket->default_attribute_name, MAX_NAME);
705  IDP_Int(use_attribute_prop) = 1;
706  }
707  }
708  else {
709  IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties,
710  use_attribute_id.c_str());
711  if (old_prop_use_attribute != nullptr) {
712  IDP_CopyPropertyContent(use_attribute_prop, old_prop_use_attribute);
713  }
714 
715  IDProperty *old_attribute_name_prop = IDP_GetPropertyFromGroup(old_properties,
716  attribute_name_id.c_str());
717  if (old_attribute_name_prop != nullptr) {
718  IDP_CopyPropertyContent(attribute_prop, old_attribute_name_prop);
719  }
720  }
721  }
722  }
723 
724  LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
725  if (!socket_type_has_attribute_toggle(*socket)) {
726  continue;
727  }
728 
729  const std::string idprop_name = socket->identifier + attribute_name_suffix;
730  IDProperty *new_prop = IDP_NewString("", idprop_name.c_str(), MAX_NAME);
731  if (socket->description[0] != '\0') {
732  IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop);
733  ui_data->description = BLI_strdup(socket->description);
734  }
735  IDP_AddToGroup(nmd->settings.properties, new_prop);
736 
737  if (old_properties == nullptr) {
738  if (socket->default_attribute_name && socket->default_attribute_name[0] != '\0') {
739  IDP_AssignString(new_prop, socket->default_attribute_name, MAX_NAME);
740  }
741  }
742  else {
743  IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, idprop_name.c_str());
744  if (old_prop != nullptr) {
745  /* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
746  * want to replace the values). So release it temporarily and replace it after. */
747  IDPropertyUIData *ui_data = new_prop->ui_data;
748  new_prop->ui_data = nullptr;
749  IDP_CopyPropertyContent(new_prop, old_prop);
750  if (new_prop->ui_data != nullptr) {
751  IDP_ui_data_free(new_prop);
752  }
753  new_prop->ui_data = ui_data;
754  }
755  }
756  }
757 
758  if (old_properties != nullptr) {
759  IDP_FreeProperty(old_properties);
760  }
761 
763 }
764 
766  const OutputSocketRef &socket,
767  void *r_value)
768 {
769  const bNodeSocketType &socket_type = *socket.typeinfo();
770  const bNodeSocket &bsocket = *socket.bsocket();
771  const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(bsocket.type);
772  if (nmd.settings.properties == nullptr) {
773  socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
774  return;
775  }
777  socket.identifier().c_str());
778  if (property == nullptr) {
779  socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
780  return;
781  }
782  if (!id_property_type_matches_socket(bsocket, *property)) {
783  socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
784  return;
785  }
786 
787  if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) {
788  init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
789  return;
790  }
791 
792  const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
793  nmd.settings.properties, (socket.identifier() + use_attribute_suffix).c_str());
794  const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
795  nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str());
796  if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
797  init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
798  return;
799  }
800 
801  const bool use_attribute = IDP_Int(property_use_attribute) != 0;
802  if (use_attribute) {
803  const StringRef attribute_name{IDP_String(property_attribute_name)};
805  init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
806  return;
807  }
808  auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
809  attribute_name, *socket_type.base_cpp_type);
810  GField attribute_field{std::move(attribute_input), 0};
811  const blender::fn::ValueOrFieldCPPType *cpp_type =
812  dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(
813  socket_type.geometry_nodes_cpp_type);
814  BLI_assert(cpp_type != nullptr);
815  cpp_type->construct_from_field(r_value, std::move(attribute_field));
816  }
817  else {
818  init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
819  }
820 }
821 
823 {
824  wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
825  if (wm == nullptr) {
826  return {};
827  }
828  Vector<SpaceSpreadsheet *> spreadsheets;
829  LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
830  bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
831  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
832  SpaceLink *sl = (SpaceLink *)area->spacedata.first;
833  if (sl->spacetype == SPACE_SPREADSHEET) {
834  spreadsheets.append((SpaceSpreadsheet *)sl);
835  }
836  }
837  }
838  return spreadsheets;
839 }
840 
842  NodesModifierData *nmd,
843  const ModifierEvalContext *ctx,
844  const DerivedNodeTree &tree,
845  Set<DSocket> &r_sockets_to_preview)
846 {
847  Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
848  if (context_path.size() < 3) {
849  return;
850  }
851  if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
852  return;
853  }
854  if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
855  return;
856  }
857  SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
858  if (object_context->object != DEG_get_original_object(ctx->object)) {
859  return;
860  }
861  SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1];
862  if (StringRef(modifier_context->modifier_name) != nmd->modifier.name) {
863  return;
864  }
865  for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
866  if (context->type != SPREADSHEET_CONTEXT_NODE) {
867  return;
868  }
869  }
870 
871  Span<SpreadsheetContextNode *> nested_group_contexts =
872  context_path.as_span().drop_front(2).drop_back(1).cast<SpreadsheetContextNode *>();
873  SpreadsheetContextNode *last_context = (SpreadsheetContextNode *)context_path.last();
874 
875  const DTreeContext *context = &tree.root_context();
876  for (SpreadsheetContextNode *node_context : nested_group_contexts) {
877  const NodeTreeRef &tree_ref = context->tree();
878  const NodeRef *found_node = nullptr;
879  for (const NodeRef *node_ref : tree_ref.nodes()) {
880  if (node_ref->name() == node_context->node_name) {
881  found_node = node_ref;
882  break;
883  }
884  }
885  if (found_node == nullptr) {
886  return;
887  }
888  context = context->child_context(*found_node);
889  if (context == nullptr) {
890  return;
891  }
892  }
893 
894  const NodeTreeRef &tree_ref = context->tree();
895  for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) {
896  if (node_ref->name() == last_context->node_name) {
897  const DNode viewer_node{context, node_ref};
898  for (const InputSocketRef *input_socket : node_ref->inputs()) {
899  if (input_socket->is_available() && input_socket->is_logically_linked()) {
900  r_sockets_to_preview.add(DSocket{context, input_socket});
901  }
902  }
903  }
904  }
905 }
906 
908  const ModifierEvalContext *ctx,
909  const DerivedNodeTree &tree,
910  Set<DSocket> &r_sockets_to_preview)
911 {
912  Main *bmain = DEG_get_bmain(ctx->depsgraph);
913 
914  /* Based on every visible spreadsheet context path, get a list of sockets that need to have their
915  * intermediate geometries cached for display. */
917  for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
918  find_sockets_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree, r_sockets_to_preview);
919  }
920 }
921 
923 {
924  if (nmd->runtime_eval_log != nullptr) {
925  delete (geo_log::ModifierLog *)nmd->runtime_eval_log;
926  nmd->runtime_eval_log = nullptr;
927  }
928 }
929 
933 };
934 
940 };
941 
947  const NodesModifierData &nmd, const NodeRef &output_node, Span<GMutablePointer> output_values)
948 {
950  for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
951  if (!socket_type_has_attribute_toggle(*socket->bsocket())) {
952  continue;
953  }
954 
955  const std::string prop_name = socket->identifier() + attribute_name_suffix;
956  const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str());
957  if (prop == nullptr) {
958  continue;
959  }
960  const StringRefNull attribute_name = IDP_String(prop);
961  if (attribute_name.is_empty()) {
962  continue;
963  }
965  continue;
966  }
967 
968  const int index = socket->index();
969  const GPointer value = output_values[index];
970  const ValueOrFieldCPPType *cpp_type = dynamic_cast<const ValueOrFieldCPPType *>(value.type());
971  BLI_assert(cpp_type != nullptr);
972  const GField field = cpp_type->as_field(value.get());
973 
974  const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
975  &nmd.node_group->outputs, socket->index());
976  const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain;
977  OutputAttributeInfo output_info;
978  output_info.field = std::move(field);
979  output_info.name = attribute_name;
980  outputs_by_domain.add(domain, std::move(output_info));
981  }
982  return outputs_by_domain;
983 }
984 
990  const GeometrySet &geometry,
991  const MultiValueMap<eAttrDomain, OutputAttributeInfo> &outputs_by_domain)
992 {
993  Vector<OutputAttributeToStore> attributes_to_store;
994  for (const GeometryComponentType component_type : {GEO_COMPONENT_TYPE_MESH,
998  if (!geometry.has(component_type)) {
999  continue;
1000  }
1001  const GeometryComponent &component = *geometry.get_component_for_read(component_type);
1002  if (component.is_empty()) {
1003  continue;
1004  }
1005  const blender::bke::AttributeAccessor attributes = *component.attributes();
1006  for (const auto item : outputs_by_domain.items()) {
1007  const eAttrDomain domain = item.key;
1008  const Span<OutputAttributeInfo> outputs_info = item.value;
1009  if (!attributes.domain_supported(domain)) {
1010  continue;
1011  }
1012  const int domain_size = attributes.domain_size(domain);
1014  blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
1015  for (const OutputAttributeInfo &output_info : outputs_info) {
1016  const CPPType &type = output_info.field.cpp_type();
1017  OutputAttributeToStore store{
1018  component_type,
1019  domain,
1020  output_info.name,
1021  GMutableSpan{
1022  type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
1023  field_evaluator.add_with_destination(output_info.field, store.data);
1024  attributes_to_store.append(store);
1025  }
1026  field_evaluator.evaluate();
1027  }
1028  }
1029  return attributes_to_store;
1030 }
1031 
1033  GeometrySet &geometry, const Span<OutputAttributeToStore> attributes_to_store)
1034 {
1035  for (const OutputAttributeToStore &store : attributes_to_store) {
1036  GeometryComponent &component = geometry.get_component_for_write(store.component_type);
1037  blender::bke::MutableAttributeAccessor attributes = *component.attributes_for_write();
1038 
1040  store.data.type());
1041  const std::optional<AttributeMetaData> meta_data = attributes.lookup_meta_data(store.name);
1042 
1043  /* Attempt to remove the attribute if it already exists but the domain and type don't match.
1044  * Removing the attribute won't succeed if it is built in and non-removable. */
1045  if (meta_data.has_value() &&
1046  (meta_data->domain != store.domain || meta_data->data_type != data_type)) {
1047  attributes.remove(store.name);
1048  }
1049 
1050  /* Try to create the attribute reusing the stored buffer. This will only succeed if the
1051  * attribute didn't exist before, or if it existed but was removed above. */
1052  if (attributes.add(store.name,
1053  store.domain,
1054  blender::bke::cpp_type_to_custom_data_type(store.data.type()),
1055  blender::bke::AttributeInitMove(store.data.data()))) {
1056  continue;
1057  }
1058 
1060  store.name, store.domain, data_type);
1061  if (attribute) {
1062  attribute.varray.set_all(store.data.data());
1063  attribute.finish();
1064  }
1065 
1066  /* We were unable to reuse the data, so it must be destructed and freed. */
1067  store.data.type().destruct_n(store.data.data(), store.data.size());
1068  MEM_freeN(store.data.data());
1069  }
1070 }
1071 
1072 static void store_output_attributes(GeometrySet &geometry,
1073  const NodesModifierData &nmd,
1074  const NodeRef &output_node,
1075  Span<GMutablePointer> output_values)
1076 {
1077  /* All new attribute values have to be computed before the geometry is actually changed. This is
1078  * necessary because some fields might depend on attributes that are overwritten. */
1080  find_output_attributes_to_store(nmd, output_node, output_values);
1082  geometry, outputs_by_domain);
1083  store_computed_output_attributes(geometry, attributes_to_store);
1084 }
1085 
1090  Span<const NodeRef *> group_input_nodes,
1091  const NodeRef &output_node,
1092  GeometrySet input_geometry_set,
1093  NodesModifierData *nmd,
1094  const ModifierEvalContext *ctx)
1095 {
1096  blender::ResourceScope scope;
1097  blender::LinearAllocator<> &allocator = scope.linear_allocator();
1099 
1101 
1102  const DTreeContext *root_context = &tree.root_context();
1103  for (const NodeRef *group_input_node : group_input_nodes) {
1104  Span<const OutputSocketRef *> group_input_sockets = group_input_node->outputs().drop_back(1);
1105  if (group_input_sockets.is_empty()) {
1106  continue;
1107  }
1108 
1109  Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets;
1110 
1111  /* If the group expects a geometry as first input, use the geometry that has been passed to
1112  * modifier. */
1113  const OutputSocketRef *first_input_socket = group_input_sockets[0];
1114  if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
1115  GeometrySet *geometry_set_in =
1116  allocator.construct<GeometrySet>(input_geometry_set).release();
1117  group_inputs.add_new({root_context, first_input_socket}, geometry_set_in);
1118  remaining_input_sockets = remaining_input_sockets.drop_front(1);
1119  }
1120 
1121  /* Initialize remaining group inputs. */
1122  for (const OutputSocketRef *socket : remaining_input_sockets) {
1123  const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type;
1124  void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
1125  initialize_group_input(*nmd, *socket, value_in);
1126  group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
1127  }
1128  }
1129 
1130  Vector<DInputSocket> group_outputs;
1131  for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) {
1132  group_outputs.append({root_context, socket_ref});
1133  }
1134 
1135  std::optional<geo_log::GeoLogger> geo_logger;
1136 
1138 
1139  if (logging_enabled(ctx)) {
1140  Set<DSocket> preview_sockets;
1141  find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
1142  eval_params.force_compute_sockets.extend(preview_sockets.begin(), preview_sockets.end());
1143  geo_logger.emplace(std::move(preview_sockets));
1144 
1145  geo_logger->log_input_geometry(input_geometry_set);
1146  }
1147 
1148  /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
1149  input_geometry_set.clear();
1150 
1151  eval_params.input_values = group_inputs;
1152  eval_params.output_sockets = group_outputs;
1153  eval_params.mf_by_node = &mf_by_node;
1154  eval_params.modifier_ = nmd;
1155  eval_params.depsgraph = ctx->depsgraph;
1156  eval_params.self_object = ctx->object;
1157  eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr;
1159 
1160  GeometrySet output_geometry_set = std::move(*eval_params.r_output_values[0].get<GeometrySet>());
1161 
1162  if (geo_logger.has_value()) {
1163  geo_logger->log_output_geometry(output_geometry_set);
1165  &nmd->modifier);
1166  clear_runtime_data(nmd_orig);
1167  nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
1168  }
1169 
1170  store_output_attributes(output_geometry_set, *nmd, output_node, eval_params.r_output_values);
1171 
1172  for (GMutablePointer value : eval_params.r_output_values) {
1173  value.destruct();
1174  }
1175 
1176  return output_geometry_set;
1177 }
1178 
1184 {
1185  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1186 
1187  int geometry_socket_count = 0;
1188 
1189  int i;
1190  LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &nmd->node_group->inputs, i) {
1191  /* The first socket is the special geometry socket for the modifier object. */
1192  if (i == 0 && socket->type == SOCK_GEOMETRY) {
1193  geometry_socket_count++;
1194  continue;
1195  }
1196 
1197  IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket->identifier);
1198  if (property == nullptr) {
1199  if (socket->type == SOCK_GEOMETRY) {
1200  geometry_socket_count++;
1201  }
1202  else {
1203  BKE_modifier_set_error(ob, md, "Missing property for input socket \"%s\"", socket->name);
1204  }
1205  continue;
1206  }
1207 
1208  if (!id_property_type_matches_socket(*socket, *property)) {
1210  ob, md, "Property type does not match input socket \"(%s)\"", socket->name);
1211  continue;
1212  }
1213  }
1214 
1215  if (geometry_socket_count == 1) {
1216  if (((bNodeSocket *)nmd->node_group->inputs.first)->type != SOCK_GEOMETRY) {
1217  BKE_modifier_set_error(ob, md, "Node group's geometry input must be the first");
1218  }
1219  }
1220  else if (geometry_socket_count > 1) {
1221  BKE_modifier_set_error(ob, md, "Node group can only have one geometry input");
1222  }
1223 }
1224 
1226  const ModifierEvalContext *ctx,
1227  GeometrySet &geometry_set)
1228 {
1229  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1230  if (nmd->node_group == nullptr) {
1231  return;
1232  }
1233 
1235 
1236  NodeTreeRefMap tree_refs;
1237  DerivedNodeTree tree{*nmd->node_group, tree_refs};
1238 
1239  if (tree.has_link_cycles()) {
1240  BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
1241  geometry_set.clear();
1242  return;
1243  }
1244 
1245  const NodeTreeRef &root_tree_ref = tree.root_context().tree();
1246  Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
1247  Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
1248  if (output_nodes.size() != 1) {
1249  BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node");
1250  geometry_set.clear();
1251  return;
1252  }
1253 
1254  const NodeRef &output_node = *output_nodes[0];
1255  Span<const InputSocketRef *> group_outputs = output_node.inputs().drop_back(1);
1256  if (group_outputs.is_empty()) {
1257  BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket");
1258  geometry_set.clear();
1259  return;
1260  }
1261 
1262  const InputSocketRef *first_output_socket = group_outputs[0];
1263  if (first_output_socket->idname() != "NodeSocketGeometry") {
1264  BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry");
1265  geometry_set.clear();
1266  return;
1267  }
1268 
1269  bool use_orig_index_verts = false;
1270  bool use_orig_index_edges = false;
1271  bool use_orig_index_polys = false;
1272  if (geometry_set.has_mesh()) {
1273  const Mesh &mesh = *geometry_set.get_mesh_for_read();
1274  use_orig_index_verts = CustomData_has_layer(&mesh.vdata, CD_ORIGINDEX);
1275  use_orig_index_edges = CustomData_has_layer(&mesh.edata, CD_ORIGINDEX);
1276  use_orig_index_polys = CustomData_has_layer(&mesh.pdata, CD_ORIGINDEX);
1277  }
1278 
1279  geometry_set = compute_geometry(
1280  tree, input_nodes, output_node, std::move(geometry_set), nmd, ctx);
1281 
1282  if (geometry_set.has_mesh()) {
1283  /* Add #CD_ORIGINDEX layers if they don't exist already. This is required because the
1284  * #eModifierTypeFlag_SupportsMapping flag is set. If the layers did not exist before, it is
1285  * assumed that the output mesh does not have a mapping to the original mesh. */
1286  Mesh &mesh = *geometry_set.get_mesh_for_write();
1287  if (use_orig_index_verts) {
1289  }
1290  if (use_orig_index_edges) {
1292  }
1293  if (use_orig_index_polys) {
1295  }
1296  }
1297 }
1298 
1300 {
1302 
1303  modifyGeometry(md, ctx, geometry_set);
1304 
1305  Mesh *new_mesh = geometry_set.get_component_for_write<MeshComponent>().release();
1306  if (new_mesh == nullptr) {
1307  return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
1308  }
1309  return new_mesh;
1310 }
1311 
1313  const ModifierEvalContext *ctx,
1314  GeometrySet *geometry_set)
1315 {
1316  modifyGeometry(md, ctx, *geometry_set);
1317 }
1318 
1324 };
1325 /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
1326 BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
1327 
1329  const wmWindowManager &wm,
1330  const AttributeSearchData &data)
1331 {
1332  if (ED_screen_animation_playing(&wm)) {
1333  /* Work around an issue where the attribute search exec function has stale pointers when data
1334  * is reallocated when evaluating the node tree, causing a crash. This would be solved by
1335  * allowing the UI search data to own arbitrary memory rather than just referencing it. */
1336  return nullptr;
1337  }
1338 
1339  const Object *object = (Object *)BKE_libblock_find_session_uuid(
1340  &bmain, ID_OB, data.object_session_uid);
1341  if (object == nullptr) {
1342  return nullptr;
1343  }
1344  ModifierData *md = BKE_modifiers_findby_name(object, data.modifier_name);
1345  if (md == nullptr) {
1346  return nullptr;
1347  }
1349  return reinterpret_cast<NodesModifierData *>(md);
1350 }
1351 
1353  const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
1354 {
1355  AttributeSearchData &data = *static_cast<AttributeSearchData *>(arg);
1357  if (nmd == nullptr) {
1358  return;
1359  }
1360  const geo_log::ModifierLog *modifier_log = static_cast<const geo_log::ModifierLog *>(
1361  nmd->runtime_eval_log);
1362  if (modifier_log == nullptr) {
1363  return;
1364  }
1365  const geo_log::GeometryValueLog *geometry_log = data.is_output ?
1366  modifier_log->output_geometry_log() :
1367  modifier_log->input_geometry_log();
1368  if (geometry_log == nullptr) {
1369  return;
1370  }
1371 
1372  Span<GeometryAttributeInfo> infos = geometry_log->attributes();
1373 
1374  /* The shared attribute search code expects a span of pointers, so convert to that. */
1375  Array<const GeometryAttributeInfo *> info_ptrs(infos.size());
1376  for (const int i : infos.index_range()) {
1377  info_ptrs[i] = &infos[i];
1378  }
1380  str, data.is_output, info_ptrs.as_span(), items, is_first);
1381 }
1382 
1383 static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
1384 {
1385  if (item_v == nullptr) {
1386  return;
1387  }
1388  AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v);
1389  const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v);
1391  if (nmd == nullptr) {
1392  return;
1393  }
1394 
1395  const std::string attribute_prop_name = data.socket_identifier + attribute_name_suffix;
1396  IDProperty &name_property = *IDP_GetPropertyFromGroup(nmd->settings.properties,
1397  attribute_prop_name.c_str());
1398  IDP_AssignString(&name_property, item.name.c_str(), 0);
1399 
1400  ED_undo_push(C, "Assign Attribute Name");
1401 }
1402 
1404  uiLayout *layout,
1405  const NodesModifierData &nmd,
1406  PointerRNA *md_ptr,
1407  const StringRefNull rna_path_attribute_name,
1408  const bNodeSocket &socket,
1409  const bool is_output)
1410 {
1411  const geo_log::ModifierLog *log = static_cast<geo_log::ModifierLog *>(nmd.runtime_eval_log);
1412  if (log == nullptr) {
1413  uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, "", ICON_NONE);
1414  return;
1415  }
1416 
1417  uiBlock *block = uiLayoutGetBlock(layout);
1418  uiBut *but = uiDefIconTextButR(block,
1420  0,
1421  ICON_NONE,
1422  "",
1423  0,
1424  0,
1425  10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
1426  UI_UNIT_Y,
1427  md_ptr,
1428  rna_path_attribute_name.c_str(),
1429  0,
1430  0.0f,
1431  0.0f,
1432  0.0f,
1433  0.0f,
1434  socket.description);
1435 
1436  const Object *object = ED_object_context(&C);
1437  BLI_assert(object != nullptr);
1438  if (object == nullptr) {
1439  return;
1440  }
1441 
1442  AttributeSearchData *data = MEM_new<AttributeSearchData>(__func__);
1443  data->object_session_uid = object->id.session_uuid;
1444  STRNCPY(data->modifier_name, nmd.modifier.name);
1445  STRNCPY(data->socket_identifier, socket.identifier);
1446  data->is_output = is_output;
1447 
1451  nullptr,
1453  static_cast<void *>(data),
1454  true,
1455  nullptr,
1457  nullptr);
1458 
1459  char *attribute_name = RNA_string_get_alloc(
1460  md_ptr, rna_path_attribute_name.c_str(), nullptr, 0, nullptr);
1461  const bool access_allowed = blender::bke::allow_procedural_attribute_access(attribute_name);
1462  MEM_freeN(attribute_name);
1463  if (!access_allowed) {
1465  }
1466 }
1467 
1469  uiLayout *layout,
1470  const NodesModifierData &nmd,
1471  PointerRNA *md_ptr,
1472  const bNodeSocket &socket)
1473 {
1474  char socket_id_esc[sizeof(socket.identifier) * 2];
1475  BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
1476  const std::string rna_path = "[\"" + std::string(socket_id_esc) + "\"]";
1477  const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
1478  use_attribute_suffix + "\"]";
1479  const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
1480  attribute_name_suffix + "\"]";
1481 
1482  uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
1483  uiLayout *name_row = uiLayoutRow(split, false);
1485  uiItemL(name_row, socket.name, ICON_NONE);
1486 
1487  uiLayout *row = uiLayoutRow(split, true);
1488 
1489  PointerRNA props;
1490  uiItemFullO(row,
1491  "object.geometry_nodes_input_attribute_toggle",
1492  "",
1493  ICON_SPREADSHEET,
1494  nullptr,
1496  0,
1497  &props);
1498  RNA_string_set(&props, "modifier_name", nmd.modifier.name);
1499  RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
1500 
1501  const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
1502  if (use_attribute) {
1503  add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, false);
1504  uiItemL(row, "", ICON_BLANK1);
1505  }
1506  else {
1507  uiItemR(row, md_ptr, rna_path.c_str(), 0, "", ICON_NONE);
1508  uiItemDecoratorR(row, md_ptr, rna_path.c_str(), -1);
1509  }
1510 }
1511 
1512 /* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
1513  * the node socket identifier for the property names, since they are unique, but also having
1514  * the correct label displayed in the UI. */
1516  uiLayout *layout,
1517  NodesModifierData *nmd,
1518  PointerRNA *bmain_ptr,
1519  PointerRNA *md_ptr,
1520  const bNodeSocket &socket,
1521  const int socket_index)
1522 {
1523  /* The property should be created in #MOD_nodes_update_interface with the correct type. */
1525 
1526  /* IDProperties can be removed with python, so there could be a situation where
1527  * there isn't a property for a socket or it doesn't have the correct type. */
1528  if (property == nullptr || !id_property_type_matches_socket(socket, *property)) {
1529  return;
1530  }
1531 
1532  char socket_id_esc[sizeof(socket.identifier) * 2];
1533  BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
1534 
1535  char rna_path[sizeof(socket_id_esc) + 4];
1536  BLI_snprintf(rna_path, ARRAY_SIZE(rna_path), "[\"%s\"]", socket_id_esc);
1537 
1538  /* Use #uiItemPointerR to draw pointer properties because #uiItemR would not have enough
1539  * information about what type of ID to select for editing the values. This is because
1540  * pointer IDProperties contain no information about their type. */
1541  switch (socket.type) {
1542  case SOCK_OBJECT: {
1544  layout, md_ptr, rna_path, bmain_ptr, "objects", socket.name, ICON_OBJECT_DATA);
1545  break;
1546  }
1547  case SOCK_COLLECTION: {
1548  uiItemPointerR(layout,
1549  md_ptr,
1550  rna_path,
1551  bmain_ptr,
1552  "collections",
1553  socket.name,
1554  ICON_OUTLINER_COLLECTION);
1555  break;
1556  }
1557  case SOCK_MATERIAL: {
1558  uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "materials", socket.name, ICON_MATERIAL);
1559  break;
1560  }
1561  case SOCK_TEXTURE: {
1562  uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "textures", socket.name, ICON_TEXTURE);
1563  break;
1564  }
1565  case SOCK_IMAGE: {
1566  uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "images", socket.name, ICON_IMAGE);
1567  break;
1568  }
1569  default: {
1570  if (input_has_attribute_toggle(*nmd->node_group, socket_index)) {
1571  add_attribute_search_or_value_buttons(C, layout, *nmd, md_ptr, socket);
1572  }
1573  else {
1574  uiLayout *row = uiLayoutRow(layout, false);
1575  uiLayoutSetPropDecorate(row, true);
1576  uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
1577  }
1578  }
1579  }
1580 }
1581 
1583  uiLayout *layout,
1584  const NodesModifierData &nmd,
1585  PointerRNA *md_ptr,
1586  const bNodeSocket &socket)
1587 {
1588  char socket_id_esc[sizeof(socket.identifier) * 2];
1589  BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
1590  const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) +
1591  attribute_name_suffix + "\"]";
1592 
1593  uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
1594  uiLayout *name_row = uiLayoutRow(split, false);
1596  uiItemL(name_row, socket.name, ICON_NONE);
1597 
1598  uiLayout *row = uiLayoutRow(split, true);
1599  add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, true);
1600 }
1601 
1602 static void panel_draw(const bContext *C, Panel *panel)
1603 {
1604  uiLayout *layout = panel->layout;
1605  Main *bmain = CTX_data_main(C);
1606 
1608  NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
1609 
1610  uiLayoutSetPropSep(layout, true);
1611  /* Decorators are added manually for supported properties because the
1612  * attribute/value toggle requires a manually built layout anyway. */
1613  uiLayoutSetPropDecorate(layout, false);
1614 
1615  uiTemplateID(layout,
1616  C,
1617  ptr,
1618  "node_group",
1619  "node.new_geometry_node_group_assign",
1620  nullptr,
1621  nullptr,
1622  0,
1623  false,
1624  nullptr);
1625 
1626  if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
1627  PointerRNA bmain_ptr;
1628  RNA_main_pointer_create(bmain, &bmain_ptr);
1629 
1630  int socket_index;
1631  LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
1632  draw_property_for_socket(*C, layout, nmd, &bmain_ptr, ptr, *socket, socket_index);
1633  }
1634  }
1635 
1636  /* Draw node warnings. */
1637  if (nmd->runtime_eval_log != nullptr) {
1638  const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
1639  log.foreach_node_log([&](const geo_log::NodeLog &node_log) {
1640  for (const geo_log::NodeWarning &warning : node_log.warnings()) {
1641  if (warning.type != geo_log::NodeWarningType::Info) {
1642  uiItemL(layout, warning.message.c_str(), ICON_ERROR);
1643  }
1644  }
1645  });
1646  }
1647 
1648  modifier_panel_end(layout, ptr);
1649 }
1650 
1651 static void output_attribute_panel_draw(const bContext *C, Panel *panel)
1652 {
1653  uiLayout *layout = panel->layout;
1654 
1656  NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
1657 
1658  uiLayoutSetPropSep(layout, true);
1659  uiLayoutSetPropDecorate(layout, true);
1660 
1661  bool has_output_attribute = false;
1662  if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
1663  LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
1664  if (socket_type_has_attribute_toggle(*socket)) {
1665  has_output_attribute = true;
1666  draw_property_for_output_socket(*C, layout, *nmd, ptr, *socket);
1667  }
1668  }
1669  }
1670  if (!has_output_attribute) {
1671  uiItemL(layout, TIP_("No group output attributes connected"), ICON_INFO);
1672  }
1673 }
1674 
1676 {
1677  uiLayout *layout = panel->layout;
1678 
1680  NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
1681 
1682  if (nmd->runtime_eval_log == nullptr) {
1683  return;
1684  }
1685  const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
1686  Map<std::string, eNamedAttrUsage> usage_by_attribute;
1687  log.foreach_node_log([&](const geo_log::NodeLog &node_log) {
1688  for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
1689  usage_by_attribute.lookup_or_add_as(used_attribute.name,
1690  used_attribute.usage) |= used_attribute.usage;
1691  }
1692  });
1693 
1694  if (usage_by_attribute.is_empty()) {
1695  uiItemL(layout, IFACE_("No named attributes used"), ICON_INFO);
1696  return;
1697  }
1698 
1699  struct NameWithUsage {
1700  StringRefNull name;
1701  eNamedAttrUsage usage;
1702  };
1703 
1704  Vector<NameWithUsage> sorted_used_attribute;
1705  for (auto &&item : usage_by_attribute.items()) {
1706  sorted_used_attribute.append({item.key, item.value});
1707  }
1708  std::sort(sorted_used_attribute.begin(),
1709  sorted_used_attribute.end(),
1710  [](const NameWithUsage &a, const NameWithUsage &b) {
1711  return BLI_strcasecmp_natural(a.name.c_str(), b.name.c_str()) <= 0;
1712  });
1713 
1714  for (const NameWithUsage &attribute : sorted_used_attribute) {
1715  const StringRefNull attribute_name = attribute.name;
1716  const eNamedAttrUsage usage = attribute.usage;
1717 
1718  /* #uiLayoutRowWithHeading doesn't seem to work in this case. */
1719  uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
1720 
1721  std::stringstream ss;
1722  Vector<std::string> usages;
1723  if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) {
1724  usages.append(TIP_("Read"));
1725  }
1726  if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) {
1727  usages.append(TIP_("Write"));
1728  }
1729  if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) {
1730  usages.append(TIP_("Remove"));
1731  }
1732  for (const int i : usages.index_range()) {
1733  ss << usages[i];
1734  if (i < usages.size() - 1) {
1735  ss << ", ";
1736  }
1737  }
1738 
1739  uiLayout *row = uiLayoutRow(split, false);
1741  uiLayoutSetActive(row, false);
1742  uiItemL(row, ss.str().c_str(), ICON_NONE);
1743 
1744  row = uiLayoutRow(split, false);
1745  uiItemL(row, attribute_name.c_str(), ICON_NONE);
1746  }
1747 }
1748 
1749 static void panelRegister(ARegionType *region_type)
1750 {
1751  PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
1752  modifier_subpanel_register(region_type,
1753  "output_attributes",
1754  N_("Output Attributes"),
1755  nullptr,
1757  panel_type);
1758  modifier_subpanel_register(region_type,
1759  "internal_dependencies",
1760  N_("Internal Dependencies"),
1761  nullptr,
1763  panel_type);
1764 }
1765 
1766 static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
1767 {
1768  const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
1769 
1770  BLO_write_struct(writer, NodesModifierData, nmd);
1771 
1772  if (nmd->settings.properties != nullptr) {
1773  /* Note that the property settings are based on the socket type info
1774  * and don't necessarily need to be written, but we can't just free them. */
1775  IDP_BlendWrite(writer, nmd->settings.properties);
1776  }
1777 }
1778 
1779 static void blendRead(BlendDataReader *reader, ModifierData *md)
1780 {
1781  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1782  if (nmd->node_group == nullptr) {
1783  nmd->settings.properties = nullptr;
1784  }
1785  else {
1786  BLO_read_data_address(reader, &nmd->settings.properties);
1787  IDP_BlendDataRead(reader, &nmd->settings.properties);
1788  }
1789  nmd->runtime_eval_log = nullptr;
1790 }
1791 
1792 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
1793 {
1794  const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
1795  NodesModifierData *tnmd = reinterpret_cast<NodesModifierData *>(target);
1796 
1797  BKE_modifier_copydata_generic(md, target, flag);
1798 
1799  tnmd->runtime_eval_log = nullptr;
1800 
1801  if (nmd->settings.properties != nullptr) {
1803  }
1804 }
1805 
1806 static void freeData(ModifierData *md)
1807 {
1808  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1809  if (nmd->settings.properties != nullptr) {
1811  nmd->settings.properties = nullptr;
1812  }
1813 
1814  clear_runtime_data(nmd);
1815 }
1816 
1817 static void requiredDataMask(Object *UNUSED(ob),
1818  ModifierData *UNUSED(md),
1819  CustomData_MeshMasks *r_cddata_masks)
1820 {
1821  /* We don't know what the node tree will need. If there are vertex groups, it is likely that the
1822  * node tree wants to access them. */
1823  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
1824  r_cddata_masks->vmask |= CD_MASK_PROP_ALL;
1825 }
1826 
1828  /* name */ N_("GeometryNodes"),
1829  /* structName */ "NodesModifierData",
1830  /* structSize */ sizeof(NodesModifierData),
1831  /* srna */ &RNA_NodesModifier,
1832  /* type */ eModifierTypeType_Constructive,
1833  /* flags */
1838  /* icon */ ICON_GEOMETRY_NODES,
1839 
1840  /* copyData */ copyData,
1841 
1842  /* deformVerts */ nullptr,
1843  /* deformMatrices */ nullptr,
1844  /* deformVertsEM */ nullptr,
1845  /* deformMatricesEM */ nullptr,
1846  /* modifyMesh */ modifyMesh,
1847  /* modifyGeometrySet */ modifyGeometrySet,
1848 
1849  /* initData */ initData,
1850  /* requiredDataMask */ requiredDataMask,
1851  /* freeData */ freeData,
1852  /* isDisabled */ isDisabled,
1853  /* updateDepsgraph */ updateDepsgraph,
1854  /* dependsOnTime */ dependsOnTime,
1855  /* dependsOnNormals */ nullptr,
1856  /* foreachIDLink */ foreachIDLink,
1857  /* foreachTexLink */ foreachTexLink,
1858  /* freeRuntimeData */ nullptr,
1859  /* panelRegister */ panelRegister,
1860  /* blendWrite */ blendWrite,
1861  /* blendRead */ blendRead,
1862 };
typedef float(TangentPoint)[2]
eAttrDomain
Definition: BKE_attribute.h:25
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
CustomData interface, see also DNA_customdata_types.h.
@ CD_DEFAULT
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_INSTANCES
@ GEO_COMPONENT_TYPE_CURVE
#define IDP_Float(prop)
Definition: BKE_idprop.h:269
struct IDProperty * IDP_CopyProperty_ex(const struct IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define IDP_Int(prop)
Definition: BKE_idprop.h:244
struct IDPropertyUIData * IDP_ui_data_ensure(struct IDProperty *prop)
Definition: idprop.c:1519
void IDP_BlendWrite(struct BlendWriter *writer, const struct IDProperty *prop)
#define IDP_Id(prop)
Definition: BKE_idprop.h:273
void IDP_CopyPropertyContent(struct IDProperty *dst, struct IDProperty *src) ATTR_NONNULL()
Definition: idprop.c:769
void IDP_foreach_property(struct IDProperty *id_property_root, int type_filter, IDPForeachPropertyCallback callback, void *user_data)
Definition: idprop.c:1117
struct IDProperty * IDP_New(char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:887
#define IDP_BlendDataRead(reader, prop)
Definition: BKE_idprop.h:321
struct IDProperty * IDP_NewString(const char *st, const char *name, int maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition: idprop.c:339
#define IDP_String(prop)
Definition: BKE_idprop.h:271
#define IDP_Double(prop)
Definition: BKE_idprop.h:270
void IDP_FreeProperty_ex(struct IDProperty *prop, bool do_id_user)
Definition: idprop.c:1087
void IDP_ui_data_free(struct IDProperty *prop)
Definition: idprop.c:1023
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1093
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL()
Definition: idprop.c:631
struct IDProperty * IDP_GetPropertyFromGroup(const struct IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void IDP_AssignString(struct IDProperty *prop, const char *st, int maxlen) ATTR_NONNULL()
Definition: idprop.c:383
#define IDP_Array(prop)
Definition: BKE_idprop.h:245
struct ID * BKE_libblock_find_session_uuid(struct Main *bmain, short type, uint32_t session_uuid)
Definition: lib_id.c:1304
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:73
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
struct ModifierData * BKE_modifier_get_original(const struct Object *object, struct ModifierData *md)
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:107
ModifierTypeFlag
Definition: BKE_modifier.h:65
@ eModifierTypeFlag_AcceptsCVs
Definition: BKE_modifier.h:67
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:68
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:78
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:69
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void(* TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname)
Definition: BKE_modifier.h:108
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_Constructive
Definition: BKE_modifier.h:47
struct ModifierData * BKE_modifiers_findby_name(const struct Object *ob, const char *name)
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
@ MOD_APPLY_ORCO
Definition: BKE_modifier.h:120
#define GEO_NODE_OBJECT_INFO
Definition: BKE_node.h:1386
#define GEO_NODE_DEFORM_CURVES_ON_SURFACE
Definition: BKE_node.h:1508
#define NODE_CUSTOM_GROUP
Definition: BKE_node.h:989
#define GEO_NODE_INPUT_SCENE_TIME
Definition: BKE_node.h:1486
#define GEO_NODE_COLLECTION_INFO
Definition: BKE_node.h:1388
General operations, lookup, etc. for blender objects.
General operations for point clouds.
struct bScreen * BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:344
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:899
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
size_t size_t char size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL()
Definition: string.c:250
#define ARRAY_SIZE(arr)
#define UNUSED(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_read_data_address(reader, ptr_p)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define TIP_(msgid)
#define IFACE_(msgid)
typedef double(DMatrix)[4][4]
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
bool DEG_is_active(const struct Depsgraph *depsgraph)
Definition: depsgraph.cc:312
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_add_object_relation(struct DepsNodeHandle *node_handle, struct Object *object, eDepsObjectComponentType component, const char *description)
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, const char *description)
void DEG_add_collection_geometry_customdata_mask(struct DepsNodeHandle *node_handle, struct Collection *collection, const struct CustomData_MeshMasks *masks)
void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle, struct ID *id, const char *description)
void DEG_add_customdata_mask(struct DepsNodeHandle *handle, struct Object *object, const struct CustomData_MeshMasks *masks)
void DEG_add_collection_geometry_relation(struct DepsNodeHandle *node_handle, struct Collection *collection, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
void DEG_add_node_tree_output_relation(struct DepsNodeHandle *node_handle, struct bNodeTree *node_tree, const char *description)
bool DEG_object_has_geometry_component(struct Object *object)
struct Object * DEG_get_original_object(struct Object *object)
struct Main * DEG_get_bmain(const Depsgraph *graph)
@ IDP_TYPE_FILTER_ID
Definition: DNA_ID.h:155
@ IDP_DOUBLE
Definition: DNA_ID.h:143
@ IDP_FLOAT
Definition: DNA_ID.h:138
@ IDP_STRING
Definition: DNA_ID.h:136
@ IDP_INT
Definition: DNA_ID.h:137
@ IDP_GROUP
Definition: DNA_ID.h:141
@ IDP_ARRAY
Definition: DNA_ID.h:140
@ IDP_ID
Definition: DNA_ID.h:142
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ IDP_FLAG_OVERRIDABLE_LIBRARY
Definition: DNA_ID.h:172
ID_Type
Definition: DNA_ID_enums.h:44
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_OB
Definition: DNA_ID_enums.h:47
Object groups, one object can be in many groups at once.
#define CD_MASK_MDEFORMVERT
#define CD_MASK_PROP_ALL
eCustomDataType
@ CD_ORIGINDEX
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
#define MAX_NAME
Definition: DNA_defs.h:48
struct NodesModifierData NodesModifierData
@ eModifierType_Nodes
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_TEXTURE
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_GEOMETRY
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ GEO_NODE_TRANSFORM_SPACE_RELATIVE
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ OB_CURVES
@ SPREADSHEET_CONTEXT_OBJECT
@ SPREADSHEET_CONTEXT_MODIFIER
@ SPREADSHEET_CONTEXT_NODE
@ SPACE_SPREADSHEET
struct Object * ED_object_context(const struct bContext *C)
bScreen * ED_screen_animation_playing(const struct wmWindowManager *wm)
void ED_undo_push(struct bContext *C, const char *str)
Definition: ed_undo.c:100
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
Definition: MOD_nodes.cc:402
static void add_used_ids_from_sockets(const ListBase &sockets, Set< ID * > &ids)
Definition: MOD_nodes.cc:135
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
Definition: MOD_nodes.cc:1792
static void output_attribute_panel_draw(const bContext *C, Panel *panel)
Definition: MOD_nodes.cc:1651
static bool id_property_type_matches_socket(const bNodeSocket &socket, const IDProperty &property)
Definition: MOD_nodes.cc:537
static Vector< SpaceSpreadsheet * > find_spreadsheet_editors(Main *bmain)
Definition: MOD_nodes.cc:822
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition: MOD_nodes.cc:1299
static void initialize_group_input(NodesModifierData &nmd, const OutputSocketRef &socket, void *r_value)
Definition: MOD_nodes.cc:765
static Vector< OutputAttributeToStore > compute_attributes_to_store(const GeometrySet &geometry, const MultiValueMap< eAttrDomain, OutputAttributeInfo > &outputs_by_domain)
Definition: MOD_nodes.cc:989
static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
Definition: MOD_nodes.cc:411
static NodesModifierData * get_modifier_data(Main &bmain, const wmWindowManager &wm, const AttributeSearchData &data)
Definition: MOD_nodes.cc:1328
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition: MOD_nodes.cc:264
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
Definition: MOD_nodes.cc:643
static bool dependsOnTime(struct Scene *UNUSED(scene), ModifierData *md)
Definition: MOD_nodes.cc:334
BLI_STATIC_ASSERT(std::is_trivially_destructible_v< AttributeSearchData >, "")
static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet, NodesModifierData *nmd, const ModifierEvalContext *ctx, const DerivedNodeTree &tree, Set< DSocket > &r_sockets_to_preview)
Definition: MOD_nodes.cc:841
static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
Definition: MOD_nodes.cc:372
static void draw_property_for_socket(const bContext &C, uiLayout *layout, NodesModifierData *nmd, PointerRNA *bmain_ptr, PointerRNA *md_ptr, const bNodeSocket &socket, const int socket_index)
Definition: MOD_nodes.cc:1515
static IDProperty * id_property_create_from_socket(const bNodeSocket &socket)
Definition: MOD_nodes.cc:419
static void check_property_socket_sync(const Object *ob, ModifierData *md)
Definition: MOD_nodes.cc:1183
static MultiValueMap< eAttrDomain, OutputAttributeInfo > find_output_attributes_to_store(const NodesModifierData &nmd, const NodeRef &output_node, Span< GMutablePointer > output_values)
Definition: MOD_nodes.cc:946
static void add_collection_relation(const ModifierUpdateDepsgraphContext *ctx, Collection &collection)
Definition: MOD_nodes.cc:243
static void blendRead(BlendDataReader *reader, ModifierData *md)
Definition: MOD_nodes.cc:1779
static void store_output_attributes(GeometrySet &geometry, const NodesModifierData &nmd, const NodeRef &output_node, Span< GMutablePointer > output_values)
Definition: MOD_nodes.cc:1072
static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks)
Definition: MOD_nodes.cc:1817
static void draw_property_for_output_socket(const bContext &C, uiLayout *layout, const NodesModifierData &nmd, PointerRNA *md_ptr, const bNodeSocket &socket)
Definition: MOD_nodes.cc:1582
static const std::string use_attribute_suffix
Definition: MOD_nodes.cc:396
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
Definition: MOD_nodes.cc:345
static void attribute_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
Definition: MOD_nodes.cc:1352
static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Object &object)
Definition: MOD_nodes.cc:250
static void modifyGeometry(ModifierData *md, const ModifierEvalContext *ctx, GeometrySet &geometry_set)
Definition: MOD_nodes.cc:1225
static void add_attribute_search_or_value_buttons(const bContext &C, uiLayout *layout, const NodesModifierData &nmd, PointerRNA *md_ptr, const bNodeSocket &socket)
Definition: MOD_nodes.cc:1468
static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *panel)
Definition: MOD_nodes.cc:1675
static void find_sockets_to_preview(NodesModifierData *nmd, const ModifierEvalContext *ctx, const DerivedNodeTree &tree, Set< DSocket > &r_sockets_to_preview)
Definition: MOD_nodes.cc:907
static const std::string attribute_name_suffix
Definition: MOD_nodes.cc:397
static void modifyGeometrySet(ModifierData *md, const ModifierEvalContext *ctx, GeometrySet *geometry_set)
Definition: MOD_nodes.cc:1312
static bool logging_enabled(const ModifierEvalContext *ctx)
Definition: MOD_nodes.cc:385
static void initData(ModifierData *md)
Definition: MOD_nodes.cc:126
static void clear_runtime_data(NodesModifierData *nmd)
Definition: MOD_nodes.cc:922
static void panelRegister(ARegionType *region_type)
Definition: MOD_nodes.cc:1749
static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
Definition: MOD_nodes.cc:367
static GeometrySet compute_geometry(const DerivedNodeTree &tree, Span< const NodeRef * > group_input_nodes, const NodeRef &output_node, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx)
Definition: MOD_nodes.cc:1089
static bool node_needs_own_transform_relation(const bNode &node)
Definition: MOD_nodes.cc:180
static void init_socket_cpp_value_from_property(const IDProperty &property, const eNodeSocketDatatype socket_value_type, void *r_value)
Definition: MOD_nodes.cc:563
static void find_used_ids_from_settings(const NodesModifierSettings &settings, Set< ID * > &ids)
Definition: MOD_nodes.cc:221
ModifierTypeInfo modifierType_Nodes
Definition: MOD_nodes.cc:1827
static const CustomData_MeshMasks dependency_data_mask
Definition: MOD_nodes.cc:237
static void process_nodes_for_depsgraph(const bNodeTree &tree, Set< ID * > &ids, bool &r_needs_own_transform_relation)
Definition: MOD_nodes.cc:201
static void blendWrite(BlendWriter *writer, const ID *UNUSED(id_owner), const ModifierData *md)
Definition: MOD_nodes.cc:1766
static bool check_tree_for_time_node(const bNodeTree &tree, Set< const bNodeTree * > &r_checked_trees)
Definition: MOD_nodes.cc:314
static void store_computed_output_attributes(GeometrySet &geometry, const Span< OutputAttributeToStore > attributes_to_store)
Definition: MOD_nodes.cc:1032
static void freeData(ModifierData *md)
Definition: MOD_nodes.cc:1806
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
Definition: MOD_nodes.cc:1383
static void panel_draw(const bContext *C, Panel *panel)
Definition: MOD_nodes.cc:1602
static void add_attribute_search_button(const bContext &C, uiLayout *layout, const NodesModifierData &nmd, PointerRNA *md_ptr, const StringRefNull rna_path_attribute_name, const bNodeSocket &socket, const bool is_output)
Definition: MOD_nodes.cc:1403
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
Definition: MOD_ui_common.c:91
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
NODE_GROUP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
@ PROP_COLOR
Definition: RNA_types.h:153
#define C
Definition: RandGen.cpp:25
@ UI_LAYOUT_ALIGN_RIGHT
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ UI_BUT_REDALERT
Definition: UI_interface.h:201
void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value)
Definition: interface.cc:6324
void uiItemL(uiLayout *layout, const char *name, int icon)
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
Definition: interface.cc:6242
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
uiBut * uiDefIconTextButR(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, struct PointerRNA *ptr, const char *propname, int index, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5709
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
Definition: interface.cc:6308
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, struct IDProperty *properties, wmOperatorCallContext context, int flag, struct PointerRNA *r_opptr)
void uiItemDecoratorR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int index)
void uiTemplateID(uiLayout *layout, const struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter, bool live_icon, const char *text)
#define UI_UNIT_X
@ UI_BTYPE_SEARCH_MENU
Definition: UI_interface.h:372
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
void UI_but_flag_enable(uiBut *but, int flag)
Definition: interface.cc:5858
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
Span< T > as_span() const
Definition: BLI_array.hh:231
int64_t size() const
int64_t alignment() const
const void * get() const
const CPPType * type() const
destruct_ptr< T > construct(Args &&...args)
void * allocate(const int64_t size, const int64_t alignment)
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:220
Value & lookup_or_add_as(ForwardKey &&key, ForwardValue &&...value)
Definition: BLI_map.hh:547
ItemIterator items() const
Definition: BLI_map.hh:859
bool is_empty() const
Definition: BLI_map.hh:911
MapType::ItemIterator items() const
void add(const Key &key, const Value &value)
LinearAllocator & linear_allocator()
Iterator begin() const
Definition: BLI_set.hh:466
Iterator end() const
Definition: BLI_set.hh:476
bool add(const Key &key)
Definition: BLI_set.hh:253
constexpr Span drop_front(int64_t n) const
Definition: BLI_span.hh:159
constexpr Span drop_back(int64_t n) const
Definition: BLI_span.hh:170
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
constexpr bool is_empty() const
Definition: BLI_span.hh:248
constexpr bool is_empty() const
constexpr const char * c_str() const
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
const T & last(const int64_t n=0) const
Definition: BLI_vector.hh:663
Span< T > as_span() const
Definition: BLI_vector.hh:325
IndexRange index_range() const
Definition: BLI_vector.hh:920
void extend(Span< T > array)
Definition: BLI_vector.hh:530
int domain_size(const eAttrDomain domain) const
std::optional< AttributeMetaData > lookup_meta_data(const AttributeIDRef &attribute_id) const
bool domain_supported(const eAttrDomain domain) const
bool add(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
bool remove(const AttributeIDRef &attribute_id)
GAttributeWriter lookup_or_add_for_write(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefault())
void construct_from_field(void *dst, GField field) const
GField as_field(const void *value_or_field) const
Span< const InputSocketRef * > inputs() const
Span< const NodeRef * > nodes() const
Span< const NodeRef * > nodes_by_type(StringRefNull idname) const
bNodeSocketType * typeinfo() const
StringRefNull idname() const
bNodeSocket * bsocket() const
StringRefNull identifier() const
OperationNode * node
Scene scene
Material material
void * user_data
void * tree
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
#define str(s)
#define GS(x)
Definition: iris.c:225
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float3 log(float3 v)
Definition: math_float3.h:397
static unsigned a[3]
Definition: RandGen.cpp:78
bool allow_procedural_attribute_access(StringRef attribute_name)
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
Definition: customdata.cc:5337
static void area(int d1, int d2, int e1, int e2, float weights[2])
static int node_context(const bContext *C, const char *member, bContextDataResult *result)
Definition: space_node.cc:834
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:92
void evaluate_geometry_nodes(GeometryNodesEvaluationParams &params)
Map< bNodeTree *, std::unique_ptr< const NodeTreeRef > > NodeTreeRefMap
void attribute_search_add_items(StringRefNull str, bool can_create_attribute, Span< const nodes::geometry_nodes_eval_log::GeometryAttributeInfo * > infos, uiSearchItems *items, bool is_first)
vec_base< float, 3 > float3
std::unique_ptr< T, DestructValueAtAddress< T > > destruct_ptr
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition: BLI_color.hh:346
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:5155
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
Definition: rna_access.c:5129
void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr)
Definition: rna_access.c:105
unsigned int uint32_t
Definition: stdint.h:80
#define UI_MENU_ARROW_SEP
uint32_t object_session_uid
Definition: MOD_nodes.cc:1320
char socket_identifier[MAX_NAME]
Definition: MOD_nodes.cc:1322
char modifier_name[MAX_NAME]
Definition: MOD_nodes.cc:1321
struct Object * surface
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
static GeometrySet create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
bool has(const GeometryComponentType component_type) const
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
const Mesh * get_mesh_for_read() const
Mesh * get_mesh_for_write()
bool has_mesh() const
double * default_array
Definition: DNA_ID.h:74
IDPropertyUIData base
Definition: DNA_ID.h:73
double default_value
Definition: DNA_ID.h:85
IDPropertyUIData base
Definition: DNA_ID.h:58
char * default_value
Definition: DNA_ID.h:91
char * description
Definition: DNA_ID.h:49
int rna_subtype
Definition: DNA_ID.h:51
short flag
Definition: DNA_ID.h:109
IDPropertyUIData * ui_data
Definition: DNA_ID.h:128
char type
Definition: DNA_ID.h:108
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase wm
Definition: BKE_main.h:197
CustomData vdata
int totedge
int totvert
CustomData pdata
int totpoly
CustomData edata
struct Depsgraph * depsgraph
Definition: BKE_modifier.h:140
ModifierApplyFlag flag
Definition: BKE_modifier.h:142
struct Object * object
Definition: BKE_modifier.h:141
struct DepsNodeHandle * node
Definition: BKE_modifier.h:134
struct bNodeTree * node_group
struct NodesModifierSettings settings
struct IDProperty * properties
void * data
StringRefNull name
Definition: MOD_nodes.cc:932
StringRefNull name
Definition: MOD_nodes.cc:938
GeometryComponentType component_type
Definition: MOD_nodes.cc:936
struct uiLayout * layout
void * data
Definition: RNA_types.h:38
Defines a socket type.
Definition: BKE_node.h:143
SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value
Definition: BKE_node.h:201
const CPPTypeHandle * geometry_nodes_cpp_type
Definition: BKE_node.h:199
const CPPTypeHandle * base_cpp_type
Definition: BKE_node.h:195
char name[64]
char attribute_domain
char description[64]
void * default_value
char identifier[64]
ListBase inputs
ListBase outputs
ListBase areabase
struct IDPropertyTemplate::@27 array
struct ID * id
Definition: BKE_idprop.h:33
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480