diff options
41 files changed, 1305 insertions, 1702 deletions
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 120b4e08b9c..f6a6de04b70 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -20,6 +20,7 @@ #include "FN_cpp_type.hh" #include "FN_generic_span.hh" +#include "FN_generic_virtual_array.hh" #include "BKE_attribute.h" @@ -30,6 +31,10 @@ namespace blender::bke { using fn::CPPType; +using fn::GVArray; +using fn::GVArrayPtr; +using fn::GVMutableArray; +using fn::GVMutableArrayPtr; const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); CustomDataType cpp_type_to_custom_data_type(const CPPType &type); @@ -37,113 +42,93 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains); /** - * This class offers an indirection for reading an attribute. - * This is useful for the following reasons: - * - Blender does not store all attributes the same way. - * The simplest case are custom data layers with primitive types. - * A bit more complex are mesh attributes like the position of vertices, - * which are embedded into the MVert struct. - * Even more complex to access are vertex weights. - * - Sometimes attributes are stored on one domain, but we want to access - * the attribute on a different domain. Therefore, we have to interpolate - * between the domains. + * Used when looking up a "plain attribute" based on a name for reading from it. */ -class ReadAttribute { - protected: - const AttributeDomain domain_; - const CPPType &cpp_type_; - const CustomDataType custom_data_type_; - const int64_t size_; - - /* Protects the span below, so that no two threads initialize it at the same time. */ - mutable std::mutex span_mutex_; - /* When it is not null, it points to the attribute array or a temporary array that contains all - * the attribute values. */ - mutable void *array_buffer_ = nullptr; - /* Is true when the buffer above is owned by the attribute accessor. */ - mutable bool array_is_temporary_ = false; +struct ReadAttributeLookup { + /* The virtual array that is used to read from this attribute. */ + GVArrayPtr varray; + /* Domain the attribute lives on in the geometry. */ + AttributeDomain domain; - public: - ReadAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size) - : domain_(domain), - cpp_type_(cpp_type), - custom_data_type_(cpp_type_to_custom_data_type(cpp_type)), - size_(size) + /* Convenience function to check if the attribute has been found. */ + operator bool() const { + return this->varray.get() != nullptr; } +}; - virtual ~ReadAttribute(); +/** + * 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. */ + GVMutableArrayPtr varray; + /* Domain the attributes lives on in the geometry. */ + AttributeDomain domain; - AttributeDomain domain() const + /* Convenience function to check if the attribute has been found. */ + operator bool() const { - return domain_; + return this->varray.get() != nullptr; } +}; - const CPPType &cpp_type() const - { - return cpp_type_; - } +/** + * 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 + * VMutableArray_Span 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. + */ +class OutputAttribute { + public: + using SaveFn = std::function<void(OutputAttribute &)>; - CustomDataType custom_data_type() const + private: + GVMutableArrayPtr varray_; + AttributeDomain domain_; + SaveFn save_; + std::optional<fn::GVMutableArray_GSpan> optional_span_varray_; + bool ignore_old_values_ = false; + + public: + OutputAttribute() = default; + + OutputAttribute(GVMutableArrayPtr varray, + AttributeDomain domain, + SaveFn save, + const bool ignore_old_values) + : varray_(std::move(varray)), + domain_(domain), + save_(std::move(save)), + ignore_old_values_(ignore_old_values) { - return custom_data_type_; } - int64_t size() const + operator bool() const { - return size_; + return varray_.get() != nullptr; } - void get(const int64_t index, void *r_value) const + GVMutableArray &operator*() { - BLI_assert(index < size_); - this->get_internal(index, r_value); + return *varray_; } - /* Get a span that contains all attribute values. */ - fn::GSpan get_span() const; - - template<typename T> Span<T> get_span() const + GVMutableArray *operator->() { - return this->get_span().typed<T>(); + return varray_.get(); } - protected: - /* r_value is expected to be uninitialized. */ - virtual void get_internal(const int64_t index, void *r_value) const = 0; - - virtual void initialize_span() const; -}; - -/** - * This exists for similar reasons as the ReadAttribute class, except that - * it does not deal with interpolation between domains. - */ -class WriteAttribute { - protected: - const AttributeDomain domain_; - const CPPType &cpp_type_; - const CustomDataType custom_data_type_; - const int64_t size_; - - /* When not null, this points either to the attribute array or to a temporary array. */ - void *array_buffer_ = nullptr; - /* True, when the buffer points to a temporary array. */ - bool array_is_temporary_ = false; - /* This helps to protect against forgetting to apply changes done to the array. */ - bool array_should_be_applied_ = false; - - public: - WriteAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size) - : domain_(domain), - cpp_type_(cpp_type), - custom_data_type_(cpp_type_to_custom_data_type(cpp_type)), - size_(size) + GVMutableArray &varray() { + return *varray_; } - virtual ~WriteAttribute(); - AttributeDomain domain() const { return domain_; @@ -151,168 +136,94 @@ class WriteAttribute { const CPPType &cpp_type() const { - return cpp_type_; + return varray_->type(); } CustomDataType custom_data_type() const { - return custom_data_type_; - } - - int64_t size() const - { - return size_; - } - - void get(const int64_t index, void *r_value) const - { - BLI_assert(index < size_); - this->get_internal(index, r_value); + return cpp_type_to_custom_data_type(this->cpp_type()); } - void set(const int64_t index, const void *value) + fn::GMutableSpan as_span() { - BLI_assert(index < size_); - this->set_internal(index, value); + if (!optional_span_varray_.has_value()) { + const bool materialize_old_values = !ignore_old_values_; + optional_span_varray_.emplace(*varray_, materialize_old_values); + } + fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_; + return span_varray; } - /* Get a span that new attribute values can be written into. When all values have been changed, - * #apply_span has to be called. */ - fn::GMutableSpan get_span(); - /* The span returned by this method might not contain the current attribute values. */ - fn::GMutableSpan get_span_for_write_only(); - /* Write the changes to the span into the actual attribute, if they aren't already. */ - void apply_span(); - - template<typename T> MutableSpan<T> get_span() + template<typename T> MutableSpan<T> as_span() { - return this->get_span().typed<T>(); + return this->as_span().typed<T>(); } - template<typename T> MutableSpan<T> get_span_for_write_only() - { - return this->get_span_for_write_only().typed<T>(); - } - - protected: - virtual void get_internal(const int64_t index, void *r_value) const = 0; - virtual void set_internal(const int64_t index, const void *value) = 0; - - virtual void initialize_span(const bool write_only); - virtual void apply_span_if_necessary(); + void save(); }; -using ReadAttributePtr = std::unique_ptr<ReadAttribute>; -using WriteAttributePtr = std::unique_ptr<WriteAttribute>; - -/* This provides type safe access to an attribute. - * The underlying ReadAttribute is owned optionally. */ -template<typename T> class TypedReadAttribute { +/** + * Same as OutputAttribute, but should be used when the data type is known at compile time. + */ +template<typename T> class OutputAttribute_Typed { private: - std::unique_ptr<const ReadAttribute> owned_attribute_; - const ReadAttribute *attribute_; + OutputAttribute attribute_; + std::optional<fn::GVMutableArray_Typed<T>> optional_varray_; + VMutableArray<T> *varray_ = nullptr; public: - TypedReadAttribute(ReadAttributePtr attribute) : TypedReadAttribute(*attribute) + OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute)) { - owned_attribute_ = std::move(attribute); - BLI_assert(owned_attribute_); + if (attribute_) { + optional_varray_.emplace(attribute_.varray()); + varray_ = &**optional_varray_; + } } - TypedReadAttribute(const ReadAttribute &attribute) : attribute_(&attribute) + operator bool() const { - BLI_assert(attribute_->cpp_type().is<T>()); + return varray_ != nullptr; } - int64_t size() const + VMutableArray<T> &operator*() { - return attribute_->size(); + return *varray_; } - T operator[](const int64_t index) const + VMutableArray<T> *operator->() { - BLI_assert(index < attribute_->size()); - T value; - value.~T(); - attribute_->get(index, &value); - return value; + return varray_; } - /* Get a span to that contains all attribute values for faster and more convenient access. */ - Span<T> get_span() const + VMutableArray<T> &varray() { - return attribute_->get_span().template typed<T>(); + return *varray_; } -}; -/* This provides type safe access to an attribute. - * The underlying WriteAttribute is owned optionally. */ -template<typename T> class TypedWriteAttribute { - private: - std::unique_ptr<WriteAttribute> owned_attribute_; - WriteAttribute *attribute_; - - public: - TypedWriteAttribute(WriteAttributePtr attribute) : TypedWriteAttribute(*attribute) - { - owned_attribute_ = std::move(attribute); - BLI_assert(owned_attribute_); - } - - TypedWriteAttribute(WriteAttribute &attribute) : attribute_(&attribute) - { - BLI_assert(attribute_->cpp_type().is<T>()); - } - - int64_t size() const + AttributeDomain domain() const { - return attribute_->size(); + return attribute_.domain(); } - T operator[](const int64_t index) const + const CPPType &cpp_type() const { - BLI_assert(index < attribute_->size()); - T value; - value.~T(); - attribute_->get(index, &value); - return value; + return CPPType::get<T>(); } - void set(const int64_t index, const T &value) + CustomDataType custom_data_type() const { - attribute_->set(index, &value); + return cpp_type_to_custom_data_type(this->cpp_type()); } - /* Get a span that new values can be written into. Once all values have been updated #apply_span - * has to be called. */ - MutableSpan<T> get_span() + MutableSpan<T> as_span() { - return attribute_->get_span().typed<T>(); - } - /* The span returned by this method might not contain the current attribute values. */ - MutableSpan<T> get_span_for_write_only() - { - return attribute_->get_span_for_write_only().typed<T>(); + return attribute_.as_span<T>(); } - /* Write back all changes to the actual attribute, if necessary. */ - void apply_span() + void save() { - attribute_->apply_span(); + attribute_.save(); } }; -using BooleanReadAttribute = TypedReadAttribute<bool>; -using FloatReadAttribute = TypedReadAttribute<float>; -using Float2ReadAttribute = TypedReadAttribute<float2>; -using Float3ReadAttribute = TypedReadAttribute<float3>; -using Int32ReadAttribute = TypedReadAttribute<int>; -using Color4fReadAttribute = TypedReadAttribute<Color4f>; -using BooleanWriteAttribute = TypedWriteAttribute<bool>; -using FloatWriteAttribute = TypedWriteAttribute<float>; -using Float2WriteAttribute = TypedWriteAttribute<float2>; -using Float3WriteAttribute = TypedWriteAttribute<float3>; -using Int32WriteAttribute = TypedWriteAttribute<int>; -using Color4fWriteAttribute = TypedWriteAttribute<Color4f>; - } // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index d94b2e7902b..f5041d2bf5f 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -56,60 +56,6 @@ class ComponentAttributeProviders; class GeometryComponent; /** - * An #OutputAttributePtr wraps a #WriteAttributePtr that might not be stored in its final - * destination yet. Therefore, once the attribute has been filled with data, the #save method has - * to be called, to store the attribute where it belongs (possibly by replacing an existing - * attribute with the same name). - * - * This is useful for example in the Attribute Color Ramp node, when the same attribute name is - * used as input and output. Typically the input is a float attribute, and the output is a color. - * Those two attributes cannot exist at the same time, due to a name collision. To handle this - * situation well, first the output colors have to be computed before the input floats are deleted. - * Therefore, the outputs have to be written to a temporary buffer that replaces the existing - * attribute once all computations are done. - */ -class OutputAttributePtr { - private: - blender::bke::WriteAttributePtr attribute_; - - public: - OutputAttributePtr() = default; - OutputAttributePtr(blender::bke::WriteAttributePtr attribute); - OutputAttributePtr(GeometryComponent &component, - AttributeDomain domain, - std::string name, - CustomDataType data_type); - - ~OutputAttributePtr(); - - /* Returns false, when this wrapper is empty. */ - operator bool() const - { - return static_cast<bool>(attribute_); - } - - /* Get a reference to the underlying #WriteAttribute. */ - blender::bke::WriteAttribute &get() - { - BLI_assert(attribute_); - return *attribute_; - } - - blender::bke::WriteAttribute &operator*() - { - return *attribute_; - } - - blender::bke::WriteAttribute *operator->() - { - return attribute_.get(); - } - - void save(); - void apply_span_and_save(); -}; - -/** * 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, ...). @@ -161,21 +107,25 @@ class GeometryComponent { /* Can only be used with supported domain types. */ virtual int attribute_domain_size(const AttributeDomain domain) const; + bool attribute_is_builtin(const blender::StringRef attribute_name) const; + /* Get read-only access to the highest priority attribute with the given name. * Returns null if the attribute does not exist. */ - blender::bke::ReadAttributePtr attribute_try_get_for_read( + blender::bke::ReadAttributeLookup attribute_try_get_for_read( const blender::StringRef attribute_name) const; /* Get read and write access to the highest priority attribute with the given name. * Returns null if the attribute does not exist. */ - blender::bke::WriteAttributePtr attribute_try_get_for_write( + blender::bke::WriteAttributeLookup attribute_try_get_for_write( const blender::StringRef attribute_name); /* Get a read-only attribute for the domain based on the given attribute. This can be used to * interpolate from one domain to another. * Returns null if the interpolation is not implemented. */ - virtual blender::bke::ReadAttributePtr attribute_try_adapt_domain( - blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const; + virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( + std::unique_ptr<blender::fn::GVArray> varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const; /* Returns true when the attribute has been deleted. */ bool attribute_try_delete(const blender::StringRef attribute_name); @@ -185,80 +135,94 @@ class GeometryComponent { const AttributeDomain domain, const CustomDataType data_type); + /* 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); + blender::Set<std::string> attribute_names() const; bool attribute_foreach(const AttributeForeachCallback callback) const; virtual bool is_empty() const; - /* Get a read-only attribute for the given domain and data type. - * Returns null when it does not exist. */ - blender::bke::ReadAttributePtr attribute_try_get_for_read( + /* Get a virtual array to read the data of an attribute on the given domain and data type. + * Returns null when the attribute does not exist or cannot be converted to the requested domain + * and data type. */ + std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type) const; - /* Get a read-only attribute interpolated to the input domain, leaving the data type unchanged. - * Returns null when the attribute does not exist. */ - blender::bke::ReadAttributePtr attribute_try_get_for_read( + /* Get a virtual array to read the data of an attribute on the given domain. The data type is + * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the + * requested domain. */ + std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( const blender::StringRef attribute_name, const AttributeDomain domain) const; - /* Get a read-only attribute for the given domain and data type. - * Returns a constant attribute based on the default value if the attribute does not exist. - * Never returns null. */ - blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) const; - - /* Get a typed read-only attribute for the given domain and type. */ - template<typename T> - blender::bke::TypedReadAttribute<T> attribute_get_for_read( + /* Get a virtual array to read the data of an attribute. If that is not possible, the returned + * virtual array will contain a default value. This never returns null. */ + std::unique_ptr<blender::fn::GVArray> attribute_get_for_read( const blender::StringRef attribute_name, const AttributeDomain domain, - const T &default_value) const + const CustomDataType data_type, + const void *default_value = nullptr) const; + + /* Should be used instead of the method above when the requested data type is known at compile + * time for better type safety. */ + template<typename T> + blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name, + const AttributeDomain domain, + const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - return this->attribute_get_for_read(attribute_name, domain, type, &default_value); + std::unique_ptr varray = this->attribute_get_for_read( + attribute_name, domain, type, &default_value); + return blender::fn::GVArray_Typed<T>(std::move(varray)); } - /* Get a read-only dummy attribute that always returns the same value. */ - blender::bke::ReadAttributePtr attribute_get_constant_for_read(const AttributeDomain domain, - const CustomDataType data_type, - const void *value) const; + /** + * Returns an "output attribute", which is essentially a mutable virtual array with some commonly + * used convience 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::StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value = nullptr); - /* Create a read-only dummy attribute that always returns the same value. - * The given value is converted to the correct type if necessary. */ - blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted( + /* 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. Since values are not read + * from this attribute, no default value is necessary. */ + blender::bke::OutputAttribute attribute_try_get_for_output_only( + const blender::StringRef attribute_name, const AttributeDomain domain, - const CustomDataType in_data_type, - const CustomDataType out_data_type, - const void *value) const; + const CustomDataType data_type); - /* Get a read-only dummy attribute that always returns the same value. */ + /* Statically typed method corresponding to the equally named generic one. */ template<typename T> - blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain, - const T &value) const + blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output( + const blender::StringRef attribute_name, const AttributeDomain domain, const T default_value) { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); - const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - return this->attribute_get_constant_for_read(domain, type, &value); + const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + return this->attribute_try_get_for_output(attribute_name, domain, data_type, &default_value); } - /** - * If an attribute with the given params exist, it is returned. - * If no attribute with the given name exists, create it and - * fill it with the default value if it is provided. - * If an attribute with the given name but different domain or type exists, a temporary attribute - * is created that has to be saved after the output has been computed. This avoids deleting - * another attribute, before a computation is finished. - * - * This might return no attribute when the attribute cannot exist on the component. - */ - OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value = nullptr); + /* Statically typed method corresponding to the equally named generic one. */ + template<typename T> + blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only( + const blender::StringRef attribute_name, const AttributeDomain domain) + { + const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); + const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type); + return this->attribute_try_get_for_output_only(attribute_name, domain, data_type); + } private: virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const; @@ -377,8 +341,10 @@ class MeshComponent : public GeometryComponent { Mesh *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - blender::bke::ReadAttributePtr attribute_try_adapt_domain( - blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const final; + std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( + std::unique_ptr<blender::fn::GVArray> varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; bool is_empty() const final; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index ac582fc30e7..70572e446b7 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -44,196 +44,10 @@ using blender::float3; using blender::Set; using blender::StringRef; using blender::StringRefNull; -using blender::bke::ReadAttributePtr; -using blender::bke::WriteAttributePtr; using blender::fn::GMutableSpan; namespace blender::bke { -/* -------------------------------------------------------------------- */ -/** \name Attribute Accessor implementations - * \{ */ - -ReadAttribute::~ReadAttribute() -{ - if (array_is_temporary_ && array_buffer_ != nullptr) { - cpp_type_.destruct_n(array_buffer_, size_); - MEM_freeN(array_buffer_); - } -} - -fn::GSpan ReadAttribute::get_span() const -{ - if (size_ == 0) { - return fn::GSpan(cpp_type_); - } - if (array_buffer_ == nullptr) { - std::lock_guard lock{span_mutex_}; - if (array_buffer_ == nullptr) { - this->initialize_span(); - } - } - return fn::GSpan(cpp_type_, array_buffer_, size_); -} - -void ReadAttribute::initialize_span() const -{ - const int element_size = cpp_type_.size(); - array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__); - array_is_temporary_ = true; - for (const int i : IndexRange(size_)) { - this->get_internal(i, POINTER_OFFSET(array_buffer_, i * element_size)); - } -} - -WriteAttribute::~WriteAttribute() -{ - if (array_should_be_applied_) { - CLOG_ERROR(&LOG, "Forgot to call apply_span."); - } - if (array_is_temporary_ && array_buffer_ != nullptr) { - cpp_type_.destruct_n(array_buffer_, size_); - MEM_freeN(array_buffer_); - } -} - -/** - * Get a mutable span that can be modified. When all modifications to the attribute are done, - * #apply_span should be called. */ -fn::GMutableSpan WriteAttribute::get_span() -{ - if (size_ == 0) { - return fn::GMutableSpan(cpp_type_); - } - if (array_buffer_ == nullptr) { - this->initialize_span(false); - } - array_should_be_applied_ = true; - return fn::GMutableSpan(cpp_type_, array_buffer_, size_); -} - -fn::GMutableSpan WriteAttribute::get_span_for_write_only() -{ - if (size_ == 0) { - return fn::GMutableSpan(cpp_type_); - } - if (array_buffer_ == nullptr) { - this->initialize_span(true); - } - array_should_be_applied_ = true; - return fn::GMutableSpan(cpp_type_, array_buffer_, size_); -} - -void WriteAttribute::initialize_span(const bool write_only) -{ - const int element_size = cpp_type_.size(); - array_buffer_ = MEM_mallocN_aligned(element_size * size_, cpp_type_.alignment(), __func__); - array_is_temporary_ = true; - if (write_only) { - /* This does nothing for trivial types, but is necessary for general correctness. */ - cpp_type_.construct_default_n(array_buffer_, size_); - } - else { - for (const int i : IndexRange(size_)) { - this->get(i, POINTER_OFFSET(array_buffer_, i * element_size)); - } - } -} - -void WriteAttribute::apply_span() -{ - this->apply_span_if_necessary(); - array_should_be_applied_ = false; -} - -void WriteAttribute::apply_span_if_necessary() -{ - /* Only works when the span has been initialized beforehand. */ - BLI_assert(array_buffer_ != nullptr); - - const int element_size = cpp_type_.size(); - for (const int i : IndexRange(size_)) { - this->set_internal(i, POINTER_OFFSET(array_buffer_, i * element_size)); - } -} - -/* This is used by the #OutputAttributePtr class. */ -class TemporaryWriteAttribute final : public WriteAttribute { - public: - GMutableSpan data; - GeometryComponent &component; - std::string final_name; - - TemporaryWriteAttribute(AttributeDomain domain, - GMutableSpan data, - GeometryComponent &component, - std::string final_name) - : WriteAttribute(domain, data.type(), data.size()), - data(data), - component(component), - final_name(std::move(final_name)) - { - } - - ~TemporaryWriteAttribute() override - { - if (data.data() != nullptr) { - cpp_type_.destruct_n(data.data(), data.size()); - MEM_freeN(data.data()); - } - } - - void get_internal(const int64_t index, void *r_value) const override - { - data.type().copy_to_uninitialized(data[index], r_value); - } - - void set_internal(const int64_t index, const void *value) override - { - data.type().copy_to_initialized(value, data[index]); - } - - void initialize_span(const bool UNUSED(write_only)) override - { - array_buffer_ = data.data(); - array_is_temporary_ = false; - } - - void apply_span_if_necessary() override - { - /* Do nothing, because the span contains the attribute itself already. */ - } -}; - -class ConvertedReadAttribute final : public ReadAttribute { - private: - const CPPType &from_type_; - const CPPType &to_type_; - ReadAttributePtr base_attribute_; - void (*convert_)(const void *src, void *dst); - - public: - ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type) - : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()), - from_type_(base_attribute->cpp_type()), - to_type_(to_type), - base_attribute_(std::move(base_attribute)) - { - const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions(); - convert_ = conversions.get_conversion_functions(base_attribute_->cpp_type(), to_type) - ->convert_single_to_uninitialized; - } - - void get_internal(const int64_t index, void *r_value) const override - { - BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - base_attribute_->get(index, buffer); - convert_(buffer, r_value); - } -}; - -/** \} */ - const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type) { switch (type) { @@ -368,7 +182,17 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) return highest_priority_domain; } -ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read( +void OutputAttribute::save() +{ + if (optional_span_varray_.has_value()) { + optional_span_varray_->save(); + } + if (save_) { + save_(*this); + } +} + +GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read( const GeometryComponent &component) const { const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); @@ -384,7 +208,7 @@ ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read( return as_read_attribute_(data, domain_size); } -WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write( +GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write( GeometryComponent &component) const { if (writable_ != Writable) { @@ -463,7 +287,7 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) return data != nullptr; } -ReadAttributePtr CustomDataAttributeProvider::try_get_for_read( +ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( const GeometryComponent &component, const StringRef attribute_name) const { const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); @@ -496,7 +320,7 @@ ReadAttributePtr CustomDataAttributeProvider::try_get_for_read( return {}; } -WriteAttributePtr CustomDataAttributeProvider::try_get_for_write( +WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write( GeometryComponent &component, const StringRef attribute_name) const { CustomData *custom_data = custom_data_access_.get_custom_data(component); @@ -595,7 +419,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com return true; } -ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read( +ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read( const GeometryComponent &component, const StringRef attribute_name) const { const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); @@ -606,14 +430,14 @@ ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read( if (layer.type == stored_type_) { if (layer.name == attribute_name) { const int domain_size = component.attribute_domain_size(domain_); - return as_read_attribute_(layer.data, domain_size); + return {as_read_attribute_(layer.data, domain_size), domain_}; } } } return {}; } -WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write( +WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write( GeometryComponent &component, const StringRef attribute_name) const { CustomData *custom_data = custom_data_access_.get_custom_data(component); @@ -630,7 +454,7 @@ WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write( if (data_old != data_new) { custom_data_access_.update_custom_data_pointers(component); } - return as_write_attribute_(layer.data, domain_size); + return {as_write_attribute_(layer.data, domain_size), domain_}; } } } @@ -708,7 +532,17 @@ int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain return 0; } -ReadAttributePtr GeometryComponent::attribute_try_get_for_read( +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); +} + +blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( const StringRef attribute_name) const { using namespace blender::bke; @@ -719,11 +553,11 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read( const BuiltinAttributeProvider *builtin_provider = providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr); if (builtin_provider != nullptr) { - return builtin_provider->try_get_for_read(*this); + return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()}; } for (const DynamicAttributesProvider *dynamic_provider : providers->dynamic_attribute_providers()) { - ReadAttributePtr attribute = dynamic_provider->try_get_for_read(*this, attribute_name); + ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_name); if (attribute) { return attribute; } @@ -731,16 +565,19 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read( return {}; } -ReadAttributePtr GeometryComponent::attribute_try_adapt_domain( - ReadAttributePtr attribute, const AttributeDomain new_domain) const +std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain( + std::unique_ptr<blender::fn::GVArray> varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const { - if (attribute && attribute->domain() == new_domain) { - return attribute; + if (from_domain == to_domain) { + return varray; } return {}; } -WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef attribute_name) +blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write( + const StringRef attribute_name) { using namespace blender::bke; const ComponentAttributeProviders *providers = this->get_attribute_providers(); @@ -750,11 +587,11 @@ WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef const BuiltinAttributeProvider *builtin_provider = providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr); if (builtin_provider != nullptr) { - return builtin_provider->try_get_for_write(*this); + return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()}; } for (const DynamicAttributesProvider *dynamic_provider : providers->dynamic_attribute_providers()) { - WriteAttributePtr attribute = dynamic_provider->try_get_for_write(*this, attribute_name); + WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_name); if (attribute) { return attribute; } @@ -814,6 +651,24 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name, return false; } +bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name) +{ + 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); +} + Set<std::string> GeometryComponent::attribute_names() const { Set<std::string> attributes; @@ -867,264 +722,234 @@ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const { - ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name); + blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name); if (attribute) { return true; } return false; } -static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute, - const blender::fn::CPPType &to_type) +static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type( + std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type) { - const blender::fn::CPPType &from_type = attribute->cpp_type(); - if (from_type == to_type) { - return attribute; - } - const blender::nodes::DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - if (!conversions.is_convertible(from_type, to_type)) { - return {}; - } - - return std::make_unique<blender::bke::ConvertedReadAttribute>(std::move(attribute), to_type); + return conversions.try_convert(std::move(varray), to_type); } -ReadAttributePtr GeometryComponent::attribute_try_get_for_read( +std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read( const StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type) const { - ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name); + blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name); if (!attribute) { return {}; } - if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) { - attribute = this->attribute_try_adapt_domain(std::move(attribute), domain); - if (!attribute) { + std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray); + if (domain != ATTR_DOMAIN_AUTO && attribute.domain != domain) { + varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain); + if (!varray) { return {}; } } const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); - if (attribute->cpp_type() != *cpp_type) { - attribute = try_adapt_data_type(std::move(attribute), *cpp_type); - if (!attribute) { + if (varray->type() != *cpp_type) { + varray = try_adapt_data_type(std::move(varray), *cpp_type); + if (!varray) { return {}; } } - return attribute; + return varray; } -ReadAttributePtr GeometryComponent::attribute_try_get_for_read(const StringRef attribute_name, - const AttributeDomain domain) const +std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read( + const StringRef attribute_name, const AttributeDomain domain) const { if (!this->attribute_domain_supported(domain)) { return {}; } - ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name); + blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name); if (!attribute) { return {}; } - if (attribute->domain() != domain) { - attribute = this->attribute_try_adapt_domain(std::move(attribute), domain); - if (!attribute) { - return {}; - } + if (attribute.domain != domain) { + return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain); } - return attribute; + return std::move(attribute.varray); } -ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) const -{ - ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type); - if (attribute) { - return attribute; - } - return this->attribute_get_constant_for_read(domain, data_type, default_value); -} - -blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read( - const AttributeDomain domain, const CustomDataType data_type, const void *value) const -{ - BLI_assert(this->attribute_domain_supported(domain)); - const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); - BLI_assert(cpp_type != nullptr); - if (value == nullptr) { - value = cpp_type->default_value(); - } - const int domain_size = this->attribute_domain_size(domain); - return std::make_unique<blender::bke::ConstantReadAttribute>( - domain, domain_size, *cpp_type, value); -} - -blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read_converted( +std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read( + const StringRef attribute_name, const AttributeDomain domain, - const CustomDataType in_data_type, - const CustomDataType out_data_type, - const void *value) const + const CustomDataType data_type, + const void *default_value) const { - BLI_assert(this->attribute_domain_supported(domain)); - if (value == nullptr || in_data_type == out_data_type) { - return this->attribute_get_constant_for_read(domain, out_data_type, value); + std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read( + attribute_name, domain, data_type); + if (varray) { + return varray; + } + const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); + if (default_value == nullptr) { + default_value = type->default_value(); } - - const blender::fn::CPPType *in_cpp_type = blender::bke::custom_data_type_to_cpp_type( - in_data_type); - const blender::fn::CPPType *out_cpp_type = blender::bke::custom_data_type_to_cpp_type( - out_data_type); - BLI_assert(in_cpp_type != nullptr); - BLI_assert(out_cpp_type != nullptr); - - const blender::nodes::DataTypeConversions &conversions = - blender::nodes::get_implicit_type_conversions(); - BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type)); - - void *out_value = alloca(out_cpp_type->size()); - conversions.convert_to_uninitialized(*in_cpp_type, *out_cpp_type, value, out_value); - const int domain_size = this->attribute_domain_size(domain); - blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>( - domain, domain_size, *out_cpp_type, out_value); - - out_cpp_type->destruct(out_value); - return attribute; + return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value); } -OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) -{ - const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); - BLI_assert(cpp_type != nullptr); - - WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name); +class GVMutableAttribute_For_OutputAttribute + : public blender::fn::GVMutableArray_For_GMutableSpan { + public: + GeometryComponent *component; + std::string final_name; - /* If the attribute doesn't exist, make a new one with the correct type. */ - if (!attribute) { - this->attribute_try_create(attribute_name, domain, data_type); - attribute = this->attribute_try_get_for_write(attribute_name); - if (attribute && default_value != nullptr) { - void *data = attribute->get_span_for_write_only().data(); - cpp_type->fill_initialized(default_value, data, attribute->size()); - attribute->apply_span(); - } - return OutputAttributePtr(std::move(attribute)); + GVMutableAttribute_For_OutputAttribute(GMutableSpan data, + GeometryComponent &component, + std::string final_name) + : blender::fn::GVMutableArray_For_GMutableSpan(data), + component(&component), + final_name(std::move(final_name)) + { } - /* If an existing attribute has a matching domain and type, just use that. */ - if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) { - return OutputAttributePtr(std::move(attribute)); + ~GVMutableAttribute_For_OutputAttribute() override + { + type_->destruct_n(data_, size_); + MEM_freeN(data_); } +}; - /* Otherwise create a temporary buffer to use before saving the new attribute. */ - return OutputAttributePtr(*this, domain, attribute_name, data_type); -} - -/* Construct from an attribute that already exists in the geometry component. */ -OutputAttributePtr::OutputAttributePtr(WriteAttributePtr attribute) - : attribute_(std::move(attribute)) +static void save_output_attribute(blender::bke::OutputAttribute &output_attribute) { -} + using namespace blender; + using namespace blender::fn; + using namespace blender::bke; -/* Construct a temporary attribute that has to replace an existing one later on. */ -OutputAttributePtr::OutputAttributePtr(GeometryComponent &component, - AttributeDomain domain, - std::string final_name, - CustomDataType data_type) -{ - const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); - BLI_assert(cpp_type != nullptr); + GVMutableAttribute_For_OutputAttribute &varray = + dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray()); - const int domain_size = component.attribute_domain_size(domain); - void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__); - GMutableSpan new_span{*cpp_type, buffer, domain_size}; + GeometryComponent &component = *varray.component; + const StringRefNull name = varray.final_name; + const AttributeDomain domain = output_attribute.domain(); + const CustomDataType data_type = output_attribute.custom_data_type(); + const CPPType &cpp_type = output_attribute.cpp_type(); - /* Copy converted values from conflicting attribute, in case the value is read. - * TODO: An optimization could be to not do this, when the caller says that the attribute will - * only be written. */ - ReadAttributePtr src_attribute = component.attribute_get_for_read( - final_name, domain, data_type, nullptr); - for (const int i : blender::IndexRange(domain_size)) { - src_attribute->get(i, new_span[i]); + component.attribute_try_delete(name); + if (!component.attribute_try_create(varray.final_name, domain, data_type)) { + CLOG_WARN(&LOG, + "Could not create the '%s' attribute with type '%s'.", + name.c_str(), + cpp_type.name().c_str()); + return; + } + WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name); + 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); } - - attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>( - domain, new_span, component, std::move(final_name)); } -/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This - * might delete another attribute with the same name. */ -void OutputAttributePtr::save() +static blender::bke::OutputAttribute create_output_attribute( + GeometryComponent &component, + const blender::StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type, + const bool ignore_old_values, + const void *default_value) { - if (!attribute_) { - CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore."); - return; - } - - blender::bke::TemporaryWriteAttribute *attribute = - dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get()); + using namespace blender; + using namespace blender::fn; + using namespace blender::bke; - if (attribute == nullptr) { - /* The attribute is saved already. */ - attribute_.reset(); - return; + if (attribute_name.is_empty()) { + return {}; } - StringRefNull name = attribute->final_name; - const blender::fn::CPPType &cpp_type = attribute->cpp_type(); - - /* Delete an existing attribute with the same name if necessary. */ - attribute->component.attribute_try_delete(name); + const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type); + BLI_assert(cpp_type != nullptr); + const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions(); - if (!attribute->component.attribute_try_create( - name, attribute_->domain(), attribute_->custom_data_type())) { - /* Cannot create the target attribute for some reason. */ - CLOG_WARN(&LOG, - "Creating the '%s' attribute with type '%s' failed.", - name.c_str(), - cpp_type.name().c_str()); - attribute_.reset(); - return; + if (component.attribute_is_builtin(attribute_name)) { + WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name); + if (!attribute) { + component.attribute_try_create_builtin(attribute_name); + 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 {}; + } + GVMutableArrayPtr varray = std::move(attribute.varray); + if (varray->type() == *cpp_type) { + /* Builtin attribute matches exactly. */ + return OutputAttribute(std::move(varray), domain, {}, 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, {}, ignore_old_values); } - WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name); - - GMutableSpan temp_span = attribute->data; - GMutableSpan new_span = new_attribute->get_span_for_write_only(); - BLI_assert(temp_span.size() == new_span.size()); + WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name); + if (!attribute) { + component.attribute_try_create(attribute_name, domain, data_type); + attribute = component.attribute_try_get_for_write(attribute_name); + 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, {}, ignore_old_values); + } - /* Currently we copy over the attribute. In the future we want to reuse the buffer. */ - cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size()); - new_attribute->apply_span(); + const int domain_size = component.attribute_domain_size(domain); + /* 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_size, cpp_type->alignment(), __func__); + if (ignore_old_values) { + /* This does nothing for trivially constructible types, but is necessary for correctness. */ + cpp_type->construct_default_n(data, domain); + } + else { + /* Fill the temporary array with values from the existing attribute. */ + GVArrayPtr old_varray = component.attribute_get_for_read( + attribute_name, domain, data_type, default_value); + old_varray->materialize_to_uninitialized(IndexRange(domain_size), data); + } + GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>( + GMutableSpan{*cpp_type, data, domain_size}, component, attribute_name); - attribute_.reset(); + return OutputAttribute(std::move(varray), domain, save_output_attribute, true); } -OutputAttributePtr::~OutputAttributePtr() +blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output( + const StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value) { - if (attribute_) { - CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save."); - } + return create_output_attribute(*this, attribute_name, domain, data_type, false, default_value); } -/* Utility function to call #apply_span and #save in the right order. */ -void OutputAttributePtr::apply_span_and_save() +blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only( + const blender::StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type) { - BLI_assert(attribute_); - attribute_->apply_span(); - this->save(); + return create_output_attribute(*this, attribute_name, domain, data_type, true, nullptr); } - -/** \} */ diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index 806d10e9e89..7cf585dfbfc 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -24,166 +24,8 @@ namespace blender::bke { -class ConstantReadAttribute final : public ReadAttribute { - private: - void *value_; - - public: - ConstantReadAttribute(AttributeDomain domain, - const int64_t size, - const CPPType &type, - const void *value) - : ReadAttribute(domain, type, size) - { - value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); - type.copy_to_uninitialized(value, value_); - } - - ~ConstantReadAttribute() override - { - this->cpp_type_.destruct(value_); - MEM_freeN(value_); - } - - void get_internal(const int64_t UNUSED(index), void *r_value) const override - { - this->cpp_type_.copy_to_uninitialized(value_, r_value); - } - - void initialize_span() const override - { - const int element_size = cpp_type_.size(); - array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__); - array_is_temporary_ = true; - cpp_type_.fill_uninitialized(value_, array_buffer_, size_); - } -}; - -template<typename T> class ArrayReadAttribute final : public ReadAttribute { - private: - Span<T> data_; - - public: - ArrayReadAttribute(AttributeDomain domain, Span<T> data) - : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void initialize_span() const override - { - /* The data will not be modified, so this const_cast is fine. */ - array_buffer_ = const_cast<T *>(data_.data()); - array_is_temporary_ = false; - } -}; - -template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute { - private: - Array<T> data_; - - public: - OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data) - : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data)) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void initialize_span() const override - { - /* The data will not be modified, so this const_cast is fine. */ - array_buffer_ = const_cast<T *>(data_.data()); - array_is_temporary_ = false; - } -}; - -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class DerivedArrayReadAttribute final : public ReadAttribute { - private: - Span<StructT> data_; - - public: - DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data) - : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - const StructT &struct_value = data_[index]; - const ElemT value = GetFunc(struct_value); - new (r_value) ElemT(value); - } -}; - -template<typename T> class ArrayWriteAttribute final : public WriteAttribute { - private: - MutableSpan<T> data_; - - public: - ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data) - : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void set_internal(const int64_t index, const void *value) override - { - data_[index] = *reinterpret_cast<const T *>(value); - } - - void initialize_span(const bool UNUSED(write_only)) override - { - array_buffer_ = data_.data(); - array_is_temporary_ = false; - } - - void apply_span_if_necessary() override - { - /* Do nothing, because the span contains the attribute itself already. */ - } -}; - -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, const ElemT &)> -class DerivedArrayWriteAttribute final : public WriteAttribute { - private: - MutableSpan<StructT> data_; - - public: - DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data) - : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - const StructT &struct_value = data_[index]; - const ElemT value = GetFunc(struct_value); - new (r_value) ElemT(value); - } - - void set_internal(const int64_t index, const void *value) override - { - StructT &struct_value = data_[index]; - const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value); - SetFunc(struct_value, typed_value); - } -}; +using fn::GVArrayPtr; +using fn::GVMutableArrayPtr; /** * Utility to group together multiple functions that are used to access custom data on geometry @@ -244,8 +86,8 @@ class BuiltinAttributeProvider { { } - virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0; - virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0; + virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0; + virtual GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const = 0; virtual bool try_delete(GeometryComponent &component) const = 0; virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0; virtual bool exists(const GeometryComponent &component) const = 0; @@ -272,10 +114,10 @@ class BuiltinAttributeProvider { */ class DynamicAttributesProvider { public: - virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const = 0; - virtual WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const = 0; + virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const = 0; + virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const = 0; virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0; virtual bool try_create(GeometryComponent &UNUSED(component), const StringRef UNUSED(attribute_name), @@ -309,11 +151,11 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { { } - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final; + ReadAttributeLookup try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const final; - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final; + WriteAttributeLookup try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const final; bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final; @@ -332,18 +174,21 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { private: template<typename T> - ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer, - const int domain_size) const + ReadAttributeLookup layer_to_read_attribute(const CustomDataLayer &layer, + const int domain_size) const { - return std::make_unique<ArrayReadAttribute<T>>( - domain_, Span(static_cast<const T *>(layer.data), domain_size)); + return {std::make_unique<fn::GVArray_For_Span<T>>( + Span(static_cast<const T *>(layer.data), domain_size)), + domain_}; } template<typename T> - WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const + WriteAttributeLookup layer_to_write_attribute(CustomDataLayer &layer, + const int domain_size) const { - return std::make_unique<ArrayWriteAttribute<T>>( - domain_, MutableSpan(static_cast<T *>(layer.data), domain_size)); + return {std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( + MutableSpan(static_cast<T *>(layer.data), domain_size)), + domain_}; } bool type_is_supported(CustomDataType data_type) const @@ -357,8 +202,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { */ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { private: - using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); const AttributeDomain domain_; const CustomDataType attribute_type_; const CustomDataType stored_type_; @@ -382,10 +227,10 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { { } - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final; - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final; + ReadAttributeLookup try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const final; + WriteAttributeLookup try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const final; bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final; bool foreach_attribute(const GeometryComponent &component, const AttributeForeachCallback callback) const final; @@ -398,8 +243,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { * the #MVert struct, but is exposed as float3 attribute. */ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); using UpdateOnRead = void (*)(const GeometryComponent &component); using UpdateOnWrite = void (*)(GeometryComponent &component); const CustomDataType stored_type_; @@ -430,8 +275,8 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { { } - ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final; - WriteAttributePtr try_get_for_write(GeometryComponent &component) const final; + GVArrayPtr try_get_for_read(const GeometryComponent &component) const final; + GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final; bool try_delete(GeometryComponent &component) const final; bool try_create(GeometryComponent &component) const final; bool exists(const GeometryComponent &component) const final; diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 150cc4589c8..e5accd98952 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -32,7 +32,7 @@ /* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); -using blender::bke::ReadAttributePtr; +using blender::fn::GVArray; /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation @@ -201,14 +201,14 @@ namespace blender::bke { template<typename T> static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, - const TypedReadAttribute<T> &attribute, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totvert); attribute_math::DefaultMixer<T> mixer(r_values); for (const int loop_index : IndexRange(mesh.totloop)) { - const T value = attribute[loop_index]; + const T value = old_values[loop_index]; const MLoop &loop = mesh.mloop[loop_index]; const int point_index = loop.v; mixer.mix_in(point_index, value); @@ -216,43 +216,40 @@ static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { /* We compute all interpolated values at once, because for this interpolation, one has to * iterate over all loops anyway. */ Array<T> values(mesh.totvert); - adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } template<typename T> static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, - const TypedReadAttribute<T> &attribute, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totloop); for (const int loop_index : IndexRange(mesh.totloop)) { const int vertex_index = mesh.mloop[loop_index].v; - r_values[loop_index] = attribute[vertex_index]; + r_values[loop_index] = old_values[vertex_index]; } } -static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); /* It is not strictly necessary to compute the value for all corners here. Instead one could @@ -260,11 +257,10 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, * when an algorithm only accesses very few of the corner values. However, for the algorithms * we currently have, precomputing the array is fine. Also, it is easier to implement. */ Array<T> values(mesh.totloop); - adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER, - std::move(values)); + adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); }); - return new_attribute; + return new_varray; } /** @@ -274,7 +270,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, */ template<typename T> static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, - Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totpoly); @@ -291,26 +287,24 @@ static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } template<typename T> static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, - Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totedge); @@ -332,26 +326,24 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } template<typename T> void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, - Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totvert); @@ -370,26 +362,24 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } template<typename T> void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, - const Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totloop); @@ -401,26 +391,24 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, } } -static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } template<typename T> void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, - const Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totedge); @@ -437,21 +425,19 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } /** @@ -461,7 +447,7 @@ static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, */ template<typename T> static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, - const Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totpoly); @@ -478,21 +464,19 @@ static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } /** @@ -502,7 +486,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh, */ template<typename T> static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, - const Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totedge); @@ -517,26 +501,24 @@ static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } template<typename T> void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, - const Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totloop); @@ -558,26 +540,24 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } template<typename T> static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, - const Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totvert); @@ -593,21 +573,19 @@ static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } /** @@ -617,7 +595,7 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, */ template<typename T> static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, - const Span<T> old_values, + const VArray<T> &old_values, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totpoly); @@ -634,87 +612,86 @@ static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, - ReadAttributePtr attribute) +static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray) { - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); + GVArrayPtr new_varray; + const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type()); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); + adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values); + new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); } }); - return new_attribute; + return new_varray; } } // namespace blender::bke -ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute, - const AttributeDomain new_domain) const +blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( + blender::fn::GVArrayPtr varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const { - if (!attribute) { + if (!varray) { return {}; } - if (attribute->size() == 0) { + if (varray->size() == 0) { return {}; } - const AttributeDomain old_domain = attribute->domain(); - if (old_domain == new_domain) { - return attribute; + if (from_domain == to_domain) { + return varray; } - switch (old_domain) { + switch (from_domain) { case ATTR_DOMAIN_CORNER: { - switch (new_domain) { + switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray)); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray)); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray)); default: break; } break; } case ATTR_DOMAIN_POINT: { - switch (new_domain) { + switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray)); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray)); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray)); default: break; } break; } case ATTR_DOMAIN_FACE: { - switch (new_domain) { + switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray)); case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray)); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray)); default: break; } break; } case ATTR_DOMAIN_EDGE: { - switch (new_domain) { + switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray)); case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray)); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray)); default: break; } @@ -743,25 +720,21 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com namespace blender::bke { -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - AttributeDomain Domain> -static ReadAttributePtr make_derived_read_attribute(const void *data, const int domain_size) +template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> +static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size) { - return std::make_unique<DerivedArrayReadAttribute<StructT, ElemT, GetFunc>>( - Domain, Span<StructT>((const StructT *)data, domain_size)); + return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>( + Span<StructT>((const StructT *)data, domain_size)); } template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, const ElemT &), - AttributeDomain Domain> -static WriteAttributePtr make_derived_write_attribute(void *data, const int domain_size) + void (*SetFunc)(StructT &, ElemT)> +static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size) { - return std::make_unique<DerivedArrayWriteAttribute<StructT, ElemT, GetFunc, SetFunc>>( - Domain, MutableSpan<StructT>((StructT *)data, domain_size)); + return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>( + MutableSpan<StructT>((StructT *)data, domain_size)); } static float3 get_vertex_position(const MVert &vert) @@ -769,7 +742,7 @@ static float3 get_vertex_position(const MVert &vert) return float3(vert.co); } -static void set_vertex_position(MVert &vert, const float3 &position) +static void set_vertex_position(MVert &vert, float3 position) { copy_v3_v3(vert.co, position); } @@ -787,7 +760,7 @@ static int get_material_index(const MPoly &mpoly) return static_cast<int>(mpoly.mat_nr); } -static void set_material_index(MPoly &mpoly, const int &index) +static void set_material_index(MPoly &mpoly, int index) { mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); } @@ -797,7 +770,7 @@ static bool get_shade_smooth(const MPoly &mpoly) return mpoly.flag & ME_SMOOTH; } -static void set_shade_smooth(MPoly &mpoly, const bool &value) +static void set_shade_smooth(MPoly &mpoly, bool value) { SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH); } @@ -807,7 +780,7 @@ static float2 get_loop_uv(const MLoopUV &uv) return float2(uv.uv); } -static void set_loop_uv(MLoopUV &uv, const float2 &co) +static void set_loop_uv(MLoopUV &uv, float2 co) { copy_v2_v2(uv.uv, co); } @@ -821,7 +794,7 @@ static Color4f get_loop_color(const MLoopCol &col) return linear_color; } -static void set_loop_color(MLoopCol &col, const Color4f &linear_color) +static void set_loop_color(MLoopCol &col, Color4f linear_color) { linearrgb_to_srgb_uchar4(&col.r, linear_color); } @@ -831,71 +804,62 @@ static float get_crease(const MEdge &edge) return edge.crease / 255.0f; } -static void set_crease(MEdge &edge, const float &value) +static void set_crease(MEdge &edge, float value) { edge.crease = round_fl_to_uchar_clamp(value * 255.0f); } -class VertexWeightWriteAttribute final : public WriteAttribute { +class VMutableArray_For_VertexWeights final : public VMutableArray<float> { private: MDeformVert *dverts_; const int dvert_index_; public: - VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index) - : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert), - dverts_(dverts), - dvert_index_(dvert_index) + VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index) + : VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - void get_internal(const int64_t index, void *r_value) const override + float get_impl(const int64_t index) const override { - get_internal(dverts_, dvert_index_, index, r_value); + return get_internal(dverts_, dvert_index_, index); } - void set_internal(const int64_t index, const void *value) override + void set_impl(const int64_t index, const float value) override { MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); - weight->weight = *reinterpret_cast<const float *>(value); + weight->weight = value; } - static void get_internal(const MDeformVert *dverts, - const int dvert_index, - const int64_t index, - void *r_value) + static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index) { if (dverts == nullptr) { - *(float *)r_value = 0.0f; - return; + return 0.0f; } const MDeformVert &dvert = dverts[index]; for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) { if (weight.def_nr == dvert_index) { - *(float *)r_value = weight.weight; - return; + return weight.weight; } } - *(float *)r_value = 0.0f; + return 0.0f; } }; -class VertexWeightReadAttribute final : public ReadAttribute { +class VArray_For_VertexWeights final : public VArray<float> { private: const MDeformVert *dverts_; const int dvert_index_; public: - VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index) - : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert), - dverts_(dverts), - dvert_index_(dvert_index) + VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index) + : VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - void get_internal(const int64_t index, void *r_value) const override + float get_impl(const int64_t index) const override { - VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value); + return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index); } }; @@ -904,8 +868,8 @@ class VertexWeightReadAttribute final : public ReadAttribute { */ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { public: - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final + ReadAttributeLookup try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const final { BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); @@ -917,15 +881,17 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { } if (mesh == nullptr || mesh->dvert == nullptr) { static const float default_value = 0.0f; - return std::make_unique<ConstantReadAttribute>( - ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value); + return {std::make_unique<fn::GVArray_For_SingleValueRef>( + CPPType::get<float>(), mesh->totvert, &default_value), + ATTR_DOMAIN_POINT}; } - return std::make_unique<VertexWeightReadAttribute>( - mesh->dvert, mesh->totvert, vertex_group_index); + return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>( + mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), + ATTR_DOMAIN_POINT}; } - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final + WriteAttributeLookup try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const final { BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); MeshComponent &mesh_component = static_cast<MeshComponent &>(component); @@ -946,8 +912,11 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); } - return std::make_unique<blender::bke::VertexWeightWriteAttribute>( - mesh->dvert, mesh->totvert, vertex_group_index); + return { + std::make_unique< + fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>( + mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), + ATTR_DOMAIN_POINT}; } bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final @@ -1009,7 +978,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { { } - ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final + GVArrayPtr try_get_for_read(const GeometryComponent &component) const final { const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); @@ -1022,8 +991,8 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); - return std::make_unique<ArrayReadAttribute<float3>>( - ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly)); + return std::make_unique<fn::GVArray_For_Span<float3>>( + Span<float3>((const float3 *)data, mesh->totpoly)); } Array<float3> normals(mesh->totpoly); @@ -1032,10 +1001,10 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); } - return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals)); + return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); } - WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final + GVMutableArrayPtr try_get_for_write(GeometryComponent &UNUSED(component)) const final { return {}; } @@ -1105,12 +1074,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() BuiltinAttributeProvider::Writable, BuiltinAttributeProvider::NonDeletable, point_access, - make_derived_read_attribute<MVert, float3, get_vertex_position, ATTR_DOMAIN_POINT>, - make_derived_write_attribute<MVert, - float3, - get_vertex_position, - set_vertex_position, - ATTR_DOMAIN_POINT>, + make_derived_read_attribute<MVert, float3, get_vertex_position>, + make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>, tag_normals_dirty_when_writing_position); static NormalAttributeProvider normal; @@ -1124,12 +1089,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() BuiltinAttributeProvider::Writable, BuiltinAttributeProvider::NonDeletable, face_access, - make_derived_read_attribute<MPoly, int, get_material_index, ATTR_DOMAIN_FACE>, - make_derived_write_attribute<MPoly, - int, - get_material_index, - set_material_index, - ATTR_DOMAIN_FACE>, + make_derived_read_attribute<MPoly, int, get_material_index>, + make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>, nullptr); static BuiltinCustomDataLayerProvider shade_smooth( @@ -1141,12 +1102,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() BuiltinAttributeProvider::Writable, BuiltinAttributeProvider::NonDeletable, face_access, - make_derived_read_attribute<MPoly, bool, get_shade_smooth, ATTR_DOMAIN_FACE>, - make_derived_write_attribute<MPoly, - bool, - get_shade_smooth, - set_shade_smooth, - ATTR_DOMAIN_FACE>, + make_derived_read_attribute<MPoly, bool, get_shade_smooth>, + make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>, nullptr); static BuiltinCustomDataLayerProvider crease( @@ -1158,8 +1115,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() BuiltinAttributeProvider::Writable, BuiltinAttributeProvider::NonDeletable, edge_access, - make_derived_read_attribute<MEdge, float, get_crease, ATTR_DOMAIN_EDGE>, - make_derived_write_attribute<MEdge, float, get_crease, set_crease, ATTR_DOMAIN_EDGE>, + make_derived_read_attribute<MEdge, float, get_crease>, + make_derived_write_attribute<MEdge, float, get_crease, set_crease>, nullptr); static NamedLegacyCustomDataProvider uvs( @@ -1167,20 +1124,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() CD_PROP_FLOAT2, CD_MLOOPUV, corner_access, - make_derived_read_attribute<MLoopUV, float2, get_loop_uv, ATTR_DOMAIN_CORNER>, - make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv, ATTR_DOMAIN_CORNER>); + make_derived_read_attribute<MLoopUV, float2, get_loop_uv>, + make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv>); static NamedLegacyCustomDataProvider vertex_colors( ATTR_DOMAIN_CORNER, CD_PROP_COLOR, CD_MLOOPCOL, corner_access, - make_derived_read_attribute<MLoopCol, Color4f, get_loop_color, ATTR_DOMAIN_CORNER>, - make_derived_write_attribute<MLoopCol, - Color4f, - get_loop_color, - set_loop_color, - ATTR_DOMAIN_CORNER>); + make_derived_read_attribute<MLoopCol, Color4f, get_loop_color>, + make_derived_write_attribute<MLoopCol, Color4f, get_loop_color, set_loop_color>); static VertexGroupsAttributeProvider vertex_groups; static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index 135de14b4f7..6c4af7a6d23 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -140,16 +140,17 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con namespace blender::bke { -template<typename T, AttributeDomain Domain> -static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size) +template<typename T> +static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) { - return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size)); + return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); } -template<typename T, AttributeDomain Domain> -static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size) +template<typename T> +static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) { - return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size)); + return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( + MutableSpan<T>((T *)data, domain_size)); } /** @@ -179,30 +180,28 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() }, update_custom_data_pointers}; - static BuiltinCustomDataLayerProvider position( - "position", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_PROP_FLOAT3, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_array_read_attribute<float3, ATTR_DOMAIN_POINT>, - make_array_write_attribute<float3, ATTR_DOMAIN_POINT>, - nullptr); - static BuiltinCustomDataLayerProvider radius( - "radius", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT, - CD_PROP_FLOAT, - BuiltinAttributeProvider::Creatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::Deletable, - point_access, - make_array_read_attribute<float, ATTR_DOMAIN_POINT>, - make_array_write_attribute<float, ATTR_DOMAIN_POINT>, - nullptr); + static BuiltinCustomDataLayerProvider position("position", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_PROP_FLOAT3, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_array_read_attribute<float3>, + make_array_write_attribute<float3>, + nullptr); + static BuiltinCustomDataLayerProvider radius("radius", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT, + CD_PROP_FLOAT, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<float>, + make_array_write_attribute<float>, + nullptr); static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 07d0e520c93..2e9f6daabad 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -450,12 +450,13 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, BLI_assert(cpp_type != nullptr); result.attribute_try_create(entry.key, domain_output, data_type_output); - WriteAttributePtr write_attribute = result.attribute_try_get_for_write(name); - if (!write_attribute || &write_attribute->cpp_type() != cpp_type || - write_attribute->domain() != domain_output) { + WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name); + if (!write_attribute || &write_attribute.varray->type() != cpp_type || + write_attribute.domain != domain_output) { continue; } - fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only(); + + fn::GVMutableArray_GSpan dst_span{*write_attribute.varray}; int offset = 0; for (const GeometryInstanceGroup &set_group : set_groups) { @@ -467,11 +468,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, if (domain_size == 0) { continue; /* Domain size is 0, so no need to increment the offset. */ } - ReadAttributePtr source_attribute = component.attribute_try_get_for_read( + GVArrayPtr source_attribute = component.attribute_try_get_for_read( name, domain_output, data_type_output); if (source_attribute) { - fn::GSpan src_span = source_attribute->get_span(); + fn::GVArray_GSpan src_span{*source_attribute}; const void *src_buffer = src_span.data(); for (const int UNUSED(i) : set_group.transforms.index_range()) { void *dst_buffer = dst_span[offset]; @@ -486,7 +487,7 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, } } - write_attribute->apply_span(); + dst_span.save(); } } diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 3868f5acae9..eae15f0300c 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -248,6 +248,9 @@ template<typename T> class VMutableArray : public VArray<T> { } }; +template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>; +template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>; + /** * A virtual array implementation for a span. Methods in this class are final so that it can be * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used). diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 520d29ce306..405f0cd9455 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -78,24 +78,25 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( { std::lock_guard lock{mutex_}; - bke::ReadAttributePtr attribute_ptr = component_->attribute_try_get_for_read(column_id.name); - if (!attribute_ptr) { + bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name); + if (!attribute) { return {}; } - const bke::ReadAttribute *attribute = scope_.add(std::move(attribute_ptr), __func__); - if (attribute->domain() != domain_) { + const fn::GVArray *varray = scope_.add(std::move(attribute.varray), __func__); + if (attribute.domain != domain_) { return {}; } - int domain_size = attribute->size(); - switch (attribute->custom_data_type()) { + int domain_size = varray->size(); + const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type()); + switch (type) { case CD_PROP_FLOAT: if (column_id.index != -1) { return {}; } return column_values_from_function( - column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) { + column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) { float value; - attribute->get(index, &value); + varray->get(index, &value); r_cell_value.value_float = value; }); case CD_PROP_INT32: @@ -103,9 +104,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( return {}; } return column_values_from_function( - column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) { + column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) { int value; - attribute->get(index, &value); + varray->get(index, &value); r_cell_value.value_int = value; }); case CD_PROP_BOOL: @@ -113,9 +114,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( return {}; } return column_values_from_function( - column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) { + column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) { bool value; - attribute->get(index, &value); + varray->get(index, &value); r_cell_value.value_bool = value; }); case CD_PROP_FLOAT2: { @@ -125,11 +126,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( const std::array<const char *, 2> suffixes = {" X", " Y"}; const std::string name = StringRef(column_id.name) + suffixes[column_id.index]; return column_values_from_function( - name, - domain_size, - [attribute, axis = column_id.index](int index, CellValue &r_cell_value) { + name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) { float2 value; - attribute->get(index, &value); + varray->get(index, &value); r_cell_value.value_float = value[axis]; }); } @@ -140,11 +139,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( const std::array<const char *, 3> suffixes = {" X", " Y", " Z"}; const std::string name = StringRef(column_id.name) + suffixes[column_id.index]; return column_values_from_function( - name, - domain_size, - [attribute, axis = column_id.index](int index, CellValue &r_cell_value) { + name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) { float3 value; - attribute->get(index, &value); + varray->get(index, &value); r_cell_value.value_float = value[axis]; }); } @@ -155,11 +152,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( const std::array<const char *, 4> suffixes = {" R", " G", " B", " A"}; const std::string name = StringRef(column_id.name) + suffixes[column_id.index]; return column_values_from_function( - name, - domain_size, - [attribute, axis = column_id.index](int index, CellValue &r_cell_value) { + name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) { Color4f value; - attribute->get(index, &value); + varray->get(index, &value); r_cell_value.value_float = value[axis]; }); } diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index 00f6cacd2e1..c1af00fd4cd 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -212,6 +212,9 @@ class GVMutableArray : public GVArray { virtual void *try_get_internal_mutable_varray_impl(); }; +using GVArrayPtr = std::unique_ptr<GVArray>; +using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>; + class GVArray_For_GSpan : public GVArray { protected: const void *data_ = nullptr; @@ -582,11 +585,11 @@ template<typename T> class GVArray_Span : public Span<T> { template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> { private: - std::unique_ptr<VArray<T>> owned_varray_; + VArrayPtr<T> owned_varray_; public: /* Takes ownership of varray and passes a reference to the base class. */ - GVArray_For_OwnedVArray(std::unique_ptr<VArray<T>> varray) + GVArray_For_OwnedVArray(VArrayPtr<T> varray) : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray)) { } @@ -594,11 +597,11 @@ template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> { private: - std::unique_ptr<VArray<T>> owned_varray_; + GVArrayPtr owned_varray_; public: /* Takes ownership of varray and passes a reference to the base class. */ - VArray_For_OwnedGVArray(std::unique_ptr<GVArray> varray) + VArray_For_OwnedGVArray(GVArrayPtr varray) : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray)) { } @@ -607,11 +610,11 @@ template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T template<typename T> class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> { private: - std::unique_ptr<VMutableArray<T>> owned_varray_; + VMutableArrayPtr<T> owned_varray_; public: /* Takes ownership of varray and passes a reference to the base class. */ - GVMutableArray_For_OwnedVMutableArray(std::unique_ptr<VMutableArray<T>> varray) + GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray) : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray)) { } @@ -620,11 +623,11 @@ class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutable template<typename T> class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> { private: - std::unique_ptr<GVMutableArray> owned_varray_; + GVMutableArrayPtr owned_varray_; public: /* Takes ownership of varray and passes a reference to the base class. */ - VMutableArray_For_OwnedGVMutableArray(std::unique_ptr<GVMutableArray> varray) + VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray) : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray)) { } @@ -740,7 +743,7 @@ template<typename T> class GVArray_Typed { std::optional<VArray_For_Span<T>> varray_span_; std::optional<VArray_For_Single<T>> varray_single_; std::optional<VArray_For_GVArray<T>> varray_any_; - std::unique_ptr<GVArray> owned_gvarray_; + GVArrayPtr owned_gvarray_; public: explicit GVArray_Typed(const GVArray &gvarray) @@ -767,7 +770,7 @@ template<typename T> class GVArray_Typed { } /* Same as the constructor above, but also takes ownership of the passed in virtual array. */ - explicit GVArray_Typed(std::unique_ptr<GVArray> gvarray) : GVArray_Typed(*gvarray) + explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray) { owned_gvarray_ = std::move(gvarray); } @@ -811,7 +814,7 @@ template<typename T> class GVMutableArray_Typed { VMutableArray<T> *varray_; std::optional<VMutableArray_For_MutableSpan<T>> varray_span_; std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_; - std::unique_ptr<GVMutableArray> owned_gvarray_; + GVMutableArrayPtr owned_gvarray_; public: explicit GVMutableArray_Typed(GVMutableArray &gvarray) @@ -831,8 +834,7 @@ template<typename T> class GVMutableArray_Typed { } } - explicit GVMutableArray_Typed(std::unique_ptr<GVMutableArray> gvarray) - : GVMutableArray_Typed(*gvarray) + explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray) { owned_gvarray_ = std::move(gvarray); } diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 5d1a217db9b..f2582600c7d 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -33,29 +33,28 @@ struct ModifierData; namespace blender::nodes { -using bke::BooleanReadAttribute; -using bke::BooleanWriteAttribute; -using bke::Color4fReadAttribute; -using bke::Color4fWriteAttribute; -using bke::Float2ReadAttribute; -using bke::Float2WriteAttribute; -using bke::Float3ReadAttribute; -using bke::Float3WriteAttribute; -using bke::FloatReadAttribute; -using bke::FloatWriteAttribute; using bke::geometry_set_realize_instances; -using bke::Int32ReadAttribute; -using bke::Int32WriteAttribute; +using bke::OutputAttribute; +using bke::OutputAttribute_Typed; using bke::PersistentDataHandleMap; using bke::PersistentObjectHandle; -using bke::ReadAttribute; -using bke::ReadAttributePtr; -using bke::WriteAttribute; -using bke::WriteAttributePtr; +using bke::ReadAttributeLookup; +using bke::WriteAttributeLookup; using fn::CPPType; using fn::GMutablePointer; +using fn::GMutableSpan; using fn::GPointer; +using fn::GSpan; using fn::GValueMap; +using fn::GVArray; +using fn::GVArray_GSpan; +using fn::GVArray_Span; +using fn::GVArray_Typed; +using fn::GVArrayPtr; +using fn::GVMutableArray; +using fn::GVMutableArray_GSpan; +using fn::GVMutableArray_Typed; +using fn::GVMutableArrayPtr; class GeoNodeExecParams { private: @@ -217,20 +216,21 @@ class GeoNodeExecParams { * \note This will add an error message if the string socket is active and * the input attribute does not exist. */ - ReadAttributePtr get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const; + GVArrayPtr get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const; template<typename T> - bke::TypedReadAttribute<T> get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const T &default_value) const + GVArray_Typed<T> get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const T &default_value) const { const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>()); - return this->get_input_attribute(name, component, domain, type, &default_value); + GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value); + return GVArray_Typed<T>(std::move(varray)); } /** diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh index 34225208fe6..ec4859f0657 100644 --- a/source/blender/nodes/NOD_type_conversions.hh +++ b/source/blender/nodes/NOD_type_conversions.hh @@ -72,6 +72,10 @@ class DataTypeConversions { const CPPType &to_type, const void *from_value, void *to_value) const; + + fn::GVArrayPtr try_convert(fn::GVArrayPtr varray, const CPPType &to_type) const; + + fn::GVMutableArrayPtr try_convert(fn::GVMutableArrayPtr varray, const CPPType &to_type) const; }; const DataTypeConversions &get_implicit_type_conversions(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc index f10b81a33b4..c4d37a82617 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc @@ -50,10 +50,10 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, namespace blender::nodes { -static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors, - const FloatReadAttribute &factors, +static void align_rotations_auto_pivot(const VArray<float3> &vectors, + const VArray<float> &factors, const float3 local_main_axis, - MutableSpan<float3> rotations) + const MutableSpan<float3> rotations) { for (const int i : IndexRange(vectors.size())) { const float3 vector = vectors[i]; @@ -93,11 +93,11 @@ static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors, } } -static void align_rotations_fixed_pivot(const Float3ReadAttribute &vectors, - const FloatReadAttribute &factors, +static void align_rotations_fixed_pivot(const VArray<float3> &vectors, + const VArray<float> &factors, const float3 local_main_axis, const float3 local_pivot_axis, - MutableSpan<float3> rotations) + const MutableSpan<float3> rotations) { if (local_main_axis == local_pivot_axis) { /* Can't compute any meaningful rotation angle in this case. */ @@ -144,30 +144,30 @@ static void align_rotations_on_component(GeometryComponent &component, const NodeGeometryAlignRotationToVector &storage = *(const NodeGeometryAlignRotationToVector *) node.storage; - OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( - "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); - if (!rotation_attribute) { + OutputAttribute_Typed<float3> rotations = component.attribute_try_get_for_output<float3>( + "rotation", ATTR_DOMAIN_POINT, {0, 0, 0}); + if (!rotations) { return; } - MutableSpan<float3> rotations = rotation_attribute->get_span<float3>(); - FloatReadAttribute factors = params.get_input_attribute<float>( + GVArray_Typed<float> factors = params.get_input_attribute<float>( "Factor", component, ATTR_DOMAIN_POINT, 1.0f); - Float3ReadAttribute vectors = params.get_input_attribute<float3>( + GVArray_Typed<float3> vectors = params.get_input_attribute<float3>( "Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1}); float3 local_main_axis{0, 0, 0}; local_main_axis[storage.axis] = 1; if (storage.pivot_axis == GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO) { - align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations); + align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations.as_span()); } else { float3 local_pivot_axis{0, 0, 0}; local_pivot_axis[storage.pivot_axis - 1] = 1; - align_rotations_fixed_pivot(vectors, factors, local_main_axis, local_pivot_axis, rotations); + align_rotations_fixed_pivot( + vectors, factors, local_main_axis, local_pivot_axis, rotations.as_span()); } - rotation_attribute.apply_span_and_save(); + rotations.save(); } static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc index 95fa24c8bac..e7677ed41e1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc @@ -112,10 +112,13 @@ template<> inline Color4f clamp_value(const Color4f val, const Color4f min, cons } template<typename T> -static void clamp_attribute(Span<T> read_span, MutableSpan<T> span, const T min, const T max) +static void clamp_attribute(const VArray<T> &inputs, + const MutableSpan<T> outputs, + const T min, + const T max) { - for (const int i : span.index_range()) { - span[i] = clamp_value<T>(read_span[i], min, max); + for (const int i : IndexRange(outputs.size())) { + outputs[i] = clamp_value<T>(inputs[i], min, max); } } @@ -123,13 +126,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name) { - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } - ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name); + ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name); if (source_attribute) { - return source_attribute->domain(); + return source_attribute.domain; } return ATTR_DOMAIN_POINT; } @@ -154,10 +157,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const AttributeDomain domain = get_result_domain(component, attribute_name, result_name); const int operation = static_cast<int>(storage.operation); - ReadAttributePtr attribute_input = component.attribute_try_get_for_read( + GVArrayPtr attribute_input = component.attribute_try_get_for_read( attribute_name, domain, data_type); - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + OutputAttribute attribute_result = component.attribute_try_get_for_output_only( result_name, domain, data_type); if (!attribute_result) { @@ -169,8 +172,6 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam switch (data_type) { case CD_PROP_FLOAT3: { - Span<float3> read_span = attribute_input->get_span<float3>(); - MutableSpan<float3> span = attribute_result->get_span_for_write_only<float3>(); float3 min = params.get_input<float3>("Min"); float3 max = params.get_input<float3>("Max"); if (operation == NODE_CLAMP_RANGE) { @@ -184,38 +185,35 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam std::swap(min.z, max.z); } } - clamp_attribute<float3>(read_span, span, min, max); + MutableSpan<float3> results = attribute_result.as_span<float3>(); + clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max); break; } case CD_PROP_FLOAT: { - Span<float> read_span = attribute_input->get_span<float>(); - MutableSpan<float> span = attribute_result->get_span_for_write_only<float>(); const float min = params.get_input<float>("Min_001"); const float max = params.get_input<float>("Max_001"); + MutableSpan<float> results = attribute_result.as_span<float>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<float>(read_span, span, max, min); + clamp_attribute<float>(attribute_input->typed<float>(), results, max, min); } else { - clamp_attribute<float>(read_span, span, min, max); + clamp_attribute<float>(attribute_input->typed<float>(), results, min, max); } break; } case CD_PROP_INT32: { - Span<int> read_span = attribute_input->get_span<int>(); - MutableSpan<int> span = attribute_result->get_span_for_write_only<int>(); const int min = params.get_input<int>("Min_002"); const int max = params.get_input<int>("Max_002"); + MutableSpan<int> results = attribute_result.as_span<int>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<int>(read_span, span, max, min); + clamp_attribute<int>(attribute_input->typed<int>(), results, max, min); } else { - clamp_attribute<int>(read_span, span, min, max); + clamp_attribute<int>(attribute_input->typed<int>(), results, min, max); } break; } case CD_PROP_COLOR: { - Span<Color4f> read_span = attribute_input->get_span<Color4f>(); - MutableSpan<Color4f> span = attribute_result->get_span_for_write_only<Color4f>(); Color4f min = params.get_input<Color4f>("Min_003"); Color4f max = params.get_input<Color4f>("Max_003"); if (operation == NODE_CLAMP_RANGE) { @@ -232,7 +230,8 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam std::swap(min.a, max.a); } } - clamp_attribute<Color4f>(read_span, span, min, max); + MutableSpan<Color4f> results = attribute_result.as_span<Color4f>(); + clamp_attribute<Color4f>(attribute_input->typed<Color4f>(), results, min, max); break; } default: { @@ -241,7 +240,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam } } - attribute_result.apply_span_and_save(); + attribute_result.save(); } static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc index 2b913beb670..af65fe110e9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc @@ -47,15 +47,15 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the input attribute's domain if it exists. */ - ReadAttributePtr input_attribute = component.attribute_try_get_for_read(input_name); + ReadAttributeLookup input_attribute = component.attribute_try_get_for_read(input_name); if (input_attribute) { - return input_attribute->domain(); + return input_attribute.domain; } return ATTR_DOMAIN_POINT; @@ -71,27 +71,25 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon /* Always output a color attribute for now. We might want to allow users to customize. * Using the type of an existing attribute could work, but does not have a real benefit * currently. */ - const CustomDataType result_type = CD_PROP_COLOR; const AttributeDomain result_domain = get_result_domain(component, input_name, result_name); - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( - result_name, result_domain, result_type); + OutputAttribute_Typed<Color4f> attribute_result = + component.attribute_try_get_for_output_only<Color4f>(result_name, result_domain); if (!attribute_result) { return; } - FloatReadAttribute attribute_in = component.attribute_get_for_read<float>( + GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>( input_name, result_domain, 0.0f); - Span<float> data_in = attribute_in.get_span(); - MutableSpan<Color4f> data_out = attribute_result->get_span_for_write_only<Color4f>(); + MutableSpan<Color4f> results = attribute_result.as_span(); ColorBand *color_ramp = &node_storage->color_ramp; - for (const int i : data_in.index_range()) { - BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]); + for (const int i : IndexRange(attribute_in.size())) { + BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]); } - attribute_result.apply_span_and_save(); + attribute_result.save(); } static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc index e9e07d34c17..c3db26c7299 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc @@ -77,9 +77,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ @@ -94,27 +94,24 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa } const AttributeDomain result_domain = get_result_domain(component, params, result_name); - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( - result_name, result_domain, CD_PROP_FLOAT3); + OutputAttribute_Typed<float3> attribute_result = + component.attribute_try_get_for_output_only<float3>(result_name, result_domain); if (!attribute_result) { return; } - FloatReadAttribute attribute_x = params.get_input_attribute<float>( + GVArray_Typed<float> attribute_x = params.get_input_attribute<float>( "X", component, result_domain, 0.0f); - FloatReadAttribute attribute_y = params.get_input_attribute<float>( + GVArray_Typed<float> attribute_y = params.get_input_attribute<float>( "Y", component, result_domain, 0.0f); - FloatReadAttribute attribute_z = params.get_input_attribute<float>( + GVArray_Typed<float> attribute_z = params.get_input_attribute<float>( "Z", component, result_domain, 0.0f); - MutableSpan<float3> results = attribute_result->get_span_for_write_only<float3>(); - for (const int i : results.index_range()) { + for (const int i : IndexRange(attribute_result->size())) { const float x = attribute_x[i]; const float y = attribute_y[i]; const float z = attribute_z[i]; - const float3 result = float3(x, y, z); - results[i] = result; + attribute_result->set(i, {x, y, z}); } - attribute_result.apply_span_and_save(); } static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc index fe4045c39a6..22855787ab0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc @@ -81,21 +81,18 @@ static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *n nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage)); } -static void do_math_operation(const FloatReadAttribute &input_a, - const FloatReadAttribute &input_b, +static void do_math_operation(const VArray<float> &input_a, + const VArray<float> &input_b, const FloatCompareOperation operation, MutableSpan<bool> span_result) { const int size = input_a.size(); - Span<float> span_a = input_a.get_span(); - Span<float> span_b = input_b.get_span(); - if (try_dispatch_float_math_fl_fl_to_bool( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { for (const int i : IndexRange(size)) { - const float a = span_a[i]; - const float b = span_b[i]; + const float a = input_a[i]; + const float b = input_b[i]; const bool out = math_function(a, b); span_result[i] = out; } @@ -107,8 +104,8 @@ static void do_math_operation(const FloatReadAttribute &input_a, BLI_assert(false); } -static void do_equal_operation_float(const FloatReadAttribute &input_a, - const FloatReadAttribute &input_b, +static void do_equal_operation_float(const VArray<float> &input_a, + const VArray<float> &input_b, const float threshold, MutableSpan<bool> span_result) { @@ -120,8 +117,8 @@ static void do_equal_operation_float(const FloatReadAttribute &input_a, } } -static void do_equal_operation_float3(const Float3ReadAttribute &input_a, - const Float3ReadAttribute &input_b, +static void do_equal_operation_float3(const VArray<float3> &input_a, + const VArray<float3> &input_b, const float threshold, MutableSpan<bool> span_result) { @@ -134,8 +131,8 @@ static void do_equal_operation_float3(const Float3ReadAttribute &input_a, } } -static void do_equal_operation_color4f(const Color4fReadAttribute &input_a, - const Color4fReadAttribute &input_b, +static void do_equal_operation_color4f(const VArray<Color4f> &input_a, + const VArray<Color4f> &input_b, const float threshold, MutableSpan<bool> span_result) { @@ -148,8 +145,8 @@ static void do_equal_operation_color4f(const Color4fReadAttribute &input_a, } } -static void do_equal_operation_bool(const BooleanReadAttribute &input_a, - const BooleanReadAttribute &input_b, +static void do_equal_operation_bool(const VArray<bool> &input_a, + const VArray<bool> &input_b, const float UNUSED(threshold), MutableSpan<bool> span_result) { @@ -161,8 +158,8 @@ static void do_equal_operation_bool(const BooleanReadAttribute &input_a, } } -static void do_not_equal_operation_float(const FloatReadAttribute &input_a, - const FloatReadAttribute &input_b, +static void do_not_equal_operation_float(const VArray<float> &input_a, + const VArray<float> &input_b, const float threshold, MutableSpan<bool> span_result) { @@ -174,8 +171,8 @@ static void do_not_equal_operation_float(const FloatReadAttribute &input_a, } } -static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a, - const Float3ReadAttribute &input_b, +static void do_not_equal_operation_float3(const VArray<float3> &input_a, + const VArray<float3> &input_b, const float threshold, MutableSpan<bool> span_result) { @@ -188,8 +185,8 @@ static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a, } } -static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a, - const Color4fReadAttribute &input_b, +static void do_not_equal_operation_color4f(const VArray<Color4f> &input_a, + const VArray<Color4f> &input_b, const float threshold, MutableSpan<bool> span_result) { @@ -202,8 +199,8 @@ static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a, } } -static void do_not_equal_operation_bool(const BooleanReadAttribute &input_a, - const BooleanReadAttribute &input_b, +static void do_not_equal_operation_bool(const VArray<bool> &input_a, + const VArray<bool> &input_b, const float UNUSED(threshold), MutableSpan<bool> span_result) { @@ -237,9 +234,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ @@ -254,20 +251,19 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx node_storage->operation); const std::string result_name = params.get_input<std::string>("Result"); - const CustomDataType result_type = CD_PROP_BOOL; const AttributeDomain result_domain = get_result_domain(component, params, result_name); - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( - result_name, result_domain, result_type); + OutputAttribute_Typed<bool> attribute_result = component.attribute_try_get_for_output_only<bool>( + result_name, result_domain); if (!attribute_result) { return; } const CustomDataType input_data_type = get_data_type(component, params, *node_storage); - ReadAttributePtr attribute_a = params.get_input_attribute( + GVArrayPtr attribute_a = params.get_input_attribute( "A", component, result_domain, input_data_type, nullptr); - ReadAttributePtr attribute_b = params.get_input_attribute( + GVArrayPtr attribute_b = params.get_input_attribute( "B", component, result_domain, input_data_type, nullptr); if (!attribute_a || !attribute_b) { @@ -275,7 +271,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx return; } - MutableSpan<bool> result_span = attribute_result->get_span_for_write_only<bool>(); + MutableSpan<bool> result_span = attribute_result.as_span(); /* Use specific types for correct equality operations, but for other operations we use implicit * conversions and float comparison. In other words, the comparison is not element-wise. */ @@ -283,38 +279,47 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx const float threshold = params.get_input<float>("Threshold"); if (operation == NODE_FLOAT_COMPARE_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { - do_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span); + do_equal_operation_float( + attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { - do_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span); + do_equal_operation_float3( + attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span); + do_equal_operation_color4f( + attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { - do_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span); + do_equal_operation_bool( + attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); } } else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { - do_not_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span); + do_not_equal_operation_float( + attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { - do_not_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span); + do_not_equal_operation_float3( + attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_not_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span); + do_not_equal_operation_color4f( + attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { - do_not_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span); + do_not_equal_operation_bool( + attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); } } } else { - do_math_operation(*attribute_a, *attribute_b, operation, result_span); + do_math_operation( + attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span); } - attribute_result.apply_span_and_save(); + attribute_result.save(); } static void geo_node_attribute_compare_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc index 577c4b3d3fb..ff20b5f35a4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc @@ -55,13 +55,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name) { - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } - ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name); + ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name); if (source_attribute) { - return source_attribute->domain(); + return source_attribute.domain; } return ATTR_DOMAIN_POINT; } @@ -78,7 +78,7 @@ static void attribute_convert_calc(GeometryComponent &component, component, source_name, result_name) : domain; - ReadAttributePtr source_attribute = component.attribute_try_get_for_read( + GVArrayPtr source_attribute = component.attribute_try_get_for_read( source_name, result_domain, result_type); if (!source_attribute) { params.error_message_add(NodeWarningType::Error, @@ -86,25 +86,22 @@ static void attribute_convert_calc(GeometryComponent &component, return; } - OutputAttributePtr result_attribute = component.attribute_try_get_for_output( + OutputAttribute result_attribute = component.attribute_try_get_for_output_only( result_name, result_domain, result_type); if (!result_attribute) { return; } - fn::GSpan source_span = source_attribute->get_span(); - fn::GMutableSpan result_span = result_attribute->get_span_for_write_only(); - if (source_span.is_empty() || result_span.is_empty()) { - return; - } + GVArray_GSpan source_span{*source_attribute}; + GMutableSpan result_span = result_attribute.as_span(); + BLI_assert(source_span.size() == result_span.size()); const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(result_type); BLI_assert(cpp_type != nullptr); cpp_type->copy_to_initialized_n(source_span.data(), result_span.data(), result_span.size()); - - result_attribute.apply_span_and_save(); + result_attribute.save(); } static void geo_node_attribute_convert_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc index 7b4483a31a1..8287313e400 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc @@ -72,9 +72,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef attribute_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } return ATTR_DOMAIN_POINT; } @@ -93,7 +93,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams get_result_domain(component, attribute_name) : domain; - OutputAttributePtr attribute = component.attribute_try_get_for_output( + OutputAttribute attribute = component.attribute_try_get_for_output_only( attribute_name, result_domain, data_type); if (!attribute) { return; @@ -102,38 +102,34 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams switch (data_type) { case CD_PROP_FLOAT: { const float value = params.get_input<float>("Value_001"); - MutableSpan<float> attribute_span = attribute->get_span_for_write_only<float>(); - attribute_span.fill(value); + attribute->fill(&value); break; } case CD_PROP_FLOAT3: { const float3 value = params.get_input<float3>("Value"); - MutableSpan<float3> attribute_span = attribute->get_span_for_write_only<float3>(); - attribute_span.fill(value); + attribute->fill(&value); break; } case CD_PROP_COLOR: { const Color4f value = params.get_input<Color4f>("Value_002"); - MutableSpan<Color4f> attribute_span = attribute->get_span_for_write_only<Color4f>(); - attribute_span.fill(value); + attribute->fill(&value); break; } case CD_PROP_BOOL: { const bool value = params.get_input<bool>("Value_003"); - MutableSpan<bool> attribute_span = attribute->get_span_for_write_only<bool>(); - attribute_span.fill(value); + attribute->fill(&value); break; } case CD_PROP_INT32: { const int value = params.get_input<int>("Value_004"); - MutableSpan<int> attribute_span = attribute->get_span_for_write_only<int>(); - attribute_span.fill(value); + attribute->fill(&value); + break; } default: break; } - attribute.apply_span_and_save(); + attribute.save(); } static void geo_node_attribute_fill_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc index fdbdadf90b6..4a98d6caed2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc @@ -192,8 +192,8 @@ static float map_smootherstep(const float value, return min_to + factor_mapped * (max_to - min_to); } -static void map_range_float(FloatReadAttribute attribute_input, - FloatWriteAttribute attribute_result, +static void map_range_float(const VArray<float> &attribute_input, + MutableSpan<float> results, const GeoNodeExecParams ¶ms) { const bNode &node = params.node(); @@ -204,32 +204,31 @@ static void map_range_float(FloatReadAttribute attribute_input, const float min_to = params.get_input<float>("To Min"); const float max_to = params.get_input<float>("To Max"); - Span<float> span = attribute_input.get_span(); - MutableSpan<float> result_span = attribute_result.get_span(); + VArray_Span<float> span{attribute_input}; switch (interpolation_type) { case NODE_MAP_RANGE_LINEAR: { for (int i : span.index_range()) { - result_span[i] = map_linear(span[i], min_from, max_from, min_to, max_to); + results[i] = map_linear(span[i], min_from, max_from, min_to, max_to); } break; } case NODE_MAP_RANGE_STEPPED: { const float steps = params.get_input<float>("Steps"); for (int i : span.index_range()) { - result_span[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps); + results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps); } break; } case NODE_MAP_RANGE_SMOOTHSTEP: { for (int i : span.index_range()) { - result_span[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to); + results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to); } break; } case NODE_MAP_RANGE_SMOOTHERSTEP: { for (int i : span.index_range()) { - result_span[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to); + results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to); } break; } @@ -241,14 +240,14 @@ static void map_range_float(FloatReadAttribute attribute_input, const float clamp_min = min_to < max_to ? min_to : max_to; const float clamp_max = min_to < max_to ? max_to : min_to; - for (int i : result_span.index_range()) { - result_span[i] = std::clamp(result_span[i], clamp_min, clamp_max); + for (int i : results.index_range()) { + results[i] = std::clamp(results[i], clamp_min, clamp_max); } } } -static void map_range_float3(Float3ReadAttribute attribute_input, - Float3WriteAttribute attribute_result, +static void map_range_float3(const VArray<float3> &attribute_input, + const MutableSpan<float3> results, const GeoNodeExecParams ¶ms) { const bNode &node = params.node(); @@ -259,43 +258,39 @@ static void map_range_float3(Float3ReadAttribute attribute_input, const float3 min_to = params.get_input<float3>("To Min_001"); const float3 max_to = params.get_input<float3>("To Max_001"); - Span<float3> span = attribute_input.get_span(); - MutableSpan<float3> result_span = attribute_result.get_span(); + VArray_Span<float3> span{attribute_input}; switch (interpolation_type) { case NODE_MAP_RANGE_LINEAR: { for (int i : span.index_range()) { - result_span[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); - result_span[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); - result_span[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + results[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + results[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); } break; } case NODE_MAP_RANGE_STEPPED: { const float3 steps = params.get_input<float3>("Steps_001"); for (int i : span.index_range()) { - result_span[i].x = map_stepped( - span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x); - result_span[i].y = map_stepped( - span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y); - result_span[i].z = map_stepped( - span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z); + results[i].x = map_stepped(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x); + results[i].y = map_stepped(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y); + results[i].z = map_stepped(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z); } break; } case NODE_MAP_RANGE_SMOOTHSTEP: { for (int i : span.index_range()) { - result_span[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); - result_span[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); - result_span[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + results[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + results[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + results[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); } break; } case NODE_MAP_RANGE_SMOOTHERSTEP: { for (int i : span.index_range()) { - result_span[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); - result_span[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); - result_span[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + results[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + results[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + results[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); } break; } @@ -313,8 +308,8 @@ static void map_range_float3(Float3ReadAttribute attribute_input, clamp_min.z = min_to.z < max_to.z ? min_to.z : max_to.z; clamp_max.z = min_to.z < max_to.z ? max_to.z : min_to.z; - for (int i : result_span.index_range()) { - clamp_v3_v3v3(result_span[i], clamp_min, clamp_max); + for (int i : results.index_range()) { + clamp_v3_v3v3(results[i], clamp_min, clamp_max); } } } @@ -323,13 +318,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name) { - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } - ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name); + ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name); if (source_attribute) { - return source_attribute->domain(); + return source_attribute.domain; } return ATTR_DOMAIN_POINT; } @@ -349,8 +344,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP const AttributeDomain domain = get_result_domain(component, input_name, result_name); - ReadAttributePtr attribute_input = component.attribute_try_get_for_read( - input_name, domain, data_type); + GVArrayPtr attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type); if (!attribute_input) { params.error_message_add(NodeWarningType::Error, @@ -358,7 +352,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP return; } - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + OutputAttribute attribute_result = component.attribute_try_get_for_output_only( result_name, domain, data_type); if (!attribute_result) { params.error_message_add(NodeWarningType::Error, @@ -369,18 +363,19 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP switch (data_type) { case CD_PROP_FLOAT: { - map_range_float(*attribute_input, *attribute_result, params); + map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params); break; } case CD_PROP_FLOAT3: { - map_range_float3(*attribute_input, *attribute_result, params); + map_range_float3( + attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params); break; } default: BLI_assert_unreachable(); } - attribute_result.apply_span_and_save(); + attribute_result.save(); } static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc index 5ee31e78be2..99ba6acd94d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc @@ -149,9 +149,9 @@ static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node operation_use_input_c(operation)); } -static void do_math_operation(Span<float> span_a, - Span<float> span_b, - Span<float> span_c, +static void do_math_operation(const VArray<float> &span_a, + const VArray<float> &span_b, + const VArray<float> &span_c, MutableSpan<float> span_result, const NodeMathOperation operation) { @@ -165,8 +165,8 @@ static void do_math_operation(Span<float> span_a, UNUSED_VARS_NDEBUG(success); } -static void do_math_operation(Span<float> span_a, - Span<float> span_b, +static void do_math_operation(const VArray<float> &span_a, + const VArray<float> &span_b, MutableSpan<float> span_result, const NodeMathOperation operation) { @@ -180,7 +180,7 @@ static void do_math_operation(Span<float> span_a, UNUSED_VARS_NDEBUG(success); } -static void do_math_operation(Span<float> span_input, +static void do_math_operation(const VArray<float> &span_input, MutableSpan<float> span_result, const NodeMathOperation operation) { @@ -200,9 +200,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ @@ -224,56 +224,39 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP const std::string result_name = params.get_input<std::string>("Result"); /* The result type of this node is always float. */ - const CustomDataType result_type = CD_PROP_FLOAT; const AttributeDomain result_domain = get_result_domain( component, params, operation, result_name); - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( - result_name, result_domain, result_type); + OutputAttribute_Typed<float> attribute_result = + component.attribute_try_get_for_output_only<float>(result_name, result_domain); if (!attribute_result) { return; } - ReadAttributePtr attribute_a = params.get_input_attribute( - "A", component, result_domain, result_type, nullptr); - if (!attribute_a) { - return; - } + GVArray_Typed<float> attribute_a = params.get_input_attribute<float>( + "A", component, result_domain, 0.0f); - /* Note that passing the data with `get_span<float>()` works + MutableSpan<float> result_span = attribute_result.as_span(); + + /* Note that passing the data with `get_internal_span<float>()` works * because the attributes were accessed with #CD_PROP_FLOAT. */ if (operation_use_input_b(operation)) { - ReadAttributePtr attribute_b = params.get_input_attribute( - "B", component, result_domain, result_type, nullptr); - if (!attribute_b) { - return; - } + GVArray_Typed<float> attribute_b = params.get_input_attribute<float>( + "B", component, result_domain, 0.0f); if (operation_use_input_c(operation)) { - ReadAttributePtr attribute_c = params.get_input_attribute( - "C", component, result_domain, result_type, nullptr); - if (!attribute_c) { - return; - } - do_math_operation(attribute_a->get_span<float>(), - attribute_b->get_span<float>(), - attribute_c->get_span<float>(), - attribute_result->get_span_for_write_only<float>(), - operation); + GVArray_Typed<float> attribute_c = params.get_input_attribute<float>( + "C", component, result_domain, 0.0f); + do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation); } else { - do_math_operation(attribute_a->get_span<float>(), - attribute_b->get_span<float>(), - attribute_result->get_span_for_write_only<float>(), - operation); + do_math_operation(attribute_a, attribute_b, result_span, operation); } } else { - do_math_operation(attribute_a->get_span<float>(), - attribute_result->get_span_for_write_only<float>(), - operation); + do_math_operation(attribute_a, result_span, operation); } - attribute_result.apply_span_and_save(); + attribute_result.save(); } static void geo_node_attribute_math_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc index 9d8cd3dfa82..e7f0de8f28e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc @@ -58,10 +58,10 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), namespace blender::nodes { static void do_mix_operation_float(const int blend_mode, - const FloatReadAttribute &factors, - const FloatReadAttribute &inputs_a, - const FloatReadAttribute &inputs_b, - FloatWriteAttribute results) + const VArray<float> &factors, + const VArray<float> &inputs_a, + const VArray<float> &inputs_b, + VMutableArray<float> &results) { const int size = results.size(); for (const int i : IndexRange(size)) { @@ -75,10 +75,10 @@ static void do_mix_operation_float(const int blend_mode, } static void do_mix_operation_float3(const int blend_mode, - const FloatReadAttribute &factors, - const Float3ReadAttribute &inputs_a, - const Float3ReadAttribute &inputs_b, - Float3WriteAttribute results) + const VArray<float> &factors, + const VArray<float3> &inputs_a, + const VArray<float3> &inputs_b, + VMutableArray<float3> &results) { const int size = results.size(); for (const int i : IndexRange(size)) { @@ -91,10 +91,10 @@ static void do_mix_operation_float3(const int blend_mode, } static void do_mix_operation_color4f(const int blend_mode, - const FloatReadAttribute &factors, - const Color4fReadAttribute &inputs_a, - const Color4fReadAttribute &inputs_b, - Color4fWriteAttribute results) + const VArray<float> &factors, + const VArray<Color4f> &inputs_a, + const VArray<Color4f> &inputs_b, + VMutableArray<Color4f> &results) { const int size = results.size(); for (const int i : IndexRange(size)) { @@ -108,22 +108,31 @@ static void do_mix_operation_color4f(const int blend_mode, static void do_mix_operation(const CustomDataType result_type, int blend_mode, - const FloatReadAttribute &attribute_factor, - const ReadAttribute &attribute_a, - const ReadAttribute &attribute_b, - WriteAttribute &attribute_result) + const VArray<float> &attribute_factor, + const GVArray &attribute_a, + const GVArray &attribute_b, + GVMutableArray &attribute_result) { if (result_type == CD_PROP_FLOAT) { - do_mix_operation_float( - blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result); + do_mix_operation_float(blend_mode, + attribute_factor, + attribute_a.typed<float>(), + attribute_b.typed<float>(), + attribute_result.typed<float>()); } else if (result_type == CD_PROP_FLOAT3) { - do_mix_operation_float3( - blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result); + do_mix_operation_float3(blend_mode, + attribute_factor, + attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_result.typed<float3>()); } else if (result_type == CD_PROP_COLOR) { - do_mix_operation_color4f( - blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result); + do_mix_operation_color4f(blend_mode, + attribute_factor, + attribute_a.typed<Color4f>(), + attribute_b.typed<Color4f>(), + attribute_result.typed<Color4f>()); } } @@ -132,9 +141,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ @@ -158,17 +167,17 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa const AttributeDomain result_domain = get_result_domain(component, params, result_name); - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + OutputAttribute attribute_result = component.attribute_try_get_for_output_only( result_name, result_domain, result_type); if (!attribute_result) { return; } - FloatReadAttribute attribute_factor = params.get_input_attribute<float>( + GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>( "Factor", component, result_domain, 0.5f); - ReadAttributePtr attribute_a = params.get_input_attribute( + GVArrayPtr attribute_a = params.get_input_attribute( "A", component, result_domain, result_type, nullptr); - ReadAttributePtr attribute_b = params.get_input_attribute( + GVArrayPtr attribute_b = params.get_input_attribute( "B", component, result_domain, result_type, nullptr); do_mix_operation(result_type, diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc index f09a9bf056e..8e9892f00b6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc @@ -62,7 +62,7 @@ namespace blender::nodes { static void proximity_calc(MutableSpan<float> distance_span, MutableSpan<float3> location_span, - Span<float3> positions, + const VArray<float3> &positions, BVHTreeFromMesh &tree_data_mesh, BVHTreeFromPointCloud &tree_data_pointcloud, const bool bvh_mesh_success, @@ -169,19 +169,18 @@ static void attribute_calc_proximity(GeometryComponent &component, const AttributeDomain result_domain = ATTR_DOMAIN_POINT; const std::string distance_attribute_name = params.get_input<std::string>("Distance"); - OutputAttributePtr distance_attribute = component.attribute_try_get_for_output( - distance_attribute_name, result_domain, CD_PROP_FLOAT); + OutputAttribute_Typed<float> distance_attribute = + component.attribute_try_get_for_output_only<float>(distance_attribute_name, result_domain); const std::string location_attribute_name = params.get_input<std::string>("Position"); - OutputAttributePtr location_attribute = component.attribute_try_get_for_output( - location_attribute_name, result_domain, CD_PROP_FLOAT3); - - ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position"); - BLI_assert(position_attribute->custom_data_type() == CD_PROP_FLOAT3); + OutputAttribute_Typed<float3> location_attribute = + component.attribute_try_get_for_output_only<float3>(location_attribute_name, result_domain); + ReadAttributeLookup position_attribute = component.attribute_try_get_for_read("position"); if (!position_attribute || (!distance_attribute && !location_attribute)) { return; } + BLI_assert(position_attribute.varray->type().is<float3>()); const bNode &node = params.node(); const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *) @@ -204,18 +203,15 @@ static void attribute_calc_proximity(GeometryComponent &component, tree_data_pointcloud); } - Span<float3> position_span = position_attribute->get_span<float3>(); - - MutableSpan<float> distance_span = distance_attribute ? - distance_attribute->get_span_for_write_only<float>() : - MutableSpan<float>(); - MutableSpan<float3> location_span = location_attribute ? - location_attribute->get_span_for_write_only<float3>() : - MutableSpan<float3>(); + GVArray_Typed<float3> positions{*position_attribute.varray}; + MutableSpan<float> distance_span = distance_attribute ? distance_attribute.as_span() : + MutableSpan<float>(); + MutableSpan<float3> location_span = location_attribute ? location_attribute.as_span() : + MutableSpan<float3>(); proximity_calc(distance_span, location_span, - position_span, + positions, tree_data_mesh, tree_data_pointcloud, bvh_mesh_success, @@ -231,10 +227,10 @@ static void attribute_calc_proximity(GeometryComponent &component, } if (distance_attribute) { - distance_attribute.apply_span_and_save(); + distance_attribute.save(); } if (location_attribute) { - location_attribute.apply_span_and_save(); + location_attribute.save(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc index 28263287a10..e86fa3ae0ed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc @@ -173,12 +173,12 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo const int domain_size = component.attribute_domain_size(domain); /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ - ReadAttributePtr hash_attribute = component.attribute_try_get_for_read("id", domain); + GVArrayPtr hash_attribute = component.attribute_try_get_for_read("id", domain); Array<uint32_t> hashes(domain_size); if (hash_attribute) { BLI_assert(hashes.size() == hash_attribute->size()); - const CPPType &cpp_type = hash_attribute->cpp_type(); - fn::GSpan items = hash_attribute->get_span(); + const CPPType &cpp_type = hash_attribute->type(); + GVArray_GSpan items{*hash_attribute}; for (const int i : hashes.index_range()) { hashes[i] = cpp_type.hash(items[i]); } @@ -199,9 +199,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef attribute_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the input domain chosen in the interface. */ @@ -228,15 +228,13 @@ static void randomize_attribute_on_component(GeometryComponent &component, const AttributeDomain domain = get_result_domain(component, params, attribute_name); - OutputAttributePtr attribute = component.attribute_try_get_for_output( + OutputAttribute attribute = component.attribute_try_get_for_output( attribute_name, domain, data_type); if (!attribute) { return; } - fn::GMutableSpan span = (operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) ? - attribute->get_span_for_write_only() : - attribute->get_span(); + GMutableSpan span = attribute.as_span(); Array<uint32_t> hashes = get_geometry_element_ids_as_uints(component, domain); @@ -269,8 +267,8 @@ static void randomize_attribute_on_component(GeometryComponent &component, } } - attribute.apply_span_and_save(); -} // namespace blender::nodes + attribute.save(); +} static void geo_node_random_attribute_exec(GeoNodeExecParams params) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc index d0b2595b5b9..5b3fd75342a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc @@ -53,15 +53,16 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef map_attribute_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_attribute_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read( + result_attribute_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the name of the map attribute. */ - ReadAttributePtr map_attribute = component.attribute_try_get_for_read(map_attribute_name); + ReadAttributeLookup map_attribute = component.attribute_try_get_for_read(map_attribute_name); if (map_attribute) { - return map_attribute->domain(); + return map_attribute.domain; } /* The node won't execute in this case, but we still have to return a value. */ @@ -85,16 +86,16 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec const AttributeDomain result_domain = get_result_domain( component, result_attribute_name, mapping_name); - OutputAttributePtr attribute_out = component.attribute_try_get_for_output( - result_attribute_name, result_domain, CD_PROP_COLOR); + OutputAttribute_Typed<Color4f> attribute_out = + component.attribute_try_get_for_output_only<Color4f>(result_attribute_name, result_domain); if (!attribute_out) { return; } - Float3ReadAttribute mapping_attribute = component.attribute_get_for_read<float3>( + GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>( mapping_name, result_domain, {0, 0, 0}); - MutableSpan<Color4f> colors = attribute_out->get_span<Color4f>(); + MutableSpan<Color4f> colors = attribute_out.as_span(); for (const int i : IndexRange(mapping_attribute.size())) { TexResult texture_result = {0}; const float3 position = mapping_attribute[i]; @@ -103,7 +104,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec BKE_texture_get_value(nullptr, texture, remapped_position, &texture_result, false); colors[i] = {texture_result.tr, texture_result.tg, texture_result.tb, texture_result.ta}; } - attribute_out.apply_span_and_save(); + attribute_out.save(); } static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc index 656dc51149e..daf61b6bf57 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc @@ -77,17 +77,17 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, { /* Use the highest priority domain from any existing attribute outputs. */ Vector<AttributeDomain, 3> output_domains; - ReadAttributePtr attribute_x = component.attribute_try_get_for_read(result_name_x); - ReadAttributePtr attribute_y = component.attribute_try_get_for_read(result_name_y); - ReadAttributePtr attribute_z = component.attribute_try_get_for_read(result_name_z); + ReadAttributeLookup attribute_x = component.attribute_try_get_for_read(result_name_x); + ReadAttributeLookup attribute_y = component.attribute_try_get_for_read(result_name_y); + ReadAttributeLookup attribute_z = component.attribute_try_get_for_read(result_name_z); if (attribute_x) { - output_domains.append(attribute_x->domain()); + output_domains.append(attribute_x.domain); } if (attribute_y) { - output_domains.append(attribute_y->domain()); + output_domains.append(attribute_y.domain); } if (attribute_z) { - output_domains.append(attribute_z->domain()); + output_domains.append(attribute_z.domain); } if (output_domains.size() > 0) { return bke::attribute_domain_highest_priority(output_domains); @@ -107,37 +107,32 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa } /* The node is only for float3 to float conversions. */ - const CustomDataType input_type = CD_PROP_FLOAT3; - const CustomDataType result_type = CD_PROP_FLOAT; const AttributeDomain result_domain = get_result_domain( component, params, result_name_x, result_name_y, result_name_z); - ReadAttributePtr attribute_input = params.get_input_attribute( - "Vector", component, result_domain, input_type, nullptr); - if (!attribute_input) { - return; - } - const Span<float3> input_span = attribute_input->get_span<float3>(); + GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>( + "Vector", component, result_domain, {0, 0, 0}); + VArray_Span<float3> input_span{*attribute_input}; - OutputAttributePtr attribute_result_x = component.attribute_try_get_for_output( - result_name_x, result_domain, result_type); - OutputAttributePtr attribute_result_y = component.attribute_try_get_for_output( - result_name_y, result_domain, result_type); - OutputAttributePtr attribute_result_z = component.attribute_try_get_for_output( - result_name_z, result_domain, result_type); + OutputAttribute_Typed<float> attribute_result_x = + component.attribute_try_get_for_output_only<float>(result_name_x, result_domain); + OutputAttribute_Typed<float> attribute_result_y = + component.attribute_try_get_for_output_only<float>(result_name_y, result_domain); + OutputAttribute_Typed<float> attribute_result_z = + component.attribute_try_get_for_output_only<float>(result_name_z, result_domain); /* Only extract the components for the outputs with a given attribute. */ if (attribute_result_x) { - extract_input(0, input_span, attribute_result_x->get_span_for_write_only<float>()); - attribute_result_x.apply_span_and_save(); + extract_input(0, input_span, attribute_result_x.as_span()); + attribute_result_x.save(); } if (attribute_result_y) { - extract_input(1, input_span, attribute_result_y->get_span_for_write_only<float>()); - attribute_result_y.apply_span_and_save(); + extract_input(1, input_span, attribute_result_y.as_span()); + attribute_result_y.save(); } if (attribute_result_z) { - extract_input(2, input_span, attribute_result_z->get_span_for_write_only<float>()); - attribute_result_z.apply_span_and_save(); + extract_input(2, input_span, attribute_result_z.as_span()); + attribute_result_z.save(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc index 1ae095a27d2..86fbc9dc6d0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc @@ -168,16 +168,16 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod operation_use_input_c(operation)); } -static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a, - const Float3ReadAttribute &input_b, - Float3WriteAttribute result, +static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a, + const VArray<float3> &input_b, + VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); - Span<float3> span_a = input_a.get_span(); - Span<float3> span_b = input_b.get_span(); - MutableSpan<float3> span_result = result.get_span_for_write_only(); + VArray_Span<float3> span_a{input_a}; + VArray_Span<float3> span_b{input_b}; + VMutableArray_Span<float3> span_result{result, false}; bool success = try_dispatch_float_math_fl3_fl3_to_fl3( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { @@ -189,25 +189,25 @@ static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a, } }); - result.apply_span(); + span_result.save(); /* The operation is not supported by this node currently. */ BLI_assert(success); UNUSED_VARS_NDEBUG(success); } -static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a, - const Float3ReadAttribute &input_b, - const Float3ReadAttribute &input_c, - Float3WriteAttribute result, +static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a, + const VArray<float3> &input_b, + const VArray<float3> &input_c, + VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); - Span<float3> span_a = input_a.get_span(); - Span<float3> span_b = input_b.get_span(); - Span<float3> span_c = input_c.get_span(); - MutableSpan<float3> span_result = result.get_span_for_write_only(); + VArray_Span<float3> span_a{input_a}; + VArray_Span<float3> span_b{input_b}; + VArray_Span<float3> span_c{input_c}; + VMutableArray_Span<float3> span_result{result}; bool success = try_dispatch_float_math_fl3_fl3_fl3_to_fl3( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { @@ -220,25 +220,25 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &inpu } }); - result.apply_span(); + span_result.save(); /* The operation is not supported by this node currently. */ BLI_assert(success); UNUSED_VARS_NDEBUG(success); } -static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input_a, - const Float3ReadAttribute &input_b, - const FloatReadAttribute &input_c, - Float3WriteAttribute result, +static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a, + const VArray<float3> &input_b, + const VArray<float> &input_c, + VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); - Span<float3> span_a = input_a.get_span(); - Span<float3> span_b = input_b.get_span(); - Span<float> span_c = input_c.get_span(); - MutableSpan<float3> span_result = result.get_span_for_write_only(); + VArray_Span<float3> span_a{input_a}; + VArray_Span<float3> span_b{input_b}; + VArray_Span<float> span_c{input_c}; + VMutableArray_Span<float3> span_result{result, false}; bool success = try_dispatch_float_math_fl3_fl3_fl_to_fl3( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { @@ -251,23 +251,23 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input } }); - result.apply_span(); + span_result.save(); /* The operation is not supported by this node currently. */ BLI_assert(success); UNUSED_VARS_NDEBUG(success); } -static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a, - const Float3ReadAttribute &input_b, - FloatWriteAttribute result, +static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a, + const VArray<float3> &input_b, + VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); - Span<float3> span_a = input_a.get_span(); - Span<float3> span_b = input_b.get_span(); - MutableSpan<float> span_result = result.get_span_for_write_only(); + VArray_Span<float3> span_a{input_a}; + VArray_Span<float3> span_b{input_b}; + VMutableArray_Span<float> span_result{result, false}; bool success = try_dispatch_float_math_fl3_fl3_to_fl( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { @@ -279,23 +279,23 @@ static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a, } }); - result.apply_span(); + span_result.save(); /* The operation is not supported by this node currently. */ BLI_assert(success); UNUSED_VARS_NDEBUG(success); } -static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a, - const FloatReadAttribute &input_b, - Float3WriteAttribute result, +static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a, + const VArray<float> &input_b, + VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); - Span<float3> span_a = input_a.get_span(); - Span<float> span_b = input_b.get_span(); - MutableSpan<float3> span_result = result.get_span_for_write_only(); + VArray_Span<float3> span_a{input_a}; + VArray_Span<float> span_b{input_b}; + VMutableArray_Span<float3> span_result{result, false}; bool success = try_dispatch_float_math_fl3_fl_to_fl3( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { @@ -307,21 +307,21 @@ static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a, } }); - result.apply_span(); + span_result.save(); /* The operation is not supported by this node currently. */ BLI_assert(success); UNUSED_VARS_NDEBUG(success); } -static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a, - Float3WriteAttribute result, +static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a, + VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); - Span<float3> span_a = input_a.get_span(); - MutableSpan<float3> span_result = result.get_span_for_write_only(); + VArray_Span<float3> span_a{input_a}; + VMutableArray_Span<float3> span_result{result, false}; bool success = try_dispatch_float_math_fl3_to_fl3( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { @@ -332,21 +332,21 @@ static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a, } }); - result.apply_span(); + span_result.save(); /* The operation is not supported by this node currently. */ BLI_assert(success); UNUSED_VARS_NDEBUG(success); } -static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a, - FloatWriteAttribute result, +static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a, + VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); - Span<float3> span_a = input_a.get_span(); - MutableSpan<float> span_result = result.get_span_for_write_only(); + VArray_Span<float3> span_a{input_a}; + VMutableArray_Span<float> span_result{result, false}; bool success = try_dispatch_float_math_fl3_to_fl( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { @@ -357,7 +357,7 @@ static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a, } }); - result.apply_span(); + span_result.save(); /* The operation is not supported by this node currently. */ BLI_assert(success); @@ -370,9 +370,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef result_name) { /* Use the domain of the result attribute if it already exists. */ - ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name); if (result_attribute) { - return result_attribute->domain(); + return result_attribute.domain; } /* Otherwise use the highest priority domain from existing input attributes, or the default. */ @@ -406,13 +406,13 @@ static void attribute_vector_math_calc(GeometryComponent &component, const AttributeDomain result_domain = get_result_domain( component, params, operation, result_name); - ReadAttributePtr attribute_a = params.get_input_attribute( + GVArrayPtr attribute_a = params.get_input_attribute( "A", component, result_domain, read_type_a, nullptr); if (!attribute_a) { return; } - ReadAttributePtr attribute_b; - ReadAttributePtr attribute_c; + GVArrayPtr attribute_b; + GVArrayPtr attribute_c; if (use_input_b) { attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr); if (!attribute_b) { @@ -427,7 +427,7 @@ static void attribute_vector_math_calc(GeometryComponent &component, } /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ - OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + OutputAttribute attribute_result = component.attribute_try_get_for_output_only( result_name, result_domain, result_type); if (!attribute_result) { return; @@ -445,17 +445,27 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_MODULO: case NODE_VECTOR_MATH_MINIMUM: case NODE_VECTOR_MATH_MAXIMUM: - do_math_operation_fl3_fl3_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation); + do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(), + attribute_b->typed<float3>(), + attribute_result->typed<float3>(), + operation); break; case NODE_VECTOR_MATH_DOT_PRODUCT: case NODE_VECTOR_MATH_DISTANCE: - do_math_operation_fl3_fl3_to_fl(*attribute_a, *attribute_b, *attribute_result, operation); + do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(), + attribute_b->typed<float3>(), + attribute_result->typed<float>(), + operation); break; case NODE_VECTOR_MATH_LENGTH: - do_math_operation_fl3_to_fl(*attribute_a, *attribute_result, operation); + do_math_operation_fl3_to_fl( + attribute_a->typed<float3>(), attribute_result->typed<float>(), operation); break; case NODE_VECTOR_MATH_SCALE: - do_math_operation_fl3_fl_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation); + do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(), + attribute_b->typed<float>(), + attribute_result->typed<float3>(), + operation); break; case NODE_VECTOR_MATH_NORMALIZE: case NODE_VECTOR_MATH_FLOOR: @@ -465,16 +475,23 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_SINE: case NODE_VECTOR_MATH_COSINE: case NODE_VECTOR_MATH_TANGENT: - do_math_operation_fl3_to_fl3(*attribute_a, *attribute_result, operation); + do_math_operation_fl3_to_fl3( + attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation); break; case NODE_VECTOR_MATH_WRAP: case NODE_VECTOR_MATH_FACEFORWARD: - do_math_operation_fl3_fl3_fl3_to_fl3( - *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation); + do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(), + attribute_b->typed<float3>(), + attribute_c->typed<float3>(), + attribute_result->typed<float3>(), + operation); break; case NODE_VECTOR_MATH_REFRACT: - do_math_operation_fl3_fl3_fl_to_fl3( - *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation); + do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(), + attribute_b->typed<float3>(), + attribute_c->typed<float>(), + attribute_result->typed<float3>(), + operation); break; } attribute_result.save(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc index 96455f080e7..b6fa4c0d48f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc @@ -39,15 +39,12 @@ static void compute_min_max_from_position_and_transform(const GeometryComponent float3 &r_min, float3 &r_max) { - ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position"); - if (!position_attribute) { - BLI_assert(component.attribute_domain_size(ATTR_DOMAIN_POINT) == 0); - return; - } - Span<float3> positions = position_attribute->get_span<float3>(); + GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + "position", ATTR_DOMAIN_POINT, {0, 0, 0}); for (const float4x4 &transform : transforms) { - for (const float3 &position : positions) { + for (const int i : positions.index_range()) { + const float3 position = positions[i]; const float3 transformed_position = transform * position; minmax_v3v3_v3(r_min, r_max, transformed_position); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 52512769a47..857b60dfb93 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -149,10 +149,10 @@ static void determine_final_data_type_and_domain(Span<const GeometryComponent *> Vector<CustomDataType> data_types; Vector<AttributeDomain> domains; for (const GeometryComponent *component : components) { - ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name); + ReadAttributeLookup attribute = component->attribute_try_get_for_read(attribute_name); if (attribute) { - data_types.append(attribute->custom_data_type()); - domains.append(attribute->domain()); + data_types.append(bke::cpp_type_to_custom_data_type(attribute.varray->type())); + domains.append(attribute.domain); } } @@ -164,7 +164,7 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components, StringRef attribute_name, const CustomDataType data_type, const AttributeDomain domain, - fn::GMutableSpan dst_span) + GMutableSpan dst_span) { const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); @@ -175,10 +175,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components, if (domain_size == 0) { continue; } - ReadAttributePtr read_attribute = component->attribute_get_for_read( + GVArrayPtr read_attribute = component->attribute_get_for_read( attribute_name, domain, data_type, nullptr); - fn::GSpan src_span = read_attribute->get_span(); + GVArray_GSpan src_span{*read_attribute}; const void *src_buffer = src_span.data(); void *dst_buffer = dst_span[offset]; cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size); @@ -201,16 +201,14 @@ static void join_attributes(Span<const GeometryComponent *> src_components, AttributeDomain domain; determine_final_data_type_and_domain(src_components, attribute_name, &data_type, &domain); - OutputAttributePtr write_attribute = result.attribute_try_get_for_output( + OutputAttribute write_attribute = result.attribute_try_get_for_output_only( attribute_name, domain, data_type); - if (!write_attribute || - &write_attribute->cpp_type() != bke::custom_data_type_to_cpp_type(data_type) || - write_attribute->domain() != domain) { + if (!write_attribute) { continue; } - fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only(); + GMutableSpan dst_span = write_attribute.as_span(); fill_new_attribute(src_components, attribute_name, data_type, domain, dst_span); - write_attribute.apply_span_and_save(); + write_attribute.save(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 761d5d6c388..2806472286e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -194,9 +194,9 @@ static void calculate_uvs(Mesh *mesh, { MeshComponent mesh_component; mesh_component.replace(mesh, GeometryOwnershipType::Editable); - OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output( - "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr); - MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>(); + OutputAttribute_Typed<float2> uv_attribute = + mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER); + MutableSpan<float2> uvs = uv_attribute.as_span(); Array<float2> circle(verts_num); float angle = 0.0f; @@ -271,7 +271,7 @@ static void calculate_uvs(Mesh *mesh, } } - uv_attribute.apply_span_and_save(); + uv_attribute.save(); } Mesh *create_cylinder_or_cone_mesh(const float radius_top, diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 14c57bc7135..5a4bab86421 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -44,9 +44,9 @@ static void calculate_uvs( { MeshComponent mesh_component; mesh_component.replace(mesh, GeometryOwnershipType::Editable); - OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output( - "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr); - MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>(); + OutputAttribute_Typed<float2> uv_attribute = + mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER); + MutableSpan<float2> uvs = uv_attribute.as_span(); const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x; const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y; @@ -56,7 +56,7 @@ static void calculate_uvs( uvs[i].y = (co.y + size_y * 0.5f) * dy; } - uv_attribute.apply_span_and_save(); + uv_attribute.save(); } static Mesh *create_grid_mesh(const int verts_x, diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index fd95cdc81f7..cc93e71a5dd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -224,9 +224,9 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r { MeshComponent mesh_component; mesh_component.replace(mesh, GeometryOwnershipType::Editable); - OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output( - "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr); - MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>(); + OutputAttribute_Typed<float2> uv_attribute = + mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER); + MutableSpan<float2> uvs = uv_attribute.as_span(); int loop_index = 0; const float dy = 1.0f / rings; @@ -256,7 +256,7 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r uvs[loop_index++] = float2(segment / segments, 1.0f - dy); } - uv_attribute.apply_span_and_save(); + uv_attribute.save(); } static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 74cca8a2f3c..0f68378a8db 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -91,7 +91,7 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh) static void sample_mesh_surface(const Mesh &mesh, const float4x4 &transform, const float base_density, - const FloatReadAttribute *density_factors, + const VArray<float> *density_factors, const int seed, Vector<float3> &r_positions, Vector<float3> &r_bary_coords, @@ -113,9 +113,9 @@ static void sample_mesh_surface(const Mesh &mesh, float looptri_density_factor = 1.0f; if (density_factors != nullptr) { - const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]); - const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]); - const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]); + const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop)); + const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop)); + const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop)); looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f; } const float area = area_tri_v3(v0_pos, v1_pos, v2_pos); @@ -203,7 +203,7 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points( BLI_NOINLINE static void update_elimination_mask_based_on_density_factors( const Mesh &mesh, - const FloatReadAttribute &density_factors, + const VArray<float> &density_factors, Span<float3> bary_coords, Span<int> looptri_indices, MutableSpan<bool> elimination_mask) @@ -363,13 +363,13 @@ BLI_NOINLINE static void interpolate_existing_attributes( StringRef attribute_name = entry.key; const CustomDataType output_data_type = entry.value.data_type; /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */ - OutputAttributePtr attribute_out = component.attribute_try_get_for_output( + OutputAttribute attribute_out = component.attribute_try_get_for_output_only( attribute_name, ATTR_DOMAIN_POINT, output_data_type); if (!attribute_out) { continue; } - fn::GMutableSpan out_span = attribute_out->get_span_for_write_only(); + GMutableSpan out_span = attribute_out.as_span(); int i_instance = 0; for (const GeometryInstanceGroup &set_group : set_groups) { @@ -380,44 +380,41 @@ BLI_NOINLINE static void interpolate_existing_attributes( /* Use a dummy read without specifying a domain or data type in order to * get the existing attribute's domain. Interpolation is done manually based * on the bary coords in #interpolate_attribute. */ - ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read( + ReadAttributeLookup dummy_attribute = source_component.attribute_try_get_for_read( attribute_name); if (!dummy_attribute) { i_instance += set_group.transforms.size(); continue; } - const AttributeDomain source_domain = dummy_attribute->domain(); - ReadAttributePtr source_attribute = source_component.attribute_get_for_read( + const AttributeDomain source_domain = dummy_attribute.domain; + GVArrayPtr source_attribute = source_component.attribute_get_for_read( attribute_name, source_domain, output_data_type, nullptr); if (!source_attribute) { i_instance += set_group.transforms.size(); continue; } - fn::GSpan source_span = source_attribute->get_span(); attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) { using T = decltype(dummy); + GVArray_Span<T> source_span{*source_attribute}; + for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { const int offset = instance_start_offsets[i_instance]; Span<float3> bary_coords = bary_coords_array[i_instance]; Span<int> looptri_indices = looptri_indices_array[i_instance]; MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size()); - interpolate_attribute<T>(mesh, - bary_coords, - looptri_indices, - source_domain, - source_span.typed<T>(), - instance_span); + interpolate_attribute<T>( + mesh, bary_coords, looptri_indices, source_domain, source_span, instance_span); i_instance++; } }); } - attribute_out.apply_span_and_save(); + attribute_out.save(); } } @@ -427,16 +424,16 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup> Span<Vector<float3>> bary_coords_array, Span<Vector<int>> looptri_indices_array) { - OutputAttributePtr id_attribute = component.attribute_try_get_for_output( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); - OutputAttributePtr normal_attribute = component.attribute_try_get_for_output( - "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); - OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( - "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); + OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>( + "id", ATTR_DOMAIN_POINT); + OutputAttribute_Typed<float3> normal_attribute = + component.attribute_try_get_for_output_only<float3>("normal", ATTR_DOMAIN_POINT); + OutputAttribute_Typed<float3> rotation_attribute = + component.attribute_try_get_for_output_only<float3>("rotation", ATTR_DOMAIN_POINT); - MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>(); - MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>(); - MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>(); + MutableSpan<int> result_ids = id_attribute.as_span(); + MutableSpan<float3> result_normals = normal_attribute.as_span(); + MutableSpan<float3> result_rotations = rotation_attribute.as_span(); int i_instance = 0; for (const GeometryInstanceGroup &set_group : sets) { @@ -480,9 +477,9 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup> } } - id_attribute.apply_span_and_save(); - normal_attribute.apply_span_and_save(); - rotation_attribute.apply_span_and_save(); + id_attribute.save(); + normal_attribute.save(); + rotation_attribute.save(); } BLI_NOINLINE static void add_remaining_point_attributes( @@ -520,7 +517,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, for (const GeometryInstanceGroup &set_group : set_groups) { const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); - const FloatReadAttribute density_factors = component.attribute_get_for_read<float>( + GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); const Mesh &mesh = *component.get_for_read(); for (const float4x4 &transform : set_group.transforms) { @@ -530,7 +527,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, sample_mesh_surface(mesh, transform, density, - &density_factors, + &*density_factors, seed, positions, bary_coords, @@ -589,7 +586,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); const Mesh &mesh = *component.get_for_read(); - const FloatReadAttribute density_factors = component.attribute_get_for_read<float>( + const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index 20022e8d29d..65b7d068003 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -174,13 +174,13 @@ static void add_instances_from_geometry_component(InstancesComponent &instances, Array<std::optional<InstancedData>> instances_data = get_instanced_data( params, src_geometry, domain_size); - Float3ReadAttribute positions = src_geometry.attribute_get_for_read<float3>( + GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); - Float3ReadAttribute rotations = src_geometry.attribute_get_for_read<float3>( + GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>( "rotation", domain, {0, 0, 0}); - Float3ReadAttribute scales = src_geometry.attribute_get_for_read<float3>( + GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>( "scale", domain, {1, 1, 1}); - Int32ReadAttribute ids = src_geometry.attribute_get_for_read<int>("id", domain, -1); + GVArray_Typed<int> ids = src_geometry.attribute_get_for_read<int>("id", domain, -1); for (const int i : IndexRange(domain_size)) { if (instances_data[i].has_value()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc index 2e7fce6ea30..73d489949ad 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc @@ -60,8 +60,8 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), namespace blender::nodes { static void point_rotate__axis_angle__object_space(const int domain_size, - const Float3ReadAttribute &axis, - const FloatReadAttribute &angles, + const VArray<float3> &axis, + const VArray<float> &angles, MutableSpan<float3> rotations) { for (const int i : IndexRange(domain_size)) { @@ -76,8 +76,8 @@ static void point_rotate__axis_angle__object_space(const int domain_size, } static void point_rotate__axis_angle__point_space(const int domain_size, - const Float3ReadAttribute &axis, - const FloatReadAttribute &angles, + const VArray<float3> &axis, + const VArray<float> &angles, MutableSpan<float3> rotations) { for (const int i : IndexRange(domain_size)) { @@ -92,7 +92,7 @@ static void point_rotate__axis_angle__point_space(const int domain_size, } static void point_rotate__euler__object_space(const int domain_size, - const Float3ReadAttribute &eulers, + const VArray<float3> &eulers, MutableSpan<float3> rotations) { for (const int i : IndexRange(domain_size)) { @@ -107,7 +107,7 @@ static void point_rotate__euler__object_space(const int domain_size, } static void point_rotate__euler__point_space(const int domain_size, - const Float3ReadAttribute &eulers, + const VArray<float3> &eulers, MutableSpan<float3> rotations) { for (const int i : IndexRange(domain_size)) { @@ -127,19 +127,19 @@ static void point_rotate_on_component(GeometryComponent &component, const bNode &node = params.node(); const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage; - OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( - "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); + OutputAttribute_Typed<float3> rotation_attribute = + component.attribute_try_get_for_output<float3>("rotation", ATTR_DOMAIN_POINT, {0, 0, 0}); if (!rotation_attribute) { return; } - MutableSpan<float3> rotations = rotation_attribute->get_span<float3>(); + MutableSpan<float3> rotations = rotation_attribute.as_span(); const int domain_size = rotations.size(); if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) { - Float3ReadAttribute axis = params.get_input_attribute<float3>( + GVArray_Typed<float3> axis = params.get_input_attribute<float3>( "Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1}); - FloatReadAttribute angles = params.get_input_attribute<float>( + GVArray_Typed<float> angles = params.get_input_attribute<float>( "Angle", component, ATTR_DOMAIN_POINT, 0); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { @@ -150,7 +150,7 @@ static void point_rotate_on_component(GeometryComponent &component, } } else { - Float3ReadAttribute eulers = params.get_input_attribute<float3>( + GVArray_Typed<float3> eulers = params.get_input_attribute<float3>( "Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { @@ -161,7 +161,7 @@ static void point_rotate_on_component(GeometryComponent &component, } } - rotation_attribute.apply_span_and_save(); + rotation_attribute.save(); } static void geo_node_point_rotate_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc index 113e2c620f6..2ef21fb085b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc @@ -50,7 +50,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co * for the factor. But for it's simpler to simply always use float3, since that is usually * expected anyway. */ static const float3 scale_default = float3(1.0f); - OutputAttributePtr scale_attribute = component.attribute_try_get_for_output( + OutputAttribute_Typed<float3> scale_attribute = component.attribute_try_get_for_output( "scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, &scale_default); if (!scale_attribute) { return; @@ -63,27 +63,27 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT : CD_PROP_FLOAT3; - ReadAttributePtr attribute = params.get_input_attribute( + GVArrayPtr attribute = params.get_input_attribute( "Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr); if (!attribute) { return; } - MutableSpan<float3> scale_span = scale_attribute->get_span<float3>(); + MutableSpan<float3> scale_span = scale_attribute.as_span(); if (data_type == CD_PROP_FLOAT) { - Span<float> factors = attribute->get_span<float>(); + GVArray_Typed<float> factors{*attribute}; for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } } else if (data_type == CD_PROP_FLOAT3) { - Span<float3> factors = attribute->get_span<float3>(); + GVArray_Typed<float3> factors{*attribute}; for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } } - scale_attribute.apply_span_and_save(); + scale_attribute.save(); } static void geo_node_point_scale_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc index 522dea4aa0e..6541d982629 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc @@ -58,27 +58,27 @@ static void copy_attributes_based_on_mask(const GeometryComponent &in_component, const bool invert) { for (const std::string &name : in_component.attribute_names()) { - ReadAttributePtr attribute = in_component.attribute_try_get_for_read(name); - const CustomDataType data_type = attribute->custom_data_type(); + ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(name); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); /* Only copy point attributes. Theoretically this could interpolate attributes on other * domains to the point domain, but that would conflict with attributes that are built-in * on other domains, which causes creating the attributes to fail. */ - if (attribute->domain() != ATTR_DOMAIN_POINT) { + if (attribute.domain != ATTR_DOMAIN_POINT) { continue; } - OutputAttributePtr result_attribute = result_component.attribute_try_get_for_output( + OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( name, ATTR_DOMAIN_POINT, data_type); attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - Span<T> span = attribute->get_span<T>(); - MutableSpan<T> out_span = result_attribute->get_span_for_write_only<T>(); + GVArray_Span<T> span{*attribute.varray}; + MutableSpan<T> out_span = result_attribute.as_span<T>(); copy_data_based_on_mask(span, masks, invert, out_span); }); - result_attribute.apply_span_and_save(); + result_attribute.save(); } } @@ -107,9 +107,9 @@ static void separate_points_from_component(const GeometryComponent &in_component return; } - const BooleanReadAttribute mask_attribute = in_component.attribute_get_for_read<bool>( + const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>( mask_name, ATTR_DOMAIN_POINT, false); - Span<bool> masks = mask_attribute.get_span(); + VArray_Span<bool> masks{mask_attribute}; const int total = masks.count(!invert); if (total == 0) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc index 8c7387f7d9b..44203228899 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc @@ -42,24 +42,19 @@ namespace blender::nodes { static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component) { - OutputAttributePtr position_attribute = component.attribute_try_get_for_output( - "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); + OutputAttribute_Typed<float3> position_attribute = + component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0}); if (!position_attribute) { return; } - ReadAttributePtr attribute = params.get_input_attribute( - "Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr); - if (!attribute) { - return; - } + GVArray_Typed<float3> attribute = params.get_input_attribute<float3>( + "Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); - Span<float3> data = attribute->get_span<float3>(); - MutableSpan<float3> scale_span = position_attribute->get_span<float3>(); - for (const int i : scale_span.index_range()) { - scale_span[i] = scale_span[i] + data[i]; + for (const int i : IndexRange(attribute.size())) { + position_attribute->set(i, position_attribute->get(i) + attribute[i]); } - position_attribute.apply_span_and_save(); + position_attribute.save(); } static void geo_node_point_translate_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index a9eb136597e..d73c83b4caf 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -147,13 +147,15 @@ static void gather_point_data_from_component(const GeoNodeExecParams ¶ms, Vector<float3> &r_positions, Vector<float> &r_radii) { - Float3ReadAttribute positions = component.attribute_get_for_read<float3>( + GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - FloatReadAttribute radii = params.get_input_attribute<float>( + GVArray_Typed<float> radii = params.get_input_attribute<float>( "Radius", component, ATTR_DOMAIN_POINT, 0.0f); - r_positions.extend(positions.get_span()); - r_radii.extend(radii.get_span()); + for (const int i : IndexRange(positions.size())) { + r_positions.append(positions[i]); + r_radii.append(radii[i]); + } } static void convert_to_grid_index_space(const float voxel_size, diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index a4fb99a988e..2648336f0c0 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -22,6 +22,7 @@ #include "NOD_geometry_exec.hh" #include "NOD_type_callbacks.hh" +#include "NOD_type_conversions.hh" #include "node_geometry_util.hh" @@ -53,22 +54,29 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name return nullptr; } -ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const +GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const { const bNodeSocket *found_socket = this->find_available_socket(name); BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ + const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type); + const int64_t domain_size = component.attribute_domain_size(domain); + + if (default_value == nullptr) { + default_value = cpp_type->default_value(); + } + if (found_socket == nullptr) { - return component.attribute_get_constant_for_read(domain, type, default_value); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); } if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); /* Try getting the attribute without the default value. */ - ReadAttributePtr attribute = component.attribute_try_get_for_read(name, domain, type); + GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type); if (attribute) { return attribute; } @@ -80,25 +88,29 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name, this->error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + name + "\""); } - return component.attribute_get_constant_for_read(domain, type, default_value); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); } + const DataTypeConversions &conversions = get_implicit_type_conversions(); if (found_socket->type == SOCK_FLOAT) { const float value = this->get_input<float>(found_socket->identifier); - return component.attribute_get_constant_for_read_converted( - domain, CD_PROP_FLOAT, type, &value); + BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); + conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_VECTOR) { const float3 value = this->get_input<float3>(found_socket->identifier); - return component.attribute_get_constant_for_read_converted( - domain, CD_PROP_FLOAT3, type, &value); + BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); + conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_RGBA) { const Color4f value = this->get_input<Color4f>(found_socket->identifier); - return component.attribute_get_constant_for_read_converted( - domain, CD_PROP_COLOR, type, &value); + BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); + conversions.convert_to_uninitialized(CPPType::get<Color4f>(), *cpp_type, &value, buffer); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); } BLI_assert(false); - return component.attribute_get_constant_for_read(domain, type, default_value); + return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); } CustomDataType GeoNodeExecParams::get_input_attribute_data_type( @@ -114,11 +126,11 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type( if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); - ReadAttributePtr attribute = component.attribute_try_get_for_read(name); + ReadAttributeLookup attribute = component.attribute_try_get_for_read(name); if (!attribute) { return default_type; } - return attribute->custom_data_type(); + return bke::cpp_type_to_custom_data_type(attribute.varray->type()); } if (found_socket->type == SOCK_FLOAT) { return CD_PROP_FLOAT; @@ -157,9 +169,9 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain( if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); - ReadAttributePtr attribute = component.attribute_try_get_for_read(name); + ReadAttributeLookup attribute = component.attribute_try_get_for_read(name); if (attribute) { - input_domains.append(attribute->domain()); + input_domains.append(attribute.domain); } } } diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc index 1c1b7c7feb5..63f7b8a9ee8 100644 --- a/source/blender/nodes/intern/type_conversions.cc +++ b/source/blender/nodes/intern/type_conversions.cc @@ -24,6 +24,9 @@ namespace blender::nodes { +using fn::GVArrayPtr; +using fn::GVMutableArray; +using fn::GVMutableArrayPtr; using fn::MFDataType; template<typename From, typename To, To (*ConversionF)(const From &)> @@ -227,6 +230,11 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, const void *from_value, void *to_value) const { + if (from_type == to_type) { + from_type.copy_to_uninitialized(from_value, to_value); + return; + } + const ConversionFunctions *functions = this->get_conversion_functions( MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type)); BLI_assert(functions != nullptr); @@ -234,4 +242,108 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, functions->convert_single_to_uninitialized(from_value, to_value); } +class GVArray_For_ConvertedGVArray : public GVArray { + private: + GVArrayPtr varray_; + const CPPType &from_type_; + ConversionFunctions old_to_new_conversions_; + + public: + GVArray_For_ConvertedGVArray(GVArrayPtr varray, + const CPPType &to_type, + const DataTypeConversions &conversions) + : GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type()) + { + old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); + } + + private: + void get_impl(const int64_t index, void *r_value) const override + { + BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); + varray_->get(index, buffer); + old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); + from_type_.destruct(buffer); + } + + void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + { + BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); + varray_->get(index, buffer); + old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); + from_type_.destruct(buffer); + } +}; + +class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray { + private: + GVMutableArrayPtr varray_; + const CPPType &from_type_; + ConversionFunctions old_to_new_conversions_; + ConversionFunctions new_to_old_conversions_; + + public: + GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray, + const CPPType &to_type, + const DataTypeConversions &conversions) + : GVMutableArray(to_type, varray->size()), + varray_(std::move(varray)), + from_type_(varray_->type()) + { + old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); + new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_); + } + + private: + void get_impl(const int64_t index, void *r_value) const override + { + BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); + varray_->get(index, buffer); + old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); + from_type_.destruct(buffer); + } + + void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + { + BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); + varray_->get(index, buffer); + old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); + from_type_.destruct(buffer); + } + + void set_by_move_impl(const int64_t index, void *value) override + { + BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); + new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); + varray_->set_by_relocate(index, buffer); + } +}; + +fn::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr varray, + const CPPType &to_type) const +{ + const CPPType &from_type = varray->type(); + if (from_type == to_type) { + return varray; + } + if (!this->is_convertible(from_type, to_type)) { + return {}; + } + return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); +} + +fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr varray, + const CPPType &to_type) const +{ + const CPPType &from_type = varray->type(); + if (from_type == to_type) { + return varray; + } + if (!this->is_convertible(from_type, to_type)) { + return {}; + } + return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>( + std::move(varray), to_type, *this); +} + } // namespace blender::nodes |