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