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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh66
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc1382
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc11
3 files changed, 935 insertions, 524 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 2bed1a36ed7..9a871574f6f 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -68,6 +68,10 @@ template<> struct DefaultHash<GeometryComponentType> {
};
} // namespace blender
+namespace blender::bke {
+struct ComponentAttributeProviders;
+}
+
class GeometryComponent;
/**
@@ -152,23 +156,18 @@ class GeometryComponent {
bool attribute_exists(const blender::StringRef attribute_name) const;
/* Returns true when the geometry component supports this attribute domain. */
- virtual bool attribute_domain_supported(const AttributeDomain domain) const;
- /* Returns true when the given data type is supported in the given domain. */
- virtual bool attribute_domain_with_type_supported(const AttributeDomain domain,
- const CustomDataType data_type) const;
+ bool attribute_domain_supported(const AttributeDomain domain) const;
/* Can only be used with supported domain types. */
virtual int attribute_domain_size(const AttributeDomain domain) const;
- /* Attributes with these names cannot be created or removed via this api. */
- virtual 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. */
- virtual blender::bke::ReadAttributePtr attribute_try_get_for_read(
+ blender::bke::ReadAttributePtr 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. */
- virtual blender::bke::WriteAttributePtr attribute_try_get_for_write(
+ blender::bke::WriteAttributePtr 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
@@ -178,14 +177,14 @@ class GeometryComponent {
blender::bke::ReadAttributePtr attribute, const AttributeDomain domain) const;
/* Returns true when the attribute has been deleted. */
- virtual bool attribute_try_delete(const blender::StringRef attribute_name);
+ bool attribute_try_delete(const blender::StringRef attribute_name);
/* Returns true when the attribute has been created. */
- virtual bool attribute_try_create(const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type);
+ bool attribute_try_create(const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type);
- virtual blender::Set<std::string> attribute_names() const;
+ blender::Set<std::string> attribute_names() const;
virtual bool is_empty() const;
/* Get a read-only attribute for the given domain and data type.
@@ -257,6 +256,9 @@ class GeometryComponent {
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr);
+
+ private:
+ virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
};
template<typename T>
@@ -359,30 +361,20 @@ class MeshComponent : public GeometryComponent {
Mesh *release();
void copy_vertex_group_names_from_object(const struct Object &object);
+ const blender::Map<std::string, int> &vertex_group_names() const;
+ blender::Map<std::string, int> &vertex_group_names();
const Mesh *get_for_read() const;
Mesh *get_for_write();
- bool attribute_domain_supported(const AttributeDomain domain) const final;
- bool attribute_domain_with_type_supported(const AttributeDomain domain,
- const CustomDataType data_type) const final;
int attribute_domain_size(const AttributeDomain domain) const final;
- bool attribute_is_builtin(const blender::StringRef attribute_name) const final;
-
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
- const blender::StringRef attribute_name) const final;
- blender::bke::WriteAttributePtr attribute_try_get_for_write(
- const blender::StringRef attribute_name) final;
- bool attribute_try_delete(const blender::StringRef attribute_name) final;
- bool attribute_try_create(const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type) final;
-
- blender::Set<std::string> attribute_names() const final;
bool is_empty() const final;
static constexpr inline GeometryComponentType static_type = GeometryComponentType::Mesh;
+
+ private:
+ const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
/** A geometry component that stores a point cloud. */
@@ -405,26 +397,14 @@ class PointCloudComponent : public GeometryComponent {
const PointCloud *get_for_read() const;
PointCloud *get_for_write();
- bool attribute_domain_supported(const AttributeDomain domain) const final;
- bool attribute_domain_with_type_supported(const AttributeDomain domain,
- const CustomDataType data_type) const final;
int attribute_domain_size(const AttributeDomain domain) const final;
- bool attribute_is_builtin(const blender::StringRef attribute_name) const final;
-
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
- const blender::StringRef attribute_name) const final;
- blender::bke::WriteAttributePtr attribute_try_get_for_write(
- const blender::StringRef attribute_name) final;
- bool attribute_try_delete(const blender::StringRef attribute_name) final;
- bool attribute_try_create(const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type) final;
-
- blender::Set<std::string> attribute_names() const final;
bool is_empty() const final;
static constexpr inline GeometryComponentType static_type = GeometryComponentType::PointCloud;
+
+ private:
+ const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
/** A geometry component that stores instances. */
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 85dabe4490c..772309349ff 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -323,29 +323,24 @@ template<typename T> class ArrayReadAttribute final : public ReadAttribute {
}
};
-template<typename StructT, typename ElemT, typename GetFuncT, typename SetFuncT>
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, const ElemT &)>
class DerivedArrayWriteAttribute final : public WriteAttribute {
private:
MutableSpan<StructT> data_;
- GetFuncT get_function_;
- SetFuncT set_function_;
public:
- DerivedArrayWriteAttribute(AttributeDomain domain,
- MutableSpan<StructT> data,
- GetFuncT get_function,
- SetFuncT set_function)
- : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()),
- data_(data),
- get_function_(std::move(get_function)),
- set_function_(std::move(set_function))
+ 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 = get_function_(struct_value);
+ const ElemT value = GetFunc(struct_value);
new (r_value) ElemT(value);
}
@@ -353,28 +348,25 @@ class DerivedArrayWriteAttribute final : public WriteAttribute {
{
StructT &struct_value = data_[index];
const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
- set_function_(struct_value, typed_value);
+ SetFunc(struct_value, typed_value);
}
};
-template<typename StructT, typename ElemT, typename GetFuncT>
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
class DerivedArrayReadAttribute final : public ReadAttribute {
private:
Span<StructT> data_;
- GetFuncT get_function_;
public:
- DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data, GetFuncT get_function)
- : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()),
- data_(data),
- get_function_(std::move(get_function))
+ 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 = get_function_(struct_value);
+ const ElemT value = GetFunc(struct_value);
new (r_value) ElemT(value);
}
};
@@ -492,144 +484,835 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type)
return static_cast<CustomDataType>(-1);
}
-} // namespace blender::bke
+/**
+ * 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 bools in function calls. */
+ enum CreatableEnum {
+ Creatable,
+ NonCreatable,
+ };
+ enum WritableEnum {
+ Writable,
+ Readonly,
+ };
+ enum DeletableEnum {
+ Deletable,
+ NonDeletable,
+ };
-/* -------------------------------------------------------------------- */
-/** \name Utilities for Accessing Attributes
- * \{ */
+ protected:
+ const std::string name_;
+ const AttributeDomain domain_;
+ const CustomDataType data_type_;
+ const CreatableEnum createable_;
+ const WritableEnum writable_;
+ const DeletableEnum deletable_;
-static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom_data,
- const int size,
- const StringRef attribute_name,
- const AttributeDomain domain)
-{
- using namespace blender;
- using namespace blender::bke;
- for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) {
- if (layer.name != nullptr && layer.name == attribute_name) {
- switch (layer.type) {
+ 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_;
+ }
+
+ AttributeDomain domain() const
+ {
+ return domain_;
+ }
+
+ CustomDataType data_type() const
+ {
+ return data_type_;
+ }
+};
+
+/**
+ * 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 void list(const GeometryComponent &component, Set<std::string> &r_names) 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);
+ const CustomDataType stored_type_;
+ const CustomDataAccessInfo custom_data_access_;
+ const AsReadAttribute as_read_attribute_;
+ const AsWriteAttribute as_write_attribute_;
+
+ 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)
+ : 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)
+ {
+ }
+
+ 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 {};
+ }
+ 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);
+ }
+
+ 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;
+ }
+ return as_write_attribute_(data, domain_size);
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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, data_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)
+ {
+ }
+
+ 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 std::make_unique<ArrayReadAttribute<float>>(
- domain, Span(static_cast<float *>(layer.data), size));
+ return this->layer_to_read_attribute<float>(layer, domain_size);
case CD_PROP_FLOAT2:
- return std::make_unique<ArrayReadAttribute<float2>>(
- domain, Span(static_cast<float2 *>(layer.data), size));
+ return this->layer_to_read_attribute<float2>(layer, domain_size);
case CD_PROP_FLOAT3:
- return std::make_unique<ArrayReadAttribute<float3>>(
- domain, Span(static_cast<float3 *>(layer.data), size));
+ return this->layer_to_read_attribute<float3>(layer, domain_size);
case CD_PROP_INT32:
- return std::make_unique<ArrayReadAttribute<int>>(
- domain, Span(static_cast<int *>(layer.data), size));
+ return this->layer_to_read_attribute<int>(layer, domain_size);
case CD_PROP_COLOR:
- return std::make_unique<ArrayReadAttribute<Color4f>>(
- domain, Span(static_cast<Color4f *>(layer.data), size));
+ return this->layer_to_read_attribute<Color4f>(layer, domain_size);
case CD_PROP_BOOL:
- return std::make_unique<ArrayReadAttribute<bool>>(
- domain, Span(static_cast<bool *>(layer.data), size));
- case CD_MLOOPUV:
- auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); };
- return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, decltype(get_uv)>>(
- domain, Span(static_cast<MLoopUV *>(layer.data), size), get_uv);
+ return this->layer_to_read_attribute<bool>(layer, domain_size);
+ default:
+ break;
}
}
+ return {};
}
- return {};
-}
-
-static WriteAttributePtr write_attribute_from_custom_data(
- CustomData &custom_data,
- const int size,
- const StringRef attribute_name,
- const AttributeDomain domain,
- const std::function<void()> &update_customdata_pointers)
-{
- using namespace blender;
- using namespace blender::bke;
- for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) {
- if (layer.name != nullptr && layer.name == attribute_name) {
- const void *data_before = layer.data;
- /* The data layer might be shared with someone else. Since the caller wants to modify it, we
- * copy it first. */
- CustomData_duplicate_referenced_layer_named(&custom_data, layer.type, layer.name, size);
- if (data_before != layer.data) {
- update_customdata_pointers();
+ 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;
}
- switch (layer.type) {
+ 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 std::make_unique<ArrayWriteAttribute<float>>(
- domain, MutableSpan(static_cast<float *>(layer.data), size));
+ return this->layer_to_write_attribute<float>(layer, domain_size);
case CD_PROP_FLOAT2:
- return std::make_unique<ArrayWriteAttribute<float2>>(
- domain, MutableSpan(static_cast<float2 *>(layer.data), size));
+ return this->layer_to_write_attribute<float2>(layer, domain_size);
case CD_PROP_FLOAT3:
- return std::make_unique<ArrayWriteAttribute<float3>>(
- domain, MutableSpan(static_cast<float3 *>(layer.data), size));
+ return this->layer_to_write_attribute<float3>(layer, domain_size);
case CD_PROP_INT32:
- return std::make_unique<ArrayWriteAttribute<int>>(
- domain, MutableSpan(static_cast<int *>(layer.data), size));
+ return this->layer_to_write_attribute<int>(layer, domain_size);
case CD_PROP_COLOR:
- return std::make_unique<ArrayWriteAttribute<Color4f>>(
- domain, MutableSpan(static_cast<Color4f *>(layer.data), size));
+ return this->layer_to_write_attribute<Color4f>(layer, domain_size);
case CD_PROP_BOOL:
- return std::make_unique<ArrayWriteAttribute<bool>>(
- domain, MutableSpan(static_cast<bool *>(layer.data), size));
- case CD_MLOOPUV:
- auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); };
- auto set_uv = [](MLoopUV &uv, const float2 value) { copy_v2_v2(uv.uv, value); };
- return std::make_unique<
- DerivedArrayWriteAttribute<MLoopUV, float2, decltype(get_uv), decltype(set_uv)>>(
- domain, MutableSpan(static_cast<MLoopUV *>(layer.data), size), get_uv, set_uv);
+ return this->layer_to_write_attribute<bool>(layer, domain_size);
+ default:
+ break;
}
}
+ 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;
+ }
+ 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;
+ }
+ }
+ 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;
+ }
+
+ void list(const GeometryComponent &component, Set<std::string> &r_names) 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 (this->type_is_supported((CustomDataType)layer.type)) {
+ r_names.add(layer.name);
+ }
+ }
+ }
+
+ void supported_domains(Vector<AttributeDomain> &r_domains) const final
+ {
+ r_domains.append_non_duplicates(domain_);
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ bool type_is_supported(CustomDataType data_type) const
+ {
+ return ((1ULL << data_type) & supported_types_mask) != 0;
+ }
+};
+
+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();
}
-/* Returns true when the layer was found and is deleted. */
-static bool delete_named_custom_data_layer(CustomData &custom_data,
- const StringRef attribute_name,
- const int size)
+static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component)
{
- for (const int index : blender::IndexRange(custom_data.totlayer)) {
- const CustomDataLayer &layer = custom_data.layers[index];
- if (layer.name == attribute_name) {
- CustomData_free_layer(&custom_data, layer.type, size, index);
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return mesh_component.get_for_read();
+}
+
+/**
+ * This attribute provider makes uv maps available as float2 attributes.
+ */
+class MeshUVsAttributeProvider final : public DynamicAttributesProvider {
+ public:
+ ReadAttributePtr try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final
+ {
+ const Mesh *mesh = get_mesh_from_component_for_read(component);
+ if (mesh == nullptr) {
+ return {};
+ }
+ for (const CustomDataLayer &layer : Span(mesh->ldata.layers, mesh->ldata.totlayer)) {
+ if (layer.type == CD_MLOOPUV) {
+ if (layer.name == attribute_name) {
+ return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>(
+ ATTR_DOMAIN_CORNER, Span(static_cast<const MLoopUV *>(layer.data), mesh->totloop));
+ }
+ }
+ }
+ return {};
+ }
+
+ WriteAttributePtr try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final
+ {
+ Mesh *mesh = get_mesh_from_component_for_write(component);
+ if (mesh == nullptr) {
+ return {};
+ }
+ for (CustomDataLayer &layer : MutableSpan(mesh->ldata.layers, mesh->ldata.totlayer)) {
+ if (layer.type == CD_MLOOPUV) {
+ if (layer.name == attribute_name) {
+ void *data_old = layer.data;
+ void *data_new = CustomData_duplicate_referenced_layer_named(
+ &mesh->ldata, CD_MLOOPUV, layer.name, mesh->totloop);
+ if (data_old != data_new) {
+ BKE_mesh_update_customdata_pointers(mesh, false);
+ }
+ return std::make_unique<
+ DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>(
+ ATTR_DOMAIN_CORNER, MutableSpan(static_cast<MLoopUV *>(layer.data), mesh->totloop));
+ }
+ }
+ }
+ return {};
+ }
+
+ bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
+ {
+ Mesh *mesh = get_mesh_from_component_for_write(component);
+ if (mesh == nullptr) {
+ return false;
+ }
+ for (const int i : IndexRange(mesh->ldata.totlayer)) {
+ const CustomDataLayer &layer = mesh->ldata.layers[i];
+ if (layer.type == CD_MLOOPUV && layer.name == attribute_name) {
+ CustomData_free_layer(&mesh->ldata, CD_MLOOPUV, mesh->totloop, i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void list(const GeometryComponent &component, Set<std::string> &r_names) const final
+ {
+ const Mesh *mesh = get_mesh_from_component_for_read(component);
+ if (mesh == nullptr) {
+ return;
+ }
+ for (const CustomDataLayer &layer : Span(mesh->ldata.layers, mesh->ldata.totlayer)) {
+ if (layer.type == CD_MLOOPUV) {
+ r_names.add(layer.name);
+ }
+ }
+ }
+
+ void supported_domains(Vector<AttributeDomain> &r_domains) const final
+ {
+ r_domains.append_non_duplicates(ATTR_DOMAIN_CORNER);
+ }
+
+ private:
+ 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);
+ }
+};
+
+/**
+ * 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);
+ }
+
+ 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);
+ }
+
+ 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) {
+ 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;
}
- return false;
+
+ void list(const GeometryComponent &component, Set<std::string> &r_names) const final
+ {
+ BLI_assert(component.type() == GeometryComponentType::Mesh);
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ mesh_component.vertex_group_names().foreach_item(
+ [&](StringRef name, const int vertex_group_index) {
+ if (vertex_group_index >= 0) {
+ r_names.add(name);
+ }
+ });
+ }
+
+ 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_);
+ }
+ }
+
+ 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));
}
-static void get_custom_data_layer_attribute_names(const CustomData &custom_data,
- const GeometryComponent &component,
- const AttributeDomain domain,
- Set<std::string> &r_names)
+template<typename T, AttributeDomain Domain>
+static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
{
- for (const CustomDataLayer &layer : blender::Span(custom_data.layers, custom_data.totlayer)) {
- const CustomDataType data_type = static_cast<CustomDataType>(layer.type);
- if (component.attribute_domain_with_type_supported(domain, data_type) ||
- ELEM(data_type, CD_MLOOPUV)) {
- r_names.add(layer.name);
+ return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
+}
+
+template<typename T, AttributeDomain Domain>
+static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
+{
+ 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);
}
- }
+ };
+
+#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);
+ static MeshUVsAttributeProvider uvs;
+ 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},
+ {&uvs,
+ &corner_custom_data,
+ &vertex_groups,
+ &point_custom_data,
+ &edge_custom_data,
+ &polygon_custom_data});
}
-/** \} */
+/**
+ * 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()
+{
+ 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>);
+ 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>);
+ static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
+ return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
+}
+
+} // namespace blender::bke
/* -------------------------------------------------------------------- */
/** \name Geometry Component
* \{ */
-bool GeometryComponent::attribute_domain_supported(const AttributeDomain UNUSED(domain)) const
+const blender::bke::ComponentAttributeProviders *GeometryComponent::get_attribute_providers() const
{
- return false;
+ return nullptr;
}
-bool GeometryComponent::attribute_domain_with_type_supported(
- const AttributeDomain UNUSED(domain), const CustomDataType UNUSED(data_type)) const
+bool GeometryComponent::attribute_domain_supported(const AttributeDomain domain) const
{
- return false;
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return false;
+ }
+ return providers->supported_domains().contains(domain);
}
int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain)) const
@@ -638,14 +1321,26 @@ int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain
return 0;
}
-bool GeometryComponent::attribute_is_builtin(const StringRef UNUSED(attribute_name)) const
-{
- return true;
-}
-
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
- const StringRef UNUSED(attribute_name)) const
+ const StringRef attribute_name) const
{
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return {};
+ }
+ 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);
+ }
+ for (const DynamicAttributesProvider *dynamic_provider :
+ providers->dynamic_attribute_providers()) {
+ ReadAttributePtr attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
+ if (attribute) {
+ return attribute;
+ }
+ }
return {};
}
@@ -658,27 +1353,95 @@ ReadAttributePtr GeometryComponent::attribute_try_adapt_domain(ReadAttributePtr
return {};
}
-WriteAttributePtr GeometryComponent::attribute_try_get_for_write(
- const StringRef UNUSED(attribute_name))
+WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef attribute_name)
{
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return {};
+ }
+ 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);
+ }
+ for (const DynamicAttributesProvider *dynamic_provider :
+ providers->dynamic_attribute_providers()) {
+ WriteAttributePtr attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
+ if (attribute) {
+ return attribute;
+ }
+ }
return {};
}
-bool GeometryComponent::attribute_try_delete(const StringRef UNUSED(attribute_name))
+bool GeometryComponent::attribute_try_delete(const StringRef attribute_name)
{
- return false;
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return {};
+ }
+ const BuiltinAttributeProvider *builtin_provider =
+ providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
+ if (builtin_provider != nullptr) {
+ return builtin_provider->try_delete(*this);
+ }
+ bool success = false;
+ for (const DynamicAttributesProvider *dynamic_provider :
+ providers->dynamic_attribute_providers()) {
+ success = dynamic_provider->try_delete(*this, attribute_name) || success;
+ }
+ return success;
}
-bool GeometryComponent::attribute_try_create(const StringRef UNUSED(attribute_name),
- const AttributeDomain UNUSED(domain),
- const CustomDataType UNUSED(data_type))
+bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type)
{
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return {};
+ }
+ const BuiltinAttributeProvider *builtin_provider =
+ providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
+ if (builtin_provider != nullptr) {
+ if (builtin_provider->domain() != domain) {
+ return false;
+ }
+ if (builtin_provider->data_type() != data_type) {
+ return false;
+ }
+ return builtin_provider->try_create(*this);
+ }
+ for (const DynamicAttributesProvider *dynamic_provider :
+ providers->dynamic_attribute_providers()) {
+ if (dynamic_provider->try_create(*this, attribute_name, domain, data_type)) {
+ return true;
+ }
+ }
return false;
}
Set<std::string> GeometryComponent::attribute_names() const
{
- return {};
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return {};
+ }
+ Set<std::string> names;
+ for (const BuiltinAttributeProvider *provider :
+ providers->builtin_attribute_providers().values()) {
+ if (provider->exists(*this)) {
+ names.add_new(provider->name());
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers->dynamic_attribute_providers()) {
+ provider->list(*this, names);
+ }
+ return names;
}
bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
@@ -712,10 +1475,6 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
const AttributeDomain domain,
const CustomDataType data_type) const
{
- if (!this->attribute_domain_with_type_supported(domain, data_type)) {
- return {};
- }
-
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
if (!attribute) {
return {};
@@ -767,8 +1526,6 @@ ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attri
const CustomDataType data_type,
const void *default_value) const
{
- BLI_assert(this->attribute_domain_with_type_supported(domain, data_type));
-
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type);
if (attribute) {
return attribute;
@@ -828,8 +1585,6 @@ OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringR
const CustomDataType data_type,
const void *default_value)
{
- BLI_assert(this->attribute_domain_with_type_supported(domain, data_type));
-
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
@@ -957,21 +1712,12 @@ void OutputAttributePtr::apply_span_and_save()
/** \name Point Cloud Component
* \{ */
-bool PointCloudComponent::attribute_domain_supported(const AttributeDomain domain) const
-{
- return domain == ATTR_DOMAIN_POINT;
-}
-
-bool PointCloudComponent::attribute_domain_with_type_supported(
- const AttributeDomain domain, const CustomDataType data_type) const
+const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers()
+ const
{
- return domain == ATTR_DOMAIN_POINT && ELEM(data_type,
- CD_PROP_BOOL,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT2,
- CD_PROP_FLOAT3,
- CD_PROP_INT32,
- CD_PROP_COLOR);
+ static blender::bke::ComponentAttributeProviders providers =
+ blender::bke::create_attribute_providers_for_point_cloud();
+ return &providers;
}
int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const
@@ -984,119 +1730,17 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con
return pointcloud_->totpoint;
}
-bool PointCloudComponent::attribute_is_builtin(const StringRef attribute_name) const
-{
- return attribute_name == "position";
-}
-
-ReadAttributePtr PointCloudComponent::attribute_try_get_for_read(
- const StringRef attribute_name) const
-{
- if (pointcloud_ == nullptr) {
- return {};
- }
-
- return read_attribute_from_custom_data(
- pointcloud_->pdata, pointcloud_->totpoint, attribute_name, ATTR_DOMAIN_POINT);
-}
-
-WriteAttributePtr PointCloudComponent::attribute_try_get_for_write(const StringRef attribute_name)
-{
- PointCloud *pointcloud = this->get_for_write();
- if (pointcloud == nullptr) {
- return {};
- }
-
- return write_attribute_from_custom_data(
- pointcloud->pdata, pointcloud->totpoint, attribute_name, ATTR_DOMAIN_POINT, [&]() {
- BKE_pointcloud_update_customdata_pointers(pointcloud);
- });
-}
-
-bool PointCloudComponent::attribute_try_delete(const StringRef attribute_name)
-{
- if (this->attribute_is_builtin(attribute_name)) {
- return false;
- }
- PointCloud *pointcloud = this->get_for_write();
- if (pointcloud == nullptr) {
- return false;
- }
- delete_named_custom_data_layer(pointcloud->pdata, attribute_name, pointcloud->totpoint);
- return true;
-}
-
-static bool custom_data_has_layer_with_name(const CustomData &custom_data, const StringRef name)
-{
- for (const CustomDataLayer &layer : blender::Span(custom_data.layers, custom_data.totlayer)) {
- if (layer.name == name) {
- return true;
- }
- }
- return false;
-}
-
-bool PointCloudComponent::attribute_try_create(const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type)
-{
- if (this->attribute_is_builtin(attribute_name)) {
- return false;
- }
- if (!this->attribute_domain_with_type_supported(domain, data_type)) {
- return false;
- }
- PointCloud *pointcloud = this->get_for_write();
- if (pointcloud == nullptr) {
- return false;
- }
- if (custom_data_has_layer_with_name(pointcloud->pdata, attribute_name)) {
- return false;
- }
-
- char attribute_name_c[MAX_NAME];
- attribute_name.copy(attribute_name_c);
- CustomData_add_layer_named(
- &pointcloud->pdata, data_type, CD_DEFAULT, nullptr, pointcloud_->totpoint, attribute_name_c);
- return true;
-}
-
-Set<std::string> PointCloudComponent::attribute_names() const
-{
- if (pointcloud_ == nullptr) {
- return {};
- }
-
- Set<std::string> names;
- get_custom_data_layer_attribute_names(pointcloud_->pdata, *this, ATTR_DOMAIN_POINT, names);
- return names;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Component
* \{ */
-bool MeshComponent::attribute_domain_supported(const AttributeDomain domain) const
+const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const
{
- return ELEM(
- domain, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_POLYGON);
-}
-
-bool MeshComponent::attribute_domain_with_type_supported(const AttributeDomain domain,
- const CustomDataType data_type) const
-{
- if (!this->attribute_domain_supported(domain)) {
- return false;
- }
- return ELEM(data_type,
- CD_PROP_BOOL,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT2,
- CD_PROP_FLOAT3,
- CD_PROP_INT32,
- CD_PROP_COLOR);
+ static blender::bke::ComponentAttributeProviders providers =
+ blender::bke::create_attribute_providers_for_mesh();
+ return &providers;
}
int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
@@ -1121,228 +1765,4 @@ int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
return 0;
}
-bool MeshComponent::attribute_is_builtin(const StringRef attribute_name) const
-{
- return attribute_name == "position";
-}
-
-ReadAttributePtr MeshComponent::attribute_try_get_for_read(const StringRef attribute_name) const
-{
- if (mesh_ == nullptr) {
- return {};
- }
-
- if (attribute_name == "position") {
- auto get_vertex_position = [](const MVert &vert) { return float3(vert.co); };
- return std::make_unique<
- blender::bke::DerivedArrayReadAttribute<MVert, float3, decltype(get_vertex_position)>>(
- ATTR_DOMAIN_POINT, blender::Span(mesh_->mvert, mesh_->totvert), get_vertex_position);
- }
-
- ReadAttributePtr corner_attribute = read_attribute_from_custom_data(
- mesh_->ldata, mesh_->totloop, attribute_name, ATTR_DOMAIN_CORNER);
- if (corner_attribute) {
- return corner_attribute;
- }
-
- const int vertex_group_index = vertex_group_names_.lookup_default(attribute_name, -1);
- if (vertex_group_index >= 0) {
- return std::make_unique<blender::bke::VertexWeightReadAttribute>(
- mesh_->dvert, mesh_->totvert, vertex_group_index);
- }
-
- ReadAttributePtr vertex_attribute = read_attribute_from_custom_data(
- mesh_->vdata, mesh_->totvert, attribute_name, ATTR_DOMAIN_POINT);
- if (vertex_attribute) {
- return vertex_attribute;
- }
-
- ReadAttributePtr edge_attribute = read_attribute_from_custom_data(
- mesh_->edata, mesh_->totedge, attribute_name, ATTR_DOMAIN_EDGE);
- if (edge_attribute) {
- return edge_attribute;
- }
-
- ReadAttributePtr polygon_attribute = read_attribute_from_custom_data(
- mesh_->pdata, mesh_->totpoly, attribute_name, ATTR_DOMAIN_POLYGON);
- if (polygon_attribute) {
- return polygon_attribute;
- }
-
- return {};
-}
-
-WriteAttributePtr MeshComponent::attribute_try_get_for_write(const StringRef attribute_name)
-{
- Mesh *mesh = this->get_for_write();
- if (mesh == nullptr) {
- return {};
- }
-
- const std::function<void()> update_mesh_pointers = [&]() {
- BKE_mesh_update_customdata_pointers(mesh, false);
- };
-
- if (attribute_name == "position") {
- CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
- update_mesh_pointers();
-
- auto get_vertex_position = [](const MVert &vert) { return float3(vert.co); };
- auto set_vertex_position = [](MVert &vert, const float3 &co) { copy_v3_v3(vert.co, co); };
- return std::make_unique<
- blender::bke::DerivedArrayWriteAttribute<MVert,
- float3,
- decltype(get_vertex_position),
- decltype(set_vertex_position)>>(
- ATTR_DOMAIN_POINT,
- blender::MutableSpan(mesh_->mvert, mesh_->totvert),
- get_vertex_position,
- set_vertex_position);
- }
-
- WriteAttributePtr corner_attribute = write_attribute_from_custom_data(
- mesh_->ldata, mesh_->totloop, attribute_name, ATTR_DOMAIN_CORNER, update_mesh_pointers);
- if (corner_attribute) {
- return corner_attribute;
- }
-
- const int vertex_group_index = vertex_group_names_.lookup_default_as(attribute_name, -1);
- if (vertex_group_index >= 0) {
- 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);
- }
-
- WriteAttributePtr vertex_attribute = write_attribute_from_custom_data(
- mesh_->vdata, mesh_->totvert, attribute_name, ATTR_DOMAIN_POINT, update_mesh_pointers);
- if (vertex_attribute) {
- return vertex_attribute;
- }
-
- WriteAttributePtr edge_attribute = write_attribute_from_custom_data(
- mesh_->edata, mesh_->totedge, attribute_name, ATTR_DOMAIN_EDGE, update_mesh_pointers);
- if (edge_attribute) {
- return edge_attribute;
- }
-
- WriteAttributePtr polygon_attribute = write_attribute_from_custom_data(
- mesh_->pdata, mesh_->totpoly, attribute_name, ATTR_DOMAIN_POLYGON, update_mesh_pointers);
- if (polygon_attribute) {
- return polygon_attribute;
- }
-
- return {};
-}
-
-bool MeshComponent::attribute_try_delete(const StringRef attribute_name)
-{
- if (this->attribute_is_builtin(attribute_name)) {
- return false;
- }
- Mesh *mesh = this->get_for_write();
- if (mesh == nullptr) {
- return false;
- }
-
- delete_named_custom_data_layer(mesh_->ldata, attribute_name, mesh_->totloop);
- delete_named_custom_data_layer(mesh_->vdata, attribute_name, mesh_->totvert);
- delete_named_custom_data_layer(mesh_->edata, attribute_name, mesh_->totedge);
- delete_named_custom_data_layer(mesh_->pdata, attribute_name, mesh_->totpoly);
-
- const int vertex_group_index = vertex_group_names_.lookup_default_as(attribute_name, -1);
- if (vertex_group_index != -1) {
- for (MDeformVert &dvert : blender::MutableSpan(mesh_->dvert, mesh_->totvert)) {
- MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index);
- BKE_defvert_remove_group(&dvert, weight);
- }
- vertex_group_names_.remove_as(attribute_name);
- }
-
- return true;
-}
-
-bool MeshComponent::attribute_try_create(const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type)
-{
- if (this->attribute_is_builtin(attribute_name)) {
- return false;
- }
- if (!this->attribute_domain_with_type_supported(domain, data_type)) {
- return false;
- }
- Mesh *mesh = this->get_for_write();
- if (mesh == nullptr) {
- return false;
- }
-
- char attribute_name_c[MAX_NAME];
- attribute_name.copy(attribute_name_c);
-
- switch (domain) {
- case ATTR_DOMAIN_CORNER: {
- if (custom_data_has_layer_with_name(mesh->ldata, attribute_name)) {
- return false;
- }
- CustomData_add_layer_named(
- &mesh->ldata, data_type, CD_DEFAULT, nullptr, mesh->totloop, attribute_name_c);
- return true;
- }
- case ATTR_DOMAIN_POINT: {
- if (custom_data_has_layer_with_name(mesh->vdata, attribute_name)) {
- return false;
- }
- if (vertex_group_names_.contains_as(attribute_name)) {
- return false;
- }
- CustomData_add_layer_named(
- &mesh->vdata, data_type, CD_DEFAULT, nullptr, mesh->totvert, attribute_name_c);
- return true;
- }
- case ATTR_DOMAIN_EDGE: {
- if (custom_data_has_layer_with_name(mesh->edata, attribute_name)) {
- return false;
- }
- CustomData_add_layer_named(
- &mesh->edata, data_type, CD_DEFAULT, nullptr, mesh->totedge, attribute_name_c);
- return true;
- }
- case ATTR_DOMAIN_POLYGON: {
- if (custom_data_has_layer_with_name(mesh->pdata, attribute_name)) {
- return false;
- }
- CustomData_add_layer_named(
- &mesh->pdata, data_type, CD_DEFAULT, nullptr, mesh->totpoly, attribute_name_c);
- return true;
- }
- default:
- return false;
- }
-}
-
-Set<std::string> MeshComponent::attribute_names() const
-{
- if (mesh_ == nullptr) {
- return {};
- }
-
- Set<std::string> names;
- names.add("position");
- for (StringRef name : vertex_group_names_.keys()) {
- names.add(name);
- }
- get_custom_data_layer_attribute_names(mesh_->ldata, *this, ATTR_DOMAIN_CORNER, names);
- get_custom_data_layer_attribute_names(mesh_->vdata, *this, ATTR_DOMAIN_POINT, names);
- get_custom_data_layer_attribute_names(mesh_->edata, *this, ATTR_DOMAIN_EDGE, names);
- get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_POLYGON, names);
- return names;
-}
-
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index dae0b757df0..2eaef8fc121 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -377,6 +377,17 @@ void MeshComponent::copy_vertex_group_names_from_object(const Object &object)
}
}
+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