Cleanup: Sculpt: Add utility to duplicate mask data

Avoid the `PBVHVertRef` abstraction which is unnecesarily costly for
such a simple thing as copying data. Instead we can use abstractions
specific to each PBVH type (currently only `VArray` for meshes).
This commit is contained in:
Hans Goudey 2023-12-28 14:33:59 -05:00
parent a52887abb0
commit 70ae6f5d41
5 changed files with 59 additions and 21 deletions

View File

@ -468,6 +468,9 @@ void PAINT_OT_visibility_invert(wmOperatorType *ot);
/* `paint_mask.cc` */
namespace blender::ed::sculpt_paint::mask {
Array<float> duplicate_mask(const Object &object);
void PAINT_OT_mask_flood_fill(wmOperatorType *ot);
void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot);
void PAINT_OT_mask_box_gesture(wmOperatorType *ot);

View File

@ -62,6 +62,55 @@
namespace blender::ed::sculpt_paint::mask {
Array<float> duplicate_mask(const Object &object)
{
const SculptSession &ss = *object.sculpt;
switch (BKE_pbvh_type(ss.pbvh)) {
case PBVH_FACES: {
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
const bke::AttributeAccessor attributes = mesh.attributes();
const VArray mask = *attributes.lookup_or_default<float>(
".sculpt_mask", bke::AttrDomain::Point, 0.0f);
Array<float> result(mask.size());
mask.materialize(result);
return result;
}
case PBVH_GRIDS: {
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
const Span<CCGElem *> grids = subdiv_ccg.grids;
Array<float> result(grids.size() * key.grid_area);
int index = 0;
for (const int grid : grids.index_range()) {
CCGElem *elem = grids[grid];
for (const int i : IndexRange(key.grid_area)) {
result[index] = *CCG_elem_offset_mask(&key, elem, i);
index++;
}
}
return result;
}
case PBVH_BMESH: {
BMesh &bm = *ss.bm;
const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
Array<float> result(bm.totvert);
if (offset == -1) {
result.fill(0.0f);
}
else {
BM_mesh_elem_table_ensure(&bm, BM_VERT);
for (const int i : result.index_range()) {
result[i] = BM_ELEM_CD_GET_FLOAT(BM_vert_at_index(&bm, i), offset);
}
}
return result;
}
}
BLI_assert_unreachable();
return {};
}
/* The gesture API doesn't write to this enum type,
* it writes to eSelectOp from ED_select_utils.hh.
* We must thus map the modes here to the desired

View File

@ -1143,7 +1143,6 @@ static void sculpt_expand_cache_data_free(Cache *expand_cache)
{
MEM_SAFE_FREE(expand_cache->vert_falloff);
MEM_SAFE_FREE(expand_cache->face_falloff);
MEM_SAFE_FREE(expand_cache->original_mask);
MEM_SAFE_FREE(expand_cache->original_colors);
MEM_delete<Cache>(expand_cache);
}
@ -1240,7 +1239,7 @@ static void sculpt_expand_restore_original_state(bContext *C, Object *ob, Cache
SculptSession *ss = ob->sculpt;
switch (expand_cache->target) {
case SCULPT_EXPAND_TARGET_MASK:
write_mask_data(ss, {expand_cache->original_mask, SCULPT_vertex_count_get(ss)});
write_mask_data(ss, expand_cache->original_mask);
SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
SCULPT_tag_update_overlays(C);
@ -1439,13 +1438,7 @@ static void sculpt_expand_original_state_store(Object *ob, Cache *expand_cache)
expand_cache->original_face_sets = face_set::duplicate_face_sets(mesh);
if (expand_cache->target == SCULPT_EXPAND_TARGET_MASK) {
expand_cache->original_mask = static_cast<float *>(
MEM_malloc_arrayN(totvert, sizeof(float), "initial mask"));
for (int i = 0; i < totvert; i++) {
PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, vertex);
}
expand_cache->original_mask = mask::duplicate_mask(*ob);
}
if (expand_cache->target == SCULPT_EXPAND_TARGET_COLORS) {

View File

@ -23,6 +23,7 @@
#include "WM_api.hh"
#include "WM_types.hh"
#include "paint_intern.hh"
#include "sculpt_intern.hh"
#include "RNA_access.hh"
@ -64,7 +65,7 @@ static EnumPropertyItem prop_mask_filter_types[] = {
static void mask_filter_task(SculptSession *ss,
const int mode,
float *prev_mask,
const Span<float> prev_mask,
const SculptMaskWriteInfo mask_write,
PBVHNode *node)
{
@ -184,7 +185,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
undo::push_node(ob, node, undo::Type::Mask);
}
float *prev_mask = nullptr;
Array<float> prev_mask;
int iterations = RNA_int_get(op->ptr, "iterations");
/* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
@ -199,11 +200,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
for (int i = 0; i < iterations; i++) {
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
prev_mask = static_cast<float *>(MEM_mallocN(num_verts * sizeof(float), __func__));
for (int j = 0; j < num_verts; j++) {
PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, j);
prev_mask[j] = SCULPT_vertex_mask_get(ss, vertex);
}
prev_mask = duplicate_mask(*ob);
}
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
@ -211,10 +208,6 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
mask_filter_task(ss, filter_type, prev_mask, mask_write, nodes[i]);
}
});
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
MEM_freeN(prev_mask);
}
}
undo::push_end(ob);

View File

@ -709,7 +709,7 @@ struct Cache {
Array<int> initial_face_sets;
/* Original data of the sculpt as it was before running the Expand operator. */
float *original_mask;
Array<float> original_mask;
Array<int> original_face_sets;
float (*original_colors)[4];