Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-07-08 17:16:56 +0300
committerJacques Lucke <jacques@blender.org>2022-07-08 17:16:56 +0300
commitb876ce2a4a4638142439a7cf265a0780491ae4cc (patch)
tree871d71eb6d1cf215869fc941c831c81bcacc6433 /source/blender
parentf391e8f316bd29b700cef874a59cf3b64203d70c (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')
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh814
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh541
-rw-r--r--source/blender/blenkernel/BKE_curves.hh5
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh260
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh10
-rw-r--r--source/blender/blenkernel/BKE_spline.hh4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/attribute.cc2
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc856
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh266
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc125
-rw-r--r--source/blender/blenkernel/intern/curve_legacy_convert.cc11
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc72
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc230
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc191
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc101
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc212
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc102
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc41
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc7
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc15
-rw-r--r--source/blender/draw/intern/draw_curves.cc4
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc22
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc28
-rw-r--r--source/blender/editors/object/object_add.cc4
-rw-r--r--source/blender/editors/object/object_modifier.cc9
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc9
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_density.cc10
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_slide.cc9
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc48
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc33
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc2
-rw-r--r--source/blender/geometry/intern/mesh_primitive_cuboid.cc12
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc22
-rw-r--r--source/blender/geometry/intern/point_merge_by_distance.cc27
-rw-r--r--source/blender/geometry/intern/realize_instances.cc268
-rw-r--r--source/blender/geometry/intern/resample_curves.cc25
-rw-r--r--source/blender/geometry/intern/set_curve_type.cc36
-rw-r--r--source/blender/geometry/intern/subdivide_curves.cc58
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc5
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc37
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc57
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc111
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc52
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc6
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc12
109 files changed, 2764 insertions, 2809 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
new file mode 100644
index 00000000000..b92d0d4326b
--- /dev/null
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -0,0 +1,814 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_color.hh"
+#include "BLI_function_ref.hh"
+#include "BLI_generic_span.hh"
+#include "BLI_generic_virtual_array.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_set.hh"
+
+#include "BKE_anonymous_attribute.hh"
+#include "BKE_attribute.h"
+
+struct Mesh;
+struct PointCloud;
+
+namespace blender::bke {
+
+/**
+ * Identifies an attribute that is either named or anonymous.
+ * It does not own the identifier, so it is just a reference.
+ */
+class AttributeIDRef {
+ private:
+ StringRef name_;
+ const AnonymousAttributeID *anonymous_id_ = nullptr;
+
+ public:
+ AttributeIDRef();
+ AttributeIDRef(StringRef name);
+ AttributeIDRef(StringRefNull name);
+ AttributeIDRef(const char *name);
+ AttributeIDRef(const std::string &name);
+ AttributeIDRef(const AnonymousAttributeID *anonymous_id);
+
+ operator bool() const;
+ uint64_t hash() const;
+ bool is_named() const;
+ bool is_anonymous() const;
+ StringRef name() const;
+ const AnonymousAttributeID &anonymous_id() const;
+ bool should_be_kept() const;
+
+ friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b);
+ friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id);
+};
+
+/**
+ * Contains information about an attribute in a geometry component.
+ * More information can be added in the future. E.g. whether the attribute is builtin and how it is
+ * stored (uv map, vertex group, ...).
+ */
+struct AttributeMetaData {
+ eAttrDomain domain;
+ eCustomDataType data_type;
+
+ constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b)
+ {
+ return (a.domain == b.domain) && (a.data_type == b.data_type);
+ }
+};
+
+struct AttributeKind {
+ eAttrDomain domain;
+ eCustomDataType data_type;
+};
+
+/**
+ * Base class for the attribute initializer types described below.
+ */
+struct AttributeInit {
+ enum class Type {
+ Default,
+ VArray,
+ MoveArray,
+ };
+ Type type;
+ AttributeInit(const Type type) : type(type)
+ {
+ }
+};
+
+/**
+ * Create an attribute using the default value for the data type.
+ * The default values may depend on the attribute provider implementation.
+ */
+struct AttributeInitDefault : public AttributeInit {
+ AttributeInitDefault() : AttributeInit(Type::Default)
+ {
+ }
+};
+
+/**
+ * Create an attribute by copying data from an existing virtual array. The virtual array
+ * must have the same type as the newly created attribute.
+ *
+ * Note that this can be used to fill the new attribute with the default
+ */
+struct AttributeInitVArray : public AttributeInit {
+ blender::GVArray varray;
+
+ AttributeInitVArray(blender::GVArray varray)
+ : AttributeInit(Type::VArray), varray(std::move(varray))
+ {
+ }
+};
+
+/**
+ * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data.
+ * Sometimes data is created before a geometry component is available. In that case, it's
+ * preferable to move data directly to the created attribute to avoid a new allocation and a copy.
+ *
+ * Note that this will only have a benefit for attributes that are stored directly as contiguous
+ * arrays, so not for some built-in attributes.
+ *
+ * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it
+ * can't be used directly, and that is generally how Blender expects custom data to be allocated.
+ */
+struct AttributeInitMove : public AttributeInit {
+ void *data = nullptr;
+
+ AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data)
+ {
+ }
+};
+
+/* Returns false when the iteration should be stopped. */
+using AttributeForeachCallback =
+ FunctionRef<bool(const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data)>;
+
+/**
+ * Result when looking up an attribute from some geometry with the intention of only reading from
+ * it.
+ */
+template<typename T> struct AttributeReader {
+ /**
+ * Virtual array that provides access to the attribute data. This may be empty.
+ */
+ VArray<T> varray;
+ /**
+ * Domain where the attribute is stored. This also determines the size of the virtual array.
+ */
+ eAttrDomain domain;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+};
+
+/**
+ * Result when looking up an attribute from some geometry with read an write access. After writing
+ * to the attribute, the #finish method has to be called. This may invalidate caches based on this
+ * attribute.
+ */
+template<typename T> struct AttributeWriter {
+ /**
+ * Virtual array giving read and write access to the attribute. This may be empty.
+ * Consider using #SpanAttributeWriter when you want to access the virtual array as a span.
+ */
+ VMutableArray<T> varray;
+ /**
+ * Domain where the attribute is stored on the geometry. Also determines the size of the virtual
+ * array.
+ */
+ eAttrDomain domain;
+ /**
+ * A function that has to be called after the attribute has been edited. This may be empty.
+ */
+ std::function<void()> tag_modified_fn;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+
+ /**
+ * Has to be called after the attribute has been modified.
+ */
+ void finish()
+ {
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+};
+
+/**
+ * A version of #AttributeWriter for the common case when the user of the attribute wants to write
+ * to a span instead of a virtual array. Since most attributes are spans internally, this can
+ * result in better performance and also simplifies code.
+ */
+template<typename T> struct SpanAttributeWriter {
+ /**
+ * A span based on the virtual array that contains the attribute data. This may be empty.
+ */
+ MutableVArraySpan<T> span;
+ /**
+ * Domain of the attribute. Also determines the size of the span.
+ */
+ eAttrDomain domain;
+ /**
+ * Has to be called after writing to the span.
+ */
+ std::function<void()> tag_modified_fn;
+
+ SpanAttributeWriter() = default;
+
+ SpanAttributeWriter(AttributeWriter<T> &&other, const bool copy_values_to_span)
+ : span(std::move(other.varray), copy_values_to_span),
+ domain(other.domain),
+ tag_modified_fn(std::move(other.tag_modified_fn))
+ {
+ }
+
+ operator bool() const
+ {
+ return span.varray();
+ }
+
+ /**
+ * Has to be called when done writing to the attribute. This makes sure that the data is copied
+ * to the underlying attribute if it was not stored as an array. Furthermore, this may invalidate
+ * other data depending on the modified attribute.
+ */
+ void finish()
+ {
+ this->span.save();
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+};
+
+/**
+ * A generic version of #AttributeReader.
+ */
+struct GAttributeReader {
+ GVArray varray;
+ eAttrDomain domain;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+
+ template<typename T> AttributeReader<T> typed() const
+ {
+ return {varray.typed<T>(), domain};
+ }
+};
+
+/**
+ * A generic version of #AttributeWriter.
+ */
+struct GAttributeWriter {
+ GVMutableArray varray;
+ eAttrDomain domain;
+ std::function<void()> tag_modified_fn;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+
+ void finish()
+ {
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+
+ template<typename T> AttributeWriter<T> typed() const
+ {
+ return {varray.typed<T>(), domain, tag_modified_fn};
+ }
+};
+
+/**
+ * A generic version of #SpanAttributeWriter.
+ */
+struct GSpanAttributeWriter {
+ GMutableVArraySpan span;
+ eAttrDomain domain;
+ std::function<void()> tag_modified_fn;
+
+ GSpanAttributeWriter() = default;
+
+ GSpanAttributeWriter(GAttributeWriter &&other, const bool copy_values_to_span)
+ : span(std::move(other.varray), copy_values_to_span),
+ domain(other.domain),
+ tag_modified_fn(std::move(other.tag_modified_fn))
+ {
+ }
+
+ operator bool() const
+ {
+ return span.varray();
+ }
+
+ void finish()
+ {
+ this->span.save();
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+};
+
+/**
+ * Core functions which make up the attribute API. They should not be called directly, but through
+ * #AttributesAccessor or #MutableAttributesAccessor.
+ *
+ * This is similar to a virtual function table. A struct of function pointers is used instead,
+ * because this way the attribute accessors can be trivial and can be passed around by value. This
+ * makes it easy to return the attribute accessor for a geometry from a function.
+ */
+struct AttributeAccessorFunctions {
+ bool (*contains)(const void *owner, const AttributeIDRef &attribute_id);
+ std::optional<AttributeMetaData> (*lookup_meta_data)(const void *owner,
+ const AttributeIDRef &attribute_id);
+ bool (*domain_supported)(const void *owner, eAttrDomain domain);
+ int (*domain_size)(const void *owner, eAttrDomain domain);
+ bool (*is_builtin)(const void *owner, const AttributeIDRef &attribute_id);
+ GAttributeReader (*lookup)(const void *owner, const AttributeIDRef &attribute_id);
+ GVArray (*adapt_domain)(const void *owner,
+ const GVArray &varray,
+ eAttrDomain from_domain,
+ eAttrDomain to_domain);
+ bool (*for_all)(const void *owner,
+ FunctionRef<bool(const AttributeIDRef &, const AttributeMetaData &)> fn);
+
+ GAttributeWriter (*lookup_for_write)(void *owner, const AttributeIDRef &attribute_id);
+ bool (*remove)(void *owner, const AttributeIDRef &attribute_id);
+ bool (*add)(void *owner,
+ const AttributeIDRef &attribute_id,
+ eAttrDomain domain,
+ eCustomDataType data_type,
+ const AttributeInit &initializer);
+};
+
+/**
+ * Provides read-only access to the set of attributes on some geometry.
+ *
+ * Note, this does not own the attributes. When the owner is freed, it is invalid to access its
+ * attributes.
+ */
+class AttributeAccessor {
+ protected:
+ /**
+ * The data that actually owns the attributes, for example, a pointer to a #Mesh or #PointCloud
+ * Most commonly this is a pointer to a #Mesh or #PointCloud.
+ * Under some circumstances this can be null. In that case most methods can't be used. Just e.g.
+ * the #domain_size method works and returns 0 for every domain.
+ *
+ * \note This class cannot modify the owner's attributes, but the pointer is still non-const, so
+ * this class can be a base class for the mutable version.
+ */
+ void *owner_;
+ /**
+ * Functions that know how to access the attributes stored in the owner above.
+ */
+ const AttributeAccessorFunctions *fn_;
+
+ public:
+ AttributeAccessor(const void *owner, const AttributeAccessorFunctions &fn)
+ : owner_(const_cast<void *>(owner)), fn_(&fn)
+ {
+ }
+
+ /**
+ * \return True, when the attribute is available.
+ */
+ bool contains(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->contains(owner_, attribute_id);
+ }
+
+ /**
+ * \return Information about the attribute if it exists.
+ */
+ std::optional<AttributeMetaData> lookup_meta_data(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->lookup_meta_data(owner_, attribute_id);
+ }
+
+ /**
+ * \return True, when attributes can exist on that domain.
+ */
+ bool domain_supported(const eAttrDomain domain) const
+ {
+ return fn_->domain_supported(owner_, domain);
+ }
+
+ /**
+ * \return Number of elements in the given domain.
+ */
+ int domain_size(const eAttrDomain domain) const
+ {
+ return fn_->domain_size(owner_, domain);
+ }
+
+ /**
+ * \return True, when the attribute has a special meaning for Blender and can't be used for
+ * arbitrary things.
+ */
+ bool is_builtin(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->is_builtin(owner_, attribute_id);
+ }
+
+ /**
+ * Get read-only access to the attribute. If the attribute does not exist, the return value is
+ * empty.
+ */
+ GAttributeReader lookup(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->lookup(owner_, attribute_id);
+ }
+
+ /**
+ * Get read-only access to the attribute. If necessary, the attribute is interpolated to the
+ * given domain, and converted to the given type, in that order. The result may be empty.
+ */
+ GVArray lookup(const AttributeIDRef &attribute_id,
+ const std::optional<eAttrDomain> domain,
+ const std::optional<eCustomDataType> data_type) const;
+
+ /**
+ * Get read-only access to the attribute whereby the attribute is interpolated to the given
+ * domain. The result may be empty.
+ */
+ GVArray lookup(const AttributeIDRef &attribute_id, const eAttrDomain domain) const
+ {
+ return this->lookup(attribute_id, domain, std::nullopt);
+ }
+
+ /**
+ * Get read-only access to the attribute whereby the attribute is converted to the given type.
+ * The result may be empty.
+ */
+ GVArray lookup(const AttributeIDRef &attribute_id, const eCustomDataType data_type) const
+ {
+ return this->lookup(attribute_id, std::nullopt, data_type);
+ }
+
+ /**
+ * Get read-only access to the attribute. If necessary, the attribute is interpolated to the
+ * given domain and then converted to the given type, in that order. The result may be empty.
+ */
+ template<typename T>
+ VArray<T> lookup(const AttributeIDRef &attribute_id,
+ const std::optional<eAttrDomain> domain = std::nullopt) const
+ {
+ const CPPType &cpp_type = CPPType::get<T>();
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
+ return this->lookup(attribute_id, domain, data_type).typed<T>();
+ }
+
+ /**
+ * Get read-only access to the attribute. If necessary, the attribute is interpolated to the
+ * given domain and then converted to the given data type, in that order.
+ * If the attribute does not exist, a virtual array with the given default value is returned.
+ * If the passed in default value is null, the default value of the type is used (generally 0).
+ */
+ GVArray lookup_or_default(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const void *default_value = nullptr) const;
+
+ /**
+ * Same as the generic version above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ VArray<T> lookup_or_default(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const T &default_value) const
+ {
+ if (VArray<T> varray = this->lookup<T>(attribute_id, domain)) {
+ return varray;
+ }
+ return VArray<T>::ForSingle(default_value, this->domain_size(domain));
+ }
+
+ /**
+ * Interpolate data from one domain to another.
+ */
+ GVArray adapt_domain(const GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
+ {
+ return fn_->adapt_domain(owner_, varray, from_domain, to_domain);
+ }
+
+ /**
+ * Interpolate data from one domain to another.
+ */
+ template<typename T>
+ VArray<T> adapt_domain(const VArray<T> &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
+ {
+ return this->adapt_domain(GVArray(varray), from_domain, to_domain).typed<T>();
+ }
+
+ /**
+ * Run the provided function for every attribute.
+ */
+ bool for_all(const AttributeForeachCallback fn) const
+ {
+ return fn_->for_all(owner_, fn);
+ }
+
+ /**
+ * Get a set of all attributes.
+ */
+ Set<AttributeIDRef> all_ids() const;
+};
+
+/**
+ * Extends #AttributeAccessor with methods that allow modifying individual attributes as well as
+ * the set of attributes.
+ */
+class MutableAttributeAccessor : public AttributeAccessor {
+ public:
+ MutableAttributeAccessor(void *owner, const AttributeAccessorFunctions &fn)
+ : AttributeAccessor(owner, fn)
+ {
+ }
+
+ /**
+ * Get a writable attribute or none if it does not exist.
+ * Make sure to call #finish after changes are done.
+ */
+ GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id)
+ {
+ return fn_->lookup_for_write(owner_, attribute_id);
+ }
+
+ /**
+ * Get a writable attribute or non if it does not exist.
+ * Make sure to call #finish after changes are done.
+ */
+ template<typename T> AttributeWriter<T> lookup_for_write(const AttributeIDRef &attribute_id)
+ {
+ GAttributeWriter attribute = this->lookup_for_write(attribute_id);
+ if (!attribute) {
+ return {};
+ }
+ if (!attribute.varray.type().is<T>()) {
+ return {};
+ }
+ return attribute.typed<T>();
+ }
+
+ /**
+ * Create a new attribute.
+ * \return True, when a new attribute has been created. False, when it's not possible to create
+ * this attribute or there is already an attribute with that id.
+ */
+ bool add(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer)
+ {
+ return fn_->add(owner_, attribute_id, domain, data_type, initializer);
+ }
+
+ /**
+ * Find an attribute with the given id, domain and data type. If it does not exist, create a new
+ * attribute. If the attribute does not exist and can't be created (e.g. because it already
+ * exists on a different domain or with a different type), none is returned.
+ */
+ GAttributeWriter lookup_or_add_for_write(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer = AttributeInitDefault());
+
+ /**
+ * Same as above, but returns a type that makes it easier to work with the attribute as a span.
+ * If the caller newly initializes the attribute, it's better to use
+ * #lookup_or_add_for_write_only_span.
+ */
+ GSpanAttributeWriter lookup_or_add_for_write_span(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer = AttributeInitDefault());
+
+ /**
+ * Same as above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ AttributeWriter<T> lookup_or_add_for_write(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const AttributeInit &initializer = AttributeInitDefault())
+ {
+ const CPPType &cpp_type = CPPType::get<T>();
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
+ return this->lookup_or_add_for_write(attribute_id, domain, data_type, initializer).typed<T>();
+ }
+
+ /**
+ * Same as above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ SpanAttributeWriter<T> lookup_or_add_for_write_span(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const AttributeInit &initializer = AttributeInitDefault())
+ {
+ AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(
+ attribute_id, domain, initializer);
+ if (attribute) {
+ return SpanAttributeWriter<T>{std::move(attribute), true};
+ }
+ return {};
+ }
+
+ /**
+ * Find an attribute with the given id, domain and data type. If it does not exist, create a new
+ * attribute. If the attribute does not exist and can't be created, none is returned.
+ *
+ * The "only" in the name indicates that the caller should not read existing values from the
+ * span. If the attribute is not stored as span internally, the existing values won't be copied
+ * over to the span.
+ */
+ GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type);
+
+ /**
+ * Same as above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ SpanAttributeWriter<T> lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain)
+ {
+ AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(attribute_id, domain);
+ if (attribute) {
+ return SpanAttributeWriter<T>{std::move(attribute), false};
+ }
+ return {};
+ }
+
+ /**
+ * Remove an attribute.
+ * \return True, when the attribute has been deleted. False, when it's not possible to delete
+ * this attribute or if there is no attribute with that id.
+ */
+ bool remove(const AttributeIDRef &attribute_id)
+ {
+ return fn_->remove(owner_, attribute_id);
+ }
+
+ /**
+ * Remove all anonymous attributes.
+ */
+ void remove_anonymous();
+};
+
+bool allow_procedural_attribute_access(StringRef attribute_name);
+extern const char *no_procedural_access_message;
+
+eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types);
+/**
+ * Domains with a higher "information density" have a higher priority,
+ * in order to choose a domain that will not lose data through domain conversion.
+ */
+eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains);
+
+/**
+ * A basic container around DNA CustomData so that its users
+ * don't have to implement special copy and move constructors.
+ */
+class CustomDataAttributes {
+ /**
+ * #CustomData needs a size to be freed, and unfortunately it isn't stored in the struct
+ * itself, so keep track of the size here so this class can implement its own destructor.
+ * If the implementation of the attribute storage changes, this could be removed.
+ */
+ int size_;
+
+ public:
+ CustomData data;
+
+ CustomDataAttributes();
+ ~CustomDataAttributes();
+ CustomDataAttributes(const CustomDataAttributes &other);
+ CustomDataAttributes(CustomDataAttributes &&other);
+ CustomDataAttributes &operator=(const CustomDataAttributes &other);
+
+ void reallocate(int size);
+
+ void clear();
+
+ std::optional<blender::GSpan> get_for_read(const AttributeIDRef &attribute_id) const;
+
+ /**
+ * Return a virtual array for a stored attribute, or a single value virtual array with the
+ * default value if the attribute doesn't exist. If no default value is provided, the default
+ * value for the type will be used.
+ */
+ blender::GVArray get_for_read(const AttributeIDRef &attribute_id,
+ eCustomDataType data_type,
+ const void *default_value) const;
+
+ template<typename T>
+ blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const
+ {
+ const blender::CPPType &cpp_type = blender::CPPType::get<T>();
+ const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ GVArray varray = this->get_for_read(attribute_id, type, &default_value);
+ return varray.typed<T>();
+ }
+
+ std::optional<blender::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
+ bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type);
+ bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer);
+ bool remove(const AttributeIDRef &attribute_id);
+
+ /**
+ * Change the order of the attributes to match the order of IDs in the argument.
+ */
+ void reorder(Span<AttributeIDRef> new_order);
+
+ bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const;
+};
+
+AttributeAccessor mesh_attributes(const Mesh &mesh);
+MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh);
+
+AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud);
+MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud);
+
+/* -------------------------------------------------------------------- */
+/** \name #AttributeIDRef Inline Methods
+ * \{ */
+
+inline AttributeIDRef::AttributeIDRef() = default;
+
+inline AttributeIDRef::AttributeIDRef(StringRef name) : name_(name)
+{
+}
+
+inline AttributeIDRef::AttributeIDRef(StringRefNull name) : name_(name)
+{
+}
+
+inline AttributeIDRef::AttributeIDRef(const char *name) : name_(name)
+{
+}
+
+inline AttributeIDRef::AttributeIDRef(const std::string &name) : name_(name)
+{
+}
+
+/* The anonymous id is only borrowed, the caller has to keep a reference to it. */
+inline AttributeIDRef::AttributeIDRef(const AnonymousAttributeID *anonymous_id)
+ : anonymous_id_(anonymous_id)
+{
+}
+
+inline bool operator==(const AttributeIDRef &a, const AttributeIDRef &b)
+{
+ return a.anonymous_id_ == b.anonymous_id_ && a.name_ == b.name_;
+}
+
+inline AttributeIDRef::operator bool() const
+{
+ return this->is_named() || this->is_anonymous();
+}
+
+inline uint64_t AttributeIDRef::hash() const
+{
+ return get_default_hash_2(name_, anonymous_id_);
+}
+
+inline bool AttributeIDRef::is_named() const
+{
+ return !name_.is_empty();
+}
+
+inline bool AttributeIDRef::is_anonymous() const
+{
+ return anonymous_id_ != nullptr;
+}
+
+inline StringRef AttributeIDRef::name() const
+{
+ BLI_assert(this->is_named());
+ return name_;
+}
+
+inline const AnonymousAttributeID &AttributeIDRef::anonymous_id() const
+{
+ BLI_assert(this->is_anonymous());
+ return *anonymous_id_;
+}
+
+/**
+ * \return True if the attribute should not be removed automatically as an optimization during
+ * processing or copying. Anonymous attributes can be removed when they no longer have any
+ * references.
+ */
+inline bool AttributeIDRef::should_be_kept() const
+{
+ return this->is_named() || BKE_anonymous_attribute_id_has_strong_references(anonymous_id_);
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
deleted file mode 100644
index 9648b5b7cde..00000000000
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ /dev/null
@@ -1,541 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-#include <mutex>
-
-#include "BKE_anonymous_attribute.hh"
-#include "BKE_attribute.h"
-
-#include "BLI_color.hh"
-#include "BLI_function_ref.hh"
-#include "BLI_generic_span.hh"
-#include "BLI_generic_virtual_array.hh"
-#include "BLI_math_vec_types.hh"
-
-/**
- * This file defines classes that help to provide access to attribute data on a #GeometryComponent.
- * The API for retrieving attributes is defined in `BKE_geometry_set.hh`, but this comment has some
- * general comments about the system.
- *
- * Attributes are stored in geometry data, though they can also be stored in instances. Their
- * storage is often tied to `CustomData`, which is a system to store "layers" of data with specific
- * types and names. However, since `CustomData` was added to Blender before attributes were
- * conceptualized, it combines the "legacy" style of task-specific attribute types with generic
- * types like "Float". The attribute API here only provides access to generic types.
- *
- * Attributes are retrieved from geometry components by providing an "id" (#AttributeIDRef). This
- * is most commonly just an attribute name. The attribute API on geometry components has some more
- * advanced capabilities:
- * 1. Read-only access: With a `const` geometry component, an attribute on the geometry cannot be
- * modified, so the `for_write` and `for_output` versions of the API are not available. This is
- * extremely important for writing coherent bug-free code. When an attribute is retrieved with
- * write access, via #WriteAttributeLookup or #OutputAttribute, the geometry component must be
- * tagged to clear caches that depend on the changed data.
- * 2. Domain interpolation: When retrieving an attribute, a domain (#eAttrDomain) can be
- * provided. If the attribute is stored on a different domain and conversion is possible, a
- * version of the data interpolated to the requested domain will be provided. These conversions
- * are implemented in each #GeometryComponent by `attribute_try_adapt_domain_impl`.
- * 3. Implicit type conversion: In addition to interpolating domains, attribute types can be
- * converted, using the conversions in `BKE_type_conversions.hh`. The #VArray / #GVArray system
- * makes it possible to only convert necessary indices on-demand.
- * 4. Anonymous attributes: The "id" used to look up an attribute can also be an anonymous
- * attribute reference. Currently anonymous attributes are only used in geometry nodes.
- * 5. Abstracted storage: Since the data returned from the API is usually a virtual array,
- * it doesn't have to be stored contiguously (even though that is generally preferred). This
- * allows accessing "legacy" attributes like `material_index`, which is stored in `MPoly`.
- */
-
-namespace blender::bke {
-
-/**
- * Identifies an attribute that is either named or anonymous.
- * It does not own the identifier, so it is just a reference.
- */
-class AttributeIDRef {
- private:
- StringRef name_;
- const AnonymousAttributeID *anonymous_id_ = nullptr;
-
- public:
- AttributeIDRef();
- AttributeIDRef(StringRef name);
- AttributeIDRef(StringRefNull name);
- AttributeIDRef(const char *name);
- AttributeIDRef(const std::string &name);
- AttributeIDRef(const AnonymousAttributeID *anonymous_id);
-
- operator bool() const;
- uint64_t hash() const;
- bool is_named() const;
- bool is_anonymous() const;
- StringRef name() const;
- const AnonymousAttributeID &anonymous_id() const;
- bool should_be_kept() const;
-
- friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b);
- friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id);
-};
-
-bool allow_procedural_attribute_access(StringRef attribute_name);
-extern const char *no_procedural_access_message;
-
-} // namespace blender::bke
-
-/**
- * Contains information about an attribute in a geometry component.
- * More information can be added in the future. E.g. whether the attribute is builtin and how it is
- * stored (uv map, vertex group, ...).
- */
-struct AttributeMetaData {
- eAttrDomain domain;
- eCustomDataType data_type;
-
- constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b)
- {
- return (a.domain == b.domain) && (a.data_type == b.data_type);
- }
-};
-
-struct AttributeKind {
- eAttrDomain domain;
- eCustomDataType data_type;
-};
-
-/**
- * Base class for the attribute initializer types described below.
- */
-struct AttributeInit {
- enum class Type {
- Default,
- VArray,
- MoveArray,
- };
- Type type;
- AttributeInit(const Type type) : type(type)
- {
- }
-};
-
-/**
- * Create an attribute using the default value for the data type.
- * The default values may depend on the attribute provider implementation.
- */
-struct AttributeInitDefault : public AttributeInit {
- AttributeInitDefault() : AttributeInit(Type::Default)
- {
- }
-};
-
-/**
- * Create an attribute by copying data from an existing virtual array. The virtual array
- * must have the same type as the newly created attribute.
- *
- * Note that this can be used to fill the new attribute with the default
- */
-struct AttributeInitVArray : public AttributeInit {
- blender::GVArray varray;
-
- AttributeInitVArray(blender::GVArray varray)
- : AttributeInit(Type::VArray), varray(std::move(varray))
- {
- }
-};
-
-/**
- * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data.
- * Sometimes data is created before a geometry component is available. In that case, it's
- * preferable to move data directly to the created attribute to avoid a new allocation and a copy.
- *
- * Note that this will only have a benefit for attributes that are stored directly as contiguous
- * arrays, so not for some built-in attributes.
- *
- * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it
- * can't be used directly, and that is generally how Blender expects custom data to be allocated.
- */
-struct AttributeInitMove : public AttributeInit {
- void *data = nullptr;
-
- AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data)
- {
- }
-};
-
-/* Returns false when the iteration should be stopped. */
-using AttributeForeachCallback = blender::FunctionRef<bool(
- const blender::bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data)>;
-
-namespace blender::bke {
-
-eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types);
-/**
- * Domains with a higher "information density" have a higher priority,
- * in order to choose a domain that will not lose data through domain conversion.
- */
-eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains);
-
-/**
- * Used when looking up a "plain attribute" based on a name for reading from it.
- */
-struct ReadAttributeLookup {
- /* The virtual array that is used to read from this attribute. */
- GVArray varray;
- /* Domain the attribute lives on in the geometry. */
- eAttrDomain domain;
-
- /* Convenience function to check if the attribute has been found. */
- operator bool() const
- {
- return this->varray;
- }
-};
-
-/**
- * Used when looking up a "plain attribute" based on a name for reading from it and writing to it.
- */
-struct WriteAttributeLookup {
- /** The virtual array that is used to read from and write to the attribute. */
- GVMutableArray varray;
- /** Domain the attributes lives on in the geometry component. */
- eAttrDomain domain;
- /**
- * Call this after changing the attribute to invalidate caches that depend on this attribute.
- * \note Do not call this after the component the attribute is from has been destructed.
- */
- std::function<void()> tag_modified_fn;
-
- /* Convenience function to check if the attribute has been found. */
- operator bool() const
- {
- return this->varray;
- }
-};
-
-/**
- * An output attribute allows writing to an attribute (and optionally reading as well). It adds
- * some convenience features on top of `GVMutableArray` that are very commonly used.
- *
- * Supported convenience features:
- * - Implicit type conversion when writing to builtin attributes.
- * - Supports simple access to a span containing the attribute values (that avoids the use of
- * MutableVArraySpan in many cases).
- * - An output attribute can live side by side with an existing attribute with a different domain
- * or data type. The old attribute will only be overwritten when the #save function is called.
- *
- * \note The lifetime of an output attribute should not be longer than the lifetime of the
- * geometry component it comes from, since it can keep a reference to the component for use in
- * the #save method.
- */
-class OutputAttribute {
- public:
- using SaveFn = std::function<void(OutputAttribute &)>;
-
- private:
- GVMutableArray varray_;
- eAttrDomain domain_ = ATTR_DOMAIN_AUTO;
- SaveFn save_;
- std::unique_ptr<GMutableVArraySpan> optional_span_varray_;
- bool ignore_old_values_ = false;
- bool save_has_been_called_ = false;
-
- public:
- OutputAttribute();
- OutputAttribute(OutputAttribute &&other);
- OutputAttribute(GVMutableArray varray, eAttrDomain domain, SaveFn save, bool ignore_old_values);
-
- ~OutputAttribute();
-
- operator bool() const;
-
- GVMutableArray &operator*();
- GVMutableArray *operator->();
- GVMutableArray &varray();
- eAttrDomain domain() const;
- const CPPType &cpp_type() const;
- eCustomDataType custom_data_type() const;
-
- GMutableSpan as_span();
- template<typename T> MutableSpan<T> as_span();
-
- void save();
-};
-
-/**
- * Same as OutputAttribute, but should be used when the data type is known at compile time.
- */
-template<typename T> class OutputAttribute_Typed {
- private:
- OutputAttribute attribute_;
- VMutableArray<T> varray_;
-
- public:
- OutputAttribute_Typed();
- OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute))
- {
- if (attribute_) {
- varray_ = attribute_.varray().template typed<T>();
- }
- }
-
- OutputAttribute_Typed(OutputAttribute_Typed &&other);
- ~OutputAttribute_Typed();
-
- OutputAttribute_Typed &operator=(OutputAttribute_Typed &&other)
- {
- if (this == &other) {
- return *this;
- }
- this->~OutputAttribute_Typed();
- new (this) OutputAttribute_Typed(std::move(other));
- return *this;
- }
-
- operator bool() const
- {
- return varray_;
- }
-
- VMutableArray<T> &operator*()
- {
- return varray_;
- }
-
- VMutableArray<T> *operator->()
- {
- return &varray_;
- }
-
- VMutableArray<T> &varray()
- {
- return varray_;
- }
-
- eAttrDomain domain() const
- {
- return attribute_.domain();
- }
-
- const CPPType &cpp_type() const
- {
- return CPPType::get<T>();
- }
-
- eCustomDataType custom_data_type() const
- {
- return cpp_type_to_custom_data_type(this->cpp_type());
- }
-
- MutableSpan<T> as_span()
- {
- return attribute_.as_span<T>();
- }
-
- void save()
- {
- attribute_.save();
- }
-};
-
-/* These are not defined in the class directly, because when defining them there, the external
- * template instantiation does not work, resulting in longer compile times. */
-template<typename T> inline OutputAttribute_Typed<T>::OutputAttribute_Typed() = default;
-template<typename T>
-inline OutputAttribute_Typed<T>::OutputAttribute_Typed(OutputAttribute_Typed &&other) = default;
-template<typename T> inline OutputAttribute_Typed<T>::~OutputAttribute_Typed() = default;
-
-/**
- * A basic container around DNA CustomData so that its users
- * don't have to implement special copy and move constructors.
- */
-class CustomDataAttributes {
- /**
- * #CustomData needs a size to be freed, and unfortunately it isn't stored in the struct
- * itself, so keep track of the size here so this class can implement its own destructor.
- * If the implementation of the attribute storage changes, this could be removed.
- */
- int size_;
-
- public:
- CustomData data;
-
- CustomDataAttributes();
- ~CustomDataAttributes();
- CustomDataAttributes(const CustomDataAttributes &other);
- CustomDataAttributes(CustomDataAttributes &&other);
- CustomDataAttributes &operator=(const CustomDataAttributes &other);
-
- void reallocate(int size);
-
- void clear();
-
- std::optional<blender::GSpan> get_for_read(const AttributeIDRef &attribute_id) const;
-
- /**
- * Return a virtual array for a stored attribute, or a single value virtual array with the
- * default value if the attribute doesn't exist. If no default value is provided, the default
- * value for the type will be used.
- */
- blender::GVArray get_for_read(const AttributeIDRef &attribute_id,
- eCustomDataType data_type,
- const void *default_value) const;
-
- template<typename T>
- blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- GVArray varray = this->get_for_read(attribute_id, type, &default_value);
- return varray.typed<T>();
- }
-
- std::optional<blender::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
- bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type);
- bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer);
- bool remove(const AttributeIDRef &attribute_id);
-
- /**
- * Change the order of the attributes to match the order of IDs in the argument.
- */
- void reorder(Span<AttributeIDRef> new_order);
-
- bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const;
-};
-
-/* -------------------------------------------------------------------- */
-/** \name #AttributeIDRef Inline Methods
- * \{ */
-
-inline AttributeIDRef::AttributeIDRef() = default;
-
-inline AttributeIDRef::AttributeIDRef(StringRef name) : name_(name)
-{
-}
-
-inline AttributeIDRef::AttributeIDRef(StringRefNull name) : name_(name)
-{
-}
-
-inline AttributeIDRef::AttributeIDRef(const char *name) : name_(name)
-{
-}
-
-inline AttributeIDRef::AttributeIDRef(const std::string &name) : name_(name)
-{
-}
-
-/* The anonymous id is only borrowed, the caller has to keep a reference to it. */
-inline AttributeIDRef::AttributeIDRef(const AnonymousAttributeID *anonymous_id)
- : anonymous_id_(anonymous_id)
-{
-}
-
-inline bool operator==(const AttributeIDRef &a, const AttributeIDRef &b)
-{
- return a.anonymous_id_ == b.anonymous_id_ && a.name_ == b.name_;
-}
-
-inline AttributeIDRef::operator bool() const
-{
- return this->is_named() || this->is_anonymous();
-}
-
-inline uint64_t AttributeIDRef::hash() const
-{
- return get_default_hash_2(name_, anonymous_id_);
-}
-
-inline bool AttributeIDRef::is_named() const
-{
- return !name_.is_empty();
-}
-
-inline bool AttributeIDRef::is_anonymous() const
-{
- return anonymous_id_ != nullptr;
-}
-
-inline StringRef AttributeIDRef::name() const
-{
- BLI_assert(this->is_named());
- return name_;
-}
-
-inline const AnonymousAttributeID &AttributeIDRef::anonymous_id() const
-{
- BLI_assert(this->is_anonymous());
- return *anonymous_id_;
-}
-
-/**
- * \return True if the attribute should not be removed automatically as an optimization during
- * processing or copying. Anonymous attributes can be removed when they no longer have any
- * references.
- */
-inline bool AttributeIDRef::should_be_kept() const
-{
- return this->is_named() || BKE_anonymous_attribute_id_has_strong_references(anonymous_id_);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name #OutputAttribute Inline Methods
- * \{ */
-
-inline OutputAttribute::OutputAttribute() = default;
-inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default;
-
-inline OutputAttribute::OutputAttribute(GVMutableArray varray,
- eAttrDomain domain,
- SaveFn save,
- const bool ignore_old_values)
- : varray_(std::move(varray)),
- domain_(domain),
- save_(std::move(save)),
- ignore_old_values_(ignore_old_values)
-{
-}
-
-inline OutputAttribute::operator bool() const
-{
- return varray_;
-}
-
-inline GVMutableArray &OutputAttribute::operator*()
-{
- return varray_;
-}
-
-inline GVMutableArray *OutputAttribute::operator->()
-{
- return &varray_;
-}
-
-inline GVMutableArray &OutputAttribute::varray()
-{
- return varray_;
-}
-
-inline eAttrDomain OutputAttribute::domain() const
-{
- return domain_;
-}
-
-inline const CPPType &OutputAttribute::cpp_type() const
-{
- return varray_.type();
-}
-
-inline eCustomDataType OutputAttribute::custom_data_type() const
-{
- return cpp_type_to_custom_data_type(this->cpp_type());
-}
-
-template<typename T> inline MutableSpan<T> OutputAttribute::as_span()
-{
- return this->as_span().typed<T>();
-}
-
-/** \} */
-
-} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 3e00dc78b74..fb97e52f6da 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -20,7 +20,7 @@
#include "BLI_vector.hh"
#include "BLI_virtual_array.hh"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
namespace blender::bke {
@@ -401,6 +401,9 @@ class CurvesGeometry : public ::CurvesGeometry {
*/
void remove_attributes_based_on_types();
+ AttributeAccessor attributes() const;
+ MutableAttributeAccessor attributes_for_write();
+
/* --------------------------------------------------------------------
* Attributes.
*/
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 1d4291473bb..4108e2f7e2e 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -8,6 +8,7 @@
#include <atomic>
#include <iostream>
+#include <mutex>
#include "BLI_float4x4.hh"
#include "BLI_function_ref.hh"
@@ -19,7 +20,7 @@
#include "BLI_vector_set.hh"
#include "BKE_anonymous_attribute.hh"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
#include "BKE_geometry_set.h"
struct Curves;
@@ -63,6 +64,15 @@ class GeometryComponent {
virtual ~GeometryComponent() = default;
static GeometryComponent *create(GeometryComponentType component_type);
+ int attribute_domain_size(eAttrDomain domain) const;
+
+ /**
+ * Get access to the attributes in this geometry component. May return none if the geometry does
+ * not support the attribute system.
+ */
+ virtual std::optional<blender::bke::AttributeAccessor> attributes() const;
+ virtual std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write();
+
/* The returned component should be of the same type as the type this is called on. */
virtual GeometryComponent *copy() const = 0;
@@ -78,203 +88,7 @@ class GeometryComponent {
GeometryComponentType type() const;
- /**
- * Return true when any attribute with this name exists, including built in attributes.
- */
- bool attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const;
-
- /**
- * Return the data type and domain of an attribute with the given name if it exists.
- */
- std::optional<AttributeMetaData> attribute_get_meta_data(
- const blender::bke::AttributeIDRef &attribute_id) const;
-
- /**
- * Return true when the geometry component supports this attribute domain.
- * \note Conceptually this function is static, the result is always the same for different
- * instances of the same geometry component type.
- */
- bool attribute_domain_supported(eAttrDomain domain) const;
- /**
- * Return the length of a specific domain, or 0 if the domain is not supported.
- */
- virtual int attribute_domain_num(eAttrDomain domain) const;
-
- /**
- * Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain
- * and data type.
- */
- bool attribute_is_builtin(const blender::StringRef attribute_name) const;
- bool attribute_is_builtin(const blender::bke::AttributeIDRef &attribute_id) const;
-
- /**
- * Get read-only access to an attribute with the given name or id, on the highest priority domain
- * if there is a name collision.
- * \return null if the attribute does not exist.
- */
- blender::bke::ReadAttributeLookup attribute_try_get_for_read(
- const blender::bke::AttributeIDRef &attribute_id) const;
-
- /**
- * Get read and write access to an attribute with the given name or id, on the highest priority
- * domain if there is a name collision.
- * \note #WriteAttributeLookup.tag_modified_fn must be called after modifying data.
- * \return null if the attribute does not exist
- */
- blender::bke::WriteAttributeLookup attribute_try_get_for_write(
- const blender::bke::AttributeIDRef &attribute_id);
-
- /**
- * Get a read-only attribute for the domain based on the given attribute. This can be used to
- * interpolate from one domain to another.
- * \return null if the interpolation is not implemented.
- */
- blender::GVArray attribute_try_adapt_domain(const blender::GVArray &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain) const
- {
- return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain);
- }
- /* Use instead of the method above when the type is known at compile time for type safety. */
- template<typename T>
- blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain) const
- {
- return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain)
- .template typed<T>();
- }
-
- /** Returns true when the attribute has been deleted. */
- bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id);
-
- /**
- * Remove any anonymous attributes on the geometry (they generally shouldn't exist on original
- * geometry).
- */
- void attributes_remove_anonymous();
-
- /** Returns true when the attribute has been created. */
- bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
- eAttrDomain domain,
- eCustomDataType data_type,
- const AttributeInit &initializer);
-
- /**
- * Try to create the builtin attribute with the given name. No data type or domain has to be
- * provided, because those are fixed for builtin attributes.
- */
- bool attribute_try_create_builtin(const blender::StringRef attribute_name,
- const AttributeInit &initializer);
-
- blender::Set<blender::bke::AttributeIDRef> attribute_ids() const;
- /**
- * \return False if the callback explicitly returned false at any point, otherwise true,
- * meaning the callback made it all the way through.
- */
- bool attribute_foreach(const AttributeForeachCallback callback) const;
-
virtual bool is_empty() const;
-
- /**
- * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
- * and converted to the data type. Returns null when the attribute does not exist or cannot be
- * interpolated or converted.
- */
- blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- eAttrDomain domain,
- eCustomDataType data_type) const;
-
- /**
- * Get a virtual array that refers to the data of an attribute, interpolated to the given domain.
- * The data type is left unchanged. Returns null when the attribute does not exist or cannot be
- * interpolated.
- */
- blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- eAttrDomain domain) const;
-
- /**
- * Get a virtual array that refers to the data of an attribute converted to the given data type.
- * The attribute's domain is left unchanged. Returns null when the attribute does not exist or
- * cannot be converted.
- */
- blender::bke::ReadAttributeLookup attribute_try_get_for_read(
- const blender::bke::AttributeIDRef &attribute_id, eCustomDataType data_type) const;
-
- /**
- * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
- * and converted to the data type. If that is not possible, the returned virtual array will
- * contain a default value. This never returns null.
- */
- blender::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- eAttrDomain domain,
- eCustomDataType data_type,
- const void *default_value = nullptr) const;
- /* Use instead of the method above when the type is known at compile time for type safety. */
- template<typename T>
- blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const T &default_value) const
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_get_for_read(attribute_id, domain, type, &default_value)
- .template typed<T>();
- }
-
- /**
- * Returns an "output attribute", which is essentially a mutable virtual array with some commonly
- * used convince features. The returned output attribute might be empty if requested attribute
- * cannot exist on the geometry.
- *
- * The included convenience features are:
- * - Implicit type conversion when writing to builtin attributes.
- * - If the attribute name exists already, but has a different type/domain, a temporary attribute
- * is created that will overwrite the existing attribute in the end.
- */
- blender::bke::OutputAttribute attribute_try_get_for_output(
- const blender::bke::AttributeIDRef &attribute_id,
- eAttrDomain domain,
- eCustomDataType data_type,
- const void *default_value = nullptr);
- /* Use instead of the method above when the type is known at compile time for type safety. */
- template<typename T>
- blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
- const blender::bke::AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const T default_value)
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
- }
-
- /**
- * Same as #attribute_try_get_for_output, but should be used when the original values in the
- * attributes are not read, i.e. the attribute is used only for output. The can be faster because
- * it can avoid interpolation and conversion of existing values. Since values are not read from
- * this attribute, no default value is necessary.
- */
- blender::bke::OutputAttribute attribute_try_get_for_output_only(
- const blender::bke::AttributeIDRef &attribute_id,
- eAttrDomain domain,
- eCustomDataType data_type);
- /* Use instead of the method above when the type is known at compile time for type safety. */
- template<typename T>
- blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
- const blender::bke::AttributeIDRef &attribute_id, const eAttrDomain domain)
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_try_get_for_output_only(attribute_id, domain, data_type);
- }
-
- private:
- virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
-
- virtual blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- eAttrDomain from_domain,
- eAttrDomain to_domain) const;
};
template<typename T>
@@ -381,7 +195,7 @@ struct GeometrySet {
using AttributeForeachCallback =
blender::FunctionRef<void(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeMetaData &meta_data,
+ const blender::bke::AttributeMetaData &meta_data,
const GeometryComponent &component)>;
void attribute_foreach(blender::Span<GeometryComponentType> component_types,
@@ -392,7 +206,7 @@ struct GeometrySet {
blender::Span<GeometryComponentType> component_types,
GeometryComponentType dst_component_type,
bool include_instances,
- blender::Map<blender::bke::AttributeIDRef, AttributeKind> &r_attributes) const;
+ blender::Map<blender::bke::AttributeIDRef, blender::bke::AttributeKind> &r_attributes) const;
blender::Vector<GeometryComponentType> gather_component_types(bool include_instances,
bool ignore_empty) const;
@@ -565,8 +379,6 @@ class MeshComponent : public GeometryComponent {
*/
Mesh *get_for_write();
- int attribute_domain_num(eAttrDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
@@ -574,12 +386,8 @@ class MeshComponent : public GeometryComponent {
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH;
- private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
-
- blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- eAttrDomain from_domain,
- eAttrDomain to_domain) const final;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
};
/**
@@ -628,17 +436,17 @@ class PointCloudComponent : public GeometryComponent {
*/
PointCloud *get_for_write();
- int attribute_domain_num(eAttrDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
+
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
/**
@@ -669,21 +477,15 @@ class CurveComponentLegacy : public GeometryComponent {
const CurveEval *get_for_read() const;
CurveEval *get_for_write();
- int attribute_domain_num(eAttrDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
- static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
- private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
-
- blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- eAttrDomain from_domain,
- eAttrDomain to_domain) const final;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
};
/**
@@ -721,8 +523,6 @@ class CurveComponent : public GeometryComponent {
const Curves *get_for_read() const;
Curves *get_for_write();
- int attribute_domain_num(eAttrDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
@@ -734,14 +534,10 @@ class CurveComponent : public GeometryComponent {
*/
const Curve *get_curve_for_render() const;
- static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
- private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
-
- blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- eAttrDomain from_domain,
- eAttrDomain to_domain) const final;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
};
/**
@@ -966,10 +762,11 @@ class InstancesComponent : public GeometryComponent {
blender::Span<int> almost_unique_ids() const;
- blender::bke::CustomDataAttributes &attributes();
- const blender::bke::CustomDataAttributes &attributes() const;
+ blender::bke::CustomDataAttributes &instance_attributes();
+ const blender::bke::CustomDataAttributes &instance_attributes() const;
- int attribute_domain_num(eAttrDomain domain) const final;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
void foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
@@ -982,7 +779,6 @@ class InstancesComponent : public GeometryComponent {
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
/**
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index cbbd0249f4f..356709d8942 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -13,6 +13,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_attribute.h"
+#include "BKE_attribute.hh"
struct Mesh;
struct BVHTreeFromMesh;
@@ -21,11 +22,6 @@ namespace blender {
class RandomNumberGenerator;
}
-namespace blender::bke {
-struct ReadAttributeLookup;
-class OutputAttribute;
-} // namespace blender::bke
-
namespace blender::bke::mesh_surface_sample {
void sample_point_attribute(const Mesh &mesh,
@@ -81,8 +77,8 @@ class MeshAttributeInterpolator {
eAttributeMapMode mode,
const GMutableSpan dst);
- void sample_attribute(const ReadAttributeLookup &src_attribute,
- OutputAttribute &dst_attribute,
+ void sample_attribute(const GAttributeReader &src_attribute,
+ GSpanAttributeWriter &dst_attribute,
eAttributeMapMode mode);
protected:
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 28f326a4ad4..767018ae0bb 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -15,7 +15,7 @@
#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
struct Curve;
@@ -646,6 +646,8 @@ struct CurveEval {
void transform(const blender::float4x4 &matrix);
bool bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
+ blender::bke::MutableAttributeAccessor attributes_for_write();
+
/**
* Return the start indices for each of the curve spline's control points, if they were part
* of a flattened array. This can be used to facilitate parallelism by avoiding the need to
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index b2307c0e129..d0f9a67f167 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -325,7 +325,7 @@ set(SRC
BKE_asset_library.h
BKE_asset_library.hh
BKE_attribute.h
- BKE_attribute_access.hh
+ BKE_attribute.hh
BKE_attribute_math.hh
BKE_autoexec.h
BKE_blender.h
diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc
index 7c09b4a4ce3..030e4941874 100644
--- a/source/blender/blenkernel/intern/attribute.cc
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -23,7 +23,7 @@
#include "BLI_string_utils.h"
#include "BKE_attribute.h"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
#include "BKE_curves.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index ee9358eb97e..ac1ee19927c 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -2,7 +2,6 @@
#include <utility>
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -26,8 +25,6 @@
#include "attribute_access_intern.hh"
-static CLG_LogRef LOG = {"bke.attribute_access"};
-
using blender::float3;
using blender::GMutableSpan;
using blender::GSpan;
@@ -36,7 +33,6 @@ using blender::Set;
using blender::StringRef;
using blender::StringRefNull;
using blender::bke::AttributeIDRef;
-using blender::bke::OutputAttribute;
namespace blender::bke {
@@ -151,36 +147,6 @@ eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains)
return highest_priority_domain;
}
-GMutableSpan OutputAttribute::as_span()
-{
- if (!optional_span_varray_) {
- const bool materialize_old_values = !ignore_old_values_;
- optional_span_varray_ = std::make_unique<GMutableVArraySpan>(varray_, materialize_old_values);
- }
- GMutableVArraySpan &span_varray = *optional_span_varray_;
- return span_varray;
-}
-
-void OutputAttribute::save()
-{
- save_has_been_called_ = true;
- if (optional_span_varray_) {
- optional_span_varray_->save();
- }
- if (save_) {
- save_(*this);
- }
-}
-
-OutputAttribute::~OutputAttribute()
-{
- if (!save_has_been_called_) {
- if (varray_) {
- std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
- }
- }
-}
-
static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer &layer)
{
if (layer.anonymous_id != nullptr) {
@@ -292,9 +258,9 @@ static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer,
return layer.name == attribute_id.name();
}
-GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent &component) const
+GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const void *owner) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
@@ -310,21 +276,20 @@ GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
- return as_read_attribute_(data, domain_num);
+ const int element_num = custom_data_access_.get_element_num(owner);
+ return as_read_attribute_(data, element_num);
}
-WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
- GeometryComponent &component) const
+GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) const
{
if (writable_ != Writable) {
return {};
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
void *data;
if (stored_as_named_attribute_) {
@@ -340,44 +305,42 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
void *new_data;
if (stored_as_named_attribute_) {
new_data = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, name_.c_str(), domain_num);
+ custom_data, stored_type_, name_.c_str(), element_num);
}
else {
- new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_num);
+ new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num);
}
if (data != new_data) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
data = new_data;
}
std::function<void()> tag_modified_fn;
if (update_on_write_ != nullptr) {
- tag_modified_fn = [component = &component, update = update_on_write_]() {
- update(*component);
- };
+ tag_modified_fn = [owner, update = update_on_write_]() { update(owner); };
}
- return {as_write_attribute_(data, domain_num), domain_, std::move(tag_modified_fn)};
+ return {as_write_attribute_(data, element_num), domain_, std::move(tag_modified_fn)};
}
-bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const
+bool BuiltinCustomDataLayerProvider::try_delete(void *owner) const
{
if (deletable_ != Deletable) {
return false;
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
if (stored_as_named_attribute_) {
- if (CustomData_free_layer_named(custom_data, name_.c_str(), domain_num)) {
+ if (CustomData_free_layer_named(custom_data, name_.c_str(), element_num)) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
return true;
}
@@ -385,27 +348,27 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co
}
const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
- if (CustomData_free_layer(custom_data, stored_type_, domain_num, layer_index)) {
+ if (CustomData_free_layer(custom_data, stored_type_, element_num, layer_index)) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
return true;
}
return false;
}
-bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
+bool BuiltinCustomDataLayerProvider::try_create(void *owner,
const AttributeInit &initializer) const
{
if (createable_ != Creatable) {
return false;
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
bool success;
if (stored_as_named_attribute_) {
if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) {
@@ -413,7 +376,7 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
return false;
}
success = add_custom_data_layer_from_attribute_init(
- name_, *custom_data, stored_type_, domain_num, initializer);
+ name_, *custom_data, stored_type_, element_num, initializer);
}
else {
if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
@@ -421,19 +384,19 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
return false;
}
success = add_builtin_type_custom_data_layer_from_init(
- *custom_data, stored_type_, domain_num, initializer);
+ *custom_data, stored_type_, element_num, initializer);
}
if (success) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
}
return success;
}
-bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const
+bool BuiltinCustomDataLayerProvider::exists(const void *owner) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
@@ -443,14 +406,14 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
return CustomData_get_layer(custom_data, stored_type_) != nullptr;
}
-ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
- const GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeReader CustomDataAttributeProvider::try_get_for_read(
+ const void *owner, const AttributeIDRef &attribute_id) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
continue;
@@ -459,61 +422,62 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
if (type == nullptr) {
continue;
}
- GSpan data{*type, layer.data, domain_num};
+ GSpan data{*type, layer.data, element_num};
return {GVArray::ForSpan(data), domain_};
}
return {};
}
-WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
- GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeWriter CustomDataAttributeProvider::try_get_for_write(
+ void *owner, const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
continue;
}
if (attribute_id.is_named()) {
- CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_num);
+ CustomData_duplicate_referenced_layer_named(
+ custom_data, layer.type, layer.name, element_num);
}
else {
CustomData_duplicate_referenced_layer_anonymous(
- custom_data, layer.type, &attribute_id.anonymous_id(), domain_num);
+ custom_data, layer.type, &attribute_id.anonymous_id(), element_num);
}
const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
if (type == nullptr) {
continue;
}
- GMutableSpan data{*type, layer.data, domain_num};
+ GMutableSpan data{*type, layer.data, element_num};
return {GVMutableArray::ForSpan(data), domain_};
}
return {};
}
-bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const
+bool CustomDataAttributeProvider::try_delete(void *owner, const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
+ ;
for (const int i : IndexRange(custom_data->totlayer)) {
const CustomDataLayer &layer = custom_data->layers[i];
if (this->type_is_supported((eCustomDataType)layer.type) &&
custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- CustomData_free_layer(custom_data, layer.type, domain_num, i);
+ CustomData_free_layer(custom_data, layer.type, element_num, i);
return true;
}
}
return false;
}
-bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
+bool CustomDataAttributeProvider::try_create(void *owner,
const AttributeIDRef &attribute_id,
const eAttrDomain domain,
const eCustomDataType data_type,
@@ -525,7 +489,7 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
if (!this->type_is_supported(data_type)) {
return false;
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
@@ -534,16 +498,16 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
return false;
}
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
add_custom_data_layer_from_attribute_init(
- attribute_id, *custom_data, data_type, domain_num, initializer);
+ attribute_id, *custom_data, data_type, element_num, initializer);
return true;
}
-bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component,
+bool CustomDataAttributeProvider::foreach_attribute(const void *owner,
const AttributeForeachCallback callback) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return true;
}
@@ -560,17 +524,17 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
return true;
}
-ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
- const GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeReader NamedLegacyCustomDataProvider::try_get_for_read(
+ const void *owner, const AttributeIDRef &attribute_id) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_num = component.attribute_domain_num(domain_);
+ const int domain_num = custom_data_access_.get_element_num(owner);
return {as_read_attribute_(layer.data, domain_num), domain_};
}
}
@@ -578,36 +542,36 @@ ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
return {};
}
-WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
- GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeWriter NamedLegacyCustomDataProvider::try_get_for_write(
+ void *owner, const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
void *data_old = layer.data;
void *data_new = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, layer.name, domain_num);
+ custom_data, stored_type_, layer.name, element_num);
if (data_old != data_new) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
}
- return {as_write_attribute_(layer.data, domain_num), domain_};
+ return {as_write_attribute_(layer.data, element_num), domain_};
}
}
}
return {};
}
-bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
+bool NamedLegacyCustomDataProvider::try_delete(void *owner,
const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
@@ -615,10 +579,10 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
const CustomDataLayer &layer = custom_data->layers[i];
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_num = component.attribute_domain_num(domain_);
- CustomData_free_layer(custom_data, stored_type_, domain_num, i);
+ const int element_num = custom_data_access_.get_element_num(owner);
+ CustomData_free_layer(custom_data, stored_type_, element_num, i);
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
return true;
}
@@ -628,9 +592,9 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
}
bool NamedLegacyCustomDataProvider::foreach_attribute(
- const GeometryComponent &component, const AttributeForeachCallback callback) const
+ const void *owner, const AttributeForeachCallback callback) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return true;
}
@@ -804,275 +768,10 @@ void CustomDataAttributes::reorder(Span<AttributeIDRef> new_order)
CustomData_update_typemap(&data);
}
-} // namespace blender::bke
-
/* -------------------------------------------------------------------- */
/** \name Geometry Component
* \{ */
-const blender::bke::ComponentAttributeProviders *GeometryComponent::get_attribute_providers() const
-{
- return nullptr;
-}
-
-bool GeometryComponent::attribute_domain_supported(const eAttrDomain domain) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- return providers->supported_domains().contains(domain);
-}
-
-int GeometryComponent::attribute_domain_num(const eAttrDomain UNUSED(domain)) const
-{
- return 0;
-}
-
-bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_name) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- return providers->builtin_attribute_providers().contains_as(attribute_name);
-}
-
-bool GeometryComponent::attribute_is_builtin(const AttributeIDRef &attribute_id) const
-{
- /* Anonymous attributes cannot be built-in. */
- return attribute_id.is_named() && this->attribute_is_builtin(attribute_id.name());
-}
-
-blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return {};
- }
- if (attribute_id.is_named()) {
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
- if (builtin_provider != nullptr) {
- return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()};
- }
- }
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_id);
- if (attribute) {
- return attribute;
- }
- }
- return {};
-}
-
-blender::GVArray GeometryComponent::attribute_try_adapt_domain_impl(
- const blender::GVArray &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain) const
-{
- if (from_domain == to_domain) {
- return varray;
- }
- return {};
-}
-
-blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write(
- const AttributeIDRef &attribute_id)
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return {};
- }
- if (attribute_id.is_named()) {
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
- if (builtin_provider != nullptr) {
- return builtin_provider->try_get_for_write(*this);
- }
- }
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_id);
- if (attribute) {
- return attribute;
- }
- }
- return {};
-}
-
-bool GeometryComponent::attribute_try_delete(const AttributeIDRef &attribute_id)
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return {};
- }
- if (attribute_id.is_named()) {
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
- if (builtin_provider != nullptr) {
- return builtin_provider->try_delete(*this);
- }
- }
- bool success = false;
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- success = dynamic_provider->try_delete(*this, attribute_id) || success;
- }
- return success;
-}
-
-void GeometryComponent::attributes_remove_anonymous()
-{
- using namespace blender;
- Vector<const AnonymousAttributeID *> anonymous_ids;
- for (const AttributeIDRef &id : this->attribute_ids()) {
- if (id.is_anonymous()) {
- anonymous_ids.append(&id.anonymous_id());
- }
- }
-
- while (!anonymous_ids.is_empty()) {
- this->attribute_try_delete(anonymous_ids.pop_last());
- }
-}
-
-bool GeometryComponent::attribute_try_create(const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const eCustomDataType data_type,
- const AttributeInit &initializer)
-{
- using namespace blender::bke;
- if (!attribute_id) {
- return false;
- }
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- if (this->attribute_exists(attribute_id)) {
- return false;
- }
- if (attribute_id.is_named()) {
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
- if (builtin_provider != nullptr) {
- if (builtin_provider->domain() != domain) {
- return false;
- }
- if (builtin_provider->data_type() != data_type) {
- return false;
- }
- return builtin_provider->try_create(*this, initializer);
- }
- }
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- if (dynamic_provider->try_create(*this, attribute_id, domain, data_type, initializer)) {
- return true;
- }
- }
- return false;
-}
-
-bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name,
- const AttributeInit &initializer)
-{
- using namespace blender::bke;
- if (attribute_name.is_empty()) {
- return false;
- }
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
- if (builtin_provider == nullptr) {
- return false;
- }
- return builtin_provider->try_create(*this, initializer);
-}
-
-Set<AttributeIDRef> GeometryComponent::attribute_ids() const
-{
- Set<AttributeIDRef> attributes;
- this->attribute_foreach(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
- attributes.add(attribute_id);
- return true;
- });
- return attributes;
-}
-
-bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return true;
- }
-
- /* Keep track handled attribute names to make sure that we do not return the same name twice. */
- Set<std::string> handled_attribute_names;
-
- for (const BuiltinAttributeProvider *provider :
- providers->builtin_attribute_providers().values()) {
- if (provider->exists(*this)) {
- AttributeMetaData meta_data{provider->domain(), provider->data_type()};
- if (!callback(provider->name(), meta_data)) {
- return false;
- }
- handled_attribute_names.add_new(provider->name());
- }
- }
- for (const DynamicAttributesProvider *provider : providers->dynamic_attribute_providers()) {
- const bool continue_loop = provider->foreach_attribute(
- *this, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- if (attribute_id.is_anonymous() || handled_attribute_names.add(attribute_id.name())) {
- return callback(attribute_id, meta_data);
- }
- return true;
- });
- if (!continue_loop) {
- return false;
- }
- }
-
- return true;
-}
-
-bool GeometryComponent::attribute_exists(const AttributeIDRef &attribute_id) const
-{
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (attribute) {
- return true;
- }
- return false;
-}
-
-std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
- const AttributeIDRef &attribute_id) const
-{
- std::optional<AttributeMetaData> result{std::nullopt};
- this->attribute_foreach(
- [&](const AttributeIDRef &current_attribute_id, const AttributeMetaData &meta_data) {
- if (attribute_id == current_attribute_id) {
- result = meta_data;
- return false;
- }
- return true;
- });
- return result;
-}
-
static blender::GVArray try_adapt_data_type(blender::GVArray varray,
const blender::CPPType &to_type)
{
@@ -1081,294 +780,6 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray,
return conversions.try_convert(std::move(varray), to_type);
}
-blender::GVArray GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const eCustomDataType data_type) const
-{
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (!attribute) {
- return {};
- }
-
- blender::GVArray varray = std::move(attribute.varray);
- if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) {
- varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain);
- if (!varray) {
- return {};
- }
- }
-
- const blender::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
- if (varray.type() != *cpp_type) {
- varray = try_adapt_data_type(std::move(varray), *cpp_type);
- if (!varray) {
- return {};
- }
- }
-
- return varray;
-}
-
-blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeIDRef &attribute_id,
- const eAttrDomain domain) const
-{
- if (!this->attribute_domain_supported(domain)) {
- return {};
- }
-
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (!attribute) {
- return {};
- }
-
- if (attribute.domain != domain) {
- return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain);
- }
-
- return std::move(attribute.varray);
-}
-
-blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id, const eCustomDataType data_type) const
-{
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (!attribute) {
- return {};
- }
- const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(type != nullptr);
- if (attribute.varray.type() == *type) {
- return attribute;
- }
- const blender::bke::DataTypeConversions &conversions =
- blender::bke::get_implicit_type_conversions();
- return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
-}
-
-blender::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const eCustomDataType data_type,
- const void *default_value) const
-{
- blender::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type);
- if (varray) {
- return varray;
- }
- const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
- if (default_value == nullptr) {
- default_value = type->default_value();
- }
- const int domain_num = this->attribute_domain_num(domain);
- return blender::GVArray::ForSingle(*type, domain_num, default_value);
-}
-
-class GVMutableAttribute_For_OutputAttribute : public blender::GVArrayImpl_For_GSpan {
- public:
- GeometryComponent *component;
- std::string attribute_name;
- blender::bke::WeakAnonymousAttributeID anonymous_attribute_id;
-
- GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
- GeometryComponent &component,
- const AttributeIDRef &attribute_id)
- : blender::GVArrayImpl_For_GSpan(data), component(&component)
- {
- if (attribute_id.is_named()) {
- this->attribute_name = attribute_id.name();
- }
- else {
- const AnonymousAttributeID *anonymous_id = &attribute_id.anonymous_id();
- BKE_anonymous_attribute_id_increment_weak(anonymous_id);
- this->anonymous_attribute_id = blender::bke::WeakAnonymousAttributeID{anonymous_id};
- }
- }
-
- ~GVMutableAttribute_For_OutputAttribute() override
- {
- type_->destruct_n(data_, size_);
- MEM_freeN(data_);
- }
-};
-
-static void save_output_attribute(OutputAttribute &output_attribute)
-{
- using namespace blender;
- using namespace blender::fn;
- using namespace blender::bke;
-
- GVMutableAttribute_For_OutputAttribute &varray =
- dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(
- *output_attribute.varray().get_implementation());
-
- GeometryComponent &component = *varray.component;
- AttributeIDRef attribute_id;
- if (!varray.attribute_name.empty()) {
- attribute_id = varray.attribute_name;
- }
- else {
- attribute_id = varray.anonymous_attribute_id.extract();
- }
- const eAttrDomain domain = output_attribute.domain();
- const eCustomDataType data_type = output_attribute.custom_data_type();
- const CPPType &cpp_type = output_attribute.cpp_type();
-
- component.attribute_try_delete(attribute_id);
- if (!component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault())) {
- if (!varray.attribute_name.empty()) {
- CLOG_WARN(&LOG,
- "Could not create the '%s' attribute with type '%s'.",
- varray.attribute_name.c_str(),
- cpp_type.name().c_str());
- }
- return;
- }
- WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id);
- BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer);
- for (const int i : IndexRange(varray.size())) {
- varray.get(i, buffer);
- write_attribute.varray.set_by_relocate(i, buffer);
- }
- if (write_attribute.tag_modified_fn) {
- write_attribute.tag_modified_fn();
- }
-}
-
-static std::function<void(OutputAttribute &)> get_simple_output_attribute_save_method(
- const blender::bke::WriteAttributeLookup &attribute)
-{
- if (!attribute.tag_modified_fn) {
- return {};
- }
- return [tag_modified_fn = attribute.tag_modified_fn](OutputAttribute &UNUSED(attribute)) {
- tag_modified_fn();
- };
-}
-
-static OutputAttribute create_output_attribute(GeometryComponent &component,
- const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const eCustomDataType data_type,
- const bool ignore_old_values,
- const void *default_value)
-{
- using namespace blender;
- using namespace blender::fn;
- using namespace blender::bke;
-
- if (!attribute_id) {
- return {};
- }
-
- const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
- const DataTypeConversions &conversions = get_implicit_type_conversions();
-
- if (component.attribute_is_builtin(attribute_id)) {
- const StringRef attribute_name = attribute_id.name();
- WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
- if (!attribute) {
- if (default_value) {
- const int64_t domain_num = component.attribute_domain_num(domain);
- component.attribute_try_create_builtin(
- attribute_name,
- AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value)));
- }
- else {
- component.attribute_try_create_builtin(attribute_name, AttributeInitDefault());
- }
- attribute = component.attribute_try_get_for_write(attribute_name);
- if (!attribute) {
- /* Builtin attribute does not exist and can't be created. */
- return {};
- }
- }
- if (attribute.domain != domain) {
- /* Builtin attribute is on different domain. */
- return {};
- }
- GVMutableArray varray = std::move(attribute.varray);
- if (varray.type() == *cpp_type) {
- /* Builtin attribute matches exactly. */
- return OutputAttribute(std::move(varray),
- domain,
- get_simple_output_attribute_save_method(attribute),
- ignore_old_values);
- }
- /* Builtin attribute is on the same domain but has a different data type. */
- varray = conversions.try_convert(std::move(varray), *cpp_type);
- return OutputAttribute(std::move(varray),
- domain,
- get_simple_output_attribute_save_method(attribute),
- ignore_old_values);
- }
-
- const int domain_num = component.attribute_domain_num(domain);
-
- WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id);
- if (!attribute) {
- if (default_value) {
- component.attribute_try_create(
- attribute_id,
- domain,
- data_type,
- AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value)));
- }
- else {
- component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault());
- }
-
- attribute = component.attribute_try_get_for_write(attribute_id);
- if (!attribute) {
- /* Can't create the attribute. */
- return {};
- }
- }
- if (attribute.domain == domain && attribute.varray.type() == *cpp_type) {
- /* Existing generic attribute matches exactly. */
-
- return OutputAttribute(std::move(attribute.varray),
- domain,
- get_simple_output_attribute_save_method(attribute),
- ignore_old_values);
- }
-
- /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
- * attribute after processing is done. */
- void *data = MEM_mallocN_aligned(cpp_type->size() * domain_num, cpp_type->alignment(), __func__);
- if (ignore_old_values) {
- /* This does nothing for trivially constructible types, but is necessary for correctness. */
- cpp_type->default_construct_n(data, domain);
- }
- else {
- /* Fill the temporary array with values from the existing attribute. */
- GVArray old_varray = component.attribute_get_for_read(
- attribute_id, domain, data_type, default_value);
- old_varray.materialize_to_uninitialized(IndexRange(domain_num), data);
- }
- GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>(
- GMutableSpan{*cpp_type, data, domain_num}, component, attribute_id);
-
- return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
-}
-
-OutputAttribute GeometryComponent::attribute_try_get_for_output(const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const eCustomDataType data_type,
- const void *default_value)
-{
- return create_output_attribute(*this, attribute_id, domain, data_type, false, default_value);
-}
-
-OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
- const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
-{
- return create_output_attribute(*this, attribute_id, domain, data_type, true, nullptr);
-}
-
-namespace blender::bke {
-
GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope &UNUSED(scope)) const
@@ -1387,7 +798,10 @@ GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &com
IndexMask UNUSED(mask)) const
{
const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- return component.attribute_try_get_for_read(name_, domain, data_type);
+ if (auto attributes = component.attributes()) {
+ return attributes->lookup(name_, domain, data_type);
+ }
+ return {};
}
std::string AttributeFieldInput::socket_inspection_name() const
@@ -1427,10 +841,10 @@ GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &c
{
const StringRef name = get_random_id_attribute_name(domain);
- GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32);
- if (attribute) {
- BLI_assert(attribute.size() == component.attribute_domain_num(domain));
- return attribute;
+ if (auto attributes = component.attributes()) {
+ if (GVArray attribute = attributes->lookup(name, domain, CD_PROP_INT32)) {
+ return attribute;
+ }
}
/* Use the index as the fallback if no random ID attribute exists. */
@@ -1459,7 +873,7 @@ GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryCompo
IndexMask UNUSED(mask)) const
{
const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type);
+ return component.attributes()->lookup(anonymous_id_.get(), domain, data_type);
}
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
@@ -1483,6 +897,120 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
+GVArray AttributeAccessor::lookup(const AttributeIDRef &attribute_id,
+ const std::optional<eAttrDomain> domain,
+ const std::optional<eCustomDataType> data_type) const
+{
+ GAttributeReader attribute = this->lookup(attribute_id);
+ if (!attribute) {
+ return {};
+ }
+ GVArray varray = std::move(attribute.varray);
+ if (domain.has_value()) {
+ if (attribute.domain != domain) {
+ varray = this->adapt_domain(varray, attribute.domain, *domain);
+ if (!varray) {
+ return {};
+ }
+ }
+ }
+ if (data_type.has_value()) {
+ const CPPType &type = *custom_data_type_to_cpp_type(*data_type);
+ if (varray.type() != type) {
+ varray = try_adapt_data_type(std::move(varray), type);
+ if (!varray) {
+ return {};
+ }
+ }
+ }
+ return varray;
+}
+
+GVArray AttributeAccessor::lookup_or_default(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const void *default_value) const
+{
+ GVArray varray = this->lookup(attribute_id, domain, data_type);
+ if (varray) {
+ return varray;
+ }
+ const CPPType &type = *custom_data_type_to_cpp_type(data_type);
+ const int64_t domain_size = this->domain_size(domain);
+ if (default_value == nullptr) {
+ return GVArray::ForSingleRef(type, domain_size, type.default_value());
+ }
+ return GVArray::ForSingle(type, domain_size, default_value);
+}
+
+Set<AttributeIDRef> AttributeAccessor::all_ids() const
+{
+ Set<AttributeIDRef> ids;
+ this->for_all(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData & /* meta_data */) {
+ ids.add(attribute_id);
+ return true;
+ });
+ return ids;
+}
+
+void MutableAttributeAccessor::remove_anonymous()
+{
+ Vector<const AnonymousAttributeID *> anonymous_ids;
+ for (const AttributeIDRef &id : this->all_ids()) {
+ if (id.is_anonymous()) {
+ anonymous_ids.append(&id.anonymous_id());
+ }
+ }
+
+ while (!anonymous_ids.is_empty()) {
+ this->remove(anonymous_ids.pop_last());
+ }
+}
+
+GAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer)
+{
+ std::optional<AttributeMetaData> meta_data = this->lookup_meta_data(attribute_id);
+ if (meta_data.has_value()) {
+ if (meta_data->domain == domain && meta_data->data_type == data_type) {
+ return this->lookup_for_write(attribute_id);
+ }
+ return {};
+ }
+ if (this->add(attribute_id, domain, data_type, initializer)) {
+ return this->lookup_for_write(attribute_id);
+ }
+ return {};
+}
+
+GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer)
+{
+ GAttributeWriter attribute = this->lookup_or_add_for_write(
+ attribute_id, domain, data_type, initializer);
+ if (attribute) {
+ return GSpanAttributeWriter{std::move(attribute), true};
+ }
+ return {};
+}
+
+GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span(
+ const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
+{
+ GAttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain, data_type);
+ if (attribute) {
+ return GSpanAttributeWriter{std::move(attribute), false};
+ }
+ return {};
+}
+
} // namespace blender::bke
/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index ac43754dd1a..17432fa2726 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -15,12 +15,14 @@ namespace blender::bke {
* components in a generic way.
*/
struct CustomDataAccessInfo {
- using CustomDataGetter = CustomData *(*)(GeometryComponent &component);
- using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component);
- using UpdateCustomDataPointers = void (*)(GeometryComponent &component);
+ using CustomDataGetter = CustomData *(*)(void *owner);
+ using ConstCustomDataGetter = const CustomData *(*)(const void *owner);
+ using GetElementNum = int (*)(const void *owner);
+ using UpdateCustomDataPointers = void (*)(void *owner);
CustomDataGetter get_custom_data;
ConstCustomDataGetter get_const_custom_data;
+ GetElementNum get_element_num;
UpdateCustomDataPointers update_custom_data_pointers;
};
@@ -69,12 +71,11 @@ class BuiltinAttributeProvider {
{
}
- virtual GVArray try_get_for_read(const GeometryComponent &component) const = 0;
- virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component) const = 0;
- virtual bool try_delete(GeometryComponent &component) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const = 0;
- virtual bool exists(const GeometryComponent &component) const = 0;
+ virtual GVArray try_get_for_read(const void *owner) const = 0;
+ virtual GAttributeWriter try_get_for_write(void *owner) const = 0;
+ virtual bool try_delete(void *owner) const = 0;
+ virtual bool try_create(void *onwer, const AttributeInit &initializer) const = 0;
+ virtual bool exists(const void *owner) const = 0;
StringRefNull name() const
{
@@ -98,23 +99,23 @@ class BuiltinAttributeProvider {
*/
class DynamicAttributesProvider {
public:
- virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const = 0;
- virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const = 0;
- virtual bool try_delete(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component),
- const AttributeIDRef &UNUSED(attribute_id),
- const eAttrDomain UNUSED(domain),
- const eCustomDataType UNUSED(data_type),
- const AttributeInit &UNUSED(initializer)) const
+ virtual GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const = 0;
+ virtual GAttributeWriter try_get_for_write(void *owner,
+ const AttributeIDRef &attribute_id) const = 0;
+ virtual bool try_delete(void *owner, const AttributeIDRef &attribute_id) const = 0;
+ virtual bool try_create(void *owner,
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer) const
{
+ UNUSED_VARS(owner, attribute_id, domain, data_type, initializer);
/* Some providers should not create new attributes. */
return false;
};
- virtual bool foreach_attribute(const GeometryComponent &component,
+ virtual bool foreach_attribute(const void *owner,
const AttributeForeachCallback callback) const = 0;
virtual void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const = 0;
};
@@ -138,22 +139,20 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
{
}
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final;
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final;
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final;
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final;
- bool try_create(GeometryComponent &component,
+ bool try_create(void *owner,
const AttributeIDRef &attribute_id,
eAttrDomain domain,
const eCustomDataType data_type,
const AttributeInit &initializer) const final;
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final;
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final;
void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
{
@@ -197,13 +196,11 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
{
}
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final;
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final;
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final;
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final;
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final;
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final;
void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final;
};
@@ -226,10 +223,10 @@ template<typename T> GVMutableArray make_array_write_attribute(void *data, const
* if the stored type is the same as the attribute type.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = GVArray (*)(const void *data, int domain_num);
- using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num);
- using UpdateOnRead = void (*)(const GeometryComponent &component);
- using UpdateOnWrite = void (*)(GeometryComponent &component);
+ using AsReadAttribute = GVArray (*)(const void *data, int element_num);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int element_num);
+ using UpdateOnRead = void (*)(const void *owner);
+ using UpdateOnWrite = void (*)(void *owner);
const eCustomDataType stored_type_;
const CustomDataAccessInfo custom_data_access_;
const AsReadAttribute as_read_attribute_;
@@ -260,11 +257,11 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const final;
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final;
- bool try_delete(GeometryComponent &component) const final;
- bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final;
- bool exists(const GeometryComponent &component) const final;
+ GVArray try_get_for_read(const void *owner) const final;
+ GAttributeWriter try_get_for_write(void *owner) const final;
+ bool try_delete(void *owner) const final;
+ bool try_create(void *owner, const AttributeInit &initializer) const final;
+ bool exists(const void *owner) const final;
};
/**
@@ -321,4 +318,183 @@ class ComponentAttributeProviders {
}
};
+namespace attribute_accessor_functions {
+
+template<const ComponentAttributeProviders &providers>
+inline bool is_builtin(const void *UNUSED(owner), const AttributeIDRef &attribute_id)
+{
+ if (!attribute_id.is_named()) {
+ return false;
+ }
+ const StringRef name = attribute_id.name();
+ return providers.builtin_attribute_providers().contains_as(name);
+}
+
+template<const ComponentAttributeProviders &providers>
+inline GAttributeReader lookup(const void *owner, const AttributeIDRef &attribute_id)
+{
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ return {provider->try_get_for_read(owner), provider->domain()};
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ GAttributeReader attribute = provider->try_get_for_read(owner, attribute_id);
+ if (attribute) {
+ return attribute;
+ }
+ }
+ return {};
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool for_all(const void *owner,
+ FunctionRef<bool(const AttributeIDRef &, const AttributeMetaData &)> fn)
+{
+ Set<AttributeIDRef> handled_attribute_ids;
+ for (const BuiltinAttributeProvider *provider :
+ providers.builtin_attribute_providers().values()) {
+ if (provider->exists(owner)) {
+ AttributeMetaData meta_data{provider->domain(), provider->data_type()};
+ if (!fn(provider->name(), meta_data)) {
+ return false;
+ }
+ handled_attribute_ids.add_new(provider->name());
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ const bool continue_loop = provider->foreach_attribute(
+ owner, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (handled_attribute_ids.add(attribute_id)) {
+ return fn(attribute_id, meta_data);
+ }
+ return true;
+ });
+ if (!continue_loop) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool contains(const void *owner, const blender::bke::AttributeIDRef &attribute_id)
+{
+ bool found = false;
+ for_all<providers>(
+ owner,
+ [&](const AttributeIDRef &other_attribute_id, const AttributeMetaData & /* meta_data */) {
+ if (attribute_id == other_attribute_id) {
+ found = true;
+ return false;
+ }
+ return true;
+ });
+ return found;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline std::optional<AttributeMetaData> lookup_meta_data(const void *owner,
+ const AttributeIDRef &attribute_id)
+{
+ std::optional<AttributeMetaData> meta_data;
+ for_all<providers>(
+ owner,
+ [&](const AttributeIDRef &other_attribute_id, const AttributeMetaData &other_meta_data) {
+ if (attribute_id == other_attribute_id) {
+ meta_data = other_meta_data;
+ return false;
+ }
+ return true;
+ });
+ return meta_data;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline GAttributeWriter lookup_for_write(void *owner, const AttributeIDRef &attribute_id)
+{
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ return provider->try_get_for_write(owner);
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ GAttributeWriter attribute = provider->try_get_for_write(owner, attribute_id);
+ if (attribute) {
+ return attribute;
+ }
+ }
+ return {};
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool remove(void *owner, const AttributeIDRef &attribute_id)
+{
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ return provider->try_delete(owner);
+ }
+ }
+ bool success = false;
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ success = provider->try_delete(owner, attribute_id) || success;
+ }
+ return success;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool add(void *owner,
+ const AttributeIDRef &attribute_id,
+ eAttrDomain domain,
+ eCustomDataType data_type,
+ const AttributeInit &initializer)
+{
+ if (contains<providers>(owner, attribute_id)) {
+ return false;
+ }
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ if (provider->domain() != domain) {
+ return false;
+ }
+ if (provider->data_type() != data_type) {
+ return false;
+ }
+ return provider->try_create(owner, initializer);
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ if (provider->try_create(owner, attribute_id, domain, data_type, initializer)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline AttributeAccessorFunctions accessor_functions_for_providers()
+{
+ return AttributeAccessorFunctions{contains<providers>,
+ lookup_meta_data<providers>,
+ nullptr,
+ nullptr,
+ is_builtin<providers>,
+ lookup<providers>,
+ nullptr,
+ for_all<providers>,
+ lookup_for_write<providers>,
+ remove<providers>,
+ add<providers>};
+}
+
+} // namespace attribute_accessor_functions
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index c01a184c6f9..424fa311dc7 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -31,9 +31,7 @@ using blender::VArray;
using blender::VArraySpan;
using blender::Vector;
using blender::bke::AttributeIDRef;
-using blender::bke::OutputAttribute;
-using blender::bke::OutputAttribute_Typed;
-using blender::bke::ReadAttributeLookup;
+using blender::bke::AttributeMetaData;
blender::Span<SplinePtr> CurveEval::splines() const
{
@@ -345,32 +343,31 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve));
}
-static void copy_attributes_between_components(const GeometryComponent &src_component,
- GeometryComponent &dst_component,
- Span<std::string> skip)
+static void copy_attributes_between_components(
+ const blender::bke::AttributeAccessor &src_attributes,
+ blender::bke::MutableAttributeAccessor &dst_attributes,
+ Span<std::string> skip)
{
- src_component.attribute_foreach(
- [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (id.is_named() && skip.contains(id.name())) {
- return true;
- }
+ src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (id.is_named() && skip.contains(id.name())) {
+ return true;
+ }
- GVArray src_attribute = src_component.attribute_try_get_for_read(
- id, meta_data.domain, meta_data.data_type);
- if (!src_attribute) {
- return true;
- }
- GVArraySpan src_attribute_data{src_attribute};
+ GVArray src_attribute = src_attributes.lookup(id, meta_data.domain, meta_data.data_type);
+ if (!src_attribute) {
+ return true;
+ }
+ GVArraySpan src_attribute_data{src_attribute};
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- id, meta_data.domain, meta_data.data_type);
- if (!dst_attribute) {
- return true;
- }
- dst_attribute.varray().set_all(src_attribute_data.data());
- dst_attribute.save();
- return true;
- });
+ blender::bke::GAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write(
+ id, meta_data.domain, meta_data.data_type);
+ if (!dst_attribute) {
+ return true;
+ }
+ dst_attribute.varray.set_all(src_attribute_data.data());
+ dst_attribute.finish();
+ return true;
+ });
}
std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
@@ -379,21 +376,22 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
src_component.replace(&const_cast<Curves &>(curves_id), GeometryOwnershipType::ReadOnly);
const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
curves_id.geometry);
+ const blender::bke::AttributeAccessor src_attributes = curves.attributes();
VArray<int> resolution = curves.resolution();
VArray<int8_t> normal_mode = curves.normal_mode();
VArraySpan<float> nurbs_weights{
- src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
+ src_attributes.lookup_or_default<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
VArraySpan<int8_t> nurbs_orders{
- src_component.attribute_get_for_read<int8_t>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
+ src_attributes.lookup_or_default<int8_t>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
VArraySpan<int8_t> nurbs_knots_modes{
- src_component.attribute_get_for_read<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)};
+ src_attributes.lookup_or_default<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)};
VArraySpan<int8_t> handle_types_right{
- src_component.attribute_get_for_read<int8_t>("handle_type_right", ATTR_DOMAIN_POINT, 0)};
+ src_attributes.lookup_or_default<int8_t>("handle_type_right", ATTR_DOMAIN_POINT, 0)};
VArraySpan<int8_t> handle_types_left{
- src_component.attribute_get_for_read<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)};
+ src_attributes.lookup_or_default<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)};
/* Create splines with the correct size and type. */
VArray<int8_t> curve_types = curves.curve_types();
@@ -446,9 +444,10 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
CurveComponentLegacy dst_component;
dst_component.replace(curve_eval.get(), GeometryOwnershipType::Editable);
+ blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
- copy_attributes_between_components(src_component,
- dst_component,
+ copy_attributes_between_components(src_attributes,
+ dst_attributes,
{"curve_type",
"resolution",
"normal_mode",
@@ -467,37 +466,38 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
curve_eval.splines().size());
CurveComponent dst_component;
dst_component.replace(curves_id, GeometryOwnershipType::Editable);
+ blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(curves_id->geometry);
curves.offsets_for_write().copy_from(curve_eval.control_point_offsets());
MutableSpan<int8_t> curve_types = curves.curve_types_for_write();
- OutputAttribute_Typed<int8_t> normal_mode =
- dst_component.attribute_try_get_for_output_only<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
- OutputAttribute_Typed<float> nurbs_weight;
- OutputAttribute_Typed<int> nurbs_order;
- OutputAttribute_Typed<int8_t> nurbs_knots_mode;
+ blender::bke::SpanAttributeWriter<int8_t> normal_mode =
+ dst_attributes.lookup_or_add_for_write_only_span<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
+ blender::bke::SpanAttributeWriter<float> nurbs_weight;
+ blender::bke::SpanAttributeWriter<int> nurbs_order;
+ blender::bke::SpanAttributeWriter<int8_t> nurbs_knots_mode;
if (curve_eval.has_spline_with_type(CURVE_TYPE_NURBS)) {
- nurbs_weight = dst_component.attribute_try_get_for_output_only<float>("nurbs_weight",
- ATTR_DOMAIN_POINT);
- nurbs_order = dst_component.attribute_try_get_for_output_only<int>("nurbs_order",
- ATTR_DOMAIN_CURVE);
- nurbs_knots_mode = dst_component.attribute_try_get_for_output_only<int8_t>("knots_mode",
- ATTR_DOMAIN_CURVE);
+ nurbs_weight = dst_attributes.lookup_or_add_for_write_only_span<float>("nurbs_weight",
+ ATTR_DOMAIN_POINT);
+ nurbs_order = dst_attributes.lookup_or_add_for_write_only_span<int>("nurbs_order",
+ ATTR_DOMAIN_CURVE);
+ nurbs_knots_mode = dst_attributes.lookup_or_add_for_write_only_span<int8_t>("knots_mode",
+ ATTR_DOMAIN_CURVE);
}
- OutputAttribute_Typed<int8_t> handle_type_right;
- OutputAttribute_Typed<int8_t> handle_type_left;
+ blender::bke::SpanAttributeWriter<int8_t> handle_type_right;
+ blender::bke::SpanAttributeWriter<int8_t> handle_type_left;
if (curve_eval.has_spline_with_type(CURVE_TYPE_BEZIER)) {
- handle_type_right = dst_component.attribute_try_get_for_output_only<int8_t>(
+ handle_type_right = dst_attributes.lookup_or_add_for_write_only_span<int8_t>(
"handle_type_right", ATTR_DOMAIN_POINT);
- handle_type_left = dst_component.attribute_try_get_for_output_only<int8_t>("handle_type_left",
- ATTR_DOMAIN_POINT);
+ handle_type_left = dst_attributes.lookup_or_add_for_write_only_span<int8_t>("handle_type_left",
+ ATTR_DOMAIN_POINT);
}
for (const int curve_index : curve_eval.splines().index_range()) {
const Spline &spline = *curve_eval.splines()[curve_index];
curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
- normal_mode.as_span()[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
+ normal_mode.span[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
const IndexRange points = curves.points_for_curve(curve_index);
switch (spline.type()) {
@@ -505,15 +505,15 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
break;
case CURVE_TYPE_BEZIER: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
- handle_type_right.as_span().slice(points).copy_from(src.handle_types_right());
- handle_type_left.as_span().slice(points).copy_from(src.handle_types_left());
+ handle_type_right.span.slice(points).copy_from(src.handle_types_right());
+ handle_type_left.span.slice(points).copy_from(src.handle_types_left());
break;
}
case CURVE_TYPE_NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
- nurbs_knots_mode.as_span()[curve_index] = static_cast<int8_t>(src.knots_mode);
- nurbs_order.as_span()[curve_index] = src.order();
- nurbs_weight.as_span().slice(points).copy_from(src.weights());
+ nurbs_knots_mode.span[curve_index] = static_cast<int8_t>(src.knots_mode);
+ nurbs_order.span[curve_index] = src.order();
+ nurbs_weight.span.slice(points).copy_from(src.weights());
break;
}
case CURVE_TYPE_CATMULL_ROM: {
@@ -525,17 +525,18 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
curves.update_curve_types();
- normal_mode.save();
- nurbs_weight.save();
- nurbs_order.save();
- nurbs_knots_mode.save();
- handle_type_right.save();
- handle_type_left.save();
+ normal_mode.finish();
+ nurbs_weight.finish();
+ nurbs_order.finish();
+ nurbs_knots_mode.finish();
+ handle_type_right.finish();
+ handle_type_left.finish();
CurveComponentLegacy src_component;
src_component.replace(&const_cast<CurveEval &>(curve_eval), GeometryOwnershipType::ReadOnly);
+ const blender::bke::AttributeAccessor src_attributes = *src_component.attributes();
- copy_attributes_between_components(src_component, dst_component, {});
+ copy_attributes_between_components(src_attributes, dst_attributes, {});
return curves_id;
}
diff --git a/source/blender/blenkernel/intern/curve_legacy_convert.cc b/source/blender/blenkernel/intern/curve_legacy_convert.cc
index 299a0fbb44c..ff5bbc32afe 100644
--- a/source/blender/blenkernel/intern/curve_legacy_convert.cc
+++ b/source/blender/blenkernel/intern/curve_legacy_convert.cc
@@ -83,8 +83,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
Curves *curves_id = curves_new_nomain(0, src_curves.size());
CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
- CurveComponent component;
- component.replace(curves_id, GeometryOwnershipType::Editable);
+ MutableAttributeAccessor curves_attributes = curves.attributes_for_write();
MutableSpan<int8_t> types = curves.curve_types_for_write();
MutableSpan<bool> cyclic = curves.cyclic_for_write();
@@ -110,9 +109,9 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
}
MutableSpan<float3> positions = curves.positions_for_write();
- OutputAttribute_Typed<float> radius_attribute =
- component.attribute_try_get_for_output_only<float>("radius", ATTR_DOMAIN_POINT);
- MutableSpan<float> radii = radius_attribute.as_span();
+ SpanAttributeWriter<float> radius_attribute =
+ curves_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
+ MutableSpan<float> radii = radius_attribute.span;
MutableSpan<float> tilts = curves.tilt_for_write();
auto create_poly = [&](IndexMask selection) {
@@ -203,7 +202,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
curves.normal_mode_for_write().fill(normal_mode_from_legacy(curve_legacy.twist_mode));
- radius_attribute.save();
+ radius_attribute.finish();
return curves_id;
}
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index baf56c0c350..7f051b683b4 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -8,7 +8,6 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
@@ -315,15 +314,15 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
return result;
}
-static eAttrDomain get_attribute_domain_for_mesh(const MeshComponent &mesh,
+static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_attributes,
const AttributeIDRef &attribute_id)
{
/* Only use a different domain if it is builtin and must only exist on one domain. */
- if (!mesh.attribute_is_builtin(attribute_id)) {
+ if (!mesh_attributes.is_builtin(attribute_id)) {
return ATTR_DOMAIN_POINT;
}
- std::optional<AttributeMetaData> meta_data = mesh.attribute_get_meta_data(attribute_id);
+ std::optional<AttributeMetaData> meta_data = mesh_attributes.lookup_meta_data(attribute_id);
if (!meta_data) {
return ATTR_DOMAIN_POINT;
}
@@ -331,16 +330,17 @@ static eAttrDomain get_attribute_domain_for_mesh(const MeshComponent &mesh,
return meta_data->domain;
}
-static bool should_add_attribute_to_mesh(const CurveComponent &curve_component,
- const MeshComponent &mesh_component,
+static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes,
+ const AttributeAccessor &mesh_attributes,
const AttributeIDRef &id)
{
+
/* The position attribute has special non-generic evaluation. */
if (id.is_named() && id.name() == "position") {
return false;
}
/* Don't propagate built-in curves attributes that are not built-in on meshes. */
- if (curve_component.attribute_is_builtin(id) && !mesh_component.attribute_is_builtin(id)) {
+ if (curve_attributes.is_builtin(id) && !mesh_attributes.is_builtin(id)) {
return false;
}
if (!id.should_be_kept()) {
@@ -667,20 +667,13 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
Vector<std::byte> eval_buffer;
- Curves main_id = {{nullptr}};
- main_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(main);
- CurveComponent main_component;
- main_component.replace(&main_id, GeometryOwnershipType::Editable);
-
- Curves profile_id = {{nullptr}};
- profile_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(profile);
- CurveComponent profile_component;
- profile_component.replace(&profile_id, GeometryOwnershipType::Editable);
+ const AttributeAccessor main_attributes = main.attributes();
+ const AttributeAccessor profile_attributes = profile.attributes();
Span<float> radii = {};
- if (main_component.attribute_exists("radius")) {
+ if (main_attributes.contains("radius")) {
radii = evaluated_attribute_if_necessary(
- main_component.attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 1.0f),
+ main_attributes.lookup_or_default<float>("radius", ATTR_DOMAIN_POINT, 1.0f),
main,
main.curve_type_counts(),
eval_buffer)
@@ -716,24 +709,23 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
});
}
- Set<AttributeIDRef> main_attributes;
+ Set<AttributeIDRef> main_attributes_set;
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ MutableAttributeAccessor mesh_attributes = bke::mesh_attributes_for_write(*mesh);
- main_component.attribute_foreach([&](const AttributeIDRef &id,
- const AttributeMetaData meta_data) {
- if (!should_add_attribute_to_mesh(main_component, mesh_component, id)) {
+ main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) {
return true;
}
- main_attributes.add_new(id);
+ main_attributes_set.add_new(id);
const eAttrDomain src_domain = meta_data.domain;
const eCustomDataType type = meta_data.data_type;
- GVArray src = main_component.attribute_try_get_for_read(id, src_domain, type);
+ GVArray src = main_attributes.lookup(id, src_domain, type);
- const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
- OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
+ const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_attributes, id);
+ GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span(
+ id, dst_domain, type);
if (!dst) {
return true;
}
@@ -744,31 +736,31 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
offsets,
dst_domain,
evaluated_attribute_if_necessary(src, main, main.curve_type_counts(), eval_buffer),
- dst.as_span());
+ dst.span);
}
else if (src_domain == ATTR_DOMAIN_CURVE) {
copy_curve_domain_attribute_to_mesh(
- offsets, offsets.main_indices, dst_domain, src, dst.as_span());
+ offsets, offsets.main_indices, dst_domain, src, dst.span);
}
- dst.save();
+ dst.finish();
return true;
});
- profile_component.attribute_foreach([&](const AttributeIDRef &id,
- const AttributeMetaData meta_data) {
+ profile_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (main_attributes.contains(id)) {
return true;
}
- if (!should_add_attribute_to_mesh(profile_component, mesh_component, id)) {
+ if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) {
return true;
}
const eAttrDomain src_domain = meta_data.domain;
const eCustomDataType type = meta_data.data_type;
- GVArray src = profile_component.attribute_try_get_for_read(id, src_domain, type);
+ GVArray src = profile_attributes.lookup(id, src_domain, type);
- const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
- OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
+ const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_attributes, id);
+ GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span(
+ id, dst_domain, type);
if (!dst) {
return true;
}
@@ -779,14 +771,14 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
offsets,
dst_domain,
evaluated_attribute_if_necessary(src, profile, profile.curve_type_counts(), eval_buffer),
- dst.as_span());
+ dst.span);
}
else if (src_domain == ATTR_DOMAIN_CURVE) {
copy_curve_domain_attribute_to_mesh(
- offsets, offsets.profile_indices, dst_domain, src, dst.as_span());
+ offsets, offsets.profile_indices, dst_domain, src, dst.span);
}
- dst.save();
+ dst.finish();
return true;
});
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index 5725c6043b2..0d899ec7b06 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -5,7 +5,6 @@
#include "DNA_ID_enums.h"
#include "DNA_curve_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_curve.h"
#include "BKE_geometry_set.hh"
@@ -114,24 +113,6 @@ void CurveComponentLegacy::ensure_owns_direct_data()
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponentLegacy::attribute_domain_num(const eAttrDomain domain) const
-{
- if (curve_ == nullptr) {
- return 0;
- }
- if (domain == ATTR_DOMAIN_POINT) {
- int total = 0;
- for (const SplinePtr &spline : curve_->splines()) {
- total += spline->size();
- }
- return total;
- }
- if (domain == ATTR_DOMAIN_CURVE) {
- return curve_->splines().size();
- }
- return 0;
-}
-
namespace blender::bke {
namespace {
@@ -308,9 +289,10 @@ static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArra
} // namespace blender::bke
-GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(const GVArray &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain) const
+static GVArray adapt_curve_attribute_domain(const CurveEval &curve,
+ const GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain)
{
if (!varray) {
return {};
@@ -323,30 +305,15 @@ GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(const GVArray &var
}
if (from_domain == ATTR_DOMAIN_POINT && to_domain == ATTR_DOMAIN_CURVE) {
- return blender::bke::adapt_curve_domain_point_to_spline(*curve_, std::move(varray));
+ return blender::bke::adapt_curve_domain_point_to_spline(curve, std::move(varray));
}
if (from_domain == ATTR_DOMAIN_CURVE && to_domain == ATTR_DOMAIN_POINT) {
- return blender::bke::adapt_curve_domain_spline_to_point(*curve_, std::move(varray));
+ return blender::bke::adapt_curve_domain_spline_to_point(curve, std::move(varray));
}
return {};
}
-static CurveEval *get_curve_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- CurveComponentLegacy &curve_component = static_cast<CurveComponentLegacy &>(component);
- return curve_component.get_for_write();
-}
-
-static const CurveEval *get_curve_from_component_for_read(const GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- const CurveComponentLegacy &curve_component = static_cast<const CurveComponentLegacy &>(
- component);
- return curve_component.get_for_read();
-}
-
/** \} */
namespace blender::bke {
@@ -380,41 +347,41 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const void *owner) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
return as_read_attribute_(*curve);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
+ GAttributeWriter try_get_for_write(void *owner) const final
{
if (writable_ != Writable) {
return {};
}
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
return {as_write_attribute_(*curve), domain_};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- return component.attribute_domain_num(ATTR_DOMAIN_CURVE) != 0;
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
+ return !curve->splines().is_empty();
}
};
@@ -600,12 +567,11 @@ static GVArray varray_from_initializer(const AttributeInit &initializer,
return {};
}
-static bool create_point_attribute(GeometryComponent &component,
+static bool create_point_attribute(CurveEval *curve,
const AttributeIDRef &attribute_id,
const AttributeInit &initializer,
const eCustomDataType data_type)
{
- CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr || curve->splines().size() == 0) {
return false;
}
@@ -638,7 +604,7 @@ static bool create_point_attribute(GeometryComponent &component,
return true;
}
- WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id);
+ GAttributeWriter write_attribute = curve->attributes_for_write().lookup_for_write(attribute_id);
/* We just created the attribute, it should exist. */
BLI_assert(write_attribute);
@@ -647,6 +613,7 @@ static bool create_point_attribute(GeometryComponent &component,
* this theoretically unnecessary materialize step could be removed. */
GVArraySpan source_VArraySpan{source_varray};
write_attribute.varray.set_all(source_VArraySpan.data());
+ write_attribute.finish();
if (initializer.type == AttributeInit::Type::MoveArray) {
MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data);
@@ -655,10 +622,8 @@ static bool create_point_attribute(GeometryComponent &component,
return true;
}
-static bool remove_point_attribute(GeometryComponent &component,
- const AttributeIDRef &attribute_id)
+static bool remove_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id)
{
- CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
return false;
}
@@ -934,14 +899,14 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const override
+ GVArray try_get_for_read(const void *owner) const override
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
- if (!this->exists(component)) {
+ if (!this->exists(owner)) {
return {};
}
@@ -962,14 +927,14 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
return point_data_varray(spans, offsets);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
+ GAttributeWriter try_get_for_write(void *owner) const override
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
- if (!this->exists(component)) {
+ if (!this->exists(owner)) {
return {};
}
@@ -998,25 +963,27 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn};
}
- bool try_delete(GeometryComponent &component) const final
+ bool try_delete(void *owner) const final
{
if (deletable_ == DeletableEnum::NonDeletable) {
return false;
}
- return remove_point_attribute(component, name_);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return remove_point_attribute(curve, name_);
}
- bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final
+ bool try_create(void *owner, const AttributeInit &initializer) const final
{
if (createable_ == CreatableEnum::NonCreatable) {
return false;
}
- return create_point_attribute(component, name_, initializer, CD_PROP_INT32);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return create_point_attribute(curve, name_, initializer, CD_PROP_INT32);
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return false;
}
@@ -1067,9 +1034,9 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
{
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
+ GAttributeWriter try_get_for_write(void *owner) const final
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
@@ -1077,7 +1044,7 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
/* Use the regular position virtual array when there aren't any Bezier splines
* to avoid the overhead of checking the spline type for every point. */
if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
- return BuiltinPointAttributeProvider<float3>::try_get_for_write(component);
+ return BuiltinPointAttributeProvider<float3>::try_get_for_write(owner);
}
auto tag_modified_fn = [curve]() {
@@ -1110,9 +1077,9 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const override
+ GVArray try_get_for_read(const void *owner) const override
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
@@ -1128,9 +1095,9 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
const_cast<CurveEval *>(curve)->splines(), std::move(offsets), is_right_);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
+ GAttributeWriter try_get_for_write(void *owner) const override
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
@@ -1148,26 +1115,27 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
tag_modified_fn};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return false;
}
- return curve->has_spline_with_type(CURVE_TYPE_BEZIER) &&
- component.attribute_domain_num(ATTR_DOMAIN_POINT) != 0;
+ CurveComponentLegacy component;
+ component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
+
+ return curve->has_spline_with_type(CURVE_TYPE_BEZIER) && !curve->splines().is_empty();
}
};
@@ -1190,10 +1158,10 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
CD_MASK_PROP_INT8;
public:
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr || curve->splines().size() == 0) {
return {};
}
@@ -1228,7 +1196,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
}
- ReadAttributeLookup attribute = {};
+ GAttributeReader attribute = {};
Array<int> offsets = curve->control_point_offsets();
attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
using T = decltype(dummy);
@@ -1246,10 +1214,9 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
}
/* This function is almost the same as #try_get_for_read, but without const. */
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr || curve->splines().size() == 0) {
return {};
}
@@ -1284,7 +1251,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
}
- WriteAttributeLookup attribute = {};
+ GAttributeWriter attribute = {};
Array<int> offsets = curve->control_point_offsets();
attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
using T = decltype(dummy);
@@ -1298,12 +1265,13 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return attribute;
}
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
{
- return remove_point_attribute(component, attribute_id);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return remove_point_attribute(curve, attribute_id);
}
- bool try_create(GeometryComponent &component,
+ bool try_create(void *owner,
const AttributeIDRef &attribute_id,
const eAttrDomain domain,
const eCustomDataType data_type,
@@ -1313,13 +1281,13 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
if (domain != ATTR_DOMAIN_POINT) {
return false;
}
- return create_point_attribute(component, attribute_id, initializer, data_type);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return create_point_attribute(curve, attribute_id, initializer, data_type);
}
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr || curve->splines().size() == 0) {
return false;
}
@@ -1371,14 +1339,18 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
make_cyclic_write_attribute);
static CustomDataAccessInfo spline_custom_data_access = {
- [](GeometryComponent &component) -> CustomData * {
- CurveEval *curve = get_curve_from_component_for_write(component);
+ [](void *owner) -> CustomData * {
+ CurveEval *curve = static_cast<CurveEval *>(owner);
return curve ? &curve->attributes.data : nullptr;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ [](const void *owner) -> const CustomData * {
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
return curve ? &curve->attributes.data : nullptr;
},
+ [](const void *owner) -> int {
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
+ return curve->splines().size();
+ },
nullptr};
static CustomDataAttributeProvider spline_custom_data(ATTR_DOMAIN_CURVE,
@@ -1430,12 +1402,62 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
/** \} */
+static AttributeAccessorFunctions get_curve_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_curve();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) -> int {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return curve_eval.total_control_point_num();
+ case ATTR_DOMAIN_CURVE:
+ return curve_eval.splines().size();
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ };
+ fn.adapt_domain = [](const void *owner,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) -> GVArray {
+ if (owner == nullptr) {
+ return {};
+ }
+ const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
+ return adapt_curve_attribute_domain(curve_eval, varray, from_domain, to_domain);
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_curve_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_curve_accessor_functions();
+ return fn;
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *CurveComponentLegacy::get_attribute_providers()
- const
+std::optional<blender::bke::AttributeAccessor> CurveComponentLegacy::attributes() const
+{
+ return blender::bke::AttributeAccessor(curve_, blender::bke::get_curve_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> CurveComponentLegacy::attributes_for_write()
+{
+ return blender::bke::MutableAttributeAccessor(curve_,
+ blender::bke::get_curve_accessor_functions_ref());
+}
+
+blender::bke::MutableAttributeAccessor CurveEval::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_curve();
- return &providers;
+ return blender::bke::MutableAttributeAccessor(this,
+ blender::bke::get_curve_accessor_functions_ref());
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index af058534f68..34c17bedc2c 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -5,7 +5,6 @@
#include "DNA_ID_enums.h"
#include "DNA_curve_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_curve.h"
#include "BKE_curves.hh"
@@ -218,7 +217,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr
const VArray<int8_t> types = curves.curve_types();
if (curves.is_single_type(CURVE_TYPE_POLY)) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain);
}
@@ -229,7 +228,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr
}
if (domain == ATTR_DOMAIN_CURVE) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
@@ -264,7 +263,7 @@ static VArray<float> construct_curve_length_gvarray(const CurveComponent &compon
}
if (domain == ATTR_DOMAIN_POINT) {
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
@@ -307,75 +306,29 @@ bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponent::attribute_domain_num(const eAttrDomain domain) const
+static void tag_component_topology_changed(void *owner)
{
- if (curves_ == nullptr) {
- return 0;
- }
- const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
- curves_->geometry);
- if (domain == ATTR_DOMAIN_POINT) {
- return curves.points_num();
- }
- if (domain == ATTR_DOMAIN_CURVE) {
- return curves.curves_num();
- }
- return 0;
-}
-
-GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain) const
-{
- return blender::bke::CurvesGeometry::wrap(curves_->geometry)
- .adapt_domain(varray, from_domain, to_domain);
-}
-
-static Curves *get_curves_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- CurveComponent &curve_component = static_cast<CurveComponent &>(component);
- return curve_component.get_for_write();
-}
-
-static const Curves *get_curves_from_component_for_read(const GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return curve_component.get_for_read();
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.tag_topology_changed();
}
-static void tag_component_topology_changed(GeometryComponent &component)
+static void tag_component_curve_types_changed(void *owner)
{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed();
- }
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.update_curve_types();
+ curves.tag_topology_changed();
}
-static void tag_component_curve_types_changed(GeometryComponent &component)
+static void tag_component_positions_changed(void *owner)
{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).update_curve_types();
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed();
- }
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.tag_positions_changed();
}
-static void tag_component_positions_changed(GeometryComponent &component)
+static void tag_component_normals_changed(void *owner)
{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_positions_changed();
- }
-}
-
-static void tag_component_normals_changed(GeometryComponent &component)
-{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_normals_changed();
- }
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.tag_normals_changed();
}
/** \} */
@@ -393,34 +346,38 @@ namespace blender::bke {
static ComponentAttributeProviders create_attribute_providers_for_curve()
{
static CustomDataAccessInfo curve_access = {
- [](GeometryComponent &component) -> CustomData * {
- Curves *curves = get_curves_from_component_for_write(component);
- return curves ? &curves->geometry.curve_data : nullptr;
+ [](void *owner) -> CustomData * {
+ CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
+ return &curves.curve_data;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const Curves *curves = get_curves_from_component_for_read(component);
- return curves ? &curves->geometry.curve_data : nullptr;
+ [](const void *owner) -> const CustomData * {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return &curves.curve_data;
},
- [](GeometryComponent &component) {
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers();
- }
+ [](const void *owner) -> int {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return curves.curves_num();
+ },
+ [](void *owner) {
+ CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
+ curves.update_customdata_pointers();
}};
static CustomDataAccessInfo point_access = {
- [](GeometryComponent &component) -> CustomData * {
- Curves *curves = get_curves_from_component_for_write(component);
- return curves ? &curves->geometry.point_data : nullptr;
+ [](void *owner) -> CustomData * {
+ CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
+ return &curves.point_data;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const Curves *curves = get_curves_from_component_for_read(component);
- return curves ? &curves->geometry.point_data : nullptr;
+ [](const void *owner) -> const CustomData * {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return &curves.point_data;
},
- [](GeometryComponent &component) {
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers();
- }
+ [](const void *owner) -> int {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return curves.points_num();
+ },
+ [](void *owner) {
+ CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
+ curves.update_customdata_pointers();
}};
static BuiltinCustomDataLayerProvider position("position",
@@ -626,11 +583,67 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
/** \} */
+static AttributeAccessorFunctions get_curves_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_curve();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return curves.points_num();
+ case ATTR_DOMAIN_CURVE:
+ return curves.curves_num();
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ };
+ fn.adapt_domain = [](const void *owner,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) -> GVArray {
+ if (owner == nullptr) {
+ return {};
+ }
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return curves.adapt_domain(varray, from_domain, to_domain);
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_curves_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_curves_accessor_functions();
+ return fn;
+}
+
+AttributeAccessor CurvesGeometry::attributes() const
+{
+ return AttributeAccessor(this, get_curves_accessor_functions_ref());
+}
+
+MutableAttributeAccessor CurvesGeometry::attributes_for_write()
+{
+ return MutableAttributeAccessor(this, get_curves_accessor_functions_ref());
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
+std::optional<blender::bke::AttributeAccessor> CurveComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(curves_ ? &curves_->geometry : nullptr,
+ blender::bke::get_curves_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> CurveComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_curve();
- return &providers;
+ return blender::bke::MutableAttributeAccessor(curves_ ? &curves_->geometry : nullptr,
+ blender::bke::get_curves_accessor_functions_ref());
}
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 653be03b991..c16311945ba 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -13,7 +13,6 @@
#include "DNA_collection_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
@@ -157,7 +156,7 @@ void InstancesComponent::remove_instances(const IndexMask mask)
dst_attributes.reallocate(mask.size());
src_attributes.foreach_attribute(
- [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
if (!id.should_be_kept()) {
return true;
}
@@ -366,20 +365,12 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const
return almost_unique_ids_;
}
-int InstancesComponent::attribute_domain_num(const eAttrDomain domain) const
-{
- if (domain != ATTR_DOMAIN_INSTANCE) {
- return 0;
- }
- return this->instances_num();
-}
-
-blender::bke::CustomDataAttributes &InstancesComponent::attributes()
+blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes()
{
return this->attributes_;
}
-const blender::bke::CustomDataAttributes &InstancesComponent::attributes() const
+const blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() const
{
return this->attributes_;
}
@@ -404,17 +395,17 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const void *owner) const final
{
- const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
- component);
+ const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
+ owner);
Span<float4x4> transforms = instances_component.instance_transforms();
return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
+ GAttributeWriter try_get_for_write(void *owner) const final
{
- InstancesComponent &instances_component = static_cast<InstancesComponent &>(component);
+ InstancesComponent &instances_component = *static_cast<InstancesComponent *>(owner);
MutableSpan<float4x4> transforms = instances_component.instance_transforms();
return {VMutableArray<float3>::ForDerivedSpan<float4x4,
get_transform_position,
@@ -422,18 +413,17 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
domain_};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &UNUSED(component)) const final
+ bool exists(const void *UNUSED(owner)) const final
{
return true;
}
@@ -443,13 +433,17 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;
static CustomDataAccessInfo instance_custom_data_access = {
- [](GeometryComponent &component) -> CustomData * {
- InstancesComponent &inst = static_cast<InstancesComponent &>(component);
- return &inst.attributes().data;
+ [](void *owner) -> CustomData * {
+ InstancesComponent &inst = *static_cast<InstancesComponent *>(owner);
+ return &inst.instance_attributes().data;
+ },
+ [](const void *owner) -> const CustomData * {
+ const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
+ return &inst.instance_attributes().data;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const InstancesComponent &inst = static_cast<const InstancesComponent &>(component);
- return &inst.attributes().data;
+ [](const void *owner) -> int {
+ const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
+ return inst.instances_num();
},
nullptr};
@@ -476,14 +470,57 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
return ComponentAttributeProviders({&position, &id}, {&instance_custom_data});
}
+
+static AttributeAccessorFunctions get_instances_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_instances();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const InstancesComponent &instances = *static_cast<const InstancesComponent *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_INSTANCE:
+ return instances.instances_num();
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return domain == ATTR_DOMAIN_INSTANCE;
+ };
+ fn.adapt_domain = [](const void *UNUSED(owner),
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) {
+ if (from_domain == to_domain && from_domain == ATTR_DOMAIN_INSTANCE) {
+ return varray;
+ }
+ return blender::GVArray{};
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_instances_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_instances_accessor_functions();
+ return fn;
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *InstancesComponent::get_attribute_providers()
- const
+std::optional<blender::bke::AttributeAccessor> InstancesComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(this,
+ blender::bke::get_instances_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> InstancesComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_instances();
- return &providers;
+ return blender::bke::MutableAttributeAccessor(
+ this, blender::bke::get_instances_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 9e64acf218b..cb36b9b19f7 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -7,7 +7,6 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_deform.h"
#include "BKE_geometry_fields.hh"
@@ -151,7 +150,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
* array and copy the face normal for each of its corners. In this case using the mesh
* component's generic domain interpolation is fine, the data will still be normalized,
* since the face normal is just copied to every corner. */
- return mesh_component.attribute_try_adapt_domain(
+ return mesh_component.attributes()->adapt_domain(
VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}),
ATTR_DOMAIN_FACE,
ATTR_DOMAIN_CORNER);
@@ -169,26 +168,6 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
/** \name Attribute Access
* \{ */
-int MeshComponent::attribute_domain_num(const eAttrDomain domain) const
-{
- if (mesh_ == nullptr) {
- return 0;
- }
- switch (domain) {
- case ATTR_DOMAIN_CORNER:
- return mesh_->totloop;
- case ATTR_DOMAIN_POINT:
- return mesh_->totvert;
- case ATTR_DOMAIN_EDGE:
- return mesh_->totedge;
- case ATTR_DOMAIN_FACE:
- return mesh_->totpoly;
- default:
- break;
- }
- return 0;
-}
-
namespace blender::bke {
template<typename T>
@@ -747,9 +726,10 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
} // namespace blender::bke
-blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain) const
+static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain)
{
if (!varray) {
return {};
@@ -765,11 +745,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G
case ATTR_DOMAIN_CORNER: {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_corner_to_point(mesh, varray);
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_corner_to_face(mesh, varray);
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_corner_to_edge(mesh, varray);
default:
break;
}
@@ -778,11 +758,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G
case ATTR_DOMAIN_POINT: {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_point_to_corner(mesh, varray);
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_point_to_face(mesh, varray);
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_point_to_edge(mesh, varray);
default:
break;
}
@@ -791,11 +771,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G
case ATTR_DOMAIN_FACE: {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_face_to_point(mesh, varray);
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_face_to_corner(mesh, varray);
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_face_to_edge(mesh, varray);
default:
break;
}
@@ -804,11 +784,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G
case ATTR_DOMAIN_EDGE: {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_edge_to_corner(mesh, varray);
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_edge_to_point(mesh, varray);
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, varray);
+ return blender::bke::adapt_mesh_domain_edge_to_face(mesh, varray);
default:
break;
}
@@ -821,20 +801,6 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G
return {};
}
-static Mesh *get_mesh_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- return mesh_component.get_for_write();
-}
-
-static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return mesh_component.get_for_read();
-}
-
namespace blender::bke {
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
@@ -864,9 +830,9 @@ static void set_vertex_position(MVert &vert, float3 position)
copy_v3_v3(vert.co, position);
}
-static void tag_component_positions_changed(GeometryComponent &component)
+static void tag_component_positions_changed(void *owner)
{
- Mesh *mesh = get_mesh_from_component_for_write(component);
+ Mesh *mesh = static_cast<Mesh *>(owner);
if (mesh != nullptr) {
BKE_mesh_tag_coords_changed(mesh);
}
@@ -1001,15 +967,13 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
*/
class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
public:
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
if (!attribute_id.is_named()) {
return {};
}
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
if (mesh == nullptr) {
return {};
}
@@ -1028,15 +992,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
ATTR_DOMAIN_POINT};
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
if (!attribute_id.is_named()) {
return {};
}
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- Mesh *mesh = mesh_component.get_for_write();
+ Mesh *mesh = static_cast<Mesh *>(owner);
if (mesh == nullptr) {
return {};
}
@@ -1060,14 +1021,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
ATTR_DOMAIN_POINT};
}
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
if (!attribute_id.is_named()) {
return false;
}
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- Mesh *mesh = mesh_component.get_for_write();
+ Mesh *mesh = static_cast<Mesh *>(owner);
if (mesh == nullptr) {
return true;
}
@@ -1101,12 +1060,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
return true;
}
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
if (mesh == nullptr) {
return true;
}
@@ -1136,35 +1092,34 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const void *owner) const final
{
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
if (mesh == nullptr || mesh->totpoly == 0) {
return {};
}
return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly});
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final
+ GAttributeWriter try_get_for_write(void *UNUSED(owner)) const final
{
return {};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- return component.attribute_domain_num(ATTR_DOMAIN_FACE) != 0;
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
+ return mesh->totpoly != 0;
}
};
@@ -1174,34 +1129,42 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
*/
static ComponentAttributeProviders create_attribute_providers_for_mesh()
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- if (Mesh *mesh = get_mesh_from_component_for_write(component)) {
- BKE_mesh_update_customdata_pointers(mesh, false);
- }
+ static auto update_custom_data_pointers = [](void *owner) {
+ Mesh *mesh = static_cast<Mesh *>(owner);
+ BKE_mesh_update_customdata_pointers(mesh, false);
};
#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
- [](GeometryComponent &component) -> CustomData * { \
- Mesh *mesh = get_mesh_from_component_for_write(component); \
- return mesh ? &mesh->NAME : nullptr; \
+ [](void *owner) -> CustomData * { \
+ Mesh *mesh = static_cast<Mesh *>(owner); \
+ return &mesh->NAME; \
}
#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
- [](const GeometryComponent &component) -> const CustomData * { \
- const Mesh *mesh = get_mesh_from_component_for_read(component); \
- return mesh ? &mesh->NAME : nullptr; \
+ [](const void *owner) -> const CustomData * { \
+ const Mesh *mesh = static_cast<const Mesh *>(owner); \
+ return &mesh->NAME; \
+ }
+#define MAKE_GET_ELEMENT_NUM_GETTER(NAME) \
+ [](const void *owner) -> int { \
+ const Mesh *mesh = static_cast<const Mesh *>(owner); \
+ return mesh->NAME; \
}
static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata),
MAKE_CONST_CUSTOM_DATA_GETTER(ldata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totloop),
update_custom_data_pointers};
static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata),
MAKE_CONST_CUSTOM_DATA_GETTER(vdata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totvert),
update_custom_data_pointers};
static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
MAKE_CONST_CUSTOM_DATA_GETTER(edata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totedge),
update_custom_data_pointers};
static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totpoly),
update_custom_data_pointers};
#undef MAKE_CONST_CUSTOM_DATA_GETTER
@@ -1297,13 +1260,72 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
&face_custom_data});
}
+static AttributeAccessorFunctions get_mesh_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_mesh();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const Mesh &mesh = *static_cast<const Mesh *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return mesh.totvert;
+ case ATTR_DOMAIN_EDGE:
+ return mesh.totedge;
+ case ATTR_DOMAIN_FACE:
+ return mesh.totpoly;
+ case ATTR_DOMAIN_CORNER:
+ return mesh.totloop;
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
+ };
+ fn.adapt_domain = [](const void *owner,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) -> blender::GVArray {
+ if (owner == nullptr) {
+ return {};
+ }
+ const Mesh &mesh = *static_cast<const Mesh *>(owner);
+ return adapt_mesh_attribute_domain(mesh, varray, from_domain, to_domain);
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_mesh_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_mesh_accessor_functions();
+ return fn;
+}
+
+AttributeAccessor mesh_attributes(const Mesh &mesh)
+{
+ return AttributeAccessor(&mesh, get_mesh_accessor_functions_ref());
+}
+
+MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
+{
+ return MutableAttributeAccessor(&mesh, get_mesh_accessor_functions_ref());
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const
+std::optional<blender::bke::AttributeAccessor> MeshComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(mesh_, blender::bke::get_mesh_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> MeshComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_mesh();
- return &providers;
+ return blender::bke::MutableAttributeAccessor(mesh_,
+ blender::bke::get_mesh_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index facdbed265d..b439a9ba7f8 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -2,7 +2,6 @@
#include "DNA_pointcloud_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_pointcloud.h"
@@ -104,17 +103,6 @@ void PointCloudComponent::ensure_owns_direct_data()
/** \name Attribute Access
* \{ */
-int PointCloudComponent::attribute_domain_num(const eAttrDomain domain) const
-{
- if (pointcloud_ == nullptr) {
- return 0;
- }
- if (domain != ATTR_DOMAIN_POINT) {
- return 0;
- }
- return pointcloud_->totpoint;
-}
-
namespace blender::bke {
/**
@@ -123,23 +111,22 @@ namespace blender::bke {
*/
static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- if (PointCloud *pointcloud = pointcloud_component.get_for_write()) {
- BKE_pointcloud_update_customdata_pointers(pointcloud);
- }
+ static auto update_custom_data_pointers = [](void *owner) {
+ PointCloud *pointcloud = static_cast<PointCloud *>(owner);
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
};
static CustomDataAccessInfo point_access = {
- [](GeometryComponent &component) -> CustomData * {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- PointCloud *pointcloud = pointcloud_component.get_for_write();
- return pointcloud ? &pointcloud->pdata : nullptr;
+ [](void *owner) -> CustomData * {
+ PointCloud *pointcloud = static_cast<PointCloud *>(owner);
+ return &pointcloud->pdata;
+ },
+ [](const void *owner) -> const CustomData * {
+ const PointCloud *pointcloud = static_cast<const PointCloud *>(owner);
+ return &pointcloud->pdata;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
- component);
- const PointCloud *pointcloud = pointcloud_component.get_for_read();
- return pointcloud ? &pointcloud->pdata : nullptr;
+ [](const void *owner) -> int {
+ const PointCloud *pointcloud = static_cast<const PointCloud *>(owner);
+ return pointcloud->totpoint;
},
update_custom_data_pointers};
@@ -180,14 +167,67 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
return ComponentAttributeProviders({&position, &radius, &id}, {&point_custom_data});
}
+static AttributeAccessorFunctions get_pointcloud_accessor_functions()
+{
+ static const ComponentAttributeProviders providers =
+ create_attribute_providers_for_point_cloud();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const PointCloud &pointcloud = *static_cast<const PointCloud *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return pointcloud.totpoint;
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return domain == ATTR_DOMAIN_POINT;
+ };
+ fn.adapt_domain = [](const void *UNUSED(owner),
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) {
+ if (from_domain == to_domain && from_domain == ATTR_DOMAIN_POINT) {
+ return varray;
+ }
+ return blender::GVArray{};
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_pointcloud_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_pointcloud_accessor_functions();
+ return fn;
+}
+
+AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud)
+{
+ return AttributeAccessor(&pointcloud, get_pointcloud_accessor_functions_ref());
+}
+
+MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
+{
+ return MutableAttributeAccessor(&pointcloud, get_pointcloud_accessor_functions_ref());
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers()
- const
+std::optional<blender::bke::AttributeAccessor> PointCloudComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(pointcloud_,
+ blender::bke::get_pointcloud_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> PointCloudComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_point_cloud();
- return &providers;
+ return blender::bke::MutableAttributeAccessor(
+ pointcloud_, blender::bke::get_pointcloud_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 70a39acf620..c6fe8eebc7f 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -7,7 +7,6 @@
#include "BLT_translation.h"
#include "BKE_attribute.h"
-#include "BKE_attribute_access.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
@@ -59,6 +58,27 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
return nullptr;
}
+int GeometryComponent::attribute_domain_size(const eAttrDomain domain) const
+{
+ if (this->is_empty()) {
+ return 0;
+ }
+ const std::optional<blender::bke::AttributeAccessor> attributes = this->attributes();
+ if (attributes.has_value()) {
+ return attributes->domain_size(domain);
+ }
+ return 0;
+}
+
+std::optional<blender::bke::AttributeAccessor> GeometryComponent::attributes() const
+{
+ return std::nullopt;
+};
+std::optional<blender::bke::MutableAttributeAccessor> GeometryComponent::attributes_for_write()
+{
+ return std::nullopt;
+}
+
void GeometryComponent::user_add() const
{
users_.fetch_add(1);
@@ -444,11 +464,14 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_
continue;
}
const GeometryComponent &component = *this->get_component_for_read(component_type);
- component.attribute_foreach(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- callback(attribute_id, meta_data, component);
- return true;
- });
+ const std::optional<AttributeAccessor> attributes = component.attributes();
+ if (attributes.has_value()) {
+ attributes->for_all(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ callback(attribute_id, meta_data, component);
+ return true;
+ });
+ }
}
if (include_instances && this->has_instances()) {
const InstancesComponent &instances = *this->get_component_for_read<InstancesComponent>();
@@ -462,7 +485,7 @@ void GeometrySet::gather_attributes_for_propagation(
const Span<GeometryComponentType> component_types,
const GeometryComponentType dst_component_type,
bool include_instances,
- blender::Map<blender::bke::AttributeIDRef, AttributeKind> &r_attributes) const
+ blender::Map<blender::bke::AttributeIDRef, blender::bke::AttributeKind> &r_attributes) const
{
using namespace blender;
using namespace blender::bke;
@@ -475,8 +498,8 @@ void GeometrySet::gather_attributes_for_propagation(
[&](const AttributeIDRef &attribute_id,
const AttributeMetaData &meta_data,
const GeometryComponent &component) {
- if (component.attribute_is_builtin(attribute_id)) {
- if (!dummy_component->attribute_is_builtin(attribute_id)) {
+ if (component.attributes()->is_builtin(attribute_id)) {
+ if (!dummy_component->attributes()->is_builtin(attribute_id)) {
/* Don't propagate built-in attributes that are not built-in on the destination
* component. */
return;
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 9cb3e684667..7ebb3e25fd4 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1209,9 +1209,7 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr, &CD_MASK_MESH, true);
/* Anonymous attributes shouldn't exist on original data. */
- MeshComponent component;
- component.replace(mesh_in_bmain, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ blender::bke::mesh_attributes_for_write(*mesh_in_bmain).remove_anonymous();
/* User-count is required because so far mesh was in a limbo, where library management does
* not perform any user management (i.e. copy of a mesh will not increase users of materials). */
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
index b792c5c98b9..dd09a3d6917 100644
--- a/source/blender/blenkernel/intern/mesh_sample.cc
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_mesh_runtime.h"
@@ -253,12 +252,12 @@ void MeshAttributeInterpolator::sample_data(const GVArray &src,
}
}
-void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute,
- OutputAttribute &dst_attribute,
+void MeshAttributeInterpolator::sample_attribute(const GAttributeReader &src_attribute,
+ GSpanAttributeWriter &dst_attribute,
eAttributeMapMode mode)
{
if (src_attribute && dst_attribute) {
- this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span());
+ this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.span);
}
}
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index e8c7aff75d1..a674bf7800a 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -6,7 +6,6 @@
#include "BLI_task.hh"
#include "BLI_timeit.hh"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_spline.hh"
@@ -21,6 +20,7 @@ using blender::Span;
using blender::VArray;
using blender::attribute_math::convert_to_static_type;
using blender::bke::AttributeIDRef;
+using blender::bke::AttributeMetaData;
CurveType Spline::type() const
{
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index 2460482fbbf..d5f188402d6 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -357,20 +357,20 @@ static void curves_batch_ensure_attribute(const Curves &curves,
request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num :
curves.geometry.curve_num);
- CurveComponent component;
- component.replace(const_cast<Curves *>(&curves), GeometryOwnershipType::ReadOnly);
+ const blender::bke::AttributeAccessor attributes =
+ blender::bke::CurvesGeometry::wrap(curves.geometry).attributes();
/* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done
* by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following
* the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a
* similar texture state swizzle to map the attribute correctly as for volume attributes, so we
* can control the conversion ourselves. */
- blender::VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ blender::VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>(
request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f});
MutableSpan<ColorGeometry4f> vbo_span{
static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(attr_vbo)),
- component.attribute_domain_num(request.domain)};
+ attributes.domain_size(request.domain)};
attribute.materialize(vbo_span);
@@ -629,9 +629,10 @@ static void request_attribute(Curves &curves, const char *name)
DRW_Attributes attributes{};
- CurveComponent component;
- component.replace(&curves, GeometryOwnershipType::ReadOnly);
- std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(name);
+ blender::bke::CurvesGeometry &curves_geometry = blender::bke::CurvesGeometry::wrap(
+ curves.geometry);
+ std::optional<blender::bke::AttributeMetaData> meta_data =
+ curves_geometry.attributes().lookup_meta_data(name);
if (!meta_data) {
return;
}
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index 246f7c843ba..233af08c363 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -336,9 +336,7 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
curves_id.geometry);
if (curves.curves_num() >= 1) {
- CurveComponent curves_component;
- curves_component.replace(&curves_id, GeometryOwnershipType::ReadOnly);
- blender::VArray<float> radii = curves_component.attribute_get_for_read(
+ blender::VArray<float> radii = curves.attributes().lookup_or_default(
"radius", ATTR_DOMAIN_POINT, 0.005f);
const blender::IndexRange first_curve_points = curves.points_for_curve(0);
const float first_radius = radii[first_curve_points.first()];
diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc
index 49e21d00195..a4492a1d516 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -533,9 +533,9 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
VArraySpan<float2> surface_uv_map;
if (curves_id.surface_uv_map != nullptr) {
- surface_uv_map = surface_mesh_component
- .attribute_try_get_for_read(
- curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
+ const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(surface_mesh);
+ surface_uv_map = surface_attributes
+ .lookup(curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
.typed<float2>();
}
@@ -756,21 +756,20 @@ static int curves_set_selection_domain_exec(bContext *C, wmOperator *op)
curves_id->selection_domain = domain;
curves_id->flag |= CV_SCULPT_SELECTION_ENABLED;
- CurveComponent component;
- component.replace(curves_id, GeometryOwnershipType::Editable);
CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) {
VArray<float> curve_selection = curves.adapt_domain(
curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
curve_selection.materialize(curves.selection_curve_float_for_write());
- component.attribute_try_delete(".selection_point_float");
+ attributes.remove(".selection_point_float");
}
else if (old_domain == ATTR_DOMAIN_CURVE && domain == ATTR_DOMAIN_POINT) {
VArray<float> point_selection = curves.adapt_domain(
curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
point_selection.materialize(curves.selection_point_float_for_write());
- component.attribute_try_delete(".selection_curve_float");
+ attributes.remove(".selection_curve_float");
}
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
@@ -900,15 +899,14 @@ static int select_all_exec(bContext *C, wmOperator *op)
}
for (Curves *curves_id : unique_curves) {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
if (action == SEL_SELECT) {
/* As an optimization, just remove the selection attributes when everything is selected. */
- CurveComponent component;
- component.replace(curves_id, GeometryOwnershipType::Editable);
- component.attribute_try_delete(".selection_point_float");
- component.attribute_try_delete(".selection_curve_float");
+ bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
+ attributes.remove(".selection_point_float");
+ attributes.remove(".selection_curve_float");
}
else {
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
curves.selection_point_float_for_write() :
curves.selection_curve_float_for_write();
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index c7e782b7b89..4cf14334ac7 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -282,8 +282,7 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
RNA_enum_get(op->ptr, "mode"));
Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
/* General conversion steps are always the same:
* 1. Convert old data to right domain and data type.
@@ -301,33 +300,33 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type);
+ GVArray src_varray = attributes.lookup_or_default(name, dst_domain, dst_type);
const CPPType &cpp_type = src_varray.type();
void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
src_varray.materialize_to_uninitialized(new_data);
- mesh_component.attribute_try_delete(name);
- mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data));
+ attributes.remove(name);
+ attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMove(new_data));
break;
}
case ConvertAttributeMode::UVMap: {
MLoopUV *dst_uvs = static_cast<MLoopUV *>(
MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__));
- VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>(
+ VArray<float2> src_varray = attributes.lookup_or_default<float2>(
name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
for (const int i : IndexRange(mesh->totloop)) {
copy_v2_v2(dst_uvs[i].uv, src_varray[i]);
}
- mesh_component.attribute_try_delete(name);
+ attributes.remove(name);
CustomData_add_layer_named(
&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str());
break;
}
case ConvertAttributeMode::VertexGroup: {
Array<float> src_weights(mesh->totvert);
- VArray<float> src_varray = mesh_component.attribute_get_for_read<float>(
+ VArray<float> src_varray = attributes.lookup_or_default<float>(
name, ATTR_DOMAIN_POINT, 0.0f);
src_varray.materialize(src_weights);
- mesh_component.attribute_try_delete(name);
+ attributes.remove(name);
bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str());
const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup);
@@ -652,15 +651,16 @@ bool ED_geometry_attribute_convert(Mesh *mesh,
return false;
}
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- GVArray src_varray = mesh_component.attribute_get_for_read(name, new_domain, new_type);
+ blender::bke::MutableAttributeAccessor attributes = blender::bke::mesh_attributes_for_write(
+ *mesh);
+
+ GVArray src_varray = attributes.lookup_or_default(name, new_domain, new_type);
const CPPType &cpp_type = src_varray.type();
void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
src_varray.materialize_to_uninitialized(new_data);
- mesh_component.attribute_try_delete(name);
- mesh_component.attribute_try_create(name, new_domain, new_type, AttributeInitMove(new_data));
+ attributes.remove(name);
+ attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMove(new_data));
int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
if (*active_index > 0) {
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index a2c08109ec0..66e76addd6f 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -3177,9 +3177,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
}
/* Anonymous attributes shouldn't be available on the applied geometry. */
- MeshComponent component;
- component.replace(new_mesh, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ blender::bke::mesh_attributes_for_write(*new_mesh).remove_anonymous();
BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
}
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 202c6d96a47..69edd00ae24 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -757,9 +757,7 @@ static bool modifier_apply_obdata(
BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true);
/* Anonymous attributes shouldn't be available on the applied geometry. */
- MeshComponent component;
- component.replace(me, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ blender::bke::mesh_attributes_for_write(*me).remove_anonymous();
if (md_eval->type == eModifierType_Multires) {
multires_customdata_delete(me);
@@ -828,11 +826,12 @@ static bool modifier_apply_obdata(
BKE_report(reports, RPT_ERROR, "Evaluated geometry from modifier does not contain curves");
return false;
}
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
Curves &curves_eval = *geometry_set.get_curves_for_write();
/* Anonymous attributes shouldn't be available on the applied geometry. */
- component.attributes_remove_anonymous();
+ blender::bke::CurvesGeometry::wrap(curves_eval.geometry)
+ .attributes_for_write()
+ .remove_anonymous();
/* If the modifier's output is a different curves data-block, copy the relevant information to
* the original. */
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index 401550b3b3a..26145a386f5 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -176,12 +176,9 @@ struct AddOperationExecutor {
/* Find UV map. */
VArraySpan<float2> surface_uv_map;
if (curves_id_->surface_uv_map != nullptr) {
- MeshComponent surface_component;
- surface_component.replace(surface_, GeometryOwnershipType::ReadOnly);
- surface_uv_map = surface_component
- .attribute_try_get_for_read(curves_id_->surface_uv_map,
- ATTR_DOMAIN_CORNER)
- .typed<float2>();
+ const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_);
+ surface_uv_map = surface_attributes.lookup<float2>(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
}
/* Find normals. */
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
index 826b0611e81..e211a568705 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
@@ -64,7 +64,6 @@ struct DensityAddOperationExecutor {
Mesh *surface_ = nullptr;
Span<MLoopTri> surface_looptris_;
Span<float3> corner_normals_su_;
- VArraySpan<float2> surface_uv_map_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
@@ -228,12 +227,9 @@ struct DensityAddOperationExecutor {
/* Find UV map. */
VArraySpan<float2> surface_uv_map;
if (curves_id_->surface_uv_map != nullptr) {
- MeshComponent surface_component;
- surface_component.replace(surface_, GeometryOwnershipType::ReadOnly);
- surface_uv_map = surface_component
- .attribute_try_get_for_read(curves_id_->surface_uv_map,
- ATTR_DOMAIN_CORNER)
- .typed<float2>();
+ bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_);
+ surface_uv_map = surface_attributes.lookup<float2>(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
}
/* Find normals. */
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc
index dedc880988d..aabe6fd93e4 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc
@@ -148,12 +148,9 @@ struct SlideOperationExecutor {
BKE_mesh_runtime_looptri_len(surface_)};
if (curves_id_->surface_uv_map != nullptr) {
- MeshComponent surface_component;
- surface_component.replace(surface_, GeometryOwnershipType::ReadOnly);
- surface_uv_map_ = surface_component
- .attribute_try_get_for_read(curves_id_->surface_uv_map,
- ATTR_DOMAIN_CORNER)
- .typed<float2>();
+ const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_);
+ surface_uv_map_ = surface_attributes.lookup<float2>(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
}
if (stroke_extension.is_first) {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
index 50f8854d90f..8b726c7b942 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
@@ -92,11 +92,9 @@ static bool vertex_paint_from_weight(Object *ob)
return false;
}
- MeshComponent component;
- component.replace(me, GeometryOwnershipType::Editable);
+ bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*me);
- bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write(
- active_color_layer->name);
+ bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
if (!color_attribute) {
BLI_assert_unreachable();
return false;
@@ -104,7 +102,7 @@ static bool vertex_paint_from_weight(Object *ob)
/* Retrieve the vertex group with the domain and type of the existing color
* attribute, in order to let the attribute API handle both conversions. */
- const GVArray vertex_group = component.attribute_get_for_read(
+ const GVArray vertex_group = attributes.lookup(
deform_group->name,
ATTR_DOMAIN_POINT,
bke::cpp_type_to_custom_data_type(color_attribute.varray.type()));
@@ -113,14 +111,11 @@ static bool vertex_paint_from_weight(Object *ob)
return false;
}
- GVArraySpan interpolated{component.attribute_try_adapt_domain(
- vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)};
+ GVArraySpan interpolated{
+ attributes.adapt_domain(vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)};
color_attribute.varray.set_all(interpolated.data());
-
- if (color_attribute.tag_modified_fn) {
- color_attribute.tag_modified_fn();
- }
+ color_attribute.finish();
tag_object_after_update(ob);
return true;
@@ -167,29 +162,28 @@ static IndexMask get_selected_indices(const Mesh &mesh,
Span<MVert> verts(mesh.mvert, mesh.totvert);
Span<MPoly> faces(mesh.mpoly, mesh.totpoly);
- MeshComponent component;
- component.replace(&const_cast<Mesh &>(mesh), GeometryOwnershipType::ReadOnly);
+ bke::AttributeAccessor attributes = bke::mesh_attributes(mesh);
if (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) {
- const VArray<bool> selection = component.attribute_try_adapt_domain(
+ const VArray<bool> selection = attributes.adapt_domain(
VArray<bool>::ForFunc(faces.size(),
[&](const int i) { return faces[i].flag & ME_FACE_SEL; }),
ATTR_DOMAIN_FACE,
domain);
return index_mask_ops::find_indices_from_virtual_array(
- IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices);
+ IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
}
if (mesh.editflag & ME_EDIT_PAINT_VERT_SEL) {
- const VArray<bool> selection = component.attribute_try_adapt_domain(
+ const VArray<bool> selection = attributes.adapt_domain(
VArray<bool>::ForFunc(verts.size(), [&](const int i) { return verts[i].flag & SELECT; }),
ATTR_DOMAIN_POINT,
domain);
return index_mask_ops::find_indices_from_virtual_array(
- IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices);
+ IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
}
- return IndexMask(component.attribute_domain_num(domain));
+ return IndexMask(attributes.domain_size(domain));
}
static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask selection)
@@ -202,17 +196,15 @@ static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask sele
return;
}
- MeshComponent component;
- component.replace(&mesh, GeometryOwnershipType::Editable);
+ bke::AttributeAccessor attributes = bke::mesh_attributes(mesh);
- if (component.attribute_get_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) {
+ if (attributes.lookup_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) {
return;
}
- GVArray color_attribute_point = component.attribute_try_get_for_read(active_color_layer->name,
- ATTR_DOMAIN_POINT);
+ GVArray color_attribute_point = attributes.lookup(active_color_layer->name, ATTR_DOMAIN_POINT);
- GVArray color_attribute_corner = component.attribute_try_adapt_domain(
+ GVArray color_attribute_corner = attributes.adapt_domain(
color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER);
color_attribute_corner.materialize(selection, active_color_layer->data);
@@ -278,11 +270,9 @@ static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
return false;
}
- MeshComponent component;
- component.replace(&mesh, GeometryOwnershipType::Editable);
+ bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
- bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write(
- active_color_layer->name);
+ bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
if (!color_attribute) {
BLI_assert_unreachable();
return false;
@@ -310,6 +300,8 @@ static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
});
});
+ color_attribute.finish();
+
DEG_id_tag_update(&mesh.id, 0);
return true;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 6be3a65cc1b..2a87c51da5d 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -3,6 +3,7 @@
#include "BLI_index_mask_ops.hh"
#include "BLI_virtual_array.hh"
+#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_geometry_fields.hh"
@@ -65,7 +66,12 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
void GeometryDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
- if (component_->attribute_domain_num(domain_) == 0) {
+ if (!component_->attributes().has_value()) {
+ return;
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+
+ if (attributes.domain_size(domain_) == 0) {
return;
}
@@ -74,8 +80,9 @@ void GeometryDataSource::foreach_default_column_ids(
}
extra_columns_.foreach_default_column_ids(fn);
- component_->attribute_foreach(
- [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+
+ attributes.for_all(
+ [&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) {
if (meta_data.domain != domain_) {
return true;
}
@@ -114,7 +121,11 @@ void GeometryDataSource::foreach_default_column_ids(
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- const int domain_num = component_->attribute_domain_num(domain_);
+ if (!component_->attributes().has_value()) {
+ return {};
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+ const int domain_num = attributes.domain_size(domain_);
if (domain_num == 0) {
return {};
}
@@ -200,7 +211,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
}
- bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
+ bke::GAttributeReader attribute = attributes.lookup(column_id.name);
if (!attribute) {
return {};
}
@@ -214,7 +225,11 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
int GeometryDataSource::tot_rows() const
{
- return component_->attribute_domain_num(domain_);
+ if (!component_->attributes().has_value()) {
+ return {};
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+ return attributes.domain_size(domain_);
}
/**
@@ -253,7 +268,7 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) c
const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
- VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool> selection = mesh_component->attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm, orig_indices](int vertex_index) -> bool {
const int i_orig = orig_indices[vertex_index];
@@ -273,7 +288,7 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) c
if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
- VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool> selection = mesh_component->attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm](int vertex_index) -> bool {
BMVert *vert = bm->vtable[vertex_index];
@@ -511,7 +526,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
std::make_unique<GeometryComponentCacheKey>(component));
const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
- const int domain_num = component.attribute_domain_num(domain);
+ const int domain_num = component.attributes()->domain_size(domain);
for (const auto item : fields_to_show.items()) {
const StringRef name = item.key;
const GField &field = item.value;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index ee22f4173ab..aa9b867264a 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -194,7 +194,7 @@ std::optional<int> GeometryDataSetTreeViewItem::count() const
}
if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
- return component->attribute_domain_num(*domain_);
+ return component->attribute_domain_size(*domain_);
}
return 0;
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();
}
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index cb95c561547..731587bfcea 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -254,9 +254,8 @@ void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
}
if (write_colors && (colors_layer != nullptr)) {
- MeshComponent component;
- component.replace(mesh, GeometryOwnershipType::ReadOnly);
- VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh);
+ const VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>(
colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
BLI_assert(tot_count == attribute.size());
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index a63a89e076b..885d2f901ec 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -109,7 +109,7 @@ using blender::Span;
using blender::StringRef;
using blender::StringRefNull;
using blender::Vector;
-using blender::bke::OutputAttribute;
+using blender::bke::AttributeMetaData;
using blender::fn::Field;
using blender::fn::GField;
using blender::fn::ValueOrField;
@@ -999,22 +999,27 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
continue;
}
const GeometryComponent &component = *geometry.get_component_for_read(component_type);
+ if (component.is_empty()) {
+ continue;
+ }
+ const blender::bke::AttributeAccessor attributes = *component.attributes();
for (const auto item : outputs_by_domain.items()) {
const eAttrDomain domain = item.key;
const Span<OutputAttributeInfo> outputs_info = item.value;
- if (!component.attribute_domain_supported(domain)) {
+ if (!attributes.domain_supported(domain)) {
continue;
}
- const int domain_num = component.attribute_domain_num(domain);
+ const int domain_size = attributes.domain_size(domain);
blender::bke::GeometryComponentFieldContext field_context{component, domain};
- blender::fn::FieldEvaluator field_evaluator{field_context, domain_num};
+ blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
for (const OutputAttributeInfo &output_info : outputs_info) {
const CPPType &type = output_info.field.cpp_type();
OutputAttributeToStore store{
component_type,
domain,
output_info.name,
- GMutableSpan{type, MEM_malloc_arrayN(domain_num, type.size(), __func__), domain_num}};
+ GMutableSpan{
+ type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
field_evaluator.add_with_destination(output_info.field, store.data);
attributes_to_store.append(store);
}
@@ -1029,33 +1034,33 @@ static void store_computed_output_attributes(
{
for (const OutputAttributeToStore &store : attributes_to_store) {
GeometryComponent &component = geometry.get_component_for_write(store.component_type);
+ blender::bke::MutableAttributeAccessor attributes = *component.attributes_for_write();
+
const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(
store.data.type());
- const std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(
- store.name);
+ const std::optional<AttributeMetaData> meta_data = attributes.lookup_meta_data(store.name);
/* Attempt to remove the attribute if it already exists but the domain and type don't match.
* Removing the attribute won't succeed if it is built in and non-removable. */
if (meta_data.has_value() &&
(meta_data->domain != store.domain || meta_data->data_type != data_type)) {
- component.attribute_try_delete(store.name);
+ attributes.remove(store.name);
}
/* Try to create the attribute reusing the stored buffer. This will only succeed if the
* attribute didn't exist before, or if it existed but was removed above. */
- if (component.attribute_try_create(
- store.name,
- store.domain,
- blender::bke::cpp_type_to_custom_data_type(store.data.type()),
- AttributeInitMove(store.data.data()))) {
+ if (attributes.add(store.name,
+ store.domain,
+ blender::bke::cpp_type_to_custom_data_type(store.data.type()),
+ blender::bke::AttributeInitMove(store.data.data()))) {
continue;
}
- OutputAttribute attribute = component.attribute_try_get_for_output_only(
+ blender::bke::GAttributeWriter attribute = attributes.lookup_or_add_for_write(
store.name, store.domain, data_type);
if (attribute) {
- attribute.varray().set_all(store.data.data());
- attribute.save();
+ attribute.varray.set_all(store.data.data());
+ attribute.finish();
}
/* We were unable to reuse the data, so it must be destructed and freed. */
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index c2dd1cd3ab5..0d5ba6cf5db 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -5,7 +5,6 @@
#include "FN_field.hh"
#include "FN_multi_function_builder.hh"
-#include "BKE_attribute_access.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
@@ -20,16 +19,22 @@ struct ModifierData;
namespace blender::nodes {
using bke::AnonymousAttributeFieldInput;
+using bke::AttributeAccessor;
using bke::AttributeFieldInput;
using bke::AttributeIDRef;
+using bke::AttributeKind;
+using bke::AttributeMetaData;
+using bke::AttributeReader;
+using bke::AttributeWriter;
+using bke::GAttributeReader;
+using bke::GAttributeWriter;
using bke::GeometryComponentFieldContext;
using bke::GeometryFieldInput;
-using bke::OutputAttribute;
-using bke::OutputAttribute_Typed;
-using bke::ReadAttributeLookup;
+using bke::GSpanAttributeWriter;
+using bke::MutableAttributeAccessor;
+using bke::SpanAttributeWriter;
using bke::StrongAnonymousAttributeID;
using bke::WeakAnonymousAttributeID;
-using bke::WriteAttributeLookup;
using fn::Field;
using fn::FieldContext;
using fn::FieldEvaluator;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
index be7b3446125..58fbfb5a000 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -217,16 +217,20 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
IndexMask UNUSED(mask)) const final
{
const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_num = component.attribute_domain_num(field_context.domain());
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+ if (domain_size == 0) {
+ return {};
+ }
+ const AttributeAccessor attributes = *component.attributes();
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.add(input_);
evaluator.add(group_index_);
evaluator.evaluate();
const VArray<T> values = evaluator.get_evaluated<T>(0);
const VArray<int> group_indices = evaluator.get_evaluated<int>(1);
- Array<T> accumulations_out(domain_num);
+ Array<T> accumulations_out(domain_size);
if (group_indices.is_single()) {
T accumulation = T();
@@ -261,7 +265,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
}
}
- return component.attribute_try_adapt_domain<T>(
+ return attributes.adapt_domain<T>(
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
}
@@ -303,9 +307,13 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
IndexMask UNUSED(mask)) const final
{
const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_num = component.attribute_domain_num(field_context.domain());
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+ if (domain_size == 0) {
+ return {};
+ }
+ const AttributeAccessor attributes = *component.attributes();
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.add(input_);
evaluator.add(group_index_);
evaluator.evaluate();
@@ -317,10 +325,10 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
for (const int i : values.index_range()) {
accumulation = values[i] + accumulation;
}
- return VArray<T>::ForSingle(accumulation, domain_num);
+ return VArray<T>::ForSingle(accumulation, domain_size);
}
- Array<T> accumulations_out(domain_num);
+ Array<T> accumulations_out(domain_size);
Map<int, T> accumulations;
for (const int i : values.index_range()) {
T &value = accumulations.lookup_or_add_default(group_indices[i]);
@@ -330,7 +338,7 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
accumulations_out[i] = accumulations.lookup(group_indices[i]);
}
- return component.attribute_try_adapt_domain<T>(
+ return attributes.adapt_domain<T>(
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
}
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 496fb081d6b..9f317075bb5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -111,19 +111,26 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
const eAttrDomain domain,
const GField &field)
{
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
+ return;
+ }
GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- const IndexMask mask{IndexMask(domain_num)};
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ const IndexMask mask{IndexMask(domain_size)};
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
- OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
+ GAttributeWriter output_attribute = attributes.lookup_or_add_for_write(
attribute_id, domain, data_type);
+ if (!output_attribute) {
+ return;
+ }
fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, output_attribute.varray());
+ evaluator.add_with_destination(field, output_attribute.varray);
evaluator.evaluate();
- output_attribute.save();
+ output_attribute.finish();
}
static StringRefNull identifier_suffix(eCustomDataType data_type)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
index 8ab0eb678e7..7e4904a7a6a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -72,11 +72,11 @@ static void node_geo_exec(GeoNodeExecParams params)
case GEO_COMPONENT_TYPE_MESH: {
if (geometry_set.has_mesh()) {
const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT));
- params.set_output("Edge Count", component->attribute_domain_num(ATTR_DOMAIN_EDGE));
- params.set_output("Face Count", component->attribute_domain_num(ATTR_DOMAIN_FACE));
- params.set_output("Face Corner Count",
- component->attribute_domain_num(ATTR_DOMAIN_CORNER));
+ const AttributeAccessor attributes = *component->attributes();
+ params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Edge Count", attributes.domain_size(ATTR_DOMAIN_EDGE));
+ params.set_output("Face Count", attributes.domain_size(ATTR_DOMAIN_FACE));
+ params.set_output("Face Corner Count", attributes.domain_size(ATTR_DOMAIN_CORNER));
}
else {
params.set_default_remaining_outputs();
@@ -86,8 +86,9 @@ static void node_geo_exec(GeoNodeExecParams params)
case GEO_COMPONENT_TYPE_CURVE: {
if (geometry_set.has_curves()) {
const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
- params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT));
- params.set_output("Spline Count", component->attribute_domain_num(ATTR_DOMAIN_CURVE));
+ const AttributeAccessor attributes = *component->attributes();
+ params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Spline Count", attributes.domain_size(ATTR_DOMAIN_CURVE));
}
else {
params.set_default_remaining_outputs();
@@ -98,7 +99,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_pointcloud()) {
const PointCloudComponent *component =
geometry_set.get_component_for_read<PointCloudComponent>();
- params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT));
+ params.set_output("Point Count", component->attributes()->domain_size(ATTR_DOMAIN_POINT));
}
else {
params.set_default_remaining_outputs();
@@ -109,7 +110,8 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_instances()) {
const InstancesComponent *component =
geometry_set.get_component_for_read<InstancesComponent>();
- params.set_output("Instance Count", component->attribute_domain_num(ATTR_DOMAIN_INSTANCE));
+ params.set_output("Instance Count",
+ component->attributes()->domain_size(ATTR_DOMAIN_INSTANCE));
}
else {
params.set_default_remaining_outputs();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index 08e72dae8f6..34e28e50c81 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -195,9 +195,13 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<float> input_field = params.get_input<Field<float>>("Attribute");
Vector<float> data;
for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
+ const std::optional<AttributeAccessor> attributes = component->attributes();
+ if (!attributes.has_value()) {
+ continue;
+ }
+ if (attributes->domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
- const int domain_num = component->attribute_domain_num(domain);
+ const int domain_num = attributes->domain_size(domain);
fn::FieldEvaluator data_evaluator{field_context, domain_num};
data_evaluator.add(input_field);
@@ -273,9 +277,13 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<float3> input_field = params.get_input<Field<float3>>("Attribute_001");
Vector<float3> data;
for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
+ const std::optional<AttributeAccessor> attributes = component->attributes();
+ if (!attributes.has_value()) {
+ continue;
+ }
+ if (attributes->domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
- const int domain_num = component->attribute_domain_num(domain);
+ const int domain_num = attributes->domain_size(domain);
fn::FieldEvaluator data_evaluator{field_context, domain_num};
data_evaluator.add(input_field);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 81cce1fc5da..69938f3e447 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -154,17 +154,15 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Store intersecting edges in attribute. */
if (attribute_outputs.intersecting_edges_id) {
- MeshComponent mesh_component;
- mesh_component.replace(result, GeometryOwnershipType::Editable);
- OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*result);
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE);
- MutableSpan<bool> selection = attribute.as_span();
- selection.fill(false);
+
+ selection.span.fill(false);
for (const int i : intersecting_edges) {
- selection[i] = true;
+ selection.span[i] = true;
}
-
- attribute.save();
+ selection.finish();
params.set_output(
"Intersecting Edges",
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 045206d04cd..489b618b8be 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -143,7 +143,8 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
if (geometry_set.has_mesh()) {
count++;
const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- total_num += component->attribute_domain_num(ATTR_DOMAIN_POINT);
+ const Mesh *mesh = component->get_for_read();
+ total_num += mesh->totvert;
}
if (geometry_set.has_pointcloud()) {
@@ -151,10 +152,9 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
span_count++;
const PointCloudComponent *component =
geometry_set.get_component_for_read<PointCloudComponent>();
- VArray<float3> varray = component->attribute_get_for_read<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
- total_num += varray.size();
- positions_span = varray.get_internal_span();
+ const PointCloud *pointcloud = component->get_for_read();
+ positions_span = {reinterpret_cast<const float3 *>(pointcloud->co), pointcloud->totpoint};
+ total_num += pointcloud->totpoint;
}
if (geometry_set.has_curves()) {
@@ -181,8 +181,8 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
if (geometry_set.has_mesh()) {
const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- VArray<float3> varray = component->attribute_get_for_read<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+ const VArray<float3> varray = component->attributes()->lookup<float3>("position",
+ ATTR_DOMAIN_POINT);
varray.materialize(positions.as_mutable_span().slice(offset, varray.size()));
offset += varray.size();
}
@@ -190,8 +190,8 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
if (geometry_set.has_pointcloud()) {
const PointCloudComponent *component =
geometry_set.get_component_for_read<PointCloudComponent>();
- VArray<float3> varray = component->attribute_get_for_read<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+ const VArray<float3> varray = component->attributes()->lookup<float3>("position",
+ ATTR_DOMAIN_POINT);
varray.materialize(positions.as_mutable_span().slice(offset, varray.size()));
offset += varray.size();
}
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 fb8a488ddae..e200350dc18 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -581,8 +581,8 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- fn::FieldEvaluator field_evaluator{field_context, domain_num};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ fn::FieldEvaluator field_evaluator{field_context, domain_size};
field_evaluator.add(radius_field);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 91ba5f2845f..286d9993d0e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -61,13 +61,13 @@ static Curves *create_star_curve(const float inner_radius,
static void create_selection_output(CurveComponent &component,
StrongAnonymousAttributeID &r_attribute)
{
- OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>(
- r_attribute.get(), ATTR_DOMAIN_POINT);
- MutableSpan<bool> selection = attribute.as_span();
- for (int i : selection.index_range()) {
- selection[i] = i % 2 == 0;
+ SpanAttributeWriter<bool> selection =
+ component.attributes_for_write()->lookup_or_add_for_write_only_span<bool>(r_attribute.get(),
+ ATTR_DOMAIN_POINT);
+ for (int i : selection.span.index_range()) {
+ selection.span[i] = i % 2 == 0;
}
- attribute.save();
+ selection.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 64a174df599..de29735bd2d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -27,9 +27,9 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
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 469d8d8d13b..f7ba724c377 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
@@ -98,8 +98,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
has_curves = true;
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- if (!component.attribute_exists("handle_type_left") ||
- !component.attribute_exists("handle_type_right")) {
+ const AttributeAccessor attributes = *component.attributes();
+ if (!attributes.contains("handle_type_left") || !attributes.contains("handle_type_right")) {
return;
}
has_bezier = true;
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 7d83b4b3ecb..6c4fb2e0855 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
@@ -126,19 +126,18 @@ static GMutableSpan ensure_point_attribute(PointCloudComponent &points,
const AttributeIDRef &attribute_id,
const eCustomDataType data_type)
{
- points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
- WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
- BLI_assert(attribute);
- return attribute.varray.get_internal_span();
+ return points.attributes_for_write()
+ ->lookup_or_add_for_write(attribute_id, ATTR_DOMAIN_POINT, data_type)
+ .varray.get_internal_span();
}
template<typename T>
static MutableSpan<T> ensure_point_attribute(PointCloudComponent &points,
const AttributeIDRef &attribute_id)
{
- GMutableSpan attribute = ensure_point_attribute(
- points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
- return attribute.typed<T>();
+ return points.attributes_for_write()
+ ->lookup_or_add_for_write<T>(attribute_id, ATTR_DOMAIN_POINT)
+ .varray.get_internal_span();
}
namespace {
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 2b90428acb1..00a79168087 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -506,9 +506,9 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.add(start_field);
evaluator.add(end_field);
evaluator.evaluate();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
index 60b5f0383ca..ab7ddfa71f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
@@ -252,10 +252,8 @@ static void node_geo_exec(GeoNodeExecParams params)
BKE_mesh_wrapper_ensure_mdata(surface_mesh_eval);
- MeshComponent mesh_eval;
- mesh_eval.replace(surface_mesh_eval, GeometryOwnershipType::ReadOnly);
- MeshComponent mesh_orig;
- mesh_orig.replace(surface_mesh_orig, GeometryOwnershipType::ReadOnly);
+ const AttributeAccessor mesh_attributes_eval = bke::mesh_attributes(*surface_mesh_eval);
+ const AttributeAccessor mesh_attributes_orig = bke::mesh_attributes(*surface_mesh_orig);
Curves &curves_id = *curves_geometry.get_curves_for_write();
CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
@@ -266,7 +264,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.error_message_add(NodeWarningType::Error, message);
return;
}
- if (!mesh_eval.attribute_exists(uv_map_name)) {
+ if (!mesh_attributes_eval.contains(uv_map_name)) {
pass_through_input();
char *message = BLI_sprintfN(TIP_("Evaluated surface missing UV map: %s."),
uv_map_name.c_str());
@@ -274,7 +272,7 @@ static void node_geo_exec(GeoNodeExecParams params)
MEM_freeN(message);
return;
}
- if (!mesh_orig.attribute_exists(uv_map_name)) {
+ if (!mesh_attributes_orig.contains(uv_map_name)) {
pass_through_input();
char *message = BLI_sprintfN(TIP_("Original surface missing UV map: %s."),
uv_map_name.c_str());
@@ -282,7 +280,7 @@ static void node_geo_exec(GeoNodeExecParams params)
MEM_freeN(message);
return;
}
- if (!mesh_eval.attribute_exists(rest_position_name)) {
+ if (!mesh_attributes_eval.contains(rest_position_name)) {
pass_through_input();
params.error_message_add(NodeWarningType::Error,
TIP_("Evaluated surface missing attribute: rest_position."));
@@ -294,12 +292,12 @@ static void node_geo_exec(GeoNodeExecParams params)
TIP_("Curves are not attached to any UV map."));
return;
}
- const VArraySpan<float2> uv_map_orig = mesh_orig.attribute_get_for_read<float2>(
- uv_map_name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
- const VArraySpan<float2> uv_map_eval = mesh_eval.attribute_get_for_read<float2>(
- uv_map_name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
- const VArraySpan<float3> rest_positions = mesh_eval.attribute_get_for_read<float3>(
- rest_position_name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f});
+ const VArraySpan<float2> uv_map_orig = mesh_attributes_orig.lookup<float2>(uv_map_name,
+ ATTR_DOMAIN_CORNER);
+ const VArraySpan<float2> uv_map_eval = mesh_attributes_eval.lookup<float2>(uv_map_name,
+ ATTR_DOMAIN_CORNER);
+ const VArraySpan<float3> rest_positions = mesh_attributes_eval.lookup<float3>(rest_position_name,
+ ATTR_DOMAIN_POINT);
const Span<float2> surface_uv_coords = curves.surface_uv_coords();
const Span<MLoopTri> looptris_orig{BKE_mesh_runtime_looptri_ensure(surface_mesh_orig),
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 68489d1b9a6..408596b65aa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -49,7 +49,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
{
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader attribute = in_component.attributes()->lookup(attribute_id);
if (!attribute) {
continue;
}
@@ -60,8 +60,9 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
}
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
- OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
- attribute_id, attribute.domain, data_type);
+ GSpanAttributeWriter result_attribute =
+ result_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, attribute.domain, data_type);
if (!result_attribute) {
continue;
@@ -70,10 +71,10 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> span{attribute.varray.typed<T>()};
- MutableSpan<T> out_span = result_attribute.as_span<T>();
+ MutableSpan<T> out_span = result_attribute.span.typed<T>();
out_span.copy_from(span);
});
- result_attribute.save();
+ result_attribute.finish();
}
}
@@ -89,7 +90,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
{
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader attribute = in_component.attributes()->lookup(attribute_id);
if (!attribute) {
continue;
}
@@ -100,8 +101,9 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
}
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
- OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
- attribute_id, attribute.domain, data_type);
+ GSpanAttributeWriter result_attribute =
+ result_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, attribute.domain, data_type);
if (!result_attribute) {
continue;
@@ -110,10 +112,10 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> span{attribute.varray.typed<T>()};
- MutableSpan<T> out_span = result_attribute.as_span<T>();
+ MutableSpan<T> out_span = result_attribute.span.typed<T>();
copy_data_based_on_mask(span, out_span, mask);
});
- result_attribute.save();
+ result_attribute.finish();
}
}
@@ -125,7 +127,7 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
{
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader attribute = in_component.attributes()->lookup(attribute_id);
if (!attribute) {
continue;
}
@@ -136,8 +138,9 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
}
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
- OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
- attribute_id, attribute.domain, data_type);
+ GSpanAttributeWriter result_attribute =
+ result_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, attribute.domain, data_type);
if (!result_attribute) {
continue;
@@ -146,10 +149,10 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> span{attribute.varray.typed<T>()};
- MutableSpan<T> out_span = result_attribute.as_span<T>();
+ MutableSpan<T> out_span = result_attribute.span.typed<T>();
copy_data_based_on_map(span, out_span, index_map);
});
- result_attribute.save();
+ result_attribute.finish();
}
}
@@ -319,7 +322,7 @@ static void delete_curves_selection(GeometrySet &geometry_set,
const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
GeometryComponentFieldContext field_context{src_component, selection_domain};
- const int domain_num = src_component.attribute_domain_num(selection_domain);
+ const int domain_num = src_component.attribute_domain_size(selection_domain);
fn::FieldEvaluator evaluator{field_context, domain_num};
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -351,7 +354,7 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
*geometry_set.get_component_for_read<PointCloudComponent>();
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
- fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_num(ATTR_DOMAIN_POINT)};
+ fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_size(ATTR_DOMAIN_POINT)};
evaluator.set_selection(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
@@ -379,8 +382,7 @@ static void delete_selected_instances(GeometrySet &geometry_set,
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
- fn::FieldEvaluator evaluator{field_context,
- instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE)};
+ fn::FieldEvaluator evaluator{field_context, instances.instances_num()};
evaluator.set_selection(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
@@ -1058,7 +1060,7 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
GeometryComponentFieldContext field_context{src_component, selection_domain};
fn::FieldEvaluator evaluator{field_context,
- src_component.attribute_domain_num(selection_domain)};
+ src_component.attribute_domain_size(selection_domain)};
evaluator.add(selection_field);
evaluator.evaluate();
const VArray<bool> selection = evaluator.get_evaluated<bool>(0);
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 f95601813a3..faf5b7f65fa 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
@@ -290,31 +290,32 @@ BLI_NOINLINE static void propagate_existing_attributes(
const Span<int> looptri_indices)
{
const Mesh &mesh = *mesh_component.get_for_read();
+ const AttributeAccessor mesh_attributes = *mesh_component.attributes();
+ MutableAttributeAccessor point_attributes = *point_component.attributes_for_write();
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const eCustomDataType output_data_type = entry.value.data_type;
- ReadAttributeLookup source_attribute = mesh_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader source_attribute = mesh_attributes.lookup(attribute_id);
if (!source_attribute) {
continue;
}
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
- OutputAttribute attribute_out = point_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter attribute_out = point_attributes.lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, output_data_type);
if (!attribute_out) {
continue;
}
- GMutableSpan out_span = attribute_out.as_span();
interpolate_attribute(mesh,
bary_coords,
looptri_indices,
source_attribute.domain,
source_attribute.varray,
- out_span);
- attribute_out.save();
+ attribute_out.span);
+ attribute_out.finish();
}
}
@@ -331,25 +332,21 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
const Span<int> looptri_indices,
const AttributeOutputs &attribute_outputs)
{
- OutputAttribute_Typed<int> id_attribute = point_component.attribute_try_get_for_output_only<int>(
- "id", ATTR_DOMAIN_POINT);
- MutableSpan<int> ids = id_attribute.as_span();
+ MutableAttributeAccessor pointcloud_attributes = *point_component.attributes_for_write();
- OutputAttribute_Typed<float3> normal_attribute;
- OutputAttribute_Typed<float3> rotation_attribute;
+ SpanAttributeWriter<int> ids = pointcloud_attributes.lookup_or_add_for_write_only_span<int>(
+ "id", ATTR_DOMAIN_POINT);
- MutableSpan<float3> normals;
- MutableSpan<float3> rotations;
+ SpanAttributeWriter<float3> normals;
+ SpanAttributeWriter<float3> rotations;
if (attribute_outputs.normal_id) {
- normal_attribute = point_component.attribute_try_get_for_output_only<float3>(
+ normals = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT);
- normals = normal_attribute.as_span();
}
if (attribute_outputs.rotation_id) {
- rotation_attribute = point_component.attribute_try_get_for_output_only<float3>(
+ rotations = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT);
- rotations = rotation_attribute.as_span();
}
const Mesh &mesh = *mesh_component.get_for_read();
@@ -368,27 +365,27 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
const float3 v1_pos = float3(mesh.mvert[v1_index].co);
const float3 v2_pos = float3(mesh.mvert[v2_index].co);
- ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
+ ids.span[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
float3 normal;
- if (!normals.is_empty() || !rotations.is_empty()) {
+ if (!normals.span.is_empty() || !rotations.span.is_empty()) {
normal_tri_v3(normal, v0_pos, v1_pos, v2_pos);
}
- if (!normals.is_empty()) {
- normals[i] = normal;
+ if (!normals.span.is_empty()) {
+ normals.span[i] = normal;
}
- if (!rotations.is_empty()) {
- rotations[i] = normal_to_euler_rotation(normal);
+ if (!rotations.span.is_empty()) {
+ rotations.span[i] = normal_to_euler_rotation(normal);
}
}
- id_attribute.save();
+ ids.finish();
- if (normal_attribute) {
- normal_attribute.save();
+ if (normals) {
+ normals.finish();
}
- if (rotation_attribute) {
- rotation_attribute.save();
+ if (rotations) {
+ rotations.finish();
}
}
@@ -398,11 +395,11 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
{
const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER;
GeometryComponentFieldContext field_context{component, attribute_domain};
- const int domain_num = component.attribute_domain_num(attribute_domain);
+ const int domain_size = component.attribute_domain_size(attribute_domain);
- Array<float> densities(domain_num, 0.0f);
+ Array<float> densities(domain_size, 0.0f);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(density_field, densities.as_mutable_span());
evaluator.evaluate();
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 8a256a9b91b..bf5479d552e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -146,9 +146,12 @@ static void transfer_attributes(
const GeometryComponent &src_component,
GeometryComponent &dst_component)
{
+ const AttributeAccessor src_attributes = *src_component.attributes();
+ MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
+
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader src_attribute = src_attributes.lookup(attribute_id);
if (!src_attribute) {
continue;
}
@@ -166,7 +169,7 @@ static void transfer_attributes(
}
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, out_domain, data_type);
if (!dst_attribute) {
@@ -176,7 +179,7 @@ static void transfer_attributes(
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> span{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst_span = dst_attribute.as_span<T>();
+ MutableSpan<T> dst_span = dst_attribute.span.typed<T>();
if (src_attribute.domain == ATTR_DOMAIN_FACE) {
dst_span.take_front(span.size()).copy_from(span);
if (keep_boundaries) {
@@ -193,7 +196,7 @@ static void transfer_attributes(
copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map);
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
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 5fe300e0a08..41136060ab7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -147,17 +147,17 @@ static void create_duplicate_index_attribute(GeometryComponent &component,
const IndexAttributes &attribute_outputs,
const Span<int> offsets)
{
- OutputAttribute_Typed<int> copy_attribute = component.attribute_try_get_for_output_only<int>(
- attribute_outputs.duplicate_index.get(), output_domain);
- MutableSpan<int> duplicate_indices = copy_attribute.as_span();
+ SpanAttributeWriter<int> duplicate_indices =
+ component.attributes_for_write()->lookup_or_add_for_write_only_span<int>(
+ attribute_outputs.duplicate_index.get(), output_domain);
for (const int i : IndexRange(selection.size())) {
const IndexRange range = range_for_offsets_index(offsets, i);
- MutableSpan<int> indices = duplicate_indices.slice(range);
+ MutableSpan<int> indices = duplicate_indices.span.slice(range);
for (const int i : indices.index_range()) {
indices[i] = i;
}
}
- copy_attribute.save();
+ duplicate_indices.finish();
}
/**
@@ -168,20 +168,21 @@ static void copy_stable_id_point(const Span<int> offsets,
const GeometryComponent &src_component,
GeometryComponent &dst_component)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_component.attributes()->lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
}
VArraySpan<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
threaded_id_offset_copy(offsets, src, dst);
- dst_attribute.save();
+ dst_attribute.finish();
}
static void copy_attributes_without_id(GeometrySet &geometry_set,
@@ -197,25 +198,26 @@ static void copy_attributes_without_id(GeometrySet &geometry_set,
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
if (!src_attribute || src_attribute.domain != domain) {
continue;
}
eAttrDomain out_domain = src_attribute.domain;
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- attribute_id, out_domain, data_type);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, out_domain, data_type);
if (!dst_attribute) {
continue;
}
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> src = src_attribute.varray.typed<T>();
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
threaded_slice_fill<T>(offsets, selection, src, dst);
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -242,7 +244,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
if (!src_attribute) {
continue;
}
@@ -250,8 +252,9 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
eAttrDomain out_domain = src_attribute.domain;
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- attribute_id, out_domain, data_type);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, out_domain, data_type);
if (!dst_attribute) {
continue;
}
@@ -259,7 +262,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (out_domain) {
case ATTR_DOMAIN_CURVE:
@@ -280,7 +283,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -297,18 +300,19 @@ static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves,
bke::CurvesGeometry &dst_curves,
CurveComponent &dst_component)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_component.attributes()->lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
}
VArraySpan<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int i_selection : range) {
@@ -322,7 +326,7 @@ static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves,
}
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
static void duplicate_curves(GeometrySet &geometry_set,
@@ -423,7 +427,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
if (!src_attribute) {
continue;
}
@@ -431,8 +435,9 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
eAttrDomain out_domain = src_attribute.domain;
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- attribute_id, out_domain, data_type);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, out_domain, data_type);
if (!dst_attribute) {
continue;
}
@@ -440,7 +445,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (out_domain) {
case ATTR_DOMAIN_FACE:
@@ -459,7 +464,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -477,18 +482,19 @@ static void copy_stable_id_faces(const Mesh &mesh,
const MeshComponent &src_component,
MeshComponent &dst_component)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_component.attributes()->lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
}
VArraySpan<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
int loop_index = 0;
@@ -511,7 +517,7 @@ static void copy_stable_id_faces(const Mesh &mesh,
}
}
- dst_attribute.save();
+ dst_attribute.finish();
}
static void duplicate_faces(GeometrySet &geometry_set,
@@ -636,7 +642,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
if (!src_attribute) {
continue;
}
@@ -644,15 +650,16 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
const eAttrDomain out_domain = src_attribute.domain;
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- attribute_id, out_domain, data_type);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, out_domain, data_type);
if (!dst_attribute) {
continue;
}
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (out_domain) {
case ATTR_DOMAIN_EDGE:
@@ -665,7 +672,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -679,12 +686,13 @@ static void copy_stable_id_edges(const Mesh &mesh,
const MeshComponent &src_component,
MeshComponent &dst_component)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_component.attributes()->lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
}
@@ -692,7 +700,7 @@ static void copy_stable_id_edges(const Mesh &mesh,
Span<MEdge> edges(mesh.medge, mesh.totedge);
VArraySpan<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
for (const int i_selection : range) {
const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
@@ -710,7 +718,7 @@ static void copy_stable_id_edges(const Mesh &mesh,
}
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
static void duplicate_edges(GeometrySet &geometry_set,
@@ -837,7 +845,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
if (!src_attribute) {
continue;
}
@@ -845,8 +853,9 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
eAttrDomain domain = src_attribute.domain;
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- attribute_id, domain, data_type);
+ GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, domain, data_type);
if (!dst_attribute) {
continue;
}
@@ -854,7 +863,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArraySpan<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (domain) {
case ATTR_DOMAIN_CURVE:
@@ -873,7 +882,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
copy_stable_id_point(offsets, src_component, dst_component);
@@ -949,7 +958,7 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
{
const PointCloudComponent &src_points =
*geometry_set.get_component_for_read<PointCloudComponent>();
- const int point_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int point_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{field_context, point_num};
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 94fbec66bfe..84acab47661 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -57,8 +57,8 @@ static void node_geo_exec(GeoNodeExecParams params)
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
- const int domain_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
+ const int domain_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
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 59d7154db6e..baa9952b950 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -66,21 +66,21 @@ static void save_selection_as_attribute(MeshComponent &component,
const eAttrDomain domain,
const IndexMask selection)
{
- BLI_assert(!component.attribute_exists(id));
+ BLI_assert(!component.attributes()->contains(id));
- OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>(
- id, domain);
+ SpanAttributeWriter<bool> attribute =
+ component.attributes_for_write()->lookup_or_add_for_write_span<bool>(id, domain);
/* Rely on the new attribute being zeroed by default. */
- BLI_assert(!attribute.as_span().as_span().contains(true));
+ BLI_assert(!attribute.span.as_span().contains(true));
if (selection.is_range()) {
- attribute.as_span().slice(selection.as_range()).fill(true);
+ attribute.span.slice(selection.as_range()).fill(true);
}
else {
- attribute.as_span().fill_indices(selection, true);
+ attribute.span.fill_indices(selection, true);
}
- attribute.save();
+ attribute.finish();
}
static MutableSpan<MVert> mesh_verts(Mesh &mesh)
@@ -168,7 +168,7 @@ static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domai
component.replace(&mesh, GeometryOwnershipType::ReadOnly);
CustomData &custom_data = get_customdata(mesh, domain);
if (int *orig_indices = static_cast<int *>(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) {
- return {orig_indices, component.attribute_domain_num(domain)};
+ return {orig_indices, component.attribute_domain_size(domain)};
}
return {};
}
@@ -280,16 +280,18 @@ static void extrude_mesh_vertices(MeshComponent &component,
new_edges[i_selection] = new_loose_edge(selection[i_selection], new_vert_range[i_selection]);
}
- component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
return true;
}
- OutputAttribute attribute = component.attribute_try_get_for_output(
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
- MutableSpan<T> data = attribute.as_span().typed<T>();
- switch (attribute.domain()) {
+ MutableSpan<T> data = attribute.span.typed<T>();
+ switch (attribute.domain) {
case ATTR_DOMAIN_POINT: {
/* New vertices copy the attribute values from their source vertex. */
copy_with_mask(data.slice(new_vert_range), data.as_span(), selection);
@@ -307,7 +309,7 @@ static void extrude_mesh_vertices(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
@@ -524,8 +526,10 @@ static void extrude_mesh_edges(MeshComponent &component,
const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
new_vert_range.size(), duplicate_edges, orig_vert_size);
- component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- OutputAttribute attribute = component.attribute_try_get_for_output(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
return true; /* Impossible to write the "normal" attribute. */
@@ -533,8 +537,8 @@ static void extrude_mesh_edges(MeshComponent &component,
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
- MutableSpan<T> data = attribute.as_span().typed<T>();
- switch (attribute.domain()) {
+ MutableSpan<T> data = attribute.span.typed<T>();
+ switch (attribute.domain) {
case ATTR_DOMAIN_POINT: {
/* New vertices copy the attribute values from their source vertex. */
copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
@@ -626,7 +630,7 @@ static void extrude_mesh_edges(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
@@ -902,8 +906,10 @@ static void extrude_mesh_face_regions(MeshComponent &component,
const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
new_vert_range.size(), boundary_edges, orig_vert_size);
- component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- OutputAttribute attribute = component.attribute_try_get_for_output(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
return true; /* Impossible to write the "normal" attribute. */
@@ -911,8 +917,8 @@ static void extrude_mesh_face_regions(MeshComponent &component,
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
- MutableSpan<T> data = attribute.as_span().typed<T>();
- switch (attribute.domain()) {
+ MutableSpan<T> data = attribute.span.typed<T>();
+ switch (attribute.domain) {
case ATTR_DOMAIN_POINT: {
/* New vertices copy the attributes from their original vertices. */
copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
@@ -991,7 +997,7 @@ static void extrude_mesh_face_regions(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
@@ -1154,8 +1160,10 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
- component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- OutputAttribute attribute = component.attribute_try_get_for_output(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
return true; /* Impossible to write the "normal" attribute. */
@@ -1163,8 +1171,8 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
- MutableSpan<T> data = attribute.as_span().typed<T>();
- switch (attribute.domain()) {
+ MutableSpan<T> data = attribute.span.typed<T>();
+ switch (attribute.domain) {
case ATTR_DOMAIN_POINT: {
/* New vertices copy the attributes from their original vertices. */
MutableSpan<T> new_data = data.slice(new_vert_range);
@@ -1267,7 +1275,7 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
index 7839e148ee3..64861e529bc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
@@ -91,7 +91,7 @@ class FieldAtIndex final : public GeometryFieldInput {
{
const GeometryComponentFieldContext value_field_context{component, value_field_domain_};
FieldEvaluator value_evaluator{value_field_context,
- component.attribute_domain_num(value_field_domain_)};
+ component.attribute_domain_size(value_field_domain_)};
value_evaluator.add(value_field_);
value_evaluator.evaluate();
const GVArray &values = value_evaluator.get_evaluated(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc
index e6906f4fb21..5939ed5334d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc
@@ -85,12 +85,12 @@ class FieldOnDomain final : public GeometryFieldInput {
IndexMask /* mask */) const final
{
const GeometryComponentFieldContext context{component, src_domain_};
- FieldEvaluator value_evaluator{context, component.attribute_domain_num(src_domain_)};
+ FieldEvaluator value_evaluator{context, component.attribute_domain_size(src_domain_)};
value_evaluator.add(src_field_);
value_evaluator.evaluate();
const GVArray &values = value_evaluator.get_evaluated(0);
- return component.attribute_try_adapt_domain(values, src_domain_, domain);
+ return component.attributes()->adapt_domain(values, src_domain_, domain);
}
};
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 0484017cf3b..15b2822805a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -22,11 +22,11 @@ static void node_declare(NodeDeclarationBuilder &b)
static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
@@ -49,20 +49,21 @@ static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selecti
}
}
- component.attribute_foreach(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ attributes.for_all(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
if (meta_data.domain == ATTR_DOMAIN_CORNER) {
- OutputAttribute attribute = component.attribute_try_get_for_output(
- attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type, nullptr);
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
+ attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type);
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
- MutableSpan<T> dst_span = attribute.as_span<T>();
+ MutableSpan<T> dst_span = attribute.span.typed<T>();
for (const int j : selection.index_range()) {
const MPoly &poly = polys[selection[j]];
dst_span.slice(poly.loopstart + 1, poly.totloop - 1).reverse();
}
});
- attribute.save();
+ attribute.finish();
}
return true;
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index e0aaf43235c..bc1b9e940a1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -39,11 +39,13 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
evaluator.evaluate();
const VArray<bool> relative = evaluator.get_evaluated<bool>(0);
- VArray<float3> positions = component.attribute_get_for_read<float3>(
+ const AttributeAccessor attributes = *component.attributes();
+
+ VArray<float3> positions = attributes.lookup_or_default<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
StringRef side = left_ ? "handle_left" : "handle_right";
- VArray<float3> handles = component.attribute_get_for_read<float3>(
+ VArray<float3> handles = attributes.lookup_or_default<float3>(
side, ATTR_DOMAIN_POINT, {0, 0, 0});
if (relative.is_single()) {
@@ -52,10 +54,10 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
for (const int i : positions.index_range()) {
output[i] = handles[i] - positions[i];
}
- return component.attribute_try_adapt_domain<float3>(
+ return attributes.adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
}
- return component.attribute_try_adapt_domain<float3>(handles, ATTR_DOMAIN_POINT, domain);
+ return attributes.adapt_domain<float3>(handles, ATTR_DOMAIN_POINT, domain);
}
Array<float3> output(positions.size());
@@ -67,7 +69,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
output[i] = handles[i];
}
}
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
index f27e0305c7d..b009aaa5291 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
@@ -91,7 +91,7 @@ class AngleFieldInput final : public GeometryFieldInput {
};
VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
std::move(angles), ATTR_DOMAIN_EDGE, domain);
}
@@ -166,7 +166,7 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
};
VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
std::move(angles), ATTR_DOMAIN_EDGE, domain);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
index cbc2ebc3e68..50d6998bb27 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -40,7 +40,7 @@ class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
face_count[mesh->mloop[i].e]++;
}
- return mesh_component.attribute_try_adapt_domain<int>(
+ return mesh_component.attributes()->adapt_domain<int>(
VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
}
return {};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
index 6201ad26bfb..83e511f45c2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -93,14 +93,14 @@ static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &comp
}
if (vertex == VERTEX_ONE) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForFunc(
mesh->totedge,
[mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v1].co); }),
ATTR_DOMAIN_EDGE,
domain);
}
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForFunc(
mesh->totedge,
[mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }),
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
index 7a0e3e37a65..4d21bf9443a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -29,7 +29,7 @@ static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert);
};
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index d02f7291704..6b04ff08d9e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -80,7 +80,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
return max - min < thresholds[i_poly] / 2.0f;
};
- return component.attribute_try_adapt_domain<bool>(
+ return component.attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh->totpoly, planar_fn), ATTR_DOMAIN_FACE, domain);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
index 67a21cb06f0..a225ce61b14 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -40,7 +40,7 @@ static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &compone
}
}
- return component.attribute_try_adapt_domain<int>(
+ return component.attributes()->adapt_domain<int>(
VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain);
}
@@ -83,7 +83,7 @@ static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component
return {};
}
- return component.attribute_try_adapt_domain<int>(
+ return component.attributes()->adapt_domain<int>(
VArray<int>::ForFunc(mesh->totpoly,
[mesh](const int i) -> float { return mesh->mpoly[i].totloop; }),
ATTR_DOMAIN_FACE,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
index bd57924d685..2c7eef5665f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -54,7 +54,7 @@ class IslandFieldInput final : public GeometryFieldInput {
output[i] = ordered_roots.index_of_or_add(root);
}
- return mesh_component.attribute_try_adapt_domain<int>(
+ return mesh_component.attributes()->adapt_domain<int>(
VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
}
@@ -101,7 +101,8 @@ class IslandCountFieldInput final : public GeometryFieldInput {
island_list.add(root);
}
- return VArray<int>::ForSingle(island_list.size(), mesh_component.attribute_domain_num(domain));
+ return VArray<int>::ForSingle(island_list.size(),
+ mesh_component.attribute_domain_size(domain));
}
uint64_t hash() const override
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index def82eefca5..267ba44cc00 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -32,7 +32,7 @@ static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &com
}
if (domain == ATTR_DOMAIN_POINT) {
VArray<int> count = VArray<int>::ForFunc(curves.curves_num(), count_fn);
- return component.attribute_try_adapt_domain<int>(
+ return component.attributes()->adapt_domain<int>(
std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index f5831941094..a2aab5464aa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -75,7 +75,7 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
const VArray<int8_t> types = curves.curve_types();
if (curves.is_single_type(CURVE_TYPE_POLY)) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForSpan(curves.evaluated_tangents()), ATTR_DOMAIN_POINT, domain);
}
@@ -86,7 +86,7 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
}
if (domain == ATTR_DOMAIN_CURVE) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(tangents)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
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 21ef8765e43..3ce26a086e2 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
@@ -50,7 +50,7 @@ static void add_instances_from_component(
const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate)
{
const eAttrDomain domain = ATTR_DOMAIN_POINT;
- const int domain_num = src_component.attribute_domain_num(domain);
+ const int domain_num = src_component.attribute_domain_size(domain);
VArray<bool> pick_instance;
VArray<int> indices;
@@ -82,7 +82,7 @@ static void add_instances_from_component(
MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
select_len);
- VArray<float3> positions = src_component.attribute_get_for_read<float3>(
+ VArray<float3> positions = src_component.attributes()->lookup_or_default<float3>(
"position", domain, {0, 0, 0});
const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>();
@@ -154,12 +154,12 @@ static void add_instances_from_component(
}
}
- bke::CustomDataAttributes &instance_attributes = dst_component.attributes();
+ bke::CustomDataAttributes &instance_attributes = dst_component.instance_attributes();
for (const auto item : attributes_to_propagate.items()) {
const AttributeIDRef &attribute_id = item.key;
const AttributeKind attribute_kind = item.value;
- const GVArray src_attribute = src_component.attribute_get_for_read(
+ const GVArray src_attribute = src_component.attributes()->lookup_or_default(
attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
BLI_assert(src_attribute);
std::optional<GMutableSpan> dst_attribute_opt = instance_attributes.get_for_write(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index ffc6137cf83..edbe6e1593f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -40,9 +40,9 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
- const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE);
+ const int domain_size = instances.instances_num();
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(std::move(selection_field));
evaluator.add(std::move(position_field));
evaluator.add(std::move(radius_field));
@@ -75,18 +75,18 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const AttributeIDRef &attribute_id = item.key;
const AttributeKind attribute_kind = item.value;
- const GVArray src = instances.attribute_get_for_read(
+ const GVArray src = instances.attributes()->lookup_or_default(
attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
BLI_assert(src);
- OutputAttribute dst = points.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst = points.attributes_for_write()->lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
BLI_assert(dst);
attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) {
using T = decltype(dummy);
- copy_attribute_to_points(src.typed<T>(), selection, dst.as_span().typed<T>());
+ copy_attribute_to_points(src.typed<T>(), selection, dst.span.typed<T>());
});
- dst.save();
+ dst.finish();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 62cd1d8ac3a..083a505539a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -24,7 +24,7 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
Map<AttributeIDRef, AttributeMetaData> info;
for (const GeometryComponent *component : components) {
- component->attribute_foreach(
+ component->attributes()->for_all(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
return true;
@@ -56,11 +56,11 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
int offset = 0;
for (const GeometryComponent *component : src_components) {
- const int domain_num = component->attribute_domain_num(domain);
+ const int domain_num = component->attribute_domain_size(domain);
if (domain_num == 0) {
continue;
}
- GVArray read_attribute = component->attribute_get_for_read(
+ GVArray read_attribute = component->attributes()->lookup_or_default(
attribute_id, domain, data_type, nullptr);
GVArraySpan src_span{read_attribute};
@@ -83,15 +83,15 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
const AttributeIDRef attribute_id = item.key;
const AttributeMetaData &meta_data = item.value;
- OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
- attribute_id, meta_data.domain, meta_data.data_type);
+ GSpanAttributeWriter write_attribute =
+ result.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, meta_data.domain, meta_data.data_type);
if (!write_attribute) {
continue;
}
- GMutableSpan dst_span = write_attribute.as_span();
fill_new_attribute(
- src_components, attribute_id, meta_data.data_type, meta_data.domain, dst_span);
- write_attribute.save();
+ src_components, attribute_id, meta_data.data_type, meta_data.domain, write_attribute.span);
+ write_attribute.finish();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 5875606da97..ca613ae009b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -71,7 +71,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput {
Array<bool> selection(mesh->totpoly);
select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
- return mesh_component.attribute_try_adapt_domain<bool>(
+ return mesh_component.attributes()->adapt_domain<bool>(
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
return nullptr;
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 1def4089115..4bc84a7a08a 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
@@ -39,7 +39,7 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int src_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{context, src_num};
evaluator.add(selection_field);
@@ -57,7 +57,7 @@ static std::optional<Mesh *> mesh_merge_by_distance_connected(const MeshComponen
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
Array<bool> selection(src_num);
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{context, src_num};
@@ -72,7 +72,7 @@ static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mes
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{context, src_num};
evaluator.add(selection_field);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index b882d4bdf09..cb79ef93de9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -480,53 +480,49 @@ static void calculate_selection_outputs(Mesh *mesh,
const ConeConfig &config,
ConeAttributeOutputs &attribute_outputs)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
/* Populate "Top" selection output. */
if (attribute_outputs.top_id) {
const bool face = !config.top_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
- OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
attribute_outputs.top_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT);
- MutableSpan<bool> selection = attribute.as_span();
if (config.top_is_point) {
- selection[config.first_vert] = true;
+ selection.span[config.first_vert] = true;
}
else {
- selection.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true);
+ selection.span.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true);
}
- attribute.save();
+ selection.finish();
}
/* Populate "Bottom" selection output. */
if (attribute_outputs.bottom_id) {
const bool face = !config.bottom_is_point &&
config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE;
- OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
attribute_outputs.bottom_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT);
- MutableSpan<bool> selection = attribute.as_span();
if (config.bottom_is_point) {
- selection[config.last_vert] = true;
+ selection.span[config.last_vert] = true;
}
else if (face) {
- selection.slice(config.bottom_faces_start, config.bottom_faces_len).fill(true);
+ selection.span.slice(config.bottom_faces_start, config.bottom_faces_len).fill(true);
}
else {
- selection.slice(config.last_ring_verts_start + 1, config.circle_segments).fill(true);
+ selection.span.slice(config.last_ring_verts_start + 1, config.circle_segments).fill(true);
}
- attribute.save();
+ selection.finish();
}
/* Populate "Side" selection output. */
if (attribute_outputs.side_id) {
- OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE);
- MutableSpan<bool> selection = attribute.as_span();
- selection.slice(config.side_faces_start, config.side_faces_len).fill(true);
- attribute.save();
+ selection.span.slice(config.side_faces_start, config.side_faces_len).fill(true);
+ selection.finish();
}
}
@@ -540,11 +536,11 @@ static void calculate_selection_outputs(Mesh *mesh,
*/
static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttribute_Typed<float2> uv_attribute =
- mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
- MutableSpan<float2> uvs = uv_attribute.as_span();
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+
+ SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
+ "uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.span;
Array<float2> circle(config.circle_segments);
float angle = 0.0f;
@@ -654,7 +650,7 @@ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
}
}
- uv_attribute.save();
+ uv_attribute.finish();
}
static Mesh *create_vertex_mesh()
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 523dbd5dac2..9baf0b3171e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -18,23 +18,22 @@ namespace blender::nodes {
static void calculate_uvs(
Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttribute_Typed<float2> uv_attribute =
- mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
- MutableSpan<float2> uvs = uv_attribute.as_span();
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+
+ SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
+ "uv_map", ATTR_DOMAIN_CORNER);
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
const float3 &co = verts[loops[i].v].co;
- uvs[i].x = (co.x + size_x * 0.5f) * dx;
- uvs[i].y = (co.y + size_y * 0.5f) * dy;
+ uv_attribute.span[i].x = (co.x + size_x * 0.5f) * dx;
+ uv_attribute.span[i].y = (co.y + size_y * 0.5f) * dy;
}
});
- uv_attribute.save();
+ uv_attribute.finish();
}
Mesh *create_grid_mesh(const int verts_x,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index 4e0e5c7c912..f78752387c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -220,11 +220,11 @@ static void calculate_sphere_faces(MutableSpan<MLoop> loops,
static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttribute_Typed<float2> uv_attribute =
- mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
- MutableSpan<float2> uvs = uv_attribute.as_span();
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+
+ SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
+ "uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.span;
int loop_index = 0;
const float dy = 1.0f / rings;
@@ -254,7 +254,7 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
uvs[loop_index++] = float2(segment / segments, 1.0f - dy);
}
- uv_attribute.save();
+ uv_attribute.finish();
}
static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)
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 ec6acf55dd8..f6ee3d00dee 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
@@ -25,7 +25,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
GeometryComponentFieldContext context{component, ATTR_DOMAIN_EDGE};
- fn::FieldEvaluator evaluator{context, component.attribute_domain_num(ATTR_DOMAIN_EDGE)};
+ fn::FieldEvaluator evaluator{context, component.attribute_domain_size(ATTR_DOMAIN_EDGE)};
evaluator.add(params.get_input<Field<bool>>("Selection"));
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
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 7463eb01471..8e621d3ed97 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
@@ -66,7 +66,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
return;
}
GeometryComponentFieldContext field_context{*mesh_component, domain};
- const int domain_num = mesh_component->attribute_domain_num(domain);
+ const int domain_num = mesh_component->attribute_domain_size(domain);
if (domain_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
@@ -83,20 +83,20 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
geometry_set.replace_pointcloud(pointcloud);
- PointCloudComponent &point_component =
- geometry_set.get_component_for_write<PointCloudComponent>();
+ MutableAttributeAccessor pointcloud_attributes = bke::pointcloud_attributes_for_write(
+ *pointcloud);
- OutputAttribute position = point_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter position = pointcloud_attributes.lookup_or_add_for_write_only_span(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
materialize_compressed_to_uninitialized_threaded(
- evaluator.get_evaluated(0), selection, position.as_span());
- position.save();
+ evaluator.get_evaluated(0), selection, position.span);
+ position.finish();
- OutputAttribute radius = point_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter radius = pointcloud_attributes.lookup_or_add_for_write_only_span(
"radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
materialize_compressed_to_uninitialized_threaded(
- evaluator.get_evaluated(1), selection, radius.as_span());
- radius.save();
+ evaluator.get_evaluated(1), selection, radius.span);
+ radius.finish();
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
@@ -106,12 +106,12 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const eCustomDataType data_type = entry.value.data_type;
- GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type);
- OutputAttribute dst = point_component.attribute_try_get_for_output_only(
+ GVArray src = mesh_component->attributes()->lookup_or_default(attribute_id, domain, data_type);
+ GSpanAttributeWriter dst = pointcloud_attributes.lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
- materialize_compressed_to_uninitialized_threaded(src, selection, dst.as_span());
- dst.save();
+ materialize_compressed_to_uninitialized_threaded(src, selection, dst.span);
+ dst.finish();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points.cc b/source/blender/nodes/geometry/nodes/node_geo_points.cc
index da414960e1d..dd32e6714f4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points.cc
@@ -72,19 +72,20 @@ static void node_geo_exec(GeoNodeExecParams params)
PointCloud *new_point_cloud = BKE_pointcloud_new_nomain(count);
GeometrySet geometry_set = GeometrySet::create_with_pointcloud(new_point_cloud);
PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
- OutputAttribute_Typed<float3> output_position = points.attribute_try_get_for_output_only<float3>(
+ MutableAttributeAccessor attributes = *points.attributes_for_write();
+ AttributeWriter<float3> output_position = attributes.lookup_or_add_for_write<float3>(
"position", ATTR_DOMAIN_POINT);
- OutputAttribute_Typed<float> output_radii = points.attribute_try_get_for_output_only<float>(
+ AttributeWriter<float> output_radii = attributes.lookup_or_add_for_write<float>(
"radius", ATTR_DOMAIN_POINT);
PointsFieldContext context{count};
fn::FieldEvaluator evaluator{context, count};
- evaluator.add_with_destination(position_field, output_position.as_span());
- evaluator.add_with_destination(radius_field, output_radii.as_span());
+ evaluator.add_with_destination(position_field, output_position.varray);
+ evaluator.add_with_destination(radius_field, output_radii.varray);
evaluator.evaluate();
- output_position.save();
- output_radii.save();
+ output_position.finish();
+ output_radii.finish();
params.set_output("Geometry", 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 95ff53b7146..9cc64d4bc44 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
@@ -38,7 +38,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
}
GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT};
- const int domain_num = point_component->attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int domain_num = point_component->attribute_domain_size(ATTR_DOMAIN_POINT);
if (domain_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
@@ -60,18 +60,19 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
const eCustomDataType data_type = entry.value.data_type;
- GVArray src = point_component->attribute_get_for_read(
- attribute_id, ATTR_DOMAIN_POINT, data_type);
- OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(
+ GVArray src = point_component->attributes()->lookup_or_default(
attribute_id, ATTR_DOMAIN_POINT, data_type);
+ GSpanAttributeWriter dst =
+ mesh_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
VArray<T> src_typed = src.typed<T>();
VArraySpan<T> src_typed_span{src_typed};
- copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed<T>());
+ copy_attribute_to_vertices(src_typed_span, selection, dst.span.typed<T>());
});
- dst.save();
+ dst.finish();
}
}
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 42cee4c0efe..28a01a5cbce 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
@@ -163,12 +163,15 @@ static void gather_point_data_from_component(GeoNodeExecParams &params,
Vector<float3> &r_positions,
Vector<float> &r_radii)
{
- VArray<float3> positions = component.attribute_get_for_read<float3>(
+ if (component.is_empty()) {
+ return;
+ }
+ VArray<float3> positions = component.attributes()->lookup_or_default<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
Field<float> radius_field = params.get_input<Field<float>>("Radius");
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int domain_num = component.attribute_domain_size(ATTR_DOMAIN_POINT);
r_positions.resize(r_positions.size() + domain_num);
positions.materialize(r_positions.as_mutable_span().take_back(domain_num));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index a92cee2d066..f81748da587 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -312,8 +312,8 @@ class RaycastFunction : public fn::MultiFunction {
}
const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_num = mesh_component.attribute_domain_num(domain_);
- target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_num);
+ const int domain_size = mesh_component.attribute_domain_size(domain_);
+ target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_size);
target_evaluator_->add(std::move(src_field));
target_evaluator_->evaluate();
target_data_ = &target_evaluator_->get_evaluated(0);
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 da42b8c5ee0..ee279ba58f9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
@@ -39,7 +39,7 @@ static void node_geo_exec(GeoNodeExecParams params)
/* 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_for_read(type);
- if (read_only_component.attribute_exists(name)) {
+ if (read_only_component.attributes()->contains(name)) {
attribute_exists = true;
}
else {
@@ -47,7 +47,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
GeometryComponent &component = geometry_set.get_component_for_write(type);
- if (!component.attribute_try_delete(name)) {
+ if (!component.attributes_for_write()->remove(name)) {
cannot_delete = true;
}
}
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 37533a7b99a..fc3cb7006bb 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
@@ -75,12 +75,12 @@ static void set_position_in_component(CurveComponent &component,
const Field<float3> &offset_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
evaluator.add(position_field);
evaluator.add(offset_field);
@@ -146,8 +146,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
has_curves = true;
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- if (!component.attribute_exists("handle_left") ||
- !component.attribute_exists("handle_right")) {
+ const AttributeAccessor attributes = *component.attributes();
+ if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) {
return;
}
has_bezier = true;
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 4c84093bfcb..90411baac3e 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
@@ -20,21 +20,22 @@ static void set_radius_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<float> &radius_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
- "radius", ATTR_DOMAIN_POINT);
+ AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
+ ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.add_with_destination(radius_field, radii.varray);
evaluator.evaluate();
- radii.save();
+ radii.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 8b1e5935a61..2211ac62727 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
@@ -16,21 +16,23 @@ static void set_tilt_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<float> &tilt_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- OutputAttribute_Typed<float> tilts = component.attribute_try_get_for_output_only<float>(
- "tilt", ATTR_DOMAIN_POINT);
+ AttributeWriter<float> tilts = attributes.lookup_or_add_for_write<float>("tilt",
+ ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(tilt_field, tilts.varray());
+ evaluator.add_with_destination(tilt_field, tilts.varray);
evaluator.evaluate();
- tilts.save();
+ tilts.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index a7f17c02ce8..fbb2ecbb799 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -19,34 +19,34 @@ static void set_id_in_component(GeometryComponent &component,
const eAttrDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ?
ATTR_DOMAIN_INSTANCE :
ATTR_DOMAIN_POINT;
- GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, domain};
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
/* Since adding the ID attribute can change the result of the field evaluation (the random value
* node uses the index if the ID is unavailable), make sure that it isn't added before evaluating
* the field. However, as an optimization, use a faster code path when it already exists. */
- if (component.attribute_exists("id")) {
- OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
- "id", domain);
- evaluator.add_with_destination(id_field, id_attribute.varray());
+ if (attributes.contains("id")) {
+ AttributeWriter<int> id_attribute = attributes.lookup_or_add_for_write<int>("id", domain);
+ evaluator.add_with_destination(id_field, id_attribute.varray);
evaluator.evaluate();
- id_attribute.save();
+ id_attribute.finish();
}
else {
evaluator.add(id_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
const VArray<int> result_ids = evaluator.get_evaluated<int>(0);
- OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
- "id", domain);
- result_ids.materialize(selection, id_attribute.as_span());
- id_attribute.save();
+ SpanAttributeWriter<int> id_attribute = attributes.lookup_or_add_for_write_span<int>("id",
+ domain);
+ result_ids.materialize(selection, id_attribute.span);
+ id_attribute.finish();
}
}
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 58613dae832..0dc89bb7ef4 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
@@ -16,20 +16,21 @@ static void set_material_index_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<int> &index_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- OutputAttribute_Typed<int> indices = component.attribute_try_get_for_output_only<int>(
- "material_index", ATTR_DOMAIN_FACE);
+ AttributeWriter<int> indices = attributes.lookup_or_add_for_write<int>("material_index",
+ ATTR_DOMAIN_FACE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(index_field, indices.varray());
+ evaluator.add_with_destination(index_field, indices.varray);
evaluator.evaluate();
- indices.save();
+ indices.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 571bead9743..da7977a4fb4 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
@@ -20,21 +20,22 @@ static void set_radius_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<float> &radius_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
- "radius", ATTR_DOMAIN_POINT);
+ AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
+ ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.add_with_destination(radius_field, radii.varray);
evaluator.evaluate();
- radii.save();
+ radii.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 1935409b3e5..880252de4fa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -25,12 +25,10 @@ static void node_declare(NodeDeclarationBuilder &b)
static void set_computed_position_and_offset(GeometryComponent &component,
const VArray<float3> &in_positions,
const VArray<float3> &in_offsets,
- const eAttrDomain domain,
const IndexMask selection)
{
-
- OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
- "position", domain, {0, 0, 0});
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ AttributeWriter<float3> positions = attributes.lookup_for_write<float3>("position");
const int grain_size = 10000;
@@ -38,7 +36,7 @@ static void set_computed_position_and_offset(GeometryComponent &component,
case GEO_COMPONENT_TYPE_MESH: {
Mesh *mesh = static_cast<MeshComponent &>(component).get_for_write();
MutableSpan<MVert> mverts{mesh->mvert, mesh->totvert};
- if (in_positions.is_same(positions.varray())) {
+ if (in_positions.is_same(positions.varray)) {
devirtualize_varray(in_offsets, [&](const auto in_offsets) {
threading::parallel_for(
selection.index_range(), grain_size, [&](const IndexRange range) {
@@ -67,18 +65,13 @@ static void set_computed_position_and_offset(GeometryComponent &component,
CurveComponent &curve_component = static_cast<CurveComponent &>(component);
Curves &curves_id = *curve_component.get_for_write();
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- if (component.attribute_exists("handle_right") &&
- component.attribute_exists("handle_left")) {
- OutputAttribute_Typed<float3> handle_right_attribute =
- component.attribute_try_get_for_output<float3>(
- "handle_right", ATTR_DOMAIN_POINT, {0, 0, 0});
- OutputAttribute_Typed<float3> handle_left_attribute =
- component.attribute_try_get_for_output<float3>(
- "handle_left", ATTR_DOMAIN_POINT, {0, 0, 0});
- MutableSpan<float3> handle_right = handle_right_attribute.as_span();
- MutableSpan<float3> handle_left = handle_left_attribute.as_span();
-
- MutableSpan<float3> out_positions_span = positions.as_span();
+ if (attributes.contains("handle_right") && attributes.contains("handle_left")) {
+ SpanAttributeWriter<float3> handle_right_attribute =
+ attributes.lookup_or_add_for_write_span<float3>("handle_right", ATTR_DOMAIN_POINT);
+ SpanAttributeWriter<float3> handle_left_attribute =
+ attributes.lookup_or_add_for_write_span<float3>("handle_left", ATTR_DOMAIN_POINT);
+
+ MutableVArraySpan<float3> out_positions_span = positions.varray;
devirtualize_varray2(
in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
threading::parallel_for(
@@ -86,15 +79,16 @@ static void set_computed_position_and_offset(GeometryComponent &component,
for (const int i : selection.slice(range)) {
const float3 new_position = in_positions[i] + in_offsets[i];
const float3 delta = new_position - out_positions_span[i];
- handle_right[i] += delta;
- handle_left[i] += delta;
+ handle_right_attribute.span[i] += delta;
+ handle_left_attribute.span[i] += delta;
out_positions_span[i] = new_position;
}
});
});
- handle_right_attribute.save();
- handle_left_attribute.save();
+ out_positions_span.save();
+ handle_right_attribute.finish();
+ handle_left_attribute.finish();
/* Automatic Bezier handles must be recalculated based on the new positions. */
curves.calculate_bezier_auto_handles();
@@ -105,8 +99,8 @@ static void set_computed_position_and_offset(GeometryComponent &component,
}
}
default: {
- MutableSpan<float3> out_positions_span = positions.as_span();
- if (in_positions.is_same(positions.varray())) {
+ MutableVArraySpan<float3> out_positions_span = positions.varray;
+ if (in_positions.is_same(positions.varray)) {
devirtualize_varray(in_offsets, [&](const auto in_offsets) {
threading::parallel_for(
selection.index_range(), grain_size, [&](const IndexRange range) {
@@ -127,11 +121,12 @@ static void set_computed_position_and_offset(GeometryComponent &component,
});
});
}
+ out_positions_span.save();
break;
}
}
- positions.save();
+ positions.finish();
}
static void set_position_in_component(GeometryComponent &component,
@@ -142,21 +137,22 @@ static void set_position_in_component(GeometryComponent &component,
eAttrDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? ATTR_DOMAIN_INSTANCE :
ATTR_DOMAIN_POINT;
GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
evaluator.add(position_field);
evaluator.add(offset_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
const VArray<float3> positions_input = evaluator.get_evaluated<float3>(0);
const VArray<float3> offsets_input = evaluator.get_evaluated<float3>(1);
- set_computed_position_and_offset(component, positions_input, offsets_input, domain, selection);
+ set_computed_position_and_offset(component, positions_input, offsets_input, selection);
}
static void node_geo_exec(GeoNodeExecParams params)
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 b98fbd0a0fe..e0cf0f98d58 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
@@ -16,21 +16,23 @@ static void set_smooth_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<bool> &shade_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- OutputAttribute_Typed<bool> shades = component.attribute_try_get_for_output_only<bool>(
- "shade_smooth", ATTR_DOMAIN_FACE);
+ AttributeWriter<bool> shades = attributes.lookup_or_add_for_write<bool>("shade_smooth",
+ ATTR_DOMAIN_FACE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(shade_field, shades.varray());
+ evaluator.add_with_destination(shade_field, shades.varray);
evaluator.evaluate();
- shades.save();
+ shades.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 976857883f0..a35d8d66558 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
@@ -16,21 +16,23 @@ static void set_cyclic_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<bool> &cyclic_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- OutputAttribute_Typed<bool> cyclics = component.attribute_try_get_for_output_only<bool>(
- "cyclic", ATTR_DOMAIN_CURVE);
+ AttributeWriter<bool> cyclics = attributes.lookup_or_add_for_write<bool>("cyclic",
+ ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(cyclic_field, cyclics.varray());
+ evaluator.add_with_destination(cyclic_field, cyclics.varray);
evaluator.evaluate();
- cyclics.save();
+ cyclics.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 8b665376c01..fcebc1116d7 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
@@ -16,21 +16,23 @@ static void set_resolution_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<int> &resolution_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- OutputAttribute_Typed<int> resolutions = component.attribute_try_get_for_output_only<int>(
- "resolution", ATTR_DOMAIN_CURVE);
+ AttributeWriter<int> resolutions = attributes.lookup_or_add_for_write<int>("resolution",
+ ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(resolution_field, resolutions.varray());
+ evaluator.add_with_destination(resolution_field, resolutions.varray);
evaluator.evaluate();
- resolutions.save();
+ resolutions.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 abac6d8d6b3..69a4fad10e2 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
@@ -87,9 +87,14 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
const eAttrDomain domain,
const GField &field)
{
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
+ return;
+ }
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- const IndexMask mask{IndexMask(domain_num)};
+ const IndexMask mask{IndexMask(domain_size)};
const CPPType &type = field.cpp_type();
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
@@ -97,28 +102,28 @@ static void try_capture_field_on_geometry(GeometryComponent &component,
/* Could avoid allocating a new buffer if:
* - We are writing to an attribute that exists already.
* - The field does not depend on that attribute (we can't easily check for that yet). */
- void *buffer = MEM_mallocN(type.size() * domain_num, __func__);
+ void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_num});
+ evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size});
evaluator.evaluate();
- component.attribute_try_delete(name);
- if (component.attribute_exists(name)) {
- WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name);
+ attributes.remove(name);
+ if (attributes.contains(name)) {
+ GAttributeWriter write_attribute = attributes.lookup_for_write(name);
if (write_attribute && write_attribute.domain == domain &&
write_attribute.varray.type() == type) {
write_attribute.varray.set_all(buffer);
- write_attribute.tag_modified_fn();
+ write_attribute.finish();
}
else {
/* Cannot change type of built-in attribute. */
}
- type.destruct_n(buffer, domain_num);
+ type.destruct_n(buffer, domain_size);
MEM_freeN(buffer);
}
else {
- if (!component.attribute_try_create(name, domain, data_type, AttributeInitMove{buffer})) {
+ if (!attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) {
MEM_freeN(buffer);
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 94d5d7f946f..afd7db6604d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -335,13 +335,14 @@ static void create_attributes(GeoNodeExecParams &params,
const TextLayout &layout,
InstancesComponent &instances)
{
+ MutableAttributeAccessor attributes = *instances.attributes_for_write();
+
if (params.output_is_required("Line")) {
StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line");
- OutputAttribute_Typed<int> line_attribute = instances.attribute_try_get_for_output_only<int>(
+ SpanAttributeWriter<int> line_attribute = attributes.lookup_or_add_for_write_only_span<int>(
line_id.get(), ATTR_DOMAIN_INSTANCE);
- MutableSpan<int> lines = line_attribute.as_span();
- lines.copy_from(layout.line_numbers);
- line_attribute.save();
+ line_attribute.span.copy_from(layout.line_numbers);
+ line_attribute.finish();
params.set_output("Line",
AnonymousAttributeFieldInput::Create<int>(std::move(line_id),
params.attribute_producer_name()));
@@ -349,15 +350,14 @@ static void create_attributes(GeoNodeExecParams &params,
if (params.output_is_required("Pivot Point")) {
StrongAnonymousAttributeID pivot_id = StrongAnonymousAttributeID("Pivot");
- OutputAttribute_Typed<float3> pivot_attribute =
- instances.attribute_try_get_for_output_only<float3>(pivot_id.get(), ATTR_DOMAIN_INSTANCE);
- MutableSpan<float3> pivots = pivot_attribute.as_span();
+ SpanAttributeWriter<float3> pivot_attribute =
+ attributes.lookup_or_add_for_write_only_span<float3>(pivot_id.get(), ATTR_DOMAIN_INSTANCE);
for (const int i : layout.char_codes.index_range()) {
- pivots[i] = layout.pivot_points.lookup(layout.char_codes[i]);
+ pivot_attribute.span[i] = layout.pivot_points.lookup(layout.char_codes[i]);
}
- pivot_attribute.save();
+ pivot_attribute.finish();
params.set_output("Pivot Point",
AnonymousAttributeFieldInput::Create<float3>(
std::move(pivot_id), params.attribute_producer_name()));
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 9eda5bb34ff..eda6a51d412 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -6,6 +6,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
+#include "BKE_attribute.hh"
#include "BKE_mesh.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_mesh.h"
@@ -79,10 +80,11 @@ static void write_vertex_creases(Mesh &mesh, const VArray<float> &crease_varray)
static void write_edge_creases(MeshComponent &mesh, const VArray<float> &crease_varray)
{
- OutputAttribute_Typed<float> attribute = mesh.attribute_try_get_for_output_only<float>(
- "crease", ATTR_DOMAIN_EDGE);
- materialize_and_clamp_creases(crease_varray, attribute.as_span());
- attribute.save();
+ bke::SpanAttributeWriter<float> attribute =
+ mesh.attributes_for_write()->lookup_or_add_for_write_only_span<float>("crease",
+ ATTR_DOMAIN_EDGE);
+ materialize_and_clamp_creases(crease_varray, attribute.span);
+ attribute.finish();
}
static bool varray_is_nonzero(const VArray<float> &varray)
@@ -118,8 +120,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
- const int verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
- const int edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
+ const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
if (verts_num == 0 || edges_num == 0) {
return;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index 0af6c76feaf..cd75822f665 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -365,7 +365,7 @@ static bool component_is_available(const GeometrySet &geometry,
if (component.is_empty()) {
return false;
}
- return component.attribute_domain_num(domain) != 0;
+ return component.attribute_domain_size(domain) != 0;
}
/**
@@ -433,7 +433,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
{
const MeshComponent &mesh_component = *source_.get_component_for_read<MeshComponent>();
source_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_num = mesh_component.attribute_domain_num(domain_);
+ const int domain_num = mesh_component.attribute_domain_size(domain_);
source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_num);
source_evaluator_->add(src_field_);
source_evaluator_->evaluate();
@@ -578,7 +578,7 @@ class NearestTransferFunction : public fn::MultiFunction {
{
if (use_mesh_) {
const MeshComponent &mesh = *source_.get_component_for_read<MeshComponent>();
- const int domain_num = mesh.attribute_domain_num(domain_);
+ const int domain_num = mesh.attribute_domain_size(domain_);
mesh_context_.emplace(GeometryComponentFieldContext(mesh, domain_));
mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_num);
mesh_evaluator_->add(src_field_);
@@ -588,7 +588,7 @@ class NearestTransferFunction : public fn::MultiFunction {
if (use_points_) {
const PointCloudComponent &points = *source_.get_component_for_read<PointCloudComponent>();
- const int domain_num = points.attribute_domain_num(domain_);
+ const int domain_num = points.attribute_domain_size(domain_);
point_context_.emplace(GeometryComponentFieldContext(points, domain_));
point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, domain_num);
point_evaluator_->add(src_field_);
@@ -658,7 +658,7 @@ class IndexTransferFunction : public fn::MultiFunction {
if (component == nullptr) {
return;
}
- const int domain_num = component->attribute_domain_num(domain_);
+ const int domain_num = component->attribute_domain_size(domain_);
geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_));
evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_num);
evaluator_->add(src_field_);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index e47dc22da04..992470e8279 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -83,9 +83,9 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometryComponent &component = geometry_set.get_component_for_write<MeshComponent>();
const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
- FieldEvaluator evaluator{context, domain_num};
+ FieldEvaluator evaluator{context, domain_size};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
index feff6efc3f8..17413e64f7d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
@@ -40,7 +40,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
return {};
}
- const int face_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
FieldEvaluator face_evaluator{face_context, face_num};
face_evaluator.add(selection_field);
@@ -50,7 +50,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
return {};
}
- const int corner_num = component.attribute_domain_num(ATTR_DOMAIN_CORNER);
+ const int corner_num = component.attribute_domain_size(ATTR_DOMAIN_CORNER);
GeometryComponentFieldContext corner_context{component, ATTR_DOMAIN_CORNER};
FieldEvaluator evaluator{corner_context, corner_num};
Array<float3> uv(corner_num);
@@ -88,7 +88,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
index 364106455b6..2ec14ad2d29 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
@@ -65,7 +65,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
return {};
}
- const int face_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
FieldEvaluator face_evaluator{face_context, face_num};
face_evaluator.add(selection_field);
@@ -75,7 +75,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
return {};
}
- const int edge_num = component.attribute_domain_num(ATTR_DOMAIN_EDGE);
+ const int edge_num = component.attribute_domain_size(ATTR_DOMAIN_EDGE);
GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
FieldEvaluator edge_evaluator{edge_context, edge_num};
edge_evaluator.add(seam_field);
@@ -126,7 +126,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
}
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 85dfdf03b82..cf7cbbdc4bf 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -228,7 +228,7 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
all_component_types,
true,
[&](const bke::AttributeIDRef &attribute_id,
- const AttributeMetaData &meta_data,
+ const bke::AttributeMetaData &meta_data,
const GeometryComponent &UNUSED(component)) {
if (attribute_id.is_named() && names.add(attribute_id.name())) {
this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type});
@@ -241,21 +241,21 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
case GEO_COMPONENT_TYPE_MESH: {
const MeshComponent &mesh_component = *(const MeshComponent *)component;
MeshInfo &info = this->mesh_info.emplace();
- info.verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
- info.edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
- info.faces_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ info.verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ info.edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ info.faces_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE);
break;
}
case GEO_COMPONENT_TYPE_CURVE: {
const CurveComponent &curve_component = *(const CurveComponent *)component;
CurveInfo &info = this->curve_info.emplace();
- info.splines_num = curve_component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ info.splines_num = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
break;
}
case GEO_COMPONENT_TYPE_POINT_CLOUD: {
const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component;
PointCloudInfo &info = this->pointcloud_info.emplace();
- info.points_num = pointcloud_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ info.points_num = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT);
break;
}
case GEO_COMPONENT_TYPE_INSTANCES: {