Sculpt-dev: all vertex colors now live in single

UI list.

* Added an index to Mesh for active color attribute.
  This seems janky to me, shouldn't this (along
  with the active attribute index) be a
  domain, name, cdtype triplet?
* Added a little api to preserve the active attribute
  and color indices when changing mesh customdata
  layouts.  See above comment.
* The vertex color panel is now completely unified.
* TODO: allow setting render color layer (not sure how
  to do this).
This commit is contained in:
Joseph Eagar 2021-11-08 21:09:17 -08:00
parent 78d62d9be7
commit f0d0369506
20 changed files with 756 additions and 53 deletions

View File

@ -433,6 +433,44 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
col.operator("mesh.uv_texture_add", icon='ADD', text="")
col.operator("mesh.uv_texture_remove", icon='REMOVE', text="")
class MESH_UL_color_attributes(UIList):
display_domain_names = {
'POINT': "Vertex",
'EDGE': "Edge",
'FACE': "Face",
'CORNER': "Face Corner",
}
def filter_items(self, context, data, property):
attrs = getattr(data, property)
ret = []
idxs = []
idx = 0
for item in attrs:
bad = item.domain not in ["POINT", "CORNER"]
bad = bad or item.data_type not in ["FLOAT_COLOR", "BYTE_COLOR"]
ret.append(self.bitflag_filter_item if not bad else 0)
idxs.append(idx)
idx += 1
return ret, idxs
def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index):
data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type]
domain_name = self.display_domain_names.get(attribute.domain, "")
split = layout.split(factor=0.50)
split.emboss = 'NONE'
split.prop(attribute, "name", text="")
sub = split.row()
sub.alignment = 'RIGHT'
sub.active = False
sub.label(text="%s%s" % (domain_name, data_type.name))
class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
bl_label = "Vertex Colors"
@ -440,18 +478,62 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
def draw(self, context):
mesh = context.mesh
layout = self.layout
me = context.mesh
row = layout.row()
col = row.column()
col.template_list("MESH_UL_vcols", "vcols", me, "vertex_colors", me.vertex_colors, "active_index", rows=2)
col = row.column()
col.template_list("MESH_UL_color_attributes",
"attributes",
mesh,
"attributes",
mesh.attributes,
"active_color_index",
rows=3,)
col = row.column(align=True)
col.operator("mesh.vertex_color_add", icon='ADD', text="")
col.operator("mesh.vertex_color_remove", icon='REMOVE', text="")
col.operator("geometry.color_attribute_add", icon='ADD', text="")
col.operator("geometry.attribute_remove", icon='REMOVE', text="")
active = mesh.attributes.active
if active and (active.domain == "POINT" and active.data_type == "FLOAT_COLOR"):
layout.operator("sculpt.vertex_to_loop_colors", text="Save To Corners")
layout.operator("sculpt.loop_to_vertex_colors", text="Load From Corners")
self.draw_attribute_warnings(context, layout)
def draw_attribute_warnings(self, context, layout):
attributes_by_name = defaultdict(list)
ob = context.object
mesh = ob.data
builtin_attribute = object()
def add_builtin(name):
attributes_by_name[name].append(builtin_attribute)
def add_attributes(layers):
for layer in layers:
attributes_by_name[layer.name].append(layer)
add_builtin("position")
add_builtin("material_index")
add_builtin("shade_smooth")
add_builtin("normal")
add_builtin("crease")
add_attributes(mesh.attributes)
add_attributes(mesh.uv_layers)
add_attributes(ob.vertex_groups)
colliding_names = [name for name, layers in attributes_by_name.items() if len(layers) >= 2]
if len(colliding_names) == 0:
return
layout.label(text="Name collisions: {}".format(", ".join(colliding_names)), icon='ERROR')
class DATA_PT_remesh(MeshButtonsPanel, Panel):
bl_label = "Remesh"
@ -615,6 +697,7 @@ classes = (MESH_MT_vertex_group_context_menu,
MESH_UL_uvmaps,
MESH_UL_vcols,
MESH_UL_attributes,
MESH_UL_color_attributes,
DATA_PT_context_mesh,
DATA_PT_vertex_groups,
DATA_PT_shape_keys,

View File

@ -86,6 +86,11 @@ void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer);
int *BKE_id_attributes_active_index_p(struct ID *id);
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
CustomDataLayer *BKE_id_attribute_from_index(const struct ID *id, int lookup_index);
int *BKE_id_attributes_active_color_index_p(struct ID *id);
void BKE_id_attributes_active_color_set(struct ID *id, struct CustomDataLayer *active_layer);
struct CustomDataLayer *BKE_id_attributes_active_color_get(struct ID *id);
#ifdef __cplusplus
}

View File

@ -465,6 +465,14 @@ int CustomData_layertype_layers_max(const int type);
/* make sure the name of layer at index is unique */
void CustomData_set_layer_unique_name(struct CustomData *data, int index);
/* get unique layer name for a layer that doesn't currently exist */
void CustomData_find_unique_layer_name(CustomData *data,
int type,
const char *name,
char *outname);
/* try to find layer with name name; if it does not exist,
load the active layer name into outname*/
void CustomData_validate_layer_name(const struct CustomData *data,
int type,
const char *name,

View File

@ -22,6 +22,8 @@
* \ingroup bke
*/
#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_mesh_types.h"
#include "BLI_utildefines.h"
@ -662,6 +664,37 @@ BLI_INLINE int BKE_mesh_origindex_mface_mpoly(const int *index_mf_to_mpoly,
return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1;
}
/* ensures attribute active indices are kept up to date */
bool BKE_mesh_customdata_merge(struct Mesh *me,
AttributeDomain domain,
CustomData *src,
CustomDataMask mask,
eCDAllocType alloctype,
int totelem);
void BKE_mesh_customdata_copy(struct Mesh *me,
AttributeDomain domain,
CustomData *src,
CustomDataMask mask,
eCDAllocType alloctype,
int totelem);
void BKE_mesh_attributes_update_pre(struct Mesh *me,
AttributeDomain domain,
CustomData **r_dst,
CustomData *src,
int *active_type,
char active_name[MAX_CUSTOMDATA_LAYER_NAME],
int *active_color_type,
char active_color_name[MAX_CUSTOMDATA_LAYER_NAME]);
void BKE_mesh_attributes_update_post(struct Mesh *me,
AttributeDomain domain,
CustomData *dst,
CustomData *src,
int *active_type,
char active_name[MAX_CUSTOMDATA_LAYER_NAME],
int *active_color_type,
char active_color_name[MAX_CUSTOMDATA_LAYER_NAME]);
#ifdef __cplusplus
}
#endif

View File

@ -409,6 +409,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
/* Drawing */
void BKE_pbvh_draw_cb(PBVH *pbvh,
struct Mesh *me,
bool update_only_visible,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,

View File

@ -149,7 +149,7 @@ bool BKE_id_attribute_rename(ID *id,
return true;
}
CustomDataLayer *BKE_id_attribute_new(
ATTR_NO_OPT CustomDataLayer *BKE_id_attribute_new(
ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
{
DomainInfo info[ATTR_DOMAIN_NUM];
@ -161,25 +161,30 @@ CustomDataLayer *BKE_id_attribute_new(
return NULL;
}
char uniquename[sizeof(customdata->layers->name)];
CustomData_find_unique_layer_name(customdata, type, name, uniquename);
switch (GS(id->name)) {
case ID_ME: {
Mesh *me = (Mesh *)id;
BMEditMesh *em = me->edit_mesh;
if (em != NULL) {
BM_data_layer_add_named(em->bm, customdata, type, name);
BM_data_layer_add_named(em->bm, customdata, type, uniquename);
}
else {
CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
CustomData_add_layer_named(
customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
}
break;
}
default: {
CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
CustomData_add_layer_named(
customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
break;
}
}
const int index = CustomData_get_named_layer_index(customdata, type, name);
const int index = CustomData_get_named_layer_index(customdata, type, uniquename);
return (index == -1) ? NULL : &(customdata->layers[index]);
}
@ -246,6 +251,33 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
return NULL;
}
ATTR_NO_OPT CustomDataLayer *BKE_id_attribute_from_index(const ID *id, int lookup_index)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
int index = 0;
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
CustomData *customdata = info[domain].customdata;
if (!customdata) {
continue;
}
for (int i = 0; i < customdata->totlayer; i++) {
if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(customdata->layers[i].type)) {
if (index == lookup_index) {
return customdata->layers + i;
}
index++;
}
}
}
return NULL;
}
int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
@ -380,6 +412,90 @@ int *BKE_id_attributes_active_index_p(ID *id)
}
}
CustomDataLayer *BKE_id_attributes_active_color_get(ID *id)
{
int active_index = *BKE_id_attributes_active_color_index_p(id);
if (active_index > BKE_id_attributes_length(id, CD_MASK_PROP_ALL)) {
fprintf(stderr, "bad active color index %d; was out of bounds\n", active_index);
return NULL;
}
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
int index = 0;
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
CustomData *customdata = info[domain].customdata;
if (customdata) {
for (int i = 0; i < customdata->totlayer; i++) {
CustomDataLayer *layer = &customdata->layers[i];
if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
if (index == active_index) {
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER) &&
ELEM(layer->type, CD_PROP_COLOR, CD_MLOOPCOL)) {
return layer;
}
else {
fprintf(
stderr, "bad active color index %d; type was: %d\n", active_index, layer->type);
return NULL;
}
}
index++;
}
}
}
}
return NULL;
}
ATTR_NO_OPT void BKE_id_attributes_active_color_set(ID *id, CustomDataLayer *active_layer)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
if (!active_layer || !ELEM(active_layer->type, CD_PROP_COLOR, CD_MLOOPCOL)) {
fprintf(stderr,
"bad active color layer %p; type was %d\n",
active_layer,
active_layer ? active_layer->type : -1);
return;
}
int index = 0;
for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
CustomData *customdata = info[domain].customdata;
if (customdata) {
for (int i = 0; i < customdata->totlayer; i++) {
CustomDataLayer *layer = &customdata->layers[i];
if (layer == active_layer && ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
*BKE_id_attributes_active_color_index_p(id) = index;
return;
}
if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
index++;
}
}
}
}
}
int *BKE_id_attributes_active_color_index_p(ID *id)
{
switch (GS(id->name)) {
case ID_ME: {
return &((Mesh *)id)->active_color_index;
}
default:
return NULL;
}
}
CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *layers)
{
DomainInfo info[ATTR_DOMAIN_NUM];

View File

@ -5022,9 +5022,33 @@ static bool customdata_unique_check(void *arg, const char *name)
int type;
int index;
} *data_arg = arg;
return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index);
}
void CustomData_find_unique_layer_name(CustomData *data, int type, const char *name, char *outname)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
struct {
CustomData *data;
int type;
int index;
} data_arg;
if (!typeInfo->defaultname) {
return;
}
data_arg.data = data;
data_arg.type = type;
data_arg.index = -1;
BLI_strncpy(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
BLI_uniquename_cb(
customdata_unique_check, &data_arg, NULL, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
}
void CustomData_set_layer_unique_name(CustomData *data, int index)
{
CustomDataLayer *nlayer = &data->layers[index];
@ -5053,10 +5077,10 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
}
void CustomData_validate_layer_name(const CustomData *data,
int type,
const char *name,
char *outname)
ATTR_NO_OPT void CustomData_validate_layer_name(const CustomData *data,
int type,
const char *name,
char *outname)
{
int index = -1;

View File

@ -48,6 +48,7 @@
#include "BLT_translation.h"
#include "BKE_anim_data.h"
#include "BKE_attribute.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
@ -2270,3 +2271,164 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
}
}
}
void BKE_mesh_attributes_update_pre(Mesh *me,
AttributeDomain domain,
CustomData **r_dst,
CustomData *src,
int *active_type,
char active_name[MAX_CUSTOMDATA_LAYER_NAME],
int *active_color_type,
char active_color_name[MAX_CUSTOMDATA_LAYER_NAME])
{
CustomDataLayer *active = BKE_id_attributes_active_get((ID *)me);
CustomDataLayer *active_color = BKE_id_attributes_active_color_get((ID *)me);
CustomData *dst = NULL;
switch (domain) {
case ATTR_DOMAIN_POINT:
dst = &me->vdata;
break;
case ATTR_DOMAIN_EDGE:
dst = &me->edata;
break;
case ATTR_DOMAIN_CORNER:
dst = &me->ldata;
break;
case ATTR_DOMAIN_FACE:
dst = &me->pdata;
break;
default:
// should never happen
fprintf(stderr, "%s: bad domain!\n", __func__);
return;
}
*r_dst = dst;
/* check that domain is correct */
active = active && BKE_id_attribute_domain((ID *)me, active) != domain ? NULL : active;
active_color = active_color && BKE_id_attribute_domain((ID *)me, active_color) != domain ?
NULL :
active_color;
if (active) {
*active_type = active->type;
BLI_strncpy(active_name, active->name, sizeof(active_name));
}
else {
*active_type = -1;
}
if (active_color) {
*active_color_type = active_color->type;
BLI_strncpy(active_color_name, active_color->name, sizeof(active_color_name));
}
else {
*active_color_type = -1;
}
}
void BKE_mesh_attributes_update_post(Mesh *me,
AttributeDomain domain,
CustomData *dst,
CustomData *src,
int *active_type,
char active_name[MAX_CUSTOMDATA_LAYER_NAME],
int *active_color_type,
char active_color_name[MAX_CUSTOMDATA_LAYER_NAME])
{
int active_idx = *active_type != -1 ?
CustomData_get_named_layer_index(dst, *active_type, active_name) :
-1;
int active_color_idx = *active_color_type != -1 ?
CustomData_get_named_layer_index(
dst, *active_color_type, active_color_name) :
-1;
if (active_idx != -1) {
BKE_id_attributes_active_set((ID *)me, dst->layers + active_idx);
}
if (active_color_idx != -1) {
BKE_id_attributes_active_set((ID *)me, dst->layers + active_idx);
}
else if (*active_color_type != -1) {
bool ok = false;
// layer disappeared, find a new one
for (int i = 0; i < dst->totlayer; i++) {
if (ELEM(dst->layers[i].type, CD_PROP_COLOR, CD_MLOOPCOL)) {
ok = true;
BKE_id_attributes_active_set((ID *)me, dst->layers + i);
break;
}
}
if (!ok) {
// failed to find one? try other color attribute domain
CustomData *other = domain == ATTR_DOMAIN_POINT ? &me->ldata : &me->vdata;
for (int i = 0; i < other->totlayer; i++) {
if (ELEM(other->layers[i].type, CD_PROP_COLOR, CD_MLOOPCOL)) {
BKE_id_attributes_active_set((ID *)me, other->layers + i);
break;
}
}
}
}
}
bool BKE_mesh_customdata_merge(Mesh *me,
AttributeDomain domain,
CustomData *src,
CustomDataMask mask,
eCDAllocType alloctype,
int totelem)
{
int active_type, active_color_type;
char active_name[MAX_CUSTOMDATA_LAYER_NAME];
char active_color_name[MAX_CUSTOMDATA_LAYER_NAME];
CustomData *dst = NULL;
BKE_mesh_attributes_update_pre(
me, domain, &dst, src, &active_type, active_name, &active_color_type, active_color_name);
if (!dst) {
return false;
}
bool ret = CustomData_merge(src, dst, mask, alloctype, totelem);
BKE_mesh_attributes_update_post(
me, domain, dst, src, &active_type, active_name, &active_color_type, active_color_name);
return ret;
}
void BKE_mesh_customdata_copy(Mesh *me,
AttributeDomain domain,
CustomData *src,
CustomDataMask mask,
eCDAllocType alloctype,
int totelem)
{
int active_type, active_color_type;
char active_name[MAX_CUSTOMDATA_LAYER_NAME];
char active_color_name[MAX_CUSTOMDATA_LAYER_NAME];
CustomData *dst = NULL;
BKE_mesh_attributes_update_pre(
me, domain, &dst, src, &active_type, active_name, &active_color_type, active_color_name);
if (!dst) {
return;
}
CustomData_copy(src, dst, mask, alloctype, totelem);
BKE_mesh_attributes_update_post(
me, domain, dst, src, &active_type, active_name, &active_color_type, active_color_name);
}

View File

@ -1134,6 +1134,7 @@ typedef struct PBVHUpdateData {
int flag;
bool show_sculpt_face_sets;
bool flat_vcol_shading;
Mesh *mesh;
} PBVHUpdateData;
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
@ -1376,7 +1377,7 @@ ATTR_NO_OPT bool BKE_pbvh_get_color_layer(PBVH *pbvh,
CustomDataLayer **r_cl,
AttributeDomain *r_attr)
{
CustomDataLayer *cl = BKE_id_attributes_active_get((ID *)me);
CustomDataLayer *cl = BKE_id_attributes_active_color_get((ID *)me);
AttributeDomain domain;
if (!cl || !ELEM(cl->type, CD_PROP_COLOR, CD_MLOOPCOL)) {
@ -1454,6 +1455,12 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
PBVHUpdateData *data = userdata;
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
Mesh *me = data->mesh;
CustomDataLayer *vcol_layer = NULL;
AttributeDomain vcol_domain;
BKE_pbvh_get_color_layer(pbvh, me, &vcol_layer, &vcol_domain);
if (node->flag & PBVH_RebuildDrawBuffers) {
node->updategen++;
@ -1567,7 +1574,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
.flat_vcol = data->flat_vcol_shading,
.mat_nr = node->tri_buffers[i].mat_nr,
.active_vcol_domain = pbvh->vcol_domain,
.active_vcol_type = pbvh->vcol_type};
.active_vcol_type = pbvh->vcol_type,
.active_vcol_layer = vcol_layer};
GPU_pbvh_bmesh_buffers_update(&args);
}
@ -1623,7 +1631,8 @@ void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
static void pbvh_update_draw_buffers(
PBVH *pbvh, Mesh *me, PBVHNode **nodes, int totnode, int update_flag)
{
CustomData *vdata;
@ -1643,12 +1652,17 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode,
ldata = pbvh->ldata;
}
CustomDataLayer *vcol_layer = NULL;
AttributeDomain domain;
BKE_pbvh_get_color_layer(pbvh, me, &vcol_layer, &domain);
GPU_pbvh_update_attribute_names(vdata,
ldata,
GPU_pbvh_need_full_render_get(),
pbvh->flags & PBVH_FAST_DRAW,
pbvh->vcol_type,
pbvh->vcol_domain);
pbvh->vcol_domain,
vcol_layer);
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
@ -1665,7 +1679,7 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode,
/* Parallel creation and update of draw buffers. */
PBVHUpdateData data = {
.pbvh = pbvh, .nodes = nodes, .flat_vcol_shading = pbvh->flat_vcol_shading};
.pbvh = pbvh, .nodes = nodes, .flat_vcol_shading = pbvh->flat_vcol_shading, .mesh = me};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
@ -3177,6 +3191,7 @@ static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v)
}
void BKE_pbvh_draw_cb(PBVH *pbvh,
Mesh *me,
bool update_only_visible,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
@ -3221,11 +3236,11 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
pbvh->need_full_render = GPU_pbvh_need_full_render_get();
BKE_pbvh_draw_cb(
pbvh, update_only_visible, update_frustum, draw_frustum, draw_fn, user_data);
pbvh, me, update_only_visible, update_frustum, draw_frustum, draw_fn, user_data);
return;
}
pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
pbvh_update_draw_buffers(pbvh, me, nodes, totnode, update_flag);
}
MEM_SAFE_FREE(nodes);

View File

@ -1035,6 +1035,8 @@ void BM_mesh_bm_to_me(
BMIter iter;
int i, j;
CustomData *srcdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata};
if (params->copy_temp_cdlayers) {
bm_unmark_temp_cdlayers(bm);
}
@ -1066,6 +1068,24 @@ void BM_mesh_bm_to_me(
#endif
}
int active_types[4], active_color_types[4];
CustomData *active_dsts[4];
char active_names[4][MAX_CUSTOMDATA_LAYER_NAME];
char active_color_names[4][MAX_CUSTOMDATA_LAYER_NAME];
int active_domains[4] = {
ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_FACE};
for (int i = 0; i < 4; i++) {
BKE_mesh_attributes_update_pre(me,
active_domains[i],
active_dsts + i,
srcdatas[i],
active_types + i,
active_names[i],
active_color_types + i,
active_color_names[i]);
}
/* Free custom data. */
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
@ -1083,7 +1103,6 @@ void BM_mesh_bm_to_me(
me->totface = 0;
me->act_face = -1;
CustomData *srcdatas[] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata};
int id_flags[4] = {-1, -1, -1, -1};
{
@ -1121,6 +1140,18 @@ void BM_mesh_bm_to_me(
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
for (int i = 0; i < 4; i++) {
CustomData *dst;
BKE_mesh_attributes_update_post(me,
active_domains[i],
active_dsts[i],
srcdatas[i],
active_types + i,
active_names[i],
active_color_types + i,
active_color_names[i]);
}
/* This is called again, 'dotess' arg is used there. */
BKE_mesh_update_customdata_pointers(me, 0);
@ -1530,10 +1561,12 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
CustomData_MeshMasks_update(&mask, cd_mask_extra);
}
mask.vmask &= ~CD_MASK_SHAPEKEY;
CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CALLOC, me->totvert);
CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CALLOC, me->totedge);
CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CALLOC, me->totloop);
CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly);
BKE_mesh_customdata_merge(me, ATTR_DOMAIN_POINT, &bm->vdata, mask.vmask, CD_CALLOC, me->totvert);
BKE_mesh_customdata_merge(me, ATTR_DOMAIN_EDGE, &bm->edata, mask.emask, CD_CALLOC, me->totedge);
BKE_mesh_customdata_merge(
me, ATTR_DOMAIN_CORNER, &bm->ldata, mask.lmask, CD_CALLOC, me->totloop);
BKE_mesh_customdata_merge(me, ATTR_DOMAIN_FACE, &bm->pdata, mask.pmask, CD_CALLOC, me->totpoly);
BKE_mesh_update_customdata_pointers(me, false);

View File

@ -1088,6 +1088,7 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg);
BKE_pbvh_draw_cb(pbvh,
mesh,
update_only_visible,
&update_frustum,
&draw_frustum,

View File

@ -23,6 +23,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/atomic
)
set(INC_SYS

View File

@ -23,6 +23,8 @@
#include "BKE_attribute.h"
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "RNA_access.h"
#include "RNA_define.h"
@ -96,6 +98,11 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
BKE_id_attributes_active_set(id, layer);
if (ob->mode == OB_MODE_SCULPT) {
BKE_sculpt_update_object_for_edit(
CTX_data_ensure_evaluated_depsgraph(C), ob, false, false, false);
}
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
@ -141,6 +148,53 @@ void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Geometry Attribute";
ot->description = "Add attribute to geometry";
ot->idname = "GEOMETRY_OT_color_attribute_add";
/* api callbacks */
ot->poll = geometry_attributes_poll;
ot->exec = geometry_attribute_add_exec;
ot->invoke = WM_operator_props_popup_confirm;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop;
prop = RNA_def_string(ot->srna, "name", "Color", MAX_NAME, "Name", "Name of color attribute");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
static EnumPropertyItem domains[3] = {{ATTR_DOMAIN_POINT, "POINT", -1, "Point", ""},
{ATTR_DOMAIN_CORNER, "CORNER", -1, "Face Corner", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem types[3] = {{CD_PROP_COLOR, "COLOR", -1, "Color", ""},
{CD_MLOOPCOL, "BYTE_COLOR", -1, "Byte Color", ""},
{0, NULL, 0, NULL, NULL}};
prop = RNA_def_enum(ot->srna,
"domain",
domains,
ATTR_DOMAIN_POINT,
"Domain",
"Type of element that attribute is stored on");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_enum(ot->srna,
"data_type",
types,
CD_PROP_COLOR,
"Data Type",
"Type of data stored in attribute");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);

View File

@ -27,4 +27,5 @@ struct wmOperatorType;
/* *** geometry_attributes.c *** */
void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);

View File

@ -32,5 +32,6 @@
void ED_operatortypes_geometry(void)
{
WM_operatortype_append(GEOMETRY_OT_attribute_add);
WM_operatortype_append(GEOMETRY_OT_color_attribute_add);
WM_operatortype_append(GEOMETRY_OT_attribute_remove);
}

View File

@ -138,7 +138,9 @@ typedef struct SculptUndoStep {
// active vcol layer
SculptAttrRef active_attr_start;
SculptAttrRef active_vcol_attr_start;
SculptAttrRef active_attr_end;
SculptAttrRef active_vcol_attr_end;
bContext *C;
} SculptUndoStep;
@ -146,6 +148,7 @@ typedef struct SculptUndoStep {
static UndoSculpt *sculpt_undo_get_nodes(void);
static bool sculpt_attr_ref_equals(SculptAttrRef *a, SculptAttrRef *b);
static void sculpt_save_active_attr(Object *ob, SculptAttrRef *attr);
static void sculpt_save_active_vcol_attr(Object *ob, SculptAttrRef *attr);
static void update_unode_bmesh_memsize(SculptUndoNode *unode);
static UndoSculpt *sculpt_undo_get_nodes(void);
@ -2216,6 +2219,24 @@ static void sculpt_save_active_attr(Object *ob, SculptAttrRef *attr)
attr->was_set = true;
}
static void sculpt_save_active_vcol_attr(Object *ob, SculptAttrRef *attr)
{
Mesh *me = BKE_object_get_original_mesh(ob);
CustomDataLayer *cl;
if (ob && me && (cl = BKE_id_attributes_active_color_get((ID *)me))) {
attr->domain = BKE_id_attribute_domain((ID *)me, cl);
BLI_strncpy(attr->name, cl->name, sizeof(attr->name));
attr->type = cl->type;
}
else {
attr->domain = NO_ACTIVE_LAYER;
attr->name[0] = 0;
}
attr->was_set = true;
}
void sculpt_undo_push_begin_ex(Object *ob, const char *name, bool no_first_entry_check)
{
UndoStack *ustack = ED_undo_stack_get();
@ -2244,6 +2265,10 @@ void sculpt_undo_push_begin_ex(Object *ob, const char *name, bool no_first_entry
sculpt_save_active_attr(ob, &us->active_attr_start);
}
if (!us->active_vcol_attr_start.was_set) {
sculpt_save_active_vcol_attr(ob, &us->active_vcol_attr_start);
}
SculptSession *ss = ob->sculpt;
/*when pusing an undo node after
@ -2306,6 +2331,7 @@ void SCULPT_undo_push_end_ex(struct Object *ob, const bool use_nested_undo)
ustack, BKE_UNDOSYS_TYPE_SCULPT);
sculpt_save_active_attr(ob, &us->active_attr_end);
sculpt_save_active_vcol_attr(ob, &us->active_vcol_attr_end);
}
/* -------------------------------------------------------------------- */
@ -2339,6 +2365,33 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr
}
}
static void sculpt_undo_set_active_vcol_layer(struct bContext *C, SculptAttrRef *attr)
{
Object *ob = CTX_data_active_object(C);
Mesh *me = BKE_object_get_original_mesh(ob);
if (attr->domain == NO_ACTIVE_LAYER) {
// from reading the code, it appears you cannot set
// the active layer to NULL, so don't worry about it.
// BKE_id_attributes_active_set(&me->id, NULL);
return;
}
SculptAttrRef existing;
sculpt_save_active_vcol_attr(ob, &existing);
if (!sculpt_attr_ref_equals(&existing, attr) && ob->sculpt && ob->sculpt->pbvh) {
BKE_pbvh_update_vertex_data(ob->sculpt->pbvh, PBVH_UpdateColor);
}
CustomDataLayer *cl;
cl = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
if (cl) {
BKE_id_attributes_active_color_set(&me->id, cl);
}
}
static void sculpt_undosys_step_encode_init(struct bContext *C, UndoStep *us_p)
{
SculptUndoStep *us = (SculptUndoStep *)us_p;
@ -2407,12 +2460,16 @@ static void sculpt_undosys_step_decode_undo(struct bContext *C,
BLI_assert(us_iter->step.type == us->step.type); /* Previous loop ensures this. */
sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter)->active_attr_start);
sculpt_undo_set_active_vcol_layer(C, &((SculptUndoStep *)us_iter)->active_vcol_attr_start);
sculpt_undosys_step_decode_undo_impl(C, depsgraph, us_iter);
// sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter)->active_attr_start);
if (us_iter == us) {
if (us_iter->step.prev && us_iter->step.prev->type == BKE_UNDOSYS_TYPE_SCULPT) {
sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter->step.prev)->active_attr_end);
sculpt_undo_set_active_vcol_layer(
C, &((SculptUndoStep *)us_iter->step.prev)->active_vcol_attr_end);
}
break;
}
@ -2434,10 +2491,12 @@ static void sculpt_undosys_step_decode_redo(struct bContext *C,
}
while (us_iter && (us_iter->step.is_applied == false)) {
sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter)->active_attr_start);
sculpt_undo_set_active_vcol_layer(C, &((SculptUndoStep *)us_iter)->active_vcol_attr_start);
sculpt_undosys_step_decode_redo_impl(C, depsgraph, us_iter);
if (us_iter == us) {
sculpt_undo_set_active_layer(C, &((SculptUndoStep *)us_iter)->active_attr_end);
sculpt_undo_set_active_vcol_layer(C, &((SculptUndoStep *)us_iter)->active_vcol_attr_end);
break;
}
us_iter = (SculptUndoStep *)us_iter->step.next;

View File

@ -67,6 +67,7 @@ typedef struct PBVHGPUBuildArgs {
int face_sets_color_default;
bool flat_vcol;
short mat_nr, active_vcol_type, active_vcol_domain;
struct CustomDataLayer *active_vcol_layer;
} PBVHGPUBuildArgs;
/* Build must be called once before using the other functions, used every time
@ -114,7 +115,9 @@ void GPU_pbvh_update_attribute_names(
bool need_full_render,
bool fast_mode,
int active_vcol_type,
int active_vcol_domain); // fast mode renders without vcol, uv, facesets, even mask, etc
int active_vcol_domain,
struct CustomDataLayer
*active_vcol_layer); // fast mode renders without vcol, uv, facesets, even mask, etc
void GPU_pbvh_bmesh_buffers_update(PBVHGPUBuildArgs *args);

View File

@ -365,7 +365,7 @@ static void free_cd_layers(CDAttrLayers *cdattr)
void gpu_pbvh_init()
{
GPU_pbvh_update_attribute_names(NULL, NULL, false, false, -1, -1);
GPU_pbvh_update_attribute_names(NULL, NULL, false, false, -1, -1, NULL);
}
void gpu_pbvh_exit()
@ -1322,14 +1322,15 @@ static int gpu_pbvh_bmesh_make_vcol_offs(CustomData *vdata,
ColorRef r_cd_vcols[MAX_GPU_MCOL],
bool active_only,
int active_type,
int active_domain)
int active_domain,
CustomDataLayer *active_vcol_layer)
{
if (active_only) {
CustomData *cdata = active_domain == ATTR_DOMAIN_POINT ? vdata : ldata;
int idx = active_type != -1 ? CustomData_get_active_layer_index(cdata, active_type) : -1;
int idx = active_vcol_layer ? active_vcol_layer - cdata->layers : -1;
if (idx >= 0) {
if (idx >= 0 && idx < cdata->totlayer) {
r_cd_vcols[0].cd_offset = cdata->layers[idx].offset;
r_cd_vcols[0].domain = active_domain;
r_cd_vcols[0].type = active_type;
@ -1395,7 +1396,8 @@ ATTR_NO_OPT void GPU_pbvh_update_attribute_names(CustomData *vdata,
bool need_full_render,
bool fast_mode,
int active_vcol_type,
int active_vcol_domain)
int active_vcol_domain,
CustomDataLayer *active_vcol_layer)
{
const bool active_only = !need_full_render;
@ -1462,26 +1464,31 @@ ATTR_NO_OPT void GPU_pbvh_update_attribute_names(CustomData *vdata,
#if !defined(NEW_ATTR_SYSTEM) && !defined(GPU_PERF_TEST)
if (active_vcol_type != -1) {
const int act = CustomData_get_active_layer_index(
active_vcol_domain == ATTR_DOMAIN_POINT ? vdata : ldata, active_vcol_type);
int ci = 0;
ColorRef vcol_layers[MAX_GPU_MCOL];
int totlayer = gpu_pbvh_bmesh_make_vcol_offs(
vdata, ldata, vcol_layers, active_only, active_vcol_type, active_vcol_domain);
int totlayer = gpu_pbvh_bmesh_make_vcol_offs(vdata,
ldata,
vcol_layers,
active_only,
active_vcol_type,
active_vcol_domain,
active_vcol_layer);
for (int i = 0; i < totlayer; i++) {
ColorRef *ref = vcol_layers + i;
CustomDataLayer *cl = vdata->layers + ref->layer_idx;
CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
CustomDataLayer *cl = cdata->layers + ref->layer_idx;
if (g_vbo_id.totcol < MAX_GPU_MCOL) {
g_vbo_id.col[ci++] = GPU_vertformat_attr_add(
&g_vbo_id.format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
g_vbo_id.totcol++;
DRW_make_cdlayer_attr_aliases(&g_vbo_id.format, "c", vdata, cl);
DRW_make_cdlayer_attr_aliases(&g_vbo_id.format, "c", cdata, cl);
if ((int)ref->layer_idx == act && (int)ref->domain == active_vcol_domain) {
if (cl == active_vcol_layer) {
GPU_vertformat_alias_add(&g_vbo_id.format, "ac");
}
}
@ -1579,7 +1586,8 @@ static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers,
int face_sets_color_default,
short mat_nr,
int active_vcol_type,
int active_vcol_domain)
int active_vcol_domain,
CustomDataLayer *active_vcol_layer)
{
bool active_vcol_only = g_vbo_id.active_vcol_only;
@ -1592,8 +1600,13 @@ static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers,
ColorRef cd_vcols[MAX_GPU_MCOL];
const int cd_vcol_count = gpu_pbvh_bmesh_make_vcol_offs(
&bm->vdata, &bm->ldata, cd_vcols, active_vcol_only, active_vcol_type, active_vcol_domain);
const int cd_vcol_count = gpu_pbvh_bmesh_make_vcol_offs(&bm->vdata,
&bm->ldata,
cd_vcols,
active_vcol_only,
active_vcol_type,
active_vcol_domain,
active_vcol_layer);
/* Count visible triangles */
tottri = gpu_bmesh_face_visible_count(tribuf, mat_nr) * 6;
@ -1764,7 +1777,8 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers,
bool flat_vcol,
short mat_nr,
int active_vcol_type,
int active_vcol_domain)
int active_vcol_domain,
CustomDataLayer *active_vcol_layer)
{
bool active_vcol_only = g_vbo_id.active_vcol_only;
@ -1785,8 +1799,13 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers,
ColorRef cd_vcols[MAX_GPU_MCOL];
int cd_vcol_count = gpu_pbvh_bmesh_make_vcol_offs(
&bm->vdata, &bm->ldata, cd_vcols, active_vcol_only, active_vcol_type, active_vcol_domain);
int cd_vcol_count = gpu_pbvh_bmesh_make_vcol_offs(&bm->vdata,
&bm->ldata,
cd_vcols,
active_vcol_only,
active_vcol_type,
active_vcol_domain,
active_vcol_layer);
/* Count visible triangles */
tottri = gpu_bmesh_face_visible_count(tribuf, mat_nr);
@ -1936,7 +1955,8 @@ ATTR_NO_OPT void GPU_pbvh_bmesh_buffers_update(PBVHGPUBuildArgs *args)
args->face_sets_color_default,
mat_nr,
args->active_vcol_type,
args->active_vcol_domain);
args->active_vcol_domain,
args->active_vcol_layer);
return;
}
@ -1959,7 +1979,8 @@ ATTR_NO_OPT void GPU_pbvh_bmesh_buffers_update(PBVHGPUBuildArgs *args)
cd_vcols,
active_vcol_only,
args->active_vcol_type,
args->active_vcol_domain);
args->active_vcol_domain,
args->active_vcol_layer);
/* Count visible triangles */
if (buffers->smooth) {
@ -1976,7 +1997,8 @@ ATTR_NO_OPT void GPU_pbvh_bmesh_buffers_update(PBVHGPUBuildArgs *args)
args->flat_vcol,
mat_nr,
args->active_vcol_type,
args->active_vcol_domain);
args->active_vcol_domain,
args->active_vcol_layer);
return;
}

View File

@ -197,6 +197,11 @@ typedef struct Mesh {
int attributes_active_index;
int vertex_group_active_index;
/* note that this can be inside of either vdata or ldata,
and can reference a layer of type CD_PROP_COLOR or
CD_MLOOPCOL */
int active_color_index;
/* the last selected vertex/edge/face are used for the active face however
* this means the active face must always be selected, this is to keep track
* of the last selected face and is similar to the old active face flag where
@ -228,15 +233,14 @@ typedef struct Mesh {
* consistently ensure that this symmetry is maintained. */
char symmetry;
char _pad1[2];
char _pad1[6];
int face_sets_color_seed;
/* Stores the initial Face Set to be rendered white. This way the overlay can be enabled by
* default and Face Sets can be used without affecting the color of the mesh. */
int face_sets_color_default;
void *_pad2;
Mesh_Runtime runtime;
void *_pad2;
} Mesh;
/* deprecated by MTFace, only here for file reading */

View File

@ -412,6 +412,64 @@ static void rna_AttributeGroup_update_active(Main *bmain, Scene *scene, PointerR
rna_Attribute_update_data(bmain, scene, ptr);
}
static PointerRNA rna_AttributeGroup_active_color_get(PointerRNA *ptr)
{
ID *id = ptr->owner_id;
CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
PointerRNA attribute_ptr;
RNA_pointer_create(id, &RNA_Attribute, layer, &attribute_ptr);
return attribute_ptr;
}
static void rna_AttributeGroup_active_color_set(PointerRNA *ptr,
PointerRNA attribute_ptr,
ReportList *UNUSED(reports))
{
ID *id = ptr->owner_id;
CustomDataLayer *layer = attribute_ptr.data;
BKE_id_attributes_active_color_set(id, layer);
}
static int rna_AttributeGroup_active_color_index_get(PointerRNA *ptr)
{
int *active = BKE_id_attributes_active_color_index_p(ptr->owner_id);
return active ? *active : -1;
}
static void rna_AttributeGroup_active_color_index_set(PointerRNA *ptr, int value)
{
ID *id = ptr->owner_id;
int *active = BKE_id_attributes_active_color_index_p(ptr->owner_id);
if (active) {
CustomDataLayer *layer = BKE_id_attribute_from_index(id, value);
if (layer) {
BKE_id_attributes_active_color_set(id, layer);
}
else {
fprintf(stderr, "%s: error setting active color index to %d\n", __func__, value);
}
}
}
static void rna_AttributeGroup_active_color_index_range(
PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
{
*min = 0;
*max = BKE_id_attributes_length(ptr->owner_id, CD_MASK_PROP_ALL);
*softmin = *min;
*softmax = *max;
}
static void rna_AttributeGroup_update_active_color(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_Attribute_update_data(bmain, scene, ptr);
}
#else
static void rna_def_attribute_float(BlenderRNA *brna)
@ -772,6 +830,25 @@ static void rna_def_attribute_group(BlenderRNA *brna)
"rna_AttributeGroup_active_index_set",
"rna_AttributeGroup_active_index_range");
RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active");
prop = RNA_def_property(srna, "active_color", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Attribute");
RNA_def_property_pointer_funcs(prop,
"rna_AttributeGroup_active_color_get",
"rna_AttributeGroup_active_color_set",
NULL,
NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
RNA_def_property_ui_text(prop, "Active Color", "Active color attribute");
RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active_color");
prop = RNA_def_property(srna, "active_color_index", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_int_funcs(prop,
"rna_AttributeGroup_active_color_index_get",
"rna_AttributeGroup_active_color_index_set",
"rna_AttributeGroup_active_color_index_range");
RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active_color");
}
void rna_def_attributes_common(StructRNA *srna)