Refactor: Reorder attribute owner checks to handle mesh first
On its own this change is just noise and not really worth it. The point is to make a future diff for #122398 smaller and more legible. Also it's semantically more consistent with the way we usually handle early returns: the "special case" comes first, then the expected normal path continues un-indented.
This commit is contained in:
@@ -369,14 +369,15 @@ static bool attribute_name_exists(const AttributeOwner &owner, const StringRef n
|
||||
|
||||
std::string BKE_attribute_calc_unique_name(const AttributeOwner &owner, const StringRef name)
|
||||
{
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
blender::bke::AttributeStorage &storage = *owner.get_storage();
|
||||
return storage.unique_name_calc(name);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
return BLI_uniquename_cb(
|
||||
[&](const StringRef new_name) { return attribute_name_exists(owner, new_name); },
|
||||
'.',
|
||||
name.is_empty() ? DATA_("Attribute") : name);
|
||||
}
|
||||
return BLI_uniquename_cb(
|
||||
[&](const StringRef new_name) { return attribute_name_exists(owner, new_name); },
|
||||
'.',
|
||||
name.is_empty() ? DATA_("Attribute") : name);
|
||||
|
||||
blender::bke::AttributeStorage &storage = *owner.get_storage();
|
||||
return storage.unique_name_calc(name);
|
||||
}
|
||||
|
||||
CustomDataLayer *BKE_attribute_new(AttributeOwner &owner,
|
||||
@@ -789,59 +790,55 @@ std::optional<blender::StringRefNull> BKE_attributes_active_name_get(AttributeOw
|
||||
if (active_index == -1) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
if (!IndexRange(storage.count()).contains(active_index)) {
|
||||
return std::nullopt;
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
if (active_index > BKE_attributes_length(owner, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL)) {
|
||||
active_index = 0;
|
||||
}
|
||||
return storage.at_index(active_index).name();
|
||||
}
|
||||
|
||||
if (active_index > BKE_attributes_length(owner, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL)) {
|
||||
active_index = 0;
|
||||
}
|
||||
|
||||
const std::array<DomainInfo, ATTR_DOMAIN_NUM> info = get_domains(owner);
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
|
||||
CustomData *customdata = info[domain].customdata;
|
||||
if (customdata == nullptr) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < customdata->totlayer; i++) {
|
||||
CustomDataLayer *layer = &customdata->layers[i];
|
||||
if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(eCustomDataType(layer->type))) {
|
||||
if (index == active_index) {
|
||||
if (blender::bke::allow_procedural_attribute_access(layer->name)) {
|
||||
return layer->name;
|
||||
const std::array<DomainInfo, ATTR_DOMAIN_NUM> info = get_domains(owner);
|
||||
int index = 0;
|
||||
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
|
||||
CustomData *customdata = info[domain].customdata;
|
||||
if (customdata == nullptr) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < customdata->totlayer; i++) {
|
||||
CustomDataLayer *layer = &customdata->layers[i];
|
||||
if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(eCustomDataType(layer->type))) {
|
||||
if (index == active_index) {
|
||||
if (blender::bke::allow_procedural_attribute_access(layer->name)) {
|
||||
return layer->name;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::nullopt;
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
if (!IndexRange(storage.count()).contains(active_index)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return storage.at_index(active_index).name();
|
||||
}
|
||||
|
||||
void BKE_attributes_active_set(AttributeOwner &owner, const StringRef name)
|
||||
{
|
||||
using namespace blender;
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &attributes = *owner.get_storage();
|
||||
*BKE_attributes_active_index_p(owner) = attributes.index_of(name);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
const CustomDataLayer *layer = BKE_attribute_search(
|
||||
owner, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
BLI_assert(layer != nullptr);
|
||||
|
||||
const int index = BKE_attribute_to_index(owner, layer, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL);
|
||||
*BKE_attributes_active_index_p(owner) = index;
|
||||
return;
|
||||
}
|
||||
|
||||
const CustomDataLayer *layer = BKE_attribute_search(
|
||||
owner, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
BLI_assert(layer != nullptr);
|
||||
|
||||
const int index = BKE_attribute_to_index(owner, layer, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL);
|
||||
*BKE_attributes_active_index_p(owner) = index;
|
||||
bke::AttributeStorage &attributes = *owner.get_storage();
|
||||
*BKE_attributes_active_index_p(owner) = attributes.index_of(name);
|
||||
}
|
||||
|
||||
void BKE_attributes_active_clear(AttributeOwner &owner)
|
||||
|
||||
@@ -213,27 +213,27 @@ bool attribute_set_poll(bContext &C, const ID &object_data)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeAccessor attributes = *owner.get_accessor();
|
||||
std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(*name);
|
||||
if (!meta_data) {
|
||||
CTX_wm_operator_poll_msg_set(&C, "No active attribute");
|
||||
return false;
|
||||
}
|
||||
if (ELEM(meta_data->data_type,
|
||||
bke::AttrType::String,
|
||||
bke::AttrType::Float4x4,
|
||||
bke::AttrType::Quaternion))
|
||||
{
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
const CustomDataLayer *layer = BKE_attribute_search(
|
||||
owner, *name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
if (ELEM(layer->type, CD_PROP_STRING, CD_PROP_FLOAT4X4, CD_PROP_QUATERNION)) {
|
||||
CTX_wm_operator_poll_msg_set(&C, "The active attribute has an unsupported type");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const CustomDataLayer *layer = BKE_attribute_search(
|
||||
owner, *name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
if (ELEM(layer->type, CD_PROP_STRING, CD_PROP_FLOAT4X4, CD_PROP_QUATERNION)) {
|
||||
bke::AttributeAccessor attributes = *owner.get_accessor();
|
||||
std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(*name);
|
||||
if (!meta_data) {
|
||||
CTX_wm_operator_poll_msg_set(&C, "No active attribute");
|
||||
return false;
|
||||
}
|
||||
if (ELEM(meta_data->data_type,
|
||||
bke::AttrType::String,
|
||||
bke::AttrType::Float4x4,
|
||||
bke::AttrType::Quaternion))
|
||||
{
|
||||
CTX_wm_operator_poll_msg_set(&C, "The active attribute has an unsupported type");
|
||||
return false;
|
||||
}
|
||||
@@ -298,27 +298,18 @@ static wmOperatorStatus geometry_attribute_add_exec(bContext *C, wmOperator *op)
|
||||
|
||||
char name[MAX_NAME];
|
||||
RNA_string_get(op->ptr, "name", name);
|
||||
eCustomDataType type = eCustomDataType(RNA_enum_get(op->ptr, "data_type"));
|
||||
bke::AttrDomain domain = bke::AttrDomain(RNA_enum_get(op->ptr, "domain"));
|
||||
const eCustomDataType type = eCustomDataType(RNA_enum_get(op->ptr, "data_type"));
|
||||
const bke::AttrDomain domain = bke::AttrDomain(RNA_enum_get(op->ptr, "domain"));
|
||||
AttributeOwner owner = AttributeOwner::from_id(id);
|
||||
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::MutableAttributeAccessor accessor = *owner.get_accessor();
|
||||
if (!accessor.domain_supported(bke::AttrDomain(domain))) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = BKE_attribute_new(owner, name, type, domain, op->reports);
|
||||
|
||||
if (layer == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
bke::AttributeStorage &attributes = *owner.get_storage();
|
||||
const int domain_size = accessor.domain_size(bke::AttrDomain(domain));
|
||||
|
||||
const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(type);
|
||||
bke::Attribute &attr = attributes.add(
|
||||
attributes.unique_name_calc(name),
|
||||
bke::AttrDomain(domain),
|
||||
*bke::custom_data_type_to_attr_type(type),
|
||||
bke::Attribute::ArrayData::from_default_value(cpp_type, domain_size));
|
||||
|
||||
BKE_attributes_active_set(owner, attr.name());
|
||||
BKE_attributes_active_set(owner, layer->name);
|
||||
|
||||
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
@@ -326,13 +317,22 @@ static wmOperatorStatus geometry_attribute_add_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = BKE_attribute_new(owner, name, type, domain, op->reports);
|
||||
|
||||
if (layer == nullptr) {
|
||||
bke::MutableAttributeAccessor accessor = *owner.get_accessor();
|
||||
if (!accessor.domain_supported(bke::AttrDomain(domain))) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
bke::AttributeStorage &attributes = *owner.get_storage();
|
||||
const int domain_size = accessor.domain_size(bke::AttrDomain(domain));
|
||||
|
||||
BKE_attributes_active_set(owner, layer->name);
|
||||
const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(type);
|
||||
bke::Attribute &attr = attributes.add(
|
||||
attributes.unique_name_calc(name),
|
||||
bke::AttrDomain(domain),
|
||||
*bke::custom_data_type_to_attr_type(type),
|
||||
bke::Attribute::ArrayData::from_default_value(cpp_type, domain_size));
|
||||
|
||||
BKE_attributes_active_set(owner, attr.name());
|
||||
|
||||
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
|
||||
@@ -332,61 +332,60 @@ static void rna_Attribute_name_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
attr->name().copy_unsafe(value);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
strcpy(value, ptr->data_as<CustomDataLayer>()->name);
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(value, ptr->data_as<CustomDataLayer>()->name);
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
attr->name().copy_unsafe(value);
|
||||
}
|
||||
|
||||
static int rna_Attribute_name_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
return attr->name().size();
|
||||
const CustomDataLayer *layer = ptr->data_as<CustomDataLayer>();
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
return strlen(layer->name);
|
||||
}
|
||||
|
||||
const CustomDataLayer *layer = ptr->data_as<CustomDataLayer>();
|
||||
return strlen(layer->name);
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
return attr->name().size();
|
||||
}
|
||||
|
||||
static void rna_Attribute_name_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
BKE_attribute_rename(owner, attr->name(), value, nullptr);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
BKE_attribute_rename(owner, layer->name, value, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
BKE_attribute_rename(owner, layer->name, value, nullptr);
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
BKE_attribute_rename(owner, attr->name(), value, nullptr);
|
||||
}
|
||||
|
||||
static int rna_Attribute_name_editable(const PointerRNA *ptr, const char **r_info)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(const_cast<PointerRNA *>(ptr));
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
if (BKE_attribute_required(owner, attr->name())) {
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(ptr->data);
|
||||
if (BKE_attribute_required(owner, layer->name)) {
|
||||
*r_info = N_("Cannot modify name of required geometry attribute");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(ptr->data);
|
||||
if (BKE_attribute_required(owner, layer->name)) {
|
||||
bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
if (BKE_attribute_required(owner, attr->name())) {
|
||||
*r_info = N_("Cannot modify name of required geometry attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -480,12 +479,12 @@ static int rna_Attribute_domain_get(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::Attribute *attr = static_cast<const bke::Attribute *>(ptr->data);
|
||||
return int(attr->domain());
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
return int(BKE_attribute_domain(owner, static_cast<const CustomDataLayer *>(ptr->data)));
|
||||
}
|
||||
|
||||
return int(BKE_attribute_domain(owner, static_cast<const CustomDataLayer *>(ptr->data)));
|
||||
const bke::Attribute *attr = static_cast<const bke::Attribute *>(ptr->data);
|
||||
return int(attr->domain());
|
||||
}
|
||||
|
||||
static bool rna_Attribute_is_internal_get(PointerRNA *ptr)
|
||||
@@ -504,64 +503,64 @@ static bool rna_Attribute_is_required_get(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::Attribute *attr = static_cast<const bke::Attribute *>(ptr->data);
|
||||
return BKE_attribute_required(owner, attr->name());
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
return BKE_attribute_required(owner, layer->name);
|
||||
}
|
||||
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
|
||||
return BKE_attribute_required(owner, layer->name);
|
||||
const bke::Attribute *attr = static_cast<const bke::Attribute *>(ptr->data);
|
||||
return BKE_attribute_required(owner, attr->name());
|
||||
}
|
||||
|
||||
static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::MutableAttributeAccessor accessor = *owner.get_accessor();
|
||||
|
||||
bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
const int domain_size = accessor.domain_size(attr->domain());
|
||||
const CPPType &type = bke::attribute_type_to_cpp_type(attr->data_type());
|
||||
switch (attr->storage_type()) {
|
||||
case bke::AttrStorageType::Array: {
|
||||
const auto &data = std::get<bke::Attribute::ArrayData>(attr->data_for_write());
|
||||
rna_iterator_array_begin(iter, ptr, data.data, type.size, domain_size, false, nullptr);
|
||||
break;
|
||||
}
|
||||
case bke::AttrStorageType::Single: {
|
||||
/* TODO: Access to single values is unimplemented for now. */
|
||||
iter->valid = false;
|
||||
break;
|
||||
}
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
|
||||
if (!(CD_TYPE_AS_MASK(eCustomDataType(layer->type)) & CD_MASK_PROP_ALL)) {
|
||||
iter->valid = false;
|
||||
}
|
||||
|
||||
const int length = BKE_attribute_data_length(owner, layer);
|
||||
const size_t struct_size = CustomData_get_elem_size(layer);
|
||||
CustomData_ensure_data_is_mutable(layer, length);
|
||||
|
||||
rna_iterator_array_begin(iter, ptr, layer->data, struct_size, length, 0, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
|
||||
if (!(CD_TYPE_AS_MASK(eCustomDataType(layer->type)) & CD_MASK_PROP_ALL)) {
|
||||
iter->valid = false;
|
||||
bke::MutableAttributeAccessor accessor = *owner.get_accessor();
|
||||
|
||||
bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
const int domain_size = accessor.domain_size(attr->domain());
|
||||
const CPPType &type = bke::attribute_type_to_cpp_type(attr->data_type());
|
||||
switch (attr->storage_type()) {
|
||||
case bke::AttrStorageType::Array: {
|
||||
const auto &data = std::get<bke::Attribute::ArrayData>(attr->data_for_write());
|
||||
rna_iterator_array_begin(iter, ptr, data.data, type.size, domain_size, false, nullptr);
|
||||
break;
|
||||
}
|
||||
case bke::AttrStorageType::Single: {
|
||||
/* TODO: Access to single values is unimplemented for now. */
|
||||
iter->valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int length = BKE_attribute_data_length(owner, layer);
|
||||
const size_t struct_size = CustomData_get_elem_size(layer);
|
||||
CustomData_ensure_data_is_mutable(layer, length);
|
||||
|
||||
rna_iterator_array_begin(iter, ptr, layer->data, struct_size, length, 0, nullptr);
|
||||
}
|
||||
|
||||
static int rna_Attribute_data_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_attribute_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
const bke::AttributeAccessor accessor = *owner.get_accessor();
|
||||
return accessor.domain_size(attr->domain());
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
|
||||
return BKE_attribute_data_length(owner, layer);
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
|
||||
return BKE_attribute_data_length(owner, layer);
|
||||
const bke::Attribute *attr = ptr->data_as<bke::Attribute>();
|
||||
const bke::AttributeAccessor accessor = *owner.get_accessor();
|
||||
return accessor.domain_size(attr->domain());
|
||||
}
|
||||
|
||||
static void rna_Attribute_update_data(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
|
||||
@@ -660,75 +659,74 @@ static PointerRNA rna_AttributeGroupID_new(
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = AttributeOwner::from_id(id);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::AttributeAccessor accessor = *owner.get_accessor();
|
||||
if (!accessor.domain_supported(AttrDomain(domain))) {
|
||||
BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = BKE_attribute_new(
|
||||
owner, name, eCustomDataType(type), AttrDomain(domain), reports);
|
||||
|
||||
if (!layer) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
const int domain_size = accessor.domain_size(AttrDomain(domain));
|
||||
|
||||
bke::AttributeStorage &attributes = *owner.get_storage();
|
||||
const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(eCustomDataType(type));
|
||||
bke::Attribute &attr = attributes.add(
|
||||
attributes.unique_name_calc(name),
|
||||
AttrDomain(domain),
|
||||
*bke::custom_data_type_to_attr_type(eCustomDataType(type)),
|
||||
bke::Attribute::ArrayData::from_default_value(cpp_type, domain_size));
|
||||
if ((GS(id->name) == ID_ME) && ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
|
||||
Mesh *mesh = (Mesh *)id;
|
||||
if (!mesh->active_color_attribute) {
|
||||
mesh->active_color_attribute = BLI_strdup(layer->name);
|
||||
}
|
||||
if (!mesh->default_color_attribute) {
|
||||
mesh->default_color_attribute = BLI_strdup(layer->name);
|
||||
}
|
||||
}
|
||||
|
||||
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
|
||||
return RNA_pointer_create_discrete(id, &RNA_Attribute, &attr);
|
||||
PointerRNA ptr = RNA_pointer_create_discrete(id, &RNA_Attribute, layer);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = BKE_attribute_new(
|
||||
owner, name, eCustomDataType(type), AttrDomain(domain), reports);
|
||||
|
||||
if (!layer) {
|
||||
const bke::AttributeAccessor accessor = *owner.get_accessor();
|
||||
if (!accessor.domain_supported(AttrDomain(domain))) {
|
||||
BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
const int domain_size = accessor.domain_size(AttrDomain(domain));
|
||||
|
||||
if ((GS(id->name) == ID_ME) && ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
|
||||
Mesh *mesh = (Mesh *)id;
|
||||
if (!mesh->active_color_attribute) {
|
||||
mesh->active_color_attribute = BLI_strdup(layer->name);
|
||||
}
|
||||
if (!mesh->default_color_attribute) {
|
||||
mesh->default_color_attribute = BLI_strdup(layer->name);
|
||||
}
|
||||
}
|
||||
bke::AttributeStorage &attributes = *owner.get_storage();
|
||||
const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(eCustomDataType(type));
|
||||
bke::Attribute &attr = attributes.add(
|
||||
attributes.unique_name_calc(name),
|
||||
AttrDomain(domain),
|
||||
*bke::custom_data_type_to_attr_type(eCustomDataType(type)),
|
||||
bke::Attribute::ArrayData::from_default_value(cpp_type, domain_size));
|
||||
|
||||
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
|
||||
PointerRNA ptr = RNA_pointer_create_discrete(id, &RNA_Attribute, layer);
|
||||
return ptr;
|
||||
return RNA_pointer_create_discrete(id, &RNA_Attribute, &attr);
|
||||
}
|
||||
|
||||
static void rna_AttributeGroupID_remove(ID *id, ReportList *reports, PointerRNA *attribute_ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = AttributeOwner::from_id(id);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
const bke::Attribute *attr = static_cast<const bke::Attribute *>(attribute_ptr->data);
|
||||
if (BKE_attribute_required(owner, attr->name())) {
|
||||
BKE_report(reports, RPT_ERROR, "Attribute is required and cannot be removed");
|
||||
return;
|
||||
}
|
||||
|
||||
bke::MutableAttributeAccessor accessor = *owner.get_accessor();
|
||||
accessor.remove(attr->name());
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)attribute_ptr->data;
|
||||
BKE_attribute_remove(owner, layer->name, reports);
|
||||
attribute_ptr->invalidate();
|
||||
|
||||
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const CustomDataLayer *layer = (const CustomDataLayer *)attribute_ptr->data;
|
||||
BKE_attribute_remove(owner, layer->name, reports);
|
||||
const bke::Attribute *attr = static_cast<const bke::Attribute *>(attribute_ptr->data);
|
||||
if (BKE_attribute_required(owner, attr->name())) {
|
||||
BKE_report(reports, RPT_ERROR, "Attribute is required and cannot be removed");
|
||||
return;
|
||||
}
|
||||
|
||||
bke::MutableAttributeAccessor accessor = *owner.get_accessor();
|
||||
accessor.remove(attr->name());
|
||||
attribute_ptr->invalidate();
|
||||
|
||||
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
|
||||
@@ -784,77 +782,77 @@ void rna_AttributeGroup_iterator_begin(CollectionPropertyIterator *iter, Pointer
|
||||
using namespace blender;
|
||||
memset(&iter->internal.array, 0, sizeof(iter->internal.array));
|
||||
AttributeOwner owner = owner_from_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
Vector<bke::Attribute *> attributes;
|
||||
storage.foreach([&](bke::Attribute &attr) { attributes.append(&attr); });
|
||||
VectorData data = attributes.release();
|
||||
rna_iterator_array_begin(
|
||||
iter, ptr, data.data, sizeof(bke::Attribute *), data.size, true, nullptr);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
rna_AttributeGroup_next_domain(owner, iter, ptr, rna_Attributes_layer_skip);
|
||||
return;
|
||||
}
|
||||
|
||||
rna_AttributeGroup_next_domain(owner, iter, ptr, rna_Attributes_layer_skip);
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
Vector<bke::Attribute *> attributes;
|
||||
storage.foreach([&](bke::Attribute &attr) { attributes.append(&attr); });
|
||||
VectorData data = attributes.release();
|
||||
rna_iterator_array_begin(
|
||||
iter, ptr, data.data, sizeof(bke::Attribute *), data.size, true, nullptr);
|
||||
}
|
||||
|
||||
void rna_AttributeGroup_iterator_next(CollectionPropertyIterator *iter)
|
||||
{
|
||||
rna_iterator_array_next(iter);
|
||||
AttributeOwner owner = owner_from_pointer_rna(&iter->parent);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
if (!iter->valid) {
|
||||
rna_AttributeGroup_next_domain(owner, iter, &iter->parent, rna_Attributes_layer_skip);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iter->valid) {
|
||||
rna_AttributeGroup_next_domain(owner, iter, &iter->parent, rna_Attributes_layer_skip);
|
||||
}
|
||||
/* Everything stored in #AttributeStorage is an attribute. */
|
||||
}
|
||||
|
||||
PointerRNA rna_AttributeGroup_iterator_get(CollectionPropertyIterator *iter)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_pointer_rna(&iter->parent);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::Attribute *attr = *static_cast<bke::Attribute **>(rna_iterator_array_get(iter));
|
||||
const eCustomDataType data_type = *bke::attr_type_to_custom_data_type(attr->data_type());
|
||||
StructRNA *type = srna_by_custom_data_layer_type(data_type);
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, attr);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(rna_iterator_array_get(iter));
|
||||
StructRNA *type = srna_by_custom_data_layer_type(eCustomDataType(layer->type));
|
||||
if (type == nullptr) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, layer);
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(rna_iterator_array_get(iter));
|
||||
StructRNA *type = srna_by_custom_data_layer_type(eCustomDataType(layer->type));
|
||||
if (type == nullptr) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, layer);
|
||||
bke::Attribute *attr = *static_cast<bke::Attribute **>(rna_iterator_array_get(iter));
|
||||
const eCustomDataType data_type = *bke::attr_type_to_custom_data_type(attr->data_type());
|
||||
StructRNA *type = srna_by_custom_data_layer_type(data_type);
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, attr);
|
||||
}
|
||||
|
||||
void rna_AttributeGroup_color_iterator_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
Vector<bke::Attribute *> attributes;
|
||||
storage.foreach([&](bke::Attribute &attr) {
|
||||
if (!(ATTR_DOMAIN_AS_MASK(attr.domain()) & ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
if (!(CD_TYPE_AS_MASK(*bke::attr_type_to_custom_data_type(attr.data_type())) &
|
||||
CD_MASK_COLOR_ALL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
attributes.append(&attr);
|
||||
});
|
||||
VectorData data = attributes.release();
|
||||
rna_iterator_array_begin(
|
||||
iter, ptr, data.data, sizeof(bke::Attribute *), data.size, true, nullptr);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
memset(&iter->internal.array, 0, sizeof(iter->internal.array));
|
||||
rna_AttributeGroup_next_domain(owner, iter, ptr, rna_Attributes_noncolor_layer_skip);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&iter->internal.array, 0, sizeof(iter->internal.array));
|
||||
rna_AttributeGroup_next_domain(owner, iter, ptr, rna_Attributes_noncolor_layer_skip);
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
Vector<bke::Attribute *> attributes;
|
||||
storage.foreach([&](bke::Attribute &attr) {
|
||||
if (!(ATTR_DOMAIN_AS_MASK(attr.domain()) & ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
if (!(CD_TYPE_AS_MASK(*bke::attr_type_to_custom_data_type(attr.data_type())) &
|
||||
CD_MASK_COLOR_ALL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
attributes.append(&attr);
|
||||
});
|
||||
VectorData data = attributes.release();
|
||||
rna_iterator_array_begin(
|
||||
iter, ptr, data.data, sizeof(bke::Attribute *), data.size, true, nullptr);
|
||||
}
|
||||
|
||||
void rna_AttributeGroup_color_iterator_next(CollectionPropertyIterator *iter)
|
||||
@@ -862,95 +860,98 @@ void rna_AttributeGroup_color_iterator_next(CollectionPropertyIterator *iter)
|
||||
using namespace blender;
|
||||
rna_iterator_array_next(iter);
|
||||
AttributeOwner owner = owner_from_pointer_rna(&iter->parent);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
if (!iter->valid) {
|
||||
AttributeOwner owner = owner_from_pointer_rna(&iter->parent);
|
||||
rna_AttributeGroup_next_domain(
|
||||
owner, iter, &iter->parent, rna_Attributes_noncolor_layer_skip);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iter->valid) {
|
||||
AttributeOwner owner = owner_from_pointer_rna(&iter->parent);
|
||||
rna_AttributeGroup_next_domain(owner, iter, &iter->parent, rna_Attributes_noncolor_layer_skip);
|
||||
}
|
||||
/* Not used for #AttributeStorage. */
|
||||
}
|
||||
|
||||
PointerRNA rna_AttributeGroup_color_iterator_get(CollectionPropertyIterator *iter)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_pointer_rna(&iter->parent);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::Attribute *attr = *static_cast<bke::Attribute **>(rna_iterator_array_get(iter));
|
||||
const eCustomDataType data_type = *bke::attr_type_to_custom_data_type(attr->data_type());
|
||||
StructRNA *type = srna_by_custom_data_layer_type(data_type);
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, attr);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(rna_iterator_array_get(iter));
|
||||
StructRNA *type = srna_by_custom_data_layer_type(eCustomDataType(layer->type));
|
||||
if (type == nullptr) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, layer);
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(rna_iterator_array_get(iter));
|
||||
StructRNA *type = srna_by_custom_data_layer_type(eCustomDataType(layer->type));
|
||||
if (type == nullptr) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, layer);
|
||||
bke::Attribute *attr = *static_cast<bke::Attribute **>(rna_iterator_array_get(iter));
|
||||
const eCustomDataType data_type = *bke::attr_type_to_custom_data_type(attr->data_type());
|
||||
StructRNA *type = srna_by_custom_data_layer_type(data_type);
|
||||
return RNA_pointer_create_with_parent(iter->parent, type, attr);
|
||||
}
|
||||
|
||||
int rna_AttributeGroup_color_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
int count = 0;
|
||||
storage.foreach([&](bke::Attribute &attr) {
|
||||
if (!(ATTR_DOMAIN_AS_MASK(attr.domain()) & ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
if (!(CD_TYPE_AS_MASK(*bke::attr_type_to_custom_data_type(attr.data_type())) &
|
||||
CD_MASK_COLOR_ALL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
count++;
|
||||
});
|
||||
return count;
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
return BKE_attributes_length(owner, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
|
||||
}
|
||||
return BKE_attributes_length(owner, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
|
||||
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
int count = 0;
|
||||
storage.foreach([&](bke::Attribute &attr) {
|
||||
if (!(ATTR_DOMAIN_AS_MASK(attr.domain()) & ATTR_DOMAIN_MASK_COLOR)) {
|
||||
return;
|
||||
}
|
||||
if (!(CD_TYPE_AS_MASK(*bke::attr_type_to_custom_data_type(attr.data_type())) &
|
||||
CD_MASK_COLOR_ALL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
count++;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
int rna_AttributeGroup_length(PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
int count = 0;
|
||||
storage.foreach([&](bke::Attribute & /*attr*/) { count++; });
|
||||
return count;
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
return BKE_attributes_length(owner, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL);
|
||||
}
|
||||
return BKE_attributes_length(owner, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL);
|
||||
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
int count = 0;
|
||||
storage.foreach([&](bke::Attribute & /*attr*/) { count++; });
|
||||
return count;
|
||||
}
|
||||
|
||||
bool rna_AttributeGroup_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = owner_from_pointer_rna(ptr);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
bke::Attribute *attr = storage.lookup(key);
|
||||
if (!attr) {
|
||||
*r_ptr = PointerRNA_NULL;
|
||||
return false;
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
if (CustomDataLayer *layer = BKE_attribute_search_for_write(
|
||||
owner, key, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL))
|
||||
{
|
||||
rna_pointer_create_with_ancestors(*ptr, &RNA_Attribute, layer, *r_ptr);
|
||||
return true;
|
||||
}
|
||||
rna_pointer_create_with_ancestors(*ptr, &RNA_Attribute, attr, *r_ptr);
|
||||
return true;
|
||||
|
||||
*r_ptr = PointerRNA_NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CustomDataLayer *layer = BKE_attribute_search_for_write(
|
||||
owner, key, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL))
|
||||
{
|
||||
rna_pointer_create_with_ancestors(*ptr, &RNA_Attribute, layer, *r_ptr);
|
||||
return true;
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
bke::Attribute *attr = storage.lookup(key);
|
||||
if (!attr) {
|
||||
*r_ptr = PointerRNA_NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_ptr = PointerRNA_NULL;
|
||||
return false;
|
||||
rna_pointer_create_with_ancestors(*ptr, &RNA_Attribute, attr, *r_ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int rna_AttributeGroupID_active_index_get(PointerRNA *ptr)
|
||||
@@ -967,15 +968,15 @@ static PointerRNA rna_AttributeGroupID_active_get(PointerRNA *ptr)
|
||||
if (!name) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
bke::Attribute *attr = storage.lookup(*name);
|
||||
return RNA_pointer_create_with_parent(*ptr, &RNA_Attribute, attr);
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = BKE_attribute_search_for_write(
|
||||
owner, *name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
return RNA_pointer_create_with_parent(*ptr, &RNA_Attribute, layer);
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = BKE_attribute_search_for_write(
|
||||
owner, *name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
return RNA_pointer_create_with_parent(*ptr, &RNA_Attribute, layer);
|
||||
bke::AttributeStorage &storage = *owner.get_storage();
|
||||
bke::Attribute *attr = storage.lookup(*name);
|
||||
return RNA_pointer_create_with_parent(*ptr, &RNA_Attribute, attr);
|
||||
}
|
||||
|
||||
static void rna_AttributeGroupID_active_set(PointerRNA *ptr,
|
||||
@@ -984,19 +985,19 @@ static void rna_AttributeGroupID_active_set(PointerRNA *ptr,
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = AttributeOwner::from_id(ptr->owner_id);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::Attribute *attr = attribute_ptr.data_as<bke::Attribute>();
|
||||
BKE_attributes_active_set(owner, attr->name());
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(attribute_ptr.data);
|
||||
if (layer) {
|
||||
BKE_attributes_active_set(owner, layer->name);
|
||||
}
|
||||
else {
|
||||
BKE_attributes_active_clear(owner);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = static_cast<CustomDataLayer *>(attribute_ptr.data);
|
||||
if (layer) {
|
||||
BKE_attributes_active_set(owner, layer->name);
|
||||
}
|
||||
else {
|
||||
BKE_attributes_active_clear(owner);
|
||||
}
|
||||
bke::Attribute *attr = attribute_ptr.data_as<bke::Attribute>();
|
||||
BKE_attributes_active_set(owner, attr->name());
|
||||
}
|
||||
|
||||
static void rna_AttributeGroupID_active_index_set(PointerRNA *ptr, int value)
|
||||
@@ -1037,12 +1038,12 @@ static int rna_AttributeGroupID_domain_size(ID *id, const int domain)
|
||||
{
|
||||
using namespace blender;
|
||||
AttributeOwner owner = AttributeOwner::from_id(id);
|
||||
if (owner.type() != AttributeOwnerType::Mesh) {
|
||||
bke::AttributeAccessor attributes = *owner.get_accessor();
|
||||
return attributes.domain_size(bke::AttrDomain(domain));
|
||||
if (owner.type() == AttributeOwnerType::Mesh) {
|
||||
return BKE_attribute_domain_size(owner, domain);
|
||||
}
|
||||
|
||||
return BKE_attribute_domain_size(owner, domain);
|
||||
bke::AttributeAccessor attributes = *owner.get_accessor();
|
||||
return attributes.domain_size(bke::AttrDomain(domain));
|
||||
}
|
||||
|
||||
static PointerRNA rna_AttributeGroupMesh_active_color_get(PointerRNA *ptr)
|
||||
|
||||
Reference in New Issue
Block a user