From 2c435ce8dfa9e042df4ddd93ee82b0230eb2b777 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 5 Aug 2025 06:25:20 +0200 Subject: [PATCH] Fix #141469: Geometry Nodes: use safer approach to modifying each instance geometry Many nodes operate on all the instances that are passed into them. For example, the Subdivision Surface node subdivides the mesh at the root but also instanced meshes. This works well for most nodes, but there are a few nodes were the old `modify_geometry_sets` function was not very well defined and it was tricky to use correctly. The fundamental problem was that the behavior is not obvious when a node creates or modifies instances and how those are integrated with the already existing instances. This patch solves this with the following changes: * Remove the old `GeometrySet::modify_geometry_sets` and related `*_during_modify` methods. * Add a new `blender::geometry::foreach_real_geometry` function that is similar to the old `modify_geometry_sets` but has a more well-defined interface: * It never passes instances into the callback. So existing instances can't be modified with it. * The callback is allowed to create new instances. This will automatically be merged back with potentially already existing instances. The callback does not have to worry about accidentally invalidating existing instances like before. * A few existing usages used `modify_geometry_sets` to actually modify existing instances (usually just removing attributes). Those can't use the new `foreach_real_geometry`, so they just get a custom simple recursive implementation instead of using a generic function. Pull Request: https://projects.blender.org/blender/blender/pulls/143898 --- source/blender/blenkernel/BKE_geometry_set.hh | 14 -- source/blender/blenkernel/BKE_instances.hh | 2 + .../blender/blenkernel/intern/bake_items.cc | 160 ++++++++++-------- .../blender/blenkernel/intern/geometry_set.cc | 46 ----- source/blender/blenkernel/intern/instances.cc | 5 + source/blender/geometry/CMakeLists.txt | 2 + .../blender/geometry/GEO_foreach_geometry.hh | 19 +++ .../blender/geometry/GEO_join_geometries.hh | 10 +- .../geometry/intern/foreach_geometry.cc | 105 ++++++++++++ .../geometry/intern/join_geometries.cc | 21 ++- .../geometry/intern/realize_instances.cc | 14 +- .../nodes/node_geo_attribute_capture.cc | 4 +- .../geometry/nodes/node_geo_bounding_box.cc | 7 +- .../geometry/nodes/node_geo_convex_hull.cc | 7 +- .../geometry/nodes/node_geo_curve_fill.cc | 7 +- .../geometry/nodes/node_geo_curve_fillet.cc | 3 +- .../geometry/nodes/node_geo_curve_resample.cc | 7 +- .../geometry/nodes/node_geo_curve_reverse.cc | 4 +- .../nodes/node_geo_curve_set_handle_type.cc | 4 +- .../nodes/node_geo_curve_spline_type.cc | 3 +- .../nodes/node_geo_curve_subdivide.cc | 3 +- .../geometry/nodes/node_geo_curve_to_mesh.cc | 7 +- .../nodes/node_geo_curve_to_points.cc | 19 ++- .../geometry/nodes/node_geo_curve_trim.cc | 5 +- .../nodes/node_geo_delete_geometry.cc | 3 +- .../node_geo_distribute_points_in_volume.cc | 7 +- .../node_geo_distribute_points_on_faces.cc | 5 +- .../geometry/nodes/node_geo_dual_mesh.cc | 3 +- .../nodes/node_geo_duplicate_elements.cc | 21 ++- .../nodes/node_geo_edge_paths_to_curves.cc | 9 +- .../geometry/nodes/node_geo_edge_split.cc | 3 +- .../geometry/nodes/node_geo_extrude_mesh.cc | 3 +- .../geometry/nodes/node_geo_flip_faces.cc | 4 +- .../nodes/node_geo_instance_on_points.cc | 37 ++-- .../nodes/node_geo_material_replace.cc | 4 +- .../nodes/node_geo_merge_by_distance.cc | 3 +- .../geometry/nodes/node_geo_merge_layers.cc | 6 +- .../geometry/nodes/node_geo_mesh_subdivide.cc | 3 +- .../geometry/nodes/node_geo_mesh_to_curve.cc | 11 +- .../geometry/nodes/node_geo_mesh_to_points.cc | 10 +- .../geometry/nodes/node_geo_mesh_to_volume.cc | 5 +- .../nodes/node_geo_points_to_curves.cc | 5 +- .../nodes/node_geo_points_to_vertices.cc | 10 +- .../nodes/node_geo_points_to_volume.cc | 5 +- .../nodes/node_geo_remove_attribute.cc | 157 +++++++++-------- .../geometry/nodes/node_geo_scale_elements.cc | 3 +- .../nodes/node_geo_separate_geometry.cc | 3 +- .../nodes/node_geo_set_curve_handles.cc | 4 +- .../nodes/node_geo_set_curve_normal.cc | 4 +- .../nodes/node_geo_set_curve_radius.cc | 4 +- .../geometry/nodes/node_geo_set_curve_tilt.cc | 4 +- .../nodes/node_geo_set_grease_pencil_color.cc | 4 +- .../node_geo_set_grease_pencil_depth_mode.cc | 4 +- .../node_geo_set_grease_pencil_softness.cc | 4 +- .../geometry/nodes/node_geo_set_material.cc | 4 +- .../nodes/node_geo_set_material_index.cc | 4 +- .../nodes/node_geo_set_mesh_normal.cc | 8 +- .../nodes/node_geo_set_point_radius.cc | 4 +- .../nodes/node_geo_set_shade_smooth.cc | 4 +- .../nodes/node_geo_set_spline_cyclic.cc | 4 +- .../nodes/node_geo_set_spline_resolution.cc | 4 +- .../geometry/nodes/node_geo_sort_elements.cc | 3 +- .../nodes/node_geo_store_named_attribute.cc | 4 +- .../nodes/node_geo_subdivision_surface.cc | 3 +- .../nodes/node_geo_tool_set_face_set.cc | 4 +- .../nodes/node_geo_tool_set_selection.cc | 4 +- .../geometry/nodes/node_geo_triangulate.cc | 4 +- .../geometry/nodes/node_geo_volume_to_mesh.cc | 5 +- .../nodes/intern/geometry_nodes_execute.cc | 35 ++-- ...try_nodes_foreach_geometry_element_zone.cc | 3 +- .../intern/geometry_nodes_lazy_function.cc | 4 +- .../instance_on_points_in_instances.blend | 3 + 72 files changed, 577 insertions(+), 353 deletions(-) create mode 100644 source/blender/geometry/GEO_foreach_geometry.hh create mode 100644 source/blender/geometry/intern/foreach_geometry.cc create mode 100644 tests/files/modeling/geometry_nodes/instance/instance_on_points_in_instances.blend diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index fe3c97827f2..361b239cb11 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -210,12 +210,6 @@ struct GeometrySet { * Remove all geometry components with types that are not in the provided list. */ void keep_only(Span component_types); - /** - * Keeps the provided geometry types, but also instances and edit data. - * Instances must not be removed while using #modify_geometry_sets. - */ - void keep_only_during_modify(Span component_types); - void remove_geometry_during_modify(); void add(const GeometryComponent &component); @@ -272,14 +266,6 @@ struct GeometrySet { Vector gather_component_types(bool include_instances, bool ignore_empty) const; - using ForeachSubGeometryCallback = FunctionRef; - - /** - * Modify every (recursive) instance separately. This is often more efficient than realizing all - * instances just to change the same thing on all of them. - */ - void modify_geometry_sets(ForeachSubGeometryCallback callback); - /* Utility methods for creation. */ /** * Create a new geometry set that only contains the given mesh. diff --git a/source/blender/blenkernel/BKE_instances.hh b/source/blender/blenkernel/BKE_instances.hh index 9805f076b37..9cb441e7f93 100644 --- a/source/blender/blenkernel/BKE_instances.hh +++ b/source/blender/blenkernel/BKE_instances.hh @@ -168,6 +168,8 @@ class Instances { void add_instance(int instance_handle, const float4x4 &transform); Span references() const; + MutableSpan references_for_write(); + void remove_unused_references(); /** diff --git a/source/blender/blenkernel/intern/bake_items.cc b/source/blender/blenkernel/intern/bake_items.cc index 77c4d479f09..0829153cfff 100644 --- a/source/blender/blenkernel/intern/bake_items.cc +++ b/source/blender/blenkernel/intern/bake_items.cc @@ -53,52 +53,60 @@ static std::unique_ptr materials_to_weak_references( return materials_list; } +static void prepare_geometry_for_bake_recursive(GeometrySet &geometry, + BakeDataBlockMap *data_block_map) +{ + if (Mesh *mesh = geometry.get_mesh_for_write()) { + mesh->attributes_for_write().remove_anonymous(); + mesh->runtime->bake_materials = materials_to_weak_references( + &mesh->mat, &mesh->totcol, data_block_map); + } + if (Curves *curves = geometry.get_curves_for_write()) { + curves->geometry.wrap().attributes_for_write().remove_anonymous(); + curves->geometry.runtime->bake_materials = materials_to_weak_references( + &curves->mat, &curves->totcol, data_block_map); + } + if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) { + for (GreasePencilDrawingBase *base : grease_pencil->drawings()) { + if (base->type != GP_DRAWING) { + continue; + } + greasepencil::Drawing &drawing = reinterpret_cast(base)->wrap(); + drawing.strokes_for_write().attributes_for_write().remove_anonymous(); + } + grease_pencil->attributes_for_write().remove_anonymous(); + grease_pencil->runtime->bake_materials = materials_to_weak_references( + &grease_pencil->material_array, &grease_pencil->material_array_num, data_block_map); + } + if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { + pointcloud->attributes_for_write().remove_anonymous(); + pointcloud->runtime->bake_materials = materials_to_weak_references( + &pointcloud->mat, &pointcloud->totcol, data_block_map); + } + if (Volume *volume = geometry.get_volume_for_write()) { + volume->runtime->bake_materials = materials_to_weak_references( + &volume->mat, &volume->totcol, data_block_map); + } + if (bke::Instances *instances = geometry.get_instances_for_write()) { + instances->attributes_for_write().remove_anonymous(); + instances->ensure_geometry_instances(); + for (bke::InstanceReference &reference : instances->references_for_write()) { + if (reference.type() == bke::InstanceReference::Type::GeometrySet) { + prepare_geometry_for_bake_recursive(reference.geometry_set(), data_block_map); + } + else { + /* Can only bake geometry instances currently. */ + reference = bke::InstanceReference(); + } + } + } +} + void GeometryBakeItem::prepare_geometry_for_bake(GeometrySet &main_geometry, BakeDataBlockMap *data_block_map) { main_geometry.ensure_owns_all_data(); - main_geometry.modify_geometry_sets([&](GeometrySet &geometry) { - if (Mesh *mesh = geometry.get_mesh_for_write()) { - mesh->attributes_for_write().remove_anonymous(); - mesh->runtime->bake_materials = materials_to_weak_references( - &mesh->mat, &mesh->totcol, data_block_map); - } - if (Curves *curves = geometry.get_curves_for_write()) { - curves->geometry.wrap().attributes_for_write().remove_anonymous(); - curves->geometry.runtime->bake_materials = materials_to_weak_references( - &curves->mat, &curves->totcol, data_block_map); - } - if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) { - for (GreasePencilDrawingBase *base : grease_pencil->drawings()) { - if (base->type != GP_DRAWING) { - continue; - } - greasepencil::Drawing &drawing = reinterpret_cast(base)->wrap(); - drawing.strokes_for_write().attributes_for_write().remove_anonymous(); - } - grease_pencil->attributes_for_write().remove_anonymous(); - grease_pencil->runtime->bake_materials = materials_to_weak_references( - &grease_pencil->material_array, &grease_pencil->material_array_num, data_block_map); - } - if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - pointcloud->attributes_for_write().remove_anonymous(); - pointcloud->runtime->bake_materials = materials_to_weak_references( - &pointcloud->mat, &pointcloud->totcol, data_block_map); - } - if (Volume *volume = geometry.get_volume_for_write()) { - volume->runtime->bake_materials = materials_to_weak_references( - &volume->mat, &volume->totcol, data_block_map); - } - if (bke::Instances *instances = geometry.get_instances_for_write()) { - instances->attributes_for_write().remove_anonymous(); - } - geometry.keep_only_during_modify({GeometryComponent::Type::Mesh, - GeometryComponent::Type::Curve, - GeometryComponent::Type::GreasePencil, - GeometryComponent::Type::PointCloud, - GeometryComponent::Type::Volume, - GeometryComponent::Type::Instance}); - }); + prepare_geometry_for_bake_recursive(main_geometry, data_block_map); } static void restore_materials(Material ***materials, @@ -125,39 +133,47 @@ static void restore_materials(Material ***materials, } } +static void restore_data_blocks_recursive(GeometrySet &geometry, BakeDataBlockMap *data_block_map) +{ + if (Mesh *mesh = geometry.get_mesh_for_write()) { + restore_materials( + &mesh->mat, &mesh->totcol, std::move(mesh->runtime->bake_materials), data_block_map); + } + if (Curves *curves = geometry.get_curves_for_write()) { + restore_materials(&curves->mat, + &curves->totcol, + std::move(curves->geometry.runtime->bake_materials), + data_block_map); + } + if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) { + restore_materials(&grease_pencil->material_array, + &grease_pencil->material_array_num, + std::move(grease_pencil->runtime->bake_materials), + data_block_map); + } + if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { + restore_materials(&pointcloud->mat, + &pointcloud->totcol, + std::move(pointcloud->runtime->bake_materials), + data_block_map); + } + if (Volume *volume = geometry.get_volume_for_write()) { + restore_materials( + &volume->mat, &volume->totcol, std::move(volume->runtime->bake_materials), data_block_map); + } + if (bke::Instances *instances = geometry.get_instances_for_write()) { + for (bke::InstanceReference &reference : instances->references_for_write()) { + if (reference.type() == bke::InstanceReference::Type::GeometrySet) { + restore_data_blocks_recursive(reference.geometry_set(), data_block_map); + } + } + } +} + void GeometryBakeItem::try_restore_data_blocks(GeometrySet &main_geometry, BakeDataBlockMap *data_block_map) { - main_geometry.modify_geometry_sets([&](GeometrySet &geometry) { - if (Mesh *mesh = geometry.get_mesh_for_write()) { - restore_materials( - &mesh->mat, &mesh->totcol, std::move(mesh->runtime->bake_materials), data_block_map); - } - if (Curves *curves = geometry.get_curves_for_write()) { - restore_materials(&curves->mat, - &curves->totcol, - std::move(curves->geometry.runtime->bake_materials), - data_block_map); - } - if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) { - restore_materials(&grease_pencil->material_array, - &grease_pencil->material_array_num, - std::move(grease_pencil->runtime->bake_materials), - data_block_map); - } - if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - restore_materials(&pointcloud->mat, - &pointcloud->totcol, - std::move(pointcloud->runtime->bake_materials), - data_block_map); - } - if (Volume *volume = geometry.get_volume_for_write()) { - restore_materials(&volume->mat, - &volume->totcol, - std::move(volume->runtime->bake_materials), - data_block_map); - } - }); + restore_data_blocks_recursive(main_geometry, data_block_map); } #ifdef WITH_OPENVDB diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 22bd4bdbd8d..d397b64a254 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -164,19 +164,6 @@ void GeometrySet::keep_only(const Span component_types) } } -void GeometrySet::keep_only_during_modify(const Span component_types) -{ - Vector extended_types = component_types; - extended_types.append_non_duplicates(GeometryComponent::Type::Instance); - extended_types.append_non_duplicates(GeometryComponent::Type::Edit); - this->keep_only(extended_types); -} - -void GeometrySet::remove_geometry_during_modify() -{ - this->keep_only_during_modify({}); -} - void GeometrySet::add(const GeometryComponent &component) { BLI_assert(!components_[size_t(component.type())]); @@ -796,39 +783,6 @@ Vector GeometrySet::gather_component_types(const bool i return types; } -static void gather_mutable_geometry_sets(GeometrySet &geometry_set, - Vector &r_geometry_sets) -{ - r_geometry_sets.append(&geometry_set); - if (!geometry_set.has_instances()) { - return; - } - /* In the future this can be improved by deduplicating instance references across different - * instances. */ - Instances &instances = *geometry_set.get_instances_for_write(); - instances.ensure_geometry_instances(); - for (const int handle : instances.references().index_range()) { - if (instances.references()[handle].type() == InstanceReference::Type::GeometrySet) { - GeometrySet &instance_geometry = instances.geometry_set_from_reference(handle); - gather_mutable_geometry_sets(instance_geometry, r_geometry_sets); - } - } -} - -void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback) -{ - Vector geometry_sets; - gather_mutable_geometry_sets(*this, geometry_sets); - if (geometry_sets.size() == 1) { - /* Avoid possible overhead and a large call stack when multithreading is pointless. */ - callback(*geometry_sets.first()); - } - else { - threading::parallel_for_each(geometry_sets, - [&](GeometrySet *geometry_set) { callback(*geometry_set); }); - } -} - bool object_has_geometry_set_instances(const Object &object) { const GeometrySet *geometry_set = object.runtime->geometry_set_eval; diff --git a/source/blender/blenkernel/intern/instances.cc b/source/blender/blenkernel/intern/instances.cc index f13b6594f77..5d9f1fb7fc7 100644 --- a/source/blender/blenkernel/intern/instances.cc +++ b/source/blender/blenkernel/intern/instances.cc @@ -275,6 +275,11 @@ Span Instances::references() const return references_; } +MutableSpan Instances::references_for_write() +{ + return references_; +} + void Instances::remove(const IndexMask &mask, const AttributeFilter &attribute_filter) { const std::optional masked_range = mask.to_range(); diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt index e0fea3982b7..096d61fcd20 100644 --- a/source/blender/geometry/CMakeLists.txt +++ b/source/blender/geometry/CMakeLists.txt @@ -20,6 +20,7 @@ set(SRC intern/fillet_curves.cc intern/fit_curves.cc intern/interpolate_curves.cc + intern/foreach_geometry.cc intern/join_geometries.cc intern/merge_curves.cc intern/merge_layers.cc @@ -63,6 +64,7 @@ set(SRC GEO_extract_elements.hh GEO_fillet_curves.hh GEO_fit_curves.hh + GEO_foreach_geometry.hh GEO_interpolate_curves.hh GEO_join_geometries.hh GEO_merge_curves.hh diff --git a/source/blender/geometry/GEO_foreach_geometry.hh b/source/blender/geometry/GEO_foreach_geometry.hh new file mode 100644 index 00000000000..8bf8858ff05 --- /dev/null +++ b/source/blender/geometry/GEO_foreach_geometry.hh @@ -0,0 +1,19 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "BKE_geometry_set.hh" + +namespace blender::geometry { + +/** + * Modify every real geometry separately, including those from instances. The input to the + * callback never contains instances. Newly generated instances will be merged with the + * previously existing ones. + */ +void foreach_real_geometry(bke::GeometrySet &geometry, + FunctionRef fn); + +} // namespace blender::geometry diff --git a/source/blender/geometry/GEO_join_geometries.hh b/source/blender/geometry/GEO_join_geometries.hh index f278f3c1168..caed60f6599 100644 --- a/source/blender/geometry/GEO_join_geometries.hh +++ b/source/blender/geometry/GEO_join_geometries.hh @@ -8,10 +8,18 @@ namespace blender::geometry { +/** + * \param allow_merging_instance_references: If true, instance references from multiple instances + * components may be merged when they are the same. This is typically good because it reduces the + * amount of processing for later nodes. However, this may be undesirable in some cases if the + * instance references are modified afterwards and the calling code assumes that the instances + * references are just concatenated. + */ bke::GeometrySet join_geometries(Span geometries, const bke::AttributeFilter &attribute_filter, const std::optional> - &component_types_to_join = std::nullopt); + &component_types_to_join = std::nullopt, + bool allow_merging_instance_references = true); void join_attributes(const Span src_components, bke::GeometryComponent &r_result, diff --git a/source/blender/geometry/intern/foreach_geometry.cc b/source/blender/geometry/intern/foreach_geometry.cc new file mode 100644 index 00000000000..01c6dab6b72 --- /dev/null +++ b/source/blender/geometry/intern/foreach_geometry.cc @@ -0,0 +1,105 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_geometry_set.hh" +#include "BKE_instances.hh" + +#include "GEO_foreach_geometry.hh" +#include "GEO_join_geometries.hh" + +namespace blender::geometry { + +static void extract_real_geometries_recursive( + bke::GeometrySet &geometry, + Vector &path, + Map>> &r_real_geometries) +{ + bke::GeometrySet real_geometry = geometry; + real_geometry.remove(bke::GeometryComponent::Type::Instance); + geometry.keep_only({bke::GeometryComponent::Type::Instance}); + + r_real_geometries.lookup_or_add_default(std::move(real_geometry)).append(path); + + bke::Instances *instances = geometry.get_instances_for_write(); + if (!instances) { + return; + } + instances->ensure_geometry_instances(); + MutableSpan references = instances->references_for_write(); + for (const int i : references.index_range()) { + bke::InstanceReference &reference = references[i]; + if (reference.type() == bke::InstanceReference::Type::GeometrySet) { + bke::GeometrySet &sub_geometry = reference.geometry_set(); + path.append(i); + extract_real_geometries_recursive(sub_geometry, path, r_real_geometries); + path.pop_last(); + } + } +} + +static void reinsert_modified_geometry_recursive(bke::GeometrySet &geometry, + const bke::GeometrySet &geometry_to_insert, + const Span path) +{ + if (path.is_empty()) { + /* Instance references must not be merged here as that could invalidate the paths. */ + const bool allow_merging_instance_references = false; + /* Important to pass the old geometry first, so that the instance reference paths stay + * valid. */ + geometry = join_geometries( + {geometry, geometry_to_insert}, {}, {}, allow_merging_instance_references); + return; + } + bke::Instances *instances = geometry.get_instances_for_write(); + BLI_assert(instances); + const int reference_i = path.first(); + const MutableSpan references = instances->references_for_write(); + BLI_assert(reference_i < references.size()); + bke::InstanceReference &reference = references[reference_i]; + BLI_assert(reference.type() == bke::InstanceReference::Type::GeometrySet); + bke::GeometrySet &sub_geometry = reference.geometry_set(); + reinsert_modified_geometry_recursive(sub_geometry, geometry_to_insert, path.drop_front(1)); +} + +struct GeometryWithPaths { + bke::GeometrySet geometry; + Vector> paths; +}; + +void foreach_real_geometry(bke::GeometrySet &geometry, + FunctionRef fn) +{ + /* Afterwards the geometry does not have realized geometry anymore. It has been extracted and + * will be reinserted afterwards. */ + Map>> real_geometries; + { + Vector path; + extract_real_geometries_recursive(geometry, path, real_geometries); + } + /* Take the geometries out of the map so that they can be edited in-place. As keys in the #Map + * the geometries are const and thus can't be modified. */ + Vector geometries_with_paths; + for (auto &&item : real_geometries.items()) { + geometries_with_paths.append({item.key, std::move(item.value)}); + } + /* Clear to avoid extra references to the geometries which prohibit editing them in-place. */ + real_geometries.clear(); + + /* Actually modify the geometries in parallel. */ + threading::parallel_for(geometries_with_paths.index_range(), 1, [&](const IndexRange range) { + for (const int i : range) { + bke::GeometrySet &geometry_to_modify = geometries_with_paths[i].geometry; + fn(geometry_to_modify); + } + }); + + /* Reinsert modified geometries. */ + for (GeometryWithPaths &geometry_with_paths : geometries_with_paths) { + for (const Span path : geometry_with_paths.paths) { + reinsert_modified_geometry_recursive(geometry, geometry_with_paths.geometry, path); + } + } +} + +} // namespace blender::geometry diff --git a/source/blender/geometry/intern/join_geometries.cc b/source/blender/geometry/intern/join_geometries.cc index 4a9dd5d749b..ebdf1a9de8f 100644 --- a/source/blender/geometry/intern/join_geometries.cc +++ b/source/blender/geometry/intern/join_geometries.cc @@ -95,6 +95,7 @@ void join_attributes(const Span src_components, } static void join_instances(const Span src_components, + const bool allow_merging_instance_references, GeometrySet &result) { Array offsets_data(src_components.size() + 1); @@ -109,7 +110,7 @@ static void join_instances(const Span src_components, MutableSpan all_handles = dst_instances->reference_handles_for_write(); - Map, int> new_handle_by_src_reference; + Map, int> new_handle_by_src_reference_cache; for (const int i : src_components.index_range()) { const auto &src_component = static_cast(*src_components[i]); @@ -119,8 +120,13 @@ static void join_instances(const Span src_components, Array handle_map(src_references.size()); for (const int src_handle : src_references.index_range()) { const bke::InstanceReference &src_reference = src_references[src_handle]; - handle_map[src_handle] = new_handle_by_src_reference.lookup_or_add_cb( - src_reference, [&]() { return dst_instances->add_new_reference(src_reference); }); + if (allow_merging_instance_references) { + handle_map[src_handle] = new_handle_by_src_reference_cache.lookup_or_add_cb( + src_reference, [&]() { return dst_instances->add_new_reference(src_reference); }); + } + else { + handle_map[src_handle] = dst_instances->add_new_reference(src_reference); + } } const IndexRange dst_range = offsets[i]; @@ -144,6 +150,7 @@ static void join_volumes(const Span /*src_components* static void join_component_type(const bke::GeometryComponent::Type component_type, const Span src_geometry_sets, const bke::AttributeFilter &attribute_filter, + const bool allow_merging_instance_references, GeometrySet &result) { Vector components; @@ -164,7 +171,7 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ switch (component_type) { case bke::GeometryComponent::Type::Instance: - join_instances(components, result); + join_instances(components, allow_merging_instance_references, result); return; case bke::GeometryComponent::Type::Volume: join_volumes(components, result); @@ -199,7 +206,8 @@ static void join_component_type(const bke::GeometryComponent::Type component_typ GeometrySet join_geometries( const Span geometries, const bke::AttributeFilter &attribute_filter, - const std::optional> &component_types_to_join) + const std::optional> &component_types_to_join, + const bool allow_merging_instance_references) { GeometrySet result; result.name = geometries.is_empty() ? "" : geometries[0].name; @@ -218,7 +226,8 @@ GeometrySet join_geometries( supported_types); for (const GeometryComponent::Type type : types_to_join) { - join_component_type(type, geometries, attribute_filter, result); + join_component_type( + type, geometries, attribute_filter, allow_merging_instance_references, result); } return result; diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 3f7ab4b461f..bae4c3bbc12 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -2426,11 +2426,17 @@ static void execute_realize_edit_data_tasks(const Span task static void remove_id_attribute_from_instances(bke::GeometrySet &geometry_set) { - geometry_set.modify_geometry_sets([&](bke::GeometrySet &sub_geometry) { - if (Instances *instances = sub_geometry.get_instances_for_write()) { - instances->attributes_for_write().remove("id"); + Instances *instances = geometry_set.get_instances_for_write(); + if (!instances) { + return; + } + instances->attributes_for_write().remove("id"); + instances->ensure_geometry_instances(); + for (bke::InstanceReference &reference : instances->references_for_write()) { + if (reference.type() == bke::InstanceReference::Type::GeometrySet) { + remove_id_attribute_from_instances(reference.geometry_set()); } - }); + } } /** Propagate instances from the old geometry set to the new geometry set if they are not diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 73584a41e1d..ec2d6fbe0e3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -18,6 +18,8 @@ #include "BKE_library.hh" #include "BKE_screen.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_attribute_capture_cc { @@ -196,7 +198,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometryComponent::Type::Curve, GeometryComponent::Type::GreasePencil}; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { for (const GeometryComponent::Type type : types) { if (geometry_set.has(type)) { capture_on(geometry_set.get_component_for_write(type)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc index 74805459c9e..a6c02ff4ae9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc @@ -2,6 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_primitive_cuboid.hh" #include "GEO_transform.hh" @@ -49,7 +50,7 @@ static void node_geo_exec(GeoNodeExecParams params) * every instance). Because geometry components are reference counted anyway, we can just * repurpose the original geometry sets for the output. */ if (params.output_is_required("Bounding Box")) { - geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &sub_geometry) { std::optional> sub_bounds; /* Reuse the min and max calculation if this is the main "real" geometry set. */ @@ -61,7 +62,7 @@ static void node_geo_exec(GeoNodeExecParams params) } if (!sub_bounds) { - sub_geometry.remove_geometry_during_modify(); + sub_geometry.clear(); } else { const float3 scale = sub_bounds->max - sub_bounds->min; @@ -69,7 +70,7 @@ static void node_geo_exec(GeoNodeExecParams params) Mesh *mesh = geometry::create_cuboid_mesh(scale, 2, 2, 2, "uv_map"); geometry::transform_mesh(*mesh, center, math::Quaternion::identity(), float3(1)); sub_geometry.replace_mesh(mesh); - sub_geometry.keep_only_during_modify({GeometryComponent::Type::Mesh}); + sub_geometry.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit}); } }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index ce26f58a9bb..92b5b8683bb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -10,6 +10,7 @@ #include "BKE_material.hh" #include "BKE_mesh.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" #include "node_geometry_util.hh" @@ -257,7 +258,7 @@ static void node_geo_exec(GeoNodeExecParams params) #ifdef WITH_BULLET - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { Mesh *mesh = compute_hull(geometry_set); if (mesh) { geometry::debug_randomize_mesh_order(mesh); @@ -266,7 +267,9 @@ static void node_geo_exec(GeoNodeExecParams params) if (geometry_set.has_grease_pencil()) { convex_hull_grease_pencil(geometry_set); } - geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh}); + geometry_set.keep_only({GeometryComponent::Type::Mesh, + GeometryComponent::Type::Instance, + GeometryComponent::Type::Edit}); }); params.set_output("Convex Hull", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 1c212be1d61..055b916d796 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -14,6 +14,8 @@ #include "BLI_task.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_curve_fill_cc { @@ -310,8 +312,9 @@ static void node_geo_exec(GeoNodeExecParams params) Field group_index = params.extract_input>("Group ID"); const GeometryNodeCurveFillMode mode = params.extract_input("Mode"); - geometry_set.modify_geometry_sets( - [&](GeometrySet &geometry_set) { curve_fill_calculate(geometry_set, mode, group_index); }); + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { + curve_fill_calculate(geometry, mode, group_index); + }); params.set_output("Mesh", std::move(geometry_set)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index b2a8188ed1b..015b5d5eacc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -7,6 +7,7 @@ #include "BKE_grease_pencil.hh" #include "GEO_fillet_curves.hh" +#include "GEO_foreach_geometry.hh" #include "node_geometry_util.hh" @@ -142,7 +143,7 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Curve"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (geometry_set.has_curves()) { const Curves &curves_id = *geometry_set.get_curves(); const bke::CurvesGeometry &src_curves = curves_id.geometry.wrap(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index f71313fad05..cb5cf04c544 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -2,6 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "GEO_foreach_geometry.hh" #include "GEO_resample_curves.hh" #include "BKE_curves.hh" @@ -91,7 +92,7 @@ static void node_geo_exec(GeoNodeExecParams params) switch (mode) { case GEO_NODE_CURVE_RESAMPLE_COUNT: { Field count = params.extract_input>("Count"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (const Curves *src_curves_id = geometry.get_curves()) { const bke::CurvesGeometry &src_curves = src_curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context{*src_curves_id, AttrDomain::Curve}; @@ -123,7 +124,7 @@ static void node_geo_exec(GeoNodeExecParams params) } case GEO_NODE_CURVE_RESAMPLE_LENGTH: { Field length = params.extract_input>("Length"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (const Curves *src_curves_id = geometry.get_curves()) { const bke::CurvesGeometry &src_curves = src_curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context{*src_curves_id, AttrDomain::Curve}; @@ -153,7 +154,7 @@ static void node_geo_exec(GeoNodeExecParams params) break; } case GEO_NODE_CURVE_RESAMPLE_EVALUATED: - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (const Curves *src_curves_id = geometry.get_curves()) { const bke::CurvesGeometry &src_curves = src_curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context{*src_curves_id, AttrDomain::Curve}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc index 6cac0e76132..d0b3ca1ab11 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc @@ -5,6 +5,8 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_curve_reverse_cc { @@ -57,7 +59,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context{*curves_id, AttrDomain::Curve}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc index add28f24932..5c1c7c60a6b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc @@ -9,6 +9,8 @@ #include "UI_interface_layout.hh" #include "UI_resources.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_curve_set_handle_type_cc { @@ -101,7 +103,7 @@ static void node_geo_exec(GeoNodeExecParams params) std::atomic has_curves = false; std::atomic has_bezier = false; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); has_curves = true; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc index 317075ffab0..6e3a9a2fd5d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc @@ -9,6 +9,7 @@ #include "UI_interface_layout.hh" #include "UI_resources.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_set_curve_type.hh" #include "RNA_enum_types.hh" @@ -52,7 +53,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input("Curve"); Field selection_field = params.extract_input>("Selection"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (!geometry_set.has_curves()) { return; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc index f0f7896f524..244eae9a59a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -5,6 +5,7 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_subdivide_curves.hh" #include "node_geometry_util.hh" @@ -88,7 +89,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set); const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Curve"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (geometry_set.has_curves()) { const Curves &src_curves_id = *geometry_set.get_curves(); Curves *dst_curves_id = subdivide_curves(src_curves_id, cuts_field, attribute_filter); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index b5460722f8e..868e299d06b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -8,6 +8,7 @@ #include "BKE_grease_pencil.hh" #include "BKE_instances.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_join_geometries.hh" #include "GEO_randomize.hh" @@ -126,7 +127,7 @@ static void node_geo_exec(GeoNodeExecParams params) bke::GeometryComponentEditData::remember_deformed_positions_if_necessary(curve_set); const AttributeFilter &attribute_filter = params.get_attribute_filter("Mesh"); - curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(curve_set, [&](GeometrySet &geometry_set) { if (geometry_set.has_curves()) { const Curves &curves = *geometry_set.get_curves(); @@ -142,7 +143,9 @@ static void node_geo_exec(GeoNodeExecParams params) if (geometry_set.has_grease_pencil()) { grease_pencil_to_mesh(geometry_set, profile_set, scale_field, fill_caps, attribute_filter); } - geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh}); + geometry_set.keep_only({GeometryComponent::Type::Mesh, + GeometryComponent::Type::Instance, + GeometryComponent::Type::Edit}); }); params.set_output("Mesh", std::move(curve_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 1831018ab6f..ab72ef951df 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -11,6 +11,7 @@ #include "BKE_instances.hh" #include "BKE_pointcloud.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_join_geometries.hh" #include "GEO_resample_curves.hh" @@ -215,7 +216,7 @@ static void node_geo_exec(GeoNodeExecParams params) switch (mode) { case GEO_NODE_CURVE_RESAMPLE_COUNT: { const Field count = params.extract_input>("Count"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (const Curves *src_curves_id = geometry.get_curves()) { bke::CurvesGeometry dst_curves = geometry::resample_to_count( src_curves_id->geometry.wrap(), @@ -246,13 +247,15 @@ static void node_geo_exec(GeoNodeExecParams params) } layer_pointclouds_to_instances(pointcloud_by_layer, attribute_filter, geometry); } - geometry.keep_only_during_modify({bke::GeometryComponent::Type::PointCloud}); + geometry.keep_only({bke::GeometryComponent::Type::PointCloud, + bke::GeometryComponent::Type::Instance, + bke::GeometryComponent::Type::Edit}); }); break; } case GEO_NODE_CURVE_RESAMPLE_LENGTH: { const Field length = params.extract_input>("Length"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (const Curves *src_curves_id = geometry.get_curves()) { bke::CurvesGeometry dst_curves = geometry::resample_to_length( src_curves_id->geometry.wrap(), @@ -283,12 +286,14 @@ static void node_geo_exec(GeoNodeExecParams params) } layer_pointclouds_to_instances(pointcloud_by_layer, attribute_filter, geometry); } - geometry.keep_only_during_modify({bke::GeometryComponent::Type::PointCloud}); + geometry.keep_only({bke::GeometryComponent::Type::PointCloud, + bke::GeometryComponent::Type::Instance, + bke::GeometryComponent::Type::Edit}); }); break; } case GEO_NODE_CURVE_RESAMPLE_EVALUATED: { - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (const Curves *src_curves_id = geometry.get_curves()) { bke::CurvesGeometry dst_curves = geometry::resample_to_evaluated( src_curves_id->geometry.wrap(), @@ -318,7 +323,9 @@ static void node_geo_exec(GeoNodeExecParams params) } layer_pointclouds_to_instances(pointcloud_by_layer, attribute_filter, geometry); } - geometry.keep_only_during_modify({bke::GeometryComponent::Type::PointCloud}); + geometry.keep_only({bke::GeometryComponent::Type::PointCloud, + bke::GeometryComponent::Type::Instance, + bke::GeometryComponent::Type::Edit}); }); break; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 6bc491c15a1..f7c60488ecd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -10,6 +10,7 @@ #include "NOD_socket_search_link.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_trim_curves.hh" #include "NOD_rna_define.hh" @@ -219,7 +220,7 @@ static void node_geo_exec(GeoNodeExecParams params) if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) { Field start_field = params.extract_input>("Start"); Field end_field = params.extract_input>("End"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { geometry_set_curve_trim( geometry_set, mode, selection_field, start_field, end_field, attribute_filter); }); @@ -227,7 +228,7 @@ static void node_geo_exec(GeoNodeExecParams params) else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) { Field start_field = params.extract_input>("Start_001"); Field end_field = params.extract_input>("End_001"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { geometry_set_curve_trim( geometry_set, mode, selection_field, start_field, end_field, attribute_filter); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index d53a517ef73..71da28c5e92 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -7,6 +7,7 @@ #include "UI_interface_layout.hh" #include "UI_resources.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_separate_geometry.hh" #include "RNA_enum_types.hh" @@ -74,7 +75,7 @@ static void node_geo_exec(GeoNodeExecParams params) geometry::separate_geometry(geometry_set, domain, mode, selection, attribute_filter, is_error); } else { - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { bool is_error; /* Invert here because we want to keep the things not in the selection. */ geometry::separate_geometry( diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc index 35a74168bee..4371e29e8dc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc @@ -17,6 +17,7 @@ #include "BKE_volume.hh" #include "BKE_volume_grid.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" #include "node_geometry_util.hh" @@ -195,9 +196,9 @@ static void node_geo_exec(GeoNodeExecParams params) threshold = params.extract_input("Threshold"); } - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (!geometry_set.has_volume()) { - geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud}); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } const VolumeComponent *component = geometry_set.get_component(); @@ -241,7 +242,7 @@ static void node_geo_exec(GeoNodeExecParams params) geometry::debug_randomize_point_order(pointcloud); geometry_set.replace_pointcloud(pointcloud); - geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud}); + geometry_set.keep_only({GeometryComponent::Type::PointCloud, GeometryComponent::Type::Edit}); }); params.set_output("Points", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 03d7f3c251f..57411cfe2c4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -20,6 +20,7 @@ #include "UI_interface_layout.hh" #include "UI_resources.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" #include "node_geometry_util.hh" @@ -594,12 +595,12 @@ static void node_geo_exec(GeoNodeExecParams params) lazy_threading::send_hint(); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { point_distribution_calculate( geometry_set, selection_field, method, seed, attribute_outputs, params); /* Keep instances because the original geometry set may contain instances that are processed as * well. */ - geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud}); + geometry_set.keep_only({GeometryComponent::Type::PointCloud, GeometryComponent::Type::Edit}); }); params.set_output("Points", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 6b527c4bcd4..1e14826b63a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -7,6 +7,7 @@ #include "BKE_attribute_math.hh" #include "BKE_mesh.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" #include "node_geometry_util.hh" @@ -920,7 +921,7 @@ static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Mesh"); const bool keep_boundaries = params.extract_input("Keep Boundaries"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (const Mesh *mesh = geometry_set.get_mesh()) { Mesh *new_mesh = calc_dual_mesh( *mesh, keep_boundaries, params.get_attribute_filter("Dual Mesh")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 6ad53c0525f..c79204dba55 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -21,6 +21,8 @@ #include "NOD_rna_define.hh" +#include "GEO_foreach_geometry.hh" + #include "FN_multi_function_builder.hh" #include "UI_interface_layout.hh" @@ -317,8 +319,9 @@ static void duplicate_curves(GeometrySet &geometry_set, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter) { - geometry_set.keep_only_during_modify( - {GeometryComponent::Type::Curve, GeometryComponent::Type::GreasePencil}); + geometry_set.keep_only({GeometryComponent::Type::Curve, + GeometryComponent::Type::GreasePencil, + GeometryComponent::Type::Edit}); GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set); if (const Curves *curves_id = geometry_set.get_curves()) { const bke::CurvesFieldContext field_context{*curves_id, AttrDomain::Curve}; @@ -463,10 +466,10 @@ static void duplicate_faces(GeometrySet &geometry_set, const AttributeFilter &attribute_filter) { if (!geometry_set.has_mesh()) { - geometry_set.remove_geometry_during_modify(); + geometry_set.clear(); return; } - geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh}); + geometry_set.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit}); const Mesh &mesh = *geometry_set.get_mesh(); const OffsetIndices faces = mesh.faces(); @@ -649,7 +652,7 @@ static void duplicate_edges(GeometrySet &geometry_set, const AttributeFilter &attribute_filter) { if (!geometry_set.has_mesh()) { - geometry_set.remove_geometry_during_modify(); + geometry_set.clear(); return; }; const Mesh &mesh = *geometry_set.get_mesh(); @@ -994,8 +997,8 @@ static void duplicate_points(GeometrySet &geometry_set, break; } } - component_types.append(GeometryComponent::Type::Instance); - geometry_set.keep_only_during_modify(component_types); + component_types.append(GeometryComponent::Type::Edit); + geometry_set.keep_only(component_types); } /** \} */ @@ -1015,7 +1018,7 @@ static void duplicate_layers(GeometrySet &geometry_set, geometry_set.clear(); return; } - geometry_set.keep_only_during_modify({GeometryComponent::Type::GreasePencil}); + geometry_set.keep_only({GeometryComponent::Type::GreasePencil, GeometryComponent::Type::Edit}); GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set); const GreasePencil &src_grease_pencil = *geometry_set.get_grease_pencil(); @@ -1179,7 +1182,7 @@ static void node_geo_exec(GeoNodeExecParams params) geometry_set, count_field, selection_field, attribute_outputs, attribute_filter); } else { - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { switch (duplicate_domain) { case AttrDomain::Curve: duplicate_curves( diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc index f16ec24514d..a6aad1c4e2b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc @@ -6,6 +6,7 @@ #include "DNA_mesh_types.h" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_to_curve.hh" #include "node_geometry_util.hh" @@ -72,10 +73,10 @@ static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Mesh"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { const Mesh *mesh = geometry_set.get_mesh(); if (mesh == nullptr) { - geometry_set.keep_only({GeometryComponent::Type::Instance}); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } @@ -88,13 +89,13 @@ static void node_geo_exec(GeoNodeExecParams params) IndexMask start_verts = evaluator.get_evaluated_as_mask(1); if (start_verts.is_empty()) { - geometry_set.keep_only({GeometryComponent::Type::Instance}); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } geometry_set.replace_curves(edge_paths_to_curves_convert( *mesh, start_verts, next_vert, params.get_attribute_filter("Curves"))); - geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Instance}); + geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Edit}); }); params.set_output("Curves", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc index 4c3f77c32bc..e60e4386d45 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc @@ -4,6 +4,7 @@ #include "DNA_mesh_types.h" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_split_edges.hh" #include "node_geometry_util.hh" @@ -27,7 +28,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection_field = params.extract_input>("Selection"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (const Mesh *mesh = geometry_set.get_mesh()) { const bke::MeshFieldContext field_context{*mesh, AttrDomain::Edge}; fn::FieldEvaluator selection_evaluator{field_context, mesh->edges_num}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index ea00b7c7ad9..296b873c77e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -17,6 +17,7 @@ #include "BKE_mesh_mapping.hh" #include "BKE_mesh_runtime.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_selection.hh" #include "GEO_randomize.hh" @@ -1476,7 +1477,7 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Mesh"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { switch (mode) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc index 9c96fd35165..fef3998ace7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc @@ -4,6 +4,8 @@ #include "BKE_mesh.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_flip_faces_cc { @@ -25,7 +27,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection_field = params.extract_input>("Selection"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { const bke::MeshFieldContext field_context(*mesh, AttrDomain::Face); fn::FieldEvaluator evaluator(field_context, mesh->faces_num); diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index e7cca259dd6..febd2ef81d8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -11,6 +11,7 @@ #include "BKE_grease_pencil.hh" #include "BKE_instances.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_join_geometries.hh" #include "node_geometry_util.hh" @@ -187,16 +188,8 @@ static void node_geo_exec(GeoNodeExecParams params) instance.ensure_owns_direct_data(); const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Instances"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - /* It's important not to invalidate the existing #InstancesComponent because it owns references - * to other geometry sets that are processed by this node. */ - InstancesComponent &instances_component = - geometry_set.get_component_for_write(); - bke::Instances *dst_instances = instances_component.get_for_write(); - if (dst_instances == nullptr) { - dst_instances = new bke::Instances(); - instances_component.replace(dst_instances); - } + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { + bke::Instances *dst_instances = new bke::Instances(); const Array types{GeometryComponent::Type::Mesh, GeometryComponent::Type::PointCloud, @@ -226,7 +219,7 @@ static void node_geo_exec(GeoNodeExecParams params) if (geometry_set.has_grease_pencil()) { using namespace bke::greasepencil; const GreasePencil &grease_pencil = *geometry_set.get_grease_pencil(); - bke::Instances *instances = new bke::Instances(); + bke::Instances *instances_per_layer = new bke::Instances(); for (const int layer_index : grease_pencil.layers().index_range()) { const Layer &layer = grease_pencil.layer(layer_index); const Drawing *drawing = grease_pencil.get_eval_drawing(layer); @@ -239,8 +232,8 @@ static void node_geo_exec(GeoNodeExecParams params) /* Add an empty reference so the number of layers and instances match. * This makes it easy to reconstruct the layers afterwards and keep their attributes. * Although in this particular case we don't propagate the attributes. */ - const int handle = instances->add_reference(bke::InstanceReference()); - instances->add_instance(handle, layer_transform); + const int handle = instances_per_layer->add_reference(bke::InstanceReference()); + instances_per_layer->add_instance(handle, layer_transform); continue; } /* TODO: Attributes are not propagating from the curves or the points. */ @@ -254,25 +247,23 @@ static void node_geo_exec(GeoNodeExecParams params) params, attributes_to_propagate); GeometrySet temp_set = GeometrySet::from_instances(layer_instances); - const int handle = instances->add_reference(bke::InstanceReference{temp_set}); - instances->add_instance(handle, layer_transform); + const int handle = instances_per_layer->add_reference(bke::InstanceReference{temp_set}); + instances_per_layer->add_instance(handle, layer_transform); } bke::copy_attributes(geometry_set.get_grease_pencil()->attributes(), bke::AttrDomain::Layer, bke::AttrDomain::Instance, attribute_filter, - instances->attributes_for_write()); + instances_per_layer->attributes_for_write()); GeometrySet new_instances = geometry::join_geometries( - {GeometrySet::from_instances(dst_instances, bke::GeometryOwnershipType::Editable), - GeometrySet::from_instances(instances)}, + {GeometrySet::from_instances(dst_instances), + GeometrySet::from_instances(instances_per_layer)}, attribute_filter); - instances_component.replace( - new_instances.get_component_for_write().release()); - - geometry_set.replace_grease_pencil(nullptr); + dst_instances = new_instances.get_component_for_write().release(); } - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); + geometry_set.replace_instances(dst_instances); }); /* Unused references may have been added above. Remove those now so that other nodes don't diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc index 8359fe57f54..7721b40d529 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc @@ -6,6 +6,8 @@ #include "DNA_mesh_types.h" +#include "GEO_foreach_geometry.hh" + #include "BKE_grease_pencil.hh" namespace blender::nodes::node_geo_material_replace_cc { @@ -40,7 +42,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input("Geometry"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { replace_materials({mesh->mat, mesh->totcol}, old_material, new_material); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc index d862442ac04..7bce3ae8c64 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc @@ -5,6 +5,7 @@ #include "DNA_mesh_types.h" #include "DNA_pointcloud_types.h" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_merge_by_distance.hh" #include "GEO_point_merge_by_distance.hh" @@ -103,7 +104,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const float merge_distance = params.extract_input("Distance"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) { PointCloud *result = pointcloud_merge_by_distance( *pointcloud, merge_distance, selection, params.get_attribute_filter("Geometry")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_merge_layers.cc b/source/blender/nodes/geometry/nodes/node_geo_merge_layers.cc index 889af551f9c..7bf53396174 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_merge_layers.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_merge_layers.cc @@ -4,6 +4,7 @@ #include "node_geometry_util.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_merge_layers.hh" #include "BKE_grease_pencil.hh" @@ -170,8 +171,9 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeAttributeFilter attribute_filter = params.get_attribute_filter("Grease Pencil"); - main_geometry.modify_geometry_sets( - [&](GeometrySet &geometry) { merge_layers(geometry, storage, params, attribute_filter); }); + geometry::foreach_real_geometry(main_geometry, [&](GeometrySet &geometry) { + merge_layers(geometry, storage, params, attribute_filter); + }); params.set_output("Grease Pencil", std::move(main_geometry)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index f40ea7930bf..6e97703b36e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -5,6 +5,7 @@ #include "BKE_subdiv.hh" #include "BKE_subdiv_mesh.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" #include "node_geometry_util.hh" @@ -72,7 +73,7 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (const Mesh *mesh = geometry_set.get_mesh()) { geometry_set.replace_mesh(simple_subdivide_mesh(*mesh, level)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc index f782b35c196..96071ade5a8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc @@ -6,6 +6,7 @@ #include "NOD_rna_define.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_to_curve.hh" #include "UI_interface_c.hh" @@ -39,10 +40,10 @@ static void node_geo_exec(GeoNodeExecParams params) const Mode mode = Mode(params.node().custom1); GeometrySet geometry_set = params.extract_input("Mesh"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { const Mesh *mesh = geometry_set.get_mesh(); if (mesh == nullptr) { - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } @@ -54,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params) evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_as_mask(0); if (selection.is_empty()) { - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } @@ -70,7 +71,7 @@ static void node_geo_exec(GeoNodeExecParams params) evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_as_mask(0); if (selection.is_empty()) { - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } @@ -80,7 +81,7 @@ static void node_geo_exec(GeoNodeExecParams params) break; } } - geometry_set.keep_only_during_modify({GeometryComponent::Type::Curve}); + geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Edit}); }); params.set_output("Curve", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index 85b5c28299e..7bc058897c9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -16,6 +16,8 @@ #include "UI_interface_layout.hh" #include "UI_resources.hh" +#include "GEO_foreach_geometry.hh" + #include "FN_multi_function_builder.hh" #include "node_geometry_util.hh" @@ -60,12 +62,12 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, { const Mesh *mesh = geometry_set.get_mesh(); if (mesh == nullptr) { - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } const int domain_size = mesh->attributes().domain_size(domain); if (domain_size == 0) { - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } const AttributeAccessor src_attributes = mesh->attributes(); @@ -138,7 +140,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, } geometry_set.replace_pointcloud(pointcloud); - geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud}); + geometry_set.keep_only({GeometryComponent::Type::PointCloud, GeometryComponent::Type::Edit}); } static void node_geo_exec(GeoNodeExecParams params) @@ -161,7 +163,7 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeAttributeFilter &attribute_filter = params.get_attribute_filter("Points"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { switch (mode) { case GEO_NODE_MESH_TO_POINTS_VERTICES: geometry_set_mesh_to_points(geometry_set, diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc index b880a89be0f..9722d8751f3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc @@ -9,6 +9,7 @@ #include "BKE_lib_id.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_to_volume.hh" #include "NOD_rna_define.hh" @@ -127,11 +128,11 @@ static void node_geo_exec(GeoNodeExecParams params) { #ifdef WITH_OPENVDB GeometrySet geometry_set(params.extract_input("Mesh")); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (geometry_set.has_mesh()) { Volume *volume = create_volume_from_mesh(*geometry_set.get_mesh(), params); geometry_set.replace_volume(volume); - geometry_set.keep_only_during_modify({GeometryComponent::Type::Volume}); + geometry_set.keep_only({GeometryComponent::Type::Volume, GeometryComponent::Type::Edit}); } }); params.set_output("Volume", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc index ddb49ed5932..9d56ae04e9f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc @@ -14,6 +14,7 @@ #include "BLI_sort.hh" #include "BLI_task.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" #include "BKE_geometry_set.hh" @@ -174,14 +175,14 @@ static void node_geo_exec(GeoNodeExecParams params) const Field weight_field = params.extract_input>("Weight"); const NodeAttributeFilter attribute_filter = params.get_attribute_filter("Curves"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { geometry_set.replace_curves(nullptr); if (const PointCloud *points = geometry_set.get_pointcloud()) { Curves *curves_id = curves_from_points( *points, group_id_field, weight_field, attribute_filter); geometry_set.replace_curves(curves_id); } - geometry_set.keep_only_during_modify({GeometryComponent::Type::Curve}); + geometry_set.keep_only({GeometryComponent::Type::Curve, GeometryComponent::Type::Edit}); }); params.set_output("Curves", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index c79890154c2..91f0a210de3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -9,6 +9,8 @@ #include "BKE_customdata.hh" #include "BKE_mesh.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_points_to_vertices_cc { @@ -29,11 +31,11 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, { const PointCloud *points = geometry_set.get_pointcloud(); if (points == nullptr) { - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } if (points->totpoint == 0) { - geometry_set.remove_geometry_during_modify(); + geometry_set.keep_only({GeometryComponent::Type::Edit}); return; } @@ -85,7 +87,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, mesh->tag_overlapping_none(); geometry_set.replace_mesh(mesh); - geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh}); + geometry_set.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit}); } static void node_geo_exec(GeoNodeExecParams params) @@ -93,7 +95,7 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input("Points"); Field selection_field = params.extract_input>("Selection"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { geometry_set_points_to_vertices( geometry_set, selection_field, params.get_attribute_filter("Mesh")); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index 5b4eb64c661..119ca48ddc6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -12,6 +12,7 @@ #include "node_geometry_util.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_points_to_volume.hh" #include "BKE_lib_id.hh" @@ -115,7 +116,7 @@ static void initialize_volume_component_from_points(GeoNodeExecParams ¶ms, blender::geometry::fog_volume_grid_add_from_points( volume, "density", positions, radii, voxel_size, density); - r_geometry_set.keep_only_during_modify({GeometryComponent::Type::Volume}); + r_geometry_set.keep_only({GeometryComponent::Type::Volume, GeometryComponent::Type::Edit}); r_geometry_set.replace_volume(volume); } @@ -172,7 +173,7 @@ static void node_geo_exec(GeoNodeExecParams params) { #ifdef WITH_OPENVDB GeometrySet geometry_set = params.extract_input("Points"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { initialize_volume_component_from_points(params, geometry_set); }); params.set_output("Volume", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc index 0abafa96766..a52719446d4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc @@ -2,6 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BKE_instances.hh" #include "node_geometry_util.hh" #include @@ -36,6 +37,82 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input("Name").is_attribute_name().hide_label(); } +struct RemoveAttributeParams { + PatternMode pattern_mode; + std::string pattern; + std::string wildcard_prefix; + std::string wildcard_suffix; + + Set removed_attributes; + Set failed_attributes; +}; + +static void remove_attributes_recursive(GeometrySet &geometry_set, RemoveAttributeParams ¶ms) +{ + for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh, + GeometryComponent::Type::PointCloud, + GeometryComponent::Type::Curve, + GeometryComponent::Type::Instance, + GeometryComponent::Type::GreasePencil}) + { + if (!geometry_set.has(type)) { + continue; + } + /* First check if the attribute exists before getting write access, + * to avoid potentially expensive unnecessary copies. */ + const GeometryComponent &read_only_component = *geometry_set.get_component(type); + Vector attributes_to_remove; + switch (params.pattern_mode) { + case PatternMode::Exact: { + if (read_only_component.attributes()->contains(params.pattern)) { + attributes_to_remove.append(params.pattern); + } + break; + } + case PatternMode::Wildcard: { + read_only_component.attributes()->foreach_attribute([&](const bke::AttributeIter &iter) { + const StringRef attribute_name = iter.name; + if (bke::attribute_name_is_anonymous(attribute_name)) { + return; + } + if (attribute_name.startswith(params.wildcard_prefix) && + attribute_name.endswith(params.wildcard_suffix)) + { + attributes_to_remove.append(attribute_name); + } + }); + + break; + } + } + if (attributes_to_remove.is_empty()) { + break; + } + + GeometryComponent &component = geometry_set.get_component_for_write(type); + for (const StringRef attribute_name : attributes_to_remove) { + if (!bke::allow_procedural_attribute_access(attribute_name)) { + continue; + } + if (component.attributes_for_write()->remove(attribute_name)) { + params.removed_attributes.add(attribute_name); + } + else { + params.failed_attributes.add(attribute_name); + } + } + } + + if (bke::Instances *instances = geometry_set.get_instances_for_write()) { + instances->ensure_geometry_instances(); + for (bke::InstanceReference &reference : instances->references_for_write()) { + if (reference.type() == bke::InstanceReference::Type::GeometrySet) { + remove_attributes_recursive(reference.geometry_set(), params); + } + } + } +} + static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Geometry"); @@ -44,6 +121,7 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); return; } + PatternMode pattern_mode = params.get_input("Pattern Mode"); if (pattern_mode == PatternMode::Wildcard) { const int wildcard_count = Span(pattern.c_str(), pattern.size()).count('*'); @@ -58,83 +136,24 @@ static void node_geo_exec(GeoNodeExecParams params) } } - StringRef wildcard_prefix; - StringRef wildcard_suffix; + RemoveAttributeParams removal_params; + removal_params.pattern_mode = pattern_mode; + removal_params.pattern = pattern; if (pattern_mode == PatternMode::Wildcard) { const int wildcard_index = pattern.find('*'); - wildcard_prefix = StringRef(pattern).substr(0, wildcard_index); - wildcard_suffix = StringRef(pattern).substr(wildcard_index + 1); + removal_params.wildcard_prefix = StringRef(pattern).substr(0, wildcard_index); + removal_params.wildcard_suffix = StringRef(pattern).substr(wildcard_index + 1); } - Mutex attribute_log_mutex; - Set removed_attributes; - Set failed_attributes; + remove_attributes_recursive(geometry_set, removal_params); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh, - GeometryComponent::Type::PointCloud, - GeometryComponent::Type::Curve, - GeometryComponent::Type::Instance, - GeometryComponent::Type::GreasePencil}) - { - if (!geometry_set.has(type)) { - continue; - } - /* First check if the attribute exists before getting write access, - * to avoid potentially expensive unnecessary copies. */ - const GeometryComponent &read_only_component = *geometry_set.get_component(type); - Vector attributes_to_remove; - switch (pattern_mode) { - case PatternMode::Exact: { - if (read_only_component.attributes()->contains(pattern)) { - attributes_to_remove.append(pattern); - } - break; - } - case PatternMode::Wildcard: { - read_only_component.attributes()->foreach_attribute([&](const bke::AttributeIter &iter) { - const StringRef attribute_name = iter.name; - if (bke::attribute_name_is_anonymous(attribute_name)) { - return; - } - if (attribute_name.startswith(wildcard_prefix) && - attribute_name.endswith(wildcard_suffix)) - { - attributes_to_remove.append(attribute_name); - } - }); - - break; - } - } - if (attributes_to_remove.is_empty()) { - break; - } - - GeometryComponent &component = geometry_set.get_component_for_write(type); - for (const StringRef attribute_name : attributes_to_remove) { - if (!bke::allow_procedural_attribute_access(attribute_name)) { - continue; - } - if (component.attributes_for_write()->remove(attribute_name)) { - std::lock_guard lock{attribute_log_mutex}; - removed_attributes.add(attribute_name); - } - else { - std::lock_guard lock{attribute_log_mutex}; - failed_attributes.add(attribute_name); - } - } - } - }); - - for (const StringRef attribute_name : removed_attributes) { + for (const StringRef attribute_name : removal_params.removed_attributes) { params.used_named_attribute(attribute_name, NamedAttributeUsage::Remove); } - if (!failed_attributes.is_empty()) { + if (!removal_params.failed_attributes.is_empty()) { Vector quoted_attribute_names; - for (const StringRef attribute_name : failed_attributes) { + for (const StringRef attribute_name : removal_params.failed_attributes) { quoted_attribute_names.append(fmt::format("\"{}\"", attribute_name)); } const std::string message = fmt::format( @@ -142,7 +161,7 @@ static void node_geo_exec(GeoNodeExecParams params) fmt::join(quoted_attribute_names, ", ")); params.error_message_add(NodeWarningType::Warning, message); } - else if (removed_attributes.is_empty() && pattern_mode == PatternMode::Exact) { + else if (removal_params.removed_attributes.is_empty() && pattern_mode == PatternMode::Exact) { const std::string message = fmt::format(fmt::runtime(TIP_("Attribute does not exist: \"{}\"")), pattern); params.error_message_add(NodeWarningType::Warning, message); diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc index b4783642f12..22b4bfad1bf 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc @@ -17,6 +17,7 @@ #include "UI_interface_layout.hh" #include "UI_resources.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_selection.hh" #include "NOD_rna_define.hh" @@ -474,7 +475,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field scale_field = params.extract_input>("Scale"); const Field center_field = params.extract_input>("Center"); - geometry.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) { if (Mesh *mesh = geometry.get_mesh_for_write()) { const bke::MeshFieldContext context{*mesh, domain}; FieldEvaluator evaluator{context, mesh->attributes().domain_size(domain)}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc index 7ce4276ee71..0253404e178 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc @@ -9,6 +9,7 @@ #include "RNA_enum_types.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_separate_geometry.hh" #include "node_geometry_util.hh" @@ -68,7 +69,7 @@ static void node_geo_exec(GeoNodeExecParams params) is_error); } else { - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { geometry::separate_geometry(geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index 285f7936c90..0bf1e783b71 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -15,6 +15,8 @@ #include "RNA_enum_types.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_curve_handles_cc { @@ -176,7 +178,7 @@ static void node_geo_exec(GeoNodeExecParams params) std::atomic has_curves = false; std::atomic has_bezier = false; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); has_curves = true; diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc index f53e2a4e473..91997fd639d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.cc @@ -7,6 +7,8 @@ #include "RNA_enum_types.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_curve_normal_cc { @@ -90,7 +92,7 @@ static void node_geo_exec(GeoNodeExecParams params) custom_normal = params.extract_input>("Normal"); } - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); set_curve_normal(curves, diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc index a8e6b17f6dc..0f8fee23bb3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc @@ -5,6 +5,8 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_curve_radius_cc { @@ -44,7 +46,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field radius = params.extract_input>("Radius"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context(*curves_id, AttrDomain::Point); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc index e82fce6a52e..143c4f61251 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc @@ -5,6 +5,8 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_curve_tilt_cc { @@ -58,7 +60,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field tilt = params.extract_input>("Tilt"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context(*curves_id, AttrDomain::Point); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_color.cc b/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_color.cc index 9b512e7854e..9796c28d434 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_color.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_color.cc @@ -10,6 +10,8 @@ #include "NOD_rna_define.hh" +#include "GEO_foreach_geometry.hh" + #include "RNA_enum_types.hh" #include "node_geometry_util.hh" @@ -62,7 +64,7 @@ static void node_geo_exec(GeoNodeExecParams params) const StringRef color_attr_name = domain == AttrDomain::Point ? "vertex_color" : "fill_color"; const StringRef opacity_attr_name = domain == AttrDomain::Point ? "opacity" : "fill_opacity"; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) { using namespace bke::greasepencil; for (const int layer_index : grease_pencil->layers().index_range()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_depth_mode.cc b/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_depth_mode.cc index b8ea85a738e..62b1a22794a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_depth_mode.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_depth_mode.cc @@ -11,6 +11,8 @@ #include "RNA_enum_types.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_grease_pencil_set_depth_mode { @@ -40,7 +42,7 @@ static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Grease Pencil"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) { SET_FLAG_FROM_TEST(grease_pencil->flag, params.node().custom1 == GREASE_PENCIL_STROKE_ORDER_3D, diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_softness.cc b/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_softness.cc index 46d06887409..a637b3957cf 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_softness.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_grease_pencil_softness.cc @@ -5,6 +5,8 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_grease_pencil_softness_cc { @@ -28,7 +30,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field softness = params.extract_input>("Softness"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry) { if (GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write()) { using namespace bke::greasepencil; for (const int layer_index : grease_pencil->layers().index_range()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc index 6600a0239d4..29a7cbd6c9e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc @@ -13,6 +13,8 @@ #include "BKE_grease_pencil.hh" #include "BKE_material.hh" +#include "GEO_foreach_geometry.hh" + namespace blender::nodes::node_geo_set_material_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -83,7 +85,7 @@ static void node_geo_exec(GeoNodeExecParams params) bool volume_selection_warning = false; bool curves_selection_warning = false; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { if (mesh->faces_num == 0) { if (mesh->verts_num > 0) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc index cc2e218d44d..2ba24b17086 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc @@ -10,6 +10,8 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" + namespace blender::nodes::node_geo_set_material_index_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -50,7 +52,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field material_index = params.extract_input>("Material Index"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { bke::try_capture_field_on_geometry(mesh->attributes_for_write(), bke::MeshFieldContext(*mesh, AttrDomain::Face), diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_mesh_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_set_mesh_normal.cc index d1b05979957..fba7c0824e4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_mesh_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_mesh_normal.cc @@ -9,6 +9,8 @@ #include "NOD_rna_define.hh" +#include "GEO_foreach_geometry.hh" + #include "RNA_enum_types.hh" #include "node_geometry_util.hh" @@ -76,7 +78,7 @@ static void node_geo_exec(GeoNodeExecParams params) const bool remove_custom = params.extract_input("Remove Custom"); const fn::Field sharp_edge = params.extract_input>("Edge Sharpness"); const fn::Field sharp_face = params.extract_input>("Face Sharpness"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { /* Evaluate both fields before storing the result to avoid one attribute change * potentially affecting the other field evaluation. */ @@ -129,7 +131,7 @@ static void node_geo_exec(GeoNodeExecParams params) } case Mode::Free: { const fn::Field custom_normal = params.extract_input>("Custom Normal"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { const bke::AttrDomain domain = bke::AttrDomain(node.custom2); bke::try_capture_field_on_geometry(mesh->attributes_for_write(), @@ -144,7 +146,7 @@ static void node_geo_exec(GeoNodeExecParams params) } case Mode::CornerFanSpace: { const fn::Field custom_normal = params.extract_input>("Custom Normal"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { const bke::MeshFieldContext context(*mesh, bke::AttrDomain::Corner); fn::FieldEvaluator evaluator(context, mesh->corners_num); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc index b25bb74f1c4..20f5f2aab0d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc @@ -4,6 +4,8 @@ #include "DNA_pointcloud_types.h" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_point_radius_cc { @@ -30,7 +32,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field radius = params.extract_input>("Radius"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (PointCloud *pointcloud = geometry_set.get_pointcloud_for_write()) { bke::try_capture_field_on_geometry(pointcloud->attributes_for_write(), bke::PointCloudFieldContext(*pointcloud), diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index 72e54079d91..42b548f1f78 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -11,6 +11,8 @@ #include "RNA_enum_types.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_shade_smooth_cc { @@ -89,7 +91,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field smooth_field = params.extract_input>("Shade Smooth"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { set_sharp(*mesh, domain, diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc index b563e9db3d8..0aefa525d13 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc @@ -5,6 +5,8 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_spline_cyclic_cc { @@ -58,7 +60,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field cyclic = params.extract_input>("Cyclic"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context{*curves_id, AttrDomain::Curve}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc index 5db9293617a..f97962fd07a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc @@ -5,6 +5,8 @@ #include "BKE_curves.hh" #include "BKE_grease_pencil.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_set_spline_resolution_cc { @@ -59,7 +61,7 @@ static void node_geo_exec(GeoNodeExecParams params) const Field selection = params.extract_input>("Selection"); const Field resolution = params.extract_input>("Resolution"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (Curves *curves_id = geometry_set.get_curves_for_write()) { bke::CurvesGeometry &curves = curves_id->geometry.wrap(); const bke::CurvesFieldContext field_context(*curves_id, AttrDomain::Curve); diff --git a/source/blender/nodes/geometry/nodes/node_geo_sort_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_sort_elements.cc index f5bf3e15651..d380497e7aa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sort_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sort_elements.cc @@ -12,6 +12,7 @@ #include "BLI_sort.hh" #include "BLI_task.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_reorder.hh" #include "NOD_rna_define.hh" @@ -224,7 +225,7 @@ static void node_geo_exec(GeoNodeExecParams params) } } else { - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { for (const auto [type, domains] : geometry::components_supported_reordering().items()) { const bke::GeometryComponent *src_component = geometry_set.get_component(type); if (src_component == nullptr || src_component->is_empty()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc index 2e2465f5e4f..29dc4f8c314 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc @@ -18,6 +18,8 @@ #include "NOD_rna_define.hh" #include "NOD_socket_search_link.hh" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" #include @@ -145,7 +147,7 @@ static void node_geo_exec(GeoNodeExecParams params) } } else { - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { for (const GeometryComponent::Type type : {GeometryComponent::Type::Mesh, GeometryComponent::Type::PointCloud, GeometryComponent::Type::Curve, diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index b6c27c79569..a0e1e2cc819 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -12,6 +12,7 @@ #include "RNA_enum_types.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" #include "FN_multi_function_builder.hh" @@ -194,7 +195,7 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { if (const Mesh *mesh = geometry_set.get_mesh()) { geometry_set.replace_mesh(mesh_subsurf_calc( mesh, level, vert_crease, edge_crease, boundary_smooth, uv_smooth, use_limit_surface)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_tool_set_face_set.cc b/source/blender/nodes/geometry/nodes/node_geo_tool_set_face_set.cc index 41125508c6d..6824a928b41 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_tool_set_face_set.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_tool_set_face_set.cc @@ -4,6 +4,8 @@ #include "DNA_mesh_types.h" +#include "GEO_foreach_geometry.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_tool_set_face_set_cc { @@ -37,7 +39,7 @@ static void node_geo_exec(GeoNodeExecParams params) const bool is_zero = is_constant_zero(face_set); GeometrySet geometry = params.extract_input("Mesh"); - geometry.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) { if (Mesh *mesh = geometry.get_mesh_for_write()) { if (is_zero) { mesh->attributes_for_write().remove(".sculpt_face_set"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc index a1db004d33f..4c2fa1f8d14 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_tool_set_selection.cc @@ -12,6 +12,8 @@ #include "RNA_enum_types.hh" +#include "GEO_foreach_geometry.hh" + #include "FN_multi_function_builder.hh" #include "node_geometry_util.hh" @@ -95,7 +97,7 @@ static void node_geo_exec(GeoNodeExecParams params) const GField selection = params.extract_input("Selection"); const AttrDomain domain = AttrDomain(params.node().custom1); const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions(); - geometry.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) { if (Mesh *mesh = geometry.get_mesh_for_write()) { switch (mode) { case OB_MODE_EDIT: { diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index 8dd80a9e57d..d4b323a12b5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -4,8 +4,8 @@ #include "DNA_mesh_types.h" +#include "GEO_foreach_geometry.hh" #include "GEO_mesh_triangulate.hh" - #include "GEO_randomize.hh" #include "node_geometry_util.hh" @@ -85,7 +85,7 @@ static void node_geo_exec(GeoNodeExecParams params) const auto ngon_method = params.extract_input("N-gon Method"); const auto quad_method = params.extract_input("Quad Method"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { const Mesh *src_mesh = geometry_set.get_mesh(); if (!src_mesh) { return; diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index dbb5cb1fd73..ae26052d142 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -15,6 +15,7 @@ #include "BKE_volume_grid.hh" #include "BKE_volume_to_mesh.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_randomize.hh" namespace blender::nodes::node_geo_volume_to_mesh_cc { @@ -191,10 +192,10 @@ static void node_geo_exec(GeoNodeExecParams params) { #ifdef WITH_OPENVDB GeometrySet geometry_set = params.extract_input("Volume"); - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry::foreach_real_geometry(geometry_set, [&](GeometrySet &geometry_set) { Mesh *mesh = create_mesh_from_volume(geometry_set, params); geometry_set.replace_mesh(mesh); - geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh}); + geometry_set.keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit}); }); params.set_output("Mesh", std::move(geometry_set)); #else diff --git a/source/blender/nodes/intern/geometry_nodes_execute.cc b/source/blender/nodes/intern/geometry_nodes_execute.cc index 2f4fd4f2985..4e0aeb622e3 100644 --- a/source/blender/nodes/intern/geometry_nodes_execute.cc +++ b/source/blender/nodes/intern/geometry_nodes_execute.cc @@ -16,6 +16,8 @@ #include "NOD_node_declaration.hh" #include "NOD_socket.hh" +#include "GEO_foreach_geometry.hh" + #include "BKE_geometry_fields.hh" #include "BKE_geometry_nodes_reference_set.hh" #include "BKE_geometry_set.hh" @@ -738,20 +740,13 @@ static MultiValueMap find_output_attribute static Vector compute_attributes_to_store( const bke::GeometrySet &geometry, const MultiValueMap &outputs_by_domain, - const bool do_instances) + const Span component_types) { Vector attributes_to_store; - for (const auto component_type : {bke::GeometryComponent::Type::Mesh, - bke::GeometryComponent::Type::PointCloud, - bke::GeometryComponent::Type::Curve, - bke::GeometryComponent::Type::Instance}) - { + for (const auto component_type : component_types) { if (!geometry.has(component_type)) { continue; } - if (!do_instances && component_type == bke::GeometryComponent::Type::Instance) { - continue; - } const bke::GeometryComponent &component = *geometry.get_component(component_type); const bke::AttributeAccessor attributes = *component.attributes(); for (const auto item : outputs_by_domain.items()) { @@ -838,24 +833,32 @@ static void store_output_attributes(bke::GeometrySet &geometry, if (outputs_by_domain.size() == 0) { return; } + + { + /* Handle top level instances separately first. */ + Vector attributes_to_store = compute_attributes_to_store( + geometry, outputs_by_domain, {bke::GeometryComponent::Type::Instance}); + store_computed_output_attributes(geometry, attributes_to_store); + } + const bool only_instance_attributes = outputs_by_domain.size() == 1 && *outputs_by_domain.keys().begin() == bke::AttrDomain::Instance; if (only_instance_attributes) { - /* No need to call #modify_geometry_sets when only adding attributes to top-level instances. + /* No need to call #foreach_real_geometry when only adding attributes to top-level instances. * This avoids some unnecessary data copies currently if some sub-geometries are not yet owned * by the geometry set, i.e. they use #GeometryOwnershipType::Editable/ReadOnly. */ - Vector attributes_to_store = compute_attributes_to_store( - geometry, outputs_by_domain, true); - store_computed_output_attributes(geometry, attributes_to_store); return; } - geometry.modify_geometry_sets([&](bke::GeometrySet &instance_geometry) { + geometry::foreach_real_geometry(geometry, [&](bke::GeometrySet &instance_geometry) { /* Instance attributes should only be created for the top-level geometry. */ - const bool do_instances = &geometry == &instance_geometry; Vector attributes_to_store = compute_attributes_to_store( - instance_geometry, outputs_by_domain, do_instances); + instance_geometry, + outputs_by_domain, + {bke::GeometryComponent::Type::Mesh, + bke::GeometryComponent::Type::PointCloud, + bke::GeometryComponent::Type::Curve}); store_computed_output_attributes(instance_geometry, attributes_to_store); }); } diff --git a/source/blender/nodes/intern/geometry_nodes_foreach_geometry_element_zone.cc b/source/blender/nodes/intern/geometry_nodes_foreach_geometry_element_zone.cc index c8d5e42055b..d6a381ba01d 100644 --- a/source/blender/nodes/intern/geometry_nodes_foreach_geometry_element_zone.cc +++ b/source/blender/nodes/intern/geometry_nodes_foreach_geometry_element_zone.cc @@ -13,6 +13,7 @@ #include "BKE_node_socket_value.hh" #include "GEO_extract_elements.hh" +#include "GEO_foreach_geometry.hh" #include "GEO_join_geometries.hh" #include "FN_lazy_function_graph_executor.hh" @@ -1137,7 +1138,7 @@ void LazyFunctionForReduceForeachGeometryElement::handle_generation_items_group( } } else { - geometry.modify_geometry_sets([&](GeometrySet &sub_geometry) { + geometry::foreach_real_geometry(geometry, [&](GeometrySet &sub_geometry) { for (const GeometryComponent::Type component_type : {GeometryComponent::Type::Mesh, GeometryComponent::Type::PointCloud, diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index cfed417a100..1ada3f89263 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -54,6 +54,8 @@ #include "DEG_depsgraph_query.hh" +#include "GEO_foreach_geometry.hh" + #include "list_function_eval.hh" #include "volume_grid_function_eval.hh" @@ -909,7 +911,7 @@ class LazyFunctionForViewerNode : public LazyFunction { } } else { - geometry.modify_geometry_sets([&](GeometrySet &geometry) { + geometry::foreach_real_geometry(geometry, [&](GeometrySet &geometry) { for (const bke::GeometryComponent::Type type : {bke::GeometryComponent::Type::Mesh, bke::GeometryComponent::Type::PointCloud, diff --git a/tests/files/modeling/geometry_nodes/instance/instance_on_points_in_instances.blend b/tests/files/modeling/geometry_nodes/instance/instance_on_points_in_instances.blend new file mode 100644 index 00000000000..d863bf838e1 --- /dev/null +++ b/tests/files/modeling/geometry_nodes/instance/instance_on_points_in_instances.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb6c15a1d39ed18a477e93123ac886226ac8473b95821aa4647547136b61eacd +size 564009