Mesh: Store active & default color attributes with strings

Attributes are unifying around a name-based API, and we would like to
be able to move away from CustomData in the future. This patch moves
the identification of active and fallback (render) color attributes
to strings on the mesh from flags on CustomDataLayer. This also
removes some ugliness used to retrieve these attributes and maintain
the active status.

The design is described more here: T98366

The patch keeps forward compatibility working until 4.0 with
the same method as the mesh struct of array refactors (T95965).

The strings are allowed to not correspond to an attribute, to allow
setting the active/default attribute independently of actually filling
its data. When applying a modifier, if the strings don't match an
attribute, they will be removed.

The realize instances / join node and join operator take the names from
the first / active input mesh. While other heuristics may be helpful
(and could be a future improvement), just using the first is simple
and predictable.

Differential Revision: https://developer.blender.org/D15169
This commit is contained in:
Hans Goudey 2022-12-15 14:18:57 -06:00
parent b1494bcea7
commit 6514bb05ea
Notes: blender-bot 2023-11-10 12:18:24 +01:00
Referenced by commit fb8778a28c, Fix T103394: default/active color status lost after remeshing
Referenced by commit 9e94135f17, Fix: Crash after mesh color attribute name commit
Referenced by commit 841020dba2, Fix active/default color names not being editable
Referenced by issue #103761, Regression: Creating the first vertex color on a mesh does not always make it active/default
Referenced by issue #103551, Regression: Stored Attributes appear black in the viewport
Referenced by issue #103394, Sculpt: Color attribute lose selected status after remesh
Referenced by issue #98366, Active Attributes
Referenced by pull request #105020, Fix #103761: creating a color attribute doesn't make it active
Referenced by commit acfafeed88, Fix #103761: creating a color attribute doesn't make it active
Referenced by commit f9f29eefc7, Fix #105150: Mesh.vertex_colors.new() returns existing active layer
Referenced by issue #105152, Regression: Python: removing a color attribute may leave a mesh without an active color attribute
Referenced by commit b8359ede7d, Fix #105168: Entering vertexpaint creates a non-default color attribute
Referenced by issue #107067, Active Color Attribute switches after save and reverting file
Referenced by issue #109443, Cannot set the Color attribute to display an object through Geometry Nodes
Referenced by issue #114657, Color attribute from applied Geometry Nodes modifier gets disabled render icon
Referenced by pull request #114699, Fix #114657: Color attribute from applied GN modifier not active
37 changed files with 666 additions and 563 deletions

View File

@ -105,16 +105,6 @@ int BKE_id_attribute_to_index(const struct ID *id,
eAttrDomainMask domain_mask,
eCustomDataMask layer_mask);
struct CustomDataLayer *BKE_id_attribute_subset_active_get(const struct ID *id,
int active_flag,
eAttrDomainMask domain_mask,
eCustomDataMask mask);
void BKE_id_attribute_subset_active_set(struct ID *id,
struct CustomDataLayer *layer,
int active_flag,
eAttrDomainMask domain_mask,
eCustomDataMask mask);
/**
* Sets up a temporary ID with arbitrary CustomData domains. `r_id` will
* be zero initialized with ID type id_type and any non-nullptr
@ -130,10 +120,13 @@ void BKE_id_attribute_copy_domains_temp(short id_type,
const struct CustomData *cdata,
struct ID *r_id);
const char *BKE_id_attributes_active_color_name(const struct ID *id);
const char *BKE_id_attributes_default_color_name(const struct ID *id);
struct CustomDataLayer *BKE_id_attributes_active_color_get(const struct ID *id);
void BKE_id_attributes_active_color_set(struct ID *id, struct CustomDataLayer *active_layer);
struct CustomDataLayer *BKE_id_attributes_render_color_get(const struct ID *id);
void BKE_id_attributes_render_color_set(struct ID *id, struct CustomDataLayer *active_layer);
void BKE_id_attributes_active_color_set(struct ID *id, const char *name);
struct CustomDataLayer *BKE_id_attributes_default_color_get(const struct ID *id);
void BKE_id_attributes_default_color_set(struct ID *id, const char *name);
struct CustomDataLayer *BKE_id_attributes_color_find(const struct ID *id, const char *name);
bool BKE_id_attribute_calc_unique_name(struct ID *id, const char *name, char *outname);

View File

@ -85,6 +85,9 @@ void BKE_mesh_legacy_convert_mpoly_to_material_indices(struct Mesh *mesh);
/** Convert from runtime loose edge cache to legacy edge flag. */
void BKE_mesh_legacy_convert_loose_edges_to_flag(struct Mesh *mesh);
void BKE_mesh_legacy_attribute_flags_to_strings(struct Mesh *mesh);
void BKE_mesh_legacy_attribute_strings_to_flags(struct Mesh *mesh);
#endif
/**

View File

@ -145,6 +145,7 @@ bool BKE_id_attribute_rename(ID *id,
const char *new_name,
ReportList *reports)
{
using namespace blender;
if (BKE_id_attribute_required(id, old_name)) {
BLI_assert_msg(0, "Required attribute name is not editable");
return false;
@ -166,6 +167,14 @@ bool BKE_id_attribute_rename(ID *id,
char result_name[MAX_CUSTOMDATA_LAYER_NAME];
BKE_id_attribute_calc_unique_name(id, new_name, result_name);
if (StringRef(old_name) == BKE_id_attributes_active_color_name(id)) {
BKE_id_attributes_active_color_set(id, result_name);
}
if (StringRef(old_name) == BKE_id_attributes_default_color_name(id)) {
BKE_id_attributes_default_color_set(id, result_name);
}
BLI_strncpy_utf8(layer->name, result_name, sizeof(layer->name));
return true;
@ -287,6 +296,7 @@ CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList
bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
{
using namespace blender;
using namespace blender::bke;
if (!name || name[0] == '\0') {
BKE_report(reports, RPT_ERROR, "The attribute name must not be empty");
@ -306,6 +316,12 @@ bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (CustomData *data = info[domain].customdata) {
if (BM_data_layer_free_named(em->bm, data, name)) {
if (name == StringRef(mesh->active_color_attribute)) {
MEM_SAFE_FREE(mesh->active_color_attribute);
}
else if (name == StringRef(mesh->default_color_attribute)) {
MEM_SAFE_FREE(mesh->default_color_attribute);
}
return true;
}
}
@ -327,6 +343,9 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
const int type,
const eAttrDomain domain)
{
if (!name) {
return nullptr;
}
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@ -350,6 +369,9 @@ CustomDataLayer *BKE_id_attribute_search(ID *id,
const eCustomDataMask type_mask,
const eAttrDomainMask domain_mask)
{
if (!name) {
return nullptr;
}
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@ -633,104 +655,69 @@ int BKE_id_attribute_to_index(const ID *id,
return -1;
}
CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
int active_flag,
eAttrDomainMask domain_mask,
eCustomDataMask mask)
const char *BKE_id_attributes_active_color_name(const ID *id)
{
DomainInfo info[ATTR_DOMAIN_NUM];
eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
CustomDataLayer *candidate = nullptr;
for (int i = 0; i < ARRAY_SIZE(domains); i++) {
if (!((1 << domains[i]) & domain_mask) || !info[domains[i]].customdata) {
continue;
}
CustomData *cdata = info[domains[i]].customdata;
for (int j = 0; j < cdata->totlayer; j++) {
CustomDataLayer *layer = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer->type) & mask) || (layer->flag & CD_FLAG_TEMPORARY)) {
continue;
}
if (layer->flag & active_flag) {
return layer;
}
candidate = layer;
}
if (GS(id->name) == ID_ME) {
return reinterpret_cast<const Mesh *>(id)->active_color_attribute;
}
return candidate;
return nullptr;
}
void BKE_id_attribute_subset_active_set(ID *id,
CustomDataLayer *layer,
int active_flag,
eAttrDomainMask domain_mask,
eCustomDataMask mask)
const char *BKE_id_attributes_default_color_name(const ID *id)
{
DomainInfo info[ATTR_DOMAIN_NUM];
eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
for (int i = 0; i < ATTR_DOMAIN_NUM; i++) {
eAttrDomainMask domain_mask2 = (eAttrDomainMask)(1 << domains[i]);
if (!(domain_mask2 & domain_mask) || !info[domains[i]].customdata) {
continue;
}
CustomData *cdata = info[domains[i]].customdata;
for (int j = 0; j < cdata->totlayer; j++) {
CustomDataLayer *layer_iter = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer_iter->type) & mask) || (layer_iter->flag & CD_FLAG_TEMPORARY)) {
continue;
}
layer_iter->flag &= ~active_flag;
}
if (GS(id->name) == ID_ME) {
return reinterpret_cast<const Mesh *>(id)->default_color_attribute;
}
layer->flag |= active_flag;
return nullptr;
}
CustomDataLayer *BKE_id_attributes_active_color_get(const ID *id)
{
return BKE_id_attribute_subset_active_get(
id, CD_FLAG_COLOR_ACTIVE, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
return BKE_id_attributes_color_find(id, BKE_id_attributes_active_color_name(id));
}
void BKE_id_attributes_active_color_set(ID *id, CustomDataLayer *active_layer)
void BKE_id_attributes_active_color_set(ID *id, const char *name)
{
BKE_id_attribute_subset_active_set(
id, active_layer, CD_FLAG_COLOR_ACTIVE, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
switch (GS(id->name)) {
case ID_ME: {
Mesh *mesh = reinterpret_cast<Mesh *>(id);
MEM_SAFE_FREE(mesh->active_color_attribute);
if (name) {
mesh->active_color_attribute = BLI_strdup(name);
}
break;
}
default:
break;
}
}
CustomDataLayer *BKE_id_attributes_render_color_get(const ID *id)
CustomDataLayer *BKE_id_attributes_default_color_get(const ID *id)
{
return BKE_id_attribute_subset_active_get(
id, CD_FLAG_COLOR_RENDER, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
return BKE_id_attributes_color_find(id, BKE_id_attributes_default_color_name(id));
}
void BKE_id_attributes_render_color_set(ID *id, CustomDataLayer *active_layer)
void BKE_id_attributes_default_color_set(ID *id, const char *name)
{
BKE_id_attribute_subset_active_set(
id, active_layer, CD_FLAG_COLOR_RENDER, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
switch (GS(id->name)) {
case ID_ME: {
Mesh *mesh = reinterpret_cast<Mesh *>(id);
MEM_SAFE_FREE(mesh->default_color_attribute);
if (name) {
mesh->default_color_attribute = BLI_strdup(name);
}
break;
}
default:
break;
}
}
CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name)
{
if (!name) {
return nullptr;
}
CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT);
if (layer == nullptr) {
layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER);

View File

@ -2347,8 +2347,7 @@ bool CustomData_merge(const CustomData *source,
newlayer->active_rnd = lastrender;
newlayer->active_clone = lastclone;
newlayer->active_mask = lastmask;
newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY | CD_FLAG_COLOR_ACTIVE |
CD_FLAG_COLOR_RENDER);
newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
changed = true;
if (layer->anonymous_id != nullptr) {

View File

@ -144,6 +144,10 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat);
BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names);
mesh_dst->active_color_attribute = static_cast<char *>(
MEM_dupallocN(mesh_src->active_color_attribute));
mesh_dst->default_color_attribute = static_cast<char *>(
MEM_dupallocN(mesh_src->default_color_attribute));
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert);
@ -253,6 +257,9 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
BKE_mesh_legacy_face_set_from_generic(mesh, poly_layers);
BKE_mesh_legacy_edge_crease_from_layers(mesh);
BKE_mesh_legacy_attribute_strings_to_flags(mesh);
mesh->active_color_attribute = nullptr;
mesh->default_color_attribute = nullptr;
BKE_mesh_legacy_convert_loose_edges_to_flag(mesh);
/* When converting to the old mesh format, don't save redundant attributes. */
names_to_skip.add_multiple_new({".hide_vert",
@ -288,6 +295,8 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
}
BKE_defbase_blend_write(writer, &mesh->vertex_group_names);
BLO_write_string(writer, mesh->active_color_attribute);
BLO_write_string(writer, mesh->default_color_attribute);
BLO_write_pointer_array(writer, mesh->totcol, mesh->mat);
BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect);
@ -337,6 +346,8 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
* Don't read them again if they were read as part of #CustomData. */
BKE_defvert_blend_read(reader, mesh->totvert, mesh->dvert);
}
BLO_read_data_address(reader, &mesh->active_color_attribute);
BLO_read_data_address(reader, &mesh->default_color_attribute);
mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
mesh->edit_mesh = nullptr;
@ -893,6 +904,8 @@ static void mesh_clear_geometry(Mesh *mesh)
mesh->totselect = 0;
BLI_freelistN(&mesh->vertex_group_names);
MEM_SAFE_FREE(mesh->active_color_attribute);
MEM_SAFE_FREE(mesh->default_color_attribute);
}
void BKE_mesh_clear_geometry(Mesh *mesh)

View File

@ -525,7 +525,7 @@ static void convert_mfaces_to_mpolys(ID *id,
#undef ME_FGON
}
static void update_active_fdata_layers(CustomData *fdata, CustomData *ldata)
static void update_active_fdata_layers(Mesh &mesh, CustomData *fdata, CustomData *ldata)
{
int act;
@ -544,10 +544,10 @@ static void update_active_fdata_layers(CustomData *fdata, CustomData *ldata)
}
if (CustomData_has_layer(ldata, CD_PROP_BYTE_COLOR)) {
act = CustomData_get_active_layer(ldata, CD_PROP_BYTE_COLOR);
act = CustomData_get_named_layer(ldata, CD_PROP_BYTE_COLOR, mesh.active_color_attribute);
CustomData_set_layer_active(fdata, CD_MCOL, act);
act = CustomData_get_render_layer(ldata, CD_PROP_BYTE_COLOR);
act = CustomData_get_named_layer(ldata, CD_PROP_BYTE_COLOR, mesh.default_color_attribute);
CustomData_set_layer_render(fdata, CD_MCOL, act);
act = CustomData_get_clone_layer(ldata, CD_PROP_BYTE_COLOR);
@ -599,7 +599,7 @@ static bool check_matching_legacy_layer_counts(CustomData *fdata, CustomData *ld
}
#endif
static void add_mface_layers(CustomData *fdata, CustomData *ldata, int total)
static void add_mface_layers(Mesh &mesh, CustomData *fdata, CustomData *ldata, int total)
{
/* avoid accumulating extra layers */
BLI_assert(!check_matching_legacy_layer_counts(fdata, ldata, false));
@ -631,7 +631,7 @@ static void add_mface_layers(CustomData *fdata, CustomData *ldata, int total)
}
}
update_active_fdata_layers(fdata, ldata);
update_active_fdata_layers(mesh, fdata, ldata);
}
static void mesh_ensure_tessellation_customdata(Mesh *me)
@ -652,7 +652,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) {
BKE_mesh_tessface_clear(me);
add_mface_layers(&me->fdata, &me->ldata, me->totface);
add_mface_layers(*me, &me->fdata, &me->ldata, me->totface);
/* TODO: add some `--debug-mesh` option. */
if (G.debug & G_DEBUG) {
@ -931,7 +931,8 @@ int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex,
return nr;
}
static int mesh_tessface_calc(CustomData *fdata,
static int mesh_tessface_calc(Mesh &mesh,
CustomData *fdata,
CustomData *ldata,
CustomData *pdata,
MVert *mvert,
@ -1140,7 +1141,7 @@ static int mesh_tessface_calc(CustomData *fdata,
/* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons
* they are directly tessellated from. */
CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
add_mface_layers(fdata, ldata, totface);
add_mface_layers(mesh, fdata, ldata, totface);
/* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* Polygons take care of their loops ordering, hence not of their vertices ordering.
@ -1178,7 +1179,8 @@ static int mesh_tessface_calc(CustomData *fdata,
void BKE_mesh_tessface_calc(Mesh *mesh)
{
mesh->totface = mesh_tessface_calc(&mesh->fdata,
mesh->totface = mesh_tessface_calc(*mesh,
&mesh->fdata,
&mesh->ldata,
&mesh->pdata,
BKE_mesh_verts_for_write(mesh),
@ -1567,3 +1569,123 @@ void BKE_mesh_legacy_convert_loose_edges_to_flag(Mesh *mesh)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Attribute Active Flag to String Conversion
* \{ */
void BKE_mesh_legacy_attribute_flags_to_strings(Mesh *mesh)
{
using namespace blender;
/* It's not clear whether the active/render status was stored in the dedicated flags or in the
* generic CustomData layer indices, so convert from both, preferring the explicit flags. */
auto active_from_flags = [&](const CustomData &data) {
if (!mesh->active_color_attribute) {
for (const int i : IndexRange(data.totlayer)) {
if (data.layers[i].flag & CD_FLAG_COLOR_ACTIVE) {
mesh->active_color_attribute = BLI_strdup(data.layers[i].name);
}
}
}
};
auto active_from_indices = [&](const CustomData &data) {
if (!mesh->active_color_attribute) {
const int i = CustomData_get_active_layer_index(&data, CD_PROP_COLOR);
if (i != -1) {
mesh->active_color_attribute = BLI_strdup(data.layers[i].name);
}
}
if (!mesh->active_color_attribute) {
const int i = CustomData_get_active_layer_index(&data, CD_PROP_BYTE_COLOR);
if (i != -1) {
mesh->active_color_attribute = BLI_strdup(data.layers[i].name);
}
}
};
auto default_from_flags = [&](const CustomData &data) {
if (!mesh->default_color_attribute) {
for (const int i : IndexRange(data.totlayer)) {
if (data.layers[i].flag & CD_FLAG_COLOR_RENDER) {
mesh->default_color_attribute = BLI_strdup(data.layers[i].name);
}
}
}
};
auto default_from_indices = [&](const CustomData &data) {
if (!mesh->default_color_attribute) {
const int i = CustomData_get_render_layer_index(&data, CD_PROP_COLOR);
if (i != -1) {
mesh->default_color_attribute = BLI_strdup(data.layers[i].name);
}
}
if (!mesh->default_color_attribute) {
const int i = CustomData_get_render_layer_index(&data, CD_PROP_BYTE_COLOR);
if (i != -1) {
mesh->default_color_attribute = BLI_strdup(data.layers[i].name);
}
}
};
active_from_flags(mesh->vdata);
active_from_flags(mesh->ldata);
active_from_indices(mesh->vdata);
active_from_indices(mesh->ldata);
default_from_flags(mesh->vdata);
default_from_flags(mesh->ldata);
default_from_indices(mesh->vdata);
default_from_indices(mesh->ldata);
}
void BKE_mesh_legacy_attribute_strings_to_flags(Mesh *mesh)
{
using namespace blender;
CustomData *vdata = &mesh->vdata;
CustomData *ldata = &mesh->ldata;
CustomData_clear_layer_flag(
vdata, CD_PROP_BYTE_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER);
CustomData_clear_layer_flag(ldata, CD_PROP_COLOR, CD_FLAG_COLOR_ACTIVE | CD_FLAG_COLOR_RENDER);
if (const char *name = mesh->active_color_attribute) {
int i;
if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_active_index(vdata, CD_PROP_BYTE_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
else if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_active_index(vdata, CD_PROP_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_active_index(ldata, CD_PROP_BYTE_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_active_index(ldata, CD_PROP_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_ACTIVE;
}
}
if (const char *name = mesh->default_color_attribute) {
int i;
if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_render_index(vdata, CD_PROP_BYTE_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
else if ((i = CustomData_get_named_layer_index(vdata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_render_index(vdata, CD_PROP_COLOR, i);
vdata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_BYTE_COLOR, name)) != -1) {
CustomData_set_layer_render_index(ldata, CD_PROP_BYTE_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
else if ((i = CustomData_get_named_layer_index(ldata, CD_PROP_COLOR, name)) != -1) {
CustomData_set_layer_render_index(ldata, CD_PROP_COLOR, i);
ldata->layers[i].flag |= CD_FLAG_COLOR_RENDER;
}
}
}
/** \} */

View File

@ -494,21 +494,6 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
MEM_SAFE_FREE(target_lmap);
MEM_SAFE_FREE(target_lmap_mem);
free_bvhtree_from_mesh(&bvhtree);
/* Transfer active/render color attributes */
CustomDataLayer *active_layer = BKE_id_attributes_active_color_get(&source->id);
CustomDataLayer *render_layer = BKE_id_attributes_render_color_get(&source->id);
if (active_layer) {
BKE_id_attributes_active_color_set(
&target->id, BKE_id_attributes_color_find(&target->id, active_layer->name));
}
if (render_layer) {
BKE_id_attributes_render_color_set(
&target->id, BKE_id_attributes_color_find(&target->id, render_layer->name));
}
}
struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)

View File

@ -1919,32 +1919,24 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
void BKE_sculpt_color_layer_create_if_needed(Object *object)
{
using namespace blender;
using namespace blender::bke;
Mesh *orig_me = BKE_object_get_original_mesh(object);
int types[] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
bool has_color = false;
for (int i = 0; i < ARRAY_SIZE(types); i++) {
has_color = CustomData_has_layer(&orig_me->vdata, types[i]) ||
CustomData_has_layer(&orig_me->ldata, types[i]);
if (has_color) {
break;
}
}
if (has_color) {
if (orig_me->attributes().contains(orig_me->active_color_attribute)) {
return;
}
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_SET_DEFAULT, nullptr, orig_me->totvert);
CustomDataLayer *layer = orig_me->vdata.layers +
CustomData_get_layer_index(&orig_me->vdata, CD_PROP_COLOR);
char unique_name[MAX_CUSTOMDATA_LAYER_NAME];
BKE_id_attribute_calc_unique_name(&orig_me->id, "Color", unique_name);
if (!orig_me->attributes_for_write().add(
unique_name, ATTR_DOMAIN_POINT, CD_PROP_COLOR, AttributeInitDefaultValue())) {
return;
}
BKE_mesh_tessface_clear(orig_me);
BKE_id_attributes_active_color_set(&orig_me->id, layer);
BKE_id_attributes_active_color_set(&orig_me->id, unique_name);
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
BKE_mesh_tessface_clear(orig_me);
if (object->sculpt && object->sculpt->pbvh) {
BKE_pbvh_update_active_vcol(object->sculpt->pbvh, orig_me);

View File

@ -696,6 +696,9 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
args->mpoly = pbvh->mpoly;
args->vert_normals = pbvh->vert_normals;
args->active_color = pbvh->mesh->active_color_attribute;
args->render_color = pbvh->mesh->default_color_attribute;
args->prim_indices = node->prim_indices;
args->face_sets = pbvh->face_sets;
break;
@ -711,6 +714,9 @@ static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
args->face_sets = pbvh->face_sets;
args->mpoly = pbvh->mpoly;
args->active_color = pbvh->mesh->active_color_attribute;
args->render_color = pbvh->mesh->default_color_attribute;
args->mesh_grids_num = pbvh->totgrid;
args->grids = pbvh->grids;
args->gridfaces = pbvh->gridfaces;
@ -1588,7 +1594,7 @@ void pbvh_update_BB_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag)
bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_attr)
{
CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)me);
CustomDataLayer *layer = BKE_id_attributes_color_find(&me->id, me->active_color_attribute);
if (!layer || !ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
*r_layer = NULL;
@ -1596,7 +1602,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDo
return false;
}
eAttrDomain domain = BKE_id_attribute_domain((ID *)me, layer);
eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
*r_layer = NULL;

View File

@ -3197,10 +3197,10 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (actlayer) {
if (step) {
BKE_id_attributes_render_color_set(&me->id, actlayer);
BKE_id_attributes_default_color_set(&me->id, actlayer->name);
}
else {
BKE_id_attributes_active_color_set(&me->id, actlayer);
BKE_id_attributes_active_color_set(&me->id, actlayer->name);
}
}
}
@ -3362,10 +3362,10 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (actlayer) {
if (step) {
BKE_id_attributes_render_color_set(&me->id, actlayer);
BKE_id_attributes_default_color_set(&me->id, actlayer->name);
}
else {
BKE_id_attributes_active_color_set(&me->id, actlayer);
BKE_id_attributes_active_color_set(&me->id, actlayer->name);
}
}
}

View File

@ -33,6 +33,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh)
BKE_mesh_legacy_bevel_weight_to_layers(&mesh);
BKE_mesh_legacy_face_set_to_generic(&mesh);
BKE_mesh_legacy_edge_crease_to_layers(&mesh);
BKE_mesh_legacy_attribute_flags_to_strings(&mesh);
}
static void version_motion_tracking_legacy_camera_object(MovieClip &movieclip)

View File

@ -48,6 +48,9 @@ typedef struct PBVH_GPU_Args {
struct CustomData *vdata, *ldata, *pdata;
const float (*vert_normals)[3];
const char *active_color;
const char *render_color;
int face_sets_color_seed, face_sets_color_default;
int *face_sets; /* for PBVH_FACES and PBVH_GRIDS */

View File

@ -426,23 +426,8 @@ static void retrieve_active_attribute_names(MeshRenderData &mr,
const Mesh &mesh)
{
const Mesh *mesh_final = editmesh_final_or_this(&object, &mesh);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(mesh_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(mesh_final);
/* Necessary because which attributes are active/default is stored in #CustomData. */
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
mr.active_color_name = nullptr;
mr.default_color_name = nullptr;
if (const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id)) {
mr.active_color_name = active->name;
}
if (const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id)) {
mr.default_color_name = render->name;
}
mr.active_color_name = mesh_final->active_color_attribute;
mr.default_color_name = mesh_final->default_color_attribute;
}
MeshRenderData *mesh_render_data_create(Object *object,

View File

@ -282,19 +282,13 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_edata = mesh_cd_edata_get_from_mesh(me_final);
/* Create a mesh with final customdata domains
* we can query with attribute API. */
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, nullptr, &me_query.id);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
mesh_cd_layers_type_clear(&cd_used);
const CustomDataLayer *default_color = BKE_id_attributes_render_color_get(&me_query.id);
const StringRefNull default_color_name = default_color ? default_color->name : "";
const StringRefNull default_color_name = me_final->default_color_attribute ?
me_final->default_color_attribute :
"";
for (int i = 0; i < gpumat_array_len; i++) {
GPUMaterial *gpumat = gpumat_array[i];
@ -883,28 +877,21 @@ static void request_active_and_default_color_attributes(const Object &object,
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
/* Necessary because which attributes are active/default is stored in #CustomData. */
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
auto request_color_attribute = [&](const char *name) {
int layer_index;
eCustomDataType type;
if (drw_custom_data_match_attribute(cd_vdata, name, &layer_index, &type)) {
drw_attributes_add_request(&attributes, name, type, layer_index, ATTR_DOMAIN_POINT);
}
else if (drw_custom_data_match_attribute(cd_ldata, name, &layer_index, &type)) {
drw_attributes_add_request(&attributes, name, type, layer_index, ATTR_DOMAIN_CORNER);
if (name) {
int layer_index;
eCustomDataType type;
if (drw_custom_data_match_attribute(cd_vdata, name, &layer_index, &type)) {
drw_attributes_add_request(&attributes, name, type, layer_index, ATTR_DOMAIN_POINT);
}
else if (drw_custom_data_match_attribute(cd_ldata, name, &layer_index, &type)) {
drw_attributes_add_request(&attributes, name, type, layer_index, ATTR_DOMAIN_CORNER);
}
}
};
if (const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id)) {
request_color_attribute(active->name);
}
if (const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id)) {
request_color_attribute(render->name);
}
request_color_attribute(me_final->active_color_attribute);
request_color_attribute(me_final->default_color_attribute);
}
GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me)

View File

@ -841,8 +841,16 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR)) {
cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata,
CD_PROP_BYTE_COLOR);
active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
render_col = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
if (psmd->mesh_final->active_color_attribute != NULL) {
active_col = CustomData_get_named_layer(&psmd->mesh_final->ldata,
CD_PROP_BYTE_COLOR,
psmd->mesh_final->active_color_attribute);
}
if (psmd->mesh_final->default_color_attribute != NULL) {
render_col = CustomData_get_named_layer(&psmd->mesh_final->ldata,
CD_PROP_BYTE_COLOR,
psmd->mesh_final->default_color_attribute);
}
}
}
@ -1168,7 +1176,11 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
}
if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR)) {
num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR);
if (psmd->mesh_final->active_color_attribute != NULL) {
active_col = CustomData_get_named_layer(&psmd->mesh_final->ldata,
CD_PROP_BYTE_COLOR,
psmd->mesh_final->active_color_attribute);
}
}
}

View File

@ -1408,8 +1408,8 @@ void DRW_shgroup_call_sculpt(DRWShadingGroup *shgroup,
Mesh *me = BKE_object_get_original_mesh(ob);
if (use_color) {
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
const CustomDataLayer *layer = BKE_id_attributes_color_find(&me->id,
me->active_color_attribute);
if (layer) {
eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);

View File

@ -24,6 +24,7 @@
#include "BLI_map.hh"
#include "BLI_math_color.h"
#include "BLI_math_vec_types.hh"
#include "BLI_string_ref.hh"
#include "BLI_timeit.hh"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
@ -916,33 +917,9 @@ struct PBVHBatches {
const char *prefix = "a";
if (ELEM(type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
Mesh query_mesh;
/* Check if we have args->me; if not use get_cdata to build something we
* can query for color attributes.
*/
if (args->me) {
memcpy(static_cast<void *>(&query_mesh),
static_cast<const void *>(args->me),
sizeof(Mesh));
}
else {
BKE_id_attribute_copy_domains_temp(ID_ME,
get_cdata(ATTR_DOMAIN_POINT, args),
nullptr,
get_cdata(ATTR_DOMAIN_CORNER, args),
nullptr,
nullptr,
&query_mesh.id);
}
prefix = "c";
CustomDataLayer *render = BKE_id_attributes_render_color_get(&query_mesh.id);
CustomDataLayer *active = BKE_id_attributes_active_color_get(&query_mesh.id);
is_render = render && layer && STREQ(render->name, layer->name);
is_active = active && layer && STREQ(active->name, layer->name);
is_active = blender::StringRef(args->active_color) == layer->name;
is_render = blender::StringRef(args->render_color) == layer->name;
}
else {
switch (type) {

View File

@ -107,8 +107,9 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void next_color_attribute(ID *id, CustomDataLayer *layer, bool is_render)
static void next_color_attribute(ID *id, const StringRefNull name, bool is_render)
{
const CustomDataLayer *layer = BKE_id_attributes_color_find(id, name.c_str());
int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
index++;
@ -122,18 +123,18 @@ static void next_color_attribute(ID *id, CustomDataLayer *layer, bool is_render)
if (layer) {
if (is_render) {
BKE_id_attributes_active_color_set(id, layer);
BKE_id_attributes_active_color_set(id, layer->name);
}
else {
BKE_id_attributes_render_color_set(id, layer);
BKE_id_attributes_default_color_set(id, layer->name);
}
}
}
static void next_color_attributes(ID *id, CustomDataLayer *layer)
static void next_color_attributes(ID *id, const StringRefNull name)
{
next_color_attribute(id, layer, false); /* active */
next_color_attribute(id, layer, true); /* render */
next_color_attribute(id, name, false); /* active */
next_color_attribute(id, name, true); /* render */
}
void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
@ -181,7 +182,7 @@ static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
ID *id = static_cast<ID *>(ob->data);
CustomDataLayer *layer = BKE_id_attributes_active_get(id);
next_color_attributes(id, layer);
next_color_attributes(id, layer->name);
if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
return OPERATOR_CANCELLED;
@ -231,10 +232,10 @@ static int geometry_color_attribute_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
BKE_id_attributes_active_color_set(id, layer);
BKE_id_attributes_active_color_set(id, layer->name);
if (!BKE_id_attributes_render_color_get(id)) {
BKE_id_attributes_render_color_set(id, layer);
if (!BKE_id_attributes_color_find(id, BKE_id_attributes_default_color_name(id))) {
BKE_id_attributes_default_color_set(id, layer->name);
}
BKE_object_attributes_active_color_fill(ob, color, false);
@ -411,13 +412,8 @@ static int geometry_color_attribute_set_render_exec(bContext *C, wmOperator *op)
char name[MAX_NAME];
RNA_string_get(op->ptr, "name", name);
CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT);
layer = !layer ? BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT) : layer;
layer = !layer ? BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER) : layer;
layer = !layer ? BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER) : layer;
if (layer) {
BKE_id_attributes_render_color_set(id, layer);
if (BKE_id_attributes_color_find(id, name)) {
BKE_id_attributes_default_color_set(id, name);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
@ -453,15 +449,14 @@ static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
ID *id = static_cast<ID *>(ob->data);
CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
if (layer == nullptr) {
const std::string active_name = StringRef(BKE_id_attributes_active_color_name(id));
if (active_name.empty()) {
return OPERATOR_CANCELLED;
}
next_color_attributes(id, layer);
next_color_attributes(id, active_name);
if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
if (!BKE_id_attribute_remove(id, active_name.c_str(), op->reports)) {
return OPERATOR_CANCELLED;
}
@ -477,10 +472,10 @@ static bool geometry_color_attributes_remove_poll(bContext *C)
return false;
}
Object *ob = ED_object_context(C);
ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
const Object *ob = ED_object_context(C);
const ID *data = static_cast<ID *>(ob->data);
if (BKE_id_attributes_active_color_get(data) != nullptr) {
if (BKE_id_attributes_color_find(data, BKE_id_attributes_active_color_name(data))) {
return true;
}
@ -506,18 +501,17 @@ static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
ID *id = static_cast<ID *>(ob->data);
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
if (layer == nullptr) {
const char *active_name = BKE_id_attributes_active_color_name(id);
if (active_name == nullptr) {
return OPERATOR_CANCELLED;
}
CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, layer->name, op->reports);
CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, active_name, op->reports);
if (new_layer == nullptr) {
return OPERATOR_CANCELLED;
}
BKE_id_attributes_active_color_set(id, new_layer);
BKE_id_attributes_active_color_set(id, new_layer->name);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
@ -535,10 +529,10 @@ static bool geometry_color_attributes_duplicate_poll(bContext *C)
return false;
}
Object *ob = ED_object_context(C);
ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
const Object *ob = ED_object_context(C);
const ID *data = static_cast<ID *>(ob->data);
if (BKE_id_attributes_active_color_get(data) != nullptr) {
if (BKE_id_attributes_color_find(data, BKE_id_attributes_active_color_name(data))) {
return true;
}

View File

@ -377,79 +377,71 @@ bool ED_mesh_uv_remove_named(Mesh *me, const char *name)
return false;
}
int ED_mesh_color_add(Mesh *me,
const char *name,
const bool active_set,
const bool do_init,
ReportList * /*reports*/)
int ED_mesh_color_add(
Mesh *me, const char *name, const bool active_set, const bool do_init, ReportList *reports)
{
/* NOTE: keep in sync with #ED_mesh_uv_add. */
/* If no name is supplied, provide a backwards compatible default. */
if (!name) {
name = "Col";
}
BMEditMesh *em;
int layernum;
if (const CustomDataLayer *layer = BKE_id_attribute_find(
&me->id, me->active_color_attribute, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER)) {
int dummy;
const CustomData *data = mesh_customdata_get_type(me, BM_LOOP, &dummy);
return CustomData_get_named_layer(data, CD_PROP_BYTE_COLOR, layer->name);
}
if (me->edit_mesh) {
em = me->edit_mesh;
CustomDataLayer *layer = BKE_id_attribute_new(
&me->id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER, reports);
layernum = CustomData_number_of_layers(&em->bm->ldata, CD_PROP_BYTE_COLOR);
/* CD_PROP_BYTE_COLOR */
BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_PROP_BYTE_COLOR, name);
/* copy data from active vertex color layer */
if (layernum && do_init) {
const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_PROP_BYTE_COLOR);
BM_data_layer_copy(em->bm, &em->bm->ldata, CD_PROP_BYTE_COLOR, layernum_dst, layernum);
}
if (active_set || layernum == 0) {
CustomData_set_layer_active(&em->bm->ldata, CD_PROP_BYTE_COLOR, layernum);
if (do_init) {
const char *active_name = me->active_color_attribute;
if (const CustomDataLayer *active_layer = BKE_id_attributes_color_find(&me->id, active_name)) {
if (const BMEditMesh *em = me->edit_mesh) {
BMesh &bm = *em->bm;
const int src_i = CustomData_get_named_layer(&bm.ldata, CD_PROP_BYTE_COLOR, active_name);
const int dst_i = CustomData_get_named_layer(&bm.ldata, CD_PROP_BYTE_COLOR, layer->name);
BM_data_layer_copy(&bm, &bm.ldata, CD_PROP_BYTE_COLOR, src_i, dst_i);
}
else {
memcpy(layer->data, active_layer->data, CustomData_get_elem_size(layer) * me->totloop);
}
}
}
else {
layernum = CustomData_number_of_layers(&me->ldata, CD_PROP_BYTE_COLOR);
if (CustomData_get_active_layer(&me->ldata, CD_PROP_BYTE_COLOR) != -1 && do_init) {
CustomData_add_layer_named(&me->ldata,
CD_PROP_BYTE_COLOR,
CD_DUPLICATE,
CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR),
me->totloop,
name);
}
else {
CustomData_add_layer_named(
&me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name);
}
if (active_set || layernum == 0) {
CustomData_set_layer_active(&me->ldata, CD_PROP_BYTE_COLOR, layernum);
}
BKE_mesh_tessface_clear(me);
if (active_set) {
BKE_id_attributes_active_color_set(&me->id, layer->name);
}
DEG_id_tag_update(&me->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, me);
return layernum;
int dummy;
const CustomData *data = mesh_customdata_get_type(me, BM_LOOP, &dummy);
return CustomData_get_named_layer(data, CD_PROP_BYTE_COLOR, layer->name);
}
bool ED_mesh_color_ensure(Mesh *me, const char *name)
{
using namespace blender;
BLI_assert(me->edit_mesh == nullptr);
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer) {
CustomData_add_layer_named(
&me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name);
layer = me->ldata.layers + CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR);
BKE_id_attributes_active_color_set(&me->id, layer);
BKE_mesh_tessface_clear(me);
if (me->attributes().contains(me->active_color_attribute)) {
return true;
}
char unique_name[MAX_CUSTOMDATA_LAYER_NAME];
BKE_id_attribute_calc_unique_name(&me->id, name, unique_name);
if (!me->attributes_for_write().add(
unique_name, ATTR_DOMAIN_CORNER, CD_PROP_BYTE_COLOR, bke::AttributeInitDefaultValue())) {
return false;
}
BKE_id_attributes_active_color_set(&me->id, unique_name);
BKE_mesh_tessface_clear(me);
DEG_id_tag_update(&me->id, 0);
return (layer != nullptr);
return true;
}
/*********************** General poll ************************/
@ -464,57 +456,44 @@ static bool layers_poll(bContext *C)
/*********************** Sculpt Vertex colors operators ************************/
int ED_mesh_sculpt_color_add(Mesh *me,
const char *name,
const bool do_init,
ReportList * /*reports*/)
int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool do_init, ReportList *reports)
{
/* NOTE: keep in sync with #ED_mesh_uv_add. */
BMEditMesh *em;
int layernum;
if (me->edit_mesh) {
em = me->edit_mesh;
layernum = CustomData_number_of_layers(&em->bm->vdata, CD_PROP_COLOR);
/* CD_PROP_COLOR */
BM_data_layer_add_named(em->bm, &em->bm->vdata, CD_PROP_COLOR, name);
/* copy data from active vertex color layer */
if (layernum && do_init) {
const int layernum_dst = CustomData_get_active_layer(&em->bm->vdata, CD_PROP_COLOR);
BM_data_layer_copy(em->bm, &em->bm->vdata, CD_PROP_COLOR, layernum_dst, layernum);
}
if (layernum == 0) {
CustomData_set_layer_active(&em->bm->vdata, CD_PROP_COLOR, layernum);
}
/* If no name is supplied, provide a backwards compatible default. */
if (!name) {
name = "Color";
}
else {
layernum = CustomData_number_of_layers(&me->vdata, CD_PROP_COLOR);
if (CustomData_has_layer(&me->vdata, CD_PROP_COLOR) && do_init) {
const MPropCol *color_data = (const MPropCol *)CustomData_get_layer(&me->vdata,
CD_PROP_COLOR);
CustomData_add_layer_named(
&me->vdata, CD_PROP_COLOR, CD_DUPLICATE, (MPropCol *)color_data, me->totvert, name);
}
else {
CustomData_add_layer_named(
&me->vdata, CD_PROP_COLOR, CD_SET_DEFAULT, nullptr, me->totvert, name);
}
if (const CustomDataLayer *layer = BKE_id_attribute_find(
&me->id, me->active_color_attribute, CD_PROP_COLOR, ATTR_DOMAIN_POINT)) {
int dummy;
const CustomData *data = mesh_customdata_get_type(me, BM_LOOP, &dummy);
return CustomData_get_named_layer(data, CD_PROP_BYTE_COLOR, layer->name);
}
if (layernum == 0) {
CustomData_set_layer_active(&me->vdata, CD_PROP_COLOR, layernum);
}
CustomDataLayer *layer = BKE_id_attribute_new(
&me->id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT, reports);
BKE_mesh_tessface_clear(me);
if (do_init) {
const char *active_name = me->active_color_attribute;
if (const CustomDataLayer *active_layer = BKE_id_attributes_color_find(&me->id, active_name)) {
if (const BMEditMesh *em = me->edit_mesh) {
BMesh &bm = *em->bm;
const int src_i = CustomData_get_named_layer(&bm.vdata, CD_PROP_COLOR, active_name);
const int dst_i = CustomData_get_named_layer(&bm.vdata, CD_PROP_COLOR, layer->name);
BM_data_layer_copy(&bm, &bm.vdata, CD_PROP_COLOR, src_i, dst_i);
}
else {
memcpy(layer->data, active_layer->data, CustomData_get_elem_size(layer) * me->totloop);
}
}
}
DEG_id_tag_update(&me->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, me);
return layernum;
int dummy;
const CustomData *data = mesh_customdata_get_type(me, BM_VERT, &dummy);
return CustomData_get_named_layer(data, CD_PROP_COLOR, layer->name);
}
/*********************** UV texture operators ************************/

View File

@ -452,7 +452,7 @@ static bool bake_object_check(const Scene *scene,
}
if (target == R_BAKE_TARGET_VERTEX_COLORS) {
if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
if (!BKE_id_attributes_color_find(&me->id, me->active_color_attribute)) {
BKE_reportf(reports,
RPT_ERROR,
"Mesh does not have an active color attribute \"%s\"",
@ -950,7 +950,7 @@ static bool bake_targets_init_vertex_colors(Main *bmain,
}
Mesh *me = ob->data;
if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
if (!BKE_id_attributes_color_find(&me->id, me->active_color_attribute)) {
BKE_report(reports, RPT_ERROR, "No active color attribute to bake to");
return false;
}
@ -1131,7 +1131,8 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
CustomDataLayer *active_color_layer = BKE_id_attributes_color_find(&me->id,
me->active_color_attribute);
BLI_assert(active_color_layer != NULL);
const eAttrDomain domain = BKE_id_attribute_domain(&me->id, active_color_layer);

View File

@ -858,6 +858,28 @@ static bool modifier_apply_shape(Main *bmain,
return true;
}
static void remove_invalid_attribute_strings(Mesh &mesh)
{
using namespace blender;
bke::AttributeAccessor attributes = mesh.attributes();
if (mesh.active_color_attribute) {
const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(
mesh.active_color_attribute);
if (!meta_data || !(meta_data->domain & ATTR_DOMAIN_MASK_COLOR) ||
!(meta_data->data_type & CD_MASK_COLOR_ALL)) {
MEM_freeN(mesh.active_color_attribute);
}
}
if (mesh.default_color_attribute) {
const std::optional<bke::AttributeMetaData> meta_data = attributes.lookup_meta_data(
mesh.default_color_attribute);
if (!meta_data || !(meta_data->domain & ATTR_DOMAIN_MASK_COLOR) ||
!(meta_data->data_type & CD_MASK_COLOR_ALL)) {
MEM_freeN(mesh.default_color_attribute);
}
}
}
static bool modifier_apply_obdata(
ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md_eval)
{
@ -910,6 +932,9 @@ static bool modifier_apply_obdata(
/* Anonymous attributes shouldn't be available on the applied geometry. */
me->attributes_for_write().remove_anonymous();
/* Remove strings referring to attributes if they no longer exist. */
remove_invalid_attribute_strings(*me);
if (md_eval->type == eModifierType_Multires) {
multires_customdata_delete(me);
}

View File

@ -6553,10 +6553,10 @@ static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object
return nullptr;
}
BKE_id_attributes_active_color_set(id, layer);
BKE_id_attributes_active_color_set(id, layer->name);
if (!BKE_id_attributes_render_color_get(id)) {
BKE_id_attributes_render_color_set(id, layer);
if (!BKE_id_attributes_default_color_get(id)) {
BKE_id_attributes_default_color_set(id, layer->name);
}
BKE_object_attributes_active_color_fill(ob, color, false);

View File

@ -136,14 +136,14 @@ struct NormalAnglePrecalc {
/* Returns number of elements. */
static int get_vcol_elements(Mesh *me, size_t *r_elem_size)
{
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
const std::optional<bke::AttributeMetaData> meta_data = me->attributes().lookup_meta_data(
me->active_color_attribute);
if (r_elem_size) {
*r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL;
*r_elem_size = meta_data->data_type == CD_PROP_COLOR ? sizeof(float[4]) : 4ULL;
}
switch (domain) {
switch (meta_data->domain) {
case ATTR_DOMAIN_POINT:
return me->totvert;
case ATTR_DOMAIN_CORNER:
@ -234,15 +234,20 @@ static void paint_last_stroke_update(Scene *scene, const float location[3])
bool vertex_paint_mode_poll(bContext *C)
{
const Object *ob = CTX_data_active_object(C);
if (!ob) {
return false;
}
const Mesh *mesh = static_cast<const Mesh *>(ob->data);
if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((const Mesh *)ob->data)->totpoly)) {
if (!(ob->mode == OB_MODE_VERTEX_PAINT && mesh->totpoly)) {
return false;
}
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(
static_cast<const ID *>(ob->data));
if (!mesh->attributes().contains(mesh->active_color_attribute)) {
return false;
}
return layer != nullptr;
return true;
}
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
@ -2845,8 +2850,6 @@ static void *vpaint_init_vpaint(bContext *C,
{
VPaintData<Color, Traits, domain> *vpd;
size_t elem_size;
int elem_num = get_vcol_elements(me, &elem_size);
/* make mode data storage */
vpd = MEM_new<VPaintData<Color, Traits, domain>>("VPaintData");
@ -2870,12 +2873,11 @@ static void *vpaint_init_vpaint(bContext *C,
vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
const GVArray attribute = me->attributes().lookup(me->active_color_attribute, domain);
vpd->smear.color_prev = MEM_malloc_arrayN(attribute.size(), attribute.type().size(), __func__);
attribute.materialize(vpd->smear.color_prev);
vpd->smear.color_prev = MEM_malloc_arrayN(elem_num, elem_size, __func__);
memcpy(vpd->smear.color_prev, layer->data, elem_size * elem_num);
vpd->smear.color_curr = (uint *)MEM_dupallocN(vpd->smear.color_prev);
vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
}
/* Create projection handle */
@ -2908,30 +2910,31 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
ED_mesh_color_ensure(me, nullptr);
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer) {
const std::optional<bke::AttributeMetaData> meta_data = me->attributes().lookup_meta_data(
me->active_color_attribute);
if (!meta_data) {
return false;
}
eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
void *vpd = nullptr;
if (domain == ATTR_DOMAIN_POINT) {
if (layer->type == CD_PROP_COLOR) {
if (meta_data->domain == ATTR_DOMAIN_POINT) {
if (meta_data->data_type == CD_PROP_COLOR) {
vpd = vpaint_init_vpaint<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
C, op, scene, depsgraph, vp, ob, me, brush);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
else if (meta_data->data_type == CD_PROP_BYTE_COLOR) {
vpd = vpaint_init_vpaint<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
C, op, scene, depsgraph, vp, ob, me, brush);
}
}
else if (domain == ATTR_DOMAIN_CORNER) {
if (layer->type == CD_PROP_COLOR) {
else if (meta_data->domain == ATTR_DOMAIN_CORNER) {
if (meta_data->data_type == CD_PROP_COLOR) {
vpd = vpaint_init_vpaint<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
C, op, scene, depsgraph, vp, ob, me, brush);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
else if (meta_data->data_type == CD_PROP_BYTE_COLOR) {
vpd = vpaint_init_vpaint<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
C, op, scene, depsgraph, vp, ob, me, brush);
}
@ -3753,12 +3756,16 @@ static void vpaint_do_paint(bContext *C,
int totnode;
PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, vp, sd, brush, &totnode);
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
Color *color_data = static_cast<Color *>(layer->data);
bke::GSpanAttributeWriter attribute = me->attributes_for_write().lookup_for_write_span(
me->active_color_attribute);
BLI_assert(attribute.domain == domain);
Color *color_data = static_cast<Color *>(attribute.span.data());
/* Paint those leaves. */
vpaint_paint_leaves<Color, Traits, domain>(C, sd, vp, vpd, ob, me, color_data, nodes, totnode);
attribute.finish();
if (nodes) {
MEM_freeN(nodes);
}
@ -4075,98 +4082,114 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
/** \name Set Vertex Colors Operator
* \{ */
template<typename Color, typename Traits, eAttrDomain domain>
static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, CustomDataLayer *layer)
template<typename T>
static void fill_bm_face_or_corner_attribute(BMesh &bm,
const T &value,
const eAttrDomain domain,
const int cd_offset,
const bool use_vert_sel)
{
Mesh *me;
if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
(ED_mesh_color_ensure(me, nullptr) == false)) {
return false;
BMFace *f;
BMIter iter;
BM_ITER_MESH (f, &iter, &bm, BM_FACES_OF_MESH) {
BMLoop *l = f->l_first;
do {
if (!(use_vert_sel && !BM_elem_flag_test(l->v, BM_ELEM_SELECT))) {
if (domain == ATTR_DOMAIN_CORNER) {
*static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset)) = value;
}
else if (domain == ATTR_DOMAIN_POINT) {
*static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset)) = value;
}
}
} while ((l = l->next) != f->l_first);
}
}
const blender::VArray<bool> select_vert = me->attributes().lookup_or_default<bool>(
template<typename T>
static void fill_mesh_face_or_corner_attribute(Mesh &mesh,
const T &value,
const eAttrDomain domain,
const MutableSpan<T> data,
const bool use_vert_sel,
const bool use_face_sel)
{
const VArray<bool> select_vert = mesh.attributes().lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false);
const blender::VArray<bool> select_poly = me->attributes().lookup_or_default<bool>(
const VArray<bool> select_poly = mesh.attributes().lookup_or_default<bool>(
".select_poly", ATTR_DOMAIN_FACE, false);
Color paintcol = fromFloat<Color>(paintcol_in);
const Span<MPoly> polys = mesh.polys();
const Span<MLoop> loops = mesh.loops();
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
if (me->edit_mesh) {
BMesh *bm = me->edit_mesh->bm;
BMFace *f;
BMIter iter;
int cd_offset = -1;
/* Find customdata offset inside of bmesh. */
CustomData *cdata = domain == ATTR_DOMAIN_POINT ? &bm->vdata : &bm->ldata;
for (int i = 0; i < cdata->totlayer; i++) {
if (STREQ(cdata->layers[i].name, layer->name)) {
cd_offset = layer->offset;
}
for (const int i : polys.index_range()) {
if (use_face_sel && !select_poly[i]) {
continue;
}
const MPoly &poly = polys[i];
BLI_assert(cd_offset != -1);
int j = 0;
do {
uint vidx = loops[poly.loopstart + j].v;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
Color *color;
BMLoop *l = f->l_first;
do {
if (!(use_vert_sel && !BM_elem_flag_test(l->v, BM_ELEM_SELECT))) {
if constexpr (domain == ATTR_DOMAIN_CORNER) {
color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset));
}
else {
color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset));
}
*color = paintcol;
if (!(use_vert_sel && !(select_vert[vidx]))) {
if (domain == ATTR_DOMAIN_CORNER) {
data[poly.loopstart + j] = value;
}
} while ((l = l->next) != f->l_first);
else {
data[vidx] = value;
}
}
j++;
} while (j < poly.totloop);
}
BKE_mesh_tessface_clear(&mesh);
}
static void fill_mesh_color(Mesh &mesh,
const ColorPaint4f &color,
const StringRef attribute_name,
const bool use_vert_sel,
const bool use_face_sel)
{
if (mesh.edit_mesh) {
BMesh *bm = mesh.edit_mesh->bm;
const std::string name = attribute_name;
const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh.id, name.c_str());
const eAttrDomain domain = BKE_id_attribute_domain(&mesh.id, layer);
if (layer->type == CD_PROP_COLOR) {
fill_bm_face_or_corner_attribute<ColorPaint4f>(
*bm, color, domain, layer->offset, use_vert_sel);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
fill_bm_face_or_corner_attribute<ColorPaint4b>(
*bm, color.encode(), domain, layer->offset, use_vert_sel);
}
}
else {
Color *color_layer = static_cast<Color *>(layer->data);
const Span<MPoly> polys = me->polys();
const Span<MLoop> loops = me->loops();
for (const int i : polys.index_range()) {
if (use_face_sel && !select_poly[i]) {
continue;
}
const MPoly &poly = polys[i];
int j = 0;
do {
uint vidx = loops[poly.loopstart + j].v;
if (!(use_vert_sel && !(select_vert[vidx]))) {
if constexpr (domain == ATTR_DOMAIN_CORNER) {
color_layer[poly.loopstart + j] = paintcol;
}
else {
color_layer[vidx] = paintcol;
}
}
j++;
} while (j < poly.totloop);
bke::GSpanAttributeWriter attribute = mesh.attributes_for_write().lookup_for_write_span(
attribute_name);
if (attribute.span.type().is<ColorGeometry4f>()) {
fill_mesh_face_or_corner_attribute<ColorPaint4f>(
mesh,
color,
attribute.domain,
attribute.span.typed<ColorGeometry4f>().cast<ColorPaint4f>(),
use_vert_sel,
use_face_sel);
}
/* remove stale me->mcol, will be added later */
BKE_mesh_tessface_clear(me);
else if (attribute.span.type().is<ColorGeometry4b>()) {
fill_mesh_face_or_corner_attribute<ColorPaint4b>(
mesh,
color.encode(),
attribute.domain,
attribute.span.typed<ColorGeometry4b>().cast<ColorPaint4b>(),
use_vert_sel,
use_face_sel);
}
attribute.finish();
}
DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
/* NOTE: Original mesh is used for display, so tag it directly here. */
BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
return true;
}
/**
@ -4176,46 +4199,26 @@ static bool paint_object_attributes_active_color_fill_ex(Object *ob,
ColorPaint4f fill_color,
bool only_selected = true)
{
Mesh *me = BKE_object_get_original_mesh(ob);
Mesh *me = BKE_mesh_from_object(ob);
if (!me) {
return false;
}
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer) {
return false;
}
/* Store original #Mesh.editflag. */
const decltype(me->editflag) editflag = me->editflag;
if (!only_selected) {
me->editflag &= ~ME_EDIT_PAINT_FACE_SEL;
me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
}
eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
bool ok = false;
if (domain == ATTR_DOMAIN_POINT) {
if (layer->type == CD_PROP_COLOR) {
ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
}
}
else {
if (layer->type == CD_PROP_COLOR) {
ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
}
}
/* Restore #Mesh.editflag. */
me->editflag = editflag;
return ok;
const bool use_face_sel = only_selected ? (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0 : false;
const bool use_vert_sel = only_selected ? (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0 : false;
fill_mesh_color(*me, fill_color, me->active_color_attribute, use_vert_sel, use_face_sel);
DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
/* NOTE: Original mesh is used for display, so tag it directly here. */
BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
return true;
}
extern "C" bool BKE_object_attributes_active_color_fill(Object *ob,
const float fill_color[4],
bool only_selected)
bool BKE_object_attributes_active_color_fill(Object *ob,
const float fill_color[4],
bool only_selected)
{
return paint_object_attributes_active_color_fill_ex(ob, ColorPaint4f(fill_color), only_selected);
}

View File

@ -77,8 +77,7 @@ static bool vertex_paint_from_weight(Object *ob)
return false;
}
const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
if (active_color_layer == nullptr) {
if (!me->attributes().contains(me->active_color_attribute)) {
BLI_assert_unreachable();
return false;
}
@ -93,7 +92,7 @@ static bool vertex_paint_from_weight(Object *ob)
bke::MutableAttributeAccessor attributes = me->attributes_for_write();
bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
bke::GAttributeWriter color_attribute = attributes.lookup_for_write(me->active_color_attribute);
if (!color_attribute) {
BLI_assert_unreachable();
return false;
@ -178,25 +177,22 @@ static IndexMask get_selected_indices(const Mesh &mesh,
static void face_corner_color_equalize_verts(Mesh &mesh, const IndexMask selection)
{
using namespace blender;
const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
if (active_color_layer == nullptr) {
const StringRef name = mesh.active_color_attribute;
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(name);
if (!attribute) {
BLI_assert_unreachable();
return;
}
bke::AttributeAccessor attributes = mesh.attributes();
if (attributes.lookup_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) {
if (attribute.domain == ATTR_DOMAIN_POINT) {
return;
}
GVArray color_attribute_point = attributes.lookup(active_color_layer->name, ATTR_DOMAIN_POINT);
GVArray color_attribute_point = attributes.lookup(name, ATTR_DOMAIN_POINT);
GVArray color_attribute_corner = attributes.adapt_domain(
color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER);
color_attribute_corner.materialize(selection, active_color_layer->data);
color_attribute_corner.materialize(selection, attribute.span.data());
attribute.finish();
}
static bool vertex_color_smooth(Object *ob)
@ -252,16 +248,14 @@ template<typename TransformFn>
static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
{
using namespace blender;
const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
if (active_color_layer == nullptr) {
const StringRef name = mesh.active_color_attribute;
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
if (!attributes.contains(name)) {
BLI_assert_unreachable();
return false;
}
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
bke::GAttributeWriter color_attribute = attributes.lookup_for_write(name);
if (!color_attribute) {
BLI_assert_unreachable();
return false;

View File

@ -31,6 +31,7 @@
#include "DNA_scene_types.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
@ -131,10 +132,20 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, PBVHVertRef vertex)
bool SCULPT_has_loop_colors(const Object *ob)
{
using namespace blender;
Mesh *me = BKE_object_get_original_mesh(ob);
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
return layer && BKE_id_attribute_domain(&me->id, layer) == ATTR_DOMAIN_CORNER;
const std::optional<bke::AttributeMetaData> meta_data = me->attributes().lookup_meta_data(
me->active_color_attribute);
if (!meta_data) {
return false;
}
if (meta_data->domain != ATTR_DOMAIN_CORNER) {
return false;
}
if (!(CD_TYPE_AS_MASK(meta_data->data_type) & CD_MASK_COLOR_ALL)) {
return false;
}
return true;
}
bool SCULPT_has_colors(const SculptSession *ss)

View File

@ -1860,7 +1860,7 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr
}
if (layer) {
BKE_id_attributes_active_color_set(&me->id, layer);
BKE_id_attributes_active_color_set(&me->id, layer->name);
if (ob->sculpt && ob->sculpt->pbvh) {
BKE_pbvh_update_active_vcol(ob->sculpt->pbvh, me);

View File

@ -26,6 +26,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "BKE_attribute.h"
#include "BKE_collection.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
@ -606,7 +607,8 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
&mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Color");
MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named(
&mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Alpha");
CustomData_set_layer_active(&mesh->ldata, CD_PROP_BYTE_COLOR, 0);
BKE_id_attributes_active_color_set(
&mesh->id, CustomData_get_layer_name(&mesh->ldata, CD_PROP_BYTE_COLOR, 0));
mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList");
for (const auto item : group->materials.items()) {

View File

@ -1125,6 +1125,15 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
}
});
if (first_mesh.active_color_attribute) {
MEM_SAFE_FREE(dst_mesh->active_color_attribute);
dst_mesh->active_color_attribute = BLI_strdup(first_mesh.active_color_attribute);
}
if (first_mesh.default_color_attribute) {
MEM_SAFE_FREE(dst_mesh->default_color_attribute);
dst_mesh->default_color_attribute = BLI_strdup(first_mesh.default_color_attribute);
}
/* Tag modified attributes. */
for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
dst_attribute.finish();

View File

@ -111,26 +111,6 @@ void UI_GetThemeColorShadeAlpha4ubv(int /*colorid*/,
/** \name Stubs of BKE_attribute.h
* \{ */
void BKE_id_attribute_copy_domains_temp(short /*id_type*/,
const struct CustomData * /*vdata*/,
const struct CustomData * /*edata*/,
const struct CustomData * /*ldata*/,
const struct CustomData * /*pdata*/,
const struct CustomData * /*cdata*/,
struct ID * /*r_id*/)
{
}
struct CustomDataLayer *BKE_id_attributes_active_color_get(const struct ID * /*id*/)
{
return nullptr;
}
struct CustomDataLayer *BKE_id_attributes_render_color_get(const struct ID * /*id*/)
{
return nullptr;
}
eAttrDomain BKE_id_attribute_domain(const struct ID * /*id*/,
const struct CustomDataLayer * /*layer*/)
{

View File

@ -16,6 +16,7 @@
#include "MEM_guardedalloc.h"
#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_displist.h"
#include "BKE_global.h"
@ -486,7 +487,8 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
CustomData_add_layer_named(
&me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, colname.c_str());
}
CustomData_set_layer_active(&me->ldata, CD_PROP_BYTE_COLOR, 0);
BKE_id_attributes_active_color_set(
&me->id, CustomData_get_layer_name(&me->ldata, CD_PROP_BYTE_COLOR, 0));
}
}
}

View File

@ -251,14 +251,11 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
const int tot_count = obj_mesh_data.tot_vertices();
const Mesh *mesh = obj_mesh_data.get_mesh();
const CustomDataLayer *colors_layer = nullptr;
if (write_colors) {
colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
}
if (write_colors && (colors_layer != nullptr)) {
const StringRef name = mesh->active_color_attribute;
if (write_colors && !name.is_empty()) {
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>(
colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
BLI_assert(tot_count == attribute.size());
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {

View File

@ -376,6 +376,7 @@ void MeshFromGeometry::create_colors(Mesh *mesh)
/* This block is suitable, use colors from it. */
CustomDataLayer *color_layer = BKE_id_attribute_new(
&mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
BKE_id_attributes_active_color_set(&mesh->id, color_layer->name);
float4 *colors = (float4 *)color_layer->data;
int offset = mesh_geometry_.vertex_index_min_ - block.start_vertex_index;
for (int i = 0, n = mesh_geometry_.get_vertex_count(); i != n; ++i) {

View File

@ -244,8 +244,10 @@ enum {
CD_FLAG_EXTERNAL = (1 << 3),
/* Indicates external data is read into memory */
CD_FLAG_IN_MEMORY = (1 << 4),
#ifdef DNA_DEPRECATED_ALLOW
CD_FLAG_COLOR_ACTIVE = (1 << 5),
CD_FLAG_COLOR_RENDER = (1 << 6)
#endif
};
/* Limits */

View File

@ -151,6 +151,11 @@ typedef struct Mesh {
* default and Face Sets can be used without affecting the color of the mesh. */
int face_sets_color_default;
/** The color attribute currently selected in the list and edited by a user. */
char *active_color_attribute;
/** The color attribute used by default (i.e. for rendering) if no name is given explicitly. */
char *default_color_attribute;
/**
* User-defined symmetry flag (#eMeshSymmetryType) that causes editing operations to maintain
* symmetrical geometry. Supported by operations such as transform and weight-painting.

View File

@ -560,7 +560,10 @@ static void rna_AttributeGroup_update_active(Main *bmain, Scene *scene, PointerR
static PointerRNA rna_AttributeGroup_active_color_get(PointerRNA *ptr)
{
ID *id = ptr->owner_id;
CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
CustomDataLayer *layer = BKE_id_attribute_search(ptr->owner_id,
BKE_id_attributes_active_color_name(id),
CD_MASK_COLOR_ALL,
ATTR_DOMAIN_MASK_COLOR);
PointerRNA attribute_ptr;
RNA_pointer_create(id, &RNA_Attribute, layer, &attribute_ptr);
@ -573,13 +576,16 @@ static void rna_AttributeGroup_active_color_set(PointerRNA *ptr,
{
ID *id = ptr->owner_id;
CustomDataLayer *layer = attribute_ptr.data;
BKE_id_attributes_active_color_set(id, layer);
BKE_id_attributes_active_color_set(id, layer->name);
}
static int rna_AttributeGroup_active_color_index_get(PointerRNA *ptr)
{
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
const CustomDataLayer *layer = BKE_id_attribute_search(
ptr->owner_id,
BKE_id_attributes_active_color_name(ptr->owner_id),
CD_MASK_COLOR_ALL,
ATTR_DOMAIN_MASK_COLOR);
return BKE_id_attribute_to_index(
ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@ -595,7 +601,7 @@ static void rna_AttributeGroup_active_color_index_set(PointerRNA *ptr, int value
return;
}
BKE_id_attributes_active_color_set(ptr->owner_id, layer);
BKE_id_attributes_active_color_set(ptr->owner_id, layer->name);
}
static void rna_AttributeGroup_active_color_index_range(
@ -623,7 +629,8 @@ static void rna_AttributeGroup_update_active_color(Main *UNUSED(bmain),
static int rna_AttributeGroup_render_color_index_get(PointerRNA *ptr)
{
CustomDataLayer *layer = BKE_id_attributes_render_color_get(ptr->owner_id);
const CustomDataLayer *layer = BKE_id_attributes_color_find(
ptr->owner_id, BKE_id_attributes_default_color_name(ptr->owner_id));
return BKE_id_attribute_to_index(
ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@ -639,7 +646,7 @@ static void rna_AttributeGroup_render_color_index_set(PointerRNA *ptr, int value
return;
}
BKE_id_attributes_render_color_set(ptr->owner_id, layer);
BKE_id_attributes_default_color_set(ptr->owner_id, layer->name);
}
static void rna_AttributeGroup_render_color_index_range(
@ -655,43 +662,61 @@ static void rna_AttributeGroup_render_color_index_range(
static void rna_AttributeGroup_default_color_name_get(PointerRNA *ptr, char *value)
{
const ID *id = ptr->owner_id;
const CustomDataLayer *layer = BKE_id_attributes_render_color_get(id);
if (!layer) {
const char *name = BKE_id_attributes_default_color_name(id);
if (!name) {
value[0] = '\0';
return;
}
BLI_strncpy(value, layer->name, MAX_CUSTOMDATA_LAYER_NAME);
BLI_strncpy(value, name, MAX_CUSTOMDATA_LAYER_NAME);
}
static int rna_AttributeGroup_default_color_name_length(PointerRNA *ptr)
{
const ID *id = ptr->owner_id;
const CustomDataLayer *layer = BKE_id_attributes_render_color_get(id);
if (!layer) {
return 0;
const char *name = BKE_id_attributes_default_color_name(id);
return name ? strlen(name) : 0;
}
static void rna_AttributeGroup_default_color_name_set(PointerRNA *ptr, const char *value)
{
ID *id = ptr->owner_id;
if (GS(id->name) == ID_ME) {
Mesh *mesh = (Mesh *)id;
MEM_SAFE_FREE(mesh->default_color_attribute);
if (value[0]) {
mesh->default_color_attribute = BLI_strdup(value);
}
}
return strlen(layer->name);
}
static void rna_AttributeGroup_active_color_name_get(PointerRNA *ptr, char *value)
{
const ID *id = ptr->owner_id;
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
if (!layer) {
const char *name = BKE_id_attributes_active_color_name(id);
if (!name) {
value[0] = '\0';
return;
}
BLI_strncpy(value, layer->name, MAX_CUSTOMDATA_LAYER_NAME);
BLI_strncpy(value, name, MAX_CUSTOMDATA_LAYER_NAME);
}
static int rna_AttributeGroup_active_color_name_length(PointerRNA *ptr)
{
const ID *id = ptr->owner_id;
const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
if (!layer) {
return 0;
const char *name = BKE_id_attributes_active_color_name(id);
return name ? strlen(name) : 0;
}
static void rna_AttributeGroup_active_color_name_set(PointerRNA *ptr, const char *value)
{
ID *id = ptr->owner_id;
if (GS(id->name) == ID_ME) {
Mesh *mesh = (Mesh *)id;
MEM_SAFE_FREE(mesh->default_color_attribute);
if (value[0]) {
mesh->default_color_attribute = BLI_strdup(value);
}
}
return strlen(layer->name);
}
#else
@ -1160,7 +1185,7 @@ static void rna_def_attribute_group(BlenderRNA *brna)
RNA_def_property_string_funcs(prop,
"rna_AttributeGroup_default_color_name_get",
"rna_AttributeGroup_default_color_name_length",
NULL);
"rna_AttributeGroup_default_color_name_set");
RNA_def_property_ui_text(
prop,
"Default Color Attribute",
@ -1172,7 +1197,7 @@ static void rna_def_attribute_group(BlenderRNA *brna)
RNA_def_property_string_funcs(prop,
"rna_AttributeGroup_active_color_name_get",
"rna_AttributeGroup_active_color_name_length",
NULL);
"rna_AttributeGroup_active_color_name_set");
RNA_def_property_ui_text(prop,
"Active Color Attribute",
"The name of the active color attribute for display and editing");

View File

@ -171,7 +171,7 @@ static void rna_Material_active_paint_texture_index_update(bContext *C, PointerR
Mesh *mesh = ob->data;
CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, slot->attribute_name);
if (layer != NULL) {
BKE_id_attributes_active_color_set(&mesh->id, layer);
BKE_id_attributes_active_color_set(&mesh->id, layer->name);
}
DEG_id_tag_update(&ob->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, &ob->id);

View File

@ -1037,12 +1037,16 @@ static int rna_MeshLoopColorLayer_data_length(PointerRNA *ptr)
static bool rna_MeshLoopColorLayer_active_render_get(PointerRNA *ptr)
{
return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_PROP_BYTE_COLOR, 1);
const Mesh *mesh = rna_mesh(ptr);
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
return mesh->default_color_attribute && STREQ(mesh->default_color_attribute, layer->name);
}
static bool rna_MeshLoopColorLayer_active_get(PointerRNA *ptr)
{
return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_PROP_BYTE_COLOR, 0);
const Mesh *mesh = rna_mesh(ptr);
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
return mesh->active_color_attribute && STREQ(mesh->active_color_attribute, layer->name);
}
static void rna_MeshLoopColorLayer_active_render_set(PointerRNA *ptr, bool value)
@ -1077,12 +1081,16 @@ static int rna_MeshVertColorLayer_data_length(PointerRNA *ptr)
static bool rna_MeshVertColorLayer_active_render_get(PointerRNA *ptr)
{
return rna_CustomDataLayer_active_get(ptr, rna_mesh_vdata(ptr), CD_PROP_COLOR, 1);
const Mesh *mesh = rna_mesh(ptr);
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
return mesh->default_color_attribute && STREQ(mesh->default_color_attribute, layer->name);
}
static bool rna_MeshVertColorLayer_active_get(PointerRNA *ptr)
{
return rna_CustomDataLayer_active_get(ptr, rna_mesh_vdata(ptr), CD_PROP_COLOR, 0);
const Mesh *mesh = rna_mesh(ptr);
const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
return mesh->active_color_attribute && STREQ(mesh->active_color_attribute, layer->name);
}
static void rna_MeshVertColorLayer_active_render_set(PointerRNA *ptr, bool value)