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