Blender V4.3
MOD_nodes.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstring>
10#include <fmt/format.h>
11#include <iostream>
12#include <sstream>
13#include <string>
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_array.hh"
18#include "BLI_listbase.h"
21#include "BLI_path_utils.hh"
22#include "BLI_set.hh"
23#include "BLI_string.h"
24#include "BLI_utildefines.h"
25
26#include "DNA_array_utils.hh"
28#include "DNA_curves_types.h"
29#include "DNA_defaults.h"
30#include "DNA_material_types.h"
31#include "DNA_mesh_types.h"
32#include "DNA_meshdata_types.h"
33#include "DNA_modifier_types.h"
34#include "DNA_node_types.h"
35#include "DNA_object_types.h"
37#include "DNA_scene_types.h"
38#include "DNA_screen_types.h"
39#include "DNA_space_types.h"
40#include "DNA_view3d_types.h"
42
43#include "BKE_attribute_math.hh"
47#include "BKE_customdata.hh"
50#include "BKE_global.hh"
51#include "BKE_idprop.hh"
52#include "BKE_lib_id.hh"
53#include "BKE_lib_query.hh"
54#include "BKE_main.hh"
55#include "BKE_mesh.hh"
56#include "BKE_modifier.hh"
57#include "BKE_node_runtime.hh"
59#include "BKE_object.hh"
60#include "BKE_packedFile.hh"
61#include "BKE_pointcloud.hh"
62#include "BKE_screen.hh"
63#include "BKE_workspace.hh"
64
65#include "BLO_read_write.hh"
66
67#include "UI_interface.hh"
68#include "UI_resources.hh"
69
70#include "BLT_translation.hh"
71
72#include "WM_api.hh"
73#include "WM_types.hh"
74
75#include "RNA_access.hh"
76#include "RNA_enum_types.hh"
77#include "RNA_prototypes.hh"
78
82
83#include "MOD_modifiertypes.hh"
84#include "MOD_nodes.hh"
85#include "MOD_ui_common.hh"
86
87#include "ED_object.hh"
88#include "ED_screen.hh"
89#include "ED_spreadsheet.hh"
90#include "ED_undo.hh"
91#include "ED_viewer_path.hh"
92
93#include "NOD_geometry.hh"
98
99#include "FN_field.hh"
102#include "FN_multi_function.hh"
103
104namespace lf = blender::fn::lazy_function;
106namespace bake = blender::bke::bake;
107
108namespace blender {
109
110static void init_data(ModifierData *md)
111{
113
116
118 nmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
119 nmd->runtime->cache = std::make_shared<bake::ModifierCache>();
120}
121
123{
124 IDP_foreach_property(settings.properties, IDP_TYPE_FILTER_ID, [&](IDProperty *property) {
125 if (ID *id = IDP_Id(property)) {
126 ids.add(id);
127 }
128 });
129}
130
131/* We don't know exactly what attributes from the other object we will need. */
137
139 Collection &collection)
140{
141 DEG_add_collection_geometry_relation(ctx->node, &collection, "Nodes Modifier");
143}
144
146{
147 DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
148 if (&(ID &)object != &ctx->object->id) {
149 if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
150 add_collection_relation(ctx, *object.instance_collection);
151 }
152 else if (DEG_object_has_geometry_component(&object)) {
153 DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
155 }
156 }
157}
158
160{
161 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
162 if (nmd->node_group == nullptr) {
163 return;
164 }
165
166 DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
167
168 bool needs_own_transform_relation = false;
169 bool needs_scene_camera_relation = false;
170 Set<ID *> used_ids;
172 nodes::find_node_tree_dependencies(
173 *nmd->node_group, used_ids, needs_own_transform_relation, needs_scene_camera_relation);
174
175 if (ctx->object->type == OB_CURVES) {
176 Curves *curves_id = static_cast<Curves *>(ctx->object->data);
177 if (curves_id->surface != nullptr) {
178 used_ids.add(&curves_id->surface->id);
179 }
180 }
181
182 for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
183 for (const NodesModifierDataBlock &data_block : Span(bake.data_blocks, bake.data_blocks_num)) {
184 if (data_block.id) {
185 used_ids.add(data_block.id);
186 }
187 }
188 }
189
190 for (ID *id : used_ids) {
191 switch ((ID_Type)GS(id->name)) {
192 case ID_OB: {
193 Object *object = reinterpret_cast<Object *>(id);
194 add_object_relation(ctx, *object);
195 break;
196 }
197 case ID_GR: {
198 Collection *collection = reinterpret_cast<Collection *>(id);
199 add_collection_relation(ctx, *collection);
200 break;
201 }
202 case ID_IM:
203 case ID_TE: {
204 DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier");
205 break;
206 }
207 default: {
208 /* Purposefully don't add relations for materials. While there are material sockets,
209 * the pointers are only passed around as handles rather than dereferenced. */
210 break;
211 }
212 }
213 }
214
215 if (needs_own_transform_relation) {
216 DEG_add_depends_on_transform_relation(ctx->node, "Nodes Modifier");
217 }
218 if (needs_scene_camera_relation) {
219 DEG_add_scene_camera_relation(ctx->node, ctx->scene, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
220 /* Active camera is a scene parameter that can change, so we need a relation for that, too. */
221 DEG_add_scene_relation(ctx->node, ctx->scene, DEG_SCENE_COMP_PARAMETERS, "Nodes Modifier");
222 }
223}
224
226{
227 if (!checked_groups.add(&tree)) {
228 return false;
229 }
230 tree.ensure_topology_cache();
231 if (!tree.nodes_by_type("GeometryNodeInputSceneTime").is_empty()) {
232 return true;
233 }
234 if (!tree.nodes_by_type("GeometryNodeSimulationInput").is_empty()) {
235 return true;
236 }
237 for (const bNode *node : tree.group_nodes()) {
238 if (const bNodeTree *sub_tree = reinterpret_cast<const bNodeTree *>(node->id)) {
239 if (check_tree_for_time_node(*sub_tree, checked_groups)) {
240 return true;
241 }
242 }
243 }
244 return false;
245}
246
247static bool depends_on_time(Scene * /*scene*/, ModifierData *md)
248{
249 const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
250 const bNodeTree *tree = nmd->node_group;
251 if (tree == nullptr) {
252 return false;
253 }
254 for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
255 if (bake.bake_mode == NODES_MODIFIER_BAKE_MODE_ANIMATION) {
256 return true;
257 }
258 }
259 Set<const bNodeTree *> checked_groups;
260 return check_tree_for_time_node(*tree, checked_groups);
261}
262
263static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
264{
265 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
266 walk(user_data, ob, (ID **)&nmd->node_group, IDWALK_CB_USER);
267
269 walk(user_data, ob, (ID **)&id_prop->data.pointer, IDWALK_CB_USER);
270 });
271
272 for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
273 for (NodesModifierDataBlock &data_block : MutableSpan(bake.data_blocks, bake.data_blocks_num))
274 {
275 walk(user_data, ob, &data_block.id, IDWALK_CB_USER);
276 }
277 }
278}
279
280static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
281{
282 PointerRNA ptr = RNA_pointer_create(&ob->id, &RNA_Modifier, md);
283 PropertyRNA *prop = RNA_struct_find_property(&ptr, "texture");
284 walk(user_data, ob, md, &ptr, prop);
285}
286
287static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
288{
289 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
290
291 if (nmd->node_group == nullptr) {
292 return true;
293 }
294
295 return false;
296}
297
299{
300 if (!DEG_is_active(ctx->depsgraph)) {
301 return false;
302 }
303 if ((ctx->flag & MOD_APPLY_ORCO) != 0) {
304 return false;
305 }
306 return true;
307}
308
310{
311 if (nmd->node_group == nullptr) {
312 if (nmd->settings.properties) {
314 nmd->settings.properties = nullptr;
315 }
316 return;
317 }
318
319 IDProperty *old_properties = nmd->settings.properties;
320 nmd->settings.properties = bke::idprop::create_group("Nodes Modifier Settings").release();
321 IDProperty *new_properties = nmd->settings.properties;
322
323 nodes::update_input_properties_from_node_tree(*nmd->node_group, old_properties, *new_properties);
324 nodes::update_output_properties_from_node_tree(
325 *nmd->node_group, old_properties, *new_properties);
326
327 if (old_properties != nullptr) {
328 IDP_FreeProperty(old_properties);
329 }
330}
331
333{
334 if (!nmd.runtime->cache) {
335 if (nmd.bakes_num == 0) {
336 return;
337 }
338 nmd.runtime->cache = std::make_shared<bake::ModifierCache>();
339 }
340 bake::ModifierCache &modifier_cache = *nmd.runtime->cache;
341 std::lock_guard lock{modifier_cache.mutex};
342
343 Set<int> existing_bake_ids;
344 for (const NodesModifierBake &bake : Span{nmd.bakes, nmd.bakes_num}) {
345 existing_bake_ids.add(bake.id);
346 }
347
348 auto remove_predicate = [&](auto item) { return !existing_bake_ids.contains(item.key); };
349
350 modifier_cache.bake_cache_by_id.remove_if(remove_predicate);
351 modifier_cache.simulation_cache_by_id.remove_if(remove_predicate);
352}
353
355{
356 Map<int, NodesModifierBake *> old_bake_by_id;
358 old_bake_by_id.add(bake.id, &bake);
359 }
360
361 Vector<int> new_bake_ids;
362 if (nmd.node_group) {
363 for (const bNestedNodeRef &ref : nmd.node_group->nested_node_refs_span()) {
364 const bNode *node = nmd.node_group->find_nested_node(ref.id);
365 if (node) {
366 if (ELEM(node->type, GEO_NODE_SIMULATION_OUTPUT, GEO_NODE_BAKE)) {
367 new_bake_ids.append(ref.id);
368 }
369 }
370 else if (old_bake_by_id.contains(ref.id)) {
371 /* Keep baked data in case linked data is missing so that it still exists when the linked
372 * data has been found. */
373 new_bake_ids.append(ref.id);
374 }
375 }
376 }
377
378 NodesModifierBake *new_bake_data = MEM_cnew_array<NodesModifierBake>(new_bake_ids.size(),
379 __func__);
380 for (const int i : new_bake_ids.index_range()) {
381 const int id = new_bake_ids[i];
382 NodesModifierBake *old_bake = old_bake_by_id.lookup_default(id, nullptr);
383 NodesModifierBake &new_bake = new_bake_data[i];
384 if (old_bake) {
385 new_bake = *old_bake;
386 /* The ownership of the string was moved to `new_bake`. */
387 old_bake->directory = nullptr;
388 }
389 else {
390 new_bake.id = id;
391 new_bake.frame_start = 1;
392 new_bake.frame_end = 100;
394 }
395 }
396
397 for (NodesModifierBake &old_bake : MutableSpan(nmd.bakes, nmd.bakes_num)) {
398 MEM_SAFE_FREE(old_bake.directory);
399 }
400 MEM_SAFE_FREE(nmd.bakes);
401
402 nmd.bakes = new_bake_data;
403 nmd.bakes_num = new_bake_ids.size();
404
406}
407
409{
410 Map<int, NodesModifierPanel *> old_panel_by_id;
411 for (NodesModifierPanel &panel : MutableSpan(nmd.panels, nmd.panels_num)) {
412 old_panel_by_id.add(panel.id, &panel);
413 }
414
416 if (nmd.node_group) {
417 nmd.node_group->ensure_interface_cache();
418 nmd.node_group->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
419 if (item.item_type != NODE_INTERFACE_PANEL) {
420 return true;
421 }
422 interface_panels.append(reinterpret_cast<const bNodeTreeInterfacePanel *>(&item));
423 return true;
424 });
425 }
426
427 NodesModifierPanel *new_panels = MEM_cnew_array<NodesModifierPanel>(interface_panels.size(),
428 __func__);
429
430 for (const int i : interface_panels.index_range()) {
431 const bNodeTreeInterfacePanel &interface_panel = *interface_panels[i];
432 const int id = interface_panel.identifier;
433 NodesModifierPanel *old_panel = old_panel_by_id.lookup_default(id, nullptr);
434 NodesModifierPanel &new_panel = new_panels[i];
435 if (old_panel) {
436 new_panel = *old_panel;
437 }
438 else {
439 new_panel.id = id;
440 const bool default_closed = interface_panel.flag & NODE_INTERFACE_PANEL_DEFAULT_CLOSED;
441 SET_FLAG_FROM_TEST(new_panel.flag, !default_closed, NODES_MODIFIER_PANEL_OPEN);
442 }
443 }
444
446
447 nmd.panels = new_panels;
448 nmd.panels_num = interface_panels.size();
449}
450
451} // namespace blender
452
454{
455 using namespace blender;
456 update_id_properties_from_node_group(nmd);
457 update_bakes_from_node_group(*nmd);
458 update_panels_from_node_group(*nmd);
459
461}
462
463NodesModifierBake *NodesModifierData::find_bake(const int id)
464{
465 return const_cast<NodesModifierBake *>(std::as_const(*this).find_bake(id));
466}
467
468const NodesModifierBake *NodesModifierData::find_bake(const int id) const
469{
470 for (const NodesModifierBake &bake : blender::Span{this->bakes, this->bakes_num}) {
471 if (bake.id == id) {
472 return &bake;
473 }
474 }
475 return nullptr;
476}
477
478namespace blender {
479
485static void try_add_side_effect_node(const ComputeContext &final_compute_context,
486 const int final_node_id,
487 const NodesModifierData &nmd,
488 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
489{
490 if (nmd.node_group == nullptr) {
491 return;
492 }
493
494 Vector<const ComputeContext *> compute_context_vec;
495 for (const ComputeContext *c = &final_compute_context; c; c = c->parent()) {
496 compute_context_vec.append(c);
497 }
498 std::reverse(compute_context_vec.begin(), compute_context_vec.end());
499
500 const auto *modifier_compute_context = dynamic_cast<const bke::ModifierComputeContext *>(
501 compute_context_vec[0]);
502 if (modifier_compute_context == nullptr) {
503 return;
504 }
505 if (modifier_compute_context->modifier_name() != nmd.modifier.name) {
506 return;
507 }
508
509 const bNodeTree *current_tree = nmd.node_group;
510 const bke::bNodeTreeZone *current_zone = nullptr;
511
512 /* Write side effect nodes to a new map and only if everything succeeds, move the nodes to the
513 * caller. This is easier than changing r_side_effect_nodes directly and then undoing changes in
514 * case of errors. */
515 nodes::GeoNodesSideEffectNodes local_side_effect_nodes;
516 for (const ComputeContext *compute_context_generic : compute_context_vec.as_span().drop_front(1))
517 {
518 const bke::bNodeTreeZones *current_zones = current_tree->zones();
519 if (current_zones == nullptr) {
520 return;
521 }
522 const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*current_tree);
523 if (lf_graph_info == nullptr) {
524 return;
525 }
526 const ComputeContextHash &parent_compute_context_hash =
527 compute_context_generic->parent()->hash();
528 if (const auto *compute_context = dynamic_cast<const bke::SimulationZoneComputeContext *>(
529 compute_context_generic))
530 {
531 const bke::bNodeTreeZone *simulation_zone = current_zones->get_zone_by_node(
532 compute_context->output_node_id());
533 if (simulation_zone == nullptr) {
534 return;
535 }
536 if (simulation_zone->parent_zone != current_zone) {
537 return;
538 }
539 const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
540 simulation_zone, nullptr);
541 if (lf_zone_node == nullptr) {
542 return;
543 }
544 const lf::FunctionNode *lf_simulation_output_node =
545 lf_graph_info->mapping.possible_side_effect_node_map.lookup_default(
546 simulation_zone->output_node, nullptr);
547 if (lf_simulation_output_node == nullptr) {
548 return;
549 }
550 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_zone_node);
551 /* By making the simulation output node a side-effect-node, we can ensure that the simulation
552 * runs when it contains an active viewer. */
553 local_side_effect_nodes.nodes_by_context.add(compute_context_generic->hash(),
554 lf_simulation_output_node);
555
556 current_zone = simulation_zone;
557 }
558 else if (const auto *compute_context = dynamic_cast<const bke::RepeatZoneComputeContext *>(
559 compute_context_generic))
560 {
561 const bke::bNodeTreeZone *repeat_zone = current_zones->get_zone_by_node(
562 compute_context->output_node_id());
563 if (repeat_zone == nullptr) {
564 return;
565 }
566 if (repeat_zone->parent_zone != current_zone) {
567 return;
568 }
569 const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
570 repeat_zone, nullptr);
571 if (lf_zone_node == nullptr) {
572 return;
573 }
574 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_zone_node);
575 local_side_effect_nodes.iterations_by_iteration_zone.add(
576 {parent_compute_context_hash, compute_context->output_node_id()},
577 compute_context->iteration());
578 current_zone = repeat_zone;
579 }
580 else if (const auto *compute_context =
582 compute_context_generic))
583 {
584 const bke::bNodeTreeZone *foreach_zone = current_zones->get_zone_by_node(
585 compute_context->output_node_id());
586 if (foreach_zone == nullptr) {
587 return;
588 }
589 if (foreach_zone->parent_zone != current_zone) {
590 return;
591 }
592 const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
593 foreach_zone, nullptr);
594 if (lf_zone_node == nullptr) {
595 return;
596 }
597 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_zone_node);
598 local_side_effect_nodes.iterations_by_iteration_zone.add(
599 {parent_compute_context_hash, compute_context->output_node_id()},
600 compute_context->index());
601 current_zone = foreach_zone;
602 }
603 else if (const auto *compute_context = dynamic_cast<const bke::GroupNodeComputeContext *>(
604 compute_context_generic))
605 {
606 const bNode *group_node = current_tree->node_by_id(compute_context->node_id());
607 if (group_node == nullptr) {
608 return;
609 }
610 if (group_node->id == nullptr) {
611 return;
612 }
613 if (group_node->is_muted()) {
614 return;
615 }
616 if (current_zone != current_zones->get_zone_by_node(group_node->identifier)) {
617 return;
618 }
619 const lf::FunctionNode *lf_group_node = lf_graph_info->mapping.group_node_map.lookup_default(
620 group_node, nullptr);
621 if (lf_group_node == nullptr) {
622 return;
623 }
624 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_group_node);
625 current_tree = reinterpret_cast<const bNodeTree *>(group_node->id);
626 current_zone = nullptr;
627 }
628 else {
629 return;
630 }
631 }
632 const bNode *final_node = current_tree->node_by_id(final_node_id);
633 if (final_node == nullptr) {
634 return;
635 }
636 const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*current_tree);
637 if (lf_graph_info == nullptr) {
638 return;
639 }
640 const bke::bNodeTreeZones *tree_zones = current_tree->zones();
641 if (tree_zones == nullptr) {
642 return;
643 }
644 if (tree_zones->get_zone_by_node(final_node_id) != current_zone) {
645 return;
646 }
647 const lf::FunctionNode *lf_node =
648 lf_graph_info->mapping.possible_side_effect_node_map.lookup_default(final_node, nullptr);
649 if (lf_node == nullptr) {
650 return;
651 }
652 local_side_effect_nodes.nodes_by_context.add(final_compute_context.hash(), lf_node);
653
654 /* Successfully found all side effect nodes for the viewer path. */
655 for (const auto item : local_side_effect_nodes.nodes_by_context.items()) {
656 r_side_effect_nodes.nodes_by_context.add_multiple(item.key, item.value);
657 }
658 for (const auto item : local_side_effect_nodes.iterations_by_iteration_zone.items()) {
659 r_side_effect_nodes.iterations_by_iteration_zone.add_multiple(item.key, item.value);
660 }
661}
662
664 const ViewerPath &viewer_path,
665 const NodesModifierData &nmd,
666 const ModifierEvalContext &ctx,
667 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
668{
669 const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
671 if (!parsed_path.has_value()) {
672 return;
673 }
674 if (parsed_path->object != DEG_get_original_object(ctx.object)) {
675 return;
676 }
677 if (parsed_path->modifier_name != nmd.modifier.name) {
678 return;
679 }
680
681 ComputeContextBuilder compute_context_builder;
682 compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
683
684 for (const ViewerPathElem *elem : parsed_path->node_path) {
685 if (!ed::viewer_path::add_compute_context_for_viewer_path_elem(*elem, compute_context_builder))
686 {
687 return;
688 }
689 }
690
692 *compute_context_builder.current(), parsed_path->viewer_node_id, nmd, r_side_effect_nodes);
693}
694
696 const NodesModifierData &nmd,
697 const int root_nested_node_id,
698 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
699{
700 ComputeContextBuilder compute_context_builder;
701 compute_context_builder.push<bke::ModifierComputeContext>(nmd.modifier.name);
702
703 int nested_node_id = root_nested_node_id;
704 const bNodeTree *tree = nmd.node_group;
705 while (true) {
706 const bNestedNodeRef *ref = tree->find_nested_node_ref(nested_node_id);
707 if (!ref) {
708 return;
709 }
710 const bNode *node = tree->node_by_id(ref->path.node_id);
711 if (!node) {
712 return;
713 }
714 const bke::bNodeTreeZones *zones = tree->zones();
715 if (!zones) {
716 return;
717 }
718 if (zones->get_zone_by_node(node->identifier) != nullptr) {
719 /* Only top level nodes are allowed here. */
720 return;
721 }
722 if (node->is_group()) {
723 if (!node->id) {
724 return;
725 }
726 compute_context_builder.push<bke::GroupNodeComputeContext>(*node, *tree);
727 tree = reinterpret_cast<const bNodeTree *>(node->id);
728 nested_node_id = ref->path.id_in_node;
729 }
730 else {
732 *compute_context_builder.current(), ref->path.node_id, nmd, r_side_effect_nodes);
733 return;
734 }
735 }
736}
737
743 const ModifierEvalContext &ctx,
744 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
745{
746 if (!nmd.runtime->cache) {
747 return;
748 }
749 if (!DEG_is_active(ctx.depsgraph)) {
750 /* Only the active depsgraph can bake. */
751 return;
752 }
753 bake::ModifierCache &modifier_cache = *nmd.runtime->cache;
754 for (const bNestedNodeRef &ref : nmd.node_group->nested_node_refs_span()) {
755 if (!modifier_cache.requested_bakes.contains(ref.id)) {
756 continue;
757 }
758 find_side_effect_nodes_for_nested_node(nmd, ref.id, r_side_effect_nodes);
759 }
760}
761
763 const NodesModifierData &nmd,
764 const ModifierEvalContext &ctx,
765 const wmWindowManager &wm,
766 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes,
767 Set<ComputeContextHash> &r_socket_log_contexts)
768{
769 Object *object_orig = DEG_get_original_object(ctx.object);
770 const NodesModifierData &nmd_orig = *reinterpret_cast<const NodesModifierData *>(
771 BKE_modifier_get_original(ctx.object, const_cast<ModifierData *>(&nmd.modifier)));
772 ComputeContextBuilder compute_context_builder;
774 *object_orig,
775 nmd_orig,
776 wm,
777 compute_context_builder,
778 [&](const ComputeContext &compute_context,
779 const bNode &gizmo_node,
780 const bNodeSocket &gizmo_socket) {
781 try_add_side_effect_node(compute_context, gizmo_node.identifier, nmd, r_side_effect_nodes);
782 r_socket_log_contexts.add(compute_context.hash());
783
785 compute_context, gizmo_node, gizmo_socket, [&](const ComputeContext &node_context) {
786 /* Make sure that all intermediate sockets are logged. This is necessary to be able
787 * to evaluate the nodes in reverse for the gizmo. */
788 r_socket_log_contexts.add(node_context.hash());
789 });
790 });
791}
792
794 const ModifierEvalContext &ctx,
795 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes,
796 Set<ComputeContextHash> &r_socket_log_contexts)
797{
798 Main *bmain = DEG_get_bmain(ctx.depsgraph);
799 wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
800 if (wm == nullptr) {
801 return;
802 }
803 LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
804 const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
805 const WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook);
806 find_side_effect_nodes_for_viewer_path(workspace->viewer_path, nmd, ctx, r_side_effect_nodes);
807 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
808 const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
809 if (sl->spacetype == SPACE_SPREADSHEET) {
810 const SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<const SpaceSpreadsheet *>(sl);
812 sspreadsheet.viewer_path, nmd, ctx, r_side_effect_nodes);
813 }
814 if (sl->spacetype == SPACE_VIEW3D) {
815 const View3D &v3d = *reinterpret_cast<const View3D *>(sl);
816 find_side_effect_nodes_for_viewer_path(v3d.viewer_path, nmd, ctx, r_side_effect_nodes);
817 }
818 }
819 }
820
821 find_side_effect_nodes_for_baking(nmd, ctx, r_side_effect_nodes);
823 nmd, ctx, *wm, r_side_effect_nodes, r_socket_log_contexts);
824}
825
827 const ModifierEvalContext &ctx,
828 Set<ComputeContextHash> &r_socket_log_contexts)
829{
830 Main *bmain = DEG_get_bmain(ctx.depsgraph);
831 wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
832 if (wm == nullptr) {
833 return;
834 }
835 LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
836 const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
837 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
838 const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
839 if (sl->spacetype == SPACE_NODE) {
840 const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
841 if (snode.edittree == nullptr) {
842 continue;
843 }
845 geo_log::GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode,
846 nmd.modifier.name);
847 for (const ComputeContextHash &hash : hash_by_zone.values()) {
848 r_socket_log_contexts.add(hash);
849 }
850 }
851 }
852 }
853}
854
860{
861 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
862
863 int geometry_socket_count = 0;
864
865 nmd->node_group->ensure_interface_cache();
866 for (const int i : nmd->node_group->interface_inputs().index_range()) {
867 const bNodeTreeInterfaceSocket *socket = nmd->node_group->interface_inputs()[i];
868 const bke::bNodeSocketType *typeinfo = socket->socket_typeinfo();
869 const eNodeSocketDatatype type = typeinfo ? eNodeSocketDatatype(typeinfo->type) : SOCK_CUSTOM;
870 /* The first socket is the special geometry socket for the modifier object. */
871 if (i == 0 && type == SOCK_GEOMETRY) {
872 geometry_socket_count++;
873 continue;
874 }
875
877 if (property == nullptr) {
878 if (ELEM(type, SOCK_GEOMETRY, SOCK_MATRIX)) {
879 geometry_socket_count++;
880 }
881 else {
883 ob, md, "Missing property for input socket \"%s\"", socket->name ? socket->name : "");
884 }
885 continue;
886 }
887
888 if (!nodes::id_property_type_matches_socket(*socket, *property)) {
890 md,
891 "Property type does not match input socket \"(%s)\"",
892 socket->name ? socket->name : "");
893 continue;
894 }
895 }
896
897 if (geometry_socket_count == 1) {
898 const bNodeTreeInterfaceSocket *first_socket = nmd->node_group->interface_inputs()[0];
899 const bke::bNodeSocketType *typeinfo = first_socket->socket_typeinfo();
900 const eNodeSocketDatatype type = typeinfo ? eNodeSocketDatatype(typeinfo->type) : SOCK_CUSTOM;
901 if (type != SOCK_GEOMETRY) {
902 BKE_modifier_set_error(ob, md, "Node group's geometry input must be the first");
903 }
904 }
905}
906
909 std::mutex mutex_;
910
911 public:
914
916 {
917 if (ID *id = this->old_mappings.lookup_default(key, nullptr)) {
918 return id;
919 }
920 if (this->old_mappings.contains(key)) {
921 /* Don't allow overwriting old mappings. */
922 return nullptr;
923 }
924 std::lock_guard lock{mutex_};
925 return this->new_mappings.lookup_or_add(key, nullptr);
926 }
927
928 void try_add(ID &id) override
929 {
930 bake::BakeDataBlockID key{id};
931 if (this->old_mappings.contains(key)) {
932 return;
933 }
934 std::lock_guard lock{mutex_};
935 this->new_mappings.add_overwrite(std::move(key), &id);
936 }
937
938 private:
939 ID *lookup_in_map(Map<bake::BakeDataBlockID, ID *> &map,
940 const bake::BakeDataBlockID &key,
941 const std::optional<ID_Type> &type)
942 {
943 ID *id = map.lookup_default(key, nullptr);
944 if (!id) {
945 return nullptr;
946 }
947 if (type && GS(id->name) != *type) {
948 return nullptr;
949 }
950 return id;
951 }
952};
953
954namespace sim_input = nodes::sim_input;
955namespace sim_output = nodes::sim_output;
956
958 std::optional<int> prev;
959 std::optional<int> current;
960 std::optional<int> next;
961};
962
964 const Span<std::unique_ptr<bake::FrameCache>> frame_caches, const SubFrame frame)
965{
966 BakeFrameIndices frame_indices;
967 if (!frame_caches.is_empty()) {
968 const int first_future_frame_index = binary_search::find_predicate_begin(
969 frame_caches,
970 [&](const std::unique_ptr<bake::FrameCache> &value) { return value->frame > frame; });
971 frame_indices.next = (first_future_frame_index == frame_caches.size()) ?
972 std::nullopt :
973 std::optional<int>(first_future_frame_index);
974 if (first_future_frame_index > 0) {
975 const int index = first_future_frame_index - 1;
976 if (frame_caches[index]->frame < frame) {
977 frame_indices.prev = index;
978 }
979 else {
980 BLI_assert(frame_caches[index]->frame == frame);
981 frame_indices.current = index;
982 if (index > 0) {
983 frame_indices.prev = index - 1;
984 }
985 }
986 }
987 }
988 return frame_indices;
989}
990
991static void ensure_bake_loaded(bake::NodeBakeCache &bake_cache, bake::FrameCache &frame_cache)
992{
993 if (!frame_cache.state.items_by_id.is_empty()) {
994 return;
995 }
996 if (!frame_cache.meta_data_source.has_value()) {
997 return;
998 }
999 if (bake_cache.memory_blob_reader) {
1000 if (const auto *meta_buffer = std::get_if<Span<std::byte>>(&*frame_cache.meta_data_source)) {
1001 const std::string meta_str{reinterpret_cast<const char *>(meta_buffer->data()),
1002 size_t(meta_buffer->size())};
1003 std::istringstream meta_stream{meta_str};
1004 std::optional<bake::BakeState> bake_state = bake::deserialize_bake(
1005 meta_stream, *bake_cache.memory_blob_reader, *bake_cache.blob_sharing);
1006 if (!bake_state.has_value()) {
1007 return;
1008 }
1009 frame_cache.state = std::move(*bake_state);
1010 return;
1011 }
1012 }
1013 if (!bake_cache.blobs_dir) {
1014 return;
1015 }
1016 const auto *meta_path = std::get_if<std::string>(&*frame_cache.meta_data_source);
1017 if (!meta_path) {
1018 return;
1019 }
1020 bake::DiskBlobReader blob_reader{*bake_cache.blobs_dir};
1021 fstream meta_file{*meta_path};
1022 std::optional<bake::BakeState> bake_state = bake::deserialize_bake(
1023 meta_file, blob_reader, *bake_cache.blob_sharing);
1024 if (!bake_state.has_value()) {
1025 return;
1026 }
1027 frame_cache.state = std::move(*bake_state);
1028}
1029
1031 bake::NodeBakeCache &bake_cache,
1032 const Main &bmain,
1033 const Object &object,
1034 const NodesModifierData &nmd,
1035 const int id)
1036{
1037 if (bake.packed) {
1038 if (bake.packed->meta_files_num == 0) {
1039 return false;
1040 }
1041 bake_cache.reset();
1043 for (const NodesModifierBakeFile &meta_file :
1044 Span{bake.packed->meta_files, bake.packed->meta_files_num})
1045 {
1046 const std::optional<SubFrame> frame = bake::file_name_to_frame(meta_file.name);
1047 if (!frame) {
1048 return false;
1049 }
1050 if (!file_by_frame.add(*frame, &meta_file)) {
1051 /* Can only have on file per (sub)frame. */
1052 return false;
1053 }
1054 }
1055 /* Make sure frames processed in the right order. */
1056 Vector<SubFrame> frames;
1057 frames.extend(file_by_frame.keys().begin(), file_by_frame.keys().end());
1058
1059 for (const SubFrame &frame : frames) {
1060 const NodesModifierBakeFile &meta_file = *file_by_frame.lookup(frame);
1061 auto frame_cache = std::make_unique<bake::FrameCache>();
1062 frame_cache->frame = frame;
1063 frame_cache->meta_data_source = meta_file.data();
1064 bake_cache.frames.append(std::move(frame_cache));
1065 }
1066
1067 bake_cache.memory_blob_reader = std::make_unique<bake::MemoryBlobReader>();
1068 for (const NodesModifierBakeFile &blob_file :
1069 Span{bake.packed->blob_files, bake.packed->blob_files_num})
1070 {
1071 bake_cache.memory_blob_reader->add(blob_file.name, blob_file.data());
1072 }
1073 bake_cache.blob_sharing = std::make_unique<bake::BlobReadSharing>();
1074 return true;
1075 }
1076
1077 std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(bmain, object, nmd, id);
1078 if (!bake_path) {
1079 return false;
1080 }
1081 Vector<bake::MetaFile> meta_files = bake::find_sorted_meta_files(bake_path->meta_dir);
1082 if (meta_files.is_empty()) {
1083 return false;
1084 }
1085 bake_cache.reset();
1086 for (const bake::MetaFile &meta_file : meta_files) {
1087 auto frame_cache = std::make_unique<bake::FrameCache>();
1088 frame_cache->frame = meta_file.frame;
1089 frame_cache->meta_data_source = meta_file.path;
1090 bake_cache.frames.append(std::move(frame_cache));
1091 }
1092 bake_cache.blobs_dir = bake_path->blobs_dir;
1093 bake_cache.blob_sharing = std::make_unique<bake::BlobReadSharing>();
1094 return true;
1095}
1096
1098 private:
1099 static constexpr float max_delta_frames = 1.0f;
1100
1101 const NodesModifierData &nmd_;
1102 const ModifierEvalContext &ctx_;
1103 const Main *bmain_;
1104 const Scene *scene_;
1105 SubFrame current_frame_;
1106 bool use_frame_cache_;
1107 bool depsgraph_is_active_;
1108 bake::ModifierCache *modifier_cache_;
1109 float fps_;
1110 bool has_invalid_simulation_ = false;
1111
1112 public:
1117
1119
1121 : nmd_(nmd), ctx_(ctx)
1122 {
1123 const Depsgraph *depsgraph = ctx_.depsgraph;
1124 bmain_ = DEG_get_bmain(depsgraph);
1125 current_frame_ = DEG_get_ctime(depsgraph);
1126 const Scene *scene = DEG_get_input_scene(depsgraph);
1127 scene_ = scene;
1128 use_frame_cache_ = ctx_.object->flag & OB_FLAG_USE_SIMULATION_CACHE;
1129 depsgraph_is_active_ = DEG_is_active(depsgraph);
1130 modifier_cache_ = nmd.runtime->cache.get();
1131 fps_ = FPS;
1132
1133 if (!modifier_cache_) {
1134 return;
1135 }
1136 std::lock_guard lock{modifier_cache_->mutex};
1137 if (depsgraph_is_active_) {
1138 /* Invalidate data on user edits. */
1140 for (std::unique_ptr<bake::SimulationNodeCache> &node_cache :
1141 modifier_cache_->simulation_cache_by_id.values())
1142 {
1143 if (node_cache->cache_status != bake::CacheStatus::Baked) {
1144 node_cache->cache_status = bake::CacheStatus::Invalid;
1145 if (!node_cache->bake.frames.is_empty()) {
1146 if (node_cache->bake.frames.last()->frame == current_frame_) {
1147 /* Remove the last (which is the current) cached frame so that it is simulated
1148 * again. */
1149 node_cache->bake.frames.pop_last();
1150 }
1151 }
1152 }
1153 }
1154 }
1156 }
1157 for (const std::unique_ptr<bake::SimulationNodeCache> &node_cache_ptr :
1158 modifier_cache_->simulation_cache_by_id.values())
1159 {
1160 const bake::SimulationNodeCache &node_cache = *node_cache_ptr;
1161 if (node_cache.cache_status == bake::CacheStatus::Invalid) {
1162 has_invalid_simulation_ = true;
1163 break;
1164 }
1165 }
1166 }
1167
1169 {
1170 for (auto item : modifier_cache_->simulation_cache_by_id.items()) {
1171 const int id = item.key;
1172 bake::SimulationNodeCache &node_cache = *item.value;
1173 if (node_cache.cache_status != bake::CacheStatus::Invalid) {
1174 continue;
1175 }
1176 const std::optional<IndexRange> sim_frame_range = bake::get_node_bake_frame_range(
1177 *scene_, *ctx_.object, nmd_, id);
1178 if (!sim_frame_range.has_value()) {
1179 continue;
1180 }
1181 const SubFrame start_frame{int(sim_frame_range->start())};
1182 if (current_frame_ <= start_frame) {
1183 node_cache.reset();
1184 }
1185 if (!node_cache.bake.frames.is_empty() &&
1186 current_frame_ < node_cache.bake.frames.first()->frame)
1187 {
1188 node_cache.reset();
1189 }
1190 }
1191 }
1192
1193 nodes::SimulationZoneBehavior *get(const int zone_id) const override
1194 {
1195 if (!modifier_cache_) {
1196 return nullptr;
1197 }
1198 std::lock_guard lock{modifier_cache_->mutex};
1199 return &this->data_by_zone_id
1200 .lookup_or_add_cb(zone_id,
1201 [&]() {
1202 auto data = std::make_unique<DataPerZone>();
1203 data->behavior.data_block_map = &data->data_block_map;
1205 zone_id, data->behavior, data->data_block_map);
1206 return data;
1207 })
1208 ->behavior;
1209 }
1210
1211 void init_simulation_info(const int zone_id,
1212 nodes::SimulationZoneBehavior &zone_behavior,
1213 NodesModifierBakeDataBlockMap &data_block_map) const
1214 {
1215 bake::SimulationNodeCache &node_cache =
1216 *modifier_cache_->simulation_cache_by_id.lookup_or_add_cb(
1217 zone_id, []() { return std::make_unique<bake::SimulationNodeCache>(); });
1218 const NodesModifierBake &bake = *nmd_.find_bake(zone_id);
1219 const IndexRange sim_frame_range = *bake::get_node_bake_frame_range(
1220 *scene_, *ctx_.object, nmd_, zone_id);
1221 const SubFrame sim_start_frame{int(sim_frame_range.first())};
1222 const SubFrame sim_end_frame{int(sim_frame_range.last())};
1223
1224 if (!modifier_cache_->requested_bakes.contains(zone_id)) {
1225 /* Try load baked data. */
1226 if (!node_cache.bake.failed_finding_bake) {
1227 if (node_cache.cache_status != bake::CacheStatus::Baked) {
1228 if (try_find_baked_data(bake, node_cache.bake, *bmain_, *ctx_.object, nmd_, zone_id)) {
1229 node_cache.cache_status = bake::CacheStatus::Baked;
1230 }
1231 else {
1232 node_cache.bake.failed_finding_bake = true;
1233 }
1234 }
1235 }
1236 }
1237
1238 /* If there are no baked frames, we don't need keep track of the data-blocks. */
1239 if (!node_cache.bake.frames.is_empty() || node_cache.prev_cache.has_value()) {
1240 for (const NodesModifierDataBlock &data_block : Span{bake.data_blocks, bake.data_blocks_num})
1241 {
1242 data_block_map.old_mappings.add(data_block, data_block.id);
1243 }
1244 }
1245
1246 const BakeFrameIndices frame_indices = get_bake_frame_indices(node_cache.bake.frames,
1247 current_frame_);
1248 if (node_cache.cache_status == bake::CacheStatus::Baked) {
1249 this->read_from_cache(frame_indices, node_cache, zone_behavior);
1250 return;
1251 }
1252 if (use_frame_cache_) {
1253 /* If the depsgraph is active, we allow creating new simulation states. Otherwise, the access
1254 * is read-only. */
1255 if (depsgraph_is_active_) {
1256 if (node_cache.bake.frames.is_empty()) {
1257 if (current_frame_ < sim_start_frame || current_frame_ > sim_end_frame) {
1258 /* Outside of simulation frame range, so ignore the simulation if there is no cache. */
1259 this->input_pass_through(zone_behavior);
1260 this->output_pass_through(zone_behavior);
1261 return;
1262 }
1263 /* Initialize the simulation. */
1264 if (current_frame_ > sim_start_frame || has_invalid_simulation_) {
1265 node_cache.cache_status = bake::CacheStatus::Invalid;
1266 }
1267 this->input_pass_through(zone_behavior);
1268 this->output_store_frame_cache(node_cache, zone_behavior);
1269 return;
1270 }
1271 if (frame_indices.prev && !frame_indices.current && !frame_indices.next &&
1272 current_frame_ <= sim_end_frame)
1273 {
1274 /* Read the previous frame's data and store the newly computed simulation state. */
1275 auto &output_copy_info = zone_behavior.input.emplace<sim_input::OutputCopy>();
1276 const bake::FrameCache &prev_frame_cache = *node_cache.bake.frames[*frame_indices.prev];
1277 const float real_delta_frames = float(current_frame_) - float(prev_frame_cache.frame);
1278 if (real_delta_frames != 1) {
1279 node_cache.cache_status = bake::CacheStatus::Invalid;
1280 }
1281 const float delta_frames = std::min(max_delta_frames, real_delta_frames);
1282 output_copy_info.delta_time = delta_frames / fps_;
1283 output_copy_info.state = prev_frame_cache.state;
1284 this->output_store_frame_cache(node_cache, zone_behavior);
1285 return;
1286 }
1287 }
1288 this->read_from_cache(frame_indices, node_cache, zone_behavior);
1289 return;
1290 }
1291
1292 /* When there is no per-frame cache, check if there is a previous state. */
1293 if (node_cache.prev_cache) {
1294 if (node_cache.prev_cache->frame < current_frame_) {
1295 /* Do a simulation step. */
1296 const float delta_frames = std::min(
1297 max_delta_frames, float(current_frame_) - float(node_cache.prev_cache->frame));
1298 auto &output_move_info = zone_behavior.input.emplace<sim_input::OutputMove>();
1299 output_move_info.delta_time = delta_frames / fps_;
1300 output_move_info.state = std::move(node_cache.prev_cache->state);
1301 this->store_as_prev_items(node_cache, zone_behavior);
1302 return;
1303 }
1304 if (node_cache.prev_cache->frame == current_frame_) {
1305 /* Just read from the previous state if the frame has not changed. */
1306 auto &output_copy_info = zone_behavior.input.emplace<sim_input::OutputCopy>();
1307 output_copy_info.delta_time = 0.0f;
1308 output_copy_info.state = node_cache.prev_cache->state;
1309 auto &read_single_info = zone_behavior.output.emplace<sim_output::ReadSingle>();
1310 read_single_info.state = node_cache.prev_cache->state;
1311 return;
1312 }
1313 if (!depsgraph_is_active_) {
1314 /* There is no previous state, and it's not possible to initialize the simulation because
1315 * the depsgraph is not active. */
1316 zone_behavior.input.emplace<sim_input::PassThrough>();
1317 zone_behavior.output.emplace<sim_output::PassThrough>();
1318 return;
1319 }
1320 /* Reset the simulation when the scene time moved backwards. */
1321 node_cache.prev_cache.reset();
1322 }
1323 zone_behavior.input.emplace<sim_input::PassThrough>();
1324 if (depsgraph_is_active_) {
1325 /* Initialize the simulation. */
1326 this->store_as_prev_items(node_cache, zone_behavior);
1327 }
1328 else {
1329 zone_behavior.output.emplace<sim_output::PassThrough>();
1330 }
1331 }
1332
1334 {
1335 zone_behavior.input.emplace<sim_input::PassThrough>();
1336 }
1337
1339 {
1340 zone_behavior.output.emplace<sim_output::PassThrough>();
1341 }
1342
1344 nodes::SimulationZoneBehavior &zone_behavior) const
1345 {
1346 auto &store_new_state_info = zone_behavior.output.emplace<sim_output::StoreNewState>();
1347 store_new_state_info.store_fn = [simulation_cache = modifier_cache_,
1348 node_cache = &node_cache,
1349 current_frame = current_frame_](bke::bake::BakeState state) {
1350 std::lock_guard lock{simulation_cache->mutex};
1351 auto frame_cache = std::make_unique<bake::FrameCache>();
1352 frame_cache->frame = current_frame;
1353 frame_cache->state = std::move(state);
1354 node_cache->bake.frames.append(std::move(frame_cache));
1355 };
1356 }
1357
1359 nodes::SimulationZoneBehavior &zone_behavior) const
1360 {
1361 auto &store_new_state_info = zone_behavior.output.emplace<sim_output::StoreNewState>();
1362 store_new_state_info.store_fn = [simulation_cache = modifier_cache_,
1363 node_cache = &node_cache,
1364 current_frame = current_frame_](bke::bake::BakeState state) {
1365 std::lock_guard lock{simulation_cache->mutex};
1366 if (!node_cache->prev_cache) {
1367 node_cache->prev_cache.emplace();
1368 }
1369 node_cache->prev_cache->state = std::move(state);
1370 node_cache->prev_cache->frame = current_frame;
1371 };
1372 }
1373
1374 void read_from_cache(const BakeFrameIndices &frame_indices,
1375 bake::SimulationNodeCache &node_cache,
1376 nodes::SimulationZoneBehavior &zone_behavior) const
1377 {
1378 if (frame_indices.prev) {
1379 auto &output_copy_info = zone_behavior.input.emplace<sim_input::OutputCopy>();
1380 bake::FrameCache &frame_cache = *node_cache.bake.frames[*frame_indices.prev];
1381 const float delta_frames = std::min(max_delta_frames,
1382 float(current_frame_) - float(frame_cache.frame));
1383 output_copy_info.delta_time = delta_frames / fps_;
1384 output_copy_info.state = frame_cache.state;
1385 }
1386 else {
1387 zone_behavior.input.emplace<sim_input::PassThrough>();
1388 }
1389 if (frame_indices.current) {
1390 this->read_single(*frame_indices.current, node_cache, zone_behavior);
1391 }
1392 else if (frame_indices.next) {
1393 if (frame_indices.prev) {
1394 this->read_interpolated(
1395 *frame_indices.prev, *frame_indices.next, node_cache, zone_behavior);
1396 }
1397 else {
1398 this->output_pass_through(zone_behavior);
1399 }
1400 }
1401 else if (frame_indices.prev) {
1402 this->read_single(*frame_indices.prev, node_cache, zone_behavior);
1403 }
1404 else {
1405 this->output_pass_through(zone_behavior);
1406 }
1407 }
1408
1409 void read_single(const int frame_index,
1410 bake::SimulationNodeCache &node_cache,
1411 nodes::SimulationZoneBehavior &zone_behavior) const
1412 {
1413 bake::FrameCache &frame_cache = *node_cache.bake.frames[frame_index];
1414 ensure_bake_loaded(node_cache.bake, frame_cache);
1415 auto &read_single_info = zone_behavior.output.emplace<sim_output::ReadSingle>();
1416 read_single_info.state = frame_cache.state;
1417 }
1418
1419 void read_interpolated(const int prev_frame_index,
1420 const int next_frame_index,
1421 bake::SimulationNodeCache &node_cache,
1422 nodes::SimulationZoneBehavior &zone_behavior) const
1423 {
1424 bake::FrameCache &prev_frame_cache = *node_cache.bake.frames[prev_frame_index];
1425 bake::FrameCache &next_frame_cache = *node_cache.bake.frames[next_frame_index];
1426 ensure_bake_loaded(node_cache.bake, prev_frame_cache);
1427 ensure_bake_loaded(node_cache.bake, next_frame_cache);
1428 auto &read_interpolated_info = zone_behavior.output.emplace<sim_output::ReadInterpolated>();
1429 read_interpolated_info.mix_factor = (float(current_frame_) - float(prev_frame_cache.frame)) /
1430 (float(next_frame_cache.frame) -
1431 float(prev_frame_cache.frame));
1432 read_interpolated_info.prev_state = prev_frame_cache.state;
1433 read_interpolated_info.next_state = next_frame_cache.state;
1434 }
1435};
1436
1438 private:
1439 const NodesModifierData &nmd_;
1440 const ModifierEvalContext &ctx_;
1441 Main *bmain_;
1442 SubFrame current_frame_;
1443 bake::ModifierCache *modifier_cache_;
1444 bool depsgraph_is_active_;
1445
1446 public:
1451
1453
1455 : nmd_(nmd), ctx_(ctx)
1456 {
1457 const Depsgraph *depsgraph = ctx_.depsgraph;
1458 current_frame_ = DEG_get_ctime(depsgraph);
1459 modifier_cache_ = nmd.runtime->cache.get();
1460 depsgraph_is_active_ = DEG_is_active(depsgraph);
1461 bmain_ = DEG_get_bmain(depsgraph);
1462 }
1463
1464 nodes::BakeNodeBehavior *get(const int id) const
1465 {
1466 if (!modifier_cache_) {
1467 return nullptr;
1468 }
1469 std::lock_guard lock{modifier_cache_->mutex};
1470 return &this->data_by_node_id
1471 .lookup_or_add_cb(id,
1472 [&]() {
1473 auto data = std::make_unique<DataPerNode>();
1474 data->behavior.data_block_map = &data->data_block_map;
1475 this->init_bake_behavior(
1476 id, data->behavior, data->data_block_map);
1477 return data;
1478 })
1479 ->behavior;
1480 return nullptr;
1481 }
1482
1483 private:
1484 void init_bake_behavior(const int id,
1485 nodes::BakeNodeBehavior &behavior,
1486 NodesModifierBakeDataBlockMap &data_block_map) const
1487 {
1488 bake::BakeNodeCache &node_cache = *modifier_cache_->bake_cache_by_id.lookup_or_add_cb(
1489 id, []() { return std::make_unique<bake::BakeNodeCache>(); });
1490 const NodesModifierBake &bake = *nmd_.find_bake(id);
1491
1492 for (const NodesModifierDataBlock &data_block : Span{bake.data_blocks, bake.data_blocks_num}) {
1493 data_block_map.old_mappings.add(data_block, data_block.id);
1494 }
1495
1496 if (depsgraph_is_active_) {
1497 if (modifier_cache_->requested_bakes.contains(id)) {
1498 /* This node is baked during the current evaluation. */
1499 auto &store_info = behavior.behavior.emplace<sim_output::StoreNewState>();
1500 store_info.store_fn = [modifier_cache = modifier_cache_,
1501 node_cache = &node_cache,
1502 current_frame = current_frame_](bake::BakeState state) {
1503 std::lock_guard lock{modifier_cache->mutex};
1504 auto frame_cache = std::make_unique<bake::FrameCache>();
1505 frame_cache->frame = current_frame;
1506 frame_cache->state = std::move(state);
1507 auto &frames = node_cache->bake.frames;
1508 const int insert_index = binary_search::find_predicate_begin(
1509 frames, [&](const std::unique_ptr<bake::FrameCache> &frame_cache) {
1510 return frame_cache->frame > current_frame;
1511 });
1512 frames.insert(insert_index, std::move(frame_cache));
1513 };
1514 return;
1515 }
1516 }
1517
1518 /* Try load baked data. */
1519 if (node_cache.bake.frames.is_empty()) {
1520 if (!node_cache.bake.failed_finding_bake) {
1521 if (!try_find_baked_data(bake, node_cache.bake, *bmain_, *ctx_.object, nmd_, id)) {
1522 node_cache.bake.failed_finding_bake = true;
1523 }
1524 }
1525 }
1526
1527 if (node_cache.bake.frames.is_empty()) {
1528 behavior.behavior.emplace<sim_output::PassThrough>();
1529 return;
1530 }
1531 const BakeFrameIndices frame_indices = get_bake_frame_indices(node_cache.bake.frames,
1532 current_frame_);
1533 if (frame_indices.current) {
1534 this->read_single(*frame_indices.current, node_cache, behavior);
1535 return;
1536 }
1537 if (frame_indices.prev && frame_indices.next) {
1538 this->read_interpolated(*frame_indices.prev, *frame_indices.next, node_cache, behavior);
1539 return;
1540 }
1541 if (frame_indices.prev) {
1542 this->read_single(*frame_indices.prev, node_cache, behavior);
1543 return;
1544 }
1545 if (frame_indices.next) {
1546 this->read_single(*frame_indices.next, node_cache, behavior);
1547 return;
1548 }
1550 }
1551
1552 void read_single(const int frame_index,
1553 bake::BakeNodeCache &node_cache,
1554 nodes::BakeNodeBehavior &behavior) const
1555 {
1556 bake::FrameCache &frame_cache = *node_cache.bake.frames[frame_index];
1557 ensure_bake_loaded(node_cache.bake, frame_cache);
1558 if (this->check_read_error(frame_cache, behavior)) {
1559 return;
1560 }
1561 auto &read_single_info = behavior.behavior.emplace<sim_output::ReadSingle>();
1562 read_single_info.state = frame_cache.state;
1563 }
1564
1565 void read_interpolated(const int prev_frame_index,
1566 const int next_frame_index,
1567 bake::BakeNodeCache &node_cache,
1568 nodes::BakeNodeBehavior &behavior) const
1569 {
1570 bake::FrameCache &prev_frame_cache = *node_cache.bake.frames[prev_frame_index];
1571 bake::FrameCache &next_frame_cache = *node_cache.bake.frames[next_frame_index];
1572 ensure_bake_loaded(node_cache.bake, prev_frame_cache);
1573 ensure_bake_loaded(node_cache.bake, next_frame_cache);
1574 if (this->check_read_error(prev_frame_cache, behavior) ||
1575 this->check_read_error(next_frame_cache, behavior))
1576 {
1577 return;
1578 }
1579 auto &read_interpolated_info = behavior.behavior.emplace<sim_output::ReadInterpolated>();
1580 read_interpolated_info.mix_factor = (float(current_frame_) - float(prev_frame_cache.frame)) /
1581 (float(next_frame_cache.frame) -
1582 float(prev_frame_cache.frame));
1583 read_interpolated_info.prev_state = prev_frame_cache.state;
1584 read_interpolated_info.next_state = next_frame_cache.state;
1585 }
1586
1587 [[nodiscard]] bool check_read_error(const bake::FrameCache &frame_cache,
1588 nodes::BakeNodeBehavior &behavior) const
1589 {
1590 if (frame_cache.meta_data_source && frame_cache.state.items_by_id.is_empty()) {
1591 auto &read_error_info = behavior.behavior.emplace<sim_output::ReadError>();
1592 read_error_info.message = RPT_("Cannot load the baked data");
1593 return true;
1594 }
1595 return false;
1596 }
1597};
1598
1601 const Span<bake::BakeDataBlockID> missing,
1602 FunctionRef<ID *(const bake::BakeDataBlockID &)> get_data_block)
1603{
1604 const int old_num = bake.data_blocks_num;
1605 const int new_num = old_num + missing.size();
1606 bake.data_blocks = reinterpret_cast<NodesModifierDataBlock *>(
1607 MEM_recallocN(bake.data_blocks, sizeof(NodesModifierDataBlock) * new_num));
1608 for (const int i : missing.index_range()) {
1609 NodesModifierDataBlock &data_block = bake.data_blocks[old_num + i];
1610 const blender::bke::bake::BakeDataBlockID &key = missing[i];
1611
1612 data_block.id_name = BLI_strdup(key.id_name.c_str());
1613 if (!key.lib_name.empty()) {
1614 data_block.lib_name = BLI_strdup(key.lib_name.c_str());
1615 }
1616 data_block.id_type = int(key.type);
1617 ID *id = get_data_block(key);
1618 if (id) {
1619 data_block.id = id;
1620 }
1621 }
1622 bake.data_blocks_num = new_num;
1623}
1624
1625void nodes_modifier_data_block_destruct(NodesModifierDataBlock *data_block, const bool do_id_user)
1626{
1627 MEM_SAFE_FREE(data_block->id_name);
1628 MEM_SAFE_FREE(data_block->lib_name);
1629 if (do_id_user) {
1630 id_us_min(data_block->id);
1631 }
1632}
1633
1641 NodesModifierData &nmd_eval,
1642 NodesModifierData &nmd_orig,
1643 NodesModifierSimulationParams &simulation_params,
1644 NodesModifierBakeParams &bake_params)
1645{
1646 Depsgraph *depsgraph = ctx.depsgraph;
1647 Main *bmain = DEG_get_bmain(depsgraph);
1648
1649 struct DataPerBake {
1650 bool reset_first = false;
1652 };
1653 Map<int, DataPerBake> writeback_data;
1654 for (auto item : simulation_params.data_by_zone_id.items()) {
1655 DataPerBake data;
1656 NodesModifierBake &bake = *nmd_eval.find_bake(item.key);
1657 if (item.value->data_block_map.old_mappings.size() < bake.data_blocks_num) {
1658 data.reset_first = true;
1659 }
1660 if (bake::SimulationNodeCache *node_cache = nmd_eval.runtime->cache->get_simulation_node_cache(
1661 item.key))
1662 {
1663 /* Only writeback if the bake node has actually baked anything. */
1664 if (!node_cache->bake.frames.is_empty() || node_cache->prev_cache.has_value()) {
1665 data.new_mappings = std::move(item.value->data_block_map.new_mappings);
1666 }
1667 }
1668 if (data.reset_first || !data.new_mappings.is_empty()) {
1669 writeback_data.add(item.key, std::move(data));
1670 }
1671 }
1672 for (auto item : bake_params.data_by_node_id.items()) {
1673 if (bake::BakeNodeCache *node_cache = nmd_eval.runtime->cache->get_bake_node_cache(item.key)) {
1674 /* Only writeback if the bake node has actually baked anything. */
1675 if (!node_cache->bake.frames.is_empty()) {
1676 DataPerBake data;
1677 data.new_mappings = std::move(item.value->data_block_map.new_mappings);
1678 writeback_data.add(item.key, std::move(data));
1679 }
1680 }
1681 }
1682
1683 if (writeback_data.is_empty()) {
1684 /* Nothing to do. */
1685 return;
1686 }
1687
1689 *depsgraph,
1690 [object_eval = ctx.object,
1691 bmain,
1692 &nmd_orig,
1693 &nmd_eval,
1694 writeback_data = std::move(writeback_data)]() {
1695 for (auto item : writeback_data.items()) {
1696 const int bake_id = item.key;
1697 DataPerBake data = item.value;
1698
1699 NodesModifierBake &bake_orig = *nmd_orig.find_bake(bake_id);
1700 NodesModifierBake &bake_eval = *nmd_eval.find_bake(bake_id);
1701
1702 if (data.reset_first) {
1703 /* Reset data-block list on original data. */
1704 dna::array::clear<NodesModifierDataBlock>(&bake_orig.data_blocks,
1705 &bake_orig.data_blocks_num,
1706 &bake_orig.active_data_block,
1707 [](NodesModifierDataBlock *data_block) {
1708 nodes_modifier_data_block_destruct(
1709 data_block, true);
1710 });
1711 /* Reset data-block list on evaluated data. */
1712 dna::array::clear<NodesModifierDataBlock>(&bake_eval.data_blocks,
1713 &bake_eval.data_blocks_num,
1714 &bake_eval.active_data_block,
1715 [](NodesModifierDataBlock *data_block) {
1716 nodes_modifier_data_block_destruct(
1717 data_block, false);
1718 });
1719 }
1720
1721 Vector<bake::BakeDataBlockID> sorted_new_mappings;
1722 sorted_new_mappings.extend(data.new_mappings.keys().begin(),
1723 data.new_mappings.keys().end());
1724 bool needs_reevaluation = false;
1725 /* Add new data block mappings to the original modifier. This may do a name lookup in
1726 * bmain to find the data block if there is not faster way to get it. */
1727 add_missing_data_block_mappings(
1728 bake_orig, sorted_new_mappings, [&](const bake::BakeDataBlockID &key) -> ID * {
1729 ID *id_orig = nullptr;
1730 if (ID *id_eval = data.new_mappings.lookup_default(key, nullptr)) {
1731 id_orig = DEG_get_original_id(id_eval);
1732 }
1733 else {
1734 needs_reevaluation = true;
1735 id_orig = BKE_libblock_find_name_and_library(
1736 bmain, short(key.type), key.id_name.c_str(), key.lib_name.c_str());
1737 }
1738 if (id_orig) {
1739 id_us_plus(id_orig);
1740 }
1741 return id_orig;
1742 });
1743 /* Add new data block mappings to the evaluated modifier. In most cases this makes it so
1744 * the evaluated modifier is in the same state as if it were copied from the updated
1745 * original again. The exception is when a missing data block was found that is not in
1746 * the depsgraph currently. */
1747 add_missing_data_block_mappings(
1748 bake_eval, sorted_new_mappings, [&](const bake::BakeDataBlockID &key) -> ID * {
1749 return data.new_mappings.lookup_default(key, nullptr);
1750 });
1751
1752 if (needs_reevaluation) {
1753 Object *object_orig = DEG_get_original_object(object_eval);
1754 DEG_id_tag_update(&object_orig->id, ID_RECALC_GEOMETRY);
1755 DEG_relations_tag_update(bmain);
1756 }
1757 }
1758 });
1759}
1760
1762 const ModifierEvalContext *ctx,
1763 bke::GeometrySet &geometry_set)
1764{
1765 using namespace blender;
1766 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1767 if (nmd->node_group == nullptr) {
1768 return;
1769 }
1770 NodesModifierData *nmd_orig = reinterpret_cast<NodesModifierData *>(
1772
1773 const bNodeTree &tree = *nmd->node_group;
1775
1776 tree.ensure_topology_cache();
1777 const bNode *output_node = tree.group_output_node();
1778 if (output_node == nullptr) {
1779 BKE_modifier_set_error(ctx->object, md, "Node group must have a group output node");
1780 geometry_set.clear();
1781 return;
1782 }
1783
1784 Span<const bNodeSocket *> group_outputs = output_node->input_sockets().drop_back(1);
1785 if (group_outputs.is_empty()) {
1786 BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket");
1787 geometry_set.clear();
1788 return;
1789 }
1790
1791 const bNodeSocket *first_output_socket = group_outputs[0];
1792 if (!STREQ(first_output_socket->idname, "NodeSocketGeometry")) {
1793 BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry");
1794 geometry_set.clear();
1795 return;
1796 }
1797
1798 const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
1799 nodes::ensure_geometry_nodes_lazy_function_graph(tree);
1800 if (lf_graph_info == nullptr) {
1801 BKE_modifier_set_error(ctx->object, md, "Cannot evaluate node group");
1802 geometry_set.clear();
1803 return;
1804 }
1805
1806 bool use_orig_index_verts = false;
1807 bool use_orig_index_edges = false;
1808 bool use_orig_index_faces = false;
1809 if (const Mesh *mesh = geometry_set.get_mesh()) {
1810 use_orig_index_verts = CustomData_has_layer(&mesh->vert_data, CD_ORIGINDEX);
1811 use_orig_index_edges = CustomData_has_layer(&mesh->edge_data, CD_ORIGINDEX);
1812 use_orig_index_faces = CustomData_has_layer(&mesh->face_data, CD_ORIGINDEX);
1813 }
1814
1815 nodes::GeoNodesCallData call_data;
1816
1817 nodes::GeoNodesModifierData modifier_eval_data{};
1818 modifier_eval_data.depsgraph = ctx->depsgraph;
1819 modifier_eval_data.self_object = ctx->object;
1820 auto eval_log = std::make_unique<geo_log::GeoModifierLog>();
1821 call_data.modifier_data = &modifier_eval_data;
1822
1823 NodesModifierSimulationParams simulation_params(*nmd, *ctx);
1824 call_data.simulation_params = &simulation_params;
1825 NodesModifierBakeParams bake_params{*nmd, *ctx};
1826 call_data.bake_params = &bake_params;
1827
1828 Set<ComputeContextHash> socket_log_contexts;
1829 if (logging_enabled(ctx)) {
1830 call_data.eval_log = eval_log.get();
1831
1832 find_socket_log_contexts(*nmd, *ctx, socket_log_contexts);
1833 call_data.socket_log_contexts = &socket_log_contexts;
1834 }
1835
1836 nodes::GeoNodesSideEffectNodes side_effect_nodes;
1837 find_side_effect_nodes(*nmd, *ctx, side_effect_nodes, socket_log_contexts);
1838 call_data.side_effect_nodes = &side_effect_nodes;
1839
1840 bke::ModifierComputeContext modifier_compute_context{nullptr, nmd->modifier.name};
1841
1842 geometry_set = nodes::execute_geometry_nodes_on_geometry(tree,
1843 nmd->settings.properties,
1844 modifier_compute_context,
1845 call_data,
1846 std::move(geometry_set));
1847
1848 if (logging_enabled(ctx)) {
1849 nmd_orig->runtime->eval_log = std::move(eval_log);
1850 }
1851
1852 if (DEG_is_active(ctx->depsgraph) && !(ctx->flag & MOD_APPLY_TO_ORIGINAL)) {
1853 add_data_block_items_writeback(*ctx, *nmd, *nmd_orig, simulation_params, bake_params);
1854 }
1855
1856 if (use_orig_index_verts || use_orig_index_edges || use_orig_index_faces) {
1857 if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
1858 /* Add #CD_ORIGINDEX layers if they don't exist already. This is required because the
1859 * #eModifierTypeFlag_SupportsMapping flag is set. If the layers did not exist before, it is
1860 * assumed that the output mesh does not have a mapping to the original mesh. */
1861 if (use_orig_index_verts) {
1862 CustomData_add_layer(&mesh->vert_data, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->verts_num);
1863 }
1864 if (use_orig_index_edges) {
1865 CustomData_add_layer(&mesh->edge_data, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->edges_num);
1866 }
1867 if (use_orig_index_faces) {
1868 CustomData_add_layer(&mesh->face_data, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->faces_num);
1869 }
1870 }
1871 }
1872}
1873
1875{
1876 bke::GeometrySet geometry_set = bke::GeometrySet::from_mesh(
1877 mesh, bke::GeometryOwnershipType::Editable);
1878
1879 modifyGeometry(md, ctx, geometry_set);
1880
1881 Mesh *new_mesh = geometry_set.get_component_for_write<bke::MeshComponent>().release();
1882 if (new_mesh == nullptr) {
1883 return BKE_mesh_new_nomain(0, 0, 0, 0);
1884 }
1885 return new_mesh;
1886}
1887
1889 const ModifierEvalContext *ctx,
1890 bke::GeometrySet *geometry_set)
1891{
1892 modifyGeometry(md, ctx, *geometry_set);
1893}
1894
1901/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
1902BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
1903
1905 const wmWindowManager &wm,
1906 const AttributeSearchData &data)
1907{
1908 if (ED_screen_animation_playing(&wm)) {
1909 /* Work around an issue where the attribute search exec function has stale pointers when data
1910 * is reallocated when evaluating the node tree, causing a crash. This would be solved by
1911 * allowing the UI search data to own arbitrary memory rather than just referencing it. */
1912 return nullptr;
1913 }
1914
1915 const Object *object = (Object *)BKE_libblock_find_session_uid(
1916 &bmain, ID_OB, data.object_session_uid);
1917 if (object == nullptr) {
1918 return nullptr;
1919 }
1920 ModifierData *md = BKE_modifiers_findby_name(object, data.modifier_name);
1921 if (md == nullptr) {
1922 return nullptr;
1923 }
1925 return reinterpret_cast<NodesModifierData *>(md);
1926}
1927
1929{
1930 if (!nmd.runtime->eval_log) {
1931 return nullptr;
1932 }
1933 bke::ModifierComputeContext compute_context{nullptr, nmd.modifier.name};
1934 return &nmd.runtime->eval_log->get_tree_log(compute_context.hash());
1935}
1936
1938 const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
1939{
1940 AttributeSearchData &data = *static_cast<AttributeSearchData *>(arg);
1942 if (nmd == nullptr) {
1943 return;
1944 }
1945 if (nmd->node_group == nullptr) {
1946 return;
1947 }
1948 geo_log::GeoTreeLog *tree_log = get_root_tree_log(*nmd);
1949 if (tree_log == nullptr) {
1950 return;
1951 }
1952 tree_log->ensure_existing_attributes();
1953 nmd->node_group->ensure_topology_cache();
1954
1955 Vector<const bNodeSocket *> sockets_to_check;
1956 if (data.is_output) {
1957 for (const bNode *node : nmd->node_group->nodes_by_type("NodeGroupOutput")) {
1958 for (const bNodeSocket *socket : node->input_sockets()) {
1959 if (socket->type == SOCK_GEOMETRY) {
1960 sockets_to_check.append(socket);
1961 }
1962 }
1963 }
1964 }
1965 else {
1966 for (const bNode *node : nmd->node_group->group_input_nodes()) {
1967 for (const bNodeSocket *socket : node->output_sockets()) {
1968 if (socket->type == SOCK_GEOMETRY) {
1969 sockets_to_check.append(socket);
1970 }
1971 }
1972 }
1973 }
1974 Set<StringRef> names;
1976 for (const bNodeSocket *socket : sockets_to_check) {
1977 const geo_log::ValueLog *value_log = tree_log->find_socket_value_log(*socket);
1978 if (value_log == nullptr) {
1979 continue;
1980 }
1981 if (const auto *geo_log = dynamic_cast<const geo_log::GeometryInfoLog *>(value_log)) {
1982 for (const geo_log::GeometryAttributeInfo &attribute : geo_log->attributes) {
1983 if (names.add(attribute.name)) {
1984 attributes.append(&attribute);
1985 }
1986 }
1987 }
1988 }
1989 ui::attribute_search_add_items(str, data.is_output, attributes.as_span(), items, is_first);
1990}
1991
1992static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
1993{
1994 if (item_v == nullptr) {
1995 return;
1996 }
1997 AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v);
1998 const auto &item = *static_cast<const geo_log::GeometryAttributeInfo *>(item_v);
2000 if (nmd == nullptr) {
2001 return;
2002 }
2003
2004 const std::string attribute_prop_name = data.socket_identifier +
2005 nodes::input_attribute_name_suffix();
2007 attribute_prop_name.c_str());
2008 IDP_AssignString(&name_property, item.name.c_str());
2009
2010 ED_undo_push(C, "Assign Attribute Name");
2011}
2012
2014 uiLayout *layout,
2015 const NodesModifierData &nmd,
2016 PointerRNA *md_ptr,
2017 const StringRefNull rna_path_attribute_name,
2018 const bNodeTreeInterfaceSocket &socket,
2019 const bool is_output)
2020{
2021 if (!nmd.runtime->eval_log) {
2022 uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), UI_ITEM_NONE, "", ICON_NONE);
2023 return;
2024 }
2025
2026 uiBlock *block = uiLayoutGetBlock(layout);
2027 uiBut *but = uiDefIconTextButR(block,
2029 0,
2030 ICON_NONE,
2031 "",
2032 0,
2033 0,
2034 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
2035 UI_UNIT_Y,
2036 md_ptr,
2037 rna_path_attribute_name.c_str(),
2038 0,
2039 0.0f,
2040 0.0f,
2041 socket.description);
2042
2043 const Object *object = ed::object::context_object(&C);
2044 BLI_assert(object != nullptr);
2045 if (object == nullptr) {
2046 return;
2047 }
2048
2049 AttributeSearchData *data = MEM_cnew<AttributeSearchData>(__func__);
2050 data->object_session_uid = object->id.session_uid;
2051 STRNCPY(data->modifier_name, nmd.modifier.name);
2052 STRNCPY(data->socket_identifier, socket.identifier);
2053 data->is_output = is_output;
2054
2058 nullptr,
2060 static_cast<void *>(data),
2061 true,
2062 nullptr,
2064 nullptr);
2065
2066 char *attribute_name = RNA_string_get_alloc(
2067 md_ptr, rna_path_attribute_name.c_str(), nullptr, 0, nullptr);
2068 const bool access_allowed = bke::allow_procedural_attribute_access(attribute_name);
2069 MEM_freeN(attribute_name);
2070 if (!access_allowed) {
2072 }
2073}
2074
2076 uiLayout *layout,
2077 const NodesModifierData &nmd,
2078 PointerRNA *md_ptr,
2079 const bNodeTreeInterfaceSocket &socket)
2080{
2081 const StringRefNull identifier = socket.identifier;
2082 const bke::bNodeSocketType *typeinfo = socket.socket_typeinfo();
2083 const eNodeSocketDatatype type = typeinfo ? eNodeSocketDatatype(typeinfo->type) : SOCK_CUSTOM;
2084 char socket_id_esc[MAX_NAME * 2];
2085 BLI_str_escape(socket_id_esc, identifier.c_str(), sizeof(socket_id_esc));
2086 const std::string rna_path = "[\"" + std::string(socket_id_esc) + "\"]";
2087 const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
2088 nodes::input_attribute_name_suffix() + "\"]";
2089
2090 /* We're handling this manually in this case. */
2091 uiLayoutSetPropDecorate(layout, false);
2092
2093 uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
2094 uiLayout *name_row = uiLayoutRow(split, false);
2096
2097 const std::optional<StringRef> attribute_name = nodes::input_attribute_name_get(
2098 *nmd.settings.properties, socket);
2099 if (type == SOCK_BOOLEAN && !attribute_name) {
2100 uiItemL(name_row, "", ICON_NONE);
2101 }
2102 else {
2103 uiItemL(name_row, socket.name ? IFACE_(socket.name) : "", ICON_NONE);
2104 }
2105
2106 uiLayout *prop_row = uiLayoutRow(split, true);
2107 if (type == SOCK_BOOLEAN) {
2108 uiLayoutSetPropSep(prop_row, false);
2110 }
2111
2112 if (attribute_name) {
2113 add_attribute_search_button(C, prop_row, nmd, md_ptr, rna_path_attribute_name, socket, false);
2114 uiItemL(layout, "", ICON_BLANK1);
2115 }
2116 else {
2117 const char *name = type == SOCK_BOOLEAN ? (socket.name ? IFACE_(socket.name) : "") : "";
2118 uiItemR(prop_row, md_ptr, rna_path.c_str(), UI_ITEM_NONE, name, ICON_NONE);
2119 uiItemDecoratorR(layout, md_ptr, rna_path.c_str(), -1);
2120 }
2121
2122 PointerRNA props;
2123 uiItemFullO(prop_row,
2124 "object.geometry_nodes_input_attribute_toggle",
2125 "",
2126 ICON_SPREADSHEET,
2127 nullptr,
2130 &props);
2131 RNA_string_set(&props, "modifier_name", nmd.modifier.name);
2132 RNA_string_set(&props, "input_name", socket.identifier);
2133}
2134
2135/* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
2136 * the node socket identifier for the property names, since they are unique, but also having
2137 * the correct label displayed in the UI. */
2139 uiLayout *layout,
2140 NodesModifierData *nmd,
2141 PointerRNA *bmain_ptr,
2142 PointerRNA *md_ptr,
2143 const bNodeTreeInterfaceSocket &socket)
2144{
2145 const StringRefNull identifier = socket.identifier;
2146 /* The property should be created in #MOD_nodes_update_interface with the correct type. */
2147 IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, identifier.c_str());
2148
2149 /* IDProperties can be removed with python, so there could be a situation where
2150 * there isn't a property for a socket or it doesn't have the correct type. */
2151 if (property == nullptr || !nodes::id_property_type_matches_socket(socket, *property)) {
2152 return;
2153 }
2154
2155 char socket_id_esc[MAX_NAME * 2];
2156 BLI_str_escape(socket_id_esc, identifier.c_str(), sizeof(socket_id_esc));
2157
2158 char rna_path[sizeof(socket_id_esc) + 4];
2159 SNPRINTF(rna_path, "[\"%s\"]", socket_id_esc);
2160
2161 uiLayout *row = uiLayoutRow(layout, true);
2162 uiLayoutSetPropDecorate(row, true);
2163
2164 const int input_index =
2165 const_cast<const bNodeTree *>(nmd->node_group)->interface_inputs().first_index(&socket);
2166
2167 /* Use #uiItemPointerR to draw pointer properties because #uiItemR would not have enough
2168 * information about what type of ID to select for editing the values. This is because
2169 * pointer IDProperties contain no information about their type. */
2170 const bke::bNodeSocketType *typeinfo = socket.socket_typeinfo();
2171 const eNodeSocketDatatype type = typeinfo ? eNodeSocketDatatype(typeinfo->type) : SOCK_CUSTOM;
2172 const char *name = socket.name ? IFACE_(socket.name) : "";
2173 switch (type) {
2174 case SOCK_OBJECT: {
2175 uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "objects", name, ICON_OBJECT_DATA);
2176 break;
2177 }
2178 case SOCK_COLLECTION: {
2180 row, md_ptr, rna_path, bmain_ptr, "collections", name, ICON_OUTLINER_COLLECTION);
2181 break;
2182 }
2183 case SOCK_MATERIAL: {
2184 uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "materials", name, ICON_MATERIAL);
2185 break;
2186 }
2187 case SOCK_TEXTURE: {
2188 uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "textures", name, ICON_TEXTURE);
2189 break;
2190 }
2191 case SOCK_IMAGE: {
2192 uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "images", name, ICON_IMAGE);
2193 break;
2194 }
2195 case SOCK_BOOLEAN: {
2196 if (is_layer_selection_field(socket)) {
2197 uiItemR(row, md_ptr, rna_path, UI_ITEM_NONE, name, ICON_NONE);
2198 break;
2199 }
2201 }
2202 default: {
2203 if (nodes::input_has_attribute_toggle(*nmd->node_group, input_index)) {
2204 add_attribute_search_or_value_buttons(C, row, *nmd, md_ptr, socket);
2205 }
2206 else {
2207 uiItemR(row, md_ptr, rna_path, UI_ITEM_NONE, name, ICON_NONE);
2208 }
2209 }
2210 }
2211 if (!nodes::input_has_attribute_toggle(*nmd->node_group, input_index)) {
2212 uiItemL(row, "", ICON_BLANK1);
2213 }
2214}
2215
2217 uiLayout *layout,
2218 const NodesModifierData &nmd,
2219 PointerRNA *md_ptr,
2220 const bNodeTreeInterfaceSocket &socket)
2221{
2222 const StringRefNull identifier = socket.identifier;
2223 char socket_id_esc[MAX_NAME * 2];
2224 BLI_str_escape(socket_id_esc, identifier.c_str(), sizeof(socket_id_esc));
2225 const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) +
2226 nodes::input_attribute_name_suffix() + "\"]";
2227
2228 uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
2229 uiLayout *name_row = uiLayoutRow(split, false);
2231 uiItemL(name_row, socket.name ? socket.name : "", ICON_NONE);
2232
2233 uiLayout *row = uiLayoutRow(split, true);
2234 add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, true);
2235}
2236
2238{
2239 for (const int i : IndexRange(nmd.panels_num)) {
2240 if (nmd.panels[i].id == id) {
2241 return &nmd.panels[i];
2242 }
2243 }
2244 return nullptr;
2245}
2246
2247static bool interace_panel_has_socket(const bNodeTreeInterfacePanel &interface_panel)
2248{
2249 for (const bNodeTreeInterfaceItem *item : interface_panel.items()) {
2250 if (item->item_type == NODE_INTERFACE_SOCKET) {
2251 return true;
2252 }
2253 if (item->item_type == NODE_INTERFACE_PANEL) {
2254 if (interace_panel_has_socket(*reinterpret_cast<const bNodeTreeInterfacePanel *>(item))) {
2255 return true;
2256 }
2257 }
2258 }
2259 return false;
2260}
2261
2263 uiLayout *layout,
2264 PointerRNA *modifier_ptr,
2265 NodesModifierData &nmd,
2266 const bNodeTreeInterfacePanel &interface_panel)
2267{
2268 Main *bmain = CTX_data_main(C);
2269 PointerRNA bmain_ptr = RNA_main_pointer_create(bmain);
2270
2271 for (const bNodeTreeInterfaceItem *item : interface_panel.items()) {
2272 if (item->item_type == NODE_INTERFACE_PANEL) {
2273 const auto &sub_interface_panel = *reinterpret_cast<const bNodeTreeInterfacePanel *>(item);
2274 if (!interace_panel_has_socket(sub_interface_panel)) {
2275 continue;
2276 }
2277 NodesModifierPanel *panel = find_panel_by_id(nmd, sub_interface_panel.identifier);
2278 PointerRNA panel_ptr = RNA_pointer_create(
2279 modifier_ptr->owner_id, &RNA_NodesModifierPanel, panel);
2280 PanelLayout panel_layout = uiLayoutPanelProp(C, layout, &panel_ptr, "is_open");
2281 uiItemL(panel_layout.header, IFACE_(sub_interface_panel.name), ICON_NONE);
2283 panel_layout.header,
2284 [](bContext * /*C*/, void *panel_arg, const char * /*tip*/) -> std::string {
2285 const auto *panel = static_cast<bNodeTreeInterfacePanel *>(panel_arg);
2286 return StringRef(panel->description);
2287 },
2288 const_cast<bNodeTreeInterfacePanel *>(&sub_interface_panel),
2289 nullptr,
2290 nullptr);
2291 if (panel_layout.body) {
2292 draw_interface_panel_content(C, panel_layout.body, modifier_ptr, nmd, sub_interface_panel);
2293 }
2294 }
2295 else {
2296 const auto &interface_socket = *reinterpret_cast<const bNodeTreeInterfaceSocket *>(item);
2297 if (interface_socket.flag & NODE_INTERFACE_SOCKET_INPUT) {
2298 if (!(interface_socket.flag & NODE_INTERFACE_SOCKET_HIDE_IN_MODIFIER)) {
2299 draw_property_for_socket(*C, layout, &nmd, &bmain_ptr, modifier_ptr, interface_socket);
2300 }
2301 }
2302 }
2303 }
2304}
2305
2307{
2308 if (!nmd.node_group) {
2309 return false;
2310 }
2311 for (const bNodeTreeInterfaceSocket *interface_socket : nmd.node_group->interface_outputs()) {
2312 const bke::bNodeSocketType *typeinfo = interface_socket->socket_typeinfo();
2313 const eNodeSocketDatatype type = typeinfo ? eNodeSocketDatatype(typeinfo->type) : SOCK_CUSTOM;
2314 if (nodes::socket_type_has_attribute_toggle(type)) {
2315 return true;
2316 }
2317 }
2318 return false;
2319}
2320
2322 uiLayout *layout,
2323 const NodesModifierData &nmd,
2324 PointerRNA *ptr)
2325{
2326 if (nmd.node_group != nullptr && nmd.settings.properties != nullptr) {
2327 for (const bNodeTreeInterfaceSocket *socket : nmd.node_group->interface_outputs()) {
2328 const bke::bNodeSocketType *typeinfo = socket->socket_typeinfo();
2329 const eNodeSocketDatatype type = typeinfo ? eNodeSocketDatatype(typeinfo->type) :
2331 if (nodes::socket_type_has_attribute_toggle(type)) {
2332 draw_property_for_output_socket(*C, layout, nmd, ptr, *socket);
2333 }
2334 }
2335 }
2336}
2337
2338static void draw_bake_panel(uiLayout *layout, PointerRNA *modifier_ptr)
2339{
2340 uiLayout *col = uiLayoutColumn(layout, false);
2341 uiLayoutSetPropSep(col, true);
2343 uiItemR(col, modifier_ptr, "bake_target", UI_ITEM_NONE, nullptr, ICON_NONE);
2344 uiItemR(col, modifier_ptr, "bake_directory", UI_ITEM_NONE, IFACE_("Bake Path"), ICON_NONE);
2345}
2346
2348{
2349 geo_log::GeoTreeLog *tree_log = get_root_tree_log(nmd);
2350 if (tree_log == nullptr) {
2351 return;
2352 }
2353
2354 tree_log->ensure_used_named_attributes();
2355 const Map<StringRefNull, geo_log::NamedAttributeUsage> &usage_by_attribute =
2356 tree_log->used_named_attributes;
2357
2358 if (usage_by_attribute.is_empty()) {
2359 uiItemL(layout, RPT_("No named attributes used"), ICON_INFO);
2360 return;
2361 }
2362
2363 struct NameWithUsage {
2364 StringRefNull name;
2366 };
2367
2368 Vector<NameWithUsage> sorted_used_attribute;
2369 for (auto &&item : usage_by_attribute.items()) {
2370 sorted_used_attribute.append({item.key, item.value});
2371 }
2372 std::sort(sorted_used_attribute.begin(),
2373 sorted_used_attribute.end(),
2374 [](const NameWithUsage &a, const NameWithUsage &b) {
2375 return BLI_strcasecmp_natural(a.name.c_str(), b.name.c_str()) < 0;
2376 });
2377
2378 for (const NameWithUsage &attribute : sorted_used_attribute) {
2379 const StringRefNull attribute_name = attribute.name;
2380 const geo_log::NamedAttributeUsage usage = attribute.usage;
2381
2382 /* #uiLayoutRowWithHeading doesn't seem to work in this case. */
2383 uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
2384
2385 std::stringstream ss;
2386 Vector<std::string> usages;
2387 if ((usage & geo_log::NamedAttributeUsage::Read) != geo_log::NamedAttributeUsage::None) {
2388 usages.append(IFACE_("Read"));
2389 }
2390 if ((usage & geo_log::NamedAttributeUsage::Write) != geo_log::NamedAttributeUsage::None) {
2391 usages.append(IFACE_("Write"));
2392 }
2393 if ((usage & geo_log::NamedAttributeUsage::Remove) != geo_log::NamedAttributeUsage::None) {
2395 }
2396 for (const int i : usages.index_range()) {
2397 ss << usages[i];
2398 if (i < usages.size() - 1) {
2399 ss << ", ";
2400 }
2401 }
2402
2403 uiLayout *row = uiLayoutRow(split, false);
2405 uiLayoutSetActive(row, false);
2406 uiItemL(row, ss.str().c_str(), ICON_NONE);
2407
2408 row = uiLayoutRow(split, false);
2409 uiItemL(row, attribute_name.c_str(), ICON_NONE);
2410 }
2411}
2412
2413static void draw_manage_panel(const bContext *C,
2414 uiLayout *layout,
2415 PointerRNA *modifier_ptr,
2416 NodesModifierData &nmd)
2417{
2418 if (uiLayout *panel_layout = uiLayoutPanelProp(
2419 C, layout, modifier_ptr, "open_bake_panel", IFACE_("Bake")))
2420 {
2421 draw_bake_panel(panel_layout, modifier_ptr);
2422 }
2423 if (uiLayout *panel_layout = uiLayoutPanelProp(
2424 C, layout, modifier_ptr, "open_named_attributes_panel", IFACE_("Named Attributes")))
2425 {
2426 draw_named_attributes_panel(panel_layout, nmd);
2427 }
2428}
2429
2430static void draw_warnings(const bContext *C,
2431 const NodesModifierData &nmd,
2432 uiLayout *layout,
2433 PointerRNA *md_ptr)
2434{
2435 using namespace geo_log;
2436 GeoTreeLog *tree_log = get_root_tree_log(nmd);
2437 if (!tree_log) {
2438 return;
2439 }
2440 tree_log->ensure_node_warnings(nmd.node_group);
2441 const int warnings_num = tree_log->all_warnings.size();
2442 if (warnings_num == 0) {
2443 return;
2444 }
2445 PanelLayout panel = uiLayoutPanelProp(C, layout, md_ptr, "open_warnings_panel");
2446 uiItemL(panel.header, fmt::format(IFACE_("Warnings ({})"), warnings_num).c_str(), ICON_NONE);
2447 if (!panel.body) {
2448 return;
2449 }
2450 Vector<const NodeWarning *> warnings(tree_log->all_warnings.size());
2451 for (const int i : warnings.index_range()) {
2452 warnings[i] = &tree_log->all_warnings[i];
2453 }
2454 std::sort(warnings.begin(), warnings.end(), [](const NodeWarning *a, const NodeWarning *b) {
2455 const int severity_a = node_warning_type_severity(a->type);
2456 const int severity_b = node_warning_type_severity(b->type);
2457 if (severity_a > severity_b) {
2458 return true;
2459 }
2460 if (severity_a < severity_b) {
2461 return false;
2462 }
2463 return BLI_strcasecmp_natural(a->message.c_str(), b->message.c_str()) < 0;
2464 });
2465
2466 uiLayout *col = uiLayoutColumn(panel.body, false);
2467 for (const NodeWarning *warning : warnings) {
2468 const int icon = node_warning_type_icon(warning->type);
2469 uiItemL(col, warning->message.c_str(), icon);
2470 }
2471}
2472
2473static void panel_draw(const bContext *C, Panel *panel)
2474{
2475 uiLayout *layout = panel->layout;
2476
2478 NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
2479
2480 uiLayoutSetPropSep(layout, true);
2481 /* Decorators are added manually for supported properties because the
2482 * attribute/value toggle requires a manually built layout anyway. */
2483 uiLayoutSetPropDecorate(layout, false);
2484
2486 const char *newop = (nmd->node_group == nullptr) ? "node.new_geometry_node_group_assign" :
2487 "object.geometry_node_tree_copy_assign";
2488 uiTemplateID(layout, C, ptr, "node_group", newop, nullptr, nullptr);
2489 }
2490
2491 if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
2492 nmd->node_group->ensure_interface_cache();
2494 }
2495
2496 modifier_panel_end(layout, ptr);
2497
2498 draw_warnings(C, *nmd, layout, ptr);
2499
2500 if (has_output_attribute(*nmd)) {
2501 if (uiLayout *panel_layout = uiLayoutPanelProp(
2502 C, layout, ptr, "open_output_attributes_panel", IFACE_("Output Attributes")))
2503 {
2504 draw_output_attributes_panel(C, panel_layout, *nmd, ptr);
2505 }
2506 }
2507 if (uiLayout *panel_layout = uiLayoutPanelProp(
2508 C, layout, ptr, "open_manage_panel", IFACE_("Manage")))
2509 {
2510 draw_manage_panel(C, panel_layout, ptr, *nmd);
2511 }
2512}
2513
2514static void panel_register(ARegionType *region_type)
2515{
2516 using namespace blender;
2518}
2519
2520static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
2521{
2522 const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
2523
2524 BLO_write_struct(writer, NodesModifierData, nmd);
2525
2526 BLO_write_string(writer, nmd->bake_directory);
2527
2528 if (nmd->settings.properties != nullptr) {
2530 if (!BLO_write_is_undo(writer)) {
2531 /* Boolean properties are added automatically for boolean node group inputs. Integer
2532 * properties are automatically converted to boolean sockets where applicable as well.
2533 * However, boolean properties will crash old versions of Blender, so convert them to integer
2534 * properties for writing. The actual value is stored in the same variable for both types */
2536 if (prop->type == IDP_BOOLEAN) {
2537 boolean_props.add_new(prop, reinterpret_cast<IDPropertyUIDataBool *>(prop->ui_data));
2538 prop->type = IDP_INT;
2539 prop->ui_data = nullptr;
2540 }
2541 }
2542 }
2543
2544 /* Note that the property settings are based on the socket type info
2545 * and don't necessarily need to be written, but we can't just free them. */
2546 IDP_BlendWrite(writer, nmd->settings.properties);
2547
2549 for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
2550 BLO_write_string(writer, bake.directory);
2551
2553 writer, NodesModifierDataBlock, bake.data_blocks_num, bake.data_blocks);
2554 for (const NodesModifierDataBlock &item : Span(bake.data_blocks, bake.data_blocks_num)) {
2555 BLO_write_string(writer, item.id_name);
2556 BLO_write_string(writer, item.lib_name);
2557 }
2558 if (bake.packed) {
2561 writer, NodesModifierBakeFile, bake.packed->meta_files_num, bake.packed->meta_files);
2563 writer, NodesModifierBakeFile, bake.packed->blob_files_num, bake.packed->blob_files);
2564 const auto write_bake_file = [&](const NodesModifierBakeFile &bake_file) {
2565 BLO_write_string(writer, bake_file.name);
2566 if (bake_file.packed_file) {
2567 BKE_packedfile_blend_write(writer, bake_file.packed_file);
2568 }
2569 };
2570 for (const NodesModifierBakeFile &meta_file :
2571 Span{bake.packed->meta_files, bake.packed->meta_files_num})
2572 {
2573 write_bake_file(meta_file);
2574 }
2575 for (const NodesModifierBakeFile &blob_file :
2576 Span{bake.packed->blob_files, bake.packed->blob_files_num})
2577 {
2578 write_bake_file(blob_file);
2579 }
2580 }
2581 }
2583
2584 if (!BLO_write_is_undo(writer)) {
2586 if (prop->type == IDP_INT) {
2587 if (IDPropertyUIDataBool **ui_data = boolean_props.lookup_ptr(prop)) {
2588 prop->type = IDP_BOOLEAN;
2589 if (ui_data) {
2590 prop->ui_data = reinterpret_cast<IDPropertyUIData *>(*ui_data);
2591 }
2592 }
2593 }
2594 }
2595 }
2596 }
2597}
2598
2599static void blend_read(BlendDataReader *reader, ModifierData *md)
2600{
2601 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
2602 BLO_read_string(reader, &nmd->bake_directory);
2603 if (nmd->node_group == nullptr) {
2604 nmd->settings.properties = nullptr;
2605 }
2606 else {
2608 IDP_BlendDataRead(reader, &nmd->settings.properties);
2609 }
2610
2612
2613 if (nmd->bakes_num > 0 && nmd->bakes == nullptr) {
2614 /* This case generally shouldn't be allowed to happen. However, there is a bug report with a
2615 * corrupted .blend file (#123974) that triggers this case. Unfortunately, it's not clear how
2616 * that could have happened. For now, handle this case more gracefully in release builds, while
2617 * still crashing in debug builds. */
2618 nmd->bakes_num = 0;
2620 }
2621
2622 for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
2623 BLO_read_string(reader, &bake.directory);
2624
2625 BLO_read_struct_array(reader, NodesModifierDataBlock, bake.data_blocks_num, &bake.data_blocks);
2626 for (NodesModifierDataBlock &data_block : MutableSpan(bake.data_blocks, bake.data_blocks_num))
2627 {
2628 BLO_read_string(reader, &data_block.id_name);
2629 BLO_read_string(reader, &data_block.lib_name);
2630 }
2631
2633 if (bake.packed) {
2635 reader, NodesModifierBakeFile, bake.packed->meta_files_num, &bake.packed->meta_files);
2637 reader, NodesModifierBakeFile, bake.packed->blob_files_num, &bake.packed->blob_files);
2638 const auto read_bake_file = [&](NodesModifierBakeFile &bake_file) {
2639 BLO_read_string(reader, &bake_file.name);
2640 if (bake_file.packed_file) {
2641 BKE_packedfile_blend_read(reader, &bake_file.packed_file, "");
2642 }
2643 };
2644 for (NodesModifierBakeFile &meta_file :
2645 MutableSpan{bake.packed->meta_files, bake.packed->meta_files_num})
2646 {
2647 read_bake_file(meta_file);
2648 }
2649 for (NodesModifierBakeFile &blob_file :
2650 MutableSpan{bake.packed->blob_files, bake.packed->blob_files_num})
2651 {
2652 read_bake_file(blob_file);
2653 }
2654 }
2655 }
2657
2658 nmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
2659 nmd->runtime->cache = std::make_shared<bake::ModifierCache>();
2660}
2661
2662static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
2663{
2664 const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
2665 NodesModifierData *tnmd = reinterpret_cast<NodesModifierData *>(target);
2666
2668
2669 if (nmd->bakes) {
2670 tnmd->bakes = static_cast<NodesModifierBake *>(MEM_dupallocN(nmd->bakes));
2671 for (const int i : IndexRange(nmd->bakes_num)) {
2672 NodesModifierBake &bake = tnmd->bakes[i];
2673 if (bake.directory) {
2674 bake.directory = BLI_strdup(bake.directory);
2675 }
2676 if (bake.data_blocks) {
2677 bake.data_blocks = static_cast<NodesModifierDataBlock *>(MEM_dupallocN(bake.data_blocks));
2678 for (const int i : IndexRange(bake.data_blocks_num)) {
2679 NodesModifierDataBlock &data_block = bake.data_blocks[i];
2680 if (data_block.id_name) {
2681 data_block.id_name = BLI_strdup(data_block.id_name);
2682 }
2683 if (data_block.lib_name) {
2684 data_block.lib_name = BLI_strdup(data_block.lib_name);
2685 }
2686 }
2687 }
2688 if (bake.packed) {
2689 bake.packed = static_cast<NodesModifierPackedBake *>(MEM_dupallocN(bake.packed));
2690 const auto copy_bake_files_inplace = [](NodesModifierBakeFile **bake_files,
2691 const int bake_files_num) {
2692 if (!*bake_files) {
2693 return;
2694 }
2695 *bake_files = static_cast<NodesModifierBakeFile *>(MEM_dupallocN(*bake_files));
2696 for (NodesModifierBakeFile &bake_file : MutableSpan{*bake_files, bake_files_num}) {
2697 bake_file.name = BLI_strdup_null(bake_file.name);
2698 if (bake_file.packed_file) {
2699 bake_file.packed_file = BKE_packedfile_duplicate(bake_file.packed_file);
2700 }
2701 }
2702 };
2703 copy_bake_files_inplace(&bake.packed->meta_files, bake.packed->meta_files_num);
2704 copy_bake_files_inplace(&bake.packed->blob_files, bake.packed->blob_files_num);
2705 }
2706 }
2707 }
2708
2709 if (nmd->panels) {
2710 tnmd->panels = static_cast<NodesModifierPanel *>(MEM_dupallocN(nmd->panels));
2711 }
2712
2713 tnmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
2714
2716 /* Share the simulation cache between the original and evaluated modifier. */
2717 tnmd->runtime->cache = nmd->runtime->cache;
2718 /* Keep bake path in the evaluated modifier. */
2719 tnmd->bake_directory = nmd->bake_directory ? BLI_strdup(nmd->bake_directory) : nullptr;
2720 }
2721 else {
2722 tnmd->runtime->cache = std::make_shared<bake::ModifierCache>();
2723 /* Clear the bake path when duplicating. */
2724 tnmd->bake_directory = nullptr;
2725 }
2726
2727 if (nmd->settings.properties != nullptr) {
2729 }
2730}
2731
2733{
2734 const auto free_packed_files = [](NodesModifierBakeFile *files, const int files_num) {
2735 for (NodesModifierBakeFile &file : MutableSpan{files, files_num}) {
2736 MEM_SAFE_FREE(file.name);
2737 if (file.packed_file) {
2738 BKE_packedfile_free(file.packed_file);
2739 }
2740 }
2741 MEM_SAFE_FREE(files);
2742 };
2743 free_packed_files(packed_bake->meta_files, packed_bake->meta_files_num);
2744 free_packed_files(packed_bake->blob_files, packed_bake->blob_files_num);
2745 MEM_SAFE_FREE(packed_bake);
2746}
2747
2748static void free_data(ModifierData *md)
2749{
2750 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
2751 if (nmd->settings.properties != nullptr) {
2753 nmd->settings.properties = nullptr;
2754 }
2755
2756 for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
2757 MEM_SAFE_FREE(bake.directory);
2758
2759 for (NodesModifierDataBlock &data_block : MutableSpan(bake.data_blocks, bake.data_blocks_num))
2760 {
2761 MEM_SAFE_FREE(data_block.id_name);
2762 MEM_SAFE_FREE(data_block.lib_name);
2763 }
2764 MEM_SAFE_FREE(bake.data_blocks);
2765
2766 if (bake.packed) {
2768 }
2769 }
2770 MEM_SAFE_FREE(nmd->bakes);
2771
2772 MEM_SAFE_FREE(nmd->panels);
2773
2775 MEM_delete(nmd->runtime);
2776}
2777
2778static void required_data_mask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
2779{
2780 /* We don't know what the node tree will need. If there are vertex groups, it is likely that the
2781 * node tree wants to access them. */
2782 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
2783 r_cddata_masks->vmask |= CD_MASK_PROP_ALL;
2784}
2785
2786} // namespace blender
2787
2789 /*idname*/ "GeometryNodes",
2790 /*name*/ N_("GeometryNodes"),
2791 /*struct_name*/ "NodesModifierData",
2792 /*struct_size*/ sizeof(NodesModifierData),
2793 /*srna*/ &RNA_NodesModifier,
2795 /*flags*/
2796 static_cast<ModifierTypeFlag>(
2800 /*icon*/ ICON_GEOMETRY_NODES,
2801
2802 /*copy_data*/ blender::copy_data,
2803
2804 /*deform_verts*/ nullptr,
2805 /*deform_matrices*/ nullptr,
2806 /*deform_verts_EM*/ nullptr,
2807 /*deform_matrices_EM*/ nullptr,
2808 /*modify_mesh*/ blender::modify_mesh,
2809 /*modify_geometry_set*/ blender::modify_geometry_set,
2810
2811 /*init_data*/ blender::init_data,
2812 /*required_data_mask*/ blender::required_data_mask,
2813 /*free_data*/ blender::free_data,
2814 /*is_disabled*/ blender::is_disabled,
2815 /*update_depsgraph*/ blender::update_depsgraph,
2816 /*depends_on_time*/ blender::depends_on_time,
2817 /*depends_on_normals*/ nullptr,
2818 /*foreach_ID_link*/ blender::foreach_ID_link,
2819 /*foreach_tex_link*/ blender::foreach_tex_link,
2820 /*free_runtime_data*/ nullptr,
2821 /*panel_register*/ blender::panel_register,
2822 /*blend_write*/ blender::blend_write,
2823 /*blend_read*/ blender::blend_read,
2824 /*foreach_cache*/ nullptr,
2825};
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
@ CD_SET_DEFAULT
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
void IDP_AssignString(IDProperty *prop, const char *st) ATTR_NONNULL()
Definition idprop.cc:431
void IDP_foreach_property(IDProperty *id_property_root, int type_filter, blender::FunctionRef< void(IDProperty *id_property)> callback)
IDProperty * IDP_GetPropertyFromGroup(const IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:763
#define IDP_BlendDataRead(reader, prop)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1227
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:843
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1437
void IDP_FreeProperty_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1221
ID * BKE_libblock_find_session_uid(Main *bmain, short type, uint32_t session_uid)
Definition lib_id.cc:1675
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
void id_us_min(ID *id)
Definition lib_id.cc:359
@ IDWALK_CB_USER
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
void(*)(void *user_data, Object *ob, ModifierData *md, const PointerRNA *ptr, PropertyRNA *texture_prop) TexWalkFunc
ModifierTypeFlag
@ eModifierTypeFlag_AcceptsCVs
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
ModifierData * BKE_modifier_get_original(const Object *object, ModifierData *md)
ModifierData * BKE_modifiers_findby_name(const Object *ob, const char *name)
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
@ MOD_APPLY_TO_ORIGINAL
@ MOD_APPLY_ORCO
General operations, lookup, etc. for blender objects.
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p, blender::StringRefNull filepath)
General operations for point clouds.
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
WorkSpace * BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:562
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:87
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
#define LISTBASE_FOREACH(type, var, list)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.c:45
int char char int int int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define BLO_read_struct(reader, struct_name, ptr_p)
bool BLO_write_is_undo(BlendWriter *writer)
#define RPT_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:318
void DEG_add_scene_camera_relation(DepsNodeHandle *node_handle, Scene *scene, eDepsObjectComponentType component, const char *description)
void DEG_add_generic_id_relation(DepsNodeHandle *node_handle, ID *id, const char *description)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
@ DEG_SCENE_COMP_PARAMETERS
void DEG_add_customdata_mask(DepsNodeHandle *handle, Object *object, const CustomData_MeshMasks *masks)
void DEG_add_collection_geometry_relation(DepsNodeHandle *node_handle, Collection *collection, const char *description)
void DEG_add_scene_relation(DepsNodeHandle *node_handle, Scene *scene, eDepsSceneComponentType component, const char *description)
bool DEG_object_has_geometry_component(Object *object)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
void DEG_add_collection_geometry_customdata_mask(DepsNodeHandle *node_handle, Collection *collection, const CustomData_MeshMasks *masks)
void DEG_add_node_tree_output_relation(DepsNodeHandle *node_handle, bNodeTree *node_tree, const char *description)
float DEG_get_ctime(const Depsgraph *graph)
Main * DEG_get_bmain(const Depsgraph *graph)
Scene * DEG_get_input_scene(const Depsgraph *graph)
Object * DEG_get_original_object(Object *object)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
ID_Type
@ ID_TE
@ ID_IM
@ ID_GR
@ ID_OB
@ IDP_BOOLEAN
@ IDP_INT
@ IDP_TYPE_FILTER_ID
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)
#define MAX_NAME
Definition DNA_defs.h:50
@ eModifierFlag_UserModified
@ NODES_MODIFIER_PANEL_WARNINGS
struct NodesModifierData NodesModifierData
@ NODES_MODIFIER_PANEL_OPEN
@ NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR
@ eModifierType_Nodes
@ NODES_MODIFIER_BAKE_MODE_STILL
@ NODES_MODIFIER_BAKE_MODE_ANIMATION
@ NODE_INTERFACE_PANEL_DEFAULT_CLOSED
@ NODE_INTERFACE_SOCKET_HIDE_IN_MODIFIER
eNodeSocketDatatype
@ SOCK_TEXTURE
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_MATRIX
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_CUSTOM
@ SOCK_GEOMETRY
@ SOCK_OBJECT
Object is a sort of wrapper for general info.
@ OB_FLAG_USE_SIMULATION_CACHE
@ OB_EMPTY
@ OB_CURVES
#define FPS
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_VIEW3D
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
static bool is_disabled
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
static void panel_register(ARegionType *region_type)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void blend_read(BlendDataReader *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_array.cc:862
static void free_data(ModifierData *md)
Definition MOD_bevel.cc:277
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
Definition MOD_bevel.cc:440
static bool depends_on_time(Scene *, ModifierData *)
Definition MOD_build.cc:48
static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, blender::bke::GeometrySet *geometry_set)
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
Definition MOD_nodes.cc:453
ModifierTypeInfo modifierType_Nodes
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_LAYOUT_ALIGN_RIGHT
@ UI_LAYOUT_ALIGN_EXPAND
void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
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)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
void uiLayoutSetTooltipFunc(uiLayout *layout, uiButToolTipFunc func, void *arg, uiCopyArgFunc copy_arg, uiFreeArgFunc free_arg)
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
uiBut * uiDefIconTextButR(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, PointerRNA *ptr, const char *propname, int index, float min, float max, const char *tip)
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
PanelLayout uiLayoutPanelProp(const bContext *C, uiLayout *layout, PointerRNA *open_prop_owner, const char *open_prop_name)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter=UI_TEMPLATE_ID_FILTER_ALL, bool live_icon=false, const char *text=nullptr)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
#define UI_UNIT_X
@ UI_BTYPE_SEARCH_MENU
void UI_but_flag_enable(uiBut *but, int flag)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_BUT_REDALERT
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
volatile int lock
const ComputeContext * current() const
const ComputeContext * parent() const
const ComputeContextHash & hash() const
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
SubIterator begin() const
Definition BLI_map.hh:730
SubIterator end() const
Definition BLI_map.hh:740
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
KeyIterator keys() const
Definition BLI_map.hh:837
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:301
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
ValueIterator values() const
Definition BLI_map.hh:846
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:582
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
ItemIterator items() const
Definition BLI_map.hh:864
bool is_empty() const
Definition BLI_map.hh:937
bool contains(const Key &key) const
Definition BLI_map.hh:329
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:551
ID * lookup_or_remember_missing(const bake::BakeDataBlockID &key) override
Definition MOD_nodes.cc:915
Map< bake::BakeDataBlockID, ID * > old_mappings
Definition MOD_nodes.cc:912
Map< bake::BakeDataBlockID, ID * > new_mappings
Definition MOD_nodes.cc:913
nodes::BakeNodeBehavior * get(const int id) const
NodesModifierBakeParams(NodesModifierData &nmd, const ModifierEvalContext &ctx)
Map< int, std::unique_ptr< DataPerNode > > data_by_node_id
NodesModifierSimulationParams(NodesModifierData &nmd, const ModifierEvalContext &ctx)
void input_pass_through(nodes::SimulationZoneBehavior &zone_behavior) const
void output_store_frame_cache(bake::SimulationNodeCache &node_cache, nodes::SimulationZoneBehavior &zone_behavior) const
void store_as_prev_items(bake::SimulationNodeCache &node_cache, nodes::SimulationZoneBehavior &zone_behavior) const
void read_single(const int frame_index, bake::SimulationNodeCache &node_cache, nodes::SimulationZoneBehavior &zone_behavior) const
void read_interpolated(const int prev_frame_index, const int next_frame_index, bake::SimulationNodeCache &node_cache, nodes::SimulationZoneBehavior &zone_behavior) const
void read_from_cache(const BakeFrameIndices &frame_indices, bake::SimulationNodeCache &node_cache, nodes::SimulationZoneBehavior &zone_behavior) const
void output_pass_through(nodes::SimulationZoneBehavior &zone_behavior) const
Map< int, std::unique_ptr< DataPerZone > > data_by_zone_id
nodes::SimulationZoneBehavior * get(const int zone_id) const override
void init_simulation_info(const int zone_id, nodes::SimulationZoneBehavior &zone_behavior, NodesModifierBakeDataBlockMap &data_block_map) const
bool contains(const Key &key) const
Definition BLI_set.hh:291
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
constexpr const char * c_str() const
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
void extend(Span< T > array)
Span< T > as_span() const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
Vector< std::unique_ptr< bNodeTreeZone > > zones
Map< StringRefNull, NamedAttributeUsage > used_named_attributes
ValueLog * find_socket_value_log(const bNodeSocket &query_socket)
local_group_size(16, 16) .push_constant(Type b
OperationNode * node
const Depsgraph * depsgraph
KDTree_3d * tree
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
uint col
static void update_depsgraph(tGraphSliderOp *gso)
#define GS(x)
Definition iris.cc:202
static const char * modifier_name[LS_MODIFIER_NUM]
Definition linestyle.cc:680
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
static ulong state[N]
int64_t find_predicate_begin(Iterator begin, Iterator end, Predicate &&predicate)
std::optional< SubFrame > file_name_to_frame(const StringRef file_name)
std::optional< BakePath > get_node_bake_path(const Main &bmain, const Object &object, const NodesModifierData &nmd, int node_id)
std::optional< IndexRange > get_node_bake_frame_range(const Scene &scene, const Object &object, const NodesModifierData &nmd, int node_id)
Vector< MetaFile > find_sorted_meta_files(const StringRefNull meta_dir)
std::optional< BakeState > deserialize_bake(std::istream &stream, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
void add(Depsgraph &depsgraph, std::function< void()> fn)
bool add_compute_context_for_viewer_path_elem(const ViewerPathElem &elem, ComputeContextBuilder &compute_context_builder)
std::optional< ViewerPathForGeometryNodesViewer > parse_geometry_nodes_viewer(const ViewerPath &viewer_path)
void foreach_active_gizmo_in_modifier(const Object &object, const NodesModifierData &nmd, const wmWindowManager &wm, ComputeContextBuilder &compute_context_builder, const ForeachGizmoInModifierFn fn)
void foreach_compute_context_on_gizmo_path(const ComputeContext &gizmo_context, const bNode &gizmo_node, const bNodeSocket &gizmo_socket, FunctionRef< void(const ComputeContext &context)> fn)
bool id_property_type_matches_socket(const bNodeTreeInterfaceSocket &socket, const IDProperty &property, const bool use_name_for_ids)
const GeometryNodesLazyFunctionGraphInfo * ensure_geometry_nodes_lazy_function_graph(const bNodeTree &btree)
static bool depends_on_time(Scene *, ModifierData *md)
static bool logging_enabled(const ModifierEvalContext *ctx)
Definition MOD_nodes.cc:298
static void find_side_effect_nodes_for_baking(const NodesModifierData &nmd, const ModifierEvalContext &ctx, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
Definition MOD_nodes.cc:742
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void add_attribute_search_button(const bContext &C, uiLayout *layout, const NodesModifierData &nmd, PointerRNA *md_ptr, const StringRefNull rna_path_attribute_name, const bNodeTreeInterfaceSocket &socket, const bool is_output)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
static void draw_bake_panel(uiLayout *layout, PointerRNA *modifier_ptr)
static void init_data(ModifierData *md)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void find_side_effect_nodes_for_nested_node(const NodesModifierData &nmd, const int root_nested_node_id, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
Definition MOD_nodes.cc:695
static void check_property_socket_sync(const Object *ob, ModifierData *md)
Definition MOD_nodes.cc:859
static void draw_named_attributes_panel(uiLayout *layout, NodesModifierData &nmd)
static NodesModifierData * get_modifier_data(Main &bmain, const wmWindowManager &wm, const AttributeSearchData &data)
static BakeFrameIndices get_bake_frame_indices(const Span< std::unique_ptr< bake::FrameCache > > frame_caches, const SubFrame frame)
Definition MOD_nodes.cc:963
static void add_missing_data_block_mappings(NodesModifierBake &bake, const Span< bake::BakeDataBlockID > missing, FunctionRef< ID *(const bake::BakeDataBlockID &)> get_data_block)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet *geometry_set)
static void add_attribute_search_or_value_buttons(const bContext &C, uiLayout *layout, const NodesModifierData &nmd, PointerRNA *md_ptr, const bNodeTreeInterfaceSocket &socket)
static bool interace_panel_has_socket(const bNodeTreeInterfacePanel &interface_panel)
static void find_side_effect_nodes_for_viewer_path(const ViewerPath &viewer_path, const NodesModifierData &nmd, const ModifierEvalContext &ctx, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
Definition MOD_nodes.cc:663
static void draw_output_attributes_panel(const bContext *C, uiLayout *layout, const NodesModifierData &nmd, PointerRNA *ptr)
void nodes_modifier_data_block_destruct(NodesModifierDataBlock *data_block, const bool do_id_user)
static void draw_property_for_output_socket(const bContext &C, uiLayout *layout, const NodesModifierData &nmd, PointerRNA *md_ptr, const bNodeTreeInterfaceSocket &socket)
static const CustomData_MeshMasks dependency_data_mask
Definition MOD_nodes.cc:132
static void free_data(ModifierData *md)
static void update_bakes_from_node_group(NodesModifierData &nmd)
Definition MOD_nodes.cc:354
static void panel_register(ARegionType *region_type)
static void find_side_effect_nodes_for_active_gizmos(const NodesModifierData &nmd, const ModifierEvalContext &ctx, const wmWindowManager &wm, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes, Set< ComputeContextHash > &r_socket_log_contexts)
Definition MOD_nodes.cc:762
static void add_data_block_items_writeback(const ModifierEvalContext &ctx, NodesModifierData &nmd_eval, NodesModifierData &nmd_orig, NodesModifierSimulationParams &simulation_params, NodesModifierBakeParams &bake_params)
static bool has_output_attribute(const NodesModifierData &nmd)
static void draw_warnings(const bContext *C, const NodesModifierData &nmd, uiLayout *layout, PointerRNA *md_ptr)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void draw_interface_panel_content(const bContext *C, uiLayout *layout, PointerRNA *modifier_ptr, NodesModifierData &nmd, const bNodeTreeInterfacePanel &interface_panel)
static void try_add_side_effect_node(const ComputeContext &final_compute_context, const int final_node_id, const NodesModifierData &nmd, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
Definition MOD_nodes.cc:485
static bool check_tree_for_time_node(const bNodeTree &tree, Set< const bNodeTree * > &checked_groups)
Definition MOD_nodes.cc:225
static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
Definition MOD_nodes.cc:280
static void update_id_properties_from_node_group(NodesModifierData *nmd)
Definition MOD_nodes.cc:309
static void modifyGeometry(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet &geometry_set)
static void remove_outdated_bake_caches(NodesModifierData &nmd)
Definition MOD_nodes.cc:332
static void ensure_bake_loaded(bake::NodeBakeCache &bake_cache, bake::FrameCache &frame_cache)
Definition MOD_nodes.cc:991
static NodesModifierPanel * find_panel_by_id(NodesModifierData &nmd, const int id)
static bool try_find_baked_data(const NodesModifierBake &bake, bake::NodeBakeCache &bake_cache, const Main &bmain, const Object &object, const NodesModifierData &nmd, const int id)
static void draw_manage_panel(const bContext *C, uiLayout *layout, PointerRNA *modifier_ptr, NodesModifierData &nmd)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static void draw_property_for_socket(const bContext &C, uiLayout *layout, NodesModifierData *nmd, PointerRNA *bmain_ptr, PointerRNA *md_ptr, const bNodeTreeInterfaceSocket &socket)
static void find_socket_log_contexts(const NodesModifierData &nmd, const ModifierEvalContext &ctx, Set< ComputeContextHash > &r_socket_log_contexts)
Definition MOD_nodes.cc:826
void nodes_modifier_packed_bake_free(NodesModifierPackedBake *packed_bake)
static void attribute_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
static geo_log::GeoTreeLog * get_root_tree_log(const NodesModifierData &nmd)
static bool is_disabled(const Scene *, ModifierData *md, bool)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Object &object)
Definition MOD_nodes.cc:145
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
static void add_collection_relation(const ModifierUpdateDepsgraphContext *ctx, Collection &collection)
Definition MOD_nodes.cc:138
static void find_side_effect_nodes(const NodesModifierData &nmd, const ModifierEvalContext &ctx, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes, Set< ComputeContextHash > &r_socket_log_contexts)
Definition MOD_nodes.cc:793
static void find_used_ids_from_settings(const NodesModifierSettings &settings, Set< ID * > &ids)
Definition MOD_nodes.cc:122
static void update_panels_from_node_group(NodesModifierData &nmd)
Definition MOD_nodes.cc:408
bool is_layer_selection_field(const bNodeTreeInterfaceSocket &socket)
#define hash
Definition noise.c:154
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
PointerRNA RNA_main_pointer_create(Main *main)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
unsigned int uint32_t
Definition stdint.h:80
#define UI_MENU_ARROW_SEP
struct Object * surface
ListBase group
Definition DNA_ID.h:146
char name[64]
Definition DNA_ID.h:163
IDPropertyData data
Definition DNA_ID.h:168
Definition DNA_ID.h:413
void * first
ListBase wm
Definition BKE_main.hh:239
uint16_t layout_panel_open_flag
ModifierApplyFlag flag
NodesModifierPanel * panels
struct bNodeTree * node_group
NodesModifierRuntimeHandle * runtime
struct NodesModifierSettings settings
NodesModifierBake * bakes
NodesModifierBakeFile * meta_files
NodesModifierBakeFile * blob_files
struct IDProperty * properties
uiLayout * header
uiLayout * body
struct uiLayout * layout
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
struct bNodeTree * edittree
ViewerPath viewer_path
ViewerPath viewer_path
bNestedNodePath path
char idname[64]
bNodeTreeInterfacePanel root_panel
bNodeTreeInterface tree_interface
struct ID * id
int32_t identifier
std::optional< int > current
Definition MOD_nodes.cc:959
std::optional< int > prev
Definition MOD_nodes.cc:958
std::optional< int > next
Definition MOD_nodes.cc:960
NodesModifierBakeDataBlockMap data_block_map
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
const Mesh * get_mesh() const
Defines a socket type.
Definition BKE_node.hh:151
Map< int, std::unique_ptr< BakeItem > > items_by_id
std::optional< std::variant< std::string, Span< std::byte > > > meta_data_source
Map< int, std::unique_ptr< SimulationNodeCache > > simulation_cache_by_id
Map< int, std::unique_ptr< BakeNodeCache > > bake_cache_by_id
std::unique_ptr< MemoryBlobReader > memory_blob_reader
Vector< std::unique_ptr< FrameCache > > frames
std::unique_ptr< BlobReadSharing > blob_sharing
const Set< ComputeContextHash > * socket_log_contexts
const GeoNodesSideEffectNodes * side_effect_nodes
MultiValueMap< std::pair< ComputeContextHash, int32_t >, int > iterations_by_iteration_zone
MultiValueMap< ComputeContextHash, const lf::FunctionNode * > nodes_by_context
std::function< void(bke::bake::BakeState state)> store_fn
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138