diff options
author | Hans Goudey <h.goudey@me.com> | 2021-04-22 17:20:03 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-04-22 17:20:03 +0300 |
commit | d1ccc5b9694b7c737158f4d4bd83ae780b32d258 (patch) | |
tree | 18a8e6bef4dac90c72fc3337b84222b322b519bc /source/blender/blenkernel/intern/attribute_access.cc | |
parent | 9fccbe2d1385df6dfbd3291d2b8950732e028f25 (diff) |
Geometry Nodes: Add initializer for attribute creation
Previously we always had to set attribute values after creating
the attribute. This patch adds an initializer argument to
`attribute_try_create` which can fill it in a few ways, which
are explained in code comments.
This fixes T87597.
Differential Revision: https://developer.blender.org/D11045
Diffstat (limited to 'source/blender/blenkernel/intern/attribute_access.cc')
-rw-r--r-- | source/blender/blenkernel/intern/attribute_access.cc | 132 |
1 files changed, 114 insertions, 18 deletions
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 571763e3719..6c37d34dc9b 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -254,7 +254,43 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co return delete_success; } -bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const +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; + } + } + + BLI_assert_unreachable(); + return false; +} + +bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, + const AttributeInit &initializer) const { if (createable_ != Creatable) { return false; @@ -267,10 +303,10 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) co /* 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; + const bool success = add_custom_data_layer_from_attribute_init( + *custom_data, stored_type_, domain_size, initializer); if (success) { custom_data_access_.update_custom_data_pointers(component); } @@ -372,10 +408,52 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, return false; } +static bool add_named_custom_data_layer_from_attribute_init(const StringRef attribute_name, + CustomData &custom_data, + const CustomDataType data_type, + const int domain_size, + const AttributeInit &initializer) +{ + char attribute_name_c[MAX_NAME]; + attribute_name.copy(attribute_name_c); + + switch (initializer.type) { + case AttributeInit::Type::Default: { + void *data = CustomData_add_layer_named( + &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + return data != nullptr; + } + case AttributeInit::Type::VArray: { + void *data = CustomData_add_layer_named( + &custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + 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_named( + &custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_name_c); + if (data == nullptr) { + MEM_freeN(source_data); + return false; + } + return true; + } + } + + BLI_assert_unreachable(); + return false; +} + bool CustomDataAttributeProvider::try_create(GeometryComponent &component, const StringRef attribute_name, const AttributeDomain domain, - const CustomDataType data_type) const + const CustomDataType data_type, + const AttributeInit &initializer) const { if (domain_ != domain) { return false; @@ -393,10 +471,8 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component, } } 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); + add_named_custom_data_layer_from_attribute_init( + attribute_name, *custom_data, data_type, domain_size, initializer); return true; } @@ -621,7 +697,8 @@ bool GeometryComponent::attribute_try_delete(const StringRef attribute_name) bool GeometryComponent::attribute_try_create(const StringRef attribute_name, const AttributeDomain domain, - const CustomDataType data_type) + const CustomDataType data_type, + const AttributeInit &initializer) { using namespace blender::bke; if (attribute_name.is_empty()) { @@ -640,18 +717,19 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name, if (builtin_provider->data_type() != data_type) { return false; } - return builtin_provider->try_create(*this); + return builtin_provider->try_create(*this, initializer); } for (const DynamicAttributesProvider *dynamic_provider : providers->dynamic_attribute_providers()) { - if (dynamic_provider->try_create(*this, attribute_name, domain, data_type)) { + if (dynamic_provider->try_create(*this, attribute_name, domain, data_type, initializer)) { return true; } } return false; } -bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name) +bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name, + const AttributeInit &initializer) { using namespace blender::bke; if (attribute_name.is_empty()) { @@ -666,7 +744,7 @@ bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef at if (builtin_provider == nullptr) { return false; } - return builtin_provider->try_create(*this); + return builtin_provider->try_create(*this, initializer); } Set<std::string> GeometryComponent::attribute_names() const @@ -874,7 +952,8 @@ static void save_output_attribute(blender::bke::OutputAttribute &output_attribut const CPPType &cpp_type = output_attribute.cpp_type(); component.attribute_try_delete(name); - if (!component.attribute_try_create(varray.final_name, domain, data_type)) { + if (!component.attribute_try_create( + varray.final_name, domain, data_type, AttributeInitDefault())) { CLOG_WARN(&LOG, "Could not create the '%s' attribute with type '%s'.", name.c_str(), @@ -912,7 +991,15 @@ static blender::bke::OutputAttribute create_output_attribute( if (component.attribute_is_builtin(attribute_name)) { WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { - component.attribute_try_create_builtin(attribute_name); + 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)); + } + else { + component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); + } attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { /* Builtin attribute does not exist and can't be created. */ @@ -933,9 +1020,19 @@ static blender::bke::OutputAttribute create_output_attribute( return OutputAttribute(std::move(varray), domain, {}, ignore_old_values); } + const int domain_size = component.attribute_domain_size(domain); + WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { - component.attribute_try_create(attribute_name, domain, data_type); + if (default_value) { + const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; + component.attribute_try_create( + attribute_name, domain, data_type, AttributeInitVArray(&default_varray)); + } + else { + component.attribute_try_create(attribute_name, domain, data_type, AttributeInitDefault()); + } + attribute = component.attribute_try_get_for_write(attribute_name); if (!attribute) { /* Can't create the attribute. */ @@ -947,7 +1044,6 @@ static blender::bke::OutputAttribute create_output_attribute( return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values); } - const int domain_size = component.attribute_domain_size(domain); /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing * attribute after processing is done. */ void *data = MEM_mallocN_aligned( |