Cleanup: Access sculpt attributes with C++ attribute API

Access masks and face sets through the `BKE_attribute.hh` API. This
us more flexibility long term, and makes code a bit simpler in the
meantime.
This commit is contained in:
Hans Goudey 2023-11-20 13:14:16 -05:00
parent 9781600d68
commit 301731692e
11 changed files with 127 additions and 134 deletions

View File

@ -2003,23 +2003,22 @@ int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
Object *ob,
MultiresModifierData *mmd)
{
using namespace blender;
using namespace blender::bke;
Mesh *me = static_cast<Mesh *>(ob->data);
const blender::OffsetIndices faces = me->faces();
const OffsetIndices faces = me->faces();
const Span<int> corner_verts = me->corner_verts();
MutableAttributeAccessor attributes = me->attributes_for_write();
int ret = 0;
const float *paint_mask = static_cast<const float *>(
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 */
if (mmd && !CustomData_has_layer(&me->loop_data, CD_GRID_PAINT_MASK)) {
GridPaintMask *gmask;
int level = max_ii(1, mmd->sculptlvl);
int gridsize = BKE_ccg_gridsize(level);
int gridarea = gridsize * gridsize;
gmask = static_cast<GridPaintMask *>(
GridPaintMask *gmask = static_cast<GridPaintMask *>(
CustomData_add_layer(&me->loop_data, CD_GRID_PAINT_MASK, CD_SET_DEFAULT, me->totloop));
for (int i = 0; i < me->totloop; i++) {
@ -2031,14 +2030,15 @@ int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
}
/* If vertices already have mask, copy into multires data. */
if (paint_mask) {
if (const VArray<float> mask = *attributes.lookup<float>(".sculpt_mask", ATTR_DOMAIN_POINT)) {
const VArraySpan<float> mask_span(mask);
for (const int i : faces.index_range()) {
const blender::IndexRange face = faces[i];
const IndexRange face = faces[i];
/* Mask center. */
float avg = 0.0f;
for (const int vert : corner_verts.slice(face)) {
avg += paint_mask[vert];
avg += mask_span[vert];
}
avg /= float(face.size());
@ -2046,13 +2046,13 @@ int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph,
for (const int corner : face) {
GridPaintMask *gpm = &gmask[corner];
const int vert = corner_verts[corner];
const int prev = corner_verts[blender::bke::mesh::face_corner_prev(face, vert)];
const int next = corner_verts[blender::bke::mesh::face_corner_next(face, vert)];
const int prev = corner_verts[mesh::face_corner_prev(face, vert)];
const int next = corner_verts[mesh::face_corner_next(face, vert)];
gpm->data[0] = avg;
gpm->data[1] = (paint_mask[vert] + paint_mask[next]) * 0.5f;
gpm->data[2] = (paint_mask[vert] + paint_mask[prev]) * 0.5f;
gpm->data[3] = paint_mask[vert];
gpm->data[1] = (mask_span[vert] + mask_span[next]) * 0.5f;
gpm->data[2] = (mask_span[vert] + mask_span[prev]) * 0.5f;
gpm->data[3] = mask_span[vert];
}
}
}
@ -2066,9 +2066,7 @@ 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_named(
&me->vert_data, CD_PROP_FLOAT, CD_SET_DEFAULT, me->totvert, ".sculpt_mask");
if (attributes.add<float>(".sculpt_mask", ATTR_DOMAIN_POINT, AttributeInitDefaultValue())) {
/* 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

@ -679,8 +679,6 @@ static void pbvh_draw_args_init(const Mesh &mesh, PBVH *pbvh, PBVH_GPU_Args *arg
args->hide_poly = pbvh->face_data ? static_cast<const bool *>(CustomData_get_layer_named(
pbvh->face_data, CD_PROP_BOOL, ".hide_poly")) :
nullptr;
args->face_sets = static_cast<const int *>(
CustomData_get_layer_named(&pbvh->mesh->face_data, CD_PROP_INT32, ".sculpt_face_set"));
}
args->active_color = mesh.active_color_attribute;
@ -3167,12 +3165,10 @@ bool pbvh_has_mask(const PBVH *pbvh)
case PBVH_GRIDS:
return (pbvh->gridkey.has_mask != 0);
case PBVH_FACES:
return (pbvh->vert_data &&
CustomData_has_layer_named(pbvh->vert_data, CD_PROP_FLOAT, ".sculpt_mask"));
return pbvh->mesh->attributes().contains(".sculpt_mask");
case PBVH_BMESH:
return (pbvh->header.bm &&
(CustomData_get_offset_named(
&pbvh->header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask") != -1));
return pbvh->header.bm &&
(CustomData_has_layer_named(&pbvh->header.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask"));
}
return false;
@ -3183,8 +3179,7 @@ bool pbvh_has_face_sets(PBVH *pbvh)
switch (pbvh->header.type) {
case PBVH_GRIDS:
case PBVH_FACES:
return pbvh->face_data && CustomData_get_layer_named(
pbvh->face_data, CD_PROP_INT32, ".sculpt_face_set") != nullptr;
return pbvh->mesh->attributes().contains(".sculpt_face_set");
case PBVH_BMESH:
return false;
}

View File

@ -52,7 +52,6 @@ struct PBVH_GPU_Args {
const char *render_color;
int face_sets_color_seed, face_sets_color_default;
const int *face_sets; /* for PBVH_FACES and PBVH_GRIDS */
SubdivCCG *subdiv_ccg;
const DMFlagMat *grid_flag_mats;

View File

@ -575,34 +575,32 @@ struct PBVHBatches {
}
}
else if (vbo.type == CD_PBVH_FSET_TYPE) {
const int *face_sets = args.face_sets;
if (!face_sets) {
uchar white[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
foreach_grids(
[&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) {
*static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = white;
});
}
else {
const bke::AttributeAccessor attributes = args.me->attributes();
if (const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
ATTR_DOMAIN_FACE)) {
const VArraySpan<int> face_sets_span(face_sets);
foreach_grids(
[&](int /*x*/, int /*y*/, int grid_index, CCGElem * /*elems*/[4], int /*i*/) {
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (face_sets) {
const int face_index = BKE_subdiv_ccg_grid_to_face_index(args.subdiv_ccg,
grid_index);
const int fset = face_sets[face_index];
const int face_index = BKE_subdiv_ccg_grid_to_face_index(args.subdiv_ccg,
grid_index);
const int fset = face_sets_span[face_index];
/* Skip for the default color Face Set to render it white. */
if (fset != args.face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(
fset, args.face_sets_color_seed, face_set_color);
}
/* Skip for the default color Face Set to render it white. */
if (fset != args.face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(
fset, args.face_sets_color_seed, face_set_color);
}
*static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = face_set_color;
*static_cast<uchar4 *>(GPU_vertbuf_raw_step(&access)) = face_set_color;
});
}
else {
const uchar white[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
foreach_grids(
[&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) {
*static_cast<uchar4 *>(GPU_vertbuf_raw_step(&access)) = white;
});
}
}
@ -697,6 +695,8 @@ struct PBVHBatches {
GPUVertBuf &vert_buf = *vbo.vert_buf;
const bke::AttributeAccessor attributes = args.me->attributes();
if (vbo.type == CD_PBVH_CO_TYPE) {
extract_data_vert_faces<float3>(args, args.vert_positions, vert_buf);
}
@ -704,35 +704,35 @@ struct PBVHBatches {
fill_vbo_normal_faces(args, vert_buf);
}
else if (vbo.type == CD_PBVH_MASK_TYPE) {
if (const float *mask = static_cast<const float *>(
CustomData_get_layer_named(args.vert_data, CD_PROP_FLOAT, ".sculpt_mask")))
float *data = static_cast<float *>(GPU_vertbuf_get_data(&vert_buf));
if (const VArray<float> mask = *attributes.lookup<float>(".sculpt_mask", ATTR_DOMAIN_POINT))
{
const VArraySpan<float> mask_span(mask);
const Span<int> corner_verts = args.corner_verts;
const Span<MLoopTri> looptris = args.mlooptri;
const Span<int> looptri_faces = args.looptri_faces;
const bool *hide_poly = args.hide_poly;
float *data = static_cast<float *>(GPU_vertbuf_get_data(&vert_buf));
for (const int looptri_i : args.prim_indices) {
if (hide_poly && hide_poly[looptri_faces[looptri_i]]) {
continue;
}
for (int i : IndexRange(3)) {
const int vert = corner_verts[looptris[looptri_i].tri[i]];
*data = mask[vert];
*data = mask_span[vert];
data++;
}
}
}
else {
MutableSpan(static_cast<float *>(GPU_vertbuf_get_data(vbo.vert_buf)), totvert).fill(0);
MutableSpan(data, totvert).fill(0);
}
}
else if (vbo.type == CD_PBVH_FSET_TYPE) {
const int *face_sets = static_cast<const int *>(
CustomData_get_layer_named(args.face_data, CD_PROP_INT32, ".sculpt_face_set"));
uchar4 *data = static_cast<uchar4 *>(GPU_vertbuf_get_data(vbo.vert_buf));
if (face_sets) {
if (const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
ATTR_DOMAIN_FACE)) {
const VArraySpan<int> face_sets_span(face_sets);
int last_face = -1;
uchar4 fset_color(UCHAR_MAX);
@ -744,7 +744,7 @@ struct PBVHBatches {
if (last_face != face_i) {
last_face = face_i;
const int fset = face_sets[face_i];
const int fset = face_sets_span[face_i];
if (fset != args.face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, args.face_sets_color_seed, fset_color);

View File

@ -10,6 +10,7 @@
#include "BLI_string.h"
#include "BKE_attribute.hh"
#include "BKE_mesh.hh"
#include "BKE_paint.hh"
@ -40,14 +41,6 @@ static void extract_sculpt_data_init(const MeshRenderData &mr,
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPUVertFormat *format = get_sculpt_data_format();
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_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");
GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr.loop_len);
@ -59,8 +52,9 @@ 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_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");
int cd_mask_ofs = CustomData_get_offset_named(&mr.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
int cd_face_set_ofs = CustomData_get_offset_named(
&mr.bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
BMIter f_iter;
BMFace *efa;
BM_ITER_MESH (efa, &f_iter, mr.bm, BM_FACES_OF_MESH) {
@ -68,12 +62,12 @@ static void extract_sculpt_data_init(const MeshRenderData &mr,
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
do {
float v_mask = 0.0f;
if (cd_mask) {
if (cd_mask_ofs != -1) {
v_mask = BM_ELEM_CD_GET_FLOAT(l_iter->v, cd_mask_ofs);
}
vbo_data->mask = v_mask;
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (cd_face_set) {
if (cd_face_set_ofs != -1) {
const int face_set_id = BM_ELEM_CD_GET_INT(l_iter->f, cd_face_set_ofs);
if (face_set_id != mr.me->face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(
@ -86,17 +80,21 @@ static void extract_sculpt_data_init(const MeshRenderData &mr,
}
}
else {
const bke::AttributeAccessor attributes = mr.me->attributes();
const VArray<float> mask = *attributes.lookup<float>(".sculpt_mask", ATTR_DOMAIN_POINT);
const VArray<int> face_set = *attributes.lookup<int>(".sculpt_face_set", ATTR_DOMAIN_FACE);
for (int face_index = 0; face_index < mr.face_len; face_index++) {
for (const int corner : mr.faces[face_index]) {
float v_mask = 0.0f;
if (cd_mask) {
v_mask = cd_mask[mr.corner_verts[corner]];
if (mask) {
v_mask = mask[mr.corner_verts[corner]];
}
vbo_data->mask = v_mask;
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (cd_face_set) {
const int face_set_id = cd_face_set[face_index];
if (face_set) {
const int face_set_id = face_set[face_index];
/* Skip for the default color Face Set to render it white. */
if (face_set_id != mr.me->face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(
@ -119,19 +117,19 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
Mesh *coarse_mesh = mr.me;
CustomData *cd_vdata = &coarse_mesh->vert_data;
CustomData *cd_pdata = &coarse_mesh->face_data;
/* First, interpolate mask if available. */
GPUVertBuf *mask_vbo = nullptr;
GPUVertBuf *subdiv_mask_vbo = nullptr;
const float *cd_mask = (const float *)CustomData_get_layer_named(
cd_vdata, CD_PROP_FLOAT, ".sculpt_mask");
const bke::AttributeAccessor attributes = coarse_mesh->attributes();
const VArray<float> mask = *attributes.lookup<float>(".sculpt_mask", ATTR_DOMAIN_POINT);
const OffsetIndices coarse_faces = coarse_mesh->faces();
const Span<int> coarse_corner_verts = coarse_mesh->corner_verts();
if (cd_mask) {
if (mask) {
const VArraySpan<float> mask_span(mask);
GPUVertFormat mask_format = {0};
GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
@ -142,7 +140,7 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
for (int i = 0; i < coarse_mesh->faces_num; i++) {
for (const int vert : coarse_corner_verts.slice(coarse_faces[i])) {
*v_mask++ = cd_mask[vert];
*v_mask++ = mask_span[vert];
}
}
@ -165,8 +163,7 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
};
gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo);
const int *cd_face_set = (const int *)CustomData_get_layer_named(
cd_pdata, CD_PROP_INT32, ".sculpt_face_set");
const VArray<float> cd_face_sets = *attributes.lookup<float>(".sculpt_mask", ATTR_DOMAIN_POINT);
GPUVertFormat *format = get_sculpt_data_format();
GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache.num_subdiv_loops);
@ -176,8 +173,8 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
const int face_index = subdiv_loop_face_index[i];
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (cd_face_set) {
const int face_set_id = cd_face_set[face_index];
if (cd_face_sets) {
const int face_set_id = cd_face_sets[face_index];
/* Skip for the default color Face Set to render it white. */
if (face_set_id != coarse_mesh->face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(

View File

@ -12,6 +12,7 @@
#include "BLT_translation.h"
#include "BKE_attribute.hh"
#include "BKE_context.hh"
#include "BKE_editmesh.hh"
#include "BKE_layer.h"
@ -205,13 +206,14 @@ static int geometry_extract_apply(bContext *C,
C, OB_MESH, nullptr, ob->loc, ob->rot, false, local_view_bits);
BKE_mesh_nomain_to_mesh(new_mesh, static_cast<Mesh *>(new_ob->data), new_ob);
Mesh *new_ob_mesh = static_cast<Mesh *>(new_ob->data);
/* Remove the Face Sets as they need to be recreated when entering Sculpt Mode in the new object.
* TODO(pablodobarro): In the future we can try to preserve them from the original mesh. */
Mesh *new_ob_mesh = static_cast<Mesh *>(new_ob->data);
CustomData_free_layer_named(&new_ob_mesh->face_data, ".sculpt_face_set", new_ob_mesh->faces_num);
new_ob_mesh->attributes_for_write().remove(".sculpt_face_set");
/* Remove the mask from the new object so it can be sculpted directly after extracting. */
CustomData_free_layer_named(&new_ob_mesh->vert_data, ".sculpt_mask", new_ob_mesh->totvert);
new_ob_mesh->attributes_for_write().remove(".sculpt_mask");
BKE_mesh_copy_parameters_for_eval(new_ob_mesh, mesh);
@ -509,7 +511,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_layer_named(&new_ob_mesh->vert_data, ".sculpt_mask", new_ob_mesh->totvert);
new_ob_mesh->attributes_for_write().remove(".sculpt_mask");
Mesh *new_mesh = static_cast<Mesh *>(new_ob->data);
BKE_mesh_nomain_to_mesh(new_ob_mesh, new_mesh, new_ob);

View File

@ -294,24 +294,22 @@ static void join_mesh_single(Depsgraph *depsgraph,
* of them will have different IDs for their Face Sets. */
static void mesh_join_offset_face_sets_ID(Mesh *mesh, int *face_set_offset)
{
if (!mesh->faces_num) {
return;
}
int *face_sets = (int *)CustomData_get_layer_named_for_write(
&mesh->face_data, CD_PROP_INT32, ".sculpt_face_set", mesh->faces_num);
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<int> face_sets = attributes.lookup_for_write_span<int>(
".sculpt_face_set");
if (!face_sets) {
return;
}
int max_face_set = 0;
for (int f = 0; f < mesh->faces_num; f++) {
for (const int i : face_sets.span.index_range()) {
/* As face sets encode the visibility in the integer sign, the offset needs to be added or
* subtracted depending on the initial sign of the integer to get the new ID. */
if (face_sets[f] <= *face_set_offset) {
face_sets[f] += *face_set_offset;
if (face_sets.span[i] <= *face_set_offset) {
face_sets.span[i] += *face_set_offset;
}
max_face_set = max_ii(max_face_set, face_sets[f]);
max_face_set = max_ii(max_face_set, face_sets.span[i]);
}
*face_set_offset = max_face_set;
}

View File

@ -21,6 +21,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_attribute.hh"
#include "BKE_ccg.h"
#include "BKE_context.hh"
#include "BKE_mesh.hh"
@ -73,38 +74,36 @@ static void partialvis_update_mesh(Object *ob,
PartialVisArea area,
float planes[4][4])
{
Mesh *me = static_cast<Mesh *>(ob->data);
using namespace blender;
Mesh *mesh = static_cast<Mesh *>(ob->data);
const blender::Span<blender::float3> positions = BKE_pbvh_get_vert_positions(pbvh);
const float *paint_mask;
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_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));
if (hide_vert == nullptr) {
hide_vert = static_cast<bool *>(CustomData_add_layer_named(
&me->vert_data, CD_PROP_BOOL, CD_SET_DEFAULT, me->totvert, ".hide_vert"));
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
const VArray<float> mask = *attributes.lookup_or_default<float>(
".sculpt_mask", ATTR_DOMAIN_POINT, 0.0f);
bke::SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_span<bool>(
".hide_vert", ATTR_DOMAIN_POINT);
SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
for (const int vert : verts) {
float vmask = paint_mask ? paint_mask[vert] : 0;
/* Hide vertex if in the hide volume. */
if (is_effected(area, planes, positions[vert], vmask)) {
hide_vert[vert] = (action == PARTIALVIS_HIDE);
if (is_effected(area, planes, positions[vert], mask[vert])) {
hide_vert.span[vert] = (action == PARTIALVIS_HIDE);
any_changed = true;
}
if (!hide_vert[vert]) {
if (!hide_vert.span[vert]) {
any_visible = true;
}
}
hide_vert.finish();
if (any_changed) {
BKE_pbvh_node_mark_rebuild_draw(node);
BKE_pbvh_node_fully_hidden_set(node, !any_visible);

View File

@ -21,6 +21,7 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_attribute.hh"
#include "BKE_brush.hh"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
@ -1196,17 +1197,19 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *exp
static void write_mask_data(SculptSession *ss, const Span<float> mask)
{
using namespace blender;
Vector<PBVHNode *> nodes = blender::bke::pbvh::search_gather(ss->pbvh, {});
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_named_for_write(
&mesh->vert_data, CD_PROP_FLOAT, ".sculpt_mask", mesh->totvert));
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<float> attribute = attributes.lookup_or_add_for_write_span<float>(
".sculpt_mask", ATTR_DOMAIN_POINT);
for (PBVHNode *node : nodes) {
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
layer[vd.index] = mask[vd.index];
attribute.span[vd.index] = mask[vd.index];
}
BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_redraw(node);

View File

@ -66,14 +66,16 @@ using blender::Vector;
int ED_sculpt_face_sets_find_next_available_id(Mesh *mesh)
{
const int *face_sets = static_cast<const int *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_INT32, ".sculpt_face_set"));
if (!face_sets) {
using namespace blender;
const VArray<int> attribute = *mesh->attributes().lookup<int>(".sculpt_face_set",
ATTR_DOMAIN_FACE);
if (!attribute) {
return SCULPT_FACE_SET_NONE;
}
const VArraySpan<int> face_sets(attribute);
int next_face_set_id = 0;
for (int i = 0; i < mesh->faces_num; i++) {
for (const int i : face_sets.index_range()) {
next_face_set_id = max_ii(next_face_set_id, face_sets[i]);
}
next_face_set_id++;
@ -83,15 +85,17 @@ int ED_sculpt_face_sets_find_next_available_id(Mesh *mesh)
void ED_sculpt_face_sets_initialize_none_to_id(Mesh *mesh, const int new_id)
{
int *face_sets = static_cast<int *>(CustomData_get_layer_named_for_write(
&mesh->face_data, CD_PROP_INT32, ".sculpt_face_set", mesh->faces_num));
using namespace blender;
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<int> face_sets = attributes.lookup_for_write_span<int>(
".sculpt_face_set");
if (!face_sets) {
return;
}
for (int i = 0; i < mesh->faces_num; i++) {
if (face_sets[i] == SCULPT_FACE_SET_NONE) {
face_sets[i] = new_id;
for (const int i : face_sets.span.index_range()) {
if (face_sets.span[i] == SCULPT_FACE_SET_NONE) {
face_sets.span[i] = new_id;
}
}
}

View File

@ -567,22 +567,20 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode, bool *m
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
if (unode->maxvert) {
/* Regular mesh restore. */
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_named(
&mesh->vert_data, CD_PROP_FLOAT, CD_SET_DEFAULT, mesh->totvert, ".sculpt_mask"));
}
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<float> mask = attributes.lookup_or_add_for_write_span<float>(
".sculpt_mask", ATTR_DOMAIN_POINT);
const Span<int> index = unode->index;
for (int i = 0; i < unode->totvert; i++) {
if (vmask[index[i]] != unode->mask[i]) {
SWAP(float, vmask[index[i]], unode->mask[i]);
if (mask.span[index[i]] != unode->mask[i]) {
std::swap(mask.span[index[i]], unode->mask[i]);
modified_vertices[index[i]] = true;
}
}
mask.finish();
}
else if (unode->maxgrid && subdiv_ccg != nullptr) {
/* Multires restore. */
@ -600,7 +598,7 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode, bool *m
grid = grids[unode->grids[j]];
for (int i = 0; i < gridsize * gridsize; i++) {
SWAP(float, *CCG_elem_offset_mask(&key, grid, i), mask[index]);
std::swap(*CCG_elem_offset_mask(&key, grid, i), mask[index]);
index++;
}
}