diff options
Diffstat (limited to 'source/blender/blenkernel/intern/attribute_access.cc')
-rw-r--r-- | source/blender/blenkernel/intern/attribute_access.cc | 664 |
1 files changed, 394 insertions, 270 deletions
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index c2837b522c4..cc43a3e26a8 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -23,21 +23,20 @@ #include "BKE_geometry_set.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" +#include "BKE_type_conversions.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_pointcloud_types.h" #include "BLI_color.hh" -#include "BLI_float2.hh" +#include "BLI_math_vec_types.hh" #include "BLI_span.hh" #include "BLT_translation.h" #include "CLG_log.h" -#include "NOD_type_conversions.hh" - #include "attribute_access_intern.hh" static CLG_LogRef LOG = {"bke.attribute_access"}; @@ -50,8 +49,7 @@ using blender::bke::AttributeIDRef; using blender::bke::OutputAttribute; using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_SingleValue; +using blender::fn::GVArrayImpl_For_GSpan; namespace blender::bke { @@ -165,16 +163,18 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_ static int attribute_domain_priority(const AttributeDomain domain) { switch (domain) { - case ATTR_DOMAIN_CURVE: + case ATTR_DOMAIN_INSTANCE: return 0; - case ATTR_DOMAIN_FACE: + case ATTR_DOMAIN_CURVE: return 1; - case ATTR_DOMAIN_EDGE: + case ATTR_DOMAIN_FACE: return 2; - case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_EDGE: return 3; - case ATTR_DOMAIN_CORNER: + case ATTR_DOMAIN_POINT: return 4; + case ATTR_DOMAIN_CORNER: + return 5; default: /* Domain not supported in nodes yet. */ BLI_assert_unreachable(); @@ -182,10 +182,6 @@ static int attribute_domain_priority(const AttributeDomain domain) } } -/** - * Domains with a higher "information density" have a higher priority, in order - * to choose a domain that will not lose data through domain conversion. - */ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) { int highest_priority = INT_MIN; @@ -202,6 +198,17 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) return highest_priority_domain; } +fn::GMutableSpan OutputAttribute::as_span() +{ + if (!optional_span_varray_) { + const bool materialize_old_values = !ignore_old_values_; + optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(varray_, + materialize_old_values); + } + fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_; + return span_varray; +} + void OutputAttribute::save() { save_has_been_called_ = true; @@ -222,23 +229,140 @@ OutputAttribute::~OutputAttribute() } } -GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read( - const GeometryComponent &component) const +static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer &layer) +{ + if (layer.anonymous_id != nullptr) { + return layer.anonymous_id; + } + return layer.name; +} + +static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data, + const CustomDataType data_type, + const int domain_size, + const AttributeInit &initializer) +{ + switch (initializer.type) { + case AttributeInit::Type::Default: { + void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size); + return data != nullptr; + } + case AttributeInit::Type::VArray: { + void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size); + if (data == nullptr) { + return false; + } + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); + return true; + } + case AttributeInit::Type::MoveArray: { + void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *data = CustomData_add_layer( + &custom_data, data_type, CD_ASSIGN, source_data, domain_size); + if (data == nullptr) { + MEM_freeN(source_data); + return false; + } + return true; + } + } + + BLI_assert_unreachable(); + return false; +} + +static void *add_generic_custom_data_layer(CustomData &custom_data, + const CustomDataType data_type, + const eCDAllocType alloctype, + void *layer_data, + const int domain_size, + const AttributeIDRef &attribute_id) +{ + if (attribute_id.is_named()) { + char attribute_name_c[MAX_NAME]; + attribute_id.name().copy(attribute_name_c); + return CustomData_add_layer_named( + &custom_data, data_type, alloctype, layer_data, domain_size, attribute_name_c); + } + const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); + return CustomData_add_layer_anonymous( + &custom_data, data_type, alloctype, layer_data, domain_size, &anonymous_id); +} + +static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, + CustomData &custom_data, + const CustomDataType data_type, + const int domain_size, + const AttributeInit &initializer) +{ + switch (initializer.type) { + case AttributeInit::Type::Default: { + void *data = add_generic_custom_data_layer( + custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id); + return data != nullptr; + } + case AttributeInit::Type::VArray: { + void *data = add_generic_custom_data_layer( + custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id); + if (data == nullptr) { + return false; + } + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); + return true; + } + case AttributeInit::Type::MoveArray: { + void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *data = add_generic_custom_data_layer( + custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_id); + if (data == nullptr) { + MEM_freeN(source_data); + return false; + } + return true; + } + } + + BLI_assert_unreachable(); + return false; +} + +static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, + const AttributeIDRef &attribute_id) +{ + if (!attribute_id) { + return false; + } + if (attribute_id.is_anonymous()) { + return layer.anonymous_id == &attribute_id.anonymous_id(); + } + return layer.name == attribute_id.name(); +} + +GVArray 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 {}; } - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_get_layer(custom_data, stored_type_); + const void *data; + if (stored_as_named_attribute_) { + data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()); + } + else { + data = CustomData_get_layer(custom_data, stored_type_); + } if (data == nullptr) { return {}; } + + const int domain_size = component.attribute_domain_size(domain_); return as_read_attribute_(data, domain_size); } -GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write( +WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write( GeometryComponent &component) const { if (writable_ != Writable) { @@ -249,19 +373,42 @@ GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write( return {}; } const int domain_size = component.attribute_domain_size(domain_); - void *data = CustomData_get_layer(custom_data, stored_type_); + + void *data; + if (stored_as_named_attribute_) { + data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()); + } + else { + 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); + + void *new_data; + if (stored_as_named_attribute_) { + new_data = CustomData_duplicate_referenced_layer_named( + custom_data, stored_type_, name_.c_str(), domain_size); + } + else { + new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); + } + if (data != new_data) { - custom_data_access_.update_custom_data_pointers(component); + if (custom_data_access_.update_custom_data_pointers) { + custom_data_access_.update_custom_data_pointers(component); + } data = new_data; } + + std::function<void()> tag_modified_fn; if (update_on_write_ != nullptr) { - update_on_write_(component); + tag_modified_fn = [component = &component, update = update_on_write_]() { + update(*component); + }; } - return as_write_attribute_(data, domain_size); + + return {as_write_attribute_(data, domain_size), domain_, std::move(tag_modified_fn)}; } bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const @@ -275,48 +422,27 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co } const int domain_size = component.attribute_domain_size(domain_); - const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); + int layer_index; + if (stored_as_named_attribute_) { + for (const int i : IndexRange(custom_data->totlayer)) { + if (custom_data_layer_matches_attribute_id(custom_data->layers[i], name_)) { + layer_index = i; + break; + } + } + } + else { + 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; -} - -static bool add_custom_data_layer_from_attribute_init(CustomData &custom_data, - const CustomDataType data_type, - const int domain_size, - const AttributeInit &initializer) -{ - switch (initializer.type) { - case AttributeInit::Type::Default: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size); - return data != nullptr; - } - case AttributeInit::Type::VArray: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_size); - if (data == nullptr) { - return false; - } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); - return true; - } - case AttributeInit::Type::MoveArray: { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; - void *data = CustomData_add_layer( - &custom_data, data_type, CD_ASSIGN, source_data, domain_size); - if (data == nullptr) { - MEM_freeN(source_data); - return false; - } - return true; + if (custom_data_access_.update_custom_data_pointers) { + custom_data_access_.update_custom_data_pointers(component); } } - - BLI_assert_unreachable(); - return false; + return delete_success; } bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, @@ -329,16 +455,29 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &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 bool success = add_custom_data_layer_from_attribute_init( - *custom_data, stored_type_, domain_size, initializer); + bool success; + if (stored_as_named_attribute_) { + if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) { + /* Exists already. */ + return false; + } + success = add_custom_data_layer_from_attribute_init( + name_, *custom_data, stored_type_, domain_size, initializer); + } + else { + if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { + /* Exists already. */ + return false; + } + success = add_builtin_type_custom_data_layer_from_init( + *custom_data, stored_type_, domain_size, initializer); + } if (success) { - custom_data_access_.update_custom_data_pointers(component); + if (custom_data_access_.update_custom_data_pointers) { + custom_data_access_.update_custom_data_pointers(component); + } } return success; } @@ -349,20 +488,10 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) if (custom_data == nullptr) { return false; } - const void *data = CustomData_get_layer(custom_data, stored_type_); - return data != nullptr; -} - -static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, - const AttributeIDRef &attribute_id) -{ - if (!attribute_id) { - return false; + if (stored_as_named_attribute_) { + return CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()) != nullptr; } - if (attribute_id.is_anonymous()) { - return layer.anonymous_id == &attribute_id.anonymous_id(); - } - return layer.name == attribute_id.name(); + return CustomData_get_layer(custom_data, stored_type_) != nullptr; } ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( @@ -377,23 +506,12 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) { 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<ColorGeometry4f>(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_read_attribute<bool>(layer, domain_size); - default: - break; + const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type); + if (type == nullptr) { + continue; } + GSpan data{*type, layer.data, domain_size}; + return {GVArray::ForSpan(data), domain_}; } return {}; } @@ -418,23 +536,12 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write( CustomData_duplicate_referenced_layer_anonymous( custom_data, layer.type, &attribute_id.anonymous_id(), 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<ColorGeometry4f>(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_write_attribute<bool>(layer, domain_size); - default: - break; + const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type); + if (type == nullptr) { + continue; } + GMutableSpan data{*type, layer.data, domain_size}; + return {GVMutableArray::ForSpan(data), domain_}; } return {}; } @@ -458,62 +565,6 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, return false; } -static void *add_generic_custom_data_layer(CustomData &custom_data, - const CustomDataType data_type, - const eCDAllocType alloctype, - void *layer_data, - const int domain_size, - const AttributeIDRef &attribute_id) -{ - if (attribute_id.is_named()) { - char attribute_name_c[MAX_NAME]; - attribute_id.name().copy(attribute_name_c); - return CustomData_add_layer_named( - &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); - } - const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); - return CustomData_add_layer_anonymous( - &custom_data, data_type, alloctype, layer_data, domain_size, &anonymous_id); -} - -static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, - CustomData &custom_data, - const CustomDataType data_type, - const int domain_size, - const AttributeInit &initializer) -{ - switch (initializer.type) { - case AttributeInit::Type::Default: { - void *data = add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id); - return data != nullptr; - } - case AttributeInit::Type::VArray: { - void *data = add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id); - if (data == nullptr) { - return false; - } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); - return true; - } - case AttributeInit::Type::MoveArray: { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; - void *data = add_generic_custom_data_layer( - custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_id); - if (data == nullptr) { - MEM_freeN(source_data); - return false; - } - return true; - } - } - - BLI_assert_unreachable(); - return false; -} - bool CustomDataAttributeProvider::try_create(GeometryComponent &component, const AttributeIDRef &attribute_id, const AttributeDomain domain, @@ -552,13 +603,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com const CustomDataType data_type = (CustomDataType)layer.type; if (this->type_is_supported(data_type)) { AttributeMetaData meta_data{domain_, data_type}; - AttributeIDRef attribute_id; - if (layer.anonymous_id != nullptr) { - attribute_id = layer.anonymous_id; - } - else { - attribute_id = layer.name; - } + const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer); if (!callback(attribute_id, meta_data)) { return false; } @@ -600,7 +645,9 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write( 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); + if (custom_data_access_.update_custom_data_pointers) { + custom_data_access_.update_custom_data_pointers(component); + } } return {as_write_attribute_(layer.data, domain_size), domain_}; } @@ -622,7 +669,9 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component, if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { 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); + if (custom_data_access_.update_custom_data_pointers) { + custom_data_access_.update_custom_data_pointers(component); + } return true; } } @@ -690,7 +739,6 @@ CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id) const { - BLI_assert(size_ != 0); for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) { if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type); @@ -701,36 +749,29 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at return {}; } -/** - * Return a virtual array for a stored attribute, or a single value virtual array with the default - * value if the attribute doesn't exist. If no default value is provided, the default value for the - * type will be used. - */ -GVArrayPtr CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const void *default_value) const +GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, + const CustomDataType data_type, + const void *default_value) const { const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); std::optional<GSpan> attribute = this->get_for_read(attribute_id); if (!attribute) { const int domain_size = this->size_; - return std::make_unique<GVArray_For_SingleValue>( + return GVArray::ForSingle( *type, domain_size, (default_value == nullptr) ? type->default_value() : default_value); } if (attribute->type() == *type) { - return std::make_unique<GVArray_For_GSpan>(*attribute); + return GVArray::ForSpan(*attribute); } - const blender::nodes::DataTypeConversions &conversions = - blender::nodes::get_implicit_type_conversions(); - return conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), *type); + const blender::bke::DataTypeConversions &conversions = + blender::bke::get_implicit_type_conversions(); + return conversions.try_convert(GVArray::ForSpan(*attribute), *type); } std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id) { - /* If this assert hits, it most likely means that #reallocate was not called at some point. */ - BLI_assert(size_ != 0); for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) { if (custom_data_layer_matches_attribute_id(layer, attribute_id)) { const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type); @@ -777,18 +818,18 @@ void CustomDataAttributes::reallocate(const int size) CustomData_realloc(&data, size); } +void CustomDataAttributes::clear() +{ + CustomData_free(&data, size_); + size_ = 0; +} + bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback, const AttributeDomain domain) const { for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) { AttributeMetaData meta_data{domain, (CustomDataType)layer.type}; - AttributeIDRef attribute_id; - if (layer.anonymous_id != nullptr) { - attribute_id = layer.anonymous_id; - } - else { - attribute_id = layer.name; - } + const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer); if (!callback(attribute_id, meta_data)) { return false; } @@ -796,6 +837,26 @@ bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback call return true; } +void CustomDataAttributes::reorder(Span<AttributeIDRef> new_order) +{ + BLI_assert(new_order.size() == data.totlayer); + + Map<AttributeIDRef, int> old_order; + old_order.reserve(data.totlayer); + Array<CustomDataLayer> old_layers(Span(data.layers, data.totlayer)); + for (const int i : old_layers.index_range()) { + old_order.add_new(attribute_id_from_custom_data_layer(old_layers[i]), i); + } + + MutableSpan layers(data.layers, data.totlayer); + for (const int i : layers.index_range()) { + const int old_index = old_order.lookup(new_order[i]); + layers[i] = old_layers[old_index]; + } + + CustomData_update_typemap(&data); +} + } // namespace blender::bke /* -------------------------------------------------------------------- */ @@ -863,8 +924,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( return {}; } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, +blender::fn::GVArray GeometryComponent::attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { @@ -886,7 +947,7 @@ blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_writ const BuiltinAttributeProvider *builtin_provider = providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr); if (builtin_provider != nullptr) { - return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()}; + return builtin_provider->try_get_for_write(*this); } } for (const DynamicAttributesProvider *dynamic_provider : @@ -986,10 +1047,6 @@ Set<AttributeIDRef> GeometryComponent::attribute_ids() const return attributes; } -/** - * \return False if the callback explicitly returned false at any point, otherwise true, - * meaning the callback made it all the way through. - */ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const { using namespace blender::bke; @@ -1051,15 +1108,15 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data( return result; } -static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type( - std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type) +static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray, + const blender::fn::CPPType &to_type) { - const blender::nodes::DataTypeConversions &conversions = - blender::nodes::get_implicit_type_conversions(); + const blender::bke::DataTypeConversions &conversions = + blender::bke::get_implicit_type_conversions(); return conversions.try_convert(std::move(varray), to_type); } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain, const CustomDataType data_type) const @@ -1069,8 +1126,8 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return {}; } - std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray); - if (domain != ATTR_DOMAIN_AUTO && attribute.domain != domain) { + blender::fn::GVArray varray = std::move(attribute.varray); + if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) { varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain); if (!varray) { return {}; @@ -1079,7 +1136,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); - if (varray->type() != *cpp_type) { + if (varray.type() != *cpp_type) { varray = try_adapt_data_type(std::move(varray), *cpp_type); if (!varray) { return {}; @@ -1089,7 +1146,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return varray; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain) const { if (!this->attribute_domain_supported(domain)) { @@ -1117,22 +1174,20 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( } const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(type != nullptr); - if (attribute.varray->type() == *type) { + if (attribute.varray.type() == *type) { return attribute; } - const blender::nodes::DataTypeConversions &conversions = - blender::nodes::get_implicit_type_conversions(); + const blender::bke::DataTypeConversions &conversions = + blender::bke::get_implicit_type_conversions(); return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain}; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read( - const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) const +blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value) const { - std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read( - attribute_id, domain, data_type); + blender::fn::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type); if (varray) { return varray; } @@ -1141,11 +1196,10 @@ std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read default_value = type->default_value(); } const int domain_size = this->attribute_domain_size(domain); - return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value); + return blender::fn::GVArray::ForSingle(*type, domain_size, default_value); } -class GVMutableAttribute_For_OutputAttribute - : public blender::fn::GVMutableArray_For_GMutableSpan { +class GVMutableAttribute_For_OutputAttribute : public blender::fn::GVArrayImpl_For_GSpan { public: GeometryComponent *component; std::string attribute_name; @@ -1154,7 +1208,7 @@ class GVMutableAttribute_For_OutputAttribute GVMutableAttribute_For_OutputAttribute(GMutableSpan data, GeometryComponent &component, const AttributeIDRef &attribute_id) - : blender::fn::GVMutableArray_For_GMutableSpan(data), component(&component) + : blender::fn::GVArrayImpl_For_GSpan(data), component(&component) { if (attribute_id.is_named()) { this->attribute_name = attribute_id.name(); @@ -1180,7 +1234,8 @@ static void save_output_attribute(OutputAttribute &output_attribute) using namespace blender::bke; GVMutableAttribute_For_OutputAttribute &varray = - dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray()); + dynamic_cast<GVMutableAttribute_For_OutputAttribute &>( + *output_attribute.varray().get_implementation()); GeometryComponent &component = *varray.component; AttributeIDRef attribute_id; @@ -1208,10 +1263,24 @@ static void save_output_attribute(OutputAttribute &output_attribute) BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer); for (const int i : IndexRange(varray.size())) { varray.get(i, buffer); - write_attribute.varray->set_by_relocate(i, buffer); + write_attribute.varray.set_by_relocate(i, buffer); + } + if (write_attribute.tag_modified_fn) { + write_attribute.tag_modified_fn(); } } +static std::function<void(OutputAttribute &)> get_simple_output_attribute_save_method( + const blender::bke::WriteAttributeLookup &attribute) +{ + if (!attribute.tag_modified_fn) { + return {}; + } + return [tag_modified_fn = attribute.tag_modified_fn](OutputAttribute &UNUSED(attribute)) { + tag_modified_fn(); + }; +} + static OutputAttribute create_output_attribute(GeometryComponent &component, const AttributeIDRef &attribute_id, const AttributeDomain domain, @@ -1229,7 +1298,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); - const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions(); + const DataTypeConversions &conversions = get_implicit_type_conversions(); if (component.attribute_is_builtin(attribute_id)) { const StringRef attribute_name = attribute_id.name(); @@ -1237,9 +1306,9 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, if (!attribute) { if (default_value) { const int64_t domain_size = component.attribute_domain_size(domain); - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; - component.attribute_try_create_builtin(attribute_name, - AttributeInitVArray(&default_varray)); + component.attribute_try_create_builtin( + attribute_name, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); @@ -1254,14 +1323,20 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, /* Builtin attribute is on different domain. */ return {}; } - GVMutableArrayPtr varray = std::move(attribute.varray); - if (varray->type() == *cpp_type) { + GVMutableArray varray = std::move(attribute.varray); + if (varray.type() == *cpp_type) { /* Builtin attribute matches exactly. */ - return OutputAttribute(std::move(varray), domain, {}, ignore_old_values); + return OutputAttribute(std::move(varray), + domain, + get_simple_output_attribute_save_method(attribute), + ignore_old_values); } /* Builtin attribute is on the same domain but has a different data type. */ varray = conversions.try_convert(std::move(varray), *cpp_type); - return OutputAttribute(std::move(varray), domain, {}, ignore_old_values); + return OutputAttribute(std::move(varray), + domain, + get_simple_output_attribute_save_method(attribute), + ignore_old_values); } const int domain_size = component.attribute_domain_size(domain); @@ -1269,9 +1344,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id); if (!attribute) { if (default_value) { - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; component.attribute_try_create( - attribute_id, domain, data_type, AttributeInitVArray(&default_varray)); + attribute_id, + domain, + data_type, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault()); @@ -1283,9 +1360,13 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, return {}; } } - if (attribute.domain == domain && attribute.varray->type() == *cpp_type) { + if (attribute.domain == domain && attribute.varray.type() == *cpp_type) { /* Existing generic attribute matches exactly. */ - return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values); + + return OutputAttribute(std::move(attribute.varray), + domain, + get_simple_output_attribute_save_method(attribute), + ignore_old_values); } /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing @@ -1298,11 +1379,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, } else { /* Fill the temporary array with values from the existing attribute. */ - GVArrayPtr old_varray = component.attribute_get_for_read( + GVArray old_varray = component.attribute_get_for_read( attribute_id, domain, data_type, default_value); - old_varray->materialize_to_uninitialized(IndexRange(domain_size), data); + old_varray.materialize_to_uninitialized(IndexRange(domain_size), data); } - GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>( + GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>( GMutableSpan{*cpp_type, data, domain_size}, component, attribute_id); return OutputAttribute(std::move(varray), domain, save_output_attribute, true); @@ -1326,27 +1407,31 @@ OutputAttribute GeometryComponent::attribute_try_get_for_output_only( namespace blender::bke { -const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const +GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); - const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); - GVArrayPtr attribute = component.attribute_try_get_for_read(name_, domain, data_type); - if (attribute) { - return scope.add(std::move(attribute)); - } + return this->get_varray_for_context(component, domain, mask); } - return nullptr; + return {}; +} + +GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const +{ + const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); + return component.attribute_try_get_for_read(name_, domain, data_type); } std::string AttributeFieldInput::socket_inspection_name() const { std::stringstream ss; - ss << TIP_("Attribute: ") << name_; + ss << '"' << name_ << '"' << TIP_(" attribute from geometry"); return ss.str(); } @@ -1363,25 +1448,62 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return false; } -const GVArray *AnonymousAttributeFieldInput::get_varray_for_context( - const fn::FieldContext &context, IndexMask UNUSED(mask), ResourceScope &scope) const +static StringRef get_random_id_attribute_name(const AttributeDomain domain) { - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - const GeometryComponent &component = geometry_context->geometry_component(); - const AttributeDomain domain = geometry_context->domain(); - const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); - GVArrayPtr attribute = component.attribute_try_get_for_read( - anonymous_id_.get(), domain, data_type); - return scope.add(std::move(attribute)); + switch (domain) { + case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_INSTANCE: + return "id"; + default: + return ""; } - return nullptr; +} + +GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const +{ + + const StringRef name = get_random_id_attribute_name(domain); + GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); + if (attribute) { + BLI_assert(attribute.size() == component.attribute_domain_size(domain)); + return attribute; + } + + /* Use the index as the fallback if no random ID attribute exists. */ + return fn::IndexFieldInput::get_index_varray(mask); +} + +std::string IDAttributeFieldInput::socket_inspection_name() const +{ + return TIP_("ID / Index"); +} + +uint64_t IDAttributeFieldInput::hash() const +{ + /* All random ID attribute inputs are the same within the same evaluation context. */ + return 92386459827; +} + +bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const +{ + /* All random ID attribute inputs are the same within the same evaluation context. */ + return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr; +} + +GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const +{ + const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); + return component.attribute_try_get_for_read(anonymous_id_.get(), domain, data_type); } std::string AnonymousAttributeFieldInput::socket_inspection_name() const { std::stringstream ss; - ss << TIP_("Anonymous Attribute: ") << debug_name_; + ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_; return ss.str(); } @@ -1400,3 +1522,5 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const } } // namespace blender::bke + +/** \} */ |