diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index e685272de6b..b6934792a2e 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -206,6 +206,11 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { bool layer_exists(const CustomData &custom_data) const; }; +using AttributeAddHandler = void (*)(void *owner, + AttributeIDRef const &attribute_id, + eCustomDataType type); +using AttributeRemoveHandler = void (*)(void *owner, AttributeIDRef const &attribute_id); + /** * 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). @@ -229,10 +234,17 @@ class ComponentAttributeProviders { */ VectorSet supported_domains_; + AttributeAddHandler add_handler_; + AttributeRemoveHandler remove_handler_; + public: ComponentAttributeProviders(Span builtin_attribute_providers, - Span dynamic_attribute_providers) - : dynamic_attribute_providers_(dynamic_attribute_providers) + Span dynamic_attribute_providers, + AttributeAddHandler add_handler, + AttributeRemoveHandler remove_handler) + : dynamic_attribute_providers_(dynamic_attribute_providers), + add_handler_(add_handler), + remove_handler_(remove_handler) { for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) { /* Use #add_new to make sure that no two builtin attributes have the same name. */ @@ -258,6 +270,22 @@ class ComponentAttributeProviders { { return supported_domains_; } + + void call_add_handler(void *owner, + AttributeIDRef const &attribute_id, + eCustomDataType type) const + { + if (add_handler_) { + add_handler_(owner, attribute_id, type); + } + } + + void call_remove_handler(void *owner, AttributeIDRef const &attribute_id) const + { + if (remove_handler_) { + remove_handler_(owner, attribute_id); + } + } }; namespace attribute_accessor_functions { @@ -401,6 +429,7 @@ inline bool remove(void *owner, const AttributeIDRef &attribute_id) return provider->try_delete(owner); } } + providers.call_remove_handler(owner, attribute_id); for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) { if (provider->try_delete(owner, attribute_id)) { return true; @@ -435,6 +464,7 @@ inline bool add(void *owner, } for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) { if (provider->try_create(owner, attribute_id, domain, data_type, initializer)) { + providers.call_add_handler(owner, attribute_id, data_type); return true; } } diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index e20c130e9de..9ef87a6ea0f 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -560,7 +560,9 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() &curve_type, &resolution, &cyclic}, - {&curve_custom_data, &point_custom_data}); + {&curve_custom_data, &point_custom_data}, + nullptr, + nullptr); } /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 3af5d4696d9..f0129aeff87 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -207,7 +207,7 @@ static ComponentAttributeProviders create_attribute_providers_for_instances() static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE, instance_custom_data_access); - return ComponentAttributeProviders({&position, &id}, {&instance_custom_data}); + return ComponentAttributeProviders({&position, &id}, {&instance_custom_data}, nullptr, nullptr); } static AttributeAccessorFunctions get_instances_accessor_functions() diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 3a2cbe755cf..f0bdcbe8c36 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -1082,6 +1082,38 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { */ static ComponentAttributeProviders create_attribute_providers_for_mesh() { + static AttributeAddHandler mesh_add_handler = + [](void *owner, AttributeIDRef const &attribute_id, eCustomDataType type) -> void { + Mesh *mesh = static_cast(owner); + if ((type == CD_PROP_COLOR || type == CD_PROP_BYTE_COLOR) && !attribute_id.is_anonymous()) { + if (mesh->active_color_attribute == nullptr) { + mesh->active_color_attribute = static_cast( + BLI_strdupn(attribute_id.name().data(), attribute_id.name().size())); + } + if (mesh->default_color_attribute == nullptr) { + mesh->default_color_attribute = static_cast( + BLI_strdupn(attribute_id.name().data(), attribute_id.name().size())); + } + } + }; + + static AttributeRemoveHandler mesh_remove_handler = + [](void *owner, AttributeIDRef const &attribute_id) -> void { + Mesh *mesh = static_cast(owner); + if (mesh->active_color_attribute && !strncmp(mesh->active_color_attribute, + attribute_id.name().data(), + attribute_id.name().size())) + { + MEM_SAFE_FREE(mesh->active_color_attribute); + } + if (mesh->default_color_attribute && !strncmp(mesh->default_color_attribute, + attribute_id.name().data(), + attribute_id.name().size())) + { + MEM_SAFE_FREE(mesh->default_color_attribute); + } + }; + #define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ [](void *owner) -> CustomData * { \ Mesh *mesh = static_cast(owner); \ @@ -1239,7 +1271,9 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() &vertex_groups, &point_custom_data, &edge_custom_data, - &face_custom_data}); + &face_custom_data}, + mesh_add_handler, + mesh_remove_handler); } static AttributeAccessorFunctions get_mesh_accessor_functions() diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index f9261fdcfce..a54f93bae16 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -160,7 +160,8 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() point_access, nullptr); static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - return ComponentAttributeProviders({&position, &radius, &id}, {&point_custom_data}); + return ComponentAttributeProviders( + {&position, &radius, &id}, {&point_custom_data}, nullptr, nullptr); } static AttributeAccessorFunctions get_pointcloud_accessor_functions() diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc index 9dc9ce7f565..9c2d0756c3c 100644 --- a/source/blender/blenkernel/intern/geometry_fields.cc +++ b/source/blender/blenkernel/intern/geometry_fields.cc @@ -538,8 +538,9 @@ bool try_capture_field_on_geometry(GeometryComponent &component, return true; } } - - attributes.remove(attribute_id); + if (!attribute_id.is_anonymous()) { + attributes.remove(attribute_id); + } if (attributes.add(attribute_id, domain, data_type, bke::AttributeInitMoveArray(buffer))) { return true; }