Fix: initialize built-in attributes with proper default value
Previously, it was fairly easy to create built-in attributes which have invalid values, because attributes were generally zero-initialized. This was especially problematic for attributes that had certain invariants that Blender relies on and that should never be zero. For example, the curve resolution should always be at least 1. To reproduce the issue, add the `resolution` attribute from the attributes panel to curves. They had a value of 0 by default. I found this while investigating #124416. Pull Request: https://projects.blender.org/blender/blender/pulls/124534
This commit is contained in:
@@ -291,7 +291,8 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr
|
||||
CustomData &custom_data,
|
||||
const eCustomDataType data_type,
|
||||
const int domain_num,
|
||||
const AttributeInit &initializer)
|
||||
const AttributeInit &initializer,
|
||||
const GPointer custom_default_value_ptr)
|
||||
{
|
||||
const int old_layer_num = custom_data.totlayer;
|
||||
switch (initializer.type) {
|
||||
@@ -301,8 +302,16 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr
|
||||
break;
|
||||
}
|
||||
case AttributeInit::Type::DefaultValue: {
|
||||
add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_SET_DEFAULT, domain_num, attribute_id);
|
||||
if (const void *default_value = custom_default_value_ptr.get()) {
|
||||
const CPPType &type = *custom_default_value_ptr.type();
|
||||
void *data = add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_CONSTRUCT, domain_num, attribute_id);
|
||||
type.fill_assign_n(default_value, data, domain_num);
|
||||
}
|
||||
else {
|
||||
add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_SET_DEFAULT, domain_num, attribute_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AttributeInit::Type::VArray: {
|
||||
@@ -436,7 +445,7 @@ bool BuiltinCustomDataLayerProvider::try_create(void *owner,
|
||||
return false;
|
||||
}
|
||||
if (add_custom_data_layer_from_attribute_init(
|
||||
name_, *custom_data, data_type_, element_num, initializer))
|
||||
name_, *custom_data, data_type_, element_num, initializer, default_value_))
|
||||
{
|
||||
if (initializer.type != AttributeInit::Type::Construct) {
|
||||
/* Avoid calling update function when values are not initialized. In that case
|
||||
@@ -548,7 +557,7 @@ bool CustomDataAttributeProvider::try_create(void *owner,
|
||||
}
|
||||
const int element_num = custom_data_access_.get_element_num(owner);
|
||||
add_custom_data_layer_from_attribute_init(
|
||||
attribute_id, *custom_data, data_type, element_num, initializer);
|
||||
attribute_id, *custom_data, data_type, element_num, initializer, {});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_generic_pointer.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
@@ -46,18 +47,21 @@ class BuiltinAttributeProvider {
|
||||
const eCustomDataType data_type_;
|
||||
const DeletableEnum deletable_;
|
||||
const AttributeValidator validator_;
|
||||
const GPointer default_value_;
|
||||
|
||||
public:
|
||||
BuiltinAttributeProvider(std::string name,
|
||||
const AttrDomain domain,
|
||||
const eCustomDataType data_type,
|
||||
const DeletableEnum deletable,
|
||||
AttributeValidator validator = {})
|
||||
AttributeValidator validator = {},
|
||||
const GPointer default_value = {})
|
||||
: name_(std::move(name)),
|
||||
domain_(domain),
|
||||
data_type_(data_type),
|
||||
deletable_(deletable),
|
||||
validator_(validator)
|
||||
validator_(validator),
|
||||
default_value_(default_value)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -177,9 +181,10 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
|
||||
const DeletableEnum deletable,
|
||||
const CustomDataAccessInfo custom_data_access,
|
||||
const UpdateOnChange update_on_change,
|
||||
const AttributeValidator validator = {})
|
||||
const AttributeValidator validator = {},
|
||||
const GPointer default_value = {})
|
||||
: BuiltinAttributeProvider(
|
||||
std::move(attribute_name), domain, data_type, deletable, validator),
|
||||
std::move(attribute_name), domain, data_type, deletable, validator, default_value),
|
||||
custom_data_access_(custom_data_access),
|
||||
update_on_change_(update_on_change)
|
||||
{
|
||||
|
||||
@@ -548,13 +548,15 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
||||
"NURBS Order Validate",
|
||||
[](int8_t value) { return std::max<int8_t>(value, 1); },
|
||||
mf::build::exec_presets::AllSpanOrSingle());
|
||||
static int nurbs_order_default = 4;
|
||||
static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order",
|
||||
AttrDomain::Curve,
|
||||
CD_PROP_INT8,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
tag_component_topology_changed,
|
||||
AttributeValidator{&nurbs_order_clamp});
|
||||
AttributeValidator{&nurbs_order_clamp},
|
||||
&nurbs_order_default);
|
||||
|
||||
static const auto normal_mode_clamp = mf::build::SI1_SO<int8_t, int8_t>(
|
||||
"Normal Mode Validate",
|
||||
@@ -609,13 +611,15 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
|
||||
"Resolution Validate",
|
||||
[](int value) { return std::max<int>(value, 1); },
|
||||
mf::build::exec_presets::AllSpanOrSingle());
|
||||
static int resolution_default = 12;
|
||||
static BuiltinCustomDataLayerProvider resolution("resolution",
|
||||
AttrDomain::Curve,
|
||||
CD_PROP_INT32,
|
||||
BuiltinAttributeProvider::Deletable,
|
||||
curve_access,
|
||||
tag_component_topology_changed,
|
||||
AttributeValidator{&resolution_clamp});
|
||||
AttributeValidator{&resolution_clamp},
|
||||
&resolution_default);
|
||||
|
||||
static BuiltinCustomDataLayerProvider cyclic("cyclic",
|
||||
AttrDomain::Curve,
|
||||
|
||||
Reference in New Issue
Block a user