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/blenkernel
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/blenkernel')
-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
22 files changed, 1889 insertions, 1969 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
{