Blender V4.5
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
8
9#include <cstring>
10#include <fmt/format.h>
11#include <sstream>
12#include <string>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_listbase.h"
18#include "BLI_set.hh"
19#include "BLI_string.h"
20#include "BLI_utildefines.h"
21
22#include "DNA_array_utils.hh"
24#include "DNA_curves_types.h"
25#include "DNA_defaults.h"
26#include "DNA_material_types.h"
27#include "DNA_mesh_types.h"
28#include "DNA_modifier_types.h"
29#include "DNA_node_types.h"
30#include "DNA_object_types.h"
32#include "DNA_scene_types.h"
33#include "DNA_screen_types.h"
34#include "DNA_space_types.h"
35#include "DNA_view3d_types.h"
37
42#include "BKE_customdata.hh"
43#include "BKE_global.hh"
44#include "BKE_idprop.hh"
45#include "BKE_lib_id.hh"
46#include "BKE_lib_query.hh"
47#include "BKE_main.hh"
48#include "BKE_mesh.hh"
49#include "BKE_modifier.hh"
51#include "BKE_node_runtime.hh"
53#include "BKE_object.hh"
54#include "BKE_packedFile.hh"
55#include "BKE_pointcloud.hh"
56#include "BKE_screen.hh"
57#include "BKE_workspace.hh"
58
59#include "BLO_read_write.hh"
60
62#include "UI_interface.hh"
63#include "UI_resources.hh"
64
65#include "BLT_translation.hh"
66
67#include "WM_api.hh"
68#include "WM_types.hh"
69
70#include "RNA_access.hh"
71#include "RNA_enum_types.hh"
72#include "RNA_prototypes.hh"
73
77
78#include "MOD_modifiertypes.hh"
79#include "MOD_nodes.hh"
80#include "MOD_ui_common.hh"
81
82#include "ED_node.hh"
83#include "ED_object.hh"
84#include "ED_screen.hh"
85#include "ED_undo.hh"
86#include "ED_viewer_path.hh"
87
94
97namespace bake = blender::bke::bake;
98
99namespace blender {
100
101static void init_data(ModifierData *md)
102{
104
107
109 nmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
110 nmd->runtime->cache = std::make_shared<bake::ModifierCache>();
111}
112
115{
117 if (ID *id = IDP_Id(property)) {
118 deps.add_generic_id_full(id);
119 }
120 });
121}
122
123/* We don't know exactly what attributes from the other object we will need. */
129
131 Collection &collection)
132{
133 DEG_add_collection_geometry_relation(ctx->node, &collection, "Nodes Modifier");
135}
136
139 Object &object,
141{
142 if (info.transform) {
143 DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
144 }
145 if (&(ID &)object == &ctx->object->id) {
146 return;
147 }
148 if (info.geometry) {
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 if (object.type == OB_CAMERA) {
158 if (info.camera_parameters) {
159 DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_PARAMETERS, "Nodes Modifier");
160 }
161 }
162}
163
165{
166 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
167 if (nmd->node_group == nullptr) {
168 return;
169 }
170 if (ID_MISSING(nmd->node_group)) {
171 return;
172 }
173
174 DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
175
178
179 /* Create dependencies to data-blocks referenced by the settings in the modifier. */
181
182 if (ctx->object->type == OB_CURVES) {
183 Curves *curves_id = static_cast<Curves *>(ctx->object->data);
184 if (curves_id->surface != nullptr) {
185 eval_deps.add_object(curves_id->surface);
186 }
187 }
188
189 for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
190 for (const NodesModifierDataBlock &data_block : Span(bake.data_blocks, bake.data_blocks_num)) {
191 if (data_block.id) {
192 eval_deps.add_generic_id_full(data_block.id);
193 }
194 }
195 }
196
197 for (ID *id : eval_deps.ids.values()) {
198 switch ((ID_Type)GS(id->name)) {
199 case ID_OB: {
200 Object *object = reinterpret_cast<Object *>(id);
202 ctx, *object, eval_deps.objects_info.lookup_default(object->id.session_uid, {}));
203 break;
204 }
205 case ID_GR: {
206 Collection *collection = reinterpret_cast<Collection *>(id);
207 add_collection_relation(ctx, *collection);
208 break;
209 }
210 case ID_IM:
211 case ID_TE: {
212 DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier");
213 break;
214 }
215 default: {
216 /* Purposefully don't add relations for materials. While there are material sockets,
217 * the pointers are only passed around as handles rather than dereferenced. */
218 break;
219 }
220 }
221 }
222
223 if (eval_deps.needs_own_transform) {
224 DEG_add_depends_on_transform_relation(ctx->node, "Nodes Modifier");
225 }
226 if (eval_deps.needs_active_camera) {
227 DEG_add_scene_camera_relation(ctx->node, ctx->scene, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
228 }
229 /* Active camera is a scene parameter that can change, so we need a relation for that, too. */
230 if (eval_deps.needs_active_camera || eval_deps.needs_scene_render_params) {
231 DEG_add_scene_relation(ctx->node, ctx->scene, DEG_SCENE_COMP_PARAMETERS, "Nodes Modifier");
232 }
233}
234
235static bool depends_on_time(Scene * /*scene*/, ModifierData *md)
236{
237 const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
238 const bNodeTree *tree = nmd->node_group;
239 if (tree == nullptr) {
240 return false;
241 }
242 if (ID_MISSING(tree)) {
243 return false;
244 }
245 for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
246 if (bake.bake_mode == NODES_MODIFIER_BAKE_MODE_ANIMATION) {
247 return true;
248 }
249 }
252 return eval_deps.time_dependent;
253}
254
255static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
256{
257 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
258 walk(user_data, ob, (ID **)&nmd->node_group, IDWALK_CB_USER);
259
261 walk(user_data, ob, (ID **)&id_prop->data.pointer, IDWALK_CB_USER);
262 });
263
264 for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
265 for (NodesModifierDataBlock &data_block : MutableSpan(bake.data_blocks, bake.data_blocks_num))
266 {
267 walk(user_data, ob, &data_block.id, IDWALK_CB_USER);
268 }
269 }
270}
271
272static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
273{
274 PointerRNA ptr = RNA_pointer_create_discrete(&ob->id, &RNA_Modifier, md);
275 PropertyRNA *prop = RNA_struct_find_property(&ptr, "texture");
276 walk(user_data, ob, md, &ptr, prop);
277}
278
279static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
280{
281 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
282
283 if (nmd->node_group == nullptr) {
284 return true;
285 }
286
287 return false;
288}
289
291{
292 if (!DEG_is_active(ctx->depsgraph)) {
293 return false;
294 }
295 if ((ctx->flag & MOD_APPLY_ORCO) != 0) {
296 return false;
297 }
298 return true;
299}
300
302{
303 if (nmd->node_group == nullptr) {
304 if (nmd->settings.properties) {
306 nmd->settings.properties = nullptr;
307 }
308 return;
309 }
310
311 IDProperty *old_properties = nmd->settings.properties;
312 nmd->settings.properties = bke::idprop::create_group("Nodes Modifier Settings").release();
313 IDProperty *new_properties = nmd->settings.properties;
314
315 nodes::update_input_properties_from_node_tree(*nmd->node_group, old_properties, *new_properties);
317 *nmd->node_group, old_properties, *new_properties);
318
319 if (old_properties != nullptr) {
320 IDP_FreeProperty(old_properties);
321 }
322}
323
325{
326 if (!nmd.runtime->cache) {
327 if (nmd.bakes_num == 0) {
328 return;
329 }
330 nmd.runtime->cache = std::make_shared<bake::ModifierCache>();
331 }
332 bake::ModifierCache &modifier_cache = *nmd.runtime->cache;
333 std::lock_guard lock{modifier_cache.mutex};
334
335 Set<int> existing_bake_ids;
336 for (const NodesModifierBake &bake : Span{nmd.bakes, nmd.bakes_num}) {
337 existing_bake_ids.add(bake.id);
338 }
339
340 auto remove_predicate = [&](auto item) { return !existing_bake_ids.contains(item.key); };
341
342 modifier_cache.bake_cache_by_id.remove_if(remove_predicate);
343 modifier_cache.simulation_cache_by_id.remove_if(remove_predicate);
344}
345
347{
348 Map<int, NodesModifierBake *> old_bake_by_id;
350 old_bake_by_id.add(bake.id, &bake);
351 }
352
353 Vector<int> new_bake_ids;
354 if (nmd.node_group) {
355 for (const bNestedNodeRef &ref : nmd.node_group->nested_node_refs_span()) {
356 const bNode *node = nmd.node_group->find_nested_node(ref.id);
357 if (node) {
359 new_bake_ids.append(ref.id);
360 }
361 }
362 else if (old_bake_by_id.contains(ref.id)) {
363 /* Keep baked data in case linked data is missing so that it still exists when the linked
364 * data has been found. */
365 new_bake_ids.append(ref.id);
366 }
367 }
368 }
369
370 NodesModifierBake *new_bake_data = MEM_calloc_arrayN<NodesModifierBake>(new_bake_ids.size(),
371 __func__);
372 for (const int i : new_bake_ids.index_range()) {
373 const int id = new_bake_ids[i];
374 NodesModifierBake *old_bake = old_bake_by_id.lookup_default(id, nullptr);
375 NodesModifierBake &new_bake = new_bake_data[i];
376 if (old_bake) {
377 new_bake = *old_bake;
378 /* The ownership of this data was moved to `new_bake`. */
379 old_bake->directory = nullptr;
380 old_bake->data_blocks = nullptr;
381 old_bake->data_blocks_num = 0;
382 old_bake->packed = nullptr;
383 }
384 else {
385 new_bake.id = id;
386 new_bake.frame_start = 1;
387 new_bake.frame_end = 100;
389 }
390 }
391
392 for (NodesModifierBake &old_bake : MutableSpan(nmd.bakes, nmd.bakes_num)) {
393 nodes_modifier_bake_destruct(&old_bake, true);
394 }
395 MEM_SAFE_FREE(nmd.bakes);
396
397 nmd.bakes = new_bake_data;
398 nmd.bakes_num = new_bake_ids.size();
399
401}
402
404{
405 Map<int, NodesModifierPanel *> old_panel_by_id;
406 for (NodesModifierPanel &panel : MutableSpan(nmd.panels, nmd.panels_num)) {
407 old_panel_by_id.add(panel.id, &panel);
408 }
409
411 if (nmd.node_group) {
412 nmd.node_group->ensure_interface_cache();
413 nmd.node_group->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
414 if (item.item_type != NODE_INTERFACE_PANEL) {
415 return true;
416 }
417 interface_panels.append(reinterpret_cast<const bNodeTreeInterfacePanel *>(&item));
418 return true;
419 });
420 }
421
422 NodesModifierPanel *new_panels = MEM_calloc_arrayN<NodesModifierPanel>(interface_panels.size(),
423 __func__);
424
425 for (const int i : interface_panels.index_range()) {
426 const bNodeTreeInterfacePanel &interface_panel = *interface_panels[i];
427 const int id = interface_panel.identifier;
428 NodesModifierPanel *old_panel = old_panel_by_id.lookup_default(id, nullptr);
429 NodesModifierPanel &new_panel = new_panels[i];
430 if (old_panel) {
431 new_panel = *old_panel;
432 }
433 else {
434 new_panel.id = id;
435 const bool default_closed = interface_panel.flag & NODE_INTERFACE_PANEL_DEFAULT_CLOSED;
436 SET_FLAG_FROM_TEST(new_panel.flag, !default_closed, NODES_MODIFIER_PANEL_OPEN);
437 }
438 }
439
441
442 nmd.panels = new_panels;
443 nmd.panels_num = interface_panels.size();
444}
445
446} // namespace blender
447
457
458NodesModifierBake *NodesModifierData::find_bake(const int id)
459{
460 return const_cast<NodesModifierBake *>(std::as_const(*this).find_bake(id));
461}
462
463const NodesModifierBake *NodesModifierData::find_bake(const int id) const
464{
465 for (const NodesModifierBake &bake : blender::Span{this->bakes, this->bakes_num}) {
466 if (bake.id == id) {
467 return &bake;
468 }
469 }
470 return nullptr;
471}
472
473namespace blender {
474
481 const ComputeContext &final_compute_context,
482 const int final_node_id,
483 const NodesModifierData &nmd,
484 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
485{
486 if (nmd.node_group == nullptr) {
487 return;
488 }
489
490 Vector<const ComputeContext *> compute_context_vec;
491 for (const ComputeContext *c = &final_compute_context; c; c = c->parent()) {
492 compute_context_vec.append(c);
493 }
494 std::reverse(compute_context_vec.begin(), compute_context_vec.end());
495
496 const auto *modifier_compute_context = dynamic_cast<const bke::ModifierComputeContext *>(
497 compute_context_vec[0]);
498 if (modifier_compute_context == nullptr) {
499 return;
500 }
501 if (modifier_compute_context->modifier_uid() != nmd.modifier.persistent_uid) {
502 return;
503 }
504
505 const bNodeTree *current_tree = nmd.node_group;
506 const bke::bNodeTreeZone *current_zone = nullptr;
507
508 /* Write side effect nodes to a new map and only if everything succeeds, move the nodes to the
509 * caller. This is easier than changing r_side_effect_nodes directly and then undoing changes in
510 * case of errors. */
511 nodes::GeoNodesSideEffectNodes local_side_effect_nodes;
512 for (const ComputeContext *compute_context_generic : compute_context_vec.as_span().drop_front(1))
513 {
514 const bke::bNodeTreeZones *current_zones = current_tree->zones();
515 if (current_zones == nullptr) {
516 return;
517 }
518 const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*current_tree);
519 if (lf_graph_info == nullptr) {
520 return;
521 }
522 const ComputeContextHash &parent_compute_context_hash =
523 compute_context_generic->parent()->hash();
524 if (const auto *compute_context = dynamic_cast<const bke::SimulationZoneComputeContext *>(
525 compute_context_generic))
526 {
527 const bke::bNodeTreeZone *simulation_zone = current_zones->get_zone_by_node(
528 compute_context->output_node_id());
529 if (simulation_zone == nullptr) {
530 return;
531 }
532 if (simulation_zone->parent_zone != current_zone) {
533 return;
534 }
535 const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
536 simulation_zone, nullptr);
537 if (lf_zone_node == nullptr) {
538 return;
539 }
540 const lf::FunctionNode *lf_simulation_output_node =
541 lf_graph_info->mapping.possible_side_effect_node_map.lookup_default(
542 simulation_zone->output_node(), nullptr);
543 if (lf_simulation_output_node == nullptr) {
544 return;
545 }
546 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_zone_node);
547 /* By making the simulation output node a side-effect-node, we can ensure that the simulation
548 * runs when it contains an active viewer. */
549 local_side_effect_nodes.nodes_by_context.add(compute_context_generic->hash(),
550 lf_simulation_output_node);
551
552 current_zone = simulation_zone;
553 }
554 else if (const auto *compute_context = dynamic_cast<const bke::RepeatZoneComputeContext *>(
555 compute_context_generic))
556 {
557 const bke::bNodeTreeZone *repeat_zone = current_zones->get_zone_by_node(
558 compute_context->output_node_id());
559 if (repeat_zone == nullptr) {
560 return;
561 }
562 if (repeat_zone->parent_zone != current_zone) {
563 return;
564 }
565 const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
566 repeat_zone, nullptr);
567 if (lf_zone_node == nullptr) {
568 return;
569 }
570 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_zone_node);
571 local_side_effect_nodes.iterations_by_iteration_zone.add(
572 {parent_compute_context_hash, compute_context->output_node_id()},
573 compute_context->iteration());
574 current_zone = repeat_zone;
575 }
576 else if (const auto *compute_context =
578 compute_context_generic))
579 {
580 const bke::bNodeTreeZone *foreach_zone = current_zones->get_zone_by_node(
581 compute_context->output_node_id());
582 if (foreach_zone == nullptr) {
583 return;
584 }
585 if (foreach_zone->parent_zone != current_zone) {
586 return;
587 }
588 const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
589 foreach_zone, nullptr);
590 if (lf_zone_node == nullptr) {
591 return;
592 }
593 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_zone_node);
594 local_side_effect_nodes.iterations_by_iteration_zone.add(
595 {parent_compute_context_hash, compute_context->output_node_id()},
596 compute_context->index());
597 current_zone = foreach_zone;
598 }
599 else if (const auto *compute_context = dynamic_cast<const bke::GroupNodeComputeContext *>(
600 compute_context_generic))
601 {
602 const bNode *group_node = current_tree->node_by_id(compute_context->node_id());
603 if (group_node == nullptr) {
604 return;
605 }
606 if (group_node->id == nullptr) {
607 return;
608 }
609 if (group_node->is_muted()) {
610 return;
611 }
612 if (current_zone != current_zones->get_zone_by_node(group_node->identifier)) {
613 return;
614 }
615 const lf::FunctionNode *lf_group_node = lf_graph_info->mapping.group_node_map.lookup_default(
616 group_node, nullptr);
617 if (lf_group_node == nullptr) {
618 return;
619 }
620 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_group_node);
621 current_tree = reinterpret_cast<const bNodeTree *>(group_node->id);
622 current_zone = nullptr;
623 }
624 else if (const auto *compute_context =
625 dynamic_cast<const bke::EvaluateClosureComputeContext *>(compute_context_generic))
626 {
627 const bNode *evaluate_node = current_tree->node_by_id(compute_context->node_id());
628 if (!evaluate_node) {
629 return;
630 }
631 if (evaluate_node->is_muted()) {
632 return;
633 }
634 if (current_zone != current_zones->get_zone_by_node(evaluate_node->identifier)) {
635 return;
636 }
637 const std::optional<nodes::ClosureSourceLocation> &source_location =
638 compute_context->closure_source_location();
639 if (!source_location) {
640 return;
641 }
642 if (!source_location->tree->zones()) {
643 return;
644 }
645 const lf::FunctionNode *lf_evaluate_node =
646 lf_graph_info->mapping.possible_side_effect_node_map.lookup_default(evaluate_node,
647 nullptr);
648 if (!lf_evaluate_node) {
649 return;
650 }
651 /* The tree may sometimes be original and sometimes evaluated, depending on the source of the
652 * compute context. */
653 const bNodeTree *eval_closure_tree = DEG_is_evaluated(source_location->tree) ?
654 source_location->tree :
655 reinterpret_cast<const bNodeTree *>(
657 ctx.depsgraph, &source_location->tree->id));
658 const bNode *closure_output_node = eval_closure_tree->node_by_id(
659 source_location->closure_output_node_id);
660 if (!closure_output_node) {
661 return;
662 }
663 local_side_effect_nodes.nodes_by_context.add(parent_compute_context_hash, lf_evaluate_node);
664 current_tree = eval_closure_tree;
665 current_zone = eval_closure_tree->zones()->get_zone_by_node(closure_output_node->identifier);
666 }
667 else {
668 return;
669 }
670 }
671 const bNode *final_node = current_tree->node_by_id(final_node_id);
672 if (final_node == nullptr) {
673 return;
674 }
675 const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*current_tree);
676 if (lf_graph_info == nullptr) {
677 return;
678 }
679 const bke::bNodeTreeZones *tree_zones = current_tree->zones();
680 if (tree_zones == nullptr) {
681 return;
682 }
683 if (tree_zones->get_zone_by_node(final_node_id) != current_zone) {
684 return;
685 }
686 const lf::FunctionNode *lf_node =
687 lf_graph_info->mapping.possible_side_effect_node_map.lookup_default(final_node, nullptr);
688 if (lf_node == nullptr) {
689 return;
690 }
691 local_side_effect_nodes.nodes_by_context.add(final_compute_context.hash(), lf_node);
692
693 /* Successfully found all side effect nodes for the viewer path. */
694 for (const auto item : local_side_effect_nodes.nodes_by_context.items()) {
695 r_side_effect_nodes.nodes_by_context.add_multiple(item.key, item.value);
696 }
697 for (const auto item : local_side_effect_nodes.iterations_by_iteration_zone.items()) {
698 r_side_effect_nodes.iterations_by_iteration_zone.add_multiple(item.key, item.value);
699 }
700}
701
703 const ViewerPath &viewer_path,
704 const NodesModifierData &nmd,
705 const ModifierEvalContext &ctx,
706 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
707{
708 const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
710 if (!parsed_path.has_value()) {
711 return;
712 }
713 if (parsed_path->object != DEG_get_original(ctx.object)) {
714 return;
715 }
716 if (parsed_path->modifier_uid != nmd.modifier.persistent_uid) {
717 return;
718 }
719
720 bke::ComputeContextCache compute_context_cache;
721 const ComputeContext *current = &compute_context_cache.for_modifier(nullptr, nmd);
722 for (const ViewerPathElem *elem : parsed_path->node_path) {
724 *elem, compute_context_cache, current);
725 if (!current) {
726 return;
727 }
728 }
729
730 try_add_side_effect_node(ctx, *current, parsed_path->viewer_node_id, nmd, r_side_effect_nodes);
731}
732
734 const ModifierEvalContext &ctx,
735 const NodesModifierData &nmd,
736 const int root_nested_node_id,
737 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
738{
739 bke::ComputeContextCache compute_context_cache;
740 const ComputeContext *compute_context = &compute_context_cache.for_modifier(nullptr, nmd);
741
742 int nested_node_id = root_nested_node_id;
743 const bNodeTree *tree = nmd.node_group;
744 while (true) {
745 const bNestedNodeRef *ref = tree->find_nested_node_ref(nested_node_id);
746 if (!ref) {
747 return;
748 }
749 const bNode *node = tree->node_by_id(ref->path.node_id);
750 if (!node) {
751 return;
752 }
753 const bke::bNodeTreeZones *zones = tree->zones();
754 if (!zones) {
755 return;
756 }
757 if (zones->get_zone_by_node(node->identifier) != nullptr) {
758 /* Only top level nodes are allowed here. */
759 return;
760 }
761 if (node->is_group()) {
762 if (!node->id) {
763 return;
764 }
765 compute_context = &compute_context_cache.for_group_node(
766 compute_context, node->identifier, tree);
767 tree = reinterpret_cast<const bNodeTree *>(node->id);
768 nested_node_id = ref->path.id_in_node;
769 }
770 else {
771 try_add_side_effect_node(ctx, *compute_context, ref->path.node_id, nmd, r_side_effect_nodes);
772 return;
773 }
774 }
775}
776
782 const ModifierEvalContext &ctx,
783 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
784{
785 if (!nmd.runtime->cache) {
786 return;
787 }
788 if (!DEG_is_active(ctx.depsgraph)) {
789 /* Only the active depsgraph can bake. */
790 return;
791 }
792 bake::ModifierCache &modifier_cache = *nmd.runtime->cache;
793 for (const bNestedNodeRef &ref : nmd.node_group->nested_node_refs_span()) {
794 if (!modifier_cache.requested_bakes.contains(ref.id)) {
795 continue;
796 }
797 find_side_effect_nodes_for_nested_node(ctx, nmd, ref.id, r_side_effect_nodes);
798 }
799}
800
802 const NodesModifierData &nmd,
803 const ModifierEvalContext &ctx,
804 const wmWindowManager &wm,
805 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes,
806 Set<ComputeContextHash> &r_socket_log_contexts)
807{
808 Object *object_orig = DEG_get_original(ctx.object);
809 const NodesModifierData &nmd_orig = *reinterpret_cast<const NodesModifierData *>(
810 BKE_modifier_get_original(ctx.object, const_cast<ModifierData *>(&nmd.modifier)));
811 bke::ComputeContextCache compute_context_cache;
813 *object_orig,
814 nmd_orig,
815 wm,
816 compute_context_cache,
817 [&](const ComputeContext &compute_context,
818 const bNode &gizmo_node,
819 const bNodeSocket &gizmo_socket) {
821 ctx, compute_context, gizmo_node.identifier, nmd, r_side_effect_nodes);
822 r_socket_log_contexts.add(compute_context.hash());
823
825 compute_context, gizmo_node, gizmo_socket, [&](const ComputeContext &node_context) {
826 /* Make sure that all intermediate sockets are logged. This is necessary to be able
827 * to evaluate the nodes in reverse for the gizmo. */
828 r_socket_log_contexts.add(node_context.hash());
829 });
830 });
831}
832
834 const ModifierEvalContext &ctx,
835 nodes::GeoNodesSideEffectNodes &r_side_effect_nodes,
836 Set<ComputeContextHash> &r_socket_log_contexts)
837{
838 Main *bmain = DEG_get_bmain(ctx.depsgraph);
840 if (wm == nullptr) {
841 return;
842 }
843 LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
844 const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
845 const WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook);
846 find_side_effect_nodes_for_viewer_path(workspace->viewer_path, nmd, ctx, r_side_effect_nodes);
847 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
848 const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
849 if (sl->spacetype == SPACE_SPREADSHEET) {
850 const SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<const SpaceSpreadsheet *>(sl);
852 sspreadsheet.geometry_id.viewer_path, nmd, ctx, r_side_effect_nodes);
853 }
854 if (sl->spacetype == SPACE_VIEW3D) {
855 const View3D &v3d = *reinterpret_cast<const View3D *>(sl);
856 find_side_effect_nodes_for_viewer_path(v3d.viewer_path, nmd, ctx, r_side_effect_nodes);
857 }
858 }
859 }
860
861 find_side_effect_nodes_for_baking(nmd, ctx, r_side_effect_nodes);
863 nmd, ctx, *wm, r_side_effect_nodes, r_socket_log_contexts);
864}
865
867 const ModifierEvalContext &ctx,
868 Set<ComputeContextHash> &r_socket_log_contexts)
869{
870 Main *bmain = DEG_get_bmain(ctx.depsgraph);
872 if (wm == nullptr) {
873 return;
874 }
875 bke::ComputeContextCache compute_context_cache;
876 LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
877 const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
878 LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
879 const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
880 if (sl->spacetype == SPACE_NODE) {
881 const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
882 if (snode.edittree == nullptr || snode.edittree->type != NTREE_GEOMETRY) {
883 continue;
884 }
886 continue;
887 }
890 compute_context_cache);
891 for (const ComputeContextHash &hash : hash_by_zone.values()) {
892 r_socket_log_contexts.add(hash);
893 }
894 }
895 }
896 }
897}
898
903static void check_property_socket_sync(const Object *ob,
904 const nodes::PropertiesVectorSet &properties,
905 ModifierData *md)
906{
907 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
908
909 int geometry_socket_count = 0;
910
911 nmd->node_group->ensure_interface_cache();
912 const Span<nodes::StructureType> input_structure_types =
913 nmd->node_group->runtime->structure_type_interface->inputs;
914 for (const int i : nmd->node_group->interface_inputs().index_range()) {
915 const bNodeTreeInterfaceSocket *socket = nmd->node_group->interface_inputs()[i];
916 const bke::bNodeSocketType *typeinfo = socket->socket_typeinfo();
917 const eNodeSocketDatatype type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
918 if (type == SOCK_GEOMETRY) {
919 geometry_socket_count++;
920 }
921 /* The first socket is the special geometry socket for the modifier object. */
922 if (i == 0 && type == SOCK_GEOMETRY) {
923 continue;
924 }
925 if (input_structure_types[i] == nodes::StructureType::Grid) {
926 continue;
927 }
928
929 IDProperty *property = properties.lookup_key_default_as(socket->identifier, nullptr);
930 if (property == nullptr) {
933 ob, md, "Missing property for input socket \"%s\"", socket->name ? socket->name : "");
934 }
935 continue;
936 }
937
938 if (!nodes::id_property_type_matches_socket(*socket, *property)) {
940 md,
941 "Property type does not match input socket \"(%s)\"",
942 socket->name ? socket->name : "");
943 continue;
944 }
945 }
946
947 if (geometry_socket_count == 1) {
948 const bNodeTreeInterfaceSocket *first_socket = nmd->node_group->interface_inputs()[0];
949 const bke::bNodeSocketType *typeinfo = first_socket->socket_typeinfo();
950 const eNodeSocketDatatype type = typeinfo ? typeinfo->type : SOCK_CUSTOM;
951 if (type != SOCK_GEOMETRY) {
952 BKE_modifier_set_error(ob, md, "Node group's geometry input must be the first");
953 }
954 }
955}
956
959 Mutex mutex_;
960
961 public:
964
966 {
967 if (ID *id = this->old_mappings.lookup_default(key, nullptr)) {
968 return id;
969 }
970 if (this->old_mappings.contains(key)) {
971 /* Don't allow overwriting old mappings. */
972 return nullptr;
973 }
974 std::lock_guard lock{mutex_};
975 return this->new_mappings.lookup_or_add(key, nullptr);
976 }
977
978 void try_add(ID &id) override
979 {
980 bake::BakeDataBlockID key{id};
981 if (this->old_mappings.contains(key)) {
982 return;
983 }
984 std::lock_guard lock{mutex_};
985 this->new_mappings.add_overwrite(std::move(key), &id);
986 }
987
988 private:
989 ID *lookup_in_map(Map<bake::BakeDataBlockID, ID *> &map,
990 const bake::BakeDataBlockID &key,
991 const std::optional<ID_Type> &type)
992 {
993 ID *id = map.lookup_default(key, nullptr);
994 if (!id) {
995 return nullptr;
996 }
997 if (type && GS(id->name) != *type) {
998 return nullptr;
999 }
1000 return id;
1001 }
1002};
1003
1004namespace sim_input = nodes::sim_input;
1005namespace sim_output = nodes::sim_output;
1006
1008 std::optional<int> prev;
1009 std::optional<int> current;
1010 std::optional<int> next;
1011};
1012
1014 const Span<std::unique_ptr<bake::FrameCache>> frame_caches, const SubFrame frame)
1015{
1016 BakeFrameIndices frame_indices;
1017 if (!frame_caches.is_empty()) {
1018 const int first_future_frame_index = binary_search::first_if(
1019 frame_caches,
1020 [&](const std::unique_ptr<bake::FrameCache> &value) { return value->frame > frame; });
1021 frame_indices.next = (first_future_frame_index == frame_caches.size()) ?
1022 std::nullopt :
1023 std::optional<int>(first_future_frame_index);
1024 if (first_future_frame_index > 0) {
1025 const int index = first_future_frame_index - 1;
1026 if (frame_caches[index]->frame < frame) {
1027 frame_indices.prev = index;
1028 }
1029 else {
1030 BLI_assert(frame_caches[index]->frame == frame);
1031 frame_indices.current = index;
1032 if (index > 0) {
1033 frame_indices.prev = index - 1;
1034 }
1035 }
1036 }
1037 }
1038 return frame_indices;
1039}
1040
1041static void ensure_bake_loaded(bake::NodeBakeCache &bake_cache, bake::FrameCache &frame_cache)
1042{
1043 if (!frame_cache.state.items_by_id.is_empty()) {
1044 return;
1045 }
1046 if (!frame_cache.meta_data_source.has_value()) {
1047 return;
1048 }
1049 if (bake_cache.memory_blob_reader) {
1050 if (const auto *meta_buffer = std::get_if<Span<std::byte>>(&*frame_cache.meta_data_source)) {
1051 const std::string meta_str{reinterpret_cast<const char *>(meta_buffer->data()),
1052 size_t(meta_buffer->size())};
1053 std::istringstream meta_stream{meta_str};
1054 std::optional<bake::BakeState> bake_state = bake::deserialize_bake(
1055 meta_stream, *bake_cache.memory_blob_reader, *bake_cache.blob_sharing);
1056 if (!bake_state.has_value()) {
1057 return;
1058 }
1059 frame_cache.state = std::move(*bake_state);
1060 return;
1061 }
1062 }
1063 if (!bake_cache.blobs_dir) {
1064 return;
1065 }
1066 const auto *meta_path = std::get_if<std::string>(&*frame_cache.meta_data_source);
1067 if (!meta_path) {
1068 return;
1069 }
1070 bake::DiskBlobReader blob_reader{*bake_cache.blobs_dir};
1071 fstream meta_file{*meta_path};
1072 std::optional<bake::BakeState> bake_state = bake::deserialize_bake(
1073 meta_file, blob_reader, *bake_cache.blob_sharing);
1074 if (!bake_state.has_value()) {
1075 return;
1076 }
1077 frame_cache.state = std::move(*bake_state);
1078}
1079
1081 bake::NodeBakeCache &bake_cache,
1082 const Main &bmain,
1083 const Object &object,
1084 const NodesModifierData &nmd,
1085 const int id)
1086{
1087 if (bake.packed) {
1088 if (bake.packed->meta_files_num == 0) {
1089 return false;
1090 }
1091 bake_cache.reset();
1093 for (const NodesModifierBakeFile &meta_file :
1094 Span{bake.packed->meta_files, bake.packed->meta_files_num})
1095 {
1096 const std::optional<SubFrame> frame = bake::file_name_to_frame(meta_file.name);
1097 if (!frame) {
1098 return false;
1099 }
1100 if (!file_by_frame.add(*frame, &meta_file)) {
1101 /* Can only have on file per (sub)frame. */
1102 return false;
1103 }
1104 }
1105 /* Make sure frames processed in the right order. */
1106 Vector<SubFrame> frames;
1107 frames.extend(file_by_frame.keys().begin(), file_by_frame.keys().end());
1108
1109 for (const SubFrame &frame : frames) {
1110 const NodesModifierBakeFile &meta_file = *file_by_frame.lookup(frame);
1111 auto frame_cache = std::make_unique<bake::FrameCache>();
1112 frame_cache->frame = frame;
1113 frame_cache->meta_data_source = meta_file.data();
1114 bake_cache.frames.append(std::move(frame_cache));
1115 }
1116
1117 bake_cache.memory_blob_reader = std::make_unique<bake::MemoryBlobReader>();
1118 for (const NodesModifierBakeFile &blob_file :
1119 Span{bake.packed->blob_files, bake.packed->blob_files_num})
1120 {
1121 bake_cache.memory_blob_reader->add(blob_file.name, blob_file.data());
1122 }
1123 bake_cache.blob_sharing = std::make_unique<bake::BlobReadSharing>();
1124 return true;
1125 }
1126
1127 std::optional<bake::BakePath> bake_path = bake::get_node_bake_path(bmain, object, nmd, id);
1128 if (!bake_path) {
1129 return false;
1130 }
1131 Vector<bake::MetaFile> meta_files = bake::find_sorted_meta_files(bake_path->meta_dir);
1132 if (meta_files.is_empty()) {
1133 return false;
1134 }
1135 bake_cache.reset();
1136 for (const bake::MetaFile &meta_file : meta_files) {
1137 auto frame_cache = std::make_unique<bake::FrameCache>();
1138 frame_cache->frame = meta_file.frame;
1139 frame_cache->meta_data_source = meta_file.path;
1140 bake_cache.frames.append(std::move(frame_cache));
1141 }
1142 bake_cache.blobs_dir = bake_path->blobs_dir;
1143 bake_cache.blob_sharing = std::make_unique<bake::BlobReadSharing>();
1144 return true;
1145}
1146
1148 private:
1149 static constexpr float max_delta_frames = 1.0f;
1150
1151 const NodesModifierData &nmd_;
1152 const ModifierEvalContext &ctx_;
1153 const Main *bmain_;
1154 const Scene *scene_;
1155 SubFrame current_frame_;
1156 bool use_frame_cache_;
1157 bool depsgraph_is_active_;
1158 bake::ModifierCache *modifier_cache_;
1159 float fps_;
1160 bool has_invalid_simulation_ = false;
1161
1162 public:
1167
1169
1171 : nmd_(nmd), ctx_(ctx)
1172 {
1173 const Depsgraph *depsgraph = ctx_.depsgraph;
1174 bmain_ = DEG_get_bmain(depsgraph);
1175 current_frame_ = DEG_get_ctime(depsgraph);
1176 const Scene *scene = DEG_get_input_scene(depsgraph);
1177 scene_ = scene;
1178 use_frame_cache_ = ctx_.object->flag & OB_FLAG_USE_SIMULATION_CACHE;
1179 depsgraph_is_active_ = DEG_is_active(depsgraph);
1180 modifier_cache_ = nmd.runtime->cache.get();
1181 fps_ = FPS;
1182
1183 if (!modifier_cache_) {
1184 return;
1185 }
1186 std::lock_guard lock{modifier_cache_->mutex};
1187 if (depsgraph_is_active_) {
1188 /* Invalidate data on user edits. */
1190 for (std::unique_ptr<bake::SimulationNodeCache> &node_cache :
1191 modifier_cache_->simulation_cache_by_id.values())
1192 {
1193 if (node_cache->cache_status != bake::CacheStatus::Baked) {
1194 node_cache->cache_status = bake::CacheStatus::Invalid;
1195 if (!node_cache->bake.frames.is_empty()) {
1196 if (node_cache->bake.frames.last()->frame == current_frame_) {
1197 /* Remove the last (which is the current) cached frame so that it is simulated
1198 * again. */
1199 node_cache->bake.frames.pop_last();
1200 }
1201 }
1202 }
1203 }
1204 }
1206 }
1207 for (const std::unique_ptr<bake::SimulationNodeCache> &node_cache_ptr :
1208 modifier_cache_->simulation_cache_by_id.values())
1209 {
1210 const bake::SimulationNodeCache &node_cache = *node_cache_ptr;
1211 if (node_cache.cache_status == bake::CacheStatus::Invalid) {
1212 has_invalid_simulation_ = true;
1213 break;
1214 }
1215 }
1216 }
1217
1219 {
1220 for (auto item : modifier_cache_->simulation_cache_by_id.items()) {
1221 const int id = item.key;
1222 bake::SimulationNodeCache &node_cache = *item.value;
1223 if (node_cache.cache_status != bake::CacheStatus::Invalid) {
1224 continue;
1225 }
1226 const std::optional<IndexRange> sim_frame_range = bake::get_node_bake_frame_range(
1227 *scene_, *ctx_.object, nmd_, id);
1228 if (!sim_frame_range.has_value()) {
1229 continue;
1230 }
1231 const SubFrame start_frame{int(sim_frame_range->start())};
1232 if (current_frame_ <= start_frame) {
1233 node_cache.reset();
1234 }
1235 if (!node_cache.bake.frames.is_empty() &&
1236 current_frame_ < node_cache.bake.frames.first()->frame)
1237 {
1238 node_cache.reset();
1239 }
1240 }
1241 }
1242
1243 nodes::SimulationZoneBehavior *get(const int zone_id) const override
1244 {
1245 if (!modifier_cache_) {
1246 return nullptr;
1247 }
1248 std::lock_guard lock{modifier_cache_->mutex};
1249 return &this->data_by_zone_id
1250 .lookup_or_add_cb(zone_id,
1251 [&]() {
1252 auto data = std::make_unique<DataPerZone>();
1253 data->behavior.data_block_map = &data->data_block_map;
1255 zone_id, data->behavior, data->data_block_map);
1256 return data;
1257 })
1258 ->behavior;
1259 }
1260
1261 void init_simulation_info(const int zone_id,
1262 nodes::SimulationZoneBehavior &zone_behavior,
1263 NodesModifierBakeDataBlockMap &data_block_map) const
1264 {
1265 bake::SimulationNodeCache &node_cache =
1266 *modifier_cache_->simulation_cache_by_id.lookup_or_add_cb(
1267 zone_id, []() { return std::make_unique<bake::SimulationNodeCache>(); });
1268 const NodesModifierBake &bake = *nmd_.find_bake(zone_id);
1269 const IndexRange sim_frame_range = *bake::get_node_bake_frame_range(
1270 *scene_, *ctx_.object, nmd_, zone_id);
1271 const SubFrame sim_start_frame{int(sim_frame_range.first())};
1272 const SubFrame sim_end_frame{int(sim_frame_range.last())};
1273
1274 if (!modifier_cache_->requested_bakes.contains(zone_id)) {
1275 /* Try load baked data. */
1276 if (!node_cache.bake.failed_finding_bake) {
1277 if (node_cache.cache_status != bake::CacheStatus::Baked) {
1278 if (try_find_baked_data(bake, node_cache.bake, *bmain_, *ctx_.object, nmd_, zone_id)) {
1280 }
1281 else {
1282 node_cache.bake.failed_finding_bake = true;
1283 }
1284 }
1285 }
1286 }
1287
1288 /* If there are no baked frames, we don't need keep track of the data-blocks. */
1289 if (!node_cache.bake.frames.is_empty() || node_cache.prev_cache.has_value()) {
1290 for (const NodesModifierDataBlock &data_block : Span{bake.data_blocks, bake.data_blocks_num})
1291 {
1292 data_block_map.old_mappings.add(data_block, data_block.id);
1293 }
1294 }
1295
1296 const BakeFrameIndices frame_indices = get_bake_frame_indices(node_cache.bake.frames,
1297 current_frame_);
1298 if (node_cache.cache_status == bake::CacheStatus::Baked) {
1299 this->read_from_cache(frame_indices, node_cache, zone_behavior);
1300 return;
1301 }
1302 if (use_frame_cache_) {
1303 /* If the depsgraph is active, we allow creating new simulation states. Otherwise, the access
1304 * is read-only. */
1305 if (depsgraph_is_active_) {
1306 if (node_cache.bake.frames.is_empty()) {
1307 if (current_frame_ < sim_start_frame || current_frame_ > sim_end_frame) {
1308 /* Outside of simulation frame range, so ignore the simulation if there is no cache. */
1309 this->input_pass_through(zone_behavior);
1310 this->output_pass_through(zone_behavior);
1311 return;
1312 }
1313 /* Initialize the simulation. */
1314 if (current_frame_ > sim_start_frame || has_invalid_simulation_) {
1316 }
1317 this->input_pass_through(zone_behavior);
1318 this->output_store_frame_cache(node_cache, zone_behavior);
1319 return;
1320 }
1321 if (frame_indices.prev && !frame_indices.current && !frame_indices.next &&
1322 current_frame_ <= sim_end_frame)
1323 {
1324 /* Read the previous frame's data and store the newly computed simulation state. */
1325 auto &output_copy_info = zone_behavior.input.emplace<sim_input::OutputCopy>();
1326 const bake::FrameCache &prev_frame_cache = *node_cache.bake.frames[*frame_indices.prev];
1327 const float real_delta_frames = float(current_frame_) - float(prev_frame_cache.frame);
1328 if (real_delta_frames != 1) {
1330 }
1331 const float delta_frames = std::min(max_delta_frames, real_delta_frames);
1332 output_copy_info.delta_time = delta_frames / fps_;
1333 output_copy_info.state = prev_frame_cache.state;
1334 this->output_store_frame_cache(node_cache, zone_behavior);
1335 return;
1336 }
1337 }
1338 this->read_from_cache(frame_indices, node_cache, zone_behavior);
1339 return;
1340 }
1341
1342 /* When there is no per-frame cache, check if there is a previous state. */
1343 if (node_cache.prev_cache) {
1344 if (node_cache.prev_cache->frame < current_frame_) {
1345 /* Do a simulation step. */
1346 const float delta_frames = std::min(
1347 max_delta_frames, float(current_frame_) - float(node_cache.prev_cache->frame));
1348 auto &output_move_info = zone_behavior.input.emplace<sim_input::OutputMove>();
1349 output_move_info.delta_time = delta_frames / fps_;
1350 output_move_info.state = std::move(node_cache.prev_cache->state);
1351 this->store_as_prev_items(node_cache, zone_behavior);
1352 return;
1353 }
1354 if (node_cache.prev_cache->frame == current_frame_) {
1355 /* Just read from the previous state if the frame has not changed. */
1356 auto &output_copy_info = zone_behavior.input.emplace<sim_input::OutputCopy>();
1357 output_copy_info.delta_time = 0.0f;
1358 output_copy_info.state = node_cache.prev_cache->state;
1359 auto &read_single_info = zone_behavior.output.emplace<sim_output::ReadSingle>();
1360 read_single_info.state = node_cache.prev_cache->state;
1361 return;
1362 }
1363 if (!depsgraph_is_active_) {
1364 /* There is no previous state, and it's not possible to initialize the simulation because
1365 * the depsgraph is not active. */
1366 zone_behavior.input.emplace<sim_input::PassThrough>();
1367 zone_behavior.output.emplace<sim_output::PassThrough>();
1368 return;
1369 }
1370 /* Reset the simulation when the scene time moved backwards. */
1371 node_cache.prev_cache.reset();
1372 }
1373 zone_behavior.input.emplace<sim_input::PassThrough>();
1374 if (depsgraph_is_active_) {
1375 /* Initialize the simulation. */
1376 this->store_as_prev_items(node_cache, zone_behavior);
1377 }
1378 else {
1379 zone_behavior.output.emplace<sim_output::PassThrough>();
1380 }
1381 }
1382
1384 {
1385 zone_behavior.input.emplace<sim_input::PassThrough>();
1386 }
1387
1389 {
1390 zone_behavior.output.emplace<sim_output::PassThrough>();
1391 }
1392
1394 nodes::SimulationZoneBehavior &zone_behavior) const
1395 {
1396 auto &store_new_state_info = zone_behavior.output.emplace<sim_output::StoreNewState>();
1397 store_new_state_info.store_fn = [simulation_cache = modifier_cache_,
1398 node_cache = &node_cache,
1399 current_frame = current_frame_](bke::bake::BakeState state) {
1400 std::lock_guard lock{simulation_cache->mutex};
1401 auto frame_cache = std::make_unique<bake::FrameCache>();
1402 frame_cache->frame = current_frame;
1403 frame_cache->state = std::move(state);
1404 node_cache->bake.frames.append(std::move(frame_cache));
1405 };
1406 }
1407
1409 nodes::SimulationZoneBehavior &zone_behavior) const
1410 {
1411 auto &store_new_state_info = zone_behavior.output.emplace<sim_output::StoreNewState>();
1412 store_new_state_info.store_fn = [simulation_cache = modifier_cache_,
1413 node_cache = &node_cache,
1414 current_frame = current_frame_](bke::bake::BakeState state) {
1415 std::lock_guard lock{simulation_cache->mutex};
1416 if (!node_cache->prev_cache) {
1417 node_cache->prev_cache.emplace();
1418 }
1419 node_cache->prev_cache->state = std::move(state);
1420 node_cache->prev_cache->frame = current_frame;
1421 };
1422 }
1423
1424 void read_from_cache(const BakeFrameIndices &frame_indices,
1425 bake::SimulationNodeCache &node_cache,
1426 nodes::SimulationZoneBehavior &zone_behavior) const
1427 {
1428 if (frame_indices.prev) {
1429 auto &output_copy_info = zone_behavior.input.emplace<sim_input::OutputCopy>();
1430 bake::FrameCache &frame_cache = *node_cache.bake.frames[*frame_indices.prev];
1431 const float delta_frames = std::min(max_delta_frames,
1432 float(current_frame_) - float(frame_cache.frame));
1433 output_copy_info.delta_time = delta_frames / fps_;
1434 output_copy_info.state = frame_cache.state;
1435 }
1436 else {
1437 zone_behavior.input.emplace<sim_input::PassThrough>();
1438 }
1439 if (frame_indices.current) {
1440 this->read_single(*frame_indices.current, node_cache, zone_behavior);
1441 }
1442 else if (frame_indices.next) {
1443 if (frame_indices.prev) {
1444 this->read_interpolated(
1445 *frame_indices.prev, *frame_indices.next, node_cache, zone_behavior);
1446 }
1447 else {
1448 this->output_pass_through(zone_behavior);
1449 }
1450 }
1451 else if (frame_indices.prev) {
1452 this->read_single(*frame_indices.prev, node_cache, zone_behavior);
1453 }
1454 else {
1455 this->output_pass_through(zone_behavior);
1456 }
1457 }
1458
1459 void read_single(const int frame_index,
1460 bake::SimulationNodeCache &node_cache,
1461 nodes::SimulationZoneBehavior &zone_behavior) const
1462 {
1463 bake::FrameCache &frame_cache = *node_cache.bake.frames[frame_index];
1464 ensure_bake_loaded(node_cache.bake, frame_cache);
1465 auto &read_single_info = zone_behavior.output.emplace<sim_output::ReadSingle>();
1466 read_single_info.state = frame_cache.state;
1467 }
1468
1469 void read_interpolated(const int prev_frame_index,
1470 const int next_frame_index,
1471 bake::SimulationNodeCache &node_cache,
1472 nodes::SimulationZoneBehavior &zone_behavior) const
1473 {
1474 bake::FrameCache &prev_frame_cache = *node_cache.bake.frames[prev_frame_index];
1475 bake::FrameCache &next_frame_cache = *node_cache.bake.frames[next_frame_index];
1476 ensure_bake_loaded(node_cache.bake, prev_frame_cache);
1477 ensure_bake_loaded(node_cache.bake, next_frame_cache);
1478 auto &read_interpolated_info = zone_behavior.output.emplace<sim_output::ReadInterpolated>();
1479 read_interpolated_info.mix_factor = (float(current_frame_) - float(prev_frame_cache.frame)) /
1480 (float(next_frame_cache.frame) -
1481 float(prev_frame_cache.frame));
1482 read_interpolated_info.prev_state = prev_frame_cache.state;
1483 read_interpolated_info.next_state = next_frame_cache.state;
1484 }
1485};
1486
1488 private:
1489 const NodesModifierData &nmd_;
1490 const ModifierEvalContext &ctx_;
1491 Main *bmain_;
1492 SubFrame current_frame_;
1493 bake::ModifierCache *modifier_cache_;
1494 bool depsgraph_is_active_;
1495
1496 public:
1501
1503
1505 : nmd_(nmd), ctx_(ctx)
1506 {
1507 const Depsgraph *depsgraph = ctx_.depsgraph;
1508 current_frame_ = DEG_get_ctime(depsgraph);
1509 modifier_cache_ = nmd.runtime->cache.get();
1510 depsgraph_is_active_ = DEG_is_active(depsgraph);
1511 bmain_ = DEG_get_bmain(depsgraph);
1512 }
1513
1514 nodes::BakeNodeBehavior *get(const int id) const override
1515 {
1516 if (!modifier_cache_) {
1517 return nullptr;
1518 }
1519 std::lock_guard lock{modifier_cache_->mutex};
1520 return &this->data_by_node_id
1521 .lookup_or_add_cb(id,
1522 [&]() {
1523 auto data = std::make_unique<DataPerNode>();
1524 data->behavior.data_block_map = &data->data_block_map;
1525 this->init_bake_behavior(
1526 id, data->behavior, data->data_block_map);
1527 return data;
1528 })
1529 ->behavior;
1530 return nullptr;
1531 }
1532
1533 private:
1534 void init_bake_behavior(const int id,
1535 nodes::BakeNodeBehavior &behavior,
1536 NodesModifierBakeDataBlockMap &data_block_map) const
1537 {
1538 bake::BakeNodeCache &node_cache = *modifier_cache_->bake_cache_by_id.lookup_or_add_cb(
1539 id, []() { return std::make_unique<bake::BakeNodeCache>(); });
1540 const NodesModifierBake &bake = *nmd_.find_bake(id);
1541
1542 for (const NodesModifierDataBlock &data_block : Span{bake.data_blocks, bake.data_blocks_num}) {
1543 data_block_map.old_mappings.add(data_block, data_block.id);
1544 }
1545
1546 if (depsgraph_is_active_) {
1547 if (modifier_cache_->requested_bakes.contains(id)) {
1548 /* This node is baked during the current evaluation. */
1549 auto &store_info = behavior.behavior.emplace<sim_output::StoreNewState>();
1550 store_info.store_fn = [modifier_cache = modifier_cache_,
1551 node_cache = &node_cache,
1552 current_frame = current_frame_](bake::BakeState state) {
1553 std::lock_guard lock{modifier_cache->mutex};
1554 auto frame_cache = std::make_unique<bake::FrameCache>();
1555 frame_cache->frame = current_frame;
1556 frame_cache->state = std::move(state);
1557 auto &frames = node_cache->bake.frames;
1558 const int insert_index = binary_search::first_if(
1559 frames, [&](const std::unique_ptr<bake::FrameCache> &frame_cache) {
1560 return frame_cache->frame > current_frame;
1561 });
1562 frames.insert(insert_index, std::move(frame_cache));
1563 };
1564 return;
1565 }
1566 }
1567
1568 /* Try load baked data. */
1569 if (node_cache.bake.frames.is_empty()) {
1570 if (!node_cache.bake.failed_finding_bake) {
1571 if (!try_find_baked_data(bake, node_cache.bake, *bmain_, *ctx_.object, nmd_, id)) {
1572 node_cache.bake.failed_finding_bake = true;
1573 }
1574 }
1575 }
1576
1577 if (node_cache.bake.frames.is_empty()) {
1578 behavior.behavior.emplace<sim_output::PassThrough>();
1579 return;
1580 }
1581 const BakeFrameIndices frame_indices = get_bake_frame_indices(node_cache.bake.frames,
1582 current_frame_);
1583 if (frame_indices.current) {
1584 this->read_single(*frame_indices.current, node_cache, behavior);
1585 return;
1586 }
1587 if (frame_indices.prev && frame_indices.next) {
1588 this->read_interpolated(*frame_indices.prev, *frame_indices.next, node_cache, behavior);
1589 return;
1590 }
1591 if (frame_indices.prev) {
1592 this->read_single(*frame_indices.prev, node_cache, behavior);
1593 return;
1594 }
1595 if (frame_indices.next) {
1596 this->read_single(*frame_indices.next, node_cache, behavior);
1597 return;
1598 }
1600 }
1601
1602 void read_single(const int frame_index,
1603 bake::BakeNodeCache &node_cache,
1604 nodes::BakeNodeBehavior &behavior) const
1605 {
1606 bake::FrameCache &frame_cache = *node_cache.bake.frames[frame_index];
1607 ensure_bake_loaded(node_cache.bake, frame_cache);
1608 if (this->check_read_error(frame_cache, behavior)) {
1609 return;
1610 }
1611 auto &read_single_info = behavior.behavior.emplace<sim_output::ReadSingle>();
1612 read_single_info.state = frame_cache.state;
1613 }
1614
1615 void read_interpolated(const int prev_frame_index,
1616 const int next_frame_index,
1617 bake::BakeNodeCache &node_cache,
1618 nodes::BakeNodeBehavior &behavior) const
1619 {
1620 bake::FrameCache &prev_frame_cache = *node_cache.bake.frames[prev_frame_index];
1621 bake::FrameCache &next_frame_cache = *node_cache.bake.frames[next_frame_index];
1622 ensure_bake_loaded(node_cache.bake, prev_frame_cache);
1623 ensure_bake_loaded(node_cache.bake, next_frame_cache);
1624 if (this->check_read_error(prev_frame_cache, behavior) ||
1625 this->check_read_error(next_frame_cache, behavior))
1626 {
1627 return;
1628 }
1629 auto &read_interpolated_info = behavior.behavior.emplace<sim_output::ReadInterpolated>();
1630 read_interpolated_info.mix_factor = (float(current_frame_) - float(prev_frame_cache.frame)) /
1631 (float(next_frame_cache.frame) -
1632 float(prev_frame_cache.frame));
1633 read_interpolated_info.prev_state = prev_frame_cache.state;
1634 read_interpolated_info.next_state = next_frame_cache.state;
1635 }
1636
1637 [[nodiscard]] bool check_read_error(const bake::FrameCache &frame_cache,
1638 nodes::BakeNodeBehavior &behavior) const
1639 {
1640 if (frame_cache.meta_data_source && frame_cache.state.items_by_id.is_empty()) {
1641 auto &read_error_info = behavior.behavior.emplace<sim_output::ReadError>();
1642 read_error_info.message = RPT_("Cannot load the baked data");
1643 return true;
1644 }
1645 return false;
1646 }
1647};
1648
1651 const Span<bake::BakeDataBlockID> missing,
1652 FunctionRef<ID *(const bake::BakeDataBlockID &)> get_data_block)
1653{
1654 const int old_num = bake.data_blocks_num;
1655 const int new_num = old_num + missing.size();
1656 bake.data_blocks = reinterpret_cast<NodesModifierDataBlock *>(
1657 MEM_recallocN(bake.data_blocks, sizeof(NodesModifierDataBlock) * new_num));
1658 for (const int i : missing.index_range()) {
1659 NodesModifierDataBlock &data_block = bake.data_blocks[old_num + i];
1660 const blender::bke::bake::BakeDataBlockID &key = missing[i];
1661
1662 data_block.id_name = BLI_strdup(key.id_name.c_str());
1663 if (!key.lib_name.empty()) {
1664 data_block.lib_name = BLI_strdup(key.lib_name.c_str());
1665 }
1666 data_block.id_type = int(key.type);
1667 ID *id = get_data_block(key);
1668 if (id) {
1669 data_block.id = id;
1670 }
1671 }
1672 bake.data_blocks_num = new_num;
1673}
1674
1675void nodes_modifier_data_block_destruct(NodesModifierDataBlock *data_block, const bool do_id_user)
1676{
1677 MEM_SAFE_FREE(data_block->id_name);
1678 MEM_SAFE_FREE(data_block->lib_name);
1679 if (do_id_user) {
1680 id_us_min(data_block->id);
1681 }
1682}
1683
1691 NodesModifierData &nmd_eval,
1692 NodesModifierData &nmd_orig,
1693 NodesModifierSimulationParams &simulation_params,
1694 NodesModifierBakeParams &bake_params)
1695{
1696 Depsgraph *depsgraph = ctx.depsgraph;
1697 Main *bmain = DEG_get_bmain(depsgraph);
1698
1699 struct DataPerBake {
1700 bool reset_first = false;
1702 };
1703 Map<int, DataPerBake> writeback_data;
1704 for (auto item : simulation_params.data_by_zone_id.items()) {
1705 DataPerBake data;
1706 NodesModifierBake &bake = *nmd_eval.find_bake(item.key);
1707 if (item.value->data_block_map.old_mappings.size() < bake.data_blocks_num) {
1708 data.reset_first = true;
1709 }
1710 if (bake::SimulationNodeCache *node_cache = nmd_eval.runtime->cache->get_simulation_node_cache(
1711 item.key))
1712 {
1713 /* Only writeback if the bake node has actually baked anything. */
1714 if (!node_cache->bake.frames.is_empty() || node_cache->prev_cache.has_value()) {
1715 data.new_mappings = std::move(item.value->data_block_map.new_mappings);
1716 }
1717 }
1718 if (data.reset_first || !data.new_mappings.is_empty()) {
1719 writeback_data.add(item.key, std::move(data));
1720 }
1721 }
1722 for (auto item : bake_params.data_by_node_id.items()) {
1723 if (bake::BakeNodeCache *node_cache = nmd_eval.runtime->cache->get_bake_node_cache(item.key)) {
1724 /* Only writeback if the bake node has actually baked anything. */
1725 if (!node_cache->bake.frames.is_empty()) {
1726 DataPerBake data;
1727 data.new_mappings = std::move(item.value->data_block_map.new_mappings);
1728 writeback_data.add(item.key, std::move(data));
1729 }
1730 }
1731 }
1732
1733 if (writeback_data.is_empty()) {
1734 /* Nothing to do. */
1735 return;
1736 }
1737
1739 *depsgraph,
1740 [object_eval = ctx.object,
1741 bmain,
1742 &nmd_orig,
1743 &nmd_eval,
1744 writeback_data = std::move(writeback_data)]() {
1745 for (auto item : writeback_data.items()) {
1746 const int bake_id = item.key;
1747 DataPerBake data = item.value;
1748
1749 NodesModifierBake &bake_orig = *nmd_orig.find_bake(bake_id);
1750 NodesModifierBake &bake_eval = *nmd_eval.find_bake(bake_id);
1751
1752 if (data.reset_first) {
1753 /* Reset data-block list on original data. */
1754 dna::array::clear<NodesModifierDataBlock>(&bake_orig.data_blocks,
1755 &bake_orig.data_blocks_num,
1756 &bake_orig.active_data_block,
1757 [](NodesModifierDataBlock *data_block) {
1758 nodes_modifier_data_block_destruct(
1759 data_block, true);
1760 });
1761 /* Reset data-block list on evaluated data. */
1762 dna::array::clear<NodesModifierDataBlock>(&bake_eval.data_blocks,
1763 &bake_eval.data_blocks_num,
1764 &bake_eval.active_data_block,
1765 [](NodesModifierDataBlock *data_block) {
1766 nodes_modifier_data_block_destruct(
1767 data_block, false);
1768 });
1769 }
1770
1771 Vector<bake::BakeDataBlockID> sorted_new_mappings;
1772 sorted_new_mappings.extend(data.new_mappings.keys().begin(),
1773 data.new_mappings.keys().end());
1774 bool needs_reevaluation = false;
1775 /* Add new data block mappings to the original modifier. This may do a name lookup in
1776 * bmain to find the data block if there is not faster way to get it. */
1777 add_missing_data_block_mappings(
1778 bake_orig, sorted_new_mappings, [&](const bake::BakeDataBlockID &key) -> ID * {
1779 ID *id_orig = nullptr;
1780 if (ID *id_eval = data.new_mappings.lookup_default(key, nullptr)) {
1781 id_orig = DEG_get_original(id_eval);
1782 }
1783 else {
1784 needs_reevaluation = true;
1785 id_orig = BKE_libblock_find_name_and_library(
1786 bmain, short(key.type), key.id_name.c_str(), key.lib_name.c_str());
1787 }
1788 if (id_orig) {
1789 id_us_plus(id_orig);
1790 }
1791 return id_orig;
1792 });
1793 /* Add new data block mappings to the evaluated modifier. In most cases this makes it so
1794 * the evaluated modifier is in the same state as if it were copied from the updated
1795 * original again. The exception is when a missing data block was found that is not in
1796 * the depsgraph currently. */
1797 add_missing_data_block_mappings(
1798 bake_eval, sorted_new_mappings, [&](const bake::BakeDataBlockID &key) -> ID * {
1799 return data.new_mappings.lookup_default(key, nullptr);
1800 });
1801
1802 if (needs_reevaluation) {
1803 Object *object_orig = DEG_get_original(object_eval);
1804 DEG_id_tag_update(&object_orig->id, ID_RECALC_GEOMETRY);
1805 DEG_relations_tag_update(bmain);
1806 }
1807 }
1808 });
1809}
1810
1812 const ModifierEvalContext *ctx,
1813 bke::GeometrySet &geometry_set)
1814{
1815 using namespace blender;
1816 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
1817 if (nmd->node_group == nullptr) {
1818 return;
1819 }
1820 NodesModifierData *nmd_orig = reinterpret_cast<NodesModifierData *>(
1822 if (ID_MISSING(nmd_orig->node_group)) {
1823 return;
1824 }
1825
1827 nmd->settings.properties);
1828
1829 const bNodeTree &tree = *nmd->node_group;
1830 check_property_socket_sync(ctx->object, properties, md);
1831
1832 tree.ensure_topology_cache();
1833 const bNode *output_node = tree.group_output_node();
1834 if (output_node == nullptr) {
1835 BKE_modifier_set_error(ctx->object, md, "Node group must have a group output node");
1836 geometry_set.clear();
1837 return;
1838 }
1839
1840 Span<const bNodeSocket *> group_outputs = output_node->input_sockets().drop_back(1);
1841 if (group_outputs.is_empty()) {
1842 BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket");
1843 geometry_set.clear();
1844 return;
1845 }
1846
1847 const bNodeSocket *first_output_socket = group_outputs[0];
1848 if (!STREQ(first_output_socket->idname, "NodeSocketGeometry")) {
1849 BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry");
1850 geometry_set.clear();
1851 return;
1852 }
1853
1854 const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
1856 if (lf_graph_info == nullptr) {
1857 BKE_modifier_set_error(ctx->object, md, "Cannot evaluate node group");
1858 geometry_set.clear();
1859 return;
1860 }
1861
1862 bool use_orig_index_verts = false;
1863 bool use_orig_index_edges = false;
1864 bool use_orig_index_faces = false;
1865 if (const Mesh *mesh = geometry_set.get_mesh()) {
1866 use_orig_index_verts = CustomData_has_layer(&mesh->vert_data, CD_ORIGINDEX);
1867 use_orig_index_edges = CustomData_has_layer(&mesh->edge_data, CD_ORIGINDEX);
1868 use_orig_index_faces = CustomData_has_layer(&mesh->face_data, CD_ORIGINDEX);
1869 }
1870
1871 nodes::GeoNodesCallData call_data;
1872
1873 nodes::GeoNodesModifierData modifier_eval_data{};
1874 modifier_eval_data.depsgraph = ctx->depsgraph;
1875 modifier_eval_data.self_object = ctx->object;
1876 auto eval_log = std::make_unique<geo_log::GeoNodesLog>();
1877 call_data.modifier_data = &modifier_eval_data;
1878
1879 NodesModifierSimulationParams simulation_params(*nmd, *ctx);
1880 call_data.simulation_params = &simulation_params;
1881 NodesModifierBakeParams bake_params{*nmd, *ctx};
1882 call_data.bake_params = &bake_params;
1883
1884 Set<ComputeContextHash> socket_log_contexts;
1885 if (logging_enabled(ctx)) {
1886 call_data.eval_log = eval_log.get();
1887
1888 find_socket_log_contexts(*nmd, *ctx, socket_log_contexts);
1889 call_data.socket_log_contexts = &socket_log_contexts;
1890 }
1891
1892 nodes::GeoNodesSideEffectNodes side_effect_nodes;
1893 find_side_effect_nodes(*nmd, *ctx, side_effect_nodes, socket_log_contexts);
1894 call_data.side_effect_nodes = &side_effect_nodes;
1895
1896 bke::ModifierComputeContext modifier_compute_context{nullptr, *nmd};
1897
1899 tree, properties, modifier_compute_context, call_data, std::move(geometry_set));
1900
1901 if (logging_enabled(ctx)) {
1902 nmd_orig->runtime->eval_log = std::move(eval_log);
1903 }
1904
1905 if (DEG_is_active(ctx->depsgraph) && !(ctx->flag & MOD_APPLY_TO_ORIGINAL)) {
1906 add_data_block_items_writeback(*ctx, *nmd, *nmd_orig, simulation_params, bake_params);
1907 }
1908
1909 if (use_orig_index_verts || use_orig_index_edges || use_orig_index_faces) {
1910 if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
1911 /* Add #CD_ORIGINDEX layers if they don't exist already. This is required because the
1912 * #eModifierTypeFlag_SupportsMapping flag is set. If the layers did not exist before, it is
1913 * assumed that the output mesh does not have a mapping to the original mesh. */
1914 if (use_orig_index_verts) {
1915 CustomData_add_layer(&mesh->vert_data, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->verts_num);
1916 }
1917 if (use_orig_index_edges) {
1918 CustomData_add_layer(&mesh->edge_data, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->edges_num);
1919 }
1920 if (use_orig_index_faces) {
1921 CustomData_add_layer(&mesh->face_data, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->faces_num);
1922 }
1923 }
1924 }
1925}
1926
1928{
1931
1932 modifyGeometry(md, ctx, geometry_set);
1933
1934 bke::MeshComponent &mesh_component = geometry_set.get_component_for_write<bke::MeshComponent>();
1935 if (mesh_component.get() != mesh) {
1936 /* If this is the same as the input mesh, it's not necessary to make a copy of it even if it's
1937 * not owned by the geometry set. That's because we know that the caller manages the ownership
1938 * of the mesh. */
1939 mesh_component.ensure_owns_direct_data();
1940 }
1941 Mesh *new_mesh = mesh_component.release();
1942 if (new_mesh == nullptr) {
1943 return BKE_mesh_new_nomain(0, 0, 0, 0);
1944 }
1945 return new_mesh;
1946}
1947
1949 const ModifierEvalContext *ctx,
1950 bke::GeometrySet *geometry_set)
1951{
1952 modifyGeometry(md, ctx, *geometry_set);
1953}
1954
1955static void panel_draw(const bContext *C, Panel *panel)
1956{
1957 uiLayout *layout = panel->layout;
1958 PointerRNA *modifier_ptr = modifier_panel_get_property_pointers(panel, nullptr);
1959 nodes::draw_geometry_nodes_modifier_ui(*C, modifier_ptr, *layout);
1960}
1961
1962static void panel_register(ARegionType *region_type)
1963{
1964 using namespace blender;
1966}
1967
1968static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
1969{
1970 const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
1971
1972 BLO_write_struct(writer, NodesModifierData, nmd);
1973
1974 BLO_write_string(writer, nmd->bake_directory);
1975
1976 if (nmd->settings.properties != nullptr) {
1978 if (!BLO_write_is_undo(writer)) {
1979 /* Boolean properties are added automatically for boolean node group inputs. Integer
1980 * properties are automatically converted to boolean sockets where applicable as well.
1981 * However, boolean properties will crash old versions of Blender, so convert them to integer
1982 * properties for writing. The actual value is stored in the same variable for both types */
1984 if (prop->type == IDP_BOOLEAN) {
1985 boolean_props.add_new(prop, reinterpret_cast<IDPropertyUIDataBool *>(prop->ui_data));
1986 prop->type = IDP_INT;
1987 prop->ui_data = nullptr;
1988 }
1989 }
1990 }
1991
1992 /* Note that the property settings are based on the socket type info
1993 * and don't necessarily need to be written, but we can't just free them. */
1994 IDP_BlendWrite(writer, nmd->settings.properties);
1995
1997 for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
1998 BLO_write_string(writer, bake.directory);
1999
2001 writer, NodesModifierDataBlock, bake.data_blocks_num, bake.data_blocks);
2002 for (const NodesModifierDataBlock &item : Span(bake.data_blocks, bake.data_blocks_num)) {
2003 BLO_write_string(writer, item.id_name);
2004 BLO_write_string(writer, item.lib_name);
2005 }
2006 if (bake.packed) {
2009 writer, NodesModifierBakeFile, bake.packed->meta_files_num, bake.packed->meta_files);
2011 writer, NodesModifierBakeFile, bake.packed->blob_files_num, bake.packed->blob_files);
2012 const auto write_bake_file = [&](const NodesModifierBakeFile &bake_file) {
2013 BLO_write_string(writer, bake_file.name);
2014 if (bake_file.packed_file) {
2015 BKE_packedfile_blend_write(writer, bake_file.packed_file);
2016 }
2017 };
2018 for (const NodesModifierBakeFile &meta_file :
2019 Span{bake.packed->meta_files, bake.packed->meta_files_num})
2020 {
2021 write_bake_file(meta_file);
2022 }
2023 for (const NodesModifierBakeFile &blob_file :
2024 Span{bake.packed->blob_files, bake.packed->blob_files_num})
2025 {
2026 write_bake_file(blob_file);
2027 }
2028 }
2029 }
2031
2032 if (!BLO_write_is_undo(writer)) {
2034 if (prop->type == IDP_INT) {
2035 if (IDPropertyUIDataBool **ui_data = boolean_props.lookup_ptr(prop)) {
2036 prop->type = IDP_BOOLEAN;
2037 if (ui_data) {
2038 prop->ui_data = reinterpret_cast<IDPropertyUIData *>(*ui_data);
2039 }
2040 }
2041 }
2042 }
2043 }
2044 }
2045}
2046
2047static void blend_read(BlendDataReader *reader, ModifierData *md)
2048{
2049 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
2050 BLO_read_string(reader, &nmd->bake_directory);
2051 if (nmd->node_group == nullptr) {
2052 nmd->settings.properties = nullptr;
2053 }
2054 else {
2056 IDP_BlendDataRead(reader, &nmd->settings.properties);
2057 }
2058
2060
2061 if (nmd->bakes_num > 0 && nmd->bakes == nullptr) {
2062 /* This case generally shouldn't be allowed to happen. However, there is a bug report with a
2063 * corrupted .blend file (#123974) that triggers this case. Unfortunately, it's not clear how
2064 * that could have happened. For now, handle this case more gracefully in release builds, while
2065 * still crashing in debug builds. */
2066 nmd->bakes_num = 0;
2068 }
2069
2070 for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
2071 BLO_read_string(reader, &bake.directory);
2072
2073 BLO_read_struct_array(reader, NodesModifierDataBlock, bake.data_blocks_num, &bake.data_blocks);
2074 for (NodesModifierDataBlock &data_block : MutableSpan(bake.data_blocks, bake.data_blocks_num))
2075 {
2076 BLO_read_string(reader, &data_block.id_name);
2077 BLO_read_string(reader, &data_block.lib_name);
2078 }
2079
2081 if (bake.packed) {
2083 reader, NodesModifierBakeFile, bake.packed->meta_files_num, &bake.packed->meta_files);
2085 reader, NodesModifierBakeFile, bake.packed->blob_files_num, &bake.packed->blob_files);
2086 const auto read_bake_file = [&](NodesModifierBakeFile &bake_file) {
2087 BLO_read_string(reader, &bake_file.name);
2088 if (bake_file.packed_file) {
2089 BKE_packedfile_blend_read(reader, &bake_file.packed_file, "");
2090 }
2091 };
2092 for (NodesModifierBakeFile &meta_file :
2093 MutableSpan{bake.packed->meta_files, bake.packed->meta_files_num})
2094 {
2095 read_bake_file(meta_file);
2096 }
2097 for (NodesModifierBakeFile &blob_file :
2098 MutableSpan{bake.packed->blob_files, bake.packed->blob_files_num})
2099 {
2100 read_bake_file(blob_file);
2101 }
2102 }
2103 }
2105
2106 nmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
2107 nmd->runtime->cache = std::make_shared<bake::ModifierCache>();
2108}
2109
2110static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
2111{
2112 const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
2113 NodesModifierData *tnmd = reinterpret_cast<NodesModifierData *>(target);
2114
2116
2117 if (nmd->bakes) {
2118 tnmd->bakes = static_cast<NodesModifierBake *>(MEM_dupallocN(nmd->bakes));
2119 for (const int i : IndexRange(nmd->bakes_num)) {
2120 NodesModifierBake &bake = tnmd->bakes[i];
2121 if (bake.directory) {
2122 bake.directory = BLI_strdup(bake.directory);
2123 }
2124 if (bake.data_blocks) {
2125 bake.data_blocks = static_cast<NodesModifierDataBlock *>(MEM_dupallocN(bake.data_blocks));
2126 for (const int i : IndexRange(bake.data_blocks_num)) {
2127 NodesModifierDataBlock &data_block = bake.data_blocks[i];
2128 if (data_block.id_name) {
2129 data_block.id_name = BLI_strdup(data_block.id_name);
2130 }
2131 if (data_block.lib_name) {
2132 data_block.lib_name = BLI_strdup(data_block.lib_name);
2133 }
2134 }
2135 }
2136 if (bake.packed) {
2137 bake.packed = static_cast<NodesModifierPackedBake *>(MEM_dupallocN(bake.packed));
2138 const auto copy_bake_files_inplace = [](NodesModifierBakeFile **bake_files,
2139 const int bake_files_num) {
2140 if (!*bake_files) {
2141 return;
2142 }
2143 *bake_files = static_cast<NodesModifierBakeFile *>(MEM_dupallocN(*bake_files));
2144 for (NodesModifierBakeFile &bake_file : MutableSpan{*bake_files, bake_files_num}) {
2145 bake_file.name = BLI_strdup_null(bake_file.name);
2146 if (bake_file.packed_file) {
2147 bake_file.packed_file = BKE_packedfile_duplicate(bake_file.packed_file);
2148 }
2149 }
2150 };
2151 copy_bake_files_inplace(&bake.packed->meta_files, bake.packed->meta_files_num);
2152 copy_bake_files_inplace(&bake.packed->blob_files, bake.packed->blob_files_num);
2153 }
2154 }
2155 }
2156
2157 if (nmd->panels) {
2158 tnmd->panels = static_cast<NodesModifierPanel *>(MEM_dupallocN(nmd->panels));
2159 }
2160
2161 tnmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
2162
2164 /* Share the simulation cache between the original and evaluated modifier. */
2165 tnmd->runtime->cache = nmd->runtime->cache;
2166 /* Keep bake path in the evaluated modifier. */
2167 tnmd->bake_directory = nmd->bake_directory ? BLI_strdup(nmd->bake_directory) : nullptr;
2168 }
2169 else {
2170 tnmd->runtime->cache = std::make_shared<bake::ModifierCache>();
2171 /* Clear the bake path when duplicating. */
2172 tnmd->bake_directory = nullptr;
2173 }
2174
2175 if (nmd->settings.properties != nullptr) {
2177 }
2178}
2179
2181{
2182 const auto free_packed_files = [](NodesModifierBakeFile *files, const int files_num) {
2183 for (NodesModifierBakeFile &file : MutableSpan{files, files_num}) {
2184 MEM_SAFE_FREE(file.name);
2185 if (file.packed_file) {
2186 BKE_packedfile_free(file.packed_file);
2187 }
2188 }
2189 MEM_SAFE_FREE(files);
2190 };
2191 free_packed_files(packed_bake->meta_files, packed_bake->meta_files_num);
2192 free_packed_files(packed_bake->blob_files, packed_bake->blob_files_num);
2193 MEM_SAFE_FREE(packed_bake);
2194}
2195
2197{
2198 MEM_SAFE_FREE(bake->directory);
2199
2200 for (NodesModifierDataBlock &data_block : MutableSpan(bake->data_blocks, bake->data_blocks_num))
2201 {
2202 nodes_modifier_data_block_destruct(&data_block, do_id_user);
2203 }
2204 MEM_SAFE_FREE(bake->data_blocks);
2205
2206 if (bake->packed) {
2208 }
2209}
2210
2211static void free_data(ModifierData *md)
2212{
2213 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
2214 if (nmd->settings.properties != nullptr) {
2216 nmd->settings.properties = nullptr;
2217 }
2218
2219 for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
2221 }
2222 MEM_SAFE_FREE(nmd->bakes);
2223
2224 MEM_SAFE_FREE(nmd->panels);
2225
2227 MEM_delete(nmd->runtime);
2228}
2229
2230static void required_data_mask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
2231{
2232 /* We don't know what the node tree will need. If there are vertex groups, it is likely that the
2233 * node tree wants to access them. */
2234 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
2235 r_cddata_masks->vmask |= CD_MASK_PROP_ALL;
2236}
2237
2238} // namespace blender
2239
2241 /*idname*/ "GeometryNodes",
2242 /*name*/ N_("GeometryNodes"),
2243 /*struct_name*/ "NodesModifierData",
2244 /*struct_size*/ sizeof(NodesModifierData),
2245 /*srna*/ &RNA_NodesModifier,
2247 /*flags*/
2251 /*icon*/ ICON_GEOMETRY_NODES,
2252
2253 /*copy_data*/ blender::copy_data,
2254
2255 /*deform_verts*/ nullptr,
2256 /*deform_matrices*/ nullptr,
2257 /*deform_verts_EM*/ nullptr,
2258 /*deform_matrices_EM*/ nullptr,
2259 /*modify_mesh*/ blender::modify_mesh,
2260 /*modify_geometry_set*/ blender::modify_geometry_set,
2261
2262 /*init_data*/ blender::init_data,
2263 /*required_data_mask*/ blender::required_data_mask,
2264 /*free_data*/ blender::free_data,
2265 /*is_disabled*/ blender::is_disabled,
2266 /*update_depsgraph*/ blender::update_depsgraph,
2267 /*depends_on_time*/ blender::depends_on_time,
2268 /*depends_on_normals*/ nullptr,
2269 /*foreach_ID_link*/ blender::foreach_ID_link,
2270 /*foreach_tex_link*/ blender::foreach_tex_link,
2271 /*free_runtime_data*/ nullptr,
2272 /*panel_register*/ blender::panel_register,
2273 /*blend_write*/ blender::blend_write,
2274 /*blend_read*/ blender::blend_read,
2275 /*foreach_cache*/ nullptr,
2276};
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_foreach_property(IDProperty *id_property_root, int type_filter, blender::FunctionRef< void(IDProperty *id_property)> callback)
#define IDP_BlendDataRead(reader, prop)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1243
IDProperty * IDP_CopyProperty_ex(const IDProperty *prop, int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:855
void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop)
Definition idprop.cc:1453
void IDP_FreeProperty_ex(IDProperty *prop, bool do_id_user)
Definition idprop.cc:1237
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
void id_us_min(ID *id)
Definition lib_id.cc:361
@ IDWALK_CB_USER
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void(*)(void *user_data, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag cb_flag) IDWalkFunc
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
@ eModifierTypeFlag_AcceptsCVs
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
ModifierData * BKE_modifier_get_original(const Object *object, ModifierData *md)
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
@ MOD_APPLY_TO_ORIGINAL
@ MOD_APPLY_ORCO
#define GEO_NODE_SIMULATION_OUTPUT
#define GEO_NODE_BAKE
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:612
WorkSpace * BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:561
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.cc:46
#define 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:5351
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)
void DEG_id_tag_update(ID *id, unsigned int flags)
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:323
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
@ DEG_OB_COMP_PARAMETERS
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)
bool DEG_is_evaluated(const T *id)
Main * DEG_get_bmain(const Depsgraph *graph)
T * DEG_get_original(T *id)
Scene * DEG_get_input_scene(const Depsgraph *graph)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
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 DNA_struct_default_get(struct_name)
@ eModifierFlag_UserModified
@ NODES_MODIFIER_PANEL_WARNINGS
@ NODES_MODIFIER_PANEL_OPEN
@ eModifierType_Nodes
struct NodesModifierBake NodesModifierBake
@ NODES_MODIFIER_BAKE_MODE_STILL
@ NODES_MODIFIER_BAKE_MODE_ANIMATION
@ NODE_INTERFACE_PANEL_DEFAULT_CLOSED
@ NTREE_GEOMETRY
eNodeSocketDatatype
@ SOCK_CLOSURE
@ SOCK_MATRIX
@ SOCK_CUSTOM
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ OB_CAMERA
@ OB_CURVES
@ OB_FLAG_USE_SIMULATION_CACHE
#define FPS
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_VIEW3D
static bool is_disabled
Read Guarded memory(de)allocation.
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:271
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
Definition MOD_bevel.cc:433
static bool depends_on_time(Scene *, ModifierData *)
Definition MOD_build.cc:47
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:448
ModifierTypeInfo modifierType_Nodes
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
#define C
Definition RandGen.cpp:29
volatile int lock
BMesh const char void * data
BPy_StructRNA * depsgraph
SubIterator begin() const
Definition BLI_map.hh:768
SubIterator end() const
Definition BLI_map.hh:778
ValueIterator values() const &
Definition BLI_map.hh:884
bool contains(const Key &key) const
Definition BLI_set.hh:310
const ComputeContext * parent() const
const ComputeContextHash & hash() const
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
ValueIterator values() const &
Definition BLI_map.hh:884
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
KeyIterator keys() const &
Definition BLI_map.hh:875
bool is_empty() const
Definition BLI_map.hh:986
bool contains(const Key &key) const
Definition BLI_map.hh:353
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:588
ID * lookup_or_remember_missing(const bake::BakeDataBlockID &key) override
Definition MOD_nodes.cc:965
Map< bake::BakeDataBlockID, ID * > old_mappings
Definition MOD_nodes.cc:962
Map< bake::BakeDataBlockID, ID * > new_mappings
Definition MOD_nodes.cc:963
NodesModifierBakeParams(NodesModifierData &nmd, const ModifierEvalContext &ctx)
Map< int, std::unique_ptr< DataPerNode > > data_by_node_id
nodes::BakeNodeBehavior * get(const int id) const override
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:310
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
Key lookup_key_default_as(const ForwardKey &key, ForwardDefault &&...default_key) 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 ModifierComputeContext & for_modifier(const ComputeContext *parent, const NodesModifierData &nmd)
const GroupNodeComputeContext & for_group_node(const ComputeContext *parent, int32_t node_id, const bNodeTree *tree=nullptr)
const bNode * output_node() const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
static Map< const bke::bNodeTreeZone *, ComputeContextHash > get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
KDTree_3d * tree
#define MEM_recallocN(vmemh, len)
#define CD_MASK_MDEFORMVERT
#define MEM_SAFE_FREE(v)
#define CD_MASK_PROP_ALL
#define GS(a)
#define ID_MISSING(_id)
static void update_depsgraph(tGraphSliderOp *gso)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
static ulong state[N]
static int64_t first_if(Iterator begin, Iterator end, Predicate &&predicate)
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)
std::optional< BakeState > deserialize_bake(std::istream &stream, const BlobReader &blob_reader, const BlobReadSharing &blob_sharing)
std::optional< SubFrame > file_name_to_frame(StringRef file_name)
Vector< MetaFile > find_sorted_meta_files(StringRefNull meta_dir)
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRef prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
void add(Depsgraph &depsgraph, std::function< void()> fn)
bool node_editor_is_for_geometry_nodes_modifier(const SpaceNode &snode, const Object &object, const NodesModifierData &nmd)
std::optional< ViewerPathForGeometryNodesViewer > parse_geometry_nodes_viewer(const ViewerPath &viewer_path)
const ComputeContext * compute_context_for_viewer_path_elem(const ViewerPathElem &elem, bke::ComputeContextCache &compute_context_cache, const ComputeContext *parent_compute_context)
void foreach_active_gizmo_in_modifier(const Object &object, const NodesModifierData &nmd, const wmWindowManager &wm, bke::ComputeContextCache &compute_context_cache, 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)
bke::GeometrySet execute_geometry_nodes_on_geometry(const bNodeTree &btree, const PropertiesVectorSet &properties_set, const ComputeContext &base_compute_context, GeoNodesCallData &call_data, bke::GeometrySet input_geometry)
PropertiesVectorSet build_properties_vector_set(const IDProperty *properties)
void update_input_properties_from_node_tree(const bNodeTree &tree, const IDProperty *old_properties, IDProperty &properties, const bool use_name_for_ids)
bool id_property_type_matches_socket(const bNodeTreeInterfaceSocket &socket, const IDProperty &property, const bool use_name_for_ids)
CustomIDVectorSet< IDProperty *, IDPropNameGetter, 16 > PropertiesVectorSet
void draw_geometry_nodes_modifier_ui(const bContext &C, PointerRNA *modifier_ptr, uiLayout &layout)
const GeometryNodesLazyFunctionGraphInfo * ensure_geometry_nodes_lazy_function_graph(const bNodeTree &btree)
void update_output_properties_from_node_tree(const bNodeTree &tree, const IDProperty *old_properties, IDProperty &properties)
GeometryNodesEvalDependencies gather_geometry_nodes_eval_dependencies_recursive(const bNodeTree &ntree)
static bool depends_on_time(Scene *, ModifierData *md)
static bool logging_enabled(const ModifierEvalContext *ctx)
Definition MOD_nodes.cc:290
static void find_side_effect_nodes_for_baking(const NodesModifierData &nmd, const ModifierEvalContext &ctx, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
Definition MOD_nodes.cc:781
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
static void find_dependencies_from_settings(const NodesModifierSettings &settings, nodes::GeometryNodesEvalDependencies &deps)
Definition MOD_nodes.cc:113
static void init_data(ModifierData *md)
static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Object &object, const nodes::GeometryNodesEvalDependencies::ObjectDependencyInfo &info)
Definition MOD_nodes.cc:137
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void panel_draw(const bContext *C, Panel *panel)
static BakeFrameIndices get_bake_frame_indices(const Span< std::unique_ptr< bake::FrameCache > > frame_caches, const SubFrame frame)
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 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:702
static void try_add_side_effect_node(const ModifierEvalContext &ctx, const ComputeContext &final_compute_context, const int final_node_id, const NodesModifierData &nmd, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
Definition MOD_nodes.cc:480
void nodes_modifier_data_block_destruct(NodesModifierDataBlock *data_block, const bool do_id_user)
void nodes_modifier_bake_destruct(NodesModifierBake *bake, const bool do_id_user)
static const CustomData_MeshMasks dependency_data_mask
Definition MOD_nodes.cc:124
static void free_data(ModifierData *md)
static void update_bakes_from_node_group(NodesModifierData &nmd)
Definition MOD_nodes.cc:346
static void panel_register(ARegionType *region_type)
static void check_property_socket_sync(const Object *ob, const nodes::PropertiesVectorSet &properties, ModifierData *md)
Definition MOD_nodes.cc:903
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:801
static void add_data_block_items_writeback(const ModifierEvalContext &ctx, NodesModifierData &nmd_eval, NodesModifierData &nmd_orig, NodesModifierSimulationParams &simulation_params, NodesModifierBakeParams &bake_params)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
Definition MOD_nodes.cc:272
static void update_id_properties_from_node_group(NodesModifierData *nmd)
Definition MOD_nodes.cc:301
static void modifyGeometry(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet &geometry_set)
static void remove_outdated_bake_caches(NodesModifierData &nmd)
Definition MOD_nodes.cc:324
std::mutex Mutex
Definition BLI_mutex.hh:47
static void ensure_bake_loaded(bake::NodeBakeCache &bake_cache, bake::FrameCache &frame_cache)
static void find_side_effect_nodes_for_nested_node(const ModifierEvalContext &ctx, const NodesModifierData &nmd, const int root_nested_node_id, nodes::GeoNodesSideEffectNodes &r_side_effect_nodes)
Definition MOD_nodes.cc:733
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 update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static void find_socket_log_contexts(const NodesModifierData &nmd, const ModifierEvalContext &ctx, Set< ComputeContextHash > &r_socket_log_contexts)
Definition MOD_nodes.cc:866
void nodes_modifier_packed_bake_free(NodesModifierPackedBake *packed_bake)
static bool is_disabled(const Scene *, ModifierData *md, bool)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static void add_collection_relation(const ModifierUpdateDepsgraphContext *ctx, Collection &collection)
Definition MOD_nodes.cc:130
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:833
static void update_panels_from_node_group(NodesModifierData &nmd)
Definition MOD_nodes.cc:403
#define hash
Definition noise_c.cc:154
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
struct Object * surface
ListBase group
Definition DNA_ID.h:138
IDPropertyData data
Definition DNA_ID.h:159
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
unsigned int session_uid
Definition DNA_ID.h:444
void * first
ListBase wm
Definition BKE_main.hh:276
uint16_t layout_panel_open_flag
ModifierApplyFlag flag
NodesModifierDataBlock * data_blocks
NodesModifierPackedBake * packed
NodesModifierPanel * panels
struct bNodeTree * node_group
NodesModifierRuntimeHandle * runtime
struct NodesModifierSettings settings
NodesModifierBake * bakes
NodesModifierBakeFile * meta_files
NodesModifierBakeFile * blob_files
struct IDProperty * properties
struct uiLayout * layout
struct bNodeTree * edittree
SpreadsheetTableIDGeometry geometry_id
ViewerPath viewer_path
ViewerPath viewer_path
bNestedNodePath path
char idname[64]
bNodeTreeRuntimeHandle * runtime
bNodeTreeInterface tree_interface
struct ID * id
int16_t type_legacy
int32_t identifier
ListBase areabase
std::optional< int > current
std::optional< int > prev
std::optional< int > next
NodesModifierBakeDataBlockMap data_block_map
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const Mesh * get_mesh() const
Defines a socket type.
Definition BKE_node.hh:152
eNodeSocketDatatype type
Definition BKE_node.hh:187
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
void add_object(Object *object, const ObjectDependencyInfo &object_deps=all_object_deps)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4226
uint8_t flag
Definition wm_window.cc:139