Blender  V2.93
MOD_nodes.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <cstring>
25 #include <iostream>
26 #include <string>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "BLI_float3.hh"
31 #include "BLI_listbase.h"
32 #include "BLI_multi_value_map.hh"
33 #include "BLI_set.hh"
34 #include "BLI_string.h"
35 #include "BLI_utildefines.h"
36 
37 #include "DNA_collection_types.h"
38 #include "DNA_defaults.h"
39 #include "DNA_mesh_types.h"
40 #include "DNA_meshdata_types.h"
41 #include "DNA_modifier_types.h"
42 #include "DNA_node_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_pointcloud_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_screen_types.h"
47 #include "DNA_space_types.h"
49 
50 #include "BKE_customdata.h"
52 #include "BKE_global.h"
53 #include "BKE_idprop.h"
54 #include "BKE_lib_query.h"
55 #include "BKE_main.h"
56 #include "BKE_mesh.h"
57 #include "BKE_modifier.h"
58 #include "BKE_node_ui_storage.hh"
59 #include "BKE_object.h"
60 #include "BKE_pointcloud.h"
61 #include "BKE_screen.h"
62 #include "BKE_simulation.h"
63 #include "BKE_workspace.h"
64 
65 #include "BLO_read_write.h"
66 
67 #include "UI_interface.h"
68 #include "UI_resources.h"
69 
70 #include "RNA_access.h"
71 #include "RNA_enum_types.h"
72 
73 #include "DEG_depsgraph_build.h"
74 #include "DEG_depsgraph_query.h"
75 
76 #include "MOD_modifiertypes.h"
77 #include "MOD_nodes.h"
78 #include "MOD_ui_common.h"
79 
80 #include "ED_spreadsheet.h"
81 
82 #include "NOD_derived_node_tree.hh"
83 #include "NOD_geometry.h"
84 #include "NOD_geometry_exec.hh"
86 #include "NOD_type_callbacks.hh"
87 #include "NOD_type_conversions.hh"
88 
89 using blender::float3;
92 using blender::Map;
93 using blender::Set;
94 using blender::Span;
95 using blender::StringRef;
97 using blender::Vector;
105 using namespace blender::fn::multi_function_types;
107 
108 static void initData(ModifierData *md)
109 {
111 
112  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(nmd, modifier));
113 
115 }
116 
117 static void addIdsUsedBySocket(const ListBase *sockets, Set<ID *> &ids)
118 {
119  LISTBASE_FOREACH (const bNodeSocket *, socket, sockets) {
120  if (socket->type == SOCK_OBJECT) {
121  Object *object = ((bNodeSocketValueObject *)socket->default_value)->value;
122  if (object != nullptr) {
123  ids.add(&object->id);
124  }
125  }
126  else if (socket->type == SOCK_COLLECTION) {
127  Collection *collection = ((bNodeSocketValueCollection *)socket->default_value)->value;
128  if (collection != nullptr) {
129  ids.add(&collection->id);
130  }
131  }
132  }
133 }
134 
136 {
137  Set<const bNodeTree *> handled_groups;
138 
139  LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
140  addIdsUsedBySocket(&node->inputs, ids);
141  addIdsUsedBySocket(&node->outputs, ids);
142 
143  if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
144  const bNodeTree *group = (bNodeTree *)node->id;
145  if (group != nullptr && handled_groups.add(group)) {
146  find_used_ids_from_nodes(*group, ids);
147  }
148  }
149  }
150 }
151 
153 {
155  settings.properties,
157  [](IDProperty *property, void *user_data) {
158  Set<ID *> *ids = (Set<ID *> *)user_data;
159  ID *id = IDP_Id(property);
160  if (id != nullptr) {
161  ids->add(id);
162  }
163  },
164  &ids);
165 }
166 
167 /* We don't know exactly what attributes from the other object we will need. */
173 
175  Collection &collection)
176 {
177  DEG_add_collection_geometry_relation(ctx->node, &collection, "Nodes Modifier");
179 }
180 
182 {
183  DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
184  if (&(ID &)object != &ctx->object->id) {
185  if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
186  add_collection_relation(ctx, *object.instance_collection);
187  }
188  else if (DEG_object_has_geometry_component(&object)) {
189  DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
191  }
192  }
193 }
194 
196 {
197  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
198  DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier");
199  if (nmd->node_group != nullptr) {
200  DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
201 
202  Set<ID *> used_ids;
203  find_used_ids_from_settings(nmd->settings, used_ids);
204  find_used_ids_from_nodes(*nmd->node_group, used_ids);
205  for (ID *id : used_ids) {
206  if (GS(id->name) == ID_OB) {
207  Object *object = reinterpret_cast<Object *>(id);
208  add_object_relation(ctx, *object);
209  }
210  if (GS(id->name) == ID_GR) {
211  Collection *collection = reinterpret_cast<Collection *>(id);
212  add_collection_relation(ctx, *collection);
213  }
214  }
215  }
216 
217  /* TODO: Add dependency for adding and removing objects in collections. */
218 }
219 
220 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
221 {
222  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
223  walk(userData, ob, (ID **)&nmd->node_group, IDWALK_CB_USER);
224 
225  struct ForeachSettingData {
226  IDWalkFunc walk;
227  void *userData;
228  Object *ob;
229  } settings = {walk, userData, ob};
230 
232  nmd->settings.properties,
234  [](IDProperty *id_prop, void *user_data) {
235  ForeachSettingData *settings = (ForeachSettingData *)user_data;
236  settings->walk(
237  settings->userData, settings->ob, (ID **)&id_prop->data.pointer, IDWALK_CB_USER);
238  },
239  &settings);
240 }
241 
242 static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
243 {
244  walk(userData, ob, md, "texture");
245 }
246 
247 static bool isDisabled(const struct Scene *UNUSED(scene),
248  ModifierData *md,
249  bool UNUSED(useRenderParams))
250 {
251  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
252 
253  if (nmd->node_group == nullptr) {
254  return true;
255  }
256 
257  return false;
258 }
259 
260 static bool logging_enabled(const ModifierEvalContext *ctx)
261 {
262  if (!DEG_is_active(ctx->depsgraph)) {
263  return false;
264  }
265  if ((ctx->flag & MOD_APPLY_ORCO) != 0) {
266  return false;
267  }
268  return true;
269 }
270 
272  public:
273  using LogSocketValueFn = std::function<void(DSocket, Span<GPointer>)>;
274 
275  private:
276  blender::LinearAllocator<> allocator_;
278  Vector<DInputSocket> group_outputs_;
280  const blender::nodes::DataTypeConversions &conversions_;
281  const PersistentDataHandleMap &handle_map_;
282  const Object *self_object_;
283  const ModifierData *modifier_;
284  Depsgraph *depsgraph_;
285  LogSocketValueFn log_socket_value_fn_;
286 
287  public:
289  Vector<DInputSocket> group_outputs,
291  const PersistentDataHandleMap &handle_map,
292  const Object *self_object,
293  const ModifierData *modifier,
295  LogSocketValueFn log_socket_value_fn)
296  : group_outputs_(std::move(group_outputs)),
297  mf_by_node_(mf_by_node),
298  conversions_(blender::nodes::get_implicit_type_conversions()),
299  handle_map_(handle_map),
300  self_object_(self_object),
301  modifier_(modifier),
302  depsgraph_(depsgraph),
303  log_socket_value_fn_(std::move(log_socket_value_fn))
304  {
305  for (auto item : group_input_data.items()) {
306  this->log_socket_value(item.key, item.value);
307  this->forward_to_inputs(item.key, item.value);
308  }
309  }
310 
312  {
313  Vector<GMutablePointer> results;
314  for (const DInputSocket &group_output : group_outputs_) {
315  Vector<GMutablePointer> result = this->get_input_values(group_output);
316  this->log_socket_value(group_output, result);
317  results.append(result[0]);
318  }
319  for (GMutablePointer value : value_by_input_.values()) {
320  value.destruct();
321  }
322  return results;
323  }
324 
325  private:
326  Vector<GMutablePointer> get_input_values(const DInputSocket socket_to_compute)
327  {
328  Vector<DSocket> from_sockets;
329  socket_to_compute.foreach_origin_socket([&](DSocket socket) { from_sockets.append(socket); });
330 
331  if (from_sockets.is_empty()) {
332  /* The input is not connected, use the value from the socket itself. */
333  const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
334  return {get_unlinked_input_value(socket_to_compute, type)};
335  }
336 
337  /* Multi-input sockets contain a vector of inputs. */
338  if (socket_to_compute->is_multi_input_socket()) {
339  return this->get_inputs_from_incoming_links(socket_to_compute, from_sockets);
340  }
341 
342  const DSocket from_socket = from_sockets[0];
343  GMutablePointer value = this->get_input_from_incoming_link(socket_to_compute, from_socket);
344  return {value};
345  }
346 
347  Vector<GMutablePointer> get_inputs_from_incoming_links(const DInputSocket socket_to_compute,
348  const Span<DSocket> from_sockets)
349  {
351  for (const int i : from_sockets.index_range()) {
352  const DSocket from_socket = from_sockets[i];
353  const int first_occurence = from_sockets.take_front(i).first_index_try(from_socket);
354  if (first_occurence == -1) {
355  values.append(this->get_input_from_incoming_link(socket_to_compute, from_socket));
356  }
357  else {
358  /* If the same from-socket occurs more than once, we make a copy of the first value. This
359  * can happen when a node linked to a multi-input-socket is muted. */
360  GMutablePointer value = values[first_occurence];
361  const CPPType *type = value.type();
362  void *copy_buffer = allocator_.allocate(type->size(), type->alignment());
363  type->copy_to_uninitialized(value.get(), copy_buffer);
364  values.append({type, copy_buffer});
365  }
366  }
367  return values;
368  }
369 
370  GMutablePointer get_input_from_incoming_link(const DInputSocket socket_to_compute,
371  const DSocket from_socket)
372  {
373  if (from_socket->is_output()) {
374  const DOutputSocket from_output_socket{from_socket};
375  const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(socket_to_compute,
376  from_output_socket);
377  std::optional<GMutablePointer> value = value_by_input_.pop_try(key);
378  if (value.has_value()) {
379  /* This input has been computed before, return it directly. */
380  return {*value};
381  }
382 
383  /* Compute the socket now. */
384  this->compute_output_and_forward(from_output_socket);
385  return {value_by_input_.pop(key)};
386  }
387 
388  /* Get value from an unlinked input socket. */
389  const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
390  const DInputSocket from_input_socket{from_socket};
391  return {get_unlinked_input_value(from_input_socket, type)};
392  }
393 
394  void compute_output_and_forward(const DOutputSocket socket_to_compute)
395  {
396  const DNode node{socket_to_compute.context(), &socket_to_compute->node()};
397 
398  if (!socket_to_compute->is_available()) {
399  /* If the output is not available, use a default value. */
400  const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo());
401  void *buffer = allocator_.allocate(type.size(), type.alignment());
402  type.copy_to_uninitialized(type.default_value(), buffer);
403  this->forward_to_inputs(socket_to_compute, {type, buffer});
404  return;
405  }
406 
407  /* Prepare inputs required to execute the node. */
408  GValueMap<StringRef> node_inputs_map{allocator_};
409  for (const InputSocketRef *input_socket : node->inputs()) {
410  if (input_socket->is_available()) {
411  DInputSocket dsocket{node.context(), input_socket};
412  Vector<GMutablePointer> values = this->get_input_values(dsocket);
413  this->log_socket_value(dsocket, values);
414  for (int i = 0; i < values.size(); ++i) {
415  /* Values from Multi Input Sockets are stored in input map with the format
416  * <identifier>[<index>]. */
417  blender::StringRefNull key = allocator_.copy_string(
418  input_socket->identifier() + (i > 0 ? ("[" + std::to_string(i)) + "]" : ""));
419  node_inputs_map.add_new_direct(key, std::move(values[i]));
420  }
421  }
422  }
423 
424  /* Execute the node. */
425  GValueMap<StringRef> node_outputs_map{allocator_};
427  node, node_inputs_map, node_outputs_map, handle_map_, self_object_, modifier_, depsgraph_};
428  this->execute_node(node, params);
429 
430  /* Forward computed outputs to linked input sockets. */
431  for (const OutputSocketRef *output_socket : node->outputs()) {
432  if (output_socket->is_available()) {
433  const DOutputSocket dsocket{node.context(), output_socket};
434  GMutablePointer value = node_outputs_map.extract(output_socket->identifier());
435  this->log_socket_value(dsocket, value);
436  this->forward_to_inputs(dsocket, value);
437  }
438  }
439  }
440 
441  void log_socket_value(const DSocket socket, Span<GPointer> values)
442  {
443  if (log_socket_value_fn_) {
444  log_socket_value_fn_(socket, values);
445  }
446  }
447 
448  void log_socket_value(const DSocket socket, Span<GMutablePointer> values)
449  {
450  this->log_socket_value(socket, values.cast<GPointer>());
451  }
452 
453  void log_socket_value(const DSocket socket, GPointer value)
454  {
455  this->log_socket_value(socket, Span<GPointer>(&value, 1));
456  }
457 
458  void execute_node(const DNode node, GeoNodeExecParams params)
459  {
460  const bNode &bnode = params.node();
461 
462  /* Use the geometry-node-execute callback if it exists. */
463  if (bnode.typeinfo->geometry_node_execute != nullptr) {
465  return;
466  }
467 
468  /* Use the multi-function implementation if it exists. */
469  const MultiFunction *multi_function = mf_by_node_.lookup_default(node, nullptr);
470  if (multi_function != nullptr) {
471  this->execute_multi_function_node(node, params, *multi_function);
472  return;
473  }
474 
475  /* Just output default values if no implementation exists. */
476  this->execute_unknown_node(node, params);
477  }
478 
479  void execute_multi_function_node(const DNode node,
481  const MultiFunction &fn)
482  {
483  MFContextBuilder fn_context;
484  MFParamsBuilder fn_params{fn, 1};
485  Vector<GMutablePointer> input_data;
486  for (const InputSocketRef *socket_ref : node->inputs()) {
487  if (socket_ref->is_available()) {
488  GMutablePointer data = params.extract_input(socket_ref->identifier());
489  fn_params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1));
490  input_data.append(data);
491  }
492  }
493  Vector<GMutablePointer> output_data;
494  for (const OutputSocketRef *socket_ref : node->outputs()) {
495  if (socket_ref->is_available()) {
496  const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_ref->typeinfo());
497  void *buffer = allocator_.allocate(type.size(), type.alignment());
498  fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1));
499  output_data.append(GMutablePointer(type, buffer));
500  }
501  }
502  fn.call(IndexRange(1), fn_params, fn_context);
503  for (GMutablePointer value : input_data) {
504  value.destruct();
505  }
506  int output_index = 0;
507  for (const int i : node->outputs().index_range()) {
508  if (node->output(i).is_available()) {
509  GMutablePointer value = output_data[output_index];
510  params.set_output_by_move(node->output(i).identifier(), value);
511  value.destruct();
512  output_index++;
513  }
514  }
515  }
516 
517  void execute_unknown_node(const DNode node, GeoNodeExecParams params)
518  {
519  for (const OutputSocketRef *socket : node->outputs()) {
520  if (socket->is_available()) {
522  params.set_output_by_copy(socket->identifier(), {type, type.default_value()});
523  }
524  }
525  }
526 
527  void forward_to_inputs(const DOutputSocket from_socket, GMutablePointer value_to_forward)
528  {
529  /* For all sockets that are linked with the from_socket push the value to their node. */
530  Vector<DInputSocket> to_sockets_all;
531 
532  auto handle_target_socket_fn = [&](DInputSocket to_socket) {
533  to_sockets_all.append_non_duplicates(to_socket);
534  };
535  auto handle_skipped_socket_fn = [&, this](DSocket socket) {
536  this->log_socket_value(socket, value_to_forward);
537  };
538 
539  from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn);
540 
541  const CPPType &from_type = *value_to_forward.type();
542  Vector<DInputSocket> to_sockets_same_type;
543  for (const DInputSocket &to_socket : to_sockets_all) {
544  const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo());
545  const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
546  if (from_type == to_type) {
547  to_sockets_same_type.append(to_socket);
548  }
549  else {
550  void *buffer = allocator_.allocate(to_type.size(), to_type.alignment());
551  if (conversions_.is_convertible(from_type, to_type)) {
552  conversions_.convert_to_uninitialized(
553  from_type, to_type, value_to_forward.get(), buffer);
554  }
555  else {
556  to_type.copy_to_uninitialized(to_type.default_value(), buffer);
557  }
558  add_value_to_input_socket(key, GMutablePointer{to_type, buffer});
559  }
560  }
561 
562  if (to_sockets_same_type.size() == 0) {
563  /* This value is not further used, so destruct it. */
564  value_to_forward.destruct();
565  }
566  else if (to_sockets_same_type.size() == 1) {
567  /* This value is only used on one input socket, no need to copy it. */
568  const DInputSocket to_socket = to_sockets_same_type[0];
569  const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
570 
571  add_value_to_input_socket(key, value_to_forward);
572  }
573  else {
574  /* Multiple inputs use the value, make a copy for every input except for one. */
575  const DInputSocket first_to_socket = to_sockets_same_type[0];
576  Span<DInputSocket> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
577  const CPPType &type = *value_to_forward.type();
578  const std::pair<DInputSocket, DOutputSocket> first_key = std::make_pair(first_to_socket,
579  from_socket);
580  add_value_to_input_socket(first_key, value_to_forward);
581  for (const DInputSocket &to_socket : other_to_sockets) {
582  const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket);
583  void *buffer = allocator_.allocate(type.size(), type.alignment());
584  type.copy_to_uninitialized(value_to_forward.get(), buffer);
585  add_value_to_input_socket(key, GMutablePointer{type, buffer});
586  }
587  }
588  }
589 
590  void add_value_to_input_socket(const std::pair<DInputSocket, DOutputSocket> key,
591  GMutablePointer value)
592  {
593  value_by_input_.add_new(key, value);
594  }
595 
596  GMutablePointer get_unlinked_input_value(const DInputSocket &socket,
597  const CPPType &required_type)
598  {
599  bNodeSocket *bsocket = socket->bsocket();
601  void *buffer = allocator_.allocate(type.size(), type.alignment());
602 
603  if (bsocket->type == SOCK_OBJECT) {
604  Object *object = socket->default_value<bNodeSocketValueObject>()->value;
605  PersistentObjectHandle object_handle = handle_map_.lookup(object);
606  new (buffer) PersistentObjectHandle(object_handle);
607  }
608  else if (bsocket->type == SOCK_COLLECTION) {
609  Collection *collection = socket->default_value<bNodeSocketValueCollection>()->value;
610  PersistentCollectionHandle collection_handle = handle_map_.lookup(collection);
611  new (buffer) PersistentCollectionHandle(collection_handle);
612  }
613  else {
615  }
616 
617  if (type == required_type) {
618  return {type, buffer};
619  }
620  if (conversions_.is_convertible(type, required_type)) {
621  void *converted_buffer = allocator_.allocate(required_type.size(),
622  required_type.alignment());
623  conversions_.convert_to_uninitialized(type, required_type, buffer, converted_buffer);
624  type.destruct(buffer);
625  return {required_type, converted_buffer};
626  }
627  void *default_buffer = allocator_.allocate(required_type.size(), required_type.alignment());
628  required_type.copy_to_uninitialized(required_type.default_value(), default_buffer);
629  return {required_type, default_buffer};
630  }
631 };
632 
641  /* Create the actual property used to store the data for the modifier. */
642  IDProperty *(*create_prop)(const bNodeSocket &socket, const char *name);
643  /* Reused to build the "soft_min" property too. */
644  IDProperty *(*create_min_ui_prop)(const bNodeSocket &socket, const char *name);
645  /* Reused to build the "soft_max" property too. */
646  IDProperty *(*create_max_ui_prop)(const bNodeSocket &socket, const char *name);
647  /* This uses the same values as #create_prop, but sometimes the type is different, so it can't
648  * be the same function. */
649  IDProperty *(*create_default_ui_prop)(const bNodeSocket &socket, const char *name);
650  PropertyType (*rna_subtype_get)(const bNodeSocket &socket);
651  bool (*is_correct_type)(const IDProperty &property);
652  void (*init_cpp_value)(const IDProperty &property,
654  void *r_value);
655 };
656 
657 static IDProperty *socket_add_property(IDProperty *settings_prop_group,
658  IDProperty *ui_container,
659  const SocketPropertyType &property_type,
660  const bNodeSocket &socket)
661 {
662  const char *new_prop_name = socket.identifier;
663  /* Add the property actually storing the data to the modifier's group. */
664  IDProperty *prop = property_type.create_prop(socket, new_prop_name);
665  IDP_AddToGroup(settings_prop_group, prop);
666 
668 
669  /* Make the group in the UI container group to hold the property's UI settings. */
670  IDProperty *prop_ui_group;
671  {
672  IDPropertyTemplate idprop = {0};
673  prop_ui_group = IDP_New(IDP_GROUP, &idprop, new_prop_name);
674  IDP_AddToGroup(ui_container, prop_ui_group);
675  }
676 
677  /* Set property description (tooltip). */
678  IDPropertyTemplate property_description_template;
679  property_description_template.string.str = socket.description;
680  property_description_template.string.len = BLI_strnlen(socket.description, MAX_NAME) + 1;
681  property_description_template.string.subtype = IDP_STRING_SUB_UTF8;
682  IDProperty *description = IDP_New(IDP_STRING, &property_description_template, "description");
683  IDP_AddToGroup(prop_ui_group, description);
684 
685  /* Create the properties for the socket's UI settings. */
686  if (property_type.create_min_ui_prop != nullptr) {
687  IDP_AddToGroup(prop_ui_group, property_type.create_min_ui_prop(socket, "min"));
688  IDP_AddToGroup(prop_ui_group, property_type.create_min_ui_prop(socket, "soft_min"));
689  }
690  if (property_type.create_max_ui_prop != nullptr) {
691  IDP_AddToGroup(prop_ui_group, property_type.create_max_ui_prop(socket, "max"));
692  IDP_AddToGroup(prop_ui_group, property_type.create_max_ui_prop(socket, "soft_max"));
693  }
694  if (property_type.create_default_ui_prop != nullptr) {
695  IDP_AddToGroup(prop_ui_group, property_type.create_default_ui_prop(socket, "default"));
696  }
697  if (property_type.rna_subtype_get != nullptr) {
698  const char *subtype_identifier = nullptr;
700  property_type.rna_subtype_get(socket),
701  &subtype_identifier);
702 
703  if (subtype_identifier != nullptr) {
704  IDPropertyTemplate idprop = {0};
705  idprop.string.str = subtype_identifier;
706  idprop.string.len = BLI_strnlen(subtype_identifier, MAX_NAME) + 1;
707  IDP_AddToGroup(prop_ui_group, IDP_New(IDP_STRING, &idprop, "subtype"));
708  }
709  }
710 
711  return prop;
712 }
713 
715 {
716  switch (bsocket.type) {
717  case SOCK_FLOAT: {
718  static const SocketPropertyType float_type = {
719  [](const bNodeSocket &socket, const char *name) {
721  IDPropertyTemplate idprop = {0};
722  idprop.f = value->value;
723  return IDP_New(IDP_FLOAT, &idprop, name);
724  },
725  [](const bNodeSocket &socket, const char *name) {
727  IDPropertyTemplate idprop = {0};
728  idprop.d = value->min;
729  return IDP_New(IDP_DOUBLE, &idprop, name);
730  },
731  [](const bNodeSocket &socket, const char *name) {
733  IDPropertyTemplate idprop = {0};
734  idprop.d = value->max;
735  return IDP_New(IDP_DOUBLE, &idprop, name);
736  },
737  [](const bNodeSocket &socket, const char *name) {
739  IDPropertyTemplate idprop = {0};
740  idprop.d = value->value;
741  return IDP_New(IDP_DOUBLE, &idprop, name);
742  },
743  [](const bNodeSocket &socket) {
744  return (PropertyType)((bNodeSocketValueFloat *)socket.default_value)->subtype;
745  },
746  [](const IDProperty &property) { return ELEM(property.type, IDP_FLOAT, IDP_DOUBLE); },
747  [](const IDProperty &property,
749  void *r_value) {
750  if (property.type == IDP_FLOAT) {
751  *(float *)r_value = IDP_Float(&property);
752  }
753  else if (property.type == IDP_DOUBLE) {
754  *(float *)r_value = (float)IDP_Double(&property);
755  }
756  },
757  };
758  return &float_type;
759  }
760  case SOCK_INT: {
761  static const SocketPropertyType int_type = {
762  [](const bNodeSocket &socket, const char *name) {
764  IDPropertyTemplate idprop = {0};
765  idprop.i = value->value;
766  return IDP_New(IDP_INT, &idprop, name);
767  },
768  [](const bNodeSocket &socket, const char *name) {
770  IDPropertyTemplate idprop = {0};
771  idprop.i = value->min;
772  return IDP_New(IDP_INT, &idprop, name);
773  },
774  [](const bNodeSocket &socket, const char *name) {
776  IDPropertyTemplate idprop = {0};
777  idprop.i = value->max;
778  return IDP_New(IDP_INT, &idprop, name);
779  },
780  [](const bNodeSocket &socket, const char *name) {
782  IDPropertyTemplate idprop = {0};
783  idprop.i = value->value;
784  return IDP_New(IDP_INT, &idprop, name);
785  },
786  [](const bNodeSocket &socket) {
787  return (PropertyType)((bNodeSocketValueInt *)socket.default_value)->subtype;
788  },
789  [](const IDProperty &property) { return property.type == IDP_INT; },
790  [](const IDProperty &property,
792  void *r_value) { *(int *)r_value = IDP_Int(&property); },
793  };
794  return &int_type;
795  }
796  case SOCK_VECTOR: {
797  static const SocketPropertyType vector_type = {
798  [](const bNodeSocket &socket, const char *name) {
800  IDPropertyTemplate idprop = {0};
801  idprop.array.len = 3;
802  idprop.array.type = IDP_FLOAT;
803  IDProperty *property = IDP_New(IDP_ARRAY, &idprop, name);
804  copy_v3_v3((float *)IDP_Array(property), value->value);
805  return property;
806  },
807  [](const bNodeSocket &socket, const char *name) {
809  IDPropertyTemplate idprop = {0};
810  idprop.d = value->min;
811  return IDP_New(IDP_DOUBLE, &idprop, name);
812  },
813  [](const bNodeSocket &socket, const char *name) {
815  IDPropertyTemplate idprop = {0};
816  idprop.d = value->max;
817  return IDP_New(IDP_DOUBLE, &idprop, name);
818  },
819  [](const bNodeSocket &socket, const char *name) {
821  IDPropertyTemplate idprop = {0};
822  idprop.array.len = 3;
823  idprop.array.type = IDP_FLOAT;
824  IDProperty *property = IDP_New(IDP_ARRAY, &idprop, name);
825  copy_v3_v3((float *)IDP_Array(property), value->value);
826  return property;
827  },
828  [](const bNodeSocket &socket) {
830  },
831  [](const IDProperty &property) {
832  return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT &&
833  property.len == 3;
834  },
835  [](const IDProperty &property,
837  void *r_value) { copy_v3_v3((float *)r_value, (const float *)IDP_Array(&property)); },
838  };
839  return &vector_type;
840  }
841  case SOCK_BOOLEAN: {
842  static const SocketPropertyType boolean_type = {
843  [](const bNodeSocket &socket, const char *name) {
845  IDPropertyTemplate idprop = {0};
846  idprop.i = value->value != 0;
847  return IDP_New(IDP_INT, &idprop, name);
848  },
849  [](const bNodeSocket &UNUSED(socket), const char *name) {
850  IDPropertyTemplate idprop = {0};
851  idprop.i = 0;
852  return IDP_New(IDP_INT, &idprop, name);
853  },
854  [](const bNodeSocket &UNUSED(socket), const char *name) {
855  IDPropertyTemplate idprop = {0};
856  idprop.i = 1;
857  return IDP_New(IDP_INT, &idprop, name);
858  },
859  [](const bNodeSocket &socket, const char *name) {
861  IDPropertyTemplate idprop = {0};
862  idprop.i = value->value != 0;
863  return IDP_New(IDP_INT, &idprop, name);
864  },
865  nullptr,
866  [](const IDProperty &property) { return property.type == IDP_INT; },
867  [](const IDProperty &property,
869  void *r_value) { *(bool *)r_value = IDP_Int(&property) != 0; },
870  };
871  return &boolean_type;
872  }
873  case SOCK_STRING: {
874  static const SocketPropertyType string_type = {
875  [](const bNodeSocket &socket, const char *name) {
877  return IDP_NewString(
878  value->value, name, BLI_strnlen(value->value, sizeof(value->value)) + 1);
879  },
880  nullptr,
881  nullptr,
882  [](const bNodeSocket &socket, const char *name) {
884  return IDP_NewString(
885  value->value, name, BLI_strnlen(value->value, sizeof(value->value)) + 1);
886  },
887  nullptr,
888  [](const IDProperty &property) { return property.type == IDP_STRING; },
889  [](const IDProperty &property,
891  void *r_value) { new (r_value) std::string(IDP_String(&property)); },
892  };
893  return &string_type;
894  }
895  case SOCK_OBJECT: {
896  static const SocketPropertyType object_type = {
897  [](const bNodeSocket &socket, const char *name) {
899  IDPropertyTemplate idprop = {0};
900  idprop.id = (ID *)value->value;
901  return IDP_New(IDP_ID, &idprop, name);
902  },
903  nullptr,
904  nullptr,
905  nullptr,
906  nullptr,
907  [](const IDProperty &property) { return property.type == IDP_ID; },
908  [](const IDProperty &property, const PersistentDataHandleMap &handles, void *r_value) {
909  ID *id = IDP_Id(&property);
910  Object *object = (id && GS(id->name) == ID_OB) ? (Object *)id : nullptr;
911  new (r_value) PersistentObjectHandle(handles.lookup(object));
912  },
913  };
914  return &object_type;
915  }
916  case SOCK_COLLECTION: {
917  static const SocketPropertyType collection_type = {
918  [](const bNodeSocket &socket, const char *name) {
920  IDPropertyTemplate idprop = {0};
921  idprop.id = (ID *)value->value;
922  return IDP_New(IDP_ID, &idprop, name);
923  },
924  nullptr,
925  nullptr,
926  nullptr,
927  nullptr,
928  [](const IDProperty &property) { return property.type == IDP_ID; },
929  [](const IDProperty &property, const PersistentDataHandleMap &handles, void *r_value) {
930  ID *id = IDP_Id(&property);
931  Collection *collection = (id && GS(id->name) == ID_GR) ? (Collection *)id : nullptr;
932  new (r_value) PersistentCollectionHandle(handles.lookup(collection));
933  },
934  };
935  return &collection_type;
936  }
937  default: {
938  return nullptr;
939  }
940  }
941 }
942 
949 {
950  if (nmd->node_group == nullptr) {
951  return;
952  }
953 
954  IDProperty *old_properties = nmd->settings.properties;
955 
956  {
957  IDPropertyTemplate idprop = {0};
958  nmd->settings.properties = IDP_New(IDP_GROUP, &idprop, "Nodes Modifier Settings");
959  }
960 
961  IDProperty *ui_container_group;
962  {
963  IDPropertyTemplate idprop = {0};
964  ui_container_group = IDP_New(IDP_GROUP, &idprop, "_RNA_UI");
965  IDP_AddToGroup(nmd->settings.properties, ui_container_group);
966  }
967 
968  LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
969  const SocketPropertyType *property_type = get_socket_property_type(*socket);
970  if (property_type == nullptr) {
971  continue;
972  }
973 
974  IDProperty *new_prop = socket_add_property(
975  nmd->settings.properties, ui_container_group, *property_type, *socket);
976 
977  if (old_properties != nullptr) {
978  IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket->identifier);
979  if (old_prop != nullptr && property_type->is_correct_type(*old_prop)) {
980  IDP_CopyPropertyContent(new_prop, old_prop);
981  }
982  }
983  }
984 
985  if (old_properties != nullptr) {
986  IDP_FreeProperty(old_properties);
987  }
988 
990 }
991 
993 {
994  bNodeTree *ntree = ntreeAddTree(bmain, "Geometry Nodes", ntreeType_Geometry->idname);
995  nmd->node_group = ntree;
996 
997  ntreeAddSocketInterface(ntree, SOCK_IN, "NodeSocketGeometry", "Geometry");
998  ntreeAddSocketInterface(ntree, SOCK_OUT, "NodeSocketGeometry", "Geometry");
999 
1000  bNode *group_input_node = nodeAddStaticNode(nullptr, ntree, NODE_GROUP_INPUT);
1001  bNode *group_output_node = nodeAddStaticNode(nullptr, ntree, NODE_GROUP_OUTPUT);
1002 
1003  nodeSetSelected(group_input_node, false);
1004  nodeSetSelected(group_output_node, false);
1005 
1006  group_input_node->locx = -200 - group_input_node->width;
1007  group_output_node->locx = 200;
1008  group_output_node->flag |= NODE_DO_OUTPUT;
1009 
1011  group_output_node,
1012  (bNodeSocket *)group_output_node->inputs.first,
1013  group_input_node,
1014  (bNodeSocket *)group_input_node->outputs.first);
1015 
1016  ntreeUpdateTree(bmain, ntree);
1017 }
1018 
1020  const PersistentDataHandleMap &handle_map,
1021  const bNodeSocket &socket,
1022  const CPPType &cpp_type,
1023  void *r_value)
1024 {
1025  const SocketPropertyType *property_type = get_socket_property_type(socket);
1026  if (property_type == nullptr) {
1027  cpp_type.copy_to_uninitialized(cpp_type.default_value(), r_value);
1028  return;
1029  }
1030  if (nmd.settings.properties == nullptr) {
1031  blender::nodes::socket_cpp_value_get(socket, r_value);
1032  return;
1033  }
1035  socket.identifier);
1036  if (property == nullptr) {
1037  blender::nodes::socket_cpp_value_get(socket, r_value);
1038  return;
1039  }
1040  if (!property_type->is_correct_type(*property)) {
1041  blender::nodes::socket_cpp_value_get(socket, r_value);
1042  return;
1043  }
1044  property_type->init_cpp_value(*property, handle_map, r_value);
1045 }
1046 
1047 static void fill_data_handle_map(const NodesModifierSettings &settings,
1048  const DerivedNodeTree &tree,
1049  PersistentDataHandleMap &handle_map)
1050 {
1051  Set<ID *> used_ids;
1052  find_used_ids_from_settings(settings, used_ids);
1053  find_used_ids_from_nodes(*tree.root_context().tree().btree(), used_ids);
1054 
1055  int current_handle = 0;
1056  for (ID *id : used_ids) {
1057  handle_map.add(current_handle, *id);
1058  current_handle++;
1059  }
1060 }
1061 
1063  const Object &object,
1064  const ModifierData &modifier)
1065 {
1066  const NodeTreeEvaluationContext context = {object, modifier};
1067 
1068  for (const blender::nodes::NodeTreeRef *tree : trees) {
1069  bNodeTree *btree_cow = tree->btree();
1070  bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
1072  }
1073 }
1074 
1076 {
1077  wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
1078  if (wm == nullptr) {
1079  return {};
1080  }
1081  Vector<SpaceSpreadsheet *> spreadsheets;
1082  LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
1083  bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
1084  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1085  SpaceLink *sl = (SpaceLink *)area->spacedata.first;
1086  if (sl->spacetype == SPACE_SPREADSHEET) {
1087  spreadsheets.append((SpaceSpreadsheet *)sl);
1088  }
1089  }
1090  }
1091  return spreadsheets;
1092 }
1093 
1095 
1097 {
1098  for (const SocketRef *socket : node->outputs()) {
1099  if (socket->bsocket()->type == SOCK_GEOMETRY) {
1100  return {node.context(), socket};
1101  }
1102  }
1103  for (const SocketRef *socket : node->inputs()) {
1104  if (socket->bsocket()->type == SOCK_GEOMETRY &&
1105  (socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) {
1106  return {node.context(), socket};
1107  }
1108  }
1109  return {};
1110 }
1111 
1113  NodesModifierData *nmd,
1114  const ModifierEvalContext *ctx,
1115  const DerivedNodeTree &tree)
1116 {
1117  Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
1118  if (context_path.size() < 3) {
1119  return {};
1120  }
1121  if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
1122  return {};
1123  }
1124  if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
1125  return {};
1126  }
1127  SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
1128  if (object_context->object != DEG_get_original_object(ctx->object)) {
1129  return {};
1130  }
1131  SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1];
1132  if (StringRef(modifier_context->modifier_name) != nmd->modifier.name) {
1133  return {};
1134  }
1135  for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
1136  if (context->type != SPREADSHEET_CONTEXT_NODE) {
1137  return {};
1138  }
1139  }
1140 
1141  Span<SpreadsheetContextNode *> nested_group_contexts =
1142  context_path.as_span().drop_front(2).drop_back(1).cast<SpreadsheetContextNode *>();
1143  SpreadsheetContextNode *last_context = (SpreadsheetContextNode *)context_path.last();
1144 
1145  const DTreeContext *context = &tree.root_context();
1146  for (SpreadsheetContextNode *node_context : nested_group_contexts) {
1147  const NodeTreeRef &tree_ref = context->tree();
1148  const NodeRef *found_node = nullptr;
1149  for (const NodeRef *node_ref : tree_ref.nodes()) {
1150  if (node_ref->name() == node_context->node_name) {
1151  found_node = node_ref;
1152  break;
1153  }
1154  }
1155  if (found_node == nullptr) {
1156  return {};
1157  }
1158  context = context->child_context(*found_node);
1159  if (context == nullptr) {
1160  return {};
1161  }
1162  }
1163 
1164  const NodeTreeRef &tree_ref = context->tree();
1165  for (const NodeRef *node_ref : tree_ref.nodes()) {
1166  if (node_ref->name() == last_context->node_name) {
1167  return try_find_preview_socket_in_node({context, node_ref});
1168  }
1169  }
1170  return {};
1171 }
1172 
1174  const ModifierEvalContext *ctx,
1175  const DerivedNodeTree &tree,
1176  PreviewSocketMap &r_sockets_to_preview)
1177 {
1178  Main *bmain = DEG_get_bmain(ctx->depsgraph);
1179 
1180  /* Based on every visible spreadsheet context path, get a list of sockets that need to have their
1181  * intermediate geometries cached for display. */
1183  for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
1184  const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree);
1185  if (socket) {
1186  const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
1187  r_sockets_to_preview.add_non_duplicates(socket, key);
1188  }
1189  }
1190 }
1191 
1192 static void log_preview_socket_value(const Span<GPointer> values,
1193  Object *object,
1194  Span<uint64_t> keys)
1195 {
1196  GeometrySet geometry_set = *(const GeometrySet *)values[0].get();
1197  geometry_set.ensure_owns_direct_data();
1198  for (uint64_t key : keys) {
1199  BKE_object_preview_geometry_set_add(object, key, new GeometrySet(geometry_set));
1200  }
1201 }
1202 
1203 static void log_ui_hints(const DSocket socket,
1204  const Span<GPointer> values,
1205  Object *self_object,
1206  NodesModifierData *nmd)
1207 {
1208  const DNode node = socket.node();
1209  if (node->is_reroute_node() || socket->typeinfo()->type != SOCK_GEOMETRY) {
1210  return;
1211  }
1212  bNodeTree *btree_cow = node->btree();
1213  bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
1214  const NodeTreeEvaluationContext context{*self_object, nmd->modifier};
1215  for (const GPointer &data : values) {
1216  if (data.type() == &CPPType::get<GeometrySet>()) {
1217  const GeometrySet &geometry_set = *(const GeometrySet *)data.get();
1219  geometry_set,
1220  [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
1221  BKE_nodetree_attribute_hint_add(*btree_original,
1222  context,
1223  *node->bnode(),
1224  attribute_name,
1225  meta_data.domain,
1226  meta_data.data_type);
1227  return true;
1228  },
1229  8);
1230  }
1231  }
1232 }
1233 
1240  Span<const NodeRef *> group_input_nodes,
1241  const InputSocketRef &socket_to_compute,
1242  GeometrySet input_geometry_set,
1243  NodesModifierData *nmd,
1244  const ModifierEvalContext *ctx)
1245 {
1246  blender::ResourceScope scope;
1247  blender::LinearAllocator<> &allocator = scope.linear_allocator();
1249 
1250  PersistentDataHandleMap handle_map;
1251  fill_data_handle_map(nmd->settings, tree, handle_map);
1252 
1254 
1255  const DTreeContext *root_context = &tree.root_context();
1256  for (const NodeRef *group_input_node : group_input_nodes) {
1257  Span<const OutputSocketRef *> group_input_sockets = group_input_node->outputs().drop_back(1);
1258  if (group_input_sockets.is_empty()) {
1259  continue;
1260  }
1261 
1262  Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets;
1263 
1264  /* If the group expects a geometry as first input, use the geometry that has been passed to
1265  * modifier. */
1266  const OutputSocketRef *first_input_socket = group_input_sockets[0];
1267  if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
1268  GeometrySet *geometry_set_in =
1269  allocator.construct<GeometrySet>(input_geometry_set).release();
1270  group_inputs.add_new({root_context, first_input_socket}, geometry_set_in);
1271  remaining_input_sockets = remaining_input_sockets.drop_front(1);
1272  }
1273 
1274  /* Initialize remaining group inputs. */
1275  for (const OutputSocketRef *socket : remaining_input_sockets) {
1276  const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
1277  void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
1278  initialize_group_input(*nmd, handle_map, *socket->bsocket(), cpp_type, value_in);
1279  group_inputs.add_new({root_context, socket}, {cpp_type, value_in});
1280  }
1281  }
1282 
1283  /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
1284  input_geometry_set.clear();
1285 
1286  Vector<DInputSocket> group_outputs;
1287  group_outputs.append({root_context, &socket_to_compute});
1288 
1289  PreviewSocketMap preview_sockets;
1290  find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
1291 
1292  auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) {
1293  if (!logging_enabled(ctx)) {
1294  return;
1295  }
1296  Span<uint64_t> keys = preview_sockets.lookup(socket);
1297  if (!keys.is_empty()) {
1298  log_preview_socket_value(values, ctx->object, keys);
1299  }
1300  log_ui_hints(socket, values, ctx->object, nmd);
1301  };
1302 
1303  GeometryNodesEvaluator evaluator{group_inputs,
1304  group_outputs,
1305  mf_by_node,
1306  handle_map,
1307  ctx->object,
1308  (ModifierData *)nmd,
1309  ctx->depsgraph,
1310  log_socket_value};
1311 
1312  Vector<GMutablePointer> results = evaluator.execute();
1313  BLI_assert(results.size() == 1);
1314  GMutablePointer result = results[0];
1315 
1316  GeometrySet output_geometry = std::move(*(GeometrySet *)result.get());
1317  return output_geometry;
1318 }
1319 
1325 {
1326  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1327 
1328  int i = 0;
1329  LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &nmd->node_group->inputs, i) {
1330  /* The first socket is the special geometry socket for the modifier object. */
1331  if (i == 0 && socket->type == SOCK_GEOMETRY) {
1332  continue;
1333  }
1334 
1336  if (property == nullptr) {
1337  if (socket->type == SOCK_GEOMETRY) {
1338  BKE_modifier_set_error(ob, md, "Node group can only have one geometry input");
1339  }
1340  else {
1341  BKE_modifier_set_error(ob, md, "Missing property for input socket \"%s\"", socket->name);
1342  }
1343  continue;
1344  }
1345 
1346  const SocketPropertyType *property_type = get_socket_property_type(*socket);
1347  if (!property_type->is_correct_type(*property)) {
1349  ob, md, "Property type does not match input socket \"(%s)\"", socket->name);
1350  continue;
1351  }
1352  }
1353 
1354  bool has_geometry_output = false;
1355  LISTBASE_FOREACH (const bNodeSocket *, socket, &nmd->node_group->outputs) {
1356  if (socket->type == SOCK_GEOMETRY) {
1357  has_geometry_output = true;
1358  }
1359  }
1360 
1361  if (!has_geometry_output) {
1362  BKE_modifier_set_error(ob, md, "Node group must have a geometry output");
1363  }
1364 }
1365 
1367  const ModifierEvalContext *ctx,
1368  GeometrySet &geometry_set)
1369 {
1370  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1371  if (nmd->node_group == nullptr) {
1372  return;
1373  }
1374 
1376 
1377  NodeTreeRefMap tree_refs;
1378  DerivedNodeTree tree{*nmd->node_group, tree_refs};
1379 
1380  if (tree.has_link_cycles()) {
1381  BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
1382  return;
1383  }
1384  if (tree.has_undefined_nodes_or_sockets()) {
1385  BKE_modifier_set_error(ctx->object, md, "Node group has undefined nodes or sockets");
1386  return;
1387  }
1388 
1389  const NodeTreeRef &root_tree_ref = tree.root_context().tree();
1390  Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput");
1391  Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput");
1392 
1393  if (output_nodes.size() != 1) {
1394  return;
1395  }
1396 
1397  Span<const InputSocketRef *> group_outputs = output_nodes[0]->inputs().drop_back(1);
1398 
1399  if (group_outputs.size() == 0) {
1400  return;
1401  }
1402 
1403  const InputSocketRef *group_output = group_outputs[0];
1404  if (group_output->idname() != "NodeSocketGeometry") {
1405  return;
1406  }
1407 
1408  if (logging_enabled(ctx)) {
1409  reset_tree_ui_storage(tree.used_node_tree_refs(), *ctx->object, *md);
1410  }
1411 
1412  geometry_set = compute_geometry(
1413  tree, input_nodes, *group_outputs[0], std::move(geometry_set), nmd, ctx);
1414 }
1415 
1417 {
1419  geometry_set.get_component_for_write<MeshComponent>().copy_vertex_group_names_from_object(
1420  *ctx->object);
1421  modifyGeometry(md, ctx, geometry_set);
1422 
1423  if (ctx->flag & MOD_APPLY_TO_BASE_MESH) {
1424  /* In this case it makes sense to realize instances, otherwise in some cases there might be no
1425  * results when applying the modifier. */
1426  geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier(geometry_set);
1427  }
1428 
1429  Mesh *new_mesh = geometry_set.get_component_for_write<MeshComponent>().release();
1430  if (new_mesh == nullptr) {
1431  return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
1432  }
1433  return new_mesh;
1434 }
1435 
1437  const ModifierEvalContext *ctx,
1438  GeometrySet *geometry_set)
1439 {
1440  modifyGeometry(md, ctx, *geometry_set);
1441 }
1442 
1443 /* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
1444  * the node socket identifier for the property names, since they are unique, but also having
1445  * the correct label displayed in the UI. */
1447  PointerRNA *bmain_ptr,
1448  PointerRNA *md_ptr,
1449  const IDProperty *modifier_props,
1450  const bNodeSocket &socket)
1451 {
1452  const SocketPropertyType *property_type = get_socket_property_type(socket);
1453  if (property_type == nullptr) {
1454  return;
1455  }
1456 
1457  /* The property should be created in #MOD_nodes_update_interface with the correct type. */
1458  IDProperty *property = IDP_GetPropertyFromGroup(modifier_props, socket.identifier);
1459 
1460  /* IDProperties can be removed with python, so there could be a situation where
1461  * there isn't a property for a socket or it doesn't have the correct type. */
1462  if (property != nullptr && property_type->is_correct_type(*property)) {
1463 
1464  char socket_id_esc[sizeof(socket.identifier) * 2];
1465  BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
1466 
1467  char rna_path[sizeof(socket_id_esc) + 4];
1468  BLI_snprintf(rna_path, ARRAY_SIZE(rna_path), "[\"%s\"]", socket_id_esc);
1469 
1470  /* Use #uiItemPointerR to draw pointer properties because #uiItemR would not have enough
1471  * information about what type of ID to select for editing the values. This is because
1472  * pointer IDProperties contain no information about their type. */
1473  switch (socket.type) {
1474  case SOCK_OBJECT: {
1476  layout, md_ptr, rna_path, bmain_ptr, "objects", socket.name, ICON_OBJECT_DATA);
1477  break;
1478  }
1479  case SOCK_COLLECTION: {
1480  uiItemPointerR(layout,
1481  md_ptr,
1482  rna_path,
1483  bmain_ptr,
1484  "collections",
1485  socket.name,
1486  ICON_OUTLINER_COLLECTION);
1487  break;
1488  }
1489  default:
1490  uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
1491  }
1492  }
1493 }
1494 
1495 static void panel_draw(const bContext *C, Panel *panel)
1496 {
1497  uiLayout *layout = panel->layout;
1498  Main *bmain = CTX_data_main(C);
1499 
1501  NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
1502 
1503  uiLayoutSetPropSep(layout, true);
1504  uiLayoutSetPropDecorate(layout, true);
1505 
1506  uiTemplateID(layout,
1507  C,
1508  ptr,
1509  "node_group",
1510  "node.new_geometry_node_group_assign",
1511  nullptr,
1512  nullptr,
1513  0,
1514  false,
1515  nullptr);
1516 
1517  if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
1518  PointerRNA bmain_ptr;
1519  RNA_main_pointer_create(bmain, &bmain_ptr);
1520 
1521  LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
1522  draw_property_for_socket(layout, &bmain_ptr, ptr, nmd->settings.properties, *socket);
1523  }
1524  }
1525 
1526  modifier_panel_end(layout, ptr);
1527 }
1528 
1529 static void panelRegister(ARegionType *region_type)
1530 {
1532 }
1533 
1534 static void blendWrite(BlendWriter *writer, const ModifierData *md)
1535 {
1536  const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
1537  if (nmd->settings.properties != nullptr) {
1538  /* Note that the property settings are based on the socket type info
1539  * and don't necessarily need to be written, but we can't just free them. */
1540  IDP_BlendWrite(writer, nmd->settings.properties);
1541  }
1542 }
1543 
1544 static void blendRead(BlendDataReader *reader, ModifierData *md)
1545 {
1546  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1547  BLO_read_data_address(reader, &nmd->settings.properties);
1548  IDP_BlendDataRead(reader, &nmd->settings.properties);
1549 }
1550 
1551 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
1552 {
1553  const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
1554  NodesModifierData *tnmd = reinterpret_cast<NodesModifierData *>(target);
1555 
1556  BKE_modifier_copydata_generic(md, target, flag);
1557 
1558  if (nmd->settings.properties != nullptr) {
1560  }
1561 }
1562 
1563 static void freeData(ModifierData *md)
1564 {
1565  NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1566  if (nmd->settings.properties != nullptr) {
1568  nmd->settings.properties = nullptr;
1569  }
1570 }
1571 
1572 static void requiredDataMask(Object *UNUSED(ob),
1573  ModifierData *UNUSED(md),
1574  CustomData_MeshMasks *r_cddata_masks)
1575 {
1576  /* We don't know what the node tree will need. If there are vertex groups, it is likely that the
1577  * node tree wants to access them. */
1578  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
1579  r_cddata_masks->vmask |= CD_MASK_PROP_ALL;
1580 }
1581 
1583  /* name */ "GeometryNodes",
1584  /* structName */ "NodesModifierData",
1585  /* structSize */ sizeof(NodesModifierData),
1586  /* srna */ &RNA_NodesModifier,
1587  /* type */ eModifierTypeType_Constructive,
1588  /* flags */
1589  static_cast<ModifierTypeFlag>(
1592  /* icon */ ICON_NODETREE,
1593 
1594  /* copyData */ copyData,
1595 
1596  /* deformVerts */ nullptr,
1597  /* deformMatrices */ nullptr,
1598  /* deformVertsEM */ nullptr,
1599  /* deformMatricesEM */ nullptr,
1600  /* modifyMesh */ modifyMesh,
1601  /* modifyHair */ nullptr,
1602  /* modifyGeometrySet */ modifyGeometrySet,
1603  /* modifyVolume */ nullptr,
1604 
1605  /* initData */ initData,
1606  /* requiredDataMask */ requiredDataMask,
1607  /* freeData */ freeData,
1608  /* isDisabled */ isDisabled,
1609  /* updateDepsgraph */ updateDepsgraph,
1610  /* dependsOnTime */ nullptr,
1611  /* dependsOnNormals */ nullptr,
1612  /* foreachIDLink */ foreachIDLink,
1613  /* foreachTexLink */ foreachTexLink,
1614  /* freeRuntimeData */ nullptr,
1615  /* panelRegister */ panelRegister,
1616  /* blendWrite */ blendWrite,
1617  /* blendRead */ blendRead,
1618 };
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
CustomData interface, see also DNA_customdata_types.h.
#define IDP_Float(prop)
Definition: BKE_idprop.h:179
#define IDP_Int(prop)
Definition: BKE_idprop.h:154
void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user)
Definition: idprop.c:1034
void IDP_BlendWrite(struct BlendWriter *writer, const struct IDProperty *prop)
#define IDP_Id(prop)
Definition: BKE_idprop.h:183
void IDP_CopyPropertyContent(struct IDProperty *dst, struct IDProperty *src) ATTR_NONNULL()
Definition: idprop.c:755
#define IDP_BlendDataRead(reader, prop)
Definition: BKE_idprop.h:208
struct IDProperty * IDP_NewString(const char *st, const char *name, int maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition: idprop.c:325
#define IDP_String(prop)
Definition: BKE_idprop.h:181
void IDP_foreach_property(struct IDProperty *id_property_root, const int type_filter, IDPForeachPropertyCallback callback, void *user_data)
Definition: idprop.c:1072
#define IDP_Double(prop)
Definition: BKE_idprop.h:180
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1040
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL()
Definition: idprop.c:643
struct IDProperty * IDP_GetPropertyFromGroup(const struct IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct IDProperty * IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:907
struct IDProperty * IDP_CopyProperty_ex(const struct IDProperty *prop, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define IDP_Array(prop)
Definition: BKE_idprop.h:155
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:87
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.c:877
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:120
ModifierTypeFlag
Definition: BKE_modifier.h:79
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:82
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:92
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:83
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:80
void(* TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname)
Definition: BKE_modifier.h:121
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, const int flag)
@ eModifierTypeType_Constructive
Definition: BKE_modifier.h:61
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
@ MOD_APPLY_TO_BASE_MESH
Definition: BKE_modifier.h:141
@ MOD_APPLY_ORCO
Definition: BKE_modifier.h:133
#define NODE_CUSTOM_GROUP
Definition: BKE_node.h:876
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree)
Definition: node.cc:4262
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2189
void nodeSetSelected(struct bNode *node, bool select)
Definition: node.cc:3664
struct bNodeTree * ntreeAddTree(struct Main *bmain, const char *name, const char *idname)
Definition: node.cc:2529
struct bNodeSocket * ntreeAddSocketInterface(struct bNodeTree *ntree, eNodeSocketInOut in_out, const char *idname, const char *name)
Definition: node.cc:3302
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2004
#define NODE_GROUP_INPUT
Definition: BKE_node.h:874
void BKE_nodetree_ui_storage_free_for_context(bNodeTree &ntree, const NodeTreeEvaluationContext &context)
void BKE_nodetree_attribute_hint_add(bNodeTree &ntree, const NodeTreeEvaluationContext &context, const bNode &node, const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type)
General operations, lookup, etc. for blender objects.
void BKE_object_preview_geometry_set_add(struct Object *ob, const uint64_t key, struct GeometrySet *geometry_set)
Definition: object.c:1819
General operations for point-clouds.
struct bScreen * BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:180
MINLINE void copy_v3_v3(float r[3], const float a[3])
size_t size_t char size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy) ATTR_NONNULL()
Definition: string.c:333
size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:878
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#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)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
bool DEG_is_active(const struct Depsgraph *depsgraph)
Definition: depsgraph.cc:331
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle, struct bNodeTree *node_tree, const char *description)
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_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
bool DEG_object_has_geometry_component(struct Object *object)
struct Object * DEG_get_original_object(struct Object *object)
struct ID * DEG_get_original_id(struct ID *id)
struct Main * DEG_get_bmain(const Depsgraph *graph)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
@ IDP_DOUBLE
Definition: DNA_ID.h:103
@ IDP_FLOAT
Definition: DNA_ID.h:99
@ IDP_STRING
Definition: DNA_ID.h:97
@ IDP_INT
Definition: DNA_ID.h:98
@ IDP_GROUP
Definition: DNA_ID.h:101
@ IDP_ARRAY
Definition: DNA_ID.h:100
@ IDP_ID
Definition: DNA_ID.h:102
@ IDP_TYPE_FILTER_ID
Definition: DNA_ID.h:115
@ IDP_STRING_SUB_UTF8
Definition: DNA_ID.h:124
@ IDP_FLAG_OVERRIDABLE_LIBRARY
Definition: DNA_ID.h:132
@ ID_GR
Definition: DNA_ID_enums.h:77
@ ID_OB
Definition: DNA_ID_enums.h:59
Object groups, one object can be in many groups at once.
#define CD_MASK_MDEFORMVERT
#define CD_MASK_PROP_ALL
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
#define MAX_NAME
Definition: DNA_defs.h:62
struct NodesModifierData NodesModifierData
@ eModifierType_Nodes
#define NODE_DO_OUTPUT
@ SOCK_OUT
@ SOCK_IN
@ SOCK_MULTI_INPUT
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_FLOAT
@ SOCK_COLLECTION
@ SOCK_GEOMETRY
@ SOCK_OBJECT
@ SOCK_STRING
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ SPREADSHEET_CONTEXT_OBJECT
@ SPREADSHEET_CONTEXT_MODIFIER
@ SPREADSHEET_CONTEXT_NODE
@ SPACE_SPREADSHEET
uint64_t ED_spreadsheet_context_path_hash(struct SpaceSpreadsheet *sspreadsheet)
static void output_geometry(void *data, struct wl_output *, int32_t, int32_t, int32_t, int32_t, int32_t, const char *make, const char *model, int32_t transform)
_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 void copyData(const ModifierData *md, ModifierData *target, const int flag)
Definition: MOD_nodes.cc:1551
static Vector< SpaceSpreadsheet * > find_spreadsheet_editors(Main *bmain)
Definition: MOD_nodes.cc:1075
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition: MOD_nodes.cc:1416
static IDProperty * socket_add_property(IDProperty *settings_prop_group, IDProperty *ui_container, const SocketPropertyType &property_type, const bNodeSocket &socket)
Definition: MOD_nodes.cc:657
static GeometrySet compute_geometry(const DerivedNodeTree &tree, Span< const NodeRef * > group_input_nodes, const InputSocketRef &socket_to_compute, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx)
Definition: MOD_nodes.cc:1239
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition: MOD_nodes.cc:195
static void initialize_group_input(NodesModifierData &nmd, const PersistentDataHandleMap &handle_map, const bNodeSocket &socket, const CPPType &cpp_type, void *r_value)
Definition: MOD_nodes.cc:1019
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
Definition: MOD_nodes.cc:948
static void find_sockets_to_preview(NodesModifierData *nmd, const ModifierEvalContext *ctx, const DerivedNodeTree &tree, PreviewSocketMap &r_sockets_to_preview)
Definition: MOD_nodes.cc:1173
static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
Definition: MOD_nodes.cc:247
static void log_ui_hints(const DSocket socket, const Span< GPointer > values, Object *self_object, NodesModifierData *nmd)
Definition: MOD_nodes.cc:1203
void MOD_nodes_init(Main *bmain, NodesModifierData *nmd)
Definition: MOD_nodes.cc:992
static void blendWrite(BlendWriter *writer, const ModifierData *md)
Definition: MOD_nodes.cc:1534
static void check_property_socket_sync(const Object *ob, ModifierData *md)
Definition: MOD_nodes.cc:1324
static void add_collection_relation(const ModifierUpdateDepsgraphContext *ctx, Collection &collection)
Definition: MOD_nodes.cc:174
static void blendRead(BlendDataReader *reader, ModifierData *md)
Definition: MOD_nodes.cc:1544
static void fill_data_handle_map(const NodesModifierSettings &settings, const DerivedNodeTree &tree, PersistentDataHandleMap &handle_map)
Definition: MOD_nodes.cc:1047
static void requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md), CustomData_MeshMasks *r_cddata_masks)
Definition: MOD_nodes.cc:1572
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
Definition: MOD_nodes.cc:220
static DSocket try_find_preview_socket_in_node(const DNode node)
Definition: MOD_nodes.cc:1096
static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Object &object)
Definition: MOD_nodes.cc:181
static void modifyGeometry(ModifierData *md, const ModifierEvalContext *ctx, GeometrySet &geometry_set)
Definition: MOD_nodes.cc:1366
static void find_used_ids_from_nodes(const bNodeTree &tree, Set< ID * > &ids)
Definition: MOD_nodes.cc:135
static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet, NodesModifierData *nmd, const ModifierEvalContext *ctx, const DerivedNodeTree &tree)
Definition: MOD_nodes.cc:1112
static void reset_tree_ui_storage(Span< const blender::nodes::NodeTreeRef * > trees, const Object &object, const ModifierData &modifier)
Definition: MOD_nodes.cc:1062
static void modifyGeometrySet(ModifierData *md, const ModifierEvalContext *ctx, GeometrySet *geometry_set)
Definition: MOD_nodes.cc:1436
static bool logging_enabled(const ModifierEvalContext *ctx)
Definition: MOD_nodes.cc:260
static void initData(ModifierData *md)
Definition: MOD_nodes.cc:108
static void draw_property_for_socket(uiLayout *layout, PointerRNA *bmain_ptr, PointerRNA *md_ptr, const IDProperty *modifier_props, const bNodeSocket &socket)
Definition: MOD_nodes.cc:1446
static void panelRegister(ARegionType *region_type)
Definition: MOD_nodes.cc:1529
static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
Definition: MOD_nodes.cc:242
static void log_preview_socket_value(const Span< GPointer > values, Object *object, Span< uint64_t > keys)
Definition: MOD_nodes.cc:1192
static void find_used_ids_from_settings(const NodesModifierSettings &settings, Set< ID * > &ids)
Definition: MOD_nodes.cc:152
ModifierTypeInfo modifierType_Nodes
Definition: MOD_nodes.cc:1582
static void addIdsUsedBySocket(const ListBase *sockets, Set< ID * > &ids)
Definition: MOD_nodes.cc:117
static const CustomData_MeshMasks dependency_data_mask
Definition: MOD_nodes.cc:168
static void freeData(ModifierData *md)
Definition: MOD_nodes.cc:1563
static const SocketPropertyType * get_socket_property_type(const bNodeSocket &bsocket)
Definition: MOD_nodes.cc:714
static void panel_draw(const bContext *C, Panel *panel)
Definition: MOD_nodes.cc:1495
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
NODE_GROUP_OUTPUT
NODE_GROUP
StructRNA RNA_NodesModifier
PropertyType
Definition: RNA_types.h:72
#define C
Definition: RandGen.cpp:39
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, const bool live_icon, const char *text)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
GeometryNodesEvaluator(const Map< DOutputSocket, GMutablePointer > &group_input_data, Vector< DInputSocket > group_outputs, blender::nodes::MultiFunctionByNode &mf_by_node, const PersistentDataHandleMap &handle_map, const Object *self_object, const ModifierData *modifier, Depsgraph *depsgraph, LogSocketValueFn log_socket_value_fn)
Definition: MOD_nodes.cc:288
Vector< GMutablePointer > execute()
Definition: MOD_nodes.cc:311
std::function< void(DSocket, Span< GPointer >)> LogSocketValueFn
Definition: MOD_nodes.cc:273
StringRefNull copy_string(StringRef str)
void * allocate(const int64_t size, const int64_t alignment)
destruct_ptr< T > construct(Args &&... args)
Value pop(const Key &key)
Definition: BLI_map.hh:371
Value lookup_default(const Key &key, const Value &default_value) const
Definition: BLI_map.hh:524
ValueIterator values() const
Definition: BLI_map.hh:806
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:234
ItemIterator items() const
Definition: BLI_map.hh:825
std::optional< Value > pop_try(const Key &key)
Definition: BLI_map.hh:388
Span< Value > lookup(const Key &key) const
void add_non_duplicates(const Key &key, const Value &value)
LinearAllocator & linear_allocator()
bool add(const Key &key)
Definition: BLI_set.hh:267
constexpr Span drop_front(int64_t n) const
Definition: BLI_span.hh:173
constexpr int64_t first_index_try(const T &search_value) const
Definition: BLI_span.hh:400
constexpr Span drop_back(int64_t n) const
Definition: BLI_span.hh:184
constexpr int64_t size() const
Definition: BLI_span.hh:254
constexpr Span< NewT > cast() const
Definition: BLI_span.hh:422
constexpr IndexRange index_range() const
Definition: BLI_span.hh:414
constexpr Span take_front(int64_t n) const
Definition: BLI_span.hh:195
constexpr bool is_empty() const
Definition: BLI_span.hh:262
int64_t size() const
Definition: BLI_vector.hh:662
void append(const T &value)
Definition: BLI_vector.hh:438
Span< T > as_span() const
Definition: BLI_vector.hh:340
bool is_empty() const
Definition: BLI_vector.hh:674
void append_non_duplicates(const T &value)
Definition: BLI_vector.hh:465
const T & last() const
Definition: BLI_vector.hh:648
int64_t size() const
Definition: FN_cpp_type.hh:280
int64_t alignment() const
Definition: FN_cpp_type.hh:291
void copy_to_uninitialized(const void *src, void *dst) const
Definition: FN_cpp_type.hh:425
const void * default_value() const
Definition: FN_cpp_type.hh:657
const CPPType * type() const
virtual void call(IndexMask mask, MFParams params, MFContext context) const =0
void foreach_origin_socket(FunctionRef< void(DSocket)> origin_fn) const
void foreach_target_socket(FunctionRef< void(DInputSocket)> target_fn, FunctionRef< void(DSocket)> skipped_fn) const
const DTreeContext * context() const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
void convert_to_uninitialized(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value) const
Span< const NodeRef * > nodes() const
Span< const NodeRef * > nodes_by_type(StringRefNull idname) const
const NodeRef & node() const
bNodeSocketType * typeinfo() const
StringRefNull idname() const
bNodeSocket * bsocket() const
StringRefNull identifier() const
OperationNode * node
Scene scene
const Depsgraph * depsgraph
void * user_data
void * tree
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define GS(x)
Definition: iris.c:241
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set)
void geometry_set_instances_attribute_foreach(const GeometrySet &geometry_set, const AttributeForeachCallback callback, const int limit)
static void area(int d1, int d2, int e1, int e2, float weights[2])
Map< bNodeTree *, std::unique_ptr< const NodeTreeRef > > NodeTreeRefMap
MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceScope &scope)
const DataTypeConversions & get_implicit_type_conversions()
const CPPType * socket_cpp_type_get(const bNodeSocketType &stype)
bool socket_cpp_value_get(const bNodeSocket &socket, void *r_value)
std::string to_string(const T &n)
bNodeTreeType * ntreeType_Geometry
bool RNA_enum_identifier(const EnumPropertyItem *item, const int value, const char **r_identifier)
Definition: rna_access.c:1830
void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr)
Definition: rna_access.c:115
const EnumPropertyItem rna_enum_property_subtype_items[]
Definition: rna_rna.c:68
struct SELECTID_Context context
Definition: select_engine.c:47
static int node_context(const bContext *C, const char *member, bContextDataResult *result)
Definition: space_node.c:872
unsigned __int64 uint64_t
Definition: stdint.h:93
CustomDataType data_type
AttributeDomain domain
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
void ensure_owns_direct_data()
static GeometrySet create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
short flag
Definition: DNA_ID.h:72
char subtype
Definition: DNA_ID.h:71
char type
Definition: DNA_ID.h:71
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase wm
Definition: BKE_main.h:175
struct Depsgraph * depsgraph
Definition: BKE_modifier.h:153
ModifierApplyFlag flag
Definition: BKE_modifier.h:155
struct Object * object
Definition: BKE_modifier.h:154
struct DepsNodeHandle * node
Definition: BKE_modifier.h:147
struct bNodeTree * node_group
struct NodesModifierSettings settings
struct IDProperty * properties
struct uiLayout * layout
void * data
Definition: RNA_types.h:52
IDProperty *(* create_prop)(const bNodeSocket &socket, const char *name)
Definition: MOD_nodes.cc:642
PropertyType(* rna_subtype_get)(const bNodeSocket &socket)
Definition: MOD_nodes.cc:650
IDProperty *(* create_default_ui_prop)(const bNodeSocket &socket, const char *name)
Definition: MOD_nodes.cc:649
IDProperty *(* create_min_ui_prop)(const bNodeSocket &socket, const char *name)
Definition: MOD_nodes.cc:644
IDProperty *(* create_max_ui_prop)(const bNodeSocket &socket, const char *name)
Definition: MOD_nodes.cc:646
void(* init_cpp_value)(const IDProperty &property, const PersistentDataHandleMap &handles, void *r_value)
Definition: MOD_nodes.cc:652
bool(* is_correct_type)(const IDProperty &property)
Definition: MOD_nodes.cc:651
char name[64]
char description[64]
void * default_value
struct bNodeSocketType * typeinfo
char identifier[64]
char idname[64]
Definition: BKE_node.h:381
ListBase inputs
ListBase outputs
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327
float width
ListBase inputs
struct bNodeType * typeinfo
float locx
ListBase outputs
ListBase areabase
const char * str
Definition: BKE_idprop.h:41
struct IDPropertyTemplate::@28 array
struct ID * id
Definition: BKE_idprop.h:45
struct IDPropertyTemplate::@27 string
ParamHandle ** handles
PointerRNA * ptr
Definition: wm_files.c:3157