diff options
author | Hans Goudey <h.goudey@me.com> | 2021-03-09 00:31:51 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-03-09 00:31:51 +0300 |
commit | d25ab68cf4b28c01281dd689a3926887fa7d32a4 (patch) | |
tree | 1edee10ee333914f1c03586b663e19774cb3bd62 /source | |
parent | 8df968d69f07d961097f646a405aa455e6a743f3 (diff) |
Cleanup: Complete earlier geometry component refactor
This was meant to be part of rB9ce950daabbf, but the change dropped from
the set at some point in the process of updating and committing.
Sorry for the noise.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/attribute_access.cc | 1589 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_set.cc | 431 |
3 files changed, 249 insertions, 1776 deletions
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index c954d0670f0..310ac6c4903 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -131,6 +131,10 @@ set(SRC intern/fmodifier.c intern/font.c intern/freestyle.c + intern/geometry_component_instances.cc + intern/geometry_component_mesh.cc + intern/geometry_component_pointcloud.cc + intern/geometry_component_volume.cc intern/geometry_set.cc intern/geometry_set_instances.cc intern/gpencil.c @@ -430,6 +434,7 @@ set(SRC nla_private.h particle_private.h tracking_private.h + intern/attribute_access_intern.hh intern/CCGSubSurf.h intern/CCGSubSurf_inline.h intern/CCGSubSurf_intern.h diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index b04af5327ca..01a1333c3ce 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -37,6 +37,8 @@ #include "NOD_node_tree_multi_function.hh" +#include "attribute_access_intern.hh" + static CLG_LogRef LOG = {"bke.attribute_access"}; using blender::float3; @@ -47,9 +49,6 @@ using blender::bke::ReadAttributePtr; using blender::bke::WriteAttributePtr; using blender::fn::GMutableSpan; -/* 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); - namespace blender::bke { /* -------------------------------------------------------------------- */ @@ -159,101 +158,6 @@ void WriteAttribute::apply_span_if_necessary() } } -class VertexWeightWriteAttribute final : public WriteAttribute { - 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) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - get_internal(dverts_, dvert_index_, index, r_value); - } - - void set_internal(const int64_t index, const void *value) override - { - MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); - weight->weight = *reinterpret_cast<const float *>(value); - } - - static void get_internal(const MDeformVert *dverts, - const int dvert_index, - const int64_t index, - void *r_value) - { - if (dverts == nullptr) { - *(float *)r_value = 0.0f; - return; - } - 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; - } - } - *(float *)r_value = 0.0f; - } -}; - -class VertexWeightReadAttribute final : public ReadAttribute { - 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) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_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. */ - } -}; - /* This is used by the #OutputAttributePtr class. */ class TemporaryWriteAttribute final : public WriteAttribute { public: @@ -302,135 +206,6 @@ class TemporaryWriteAttribute final : public WriteAttribute { } }; -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 &), - 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); - } -}; - -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); - } -}; - -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_); - } -}; - class ConvertedReadAttribute final : public ReadAttribute { private: const CPPType &from_type_; @@ -592,1027 +367,321 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) return highest_priority_domain; } -/** - * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component. - * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do - * not follow the same loose rules as other attributes, because they are mapped to internal - * "legacy" data structures. For example, some builtin attributes cannot be deleted. */ -class BuiltinAttributeProvider { - public: - /* Some utility enums to avoid hard to read booleans in function calls. */ - enum CreatableEnum { - Creatable, - NonCreatable, - }; - enum WritableEnum { - Writable, - Readonly, - }; - enum DeletableEnum { - Deletable, - NonDeletable, - }; - - protected: - const std::string name_; - const AttributeDomain domain_; - const CustomDataType data_type_; - const CreatableEnum createable_; - const WritableEnum writable_; - const DeletableEnum deletable_; - - public: - BuiltinAttributeProvider(std::string name, - const AttributeDomain domain, - const CustomDataType data_type, - const CreatableEnum createable, - const WritableEnum writable, - const DeletableEnum deletable) - : name_(std::move(name)), - domain_(domain), - data_type_(data_type), - createable_(createable), - writable_(writable), - deletable_(deletable) - { - } - - virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0; - virtual WriteAttributePtr 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; - - StringRefNull name() const - { - return name_; +ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read( + const GeometryComponent &component) const +{ + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; } - AttributeDomain domain() const - { - return domain_; + if (update_on_read_ != nullptr) { + update_on_read_(component); } - CustomDataType data_type() const - { - return data_type_; + const int domain_size = component.attribute_domain_size(domain_); + const void *data = CustomData_get_layer(custom_data, stored_type_); + if (data == nullptr) { + return {}; } -}; - -/** - * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each - * attribute has a name, domain and type. - */ -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 bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component), - const StringRef UNUSED(attribute_name), - const AttributeDomain UNUSED(domain), - const CustomDataType UNUSED(data_type)) const - { - /* Some providers should not create new attributes. */ - return false; - }; - - virtual bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const = 0; - virtual void supported_domains(Vector<AttributeDomain> &r_domains) const = 0; -}; - -/** - * Utility to group together multiple functions that are used to access custom data on geometry - * components in a generic way. - */ -struct CustomDataAccessInfo { - using CustomDataGetter = CustomData *(*)(GeometryComponent &component); - using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component); - using UpdateCustomDataPointers = void (*)(GeometryComponent &component); - - CustomDataGetter get_custom_data; - ConstCustomDataGetter get_const_custom_data; - UpdateCustomDataPointers update_custom_data_pointers; -}; - -/** - * This provider is used to provide access to builtin attributes. It supports making internal types - * available as different types. For example, the vertex position attribute is stored as part of - * 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 UpdateOnRead = void (*)(const GeometryComponent &component); - using UpdateOnWrite = void (*)(GeometryComponent &component); - const CustomDataType stored_type_; - const CustomDataAccessInfo custom_data_access_; - const AsReadAttribute as_read_attribute_; - const AsWriteAttribute as_write_attribute_; - const UpdateOnRead update_on_read_; - const UpdateOnWrite update_on_write_; + return as_read_attribute_(data, domain_size); +} - public: - BuiltinCustomDataLayerProvider(std::string attribute_name, - const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, - const CreatableEnum creatable, - const WritableEnum writable, - const DeletableEnum deletable, - const CustomDataAccessInfo custom_data_access, - const AsReadAttribute as_read_attribute, - const AsWriteAttribute as_write_attribute, - const UpdateOnRead update_on_read, - const UpdateOnWrite update_on_write) - : BuiltinAttributeProvider( - std::move(attribute_name), domain, attribute_type, creatable, writable, deletable), - stored_type_(stored_type), - custom_data_access_(custom_data_access), - as_read_attribute_(as_read_attribute), - as_write_attribute_(as_write_attribute), - update_on_read_(update_on_read), - update_on_write_(update_on_write) - { +WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write( + GeometryComponent &component) const +{ + if (writable_ != Writable) { + return {}; } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - - if (update_on_read_ != nullptr) { - update_on_read_(component); - } - - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_get_layer(custom_data, stored_type_); - if (data == nullptr) { - return {}; - } - return as_read_attribute_(data, domain_size); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; } - - WriteAttributePtr try_get_for_write(GeometryComponent &component) const final - { - if (writable_ != Writable) { - return {}; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - void *data = CustomData_get_layer(custom_data, stored_type_); - if (data == nullptr) { - return {}; - } - void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); - if (data != new_data) { - custom_data_access_.update_custom_data_pointers(component); - data = new_data; - } - if (update_on_write_ != nullptr) { - update_on_write_(component); - } - return as_write_attribute_(data, domain_size); + const int domain_size = component.attribute_domain_size(domain_); + void *data = CustomData_get_layer(custom_data, stored_type_); + if (data == nullptr) { + return {}; } - - bool try_delete(GeometryComponent &component) const final - { - if (deletable_ != Deletable) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - - const int domain_size = component.attribute_domain_size(domain_); - const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); - const bool delete_success = CustomData_free_layer( - custom_data, stored_type_, domain_size, layer_index); - if (delete_success) { - custom_data_access_.update_custom_data_pointers(component); - } - return delete_success; + void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); + if (data != new_data) { + custom_data_access_.update_custom_data_pointers(component); + data = new_data; } - - bool try_create(GeometryComponent &component) const final - { - if (createable_ != Creatable) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { - /* Exists already. */ - return false; - } - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_add_layer( - custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size); - const bool success = data != nullptr; - if (success) { - custom_data_access_.update_custom_data_pointers(component); - } - return success; + if (update_on_write_ != nullptr) { + update_on_write_(component); } + return as_write_attribute_(data, domain_size); +} - bool exists(const GeometryComponent &component) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return false; - } - const void *data = CustomData_get_layer(custom_data, stored_type_); - return data != nullptr; - } -}; - -/** - * This is the attribute provider for most user generated attributes. - */ -class CustomDataAttributeProvider final : public DynamicAttributesProvider { - private: - static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | - CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | - CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL; - const AttributeDomain domain_; - const CustomDataAccessInfo custom_data_access_; - - public: - CustomDataAttributeProvider(const AttributeDomain domain, - const CustomDataAccessInfo custom_data_access) - : domain_(domain), custom_data_access_(custom_data_access) - { +bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const +{ + if (deletable_ != Deletable) { + return false; } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.name != attribute_name) { - continue; - } - const CustomDataType data_type = (CustomDataType)layer.type; - switch (data_type) { - case CD_PROP_FLOAT: - return this->layer_to_read_attribute<float>(layer, domain_size); - case CD_PROP_FLOAT2: - return this->layer_to_read_attribute<float2>(layer, domain_size); - case CD_PROP_FLOAT3: - return this->layer_to_read_attribute<float3>(layer, domain_size); - case CD_PROP_INT32: - return this->layer_to_read_attribute<int>(layer, domain_size); - case CD_PROP_COLOR: - return this->layer_to_read_attribute<Color4f>(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_read_attribute<bool>(layer, domain_size); - default: - break; - } - } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { return {}; } - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { - if (layer.name != attribute_name) { - continue; - } - CustomData_duplicate_referenced_layer_named( - custom_data, layer.type, layer.name, domain_size); - const CustomDataType data_type = (CustomDataType)layer.type; - switch (data_type) { - case CD_PROP_FLOAT: - return this->layer_to_write_attribute<float>(layer, domain_size); - case CD_PROP_FLOAT2: - return this->layer_to_write_attribute<float2>(layer, domain_size); - case CD_PROP_FLOAT3: - return this->layer_to_write_attribute<float3>(layer, domain_size); - case CD_PROP_INT32: - return this->layer_to_write_attribute<int>(layer, domain_size); - case CD_PROP_COLOR: - return this->layer_to_write_attribute<Color4f>(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_write_attribute<bool>(layer, domain_size); - default: - break; - } - } - return {}; + const int domain_size = component.attribute_domain_size(domain_); + const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); + const bool delete_success = CustomData_free_layer( + custom_data, stored_type_, domain_size, layer_index); + if (delete_success) { + custom_data_access_.update_custom_data_pointers(component); } + return delete_success; +} - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - const int domain_size = component.attribute_domain_size(domain_); - for (const int i : IndexRange(custom_data->totlayer)) { - const CustomDataLayer &layer = custom_data->layers[i]; - if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) { - CustomData_free_layer(custom_data, layer.type, domain_size, i); - return true; - } - } +bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const +{ + if (createable_ != Creatable) { return false; } - - bool try_create(GeometryComponent &component, - const StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type) const final - { - if (domain_ != domain) { - return false; - } - if (!this->type_is_supported(data_type)) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.name == attribute_name) { - return false; - } - } - const int domain_size = component.attribute_domain_size(domain_); - char attribute_name_c[MAX_NAME]; - attribute_name.copy(attribute_name_c); - CustomData_add_layer_named( - custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); - return true; + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; } - - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return true; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - const CustomDataType data_type = (CustomDataType)layer.type; - if (this->type_is_supported(data_type)) { - AttributeMetaData meta_data{domain_, data_type}; - if (!callback(layer.name, meta_data)) { - return false; - } - } - } - return true; + if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { + /* Exists already. */ + return false; } - - void supported_domains(Vector<AttributeDomain> &r_domains) const final - { - r_domains.append_non_duplicates(domain_); + const int domain_size = component.attribute_domain_size(domain_); + const void *data = CustomData_add_layer( + custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size); + const bool success = data != nullptr; + if (success) { + custom_data_access_.update_custom_data_pointers(component); } + return success; +} - private: - template<typename T> - ReadAttributePtr 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)); +bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const +{ + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return false; } + const void *data = CustomData_get_layer(custom_data, stored_type_); + return data != nullptr; +} - template<typename T> - WriteAttributePtr 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)); +ReadAttributePtr 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); + if (custom_data == nullptr) { + return {}; } - - bool type_is_supported(CustomDataType data_type) const - { - return ((1ULL << data_type) & supported_types_mask) != 0; + const int domain_size = component.attribute_domain_size(domain_); + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.name != attribute_name) { + continue; + } + const CustomDataType data_type = (CustomDataType)layer.type; + switch (data_type) { + case CD_PROP_FLOAT: + return this->layer_to_read_attribute<float>(layer, domain_size); + case CD_PROP_FLOAT2: + return this->layer_to_read_attribute<float2>(layer, domain_size); + case CD_PROP_FLOAT3: + return this->layer_to_read_attribute<float3>(layer, domain_size); + case CD_PROP_INT32: + return this->layer_to_read_attribute<int>(layer, domain_size); + case CD_PROP_COLOR: + return this->layer_to_read_attribute<Color4f>(layer, domain_size); + case CD_PROP_BOOL: + return this->layer_to_read_attribute<bool>(layer, domain_size); + default: + break; + } } -}; - -static Mesh *get_mesh_from_component_for_write(GeometryComponent &component) -{ - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - return mesh_component.get_for_write(); + return {}; } -static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component) +WriteAttributePtr CustomDataAttributeProvider::try_get_for_write( + GeometryComponent &component, const StringRef attribute_name) const { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - return mesh_component.get_for_read(); -} - -/** - * This attribute provider is used for uv maps and vertex colors. - */ -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); - const AttributeDomain domain_; - const CustomDataType attribute_type_; - const CustomDataType stored_type_; - const CustomDataAccessInfo custom_data_access_; - const AsReadAttribute as_read_attribute_; - const AsWriteAttribute as_write_attribute_; - - public: - NamedLegacyCustomDataProvider(const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, - const CustomDataAccessInfo custom_data_access, - const AsReadAttribute as_read_attribute, - const AsWriteAttribute as_write_attribute) - : domain_(domain), - attribute_type_(attribute_type), - stored_type_(stored_type), - custom_data_access_(custom_data_access), - as_read_attribute_(as_read_attribute), - as_write_attribute_(as_write_attribute) - { - } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - 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); - } - } - } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { return {}; } - - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; + const int domain_size = component.attribute_domain_size(domain_); + for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { + if (layer.name != attribute_name) { + continue; + } + CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_size); + const CustomDataType data_type = (CustomDataType)layer.type; + switch (data_type) { + case CD_PROP_FLOAT: + return this->layer_to_write_attribute<float>(layer, domain_size); + case CD_PROP_FLOAT2: + return this->layer_to_write_attribute<float2>(layer, domain_size); + case CD_PROP_FLOAT3: + return this->layer_to_write_attribute<float3>(layer, domain_size); + case CD_PROP_INT32: + return this->layer_to_write_attribute<int>(layer, domain_size); + case CD_PROP_COLOR: + return this->layer_to_write_attribute<Color4f>(layer, domain_size); + case CD_PROP_BOOL: + return this->layer_to_write_attribute<bool>(layer, domain_size); + default: + break; } - for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - void *data_old = layer.data; - void *data_new = CustomData_duplicate_referenced_layer_named( - custom_data, stored_type_, layer.name, domain_size); - if (data_old != data_new) { - custom_data_access_.update_custom_data_pointers(component); - } - return as_write_attribute_(layer.data, domain_size); - } - } - } - return {}; } + return {}; +} - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - for (const int i : IndexRange(custom_data->totlayer)) { - const CustomDataLayer &layer = custom_data->layers[i]; - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - CustomData_free_layer(custom_data, stored_type_, domain_size, i); - custom_data_access_.update_custom_data_pointers(component); - return true; - } - } - } +bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, + const StringRef attribute_name) const +{ + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { return false; } - - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { + const int domain_size = component.attribute_domain_size(domain_); + for (const int i : IndexRange(custom_data->totlayer)) { + const CustomDataLayer &layer = custom_data->layers[i]; + if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) { + CustomData_free_layer(custom_data, layer.type, domain_size, i); return true; } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - AttributeMetaData meta_data{domain_, attribute_type_}; - if (!callback(layer.name, meta_data)) { - return false; - } - } - } - return true; } + return false; +} - void supported_domains(Vector<AttributeDomain> &r_domains) const final - { - r_domains.append_non_duplicates(domain_); +bool CustomDataAttributeProvider::try_create(GeometryComponent &component, + const StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type) const +{ + if (domain_ != domain) { + return false; } -}; - -/** - * This provider makes vertex groups available as float attributes. - */ -class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { - public: - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - const Mesh *mesh = mesh_component.get_for_read(); - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { - return {}; - } - 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<VertexWeightReadAttribute>( - mesh->dvert, mesh->totvert, vertex_group_index); + if (!this->type_is_supported(data_type)) { + return false; } - - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - Mesh *mesh = mesh_component.get_for_write(); - if (mesh == nullptr) { - return {}; - } - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { - return {}; - } - if (mesh->dvert == nullptr) { - BKE_object_defgroup_data_create(&mesh->id); - } - else { - /* Copy the data layer if it is shared with some other mesh. */ - 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); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; } - - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - - const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.name == attribute_name) { return false; } - Mesh *mesh = mesh_component.get_for_write(); - if (mesh == nullptr) { - return true; - } - if (mesh->dvert == nullptr) { - return true; - } - for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) { - MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index); - BKE_defvert_remove_group(&dvert, weight); - } - return true; } + const int domain_size = component.attribute_domain_size(domain_); + char attribute_name_c[MAX_NAME]; + attribute_name.copy(attribute_name_c); + CustomData_add_layer_named( + custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + return true; +} - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - for (const auto item : mesh_component.vertex_group_names().items()) { - const StringRefNull name = item.key; - const int vertex_group_index = item.value; - if (vertex_group_index >= 0) { - AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT}; - if (!callback(name, meta_data)) { - return false; - } - } - } +bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const +{ + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { return true; } - - void supported_domains(Vector<AttributeDomain> &r_domains) const final - { - r_domains.append_non_duplicates(ATTR_DOMAIN_POINT); - } -}; - -/** - * This is a container for multiple attribute providers that are used by one geometry component - * type (e.g. there is a set of attribute providers for mesh components). - */ -class ComponentAttributeProviders { - private: - /** - * Builtin attribute providers are identified by their name. Attribute names that are in this - * map will only be accessed using builtin attribute providers. Therefore, these providers have - * higher priority when an attribute name is looked up. Usually, that means that builtin - * providers are checked before dynamic ones. - */ - Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_; - /** - * An ordered list of dynamic attribute providers. The order is important because that is order - * in which they are checked when an attribute is looked up. - */ - Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_; - /** - * All the domains that are supported by at least one of the providers above. - */ - Vector<AttributeDomain> supported_domains_; - - public: - ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers, - Span<const DynamicAttributesProvider *> dynamic_attribute_providers) - : dynamic_attribute_providers_(dynamic_attribute_providers) - { - Set<AttributeDomain> domains; - for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) { - /* Use #add_new to make sure that no two builtin attributes have the same name. */ - builtin_attribute_providers_.add_new(provider->name(), provider); - supported_domains_.append_non_duplicates(provider->domain()); - } - for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) { - provider->supported_domains(supported_domains_); + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + const CustomDataType data_type = (CustomDataType)layer.type; + if (this->type_is_supported(data_type)) { + AttributeMetaData meta_data{domain_, data_type}; + if (!callback(layer.name, meta_data)) { + return false; + } } } - - const Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() const - { - return builtin_attribute_providers_; - } - - Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const - { - return dynamic_attribute_providers_; - } - - Span<AttributeDomain> supported_domains() const - { - return supported_domains_; - } -}; - -static float3 get_vertex_position(const MVert &vert) -{ - return float3(vert.co); -} - -static void set_vertex_position(MVert &vert, const float3 &position) -{ - copy_v3_v3(vert.co, position); -} - -static ReadAttributePtr make_vertex_position_read_attribute(const void *data, - const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>( - ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size)); -} - -static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>( - ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size)); + return true; } -static void tag_normals_dirty_when_writing_position(GeometryComponent &component) +ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read( + const GeometryComponent &component, const StringRef attribute_name) const { - Mesh *mesh = get_mesh_from_component_for_write(component); - if (mesh != nullptr) { - mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + 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 {}; } -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) -{ - mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); -} - -static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>( - ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); -} - -static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>( - ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); -} - -static float3 get_vertex_normal(const MVert &vert) -{ - float3 result; - normal_short_to_float_v3(result, vert.no); - return result; -} - -static ReadAttributePtr make_vertex_normal_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_normal>>( - ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size)); -} - -static void update_vertex_normals_when_dirty(const GeometryComponent &component) +WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write( + GeometryComponent &component, const StringRef attribute_name) const { - const Mesh *mesh = get_mesh_from_component_for_read(component); - if (mesh == nullptr) { - return; + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; } - - /* Since normals are derived data, `const` write access to them is okay. However, ensure that - * two threads don't use write normals to a mesh at the same time. Note that this relies on - * the idempotence of the operation; calculating the normals just fills the #MVert struct - * rather than allocating new memory. */ - if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { - ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; - BLI_mutex_lock(mesh_eval_mutex); - - /* Check again to avoid a second thread needlessly recalculating the same normals. */ - if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { - BKE_mesh_calc_normals(const_cast<Mesh *>(mesh)); + for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + void *data_old = layer.data; + void *data_new = CustomData_duplicate_referenced_layer_named( + custom_data, stored_type_, layer.name, domain_size); + if (data_old != data_new) { + custom_data_access_.update_custom_data_pointers(component); + } + return as_write_attribute_(layer.data, domain_size); + } } - - BLI_mutex_unlock(mesh_eval_mutex); } + return {}; } -static float2 get_loop_uv(const MLoopUV &uv) -{ - return float2(uv.uv); -} - -static void set_loop_uv(MLoopUV &uv, const float2 &co) -{ - copy_v2_v2(uv.uv, co); -} - -static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>( - ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size)); -} - -static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size)); -} - -static Color4f get_loop_color(const MLoopCol &col) -{ - Color4f value; - rgba_uchar_to_float(value, &col.r); - return value; -} - -static void set_loop_color(MLoopCol &col, const Color4f &value) -{ - rgba_float_to_uchar(&col.r, value); -} - -static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>( - ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size)); -} - -static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size)); -} - -template<typename T, AttributeDomain Domain> -static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size) +bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component, + const StringRef attribute_name) const { - return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size)); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; + } + for (const int i : IndexRange(custom_data->totlayer)) { + const CustomDataLayer &layer = custom_data->layers[i]; + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + CustomData_free_layer(custom_data, stored_type_, domain_size, i); + custom_data_access_.update_custom_data_pointers(component); + return true; + } + } + } + return false; } -template<typename T, AttributeDomain Domain> -static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size) +bool NamedLegacyCustomDataProvider::foreach_attribute( + const GeometryComponent &component, const AttributeForeachCallback callback) const { - return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size)); -} - -/** - * In this function all the attribute providers for a mesh component are created. Most data in this - * function is statically allocated, because it does not change over time. - */ -static ComponentAttributeProviders create_attribute_providers_for_mesh() -{ - static auto update_custom_data_pointers = [](GeometryComponent &component) { - Mesh *mesh = get_mesh_from_component_for_write(component); - if (mesh != nullptr) { - BKE_mesh_update_customdata_pointers(mesh, false); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return true; + } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + AttributeMetaData meta_data{domain_, attribute_type_}; + if (!callback(layer.name, meta_data)) { + return false; + } } - }; - -#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ - [](GeometryComponent &component) -> CustomData * { \ - Mesh *mesh = get_mesh_from_component_for_write(component); \ - return mesh ? &mesh->NAME : nullptr; \ - } -#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \ - [](const GeometryComponent &component) -> const CustomData * { \ - const Mesh *mesh = get_mesh_from_component_for_read(component); \ - return mesh ? &mesh->NAME : nullptr; \ - } - - static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), - MAKE_CONST_CUSTOM_DATA_GETTER(ldata), - update_custom_data_pointers}; - static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), - MAKE_CONST_CUSTOM_DATA_GETTER(vdata), - update_custom_data_pointers}; - static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), - MAKE_CONST_CUSTOM_DATA_GETTER(edata), - update_custom_data_pointers}; - static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), - MAKE_CONST_CUSTOM_DATA_GETTER(pdata), - update_custom_data_pointers}; - -#undef MAKE_CONST_CUSTOM_DATA_GETTER -#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER - - static BuiltinCustomDataLayerProvider position("position", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_MVERT, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_vertex_position_read_attribute, - make_vertex_position_write_attribute, - nullptr, - tag_normals_dirty_when_writing_position); - - static BuiltinCustomDataLayerProvider material_index("material_index", - ATTR_DOMAIN_POLYGON, - CD_PROP_INT32, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - polygon_access, - make_material_index_read_attribute, - make_material_index_write_attribute, - nullptr, - nullptr); - - static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_MVERT, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Readonly, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_vertex_normal_read_attribute, - nullptr, - update_vertex_normals_when_dirty, - nullptr); - - static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, - CD_PROP_FLOAT2, - CD_MLOOPUV, - corner_access, - make_uvs_read_attribute, - make_uvs_write_attribute); - - static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER, - CD_PROP_COLOR, - CD_MLOOPCOL, - corner_access, - make_vertex_color_read_attribute, - make_vertex_color_write_attribute); - - static VertexGroupsAttributeProvider vertex_groups; - static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); - static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); - static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); - - return ComponentAttributeProviders({&position, &material_index, &vertex_normal}, - {&uvs, - &vertex_colors, - &corner_custom_data, - &vertex_groups, - &point_custom_data, - &edge_custom_data, - &polygon_custom_data}); + } + return true; } -/** - * In this function all the attribute providers for a point cloud component are created. Most data - * in this function is statically allocated, because it does not change over time. - */ -static ComponentAttributeProviders create_attribute_providers_for_point_cloud() +void NamedLegacyCustomDataProvider::supported_domains(Vector<AttributeDomain> &r_domains) const { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component); - PointCloud *pointcloud = pointcloud_component.get_for_write(); - if (pointcloud != nullptr) { - BKE_pointcloud_update_customdata_pointers(pointcloud); - } - }; - static CustomDataAccessInfo point_access = { - [](GeometryComponent &component) -> CustomData * { - PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component); - PointCloud *pointcloud = pointcloud_component.get_for_write(); - return pointcloud ? &pointcloud->pdata : nullptr; - }, - [](const GeometryComponent &component) -> const CustomData * { - const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>( - component); - const PointCloud *pointcloud = pointcloud_component.get_for_read(); - return pointcloud ? &pointcloud->pdata : nullptr; - }, - 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, - 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, - nullptr); - static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); + r_domains.append_non_duplicates(domain_); } } // namespace blender::bke @@ -2056,173 +1125,3 @@ void OutputAttributePtr::apply_span_and_save() } /** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Point Cloud Component - * \{ */ - -const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers() - const -{ - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_point_cloud(); - return &providers; -} - -int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const -{ - BLI_assert(domain == ATTR_DOMAIN_POINT); - UNUSED_VARS_NDEBUG(domain); - if (pointcloud_ == nullptr) { - return 0; - } - return pointcloud_->totpoint; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Mesh Component - * \{ */ - -const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const -{ - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_mesh(); - return &providers; -} - -int MeshComponent::attribute_domain_size(const AttributeDomain domain) const -{ - BLI_assert(this->attribute_domain_supported(domain)); - if (mesh_ == nullptr) { - return 0; - } - switch (domain) { - case ATTR_DOMAIN_CORNER: - return mesh_->totloop; - case ATTR_DOMAIN_POINT: - return mesh_->totvert; - case ATTR_DOMAIN_EDGE: - return mesh_->totedge; - case ATTR_DOMAIN_POLYGON: - return mesh_->totpoly; - default: - BLI_assert(false); - break; - } - return 0; -} - -namespace blender::bke { - -template<typename T> -static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, - const TypedReadAttribute<T> &attribute, - 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 MLoop &loop = mesh.mloop[loop_index]; - const int point_index = loop.v; - mixer.mix_in(point_index, value); - } - mixer.finalize(); -} - -static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, - ReadAttributePtr attribute) -{ - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_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)); - } - }); - return new_attribute; -} - -template<typename T> -static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, - const TypedReadAttribute<T> &attribute, - 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]; - } -} - -static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, - ReadAttributePtr attribute) -{ - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_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 - * lazily lookup the mesh topology when a specific index accessed. This can be more efficient - * 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)); - }); - return new_attribute; -} - -} // namespace blender::bke - -ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute, - const AttributeDomain new_domain) const -{ - if (!attribute) { - return {}; - } - if (attribute->size() == 0) { - return {}; - } - const AttributeDomain old_domain = attribute->domain(); - if (old_domain == new_domain) { - return attribute; - } - - switch (old_domain) { - case ATTR_DOMAIN_CORNER: { - switch (new_domain) { - case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); - default: - break; - } - break; - } - case ATTR_DOMAIN_POINT: { - switch (new_domain) { - case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); - default: - break; - } - } - default: - break; - } - - return {}; -} - -/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 0274dfdbd1c..e7fb184023d 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -311,437 +311,6 @@ Volume *GeometrySet::get_volume_for_write() /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mesh Component - * \{ */ - -MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh) -{ -} - -MeshComponent::~MeshComponent() -{ - this->clear(); -} - -GeometryComponent *MeshComponent::copy() const -{ - MeshComponent *new_component = new MeshComponent(); - if (mesh_ != nullptr) { - new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - new_component->vertex_group_names_ = blender::Map(vertex_group_names_); - } - return new_component; -} - -void MeshComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (mesh_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, mesh_); - } - mesh_ = nullptr; - } - vertex_group_names_.clear(); -} - -bool MeshComponent::has_mesh() const -{ - return mesh_ != nullptr; -} - -/* Clear the component and replace it with the new mesh. */ -void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - mesh_ = mesh; - ownership_ = ownership; -} - -/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to - * be able to replace the mesh data without losing the vertex group names, which may have come - * from another object. */ -void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh, - GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - if (mesh_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, mesh_); - } - mesh_ = nullptr; - } - mesh_ = mesh; - ownership_ = ownership; -} - -/* Return the mesh and clear the component. The caller takes over responsibility for freeing the - * mesh (if the component was responsible before). */ -Mesh *MeshComponent::release() -{ - BLI_assert(this->is_mutable()); - Mesh *mesh = mesh_; - mesh_ = nullptr; - return mesh; -} - -void MeshComponent::copy_vertex_group_names_from_object(const Object &object) -{ - BLI_assert(this->is_mutable()); - vertex_group_names_.clear(); - int index = 0; - LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) { - vertex_group_names_.add(group->name, index); - index++; - } -} - -const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const -{ - return vertex_group_names_; -} - -/* This is only exposed for the internal attribute API. */ -blender::Map<std::string, int> &MeshComponent::vertex_group_names() -{ - return vertex_group_names_; -} - -/* Get the mesh from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */ -const Mesh *MeshComponent::get_for_read() const -{ - return mesh_; -} - -/* Get the mesh from this component. This method can only be used when the component is mutable, - * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */ -Mesh *MeshComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - mesh_ = BKE_mesh_copy_for_eval(mesh_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return mesh_; -} - -bool MeshComponent::is_empty() const -{ - return mesh_ == nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Pointcloud Component - * \{ */ - -PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud) -{ -} - -PointCloudComponent::~PointCloudComponent() -{ - this->clear(); -} - -GeometryComponent *PointCloudComponent::copy() const -{ - PointCloudComponent *new_component = new PointCloudComponent(); - if (pointcloud_ != nullptr) { - new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - } - return new_component; -} - -void PointCloudComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (pointcloud_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, pointcloud_); - } - pointcloud_ = nullptr; - } -} - -bool PointCloudComponent::has_pointcloud() const -{ - return pointcloud_ != nullptr; -} - -/* Clear the component and replace it with the new point cloud. */ -void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - pointcloud_ = pointcloud; - ownership_ = ownership; -} - -/* Return the point cloud and clear the component. The caller takes over responsibility for freeing - * the point cloud (if the component was responsible before). */ -PointCloud *PointCloudComponent::release() -{ - BLI_assert(this->is_mutable()); - PointCloud *pointcloud = pointcloud_; - pointcloud_ = nullptr; - return pointcloud; -} - -/* Get the point cloud from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned point cloud should not be modified. No ownership is transferred. - */ -const PointCloud *PointCloudComponent::get_for_read() const -{ - return pointcloud_; -} - -/* Get the point cloud from this component. This method can only be used when the component is - * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is - * transferred. */ -PointCloud *PointCloudComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return pointcloud_; -} - -bool PointCloudComponent::is_empty() const -{ - return pointcloud_ == nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Instances Component - * \{ */ - -InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances) -{ -} - -GeometryComponent *InstancesComponent::copy() const -{ - InstancesComponent *new_component = new InstancesComponent(); - new_component->transforms_ = transforms_; - new_component->instanced_data_ = instanced_data_; - return new_component; -} - -void InstancesComponent::clear() -{ - instanced_data_.clear(); - transforms_.clear(); -} - -void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id) -{ - InstancedData data; - data.type = INSTANCE_DATA_TYPE_OBJECT; - data.data.object = object; - this->add_instance(data, transform, id); -} - -void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id) -{ - InstancedData data; - data.type = INSTANCE_DATA_TYPE_COLLECTION; - data.data.collection = collection; - this->add_instance(data, transform, id); -} - -void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id) -{ - instanced_data_.append(data); - transforms_.append(transform); - ids_.append(id); -} - -Span<InstancedData> InstancesComponent::instanced_data() const -{ - return instanced_data_; -} - -Span<float4x4> InstancesComponent::transforms() const -{ - return transforms_; -} - -Span<int> InstancesComponent::ids() const -{ - return ids_; -} - -MutableSpan<float4x4> InstancesComponent::transforms() -{ - return transforms_; -} - -int InstancesComponent::instances_amount() const -{ - const int size = instanced_data_.size(); - BLI_assert(transforms_.size() == size); - return size; -} - -bool InstancesComponent::is_empty() const -{ - return transforms_.size() == 0; -} - -static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) -{ - using namespace blender; - Array<int> unique_ids(original_ids.size()); - - Set<int> used_unique_ids; - used_unique_ids.reserve(original_ids.size()); - Vector<int> instances_with_id_collision; - for (const int instance_index : original_ids.index_range()) { - const int original_id = original_ids[instance_index]; - if (used_unique_ids.add(original_id)) { - /* The original id has not been used by another instance yet. */ - unique_ids[instance_index] = original_id; - } - else { - /* The original id of this instance collided with a previous instance, it needs to be looked - * at again in a second pass. Don't generate a new random id here, because this might collide - * with other existing ids. */ - instances_with_id_collision.append(instance_index); - } - } - - Map<int, RandomNumberGenerator> generator_by_original_id; - for (const int instance_index : instances_with_id_collision) { - const int original_id = original_ids[instance_index]; - RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() { - RandomNumberGenerator rng; - rng.seed_random(original_id); - return rng; - }); - - const int max_iteration = 100; - for (int iteration = 0;; iteration++) { - /* Try generating random numbers until an unused one has been found. */ - const int random_id = rng.get_int32(); - if (used_unique_ids.add(random_id)) { - /* This random id is not used by another instance. */ - unique_ids[instance_index] = random_id; - break; - } - if (iteration == max_iteration) { - /* It seems to be very unlikely that we ever run into this case (assuming there are less - * than 2^30 instances). However, if that happens, it's better to use an id that is not - * unique than to be stuck in an infinite loop. */ - unique_ids[instance_index] = original_id; - break; - } - } - } - - return unique_ids; -} - -blender::Span<int> InstancesComponent::almost_unique_ids() const -{ - std::lock_guard lock(almost_unique_ids_mutex_); - if (almost_unique_ids_.size() != ids_.size()) { - almost_unique_ids_ = generate_unique_instance_ids(ids_); - } - return almost_unique_ids_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Volume Component - * \{ */ - -VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume) -{ -} - -VolumeComponent::~VolumeComponent() -{ - this->clear(); -} - -GeometryComponent *VolumeComponent::copy() const -{ - VolumeComponent *new_component = new VolumeComponent(); - if (volume_ != nullptr) { - new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - } - return new_component; -} - -void VolumeComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (volume_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, volume_); - } - volume_ = nullptr; - } -} - -bool VolumeComponent::has_volume() const -{ - return volume_ != nullptr; -} - -/* Clear the component and replace it with the new volume. */ -void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - volume_ = volume; - ownership_ = ownership; -} - -/* Return the volume and clear the component. The caller takes over responsibility for freeing the - * volume (if the component was responsible before). */ -Volume *VolumeComponent::release() -{ - BLI_assert(this->is_mutable()); - Volume *volume = volume_; - volume_ = nullptr; - return volume; -} - -/* Get the volume from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned volume should not be modified. No ownership is transferred. */ -const Volume *VolumeComponent::get_for_read() const -{ - return volume_; -} - -/* Get the volume from this component. This method can only be used when the component is mutable, - * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */ -Volume *VolumeComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - volume_ = BKE_volume_copy_for_eval(volume_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return volume_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name C API * \{ */ |