Sculpt: Specialize mask gesture writing

Part of #118145.
Use the recently added utility for base mesh data, and for BMesh and
multires add a compromise that gets some benefits of simpler loops
but still avoids some duplication.

Also add move a recently added utility to only affect visible grid
vertices to the relevant header and reuse it. I expect this won't be a
permanent part of the API but for now it's better than duplicating
all the loops twice.
This commit is contained in:
Hans Goudey
2024-06-19 13:56:02 -04:00
parent 2639b1833c
commit 90c4c48bbf
3 changed files with 93 additions and 80 deletions

View File

@@ -12,12 +12,13 @@
#include "BLI_array.hh"
#include "BLI_bit_group_vector.hh"
#include "BLI_bit_span_ops.hh"
#include "BLI_index_mask_fwd.hh"
#include "BLI_offset_indices.hh"
#include "BLI_sys_types.h"
struct CCGElem;
struct CCGKey;
#include "BKE_ccg.hh"
struct Mesh;
namespace blender::bke::subdiv {
struct Subdiv;
@@ -286,3 +287,19 @@ const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG &subdiv_ccg)
blender::BitGroupVector<> &BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg);
void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg);
template<typename Fn>
inline void BKE_subdiv_ccg_foreach_visible_grid_vert(const CCGKey &key,
const blender::BitGroupVector<> &grid_hidden,
const int grid,
const Fn &fn)
{
if (grid_hidden.is_empty()) {
for (const int i : blender::IndexRange(key.grid_area)) {
fn(i);
}
}
else {
blender::bits::foreach_0_index(grid_hidden[grid], fn);
}
}

View File

@@ -563,9 +563,7 @@ static void gesture_begin(bContext &C, gesture::GestureData &gesture_data)
BKE_sculpt_update_object_for_edit(depsgraph, gesture_data.vc.obact, false);
}
static float mask_flood_fill_get_new_value_for_elem(const float elem,
FloodFillMode mode,
float value)
static float mask_gesture_get_new_value(const float elem, FloodFillMode mode, float value)
{
switch (mode) {
case FloodFillMode::Value:
@@ -579,57 +577,68 @@ static float mask_flood_fill_get_new_value_for_elem(const float elem,
return 0.0f;
}
static void gesture_apply_task(gesture::GestureData &gesture_data,
const SculptMaskWriteInfo mask_write,
PBVHNode *node)
{
MaskOperation *mask_operation = (MaskOperation *)gesture_data.operation;
Object *ob = gesture_data.vc.obact;
const bool is_multires = BKE_pbvh_type(*gesture_data.ss->pbvh) == PBVH_GRIDS;
PBVHVertexIter vd;
bool any_masked = false;
bool redraw = false;
BKE_pbvh_vertex_iter_begin (*gesture_data.ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
const float *co = SCULPT_vertex_co_get(*gesture_data.ss, vd.vertex);
const float3 vertex_normal = SCULPT_vertex_normal_get(*gesture_data.ss, vd.vertex);
if (gesture::is_affected(gesture_data, co, vertex_normal)) {
float prevmask = vd.mask;
if (!any_masked) {
any_masked = true;
undo::push_node(*ob, node, undo::Type::Mask);
if (is_multires) {
BKE_pbvh_node_mark_positions_update(node);
}
}
const float new_mask = mask_flood_fill_get_new_value_for_elem(
prevmask, mask_operation->mode, mask_operation->value);
if (prevmask != new_mask) {
SCULPT_mask_vert_set(BKE_pbvh_type(*ob->sculpt->pbvh), mask_write, new_mask, vd);
redraw = true;
}
}
}
BKE_pbvh_vertex_iter_end;
if (redraw) {
BKE_pbvh_node_mark_update_mask(node);
}
}
static void gesture_apply_for_symmetry_pass(bContext & /*C*/, gesture::GestureData &gesture_data)
{
const SculptMaskWriteInfo mask_write = SCULPT_mask_get_for_write(*gesture_data.ss);
threading::parallel_for(gesture_data.nodes.index_range(), 1, [&](const IndexRange range) {
for (const int i : range) {
gesture_apply_task(gesture_data, mask_write, gesture_data.nodes[i]);
const PBVH &pbvh = *gesture_data.ss->pbvh;
const Span<PBVHNode *> nodes = gesture_data.nodes;
const MaskOperation &op = *reinterpret_cast<const MaskOperation *>(gesture_data.operation);
Object &object = *gesture_data.vc.obact;
switch (BKE_pbvh_type(*gesture_data.ss->pbvh)) {
case PBVH_FACES: {
const Span<float3> positions = BKE_pbvh_get_vert_positions(pbvh);
const Span<float3> normals = BKE_pbvh_get_vert_normals(pbvh);
update_mask_mesh(object, nodes, [&](MutableSpan<float> node_mask, const Span<int> verts) {
for (const int i : verts.index_range()) {
const int vert = verts[i];
if (gesture::is_affected(gesture_data, positions[vert], normals[vert])) {
node_mask[i] = mask_gesture_get_new_value(node_mask[i], op.mode, op.value);
}
}
});
break;
}
});
case PBVH_GRIDS: {
SubdivCCG &subdiv_ccg = *gesture_data.ss->subdiv_ccg;
const Span<CCGElem *> grids = subdiv_ccg.grids;
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
const CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (PBVHNode *node : nodes.slice(range)) {
for (const int grid : bke::pbvh::node_grid_indices(*node)) {
CCGElem *elem = grids[grid];
BKE_subdiv_ccg_foreach_visible_grid_vert(key, grid_hidden, grid, [&](const int i) {
if (gesture::is_affected(gesture_data,
CCG_elem_offset_co(key, elem, i),
CCG_elem_offset_no(key, elem, i)))
{
float &mask = CCG_elem_offset_mask(key, elem, i);
mask = mask_gesture_get_new_value(mask, op.mode, op.value);
}
});
BKE_pbvh_node_mark_update_mask(node);
}
}
});
break;
}
case PBVH_BMESH: {
BMesh &bm = *gesture_data.ss->bm;
const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
for (PBVHNode *node : nodes.slice(range)) {
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
if (gesture::is_affected(gesture_data, vert->co, vert->no)) {
const float old_mask = BM_ELEM_CD_GET_FLOAT(vert, offset);
const float new_mask = mask_gesture_get_new_value(old_mask, op.mode, op.value);
BM_ELEM_CD_SET_FLOAT(vert, offset, new_mask);
}
}
BKE_pbvh_node_mark_update_mask(node);
}
});
break;
}
}
}
static void gesture_end(bContext &C, gesture::GestureData &gesture_data)

View File

@@ -8,7 +8,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_bit_span_ops.hh"
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_hash.h"
#include "BLI_task.h"
@@ -76,22 +75,6 @@ void write_mask_mesh(Object &object,
mask.finish();
}
template<typename Fn>
static void foreach_visible_grid_vert(const CCGKey &key,
const BitGroupVector<> &grid_hidden,
const int grid,
const Fn &fn)
{
if (grid_hidden.is_empty()) {
for (const int i : IndexRange(key.grid_area)) {
fn(i);
}
}
else {
bits::foreach_0_index(grid_hidden[grid], fn);
}
}
static void init_mask_grids(Main &bmain,
Scene &scene,
Depsgraph &depsgraph,
@@ -188,9 +171,10 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
nodes,
[&](const BitGroupVector<> &grid_hidden, const int grid_index, CCGElem *grid) {
const int verts_start = grid_index * key.grid_area;
foreach_visible_grid_vert(key, grid_hidden, grid_index, [&](const int i) {
CCG_elem_offset_mask(key, grid, i) = BLI_hash_int_01(verts_start + i + seed);
});
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
CCG_elem_offset_mask(key, grid, i) = BLI_hash_int_01(verts_start + i + seed);
});
});
break;
}
@@ -210,9 +194,10 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
[&](const BitGroupVector<> &grid_hidden, const int grid_index, CCGElem *grid) {
const int face_set = face_sets[grid_to_face[grid_index]];
const float value = BLI_hash_int_01(face_set + seed);
foreach_visible_grid_vert(key, grid_hidden, grid_index, [&](const int i) {
CCG_elem_offset_mask(key, grid, i) = value;
});
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
CCG_elem_offset_mask(key, grid, i) = value;
});
});
break;
}
@@ -226,10 +211,12 @@ static int sculpt_mask_init_exec(bContext *C, wmOperator *op)
nodes,
[&](const BitGroupVector<> &grid_hidden, const int grid_index, CCGElem *grid) {
const int verts_start = grid_index * key.grid_area;
foreach_visible_grid_vert(key, grid_hidden, grid_index, [&](const int i) {
const int island = SCULPT_vertex_island_get(ss, PBVHVertRef{verts_start + i});
CCG_elem_offset_mask(key, grid, i) = BLI_hash_int_01(island + seed);
});
BKE_subdiv_ccg_foreach_visible_grid_vert(
key, grid_hidden, grid_index, [&](const int i) {
const int island = SCULPT_vertex_island_get(ss,
PBVHVertRef{verts_start + i});
CCG_elem_offset_mask(key, grid, i) = BLI_hash_int_01(island + seed);
});
});
break;
}