Mesh: Move sculpt mask to a generic attribute

Store paint masks as generic float attributes, with the name
`".sculpt_mask"`. This is similar to 060a534141, which made
the same change for face sets. The benefits are general
consistency, nicer code, and more support in newer areas
that deal with attributes like geometry nodes.

The RNA API is replaced with one created in Python. The new
API only presents a single layer as an attribute class, so it
should be simpler to use in general:
- Before: `object.data.vertex_paint_masks[0].data[0].value`
- After: `object.data.vertex_paint_mask.data[0].value`

Pull Request: https://projects.blender.org/blender/blender/pulls/115119
This commit is contained in:
Hans Goudey
2023-11-20 17:42:01 +01:00
committed by Hans Goudey
parent b3d4fc80fd
commit f2bcd73bd2
27 changed files with 168 additions and 207 deletions

View File

@@ -669,6 +669,19 @@ class Mesh(bpy_types.ID):
def edge_creases_remove(self):
_name_convention_attribute_remove(self.attributes, "crease_edge")
@property
def vertex_paint_mask(self):
"""
Mask values for sculpting and painting, corresponding to the ".sculpt_mask" attribute.
"""
return _name_convention_attribute_get(self.attributes, ".sculpt_mask", 'POINT', 'FLOAT')
def vertex_paint_mask_ensure(self):
return _name_convention_attribute_ensure(self.attributes, ".sculpt_mask", 'POINT', 'FLOAT')
def vertex_paint_mask_remove(self):
_name_convention_attribute_remove(self.attributes, ".sculpt_mask")
def shade_flat(self):
"""
Render and display faces uniform, using face normals,

View File

@@ -17,6 +17,11 @@ struct Main;
struct Mesh;
struct MFace;
namespace blender::bke {
void mesh_sculpt_mask_to_legacy(MutableSpan<CustomDataLayer> vert_layers);
void mesh_sculpt_mask_to_generic(Mesh &mesh);
} // namespace blender::bke
void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh);
/**

View File

@@ -769,27 +769,6 @@ static void layerFree_bmesh_elem_py_ptr(void *data, const int count, const int s
/** \} */
/* -------------------------------------------------------------------- */
/** \name Callbacks for (`float`, #CD_PAINT_MASK)
* \{ */
static void layerInterp_paint_mask(const void **sources,
const float *weights,
const float * /*sub_weights*/,
int count,
void *dest)
{
float mask = 0.0f;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
const float *src = static_cast<const float *>(sources[i]);
mask += (*src) * interp_weight;
}
*(float *)dest = mask;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Callbacks for (#GridPaintMask, #CD_GRID_PAINT_MASK)
* \{ */
@@ -1821,8 +1800,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr,
nullptr},
/* 34: CD_PAINT_MASK */
{sizeof(float), "", 0, nullptr, nullptr, nullptr, layerInterp_paint_mask, nullptr, nullptr},
/* 34: CD_PAINT_MASK */ /* DEPRECATED */
{sizeof(float), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask),
"GridPaintMask",
@@ -2038,8 +2017,7 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
/*lmask*/ CD_MASK_PROP_INT32,
};
const CustomData_MeshMasks CD_MASK_MESH = {
/*vmask*/ (CD_MASK_PROP_FLOAT3 | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL),
/*vmask*/ (CD_MASK_PROP_FLOAT3 | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PROP_ALL),
/*emask*/
(CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/*fmask*/ 0,
@@ -2050,7 +2028,7 @@ const CustomData_MeshMasks CD_MASK_MESH = {
};
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
/*vmask*/ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL),
CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL),
/*emask*/
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/*fmask*/ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
@@ -2062,7 +2040,7 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
};
const CustomData_MeshMasks CD_MASK_BMESH = {
/*vmask*/ (CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL),
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL),
/*emask*/ (CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/*fmask*/ 0,
/*pmask*/
@@ -2073,7 +2051,7 @@ const CustomData_MeshMasks CD_MASK_BMESH = {
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
/*vmask*/ (CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT |
CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL),
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL),
/*emask*/
(CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/*fmask*/

View File

@@ -244,6 +244,7 @@ static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
{
using namespace blender;
using namespace blender::bke;
Mesh *mesh = reinterpret_cast<Mesh *>(id);
const bool is_undo = BLO_write_is_undo(writer);
@@ -277,6 +278,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
CustomData_blend_write_prepare(mesh->edge_data, edge_layers, {});
CustomData_blend_write_prepare(mesh->loop_data, loop_layers, {});
CustomData_blend_write_prepare(mesh->face_data, face_layers, {});
mesh_sculpt_mask_to_legacy(vert_layers);
}
mesh->runtime = nullptr;

View File

@@ -58,7 +58,6 @@ void mesh_flip_faces(Mesh &mesh, const IndexMask &selection)
flip_custom_data_type<float4x4>(faces, mesh.loop_data, selection, CD_TANGENT);
flip_custom_data_type<float4>(faces, mesh.loop_data, selection, CD_MLOOPTANGENT);
flip_custom_data_type<short2>(faces, mesh.loop_data, selection, CD_CUSTOMLOOPNORMAL);
flip_custom_data_type<float>(faces, mesh.loop_data, selection, CD_PAINT_MASK);
flip_custom_data_type<GridPaintMask>(faces, mesh.loop_data, selection, CD_GRID_PAINT_MASK);
flip_custom_data_type<OrigSpaceLoop>(faces, mesh.loop_data, selection, CD_ORIGSPACE_MLOOP);
flip_custom_data_type<MDisps>(faces, mesh.loop_data, selection, CD_MDISPS);

View File

@@ -2298,4 +2298,57 @@ void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain)
}
}
namespace blender::bke {
void mesh_sculpt_mask_to_legacy(MutableSpan<CustomDataLayer> vert_layers)
{
bool changed = false;
for (CustomDataLayer &layer : vert_layers) {
if (StringRef(layer.name) == ".sculpt_mask") {
layer.type = CD_PAINT_MASK;
layer.name[0] = '\0';
changed = true;
break;
}
}
if (!changed) {
return;
}
/* #CustomData expects the layers to be sorted in increasing order based on type. */
std::stable_sort(
vert_layers.begin(),
vert_layers.end(),
[](const CustomDataLayer &a, const CustomDataLayer &b) { return a.type < b.type; });
}
void mesh_sculpt_mask_to_generic(Mesh &mesh)
{
if (mesh.attributes().contains(".sculpt_mask")) {
return;
}
void *data = nullptr;
const ImplicitSharingInfo *sharing_info = nullptr;
for (const int i : IndexRange(mesh.vert_data.totlayer)) {
CustomDataLayer &layer = mesh.vert_data.layers[i];
if (layer.type == CD_PAINT_MASK) {
data = layer.data;
sharing_info = layer.sharing_info;
layer.data = nullptr;
layer.sharing_info = nullptr;
CustomData_free_layer(&mesh.vert_data, CD_PAINT_MASK, mesh.totvert, i);
break;
}
}
if (data != nullptr) {
CustomData_add_layer_named_with_data(
&mesh.vert_data, CD_PROP_FLOAT, data, mesh.totvert, ".sculpt_mask", sharing_info);
}
if (sharing_info != nullptr) {
sharing_info->remove_user_and_delete_if_last();
}
}
//
} // namespace blender::bke
/** \} */

View File

@@ -282,19 +282,20 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source)
BVHTreeFromMesh bvhtree = {nullptr};
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
const Span<float3> target_positions = target->vert_positions();
const float *source_mask = (const float *)CustomData_get_layer(&source->vert_data,
CD_PAINT_MASK);
const float *source_mask = (const float *)CustomData_get_layer_named(
&source->vert_data, CD_PROP_FLOAT, ".sculpt_mask");
if (source_mask == nullptr) {
return;
}
float *target_mask;
if (CustomData_has_layer(&target->vert_data, CD_PAINT_MASK)) {
target_mask = (float *)CustomData_get_layer(&target->vert_data, CD_PAINT_MASK);
if (CustomData_has_layer_named(&target->vert_data, CD_PROP_FLOAT, ".sculpt_mask")) {
target_mask = (float *)CustomData_get_layer_named(
&target->vert_data, CD_PROP_FLOAT, ".sculpt_mask");
}
else {
target_mask = (float *)CustomData_add_layer(
&target->vert_data, CD_PAINT_MASK, CD_CONSTRUCT, target->totvert);
target_mask = (float *)CustomData_add_layer_named(
&target->vert_data, CD_PROP_FLOAT, CD_CONSTRUCT, target->totvert, ".sculpt_mask");
}
blender::threading::parallel_for(IndexRange(target->totvert), 4096, [&](const IndexRange range) {

View File

@@ -1708,7 +1708,8 @@ static void sculpt_update_object(
ss->multires.active = false;
ss->multires.modifier = nullptr;
ss->multires.level = 0;
ss->vmask = static_cast<const float *>(CustomData_get_layer(&me->vert_data, CD_PAINT_MASK));
ss->vmask = static_cast<const float *>(
CustomData_get_layer_named(&me->vert_data, CD_PROP_FLOAT, ".sculpt_mask"));
CustomDataLayer *layer;
eAttrDomain domain;
@@ -2010,7 +2011,7 @@ int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
int ret = 0;
const float *paint_mask = static_cast<const float *>(
CustomData_get_layer(&me->vert_data, CD_PAINT_MASK));
CustomData_get_layer_named(&me->vert_data, CD_PROP_FLOAT, ".sculpt_mask"));
/* if multires is active, create a grid paint mask layer if there
* isn't one already */
@@ -2068,7 +2069,8 @@ int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
/* Create vertex paint mask layer if there isn't one already. */
if (!paint_mask) {
CustomData_add_layer(&me->vert_data, CD_PAINT_MASK, CD_SET_DEFAULT, me->totvert);
CustomData_add_layer_named(
&me->vert_data, CD_PROP_FLOAT, CD_SET_DEFAULT, me->totvert, ".sculpt_mask");
/* The evaluated mesh must be updated to contain the new data. */
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
ret |= SCULPT_MASK_LAYER_CALC_VERT;

View File

@@ -722,7 +722,8 @@ static void pbvh_draw_args_init(const Mesh &mesh, PBVH *pbvh, PBVH_GPU_Args *arg
args->loop_data = &args->bm->ldata;
args->face_data = &args->bm->pdata;
args->bm_faces = &node->bm_faces;
args->cd_mask_layer = CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK);
args->cd_mask_layer = CustomData_get_offset_named(
&pbvh->header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
break;
}
@@ -3141,7 +3142,8 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->bm_other_verts = node->bm_other_verts.begin();
vi->bm_other_verts_end = node->bm_other_verts.end();
vi->bm_vdata = &pbvh->header.bm->vdata;
vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
vi->cd_vert_mask_offset = CustomData_get_offset_named(
vi->bm_vdata, CD_PROP_FLOAT, ".sculpt_mask");
}
vi->gh = nullptr;
@@ -3154,7 +3156,8 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->vert_normals = pbvh->vert_normals;
vi->hide_vert = pbvh->hide_vert;
vi->vmask = static_cast<const float *>(CustomData_get_layer(pbvh->vert_data, CD_PAINT_MASK));
vi->vmask = static_cast<const float *>(
CustomData_get_layer_named(pbvh->vert_data, CD_PROP_FLOAT, ".sculpt_mask"));
}
}
@@ -3164,10 +3167,12 @@ bool pbvh_has_mask(const PBVH *pbvh)
case PBVH_GRIDS:
return (pbvh->gridkey.has_mask != 0);
case PBVH_FACES:
return (pbvh->vert_data && CustomData_get_layer(pbvh->vert_data, CD_PAINT_MASK));
return (pbvh->vert_data &&
CustomData_has_layer_named(pbvh->vert_data, CD_PROP_FLOAT, ".sculpt_mask"));
case PBVH_BMESH:
return (pbvh->header.bm &&
(CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK) != -1));
(CustomData_get_offset_named(
&pbvh->header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask") != -1));
}
return false;

View File

@@ -2223,7 +2223,8 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
const bool use_frontface,
const bool use_projected)
{
const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&pbvh->header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
const int cd_face_node_offset = pbvh->cd_face_node_offset;

View File

@@ -2500,5 +2500,9 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
version_geometry_nodes_use_rotation_socket(*ntree);
}
}
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
blender::bke::mesh_sculpt_mask_to_generic(*mesh);
}
}
}

View File

@@ -228,7 +228,8 @@ static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
@@ -273,7 +274,8 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
@@ -316,7 +318,8 @@ static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
@@ -870,7 +873,8 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
void BM_log_all_added(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
BMIter bm_iter;
BMVert *v;
BMFace *f;
@@ -897,7 +901,8 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
BMIter bm_iter;
BMVert *v;
BMFace *f;

View File

@@ -705,7 +705,7 @@ struct PBVHBatches {
}
else if (vbo.type == CD_PBVH_MASK_TYPE) {
if (const float *mask = static_cast<const float *>(
CustomData_get_layer(args.vert_data, CD_PAINT_MASK)))
CustomData_get_layer_named(args.vert_data, CD_PROP_FLOAT, ".sculpt_mask")))
{
const Span<int> corner_verts = args.corner_verts;
const Span<MLoopTri> looptris = args.mlooptri;

View File

@@ -43,7 +43,8 @@ static void extract_sculpt_data_init(const MeshRenderData &mr,
CustomData *cd_vdata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->vdata : &mr.me->vert_data;
CustomData *cd_pdata = (mr.extract_type == MR_EXTRACT_BMESH) ? &mr.bm->pdata : &mr.me->face_data;
const float *cd_mask = (const float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
const float *cd_mask = (const float *)CustomData_get_layer_named(
cd_vdata, CD_PROP_FLOAT, ".sculpt_mask");
const int *cd_face_set = (const int *)CustomData_get_layer_named(
cd_pdata, CD_PROP_INT32, ".sculpt_face_set");
@@ -58,7 +59,7 @@ static void extract_sculpt_data_init(const MeshRenderData &mr,
gpuSculptData *vbo_data = (gpuSculptData *)GPU_vertbuf_get_data(vbo);
if (mr.extract_type == MR_EXTRACT_BMESH) {
int cd_mask_ofs = CustomData_get_offset(cd_vdata, CD_PAINT_MASK);
int cd_mask_ofs = CustomData_get_offset_named(cd_vdata, CD_PROP_FLOAT, ".sculpt_mask");
int cd_face_set_ofs = CustomData_get_offset_named(cd_pdata, CD_PROP_INT32, ".sculpt_face_set");
BMIter f_iter;
BMFace *efa;
@@ -124,7 +125,8 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
/* First, interpolate mask if available. */
GPUVertBuf *mask_vbo = nullptr;
GPUVertBuf *subdiv_mask_vbo = nullptr;
const float *cd_mask = (const float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
const float *cd_mask = (const float *)CustomData_get_layer_named(
cd_vdata, CD_PROP_FLOAT, ".sculpt_mask");
const OffsetIndices coarse_faces = coarse_mesh->faces();
const Span<int> coarse_corner_verts = coarse_mesh->corner_verts();

View File

@@ -211,7 +211,7 @@ static int geometry_extract_apply(bContext *C,
CustomData_free_layer_named(&new_ob_mesh->face_data, ".sculpt_face_set", new_ob_mesh->faces_num);
/* Remove the mask from the new object so it can be sculpted directly after extracting. */
CustomData_free_layers(&new_ob_mesh->vert_data, CD_PAINT_MASK, new_ob_mesh->totvert);
CustomData_free_layer_named(&new_ob_mesh->vert_data, ".sculpt_mask", new_ob_mesh->totvert);
BKE_mesh_copy_parameters_for_eval(new_ob_mesh, mesh);
@@ -243,7 +243,8 @@ static void geometry_extract_tag_masked_faces(BMesh *bm, GeometryExtractParams *
const float threshold = params->mask_threshold;
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
BMFace *f;
BMIter iter;
@@ -410,7 +411,8 @@ static void slice_paint_mask(BMesh *bm, bool invert, bool fill_holes, float mask
BMIter face_iter;
/* Delete all masked faces */
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_vert_mask_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
BLI_assert(cd_vert_mask_offset != -1);
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
@@ -507,7 +509,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
BM_mesh_free(bm);
/* Remove the mask from the new object so it can be sculpted directly after slicing. */
CustomData_free_layers(&new_ob_mesh->vert_data, CD_PAINT_MASK, new_ob_mesh->totvert);
CustomData_free_layer_named(&new_ob_mesh->vert_data, ".sculpt_mask", new_ob_mesh->totvert);
Mesh *new_mesh = static_cast<Mesh *>(new_ob->data);
BKE_mesh_nomain_to_mesh(new_ob_mesh, new_mesh, new_ob);

View File

@@ -597,7 +597,7 @@ static bool mesh_customdata_mask_clear_poll(bContext *C)
if (!ID_IS_LINKED(me) && !ID_IS_OVERRIDE_LIBRARY(me)) {
CustomData *data = mesh_customdata_get_type(me, BM_VERT, nullptr);
if (CustomData_has_layer(data, CD_PAINT_MASK)) {
if (CustomData_has_layer_named(data, CD_PROP_FLOAT, ".sculpt_mask")) {
return true;
}
data = mesh_customdata_get_type(me, BM_LOOP, nullptr);
@@ -608,12 +608,14 @@ static bool mesh_customdata_mask_clear_poll(bContext *C)
}
return false;
}
static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator * /*op*/)
static int mesh_customdata_mask_clear_exec(bContext *C, wmOperator *op)
{
int ret_a = mesh_customdata_clear_exec__internal(C, BM_VERT, CD_PAINT_MASK);
Object *object = ED_object_context(C);
Mesh *mesh = static_cast<Mesh *>(object->data);
const bool ret_a = BKE_id_attribute_remove(&mesh->id, ".sculpt_mask", op->reports);
int ret_b = mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_GRID_PAINT_MASK);
if (ret_a == OPERATOR_FINISHED || ret_b == OPERATOR_FINISHED) {
if (ret_a || ret_b == OPERATOR_FINISHED) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;

View File

@@ -79,7 +79,8 @@ static void partialvis_update_mesh(Object *ob,
bool any_changed = false, any_visible = false;
const blender::Span<int> verts = BKE_pbvh_node_get_vert_indices(node);
paint_mask = static_cast<const float *>(CustomData_get_layer(&me->vert_data, CD_PAINT_MASK));
paint_mask = static_cast<const float *>(
CustomData_get_layer_named(&me->vert_data, CD_PROP_FLOAT, ".sculpt_mask"));
bool *hide_vert = static_cast<bool *>(CustomData_get_layer_named_for_write(
&me->vert_data, CD_PROP_BOOL, ".hide_vert", me->totvert));
@@ -205,12 +206,12 @@ static void partialvis_update_bmesh_verts(BMesh *bm,
bool *any_changed,
bool *any_visible)
{
const int mask_offset = CustomData_get_offset_named(&bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
for (BMVert *v : verts) {
float *vmask = static_cast<float *>(
CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK));
const float vmask = BM_ELEM_CD_GET_FLOAT(v, mask_offset);
/* Hide vertex if in the hide volume. */
if (is_effected(area, planes, v->co, *vmask)) {
if (is_effected(area, planes, v->co, vmask)) {
if (action == PARTIALVIS_HIDE) {
BM_elem_flag_enable(v, BM_ELEM_HIDDEN);
}

View File

@@ -119,12 +119,13 @@ SculptMaskWriteInfo SCULPT_mask_get_for_write(SculptSession *ss)
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
Mesh *mesh = BKE_pbvh_get_mesh(ss->pbvh);
info.layer = static_cast<float *>(
CustomData_get_layer_for_write(&mesh->vert_data, CD_PAINT_MASK, mesh->totvert));
info.layer = static_cast<float *>(CustomData_get_layer_named_for_write(
&mesh->vert_data, CD_PROP_FLOAT, ".sculpt_mask", mesh->totvert));
break;
}
case PBVH_BMESH:
info.bm_offset = CustomData_get_offset(&BKE_pbvh_get_bmesh(ss->pbvh)->vdata, CD_PAINT_MASK);
info.bm_offset = CustomData_get_offset_named(
&BKE_pbvh_get_bmesh(ss->pbvh)->vdata, CD_PROP_FLOAT, ".sculpt_mask");
break;
case PBVH_GRIDS:
break;
@@ -298,7 +299,7 @@ float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex)
return ss->vmask ? ss->vmask[vertex.i] : 0.0f;
case PBVH_BMESH: {
BMVert *v;
int cd_mask = CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK);
int cd_mask = CustomData_get_offset_named(&ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
v = (BMVert *)vertex.i;
return cd_mask != -1 ? BM_ELEM_CD_GET_FLOAT(v, cd_mask) : 0.0f;

View File

@@ -101,7 +101,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Object
BM_mesh_bm_from_me(ss->bm, me, &convert_params);
SCULPT_dynamic_topology_triangulate(ss->bm);
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
/* Make sure the data for existing faces are initialized. */
if (me->faces_num != ss->bm->totface) {
@@ -293,31 +293,20 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
return OPERATOR_INTERFACE;
}
static bool dyntopo_supports_layer(const CustomDataLayer &layer, const int elem_num)
static bool dyntopo_supports_layer(const CustomDataLayer &layer)
{
if (CD_TYPE_AS_MASK(layer.type) & CD_MASK_PROP_ALL) {
if (STREQ(layer.name, ".sculpt_face_set")) {
/* Check if only one face set exists. */
const blender::Span<int> face_sets(static_cast<const int *>(layer.data), elem_num);
for (const int i : face_sets.index_range()) {
if (face_sets[i] != face_sets.first()) {
return false;
}
}
return true;
}
/* Some data is stored as generic attributes on #Mesh but in flags or fields on #BMesh. */
return BM_attribute_stored_in_bmesh_builtin(layer.name);
}
/* Some layers just encode #Mesh topology or are handled as special cases for dyntopo. */
return ELEM(layer.type, CD_PAINT_MASK, CD_ORIGINDEX);
return ELEM(layer.type, CD_ORIGINDEX);
}
static bool dyntopo_supports_customdata_layers(const blender::Span<CustomDataLayer> layers,
const int elem_num)
static bool dyntopo_supports_customdata_layers(const blender::Span<CustomDataLayer> layers)
{
return std::all_of(layers.begin(), layers.end(), [&](const CustomDataLayer &layer) {
return dyntopo_supports_layer(layer, elem_num);
return dyntopo_supports_layer(layer);
});
}
@@ -331,24 +320,16 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
BLI_assert(ss->bm == nullptr);
UNUSED_VARS_NDEBUG(ss);
if (!dyntopo_supports_customdata_layers({me->vert_data.layers, me->vert_data.totlayer},
me->totvert))
{
if (!dyntopo_supports_customdata_layers({me->vert_data.layers, me->vert_data.totlayer})) {
flag |= DYNTOPO_WARN_VDATA;
}
if (!dyntopo_supports_customdata_layers({me->edge_data.layers, me->edge_data.totlayer},
me->totedge))
{
if (!dyntopo_supports_customdata_layers({me->edge_data.layers, me->edge_data.totlayer})) {
flag |= DYNTOPO_WARN_EDATA;
}
if (!dyntopo_supports_customdata_layers({me->face_data.layers, me->face_data.totlayer},
me->faces_num))
{
if (!dyntopo_supports_customdata_layers({me->face_data.layers, me->face_data.totlayer})) {
flag |= DYNTOPO_WARN_LDATA;
}
if (!dyntopo_supports_customdata_layers({me->loop_data.layers, me->loop_data.totlayer},
me->totloop))
{
if (!dyntopo_supports_customdata_layers({me->loop_data.layers, me->loop_data.totlayer})) {
flag |= DYNTOPO_WARN_LDATA;
}

View File

@@ -1201,8 +1201,8 @@ static void write_mask_data(SculptSession *ss, const Span<float> mask)
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
Mesh *mesh = BKE_pbvh_get_mesh(ss->pbvh);
float *layer = static_cast<float *>(
CustomData_get_layer_for_write(&mesh->vert_data, CD_PAINT_MASK, mesh->totvert));
float *layer = static_cast<float *>(CustomData_get_layer_named_for_write(
&mesh->vert_data, CD_PROP_FLOAT, ".sculpt_mask", mesh->totvert));
for (PBVHNode *node : nodes) {
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
@@ -1214,8 +1214,8 @@ static void write_mask_data(SculptSession *ss, const Span<float> mask)
break;
}
case PBVH_BMESH: {
const int offset = CustomData_get_offset(&BKE_pbvh_get_bmesh(ss->pbvh)->vdata,
CD_PAINT_MASK);
const int offset = CustomData_get_offset_named(
&BKE_pbvh_get_bmesh(ss->pbvh)->vdata, CD_PROP_FLOAT, ".sculpt_mask");
for (PBVHNode *node : nodes) {
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {

View File

@@ -1312,7 +1312,7 @@ static int sculpt_reveal_all_exec(bContext *C, wmOperator *op)
BMIter iter;
BMFace *f;
BMVert *v;
const int cd_mask = CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK);
const int cd_mask = CustomData_get_offset_named(&ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
BM_log_vert_before_modified(ss->bm_log, v, cd_mask);

View File

@@ -567,11 +567,11 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode, bool *m
if (unode->maxvert) {
/* Regular mesh restore. */
float *vmask = static_cast<float *>(
CustomData_get_layer_for_write(&mesh->vert_data, CD_PAINT_MASK, mesh->totvert));
float *vmask = static_cast<float *>(CustomData_get_layer_named_for_write(
&mesh->vert_data, CD_PROP_FLOAT, ".sculpt_mask", mesh->totvert));
if (!vmask) {
vmask = static_cast<float *>(
CustomData_add_layer(&mesh->vert_data, CD_PAINT_MASK, CD_SET_DEFAULT, mesh->totvert));
vmask = static_cast<float *>(CustomData_add_layer_named(
&mesh->vert_data, CD_PROP_FLOAT, CD_SET_DEFAULT, mesh->totvert, ".sculpt_mask"));
}
ss->vmask = vmask;
@@ -671,7 +671,7 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
bmesh_create_params.use_toolflags = false;
ss->bm = BM_mesh_create(&bm_mesh_allocsize_default, &bmesh_create_params);
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;

View File

@@ -2498,10 +2498,6 @@ void ED_view3d_datamask(const Scene *scene,
}
break;
}
case OB_MODE_SCULPT: {
r_cddata_masks->vmask |= CD_MASK_PAINT_MASK;
break;
}
}
break;
}

View File

@@ -151,7 +151,9 @@ typedef enum eCustomDataType {
CD_PREVIEW_MLOOPCOL = 32,
CD_BM_ELEM_PYPTR = 33,
#ifdef DNA_DEPRECATED_ALLOW
CD_PAINT_MASK = 34,
#endif
CD_GRID_PAINT_MASK = 35,
CD_MVERT_SKIN = 36,
CD_FREESTYLE_EDGE = 37,
@@ -205,7 +207,6 @@ typedef enum eCustomDataType {
#define CD_MASK_PREVIEW_MLOOPCOL (1LL << CD_PREVIEW_MLOOPCOL)
#define CD_MASK_BM_ELEM_PYPTR (1LL << CD_BM_ELEM_PYPTR)
#define CD_MASK_PAINT_MASK (1LL << CD_PAINT_MASK)
#define CD_MASK_GRID_PAINT_MASK (1LL << CD_GRID_PAINT_MASK)
#define CD_MASK_MVERT_SKIN (1LL << CD_MVERT_SKIN)
#define CD_MASK_FREESTYLE_EDGE (1LL << CD_FREESTYLE_EDGE)

View File

@@ -1208,38 +1208,6 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr)
/* End skin vertices */
/* Paint mask */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
static char *rna_MeshPaintMaskLayer_path(const PointerRNA *ptr)
{
const CustomDataLayer *cdl = static_cast<const CustomDataLayer *>(ptr->data);
char name_esc[sizeof(cdl->name) * 2];
BLI_str_escape(name_esc, cdl->name, sizeof(name_esc));
return BLI_sprintfN("vertex_paint_masks[\"%s\"]", name_esc);
}
static char *rna_MeshPaintMask_path(const PointerRNA *ptr)
{
return rna_VertCustomData_data_path(ptr, "vertex_paint_masks", CD_PAINT_MASK);
}
static void rna_MeshPaintMaskLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
rna_iterator_array_begin(
iter, layer->data, sizeof(MFloatProperty), (me->edit_mesh) ? 0 : me->totvert, 0, nullptr);
}
static int rna_MeshPaintMaskLayer_data_length(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return (me->edit_mesh) ? 0 : me->totvert;
}
/* End paint mask */
/* poly.vertices - this is faked loop access for convenience */
static int rna_MeshPoly_vertices_get_length(const PointerRNA *ptr,
int length[RNA_MAX_ARRAY_DIMENSION])
@@ -2871,41 +2839,6 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA * /*cprop*/)
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA * /*cprop*/)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MeshPaintMaskLayer", nullptr);
RNA_def_struct_ui_text(srna, "Mesh Paint Mask Layer", "Per-vertex paint mask data");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshPaintMaskLayer_path");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshPaintMaskProperty");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_collection_funcs(prop,
"rna_MeshPaintMaskLayer_data_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_MeshPaintMaskLayer_data_length",
nullptr,
nullptr,
nullptr);
srna = RNA_def_struct(brna, "MeshPaintMaskProperty", nullptr);
RNA_def_struct_sdna(srna, "MFloatProperty");
RNA_def_struct_ui_text(srna, "Mesh Paint Mask Property", "Floating-point paint mask value");
RNA_def_struct_path_func(srna, "rna_MeshPaintMask_path");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, nullptr, "f");
RNA_def_property_ui_text(prop, "Value", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
static void rna_def_looptri_poly_value(BlenderRNA *brna)
{
StructRNA *srna = RNA_def_struct(brna, "ReadOnlyInteger", nullptr);
@@ -3186,24 +3119,6 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_skin_vertices(brna, prop);
/* End skin vertices */
/* Paint mask */
prop = RNA_def_property(srna, "vertex_paint_masks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, nullptr, "vert_data.layers", "vert_data.totlayer");
RNA_def_property_collection_funcs(prop,
"rna_Mesh_vertex_paint_masks_begin",
nullptr,
nullptr,
nullptr,
"rna_Mesh_vertex_paint_masks_length",
nullptr,
nullptr,
nullptr);
RNA_def_property_struct_type(prop, "MeshPaintMaskLayer");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(prop, "Vertex Paint Mask", "Vertex paint mask");
rna_def_paint_mask(brna, prop);
/* End paint mask */
/* Attributes */
rna_def_attributes_common(srna);

View File

@@ -130,7 +130,6 @@ static void remove_unsupported_corner_data(Mesh &mesh)
{
CustomData_free_layers(&mesh.loop_data, CD_MDISPS, mesh.totloop);
CustomData_free_layers(&mesh.loop_data, CD_TANGENT, mesh.totloop);
CustomData_free_layers(&mesh.loop_data, CD_PAINT_MASK, mesh.totloop);
CustomData_free_layers(&mesh.loop_data, CD_MLOOPTANGENT, mesh.totloop);
CustomData_free_layers(&mesh.loop_data, CD_GRID_PAINT_MASK, mesh.totloop);
CustomData_free_layers(&mesh.loop_data, CD_CUSTOMLOOPNORMAL, mesh.totloop);

View File

@@ -205,11 +205,6 @@ static PyGetSetDef bpy_bmlayeraccess_vert_getseters[] = {
(setter) nullptr,
bpy_bmlayeraccess_collection__skin_doc,
(void *)CD_MVERT_SKIN},
{"paint_mask",
(getter)bpy_bmlayeraccess_collection_get,
(setter) nullptr,
bpy_bmlayeraccess_collection__paint_mask_doc,
(void *)CD_PAINT_MASK},
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
};
@@ -1106,8 +1101,7 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
ret = BPy_BMDeformVert_CreatePyObject(static_cast<MDeformVert *>(value));
break;
}
case CD_PROP_FLOAT:
case CD_PAINT_MASK: {
case CD_PROP_FLOAT: {
ret = PyFloat_FromDouble(*(float *)value);
break;
}
@@ -1172,8 +1166,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj
ret = BPy_BMDeformVert_AssignPyObject(static_cast<MDeformVert *>(value), py_value);
break;
}
case CD_PROP_FLOAT:
case CD_PAINT_MASK: {
case CD_PROP_FLOAT: {
const float tmp_val = PyFloat_AsDouble(py_value);
if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
PyErr_Format(