diff options
author | Jacques Lucke <jacques@blender.org> | 2022-07-08 17:16:56 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-07-08 17:16:56 +0300 |
commit | b876ce2a4a4638142439a7cf265a0780491ae4cc (patch) | |
tree | 871d71eb6d1cf215869fc941c831c81bcacc6433 /source/blender/geometry | |
parent | f391e8f316bd29b700cef874a59cf3b64203d70c (diff) |
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
Diffstat (limited to 'source/blender/geometry')
7 files changed, 213 insertions, 235 deletions
diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc index 07ac2419ad9..486d8adbf39 100644 --- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc +++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc @@ -7,7 +7,6 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_attribute_access.hh" #include "BKE_geometry_set.hh" #include "BKE_mesh.h" @@ -322,11 +321,10 @@ static void calculate_polys(const CuboidConfig &config, static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::AttributeIDRef &uv_id) { - MeshComponent mesh_component; - mesh_component.replace(mesh, GeometryOwnershipType::Editable); - bke::OutputAttribute_Typed<float2> uv_attribute = - mesh_component.attribute_try_get_for_output_only<float2>(uv_id, ATTR_DOMAIN_CORNER); - MutableSpan<float2> uvs = uv_attribute.as_span(); + bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh); + bke::SpanAttributeWriter<float2> uv_attribute = + attributes.lookup_or_add_for_write_only_span<float2>(uv_id, ATTR_DOMAIN_CORNER); + MutableSpan<float2> uvs = uv_attribute.span; int loop_index = 0; @@ -394,7 +392,7 @@ static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::Att } } - uv_attribute.save(); + uv_attribute.finish(); } Mesh *create_cuboid_mesh(const float3 &size, diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 38f9da2a60c..681dfd15137 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -8,7 +8,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_attribute_access.hh" +#include "BKE_attribute.hh" #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_geometry_set.hh" @@ -44,14 +44,13 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen curves.cyclic_for_write().fill(false); curves.cyclic_for_write().slice(cyclic_curves).fill(true); - Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids(); + bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write(); + const bke::AttributeAccessor mesh_attributes = *mesh_component.attributes(); - CurveComponent curves_component; - curves_component.replace(curves_id, GeometryOwnershipType::Editable); + Set<bke::AttributeIDRef> source_attribute_ids = mesh_attributes.all_ids(); for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) { - if (mesh_component.attribute_is_builtin(attribute_id) && - !curves_component.attribute_is_builtin(attribute_id)) { + if (mesh_attributes.is_builtin(attribute_id) && !curves_attributes.is_builtin(attribute_id)) { /* Don't copy attributes that are built-in on meshes but not on curves. */ continue; } @@ -60,8 +59,7 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen continue; } - const GVArray mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id, - ATTR_DOMAIN_POINT); + const GVArray mesh_attribute = mesh_attributes.lookup(attribute_id, ATTR_DOMAIN_POINT); /* Some attributes might not exist if they were builtin attribute on domains that don't * have any elements, i.e. a face attribute on the output of the line primitive node. */ if (!mesh_attribute) { @@ -71,10 +69,10 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen /* Copy attribute based on the map for this curve. */ attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { using T = decltype(dummy); - bke::OutputAttribute_Typed<T> attribute = - curves_component.attribute_try_get_for_output_only<T>(attribute_id, ATTR_DOMAIN_POINT); - copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.as_span()); - attribute.save(); + bke::SpanAttributeWriter<T> attribute = + curves_attributes.lookup_or_add_for_write_only_span<T>(attribute_id, ATTR_DOMAIN_POINT); + copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.span); + attribute.finish(); }); } diff --git a/source/blender/geometry/intern/point_merge_by_distance.cc b/source/blender/geometry/intern/point_merge_by_distance.cc index 6639ff650d3..40bc02cbd34 100644 --- a/source/blender/geometry/intern/point_merge_by_distance.cc +++ b/source/blender/geometry/intern/point_merge_by_distance.cc @@ -104,24 +104,24 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points, point_merge_counts[dst_index]++; } - Set<bke::AttributeIDRef> attributes = src_points.attribute_ids(); + const bke::AttributeAccessor src_attributes = *src_points.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_points.attributes_for_write(); + Set<bke::AttributeIDRef> attributes = src_attributes.all_ids(); /* Transfer the ID attribute if it exists, using the ID of the first merged point. */ if (attributes.contains("id")) { - VArray<int> src = src_points.attribute_get_for_read<int>("id", ATTR_DOMAIN_POINT, 0); - bke::OutputAttribute_Typed<int> dst = dst_points.attribute_try_get_for_output_only<int>( + VArraySpan<int> src = src_attributes.lookup_or_default<int>("id", ATTR_DOMAIN_POINT, 0); + bke::SpanAttributeWriter<int> dst = dst_attributes.lookup_or_add_for_write_only_span<int>( "id", ATTR_DOMAIN_POINT); - Span<int> src_ids = src.get_internal_span(); - MutableSpan<int> dst_ids = dst.as_span(); threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) { for (const int i_dst : range) { const IndexRange points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]); - dst_ids[i_dst] = src_ids[points.first()]; + dst.span[i_dst] = src[points.first()]; } }); - dst.save(); + dst.finish(); attributes.remove_contained("id"); } @@ -131,20 +131,19 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points, continue; } - bke::ReadAttributeLookup src_attribute = src_points.attribute_try_get_for_read(id); + bke::GAttributeReader src_attribute = src_attributes.lookup(id); attribute_math::convert_to_static_type(src_attribute.varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { - bke::OutputAttribute_Typed<T> dst_attribute = - dst_points.attribute_try_get_for_output_only<T>(id, ATTR_DOMAIN_POINT); - Span<T> src = src_attribute.varray.get_internal_span().typed<T>(); - MutableSpan<T> dst = dst_attribute.as_span(); + bke::SpanAttributeWriter<T> dst_attribute = + dst_attributes.lookup_or_add_for_write_only_span<T>(id, ATTR_DOMAIN_POINT); + VArraySpan<T> src = src_attribute.varray.typed<T>(); threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) { for (const int i_dst : range) { /* Create a separate mixer for every point to avoid allocating temporary buffers * in the mixer the size of the result point cloud and to improve memory locality. */ - attribute_math::DefaultMixer<T> mixer{dst.slice(i_dst, 1)}; + attribute_math::DefaultMixer<T> mixer{dst_attribute.span.slice(i_dst, 1)}; const IndexRange points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]); @@ -157,7 +156,7 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points, } }); - dst_attribute.save(); + dst_attribute.finish(); } }); } diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 060a1aa7603..25bf00c5783 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -23,12 +23,13 @@ namespace blender::geometry { using blender::bke::AttributeIDRef; +using blender::bke::AttributeKind; +using blender::bke::AttributeMetaData; using blender::bke::custom_data_type_to_cpp_type; using blender::bke::CustomDataAttributes; +using blender::bke::GSpanAttributeWriter; using blender::bke::object_get_evaluated_geometry_set; -using blender::bke::OutputAttribute; -using blender::bke::OutputAttribute_Typed; -using blender::bke::ReadAttributeLookup; +using blender::bke::SpanAttributeWriter; /** * An ordered set of attribute ids. Attributes are ordered to avoid name lookups in many places. @@ -287,26 +288,27 @@ static void copy_generic_attributes_to_result( const AttributeFallbacksArray &attribute_fallbacks, const OrderedAttributes &ordered_attributes, const FunctionRef<IndexRange(eAttrDomain)> &range_fn, - MutableSpan<GMutableSpan> dst_attributes) + MutableSpan<GSpanAttributeWriter> dst_attribute_writers) { - threading::parallel_for(dst_attributes.index_range(), 10, [&](const IndexRange attribute_range) { - for (const int attribute_index : attribute_range) { - const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; - const IndexRange element_slice = range_fn(domain); - - GMutableSpan dst_span = dst_attributes[attribute_index].slice(element_slice); - if (src_attributes[attribute_index].has_value()) { - threaded_copy(*src_attributes[attribute_index], dst_span); - } - else { - const CPPType &cpp_type = dst_span.type(); - const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ? - cpp_type.default_value() : - attribute_fallbacks.array[attribute_index]; - threaded_fill({cpp_type, fallback}, dst_span); - } - } - }); + threading::parallel_for( + dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) { + for (const int attribute_index : attribute_range) { + const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; + const IndexRange element_slice = range_fn(domain); + + GMutableSpan dst_span = dst_attribute_writers[attribute_index].span.slice(element_slice); + if (src_attributes[attribute_index].has_value()) { + threaded_copy(*src_attributes[attribute_index], dst_span); + } + else { + const CPPType &cpp_type = dst_span.type(); + const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ? + cpp_type.default_value() : + attribute_fallbacks.array[attribute_index]; + threaded_fill({cpp_type, fallback}, dst_span); + } + } + }); } static void create_result_ids(const RealizeInstancesOptions &options, @@ -361,7 +363,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks( const OrderedAttributes &ordered_attributes) { Vector<std::pair<int, GSpan>> attributes_to_override; - const CustomDataAttributes &attributes = instances_component.attributes(); + const CustomDataAttributes &attributes = instances_component.instance_attributes(); attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id); @@ -447,7 +449,7 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info, Span<int> stored_instance_ids; if (gather_info.create_id_attribute_on_any_component) { - std::optional<GSpan> ids = instances_component.attributes().get_for_read("id"); + std::optional<GSpan> ids = instances_component.instance_attributes().get_for_read("id"); if (ids.has_value()) { stored_instance_ids = ids->typed<int>(); } @@ -646,34 +648,34 @@ static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set pointcloud_info.pointcloud = pointcloud; /* Access attributes. */ - PointCloudComponent component; - component.replace(const_cast<PointCloud *>(pointcloud), GeometryOwnershipType::ReadOnly); + bke::AttributeAccessor attributes = bke::pointcloud_attributes(*pointcloud); pointcloud_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; - if (component.attribute_exists(attribute_id)) { - GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); + if (attributes.contains(attribute_id)) { + GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type); pointcloud_info.attributes[attribute_index].emplace(std::move(attribute)); } } if (info.create_id_attribute) { - ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id"); - if (ids_lookup) { - pointcloud_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>(); + bke::GAttributeReader ids_attribute = attributes.lookup("id"); + if (ids_attribute) { + pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>(); } } } return info; } -static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options, - const RealizePointCloudTask &task, - const OrderedAttributes &ordered_attributes, - PointCloud &dst_pointcloud, - MutableSpan<GMutableSpan> dst_attribute_spans, - MutableSpan<int> all_dst_ids) +static void execute_realize_pointcloud_task( + const RealizeInstancesOptions &options, + const RealizePointCloudTask &task, + const OrderedAttributes &ordered_attributes, + PointCloud &dst_pointcloud, + MutableSpan<GSpanAttributeWriter> dst_attribute_writers, + MutableSpan<int> all_dst_ids) { const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info; const PointCloud &pointcloud = *pointcloud_info.pointcloud; @@ -699,7 +701,7 @@ static void execute_realize_pointcloud_task(const RealizeInstancesOptions &optio UNUSED_VARS_NDEBUG(domain); return point_slice; }, - dst_attribute_spans); + dst_attribute_writers); } static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options, @@ -721,42 +723,43 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti PointCloudComponent &dst_component = r_realized_geometry.get_component_for_write<PointCloudComponent>(); dst_component.replace(dst_pointcloud); + bke::MutableAttributeAccessor dst_attributes = bke::pointcloud_attributes_for_write( + *dst_pointcloud); /* Prepare id attribute. */ - OutputAttribute_Typed<int> point_ids; - MutableSpan<int> point_ids_span; + SpanAttributeWriter<int> point_ids; if (all_pointclouds_info.create_id_attribute) { - point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT); - point_ids_span = point_ids.as_span(); + point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT); } /* Prepare generic output attributes. */ - Vector<OutputAttribute> dst_attributes; - Vector<GMutableSpan> dst_attribute_spans; + Vector<GSpanAttributeWriter> dst_attribute_writers; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, ATTR_DOMAIN_POINT, data_type); - dst_attribute_spans.append(dst_attribute.as_span()); - dst_attributes.append(std::move(dst_attribute)); + dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span( + attribute_id, ATTR_DOMAIN_POINT, data_type)); } /* Actually execute all tasks. */ threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) { for (const int task_index : task_range) { const RealizePointCloudTask &task = tasks[task_index]; - execute_realize_pointcloud_task( - options, task, ordered_attributes, *dst_pointcloud, dst_attribute_spans, point_ids_span); + execute_realize_pointcloud_task(options, + task, + ordered_attributes, + *dst_pointcloud, + dst_attribute_writers, + point_ids.span); } }); - /* Save modified attributes. */ - for (OutputAttribute &dst_attribute : dst_attributes) { - dst_attribute.save(); + /* Tag modified attributes. */ + for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) { + dst_attribute.finish(); } if (point_ids) { - point_ids.save(); + point_ids.finish(); } } @@ -837,22 +840,21 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, } /* Access attributes. */ - MeshComponent component; - component.replace(const_cast<Mesh *>(mesh), GeometryOwnershipType::ReadOnly); + bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh); mesh_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; - if (component.attribute_exists(attribute_id)) { - GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); + if (attributes.contains(attribute_id)) { + GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type); mesh_info.attributes[attribute_index].emplace(std::move(attribute)); } } if (info.create_id_attribute) { - ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id"); - if (ids_lookup) { - mesh_info.stored_vertex_ids = ids_lookup.varray.get_internal_span().typed<int>(); + bke::GAttributeReader ids_attribute = attributes.lookup("id"); + if (ids_attribute) { + mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>(); } } } @@ -863,7 +865,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, const RealizeMeshTask &task, const OrderedAttributes &ordered_attributes, Mesh &dst_mesh, - MutableSpan<GMutableSpan> dst_attribute_spans, + MutableSpan<GSpanAttributeWriter> dst_attribute_writers, MutableSpan<int> all_dst_vertex_ids) { const MeshRealizeInfo &mesh_info = *task.mesh_info; @@ -949,7 +951,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options, return IndexRange(); } }, - dst_attribute_spans); + dst_attribute_writers); } static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, @@ -973,6 +975,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, 0, tot_loops, tot_poly); MeshComponent &dst_component = r_realized_geometry.get_component_for_write<MeshComponent>(); dst_component.replace(dst_mesh); + bke::MutableAttributeAccessor dst_attributes = bke::mesh_attributes_for_write(*dst_mesh); /* Copy settings from the first input geometry set with a mesh. */ const RealizeMeshTask &first_task = tasks.first(); @@ -986,24 +989,19 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, } /* Prepare id attribute. */ - OutputAttribute_Typed<int> vertex_ids; - MutableSpan<int> vertex_ids_span; + SpanAttributeWriter<int> vertex_ids; if (all_meshes_info.create_id_attribute) { - vertex_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT); - vertex_ids_span = vertex_ids.as_span(); + vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT); } /* Prepare generic output attributes. */ - Vector<OutputAttribute> dst_attributes; - Vector<GMutableSpan> dst_attribute_spans; + Vector<GSpanAttributeWriter> dst_attribute_writers; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, domain, data_type); - dst_attribute_spans.append(dst_attribute.as_span()); - dst_attributes.append(std::move(dst_attribute)); + dst_attribute_writers.append( + dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type)); } /* Actually execute all tasks. */ @@ -1011,16 +1009,16 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, for (const int task_index : task_range) { const RealizeMeshTask &task = tasks[task_index]; execute_realize_mesh_task( - options, task, ordered_attributes, *dst_mesh, dst_attribute_spans, vertex_ids_span); + options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span); } }); - /* Save modified attributes. */ - for (OutputAttribute &dst_attribute : dst_attributes) { - dst_attribute.save(); + /* Tag modified attributes. */ + for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) { + dst_attribute.finish(); } if (vertex_ids) { - vertex_ids.save(); + vertex_ids.finish(); } } @@ -1088,49 +1086,43 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set, curve_info.curves = curves_id; /* Access attributes. */ - CurveComponent component; - component.replace(const_cast<Curves *>(curves_id), GeometryOwnershipType::ReadOnly); + bke::AttributeAccessor attributes = curves.attributes(); curve_info.attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const eAttrDomain domain = info.attributes.kinds[attribute_index].domain; const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index]; const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type; - if (component.attribute_exists(attribute_id)) { - GVArray attribute = component.attribute_get_for_read(attribute_id, domain, data_type); + if (attributes.contains(attribute_id)) { + GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type); curve_info.attributes[attribute_index].emplace(std::move(attribute)); } } if (info.create_id_attribute) { - ReadAttributeLookup ids_lookup = component.attribute_try_get_for_read("id"); - if (ids_lookup) { - curve_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>(); + bke::GAttributeReader id_attribute = attributes.lookup("id"); + if (id_attribute) { + curve_info.stored_ids = id_attribute.varray.get_internal_span().typed<int>(); } } /* Retrieve the radius attribute, if it exists. */ - if (component.attribute_exists("radius")) { - curve_info.radius = component - .attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 0.0f) - .get_internal_span(); + if (attributes.contains("radius")) { + curve_info.radius = + attributes.lookup<float>("radius", ATTR_DOMAIN_POINT).get_internal_span(); info.create_radius_attribute = true; } /* Retrieve the resolution attribute, if it exists. */ curve_info.resolution = curves.resolution(); - if (component.attribute_exists("resolution")) { + if (attributes.contains("resolution")) { info.create_resolution_attribute = true; } /* Retrieve handle position attributes, if they exist. */ - if (component.attribute_exists("handle_right")) { - curve_info.handle_left = component - .attribute_get_for_read<float3>( - "handle_left", ATTR_DOMAIN_POINT, float3(0)) - .get_internal_span(); - curve_info.handle_right = component - .attribute_get_for_read<float3>( - "handle_right", ATTR_DOMAIN_POINT, float3(0)) - .get_internal_span(); + if (attributes.contains("handle_right")) { + curve_info.handle_left = + attributes.lookup<float3>("handle_left", ATTR_DOMAIN_POINT).get_internal_span(); + curve_info.handle_right = + attributes.lookup<float3>("handle_right", ATTR_DOMAIN_POINT).get_internal_span(); info.create_handle_postion_attributes = true; } } @@ -1142,7 +1134,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, const RealizeCurveTask &task, const OrderedAttributes &ordered_attributes, bke::CurvesGeometry &dst_curves, - MutableSpan<GMutableSpan> dst_attribute_spans, + MutableSpan<GSpanAttributeWriter> dst_attribute_writers, MutableSpan<int> all_dst_ids, MutableSpan<float3> all_handle_left, MutableSpan<float3> all_handle_right, @@ -1220,7 +1212,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, return IndexRange(); } }, - dst_attribute_spans); + dst_attribute_writers); } static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, @@ -1244,57 +1236,45 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, dst_curves.offsets_for_write().last() = points_num; CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>(); dst_component.replace(dst_curves_id); + bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write(); /* Prepare id attribute. */ - OutputAttribute_Typed<int> point_ids; - MutableSpan<int> point_ids_span; + SpanAttributeWriter<int> point_ids; if (all_curves_info.create_id_attribute) { - point_ids = dst_component.attribute_try_get_for_output_only<int>("id", ATTR_DOMAIN_POINT); - point_ids_span = point_ids.as_span(); + point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT); } /* Prepare generic output attributes. */ - Vector<OutputAttribute> dst_attributes; - Vector<GMutableSpan> dst_attribute_spans; + Vector<GSpanAttributeWriter> dst_attribute_writers; for (const int attribute_index : ordered_attributes.index_range()) { const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain; const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type; - OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - attribute_id, domain, data_type); - dst_attribute_spans.append(dst_attribute.as_span()); - dst_attributes.append(std::move(dst_attribute)); + dst_attribute_writers.append( + dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type)); } /* Prepare handle position attributes if necessary. */ - OutputAttribute_Typed<float3> handle_left; - OutputAttribute_Typed<float3> handle_right; - MutableSpan<float3> handle_left_span; - MutableSpan<float3> handle_right_span; + SpanAttributeWriter<float3> handle_left; + SpanAttributeWriter<float3> handle_right; if (all_curves_info.create_handle_postion_attributes) { - handle_left = dst_component.attribute_try_get_for_output_only<float3>("handle_left", - ATTR_DOMAIN_POINT); - handle_right = dst_component.attribute_try_get_for_output_only<float3>("handle_right", + handle_left = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_left", ATTR_DOMAIN_POINT); - handle_left_span = handle_left.as_span(); - handle_right_span = handle_right.as_span(); + handle_right = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_right", + ATTR_DOMAIN_POINT); } /* Prepare radius attribute if necessary. */ - OutputAttribute_Typed<float> radius; - MutableSpan<float> radius_span; + SpanAttributeWriter<float> radius; if (all_curves_info.create_radius_attribute) { - radius = dst_component.attribute_try_get_for_output_only<float>("radius", ATTR_DOMAIN_POINT); - radius_span = radius.as_span(); + radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT); } /* Prepare resolution attribute if necessary. */ - OutputAttribute_Typed<int> resolution; - MutableSpan<int> resolution_span; + SpanAttributeWriter<int> resolution; if (all_curves_info.create_resolution_attribute) { - resolution = dst_component.attribute_try_get_for_output_only<int>("resolution", - ATTR_DOMAIN_CURVE); - resolution_span = resolution.as_span(); + resolution = dst_attributes.lookup_or_add_for_write_only_span<int>("resolution", + ATTR_DOMAIN_CURVE); } /* Actually execute all tasks. */ @@ -1306,31 +1286,31 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, task, ordered_attributes, dst_curves, - dst_attribute_spans, - point_ids_span, - handle_left_span, - handle_right_span, - radius_span, - resolution_span); + dst_attribute_writers, + point_ids.span, + handle_left.span, + handle_right.span, + radius.span, + resolution.span); } }); - /* Save modified attributes. */ - for (OutputAttribute &dst_attribute : dst_attributes) { - dst_attribute.save(); + /* Tag modified attributes. */ + for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) { + dst_attribute.finish(); } if (point_ids) { - point_ids.save(); + point_ids.finish(); } if (radius) { - radius.save(); + radius.finish(); } if (resolution) { - resolution.save(); + resolution.finish(); } if (all_curves_info.create_handle_postion_attributes) { - handle_left.save(); - handle_right.save(); + handle_left.finish(); + handle_right.finish(); } } @@ -1345,7 +1325,7 @@ static void remove_id_attribute_from_instances(GeometrySet &geometry_set) geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) { if (sub_geometry.has<InstancesComponent>()) { InstancesComponent &component = sub_geometry.get_component_for_write<InstancesComponent>(); - component.attributes().remove("id"); + component.instance_attributes().remove("id"); } }); } diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc index dd1da62408c..c9b8a032ce6 100644 --- a/source/blender/geometry/intern/resample_curves.cc +++ b/source/blender/geometry/intern/resample_curves.cc @@ -92,17 +92,18 @@ static void retrieve_attribute_spans(const Span<bke::AttributeIDRef> ids, CurveComponent &dst_component, Vector<GSpan> &src, Vector<GMutableSpan> &dst, - Vector<bke::OutputAttribute> &dst_attributes) + Vector<bke::GSpanAttributeWriter> &dst_attributes) { for (const int i : ids.index_range()) { - GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], ATTR_DOMAIN_POINT); + GVArray src_attribute = src_component.attributes()->lookup(ids[i], ATTR_DOMAIN_POINT); BLI_assert(src_attribute); src.append(src_attribute.get_internal_span()); const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type()); - bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( - ids[i], ATTR_DOMAIN_POINT, data_type); - dst.append(dst_attribute.as_span()); + bke::GSpanAttributeWriter dst_attribute = + dst_component.attributes_for_write()->lookup_or_add_for_write_only_span( + ids[i], ATTR_DOMAIN_POINT, data_type); + dst.append(dst_attribute.span); dst_attributes.append(std::move(dst_attribute)); } } @@ -111,7 +112,7 @@ struct AttributesForInterpolation : NonCopyable, NonMovable { Vector<GSpan> src; Vector<GMutableSpan> dst; - Vector<bke::OutputAttribute> dst_attributes; + Vector<bke::GSpanAttributeWriter> dst_attributes; Vector<GSpan> src_no_interpolation; Vector<GMutableSpan> dst_no_interpolation; @@ -129,8 +130,8 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com VectorSet<bke::AttributeIDRef> ids; VectorSet<bke::AttributeIDRef> ids_no_interpolation; - src_component.attribute_foreach( - [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) { + src_component.attributes()->for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { if (meta_data.domain != ATTR_DOMAIN_POINT) { return true; } @@ -311,8 +312,8 @@ static Curves *resample_to_uniform(const CurveComponent &src_component, bke::curves::copy_point_data( src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); - for (bke::OutputAttribute &attribute : attributes.dst_attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) { + attribute.finish(); } return dst_curves_id; @@ -433,8 +434,8 @@ Curves *resample_to_evaluated(const CurveComponent &src_component, bke::curves::copy_point_data( src_curves, dst_curves, unselected_ranges, src_positions, dst_positions); - for (bke::OutputAttribute &attribute : attributes.dst_attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) { + attribute.finish(); } return dst_curves_id; diff --git a/source/blender/geometry/intern/set_curve_type.cc b/source/blender/geometry/intern/set_curve_type.cc index d7a5bc9b27d..08888a74973 100644 --- a/source/blender/geometry/intern/set_curve_type.cc +++ b/source/blender/geometry/intern/set_curve_type.cc @@ -290,32 +290,32 @@ struct GenericAttributes : NonCopyable, NonMovable { Vector<GSpan> src; Vector<GMutableSpan> dst; - Vector<bke::OutputAttribute> attributes; + Vector<bke::GSpanAttributeWriter> attributes; }; -static void retrieve_generic_point_attributes(const CurveComponent &src_component, - CurveComponent &dst_component, +static void retrieve_generic_point_attributes(const bke::AttributeAccessor &src_attributes, + bke::MutableAttributeAccessor &dst_attributes, GenericAttributes &attributes) { - src_component.attribute_foreach( - [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) { + src_attributes.for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { if (meta_data.domain != ATTR_DOMAIN_POINT) { /* Curve domain attributes are all copied directly to the result in one step. */ return true; } - if (src_component.attribute_is_builtin(id)) { + if (src_attributes.is_builtin(id)) { if (!(id.is_named() && ELEM(id, "tilt", "radius"))) { return true; } } - GVArray src_attribute = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT); + GVArray src_attribute = src_attributes.lookup(id, ATTR_DOMAIN_POINT); BLI_assert(src_attribute); attributes.src.append(src_attribute.get_internal_span()); - bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( + bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_span( id, ATTR_DOMAIN_POINT, meta_data.data_type); - attributes.dst.append(dst_attribute.as_span()); + attributes.dst.append(dst_attribute.span); attributes.attributes.append(std::move(dst_attribute)); return true; @@ -367,8 +367,11 @@ static Curves *convert_curves_to_bezier(const CurveComponent &src_component, bke::curves::accumulate_counts_to_offsets(dst_offsets); dst_curves.resize(dst_offsets.last(), dst_curves.curves_num()); + const bke::AttributeAccessor src_attributes = *src_component.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); + GenericAttributes attributes; - retrieve_generic_point_attributes(src_component, dst_component, attributes); + retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes); MutableSpan<float3> dst_positions = dst_curves.positions_for_write(); MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write(); @@ -494,8 +497,8 @@ static Curves *convert_curves_to_bezier(const CurveComponent &src_component, src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } - for (bke::OutputAttribute &attribute : attributes.attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.attributes) { + attribute.finish(); } return dst_curves_id; @@ -524,8 +527,11 @@ static Curves *convert_curves_to_nurbs(const CurveComponent &src_component, bke::curves::accumulate_counts_to_offsets(dst_offsets); dst_curves.resize(dst_offsets.last(), dst_curves.curves_num()); + const bke::AttributeAccessor src_attributes = *src_component.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); + GenericAttributes attributes; - retrieve_generic_point_attributes(src_component, dst_component, attributes); + retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes); MutableSpan<float3> dst_positions = dst_curves.positions_for_write(); @@ -659,8 +665,8 @@ static Curves *convert_curves_to_nurbs(const CurveComponent &src_component, src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]); } - for (bke::OutputAttribute &attribute : attributes.attributes) { - attribute.save(); + for (bke::GSpanAttributeWriter &attribute : attributes.attributes) { + attribute.finish(); } return dst_curves_id; diff --git a/source/blender/geometry/intern/subdivide_curves.cc b/source/blender/geometry/intern/subdivide_curves.cc index 4fb21e53013..914174235cd 100644 --- a/source/blender/geometry/intern/subdivide_curves.cc +++ b/source/blender/geometry/intern/subdivide_curves.cc @@ -79,16 +79,17 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves, struct AttributeTransferData { /* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */ GVArraySpan src; - bke::OutputAttribute dst; + bke::GSpanAttributeWriter dst; }; -static Vector<AttributeTransferData> retrieve_point_attributes(const CurveComponent &src_component, - CurveComponent &dst_component, - const Set<std::string> &skip = {}) +static Vector<AttributeTransferData> retrieve_point_attributes( + const bke::AttributeAccessor &src_attributes, + bke::MutableAttributeAccessor &dst_attributes, + const Set<std::string> &skip = {}) { Vector<AttributeTransferData> attributes; - src_component.attribute_foreach( - [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) { + src_attributes.for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) { if (meta_data.domain != ATTR_DOMAIN_POINT) { /* Curve domain attributes are all copied directly to the result in one step. */ return true; @@ -97,9 +98,9 @@ static Vector<AttributeTransferData> retrieve_point_attributes(const CurveCompon return true; } - GVArray src = src_component.attribute_try_get_for_read(id, ATTR_DOMAIN_POINT); + GVArray src = src_attributes.lookup(id, ATTR_DOMAIN_POINT); BLI_assert(src); - bke::OutputAttribute dst = dst_component.attribute_try_get_for_output_only( + bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span( id, ATTR_DOMAIN_POINT, meta_data.data_type); BLI_assert(dst); attributes.append({std::move(src), std::move(dst)}); @@ -384,28 +385,27 @@ Curves *subdivide_curves(const CurveComponent &src_component, dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num()); + const bke::AttributeAccessor src_attributes = *src_component.attributes(); + bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write(); + auto subdivide_catmull_rom = [&](IndexMask selection) { - for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) { + for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { subdivide_attribute_catmull_rom(src_curves, dst_curves, selection, point_offsets, cyclic, attribute.src, - attribute.dst.as_span()); - attribute.dst.save(); + attribute.dst.span); + attribute.dst.finish(); } }; auto subdivide_poly = [&](IndexMask selection) { - for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) { - subdivide_attribute_linear(src_curves, - dst_curves, - selection, - point_offsets, - attribute.src, - attribute.dst.as_span()); - attribute.dst.save(); + for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { + subdivide_attribute_linear( + src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); + attribute.dst.finish(); } }; @@ -443,20 +443,16 @@ Curves *subdivide_curves(const CurveComponent &src_component, } }); - for (auto &attribute : retrieve_point_attributes(src_component, - dst_component, + for (auto &attribute : retrieve_point_attributes(src_attributes, + dst_attributes, {"position", "handle_type_left", "handle_type_right", "handle_right", "handle_left"})) { - subdivide_attribute_linear(src_curves, - dst_curves, - selection, - point_offsets, - attribute.src, - attribute.dst.as_span()); - attribute.dst.save(); + subdivide_attribute_linear( + src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span); + attribute.dst.finish(); } }; @@ -473,10 +469,10 @@ Curves *subdivide_curves(const CurveComponent &src_component, subdivide_nurbs); if (!unselected_ranges.is_empty()) { - for (auto &attribute : retrieve_point_attributes(src_component, dst_component)) { + for (auto &attribute : retrieve_point_attributes(src_attributes, dst_attributes)) { bke::curves::copy_point_data( - src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.as_span()); - attribute.dst.save(); + src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span); + attribute.dst.finish(); } } |