Cleanup: 3 sculpt cleanups #120708

Merged
Hans Goudey merged 3 commits from HooglyBoogly/blender:cleanup-sculpt-flood-fill into main 2024-04-16 18:43:43 +02:00
8 changed files with 183 additions and 169 deletions

View File

@ -1003,25 +1003,25 @@ void SCULPT_tag_update_overlays(bContext *C)
namespace blender::ed::sculpt_paint::flood_fill {
void init_fill(SculptSession *ss, SculptFloodFill *flood)
void init_fill(SculptSession *ss, FillData *flood)
{
SCULPT_vertex_random_access_ensure(ss);
flood->visited_verts.resize(SCULPT_vertex_count_get(ss));
}
void add_initial(SculptFloodFill *flood, PBVHVertRef vertex)
void add_initial(FillData *flood, PBVHVertRef vertex)
{
flood->queue.push(vertex);
}
void add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex)
void add_and_skip_initial(FillData *flood, PBVHVertRef vertex)
{
flood->queue.push(vertex);
flood->visited_verts[vertex.i].set(vertex.i);
}
void add_initial_with_symmetry(
Object *ob, SculptSession *ss, SculptFloodFill *flood, PBVHVertRef vertex, float radius)
Object *ob, SculptSession *ss, FillData *flood, PBVHVertRef vertex, float radius)
{
/* Add active vertex and symmetric vertices to the queue. */
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@ -1047,7 +1047,7 @@ void add_initial_with_symmetry(
}
}
void add_active(Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius)
void add_active(Object *ob, SculptSession *ss, FillData *flood, float radius)
{
/* Add active vertex and symmetric vertices to the queue. */
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
@ -1073,14 +1073,11 @@ void add_active(Object *ob, SculptSession *ss, SculptFloodFill *flood, float rad
}
}
void execute(SculptSession *ss,
SculptFloodFill *flood,
bool (*func)(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
void *userdata),
void *userdata)
void execute(
SculptSession *ss,
FillData *flood,
FunctionRef<bool(SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate)>
func)
{
while (!flood->queue.empty()) {
PBVHVertRef from_v = flood->queue.front();
@ -1101,7 +1098,7 @@ void execute(SculptSession *ss,
flood->visited_verts[BKE_pbvh_vertex_to_index(ss->pbvh, to_v)].set();
if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
if (func(ss, from_v, to_v, ni.is_duplicate)) {
flood->queue.push(to_v);
}
}

View File

@ -600,11 +600,11 @@ struct AutomaskFloodFillData {
char symm;
};
static bool floodfill_cb(
SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/, void *userdata)
static bool floodfill_cb(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
AutomaskFloodFillData *data)
{
AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata;
*(float *)SCULPT_vertex_attr_get(to_v, ss->attrs.automasking_factor) = 1.0f;
*(float *)SCULPT_vertex_attr_get(from_v, ss->attrs.automasking_factor) = 1.0f;
return (!data->use_radius ||
@ -626,7 +626,7 @@ static void topology_automasking_init(const Sculpt *sd, Object *ob)
/* Flood fill automask to connected vertices. Limited to vertices inside
* the brush radius if the tool requires it. */
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
const float radius = ss->cache ? ss->cache->radius : FLT_MAX;
flood_fill::add_active(ob, ss, &flood, radius);
@ -638,7 +638,12 @@ static void topology_automasking_init(const Sculpt *sd, Object *ob)
fdata.symm = SCULPT_mesh_symmetry_xyz_get(ob);
copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
flood_fill::execute(ss, &flood, floodfill_cb, &fdata);
flood_fill::execute(
ss,
&flood,
[&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/) {
return floodfill_cb(ss, from_v, to_v, &fdata);
});
}
static void init_face_sets_masking(const Sculpt *sd, Object *ob)

View File

@ -43,12 +43,12 @@ struct BoundaryInitialVertexFloodFillData {
float radius_sq;
};
static bool boundary_initial_vertex_floodfill_cb(
SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool boundary_initial_vertex_floodfill_cb(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
BoundaryInitialVertexFloodFillData *data)
{
BoundaryInitialVertexFloodFillData *data = static_cast<BoundaryInitialVertexFloodFillData *>(
userdata);
int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
@ -87,7 +87,7 @@ static PBVHVertRef sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss
return initial_vertex;
}
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
flood_fill::add_initial(&flood, initial_vertex);
@ -99,7 +99,10 @@ static PBVHVertRef sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss
fdata.floodfill_steps = MEM_cnew_array<int>(SCULPT_vertex_count_get(ss), __func__);
flood_fill::execute(ss, &flood, boundary_initial_vertex_floodfill_cb, &fdata);
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return boundary_initial_vertex_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
});
MEM_freeN(fdata.floodfill_steps);
return fdata.boundary_initial_vertex;
@ -201,13 +204,15 @@ struct BoundaryFloodFillData {
PBVHVertRef last_visited_vertex;
};
static bool boundary_floodfill_cb(
SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool boundary_floodfill_cb(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
BoundaryFloodFillData *data)
{
int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
BoundaryFloodFillData *data = static_cast<BoundaryFloodFillData *>(userdata);
SculptBoundary *boundary = data->boundary;
if (!SCULPT_vertex_is_boundary(ss, to_v)) {
return false;
@ -242,7 +247,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
MEM_malloc_arrayN(BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptBoundaryPreviewEdge), __func__));
GSet *included_verts = BLI_gset_int_new_ex("included verts", BOUNDARY_INDICES_BLOCK_SIZE);
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
int initial_boundary_index = BKE_pbvh_vertex_to_index(ss->pbvh, initial_boundary_vertex);
@ -261,7 +266,10 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
fdata.included_verts = included_verts;
fdata.last_visited_vertex = {BOUNDARY_VERTEX_NONE};
flood_fill::execute(ss, &flood, boundary_floodfill_cb, &fdata);
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return boundary_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
});
/* Check if the boundary loops into itself and add the extra preview edge to close the loop. */
if (fdata.last_visited_vertex.i != BOUNDARY_VERTEX_NONE &&

View File

@ -452,7 +452,7 @@ static PBVHVertRef sculpt_expand_get_vertex_index_for_symmetry_pass(
* Geodesic: Initializes the falloff with geodesic distances from the given active vertex, taking
* symmetry into account.
*/
static float *sculpt_expand_geodesic_falloff_create(Object *ob, const PBVHVertRef v)
static Array<float> sculpt_expand_geodesic_falloff_create(Object *ob, const PBVHVertRef v)
{
return geodesic::distances_create_from_vert_and_symm(ob, v, FLT_MAX);
}
@ -464,41 +464,43 @@ static float *sculpt_expand_geodesic_falloff_create(Object *ob, const PBVHVertRe
struct ExpandFloodFillData {
float original_normal[3];
float edge_sensitivity;
float *dists;
float *edge_factor;
MutableSpan<float> dists;
MutableSpan<float> edge_factor;
};
static bool expand_topology_floodfill_cb(
SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool expand_topology_floodfill_cb(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
MutableSpan<float> dists)
{
int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
ExpandFloodFillData *data = static_cast<ExpandFloodFillData *>(userdata);
if (!is_duplicate) {
const float to_it = data->dists[from_v_i] + 1.0f;
data->dists[to_v_i] = to_it;
const float to_it = dists[from_v_i] + 1.0f;
dists[to_v_i] = to_it;
}
else {
data->dists[to_v_i] = data->dists[from_v_i];
dists[to_v_i] = dists[from_v_i];
}
return true;
}
static float *sculpt_expand_topology_falloff_create(Object *ob, const PBVHVertRef v)
static Array<float> sculpt_expand_topology_falloff_create(Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = static_cast<float *>(MEM_calloc_arrayN(totvert, sizeof(float), __func__));
Array<float> dists(totvert, 0.0f);
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
flood_fill::add_initial_with_symmetry(ob, ss, &flood, v, FLT_MAX);
ExpandFloodFillData fdata;
fdata.dists = dists;
flood_fill::execute(ss, &flood, expand_topology_floodfill_cb, &fdata);
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return expand_topology_floodfill_cb(ss, from_v, to_v, is_duplicate, dists);
});
return dists;
}
@ -508,13 +510,15 @@ static float *sculpt_expand_topology_falloff_create(Object *ob, const PBVHVertRe
* each vertex and the previous one.
* This creates falloff patterns that follow and snap to the hard edges of the object.
*/
static bool mask_expand_normal_floodfill_cb(
SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool mask_expand_normal_floodfill_cb(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
ExpandFloodFillData *data)
{
int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
ExpandFloodFillData *data = static_cast<ExpandFloodFillData *>(userdata);
if (!is_duplicate) {
float current_normal[3], prev_normal[3];
SCULPT_vertex_normal_get(ss, to_v, current_normal);
@ -534,20 +538,17 @@ static bool mask_expand_normal_floodfill_cb(
return true;
}
static float *sculpt_expand_normal_falloff_create(Object *ob,
const PBVHVertRef v,
const float edge_sensitivity,
const int blur_steps)
static Array<float> sculpt_expand_normal_falloff_create(Object *ob,
const PBVHVertRef v,
const float edge_sensitivity,
const int blur_steps)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = static_cast<float *>(MEM_calloc_arrayN(totvert, sizeof(float), __func__));
float *edge_factor = static_cast<float *>(MEM_callocN(sizeof(float) * totvert, __func__));
for (int i = 0; i < totvert; i++) {
edge_factor[i] = 1.0f;
}
Array<float> dists(totvert, 0.0f);
Array<float> edge_factor(totvert, 1.0f);
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
flood_fill::add_initial_with_symmetry(ob, ss, &flood, v, FLT_MAX);
@ -557,7 +558,10 @@ static float *sculpt_expand_normal_falloff_create(Object *ob,
fdata.edge_sensitivity = edge_sensitivity;
SCULPT_vertex_normal_get(ss, v, fdata.original_normal);
flood_fill::execute(ss, &flood, mask_expand_normal_floodfill_cb, &fdata);
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return mask_expand_normal_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
});
for (int repeat = 0; repeat < blur_steps; repeat++) {
for (int i = 0; i < totvert; i++) {
@ -580,8 +584,6 @@ static float *sculpt_expand_normal_falloff_create(Object *ob,
dists[i] = 1.0 - dists[i];
}
MEM_SAFE_FREE(edge_factor);
return dists;
}
@ -589,15 +591,12 @@ static float *sculpt_expand_normal_falloff_create(Object *ob,
* Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into
* account.
*/
static float *sculpt_expand_spherical_falloff_create(Object *ob, const PBVHVertRef v)
static Array<float> sculpt_expand_spherical_falloff_create(Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = static_cast<float *>(MEM_malloc_arrayN(totvert, sizeof(float), __func__));
for (int i = 0; i < totvert; i++) {
dists[i] = FLT_MAX;
}
Array<float> dists(totvert, FLT_MAX);
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
for (char symm_it = 0; symm_it <= symm; symm_it++) {
@ -624,11 +623,11 @@ static float *sculpt_expand_spherical_falloff_create(Object *ob, const PBVHVertR
* boundary to a falloff value of 0. Then, it propagates that falloff to the rest of the mesh so it
* stays parallel to the boundary, increasing the falloff value by 1 on each step.
*/
static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const PBVHVertRef v)
static Array<float> sculpt_expand_boundary_topology_falloff_create(Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = static_cast<float *>(MEM_calloc_arrayN(totvert, sizeof(float), __func__));
Array<float> dists(totvert, 0.0f);
BitVector<> visited_verts(totvert);
std::queue<PBVHVertRef> queue;
@ -686,11 +685,11 @@ static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const P
* the base mesh faces when checking a vertex neighbor. For this reason, this is not implement
* using the general flood-fill and sculpt neighbors accessors.
*/
static float *sculpt_expand_diagonals_falloff_create(Object *ob, const PBVHVertRef v)
static Array<float> sculpt_expand_diagonals_falloff_create(Object *ob, const PBVHVertRef v)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = static_cast<float *>(MEM_calloc_arrayN(totvert, sizeof(float), __func__));
Array<float> dists(totvert, 0.0f);
/* This algorithm uses mesh data (faces and loops), so this falloff type can't be initialized for
* Multires. It also does not make sense to implement it for dyntopo as the result will be the
@ -838,7 +837,7 @@ static void sculpt_expand_mesh_face_falloff_from_vertex_falloff(SculptSession *s
Mesh *mesh,
Cache *expand_cache)
{
BLI_assert(expand_cache->vert_falloff != nullptr);
BLI_assert(!expand_cache->vert_falloff.is_empty());
if (!expand_cache->face_falloff) {
expand_cache->face_falloff = static_cast<float *>(
@ -870,21 +869,19 @@ static void sculpt_expand_geodesics_from_state_boundary(Object *ob,
SculptSession *ss = ob->sculpt;
BLI_assert(BKE_pbvh_type(ss->pbvh) == PBVH_FACES);
GSet *initial_verts = BLI_gset_int_new("initial_verts");
Set<int> initial_verts;
const BitVector<> boundary_verts = sculpt_expand_boundary_from_enabled(ss, enabled_verts, false);
const int totvert = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totvert; i++) {
if (!boundary_verts[i]) {
continue;
}
BLI_gset_add(initial_verts, POINTER_FROM_INT(i));
initial_verts.add(i);
}
MEM_SAFE_FREE(expand_cache->vert_falloff);
MEM_SAFE_FREE(expand_cache->face_falloff);
expand_cache->vert_falloff = geodesic::distances_create(ob, initial_verts, FLT_MAX);
BLI_gset_free(initial_verts, nullptr);
}
/**
@ -895,16 +892,16 @@ static void sculpt_expand_topology_from_state_boundary(Object *ob,
Cache *expand_cache,
const BitSpan enabled_verts)
{
MEM_SAFE_FREE(expand_cache->vert_falloff);
MEM_SAFE_FREE(expand_cache->face_falloff);
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
float *dists = static_cast<float *>(MEM_calloc_arrayN(totvert, sizeof(float), __func__));
expand_cache->vert_falloff.reinitialize(totvert);
expand_cache->vert_falloff.fill(0);
const BitVector<> boundary_verts = sculpt_expand_boundary_from_enabled(ss, enabled_verts, false);
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
for (int i = 0; i < totvert; i++) {
if (!boundary_verts[i]) {
@ -915,11 +912,11 @@ static void sculpt_expand_topology_from_state_boundary(Object *ob,
flood_fill::add_and_skip_initial(&flood, vertex);
}
ExpandFloodFillData fdata;
fdata.dists = dists;
flood_fill::execute(ss, &flood, expand_topology_floodfill_cb, &fdata);
expand_cache->vert_falloff = dists;
MutableSpan<float> dists = expand_cache->vert_falloff;
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return expand_topology_floodfill_cb(ss, from_v, to_v, is_duplicate, dists);
});
}
/**
@ -1033,7 +1030,6 @@ static void sculpt_expand_initialize_from_face_set_boundary(Object *ob,
static void sculpt_expand_falloff_factors_from_vertex_and_symm_create(
Cache *expand_cache, Object *ob, const PBVHVertRef v, eSculptExpandFalloffType falloff_type)
{
MEM_SAFE_FREE(expand_cache->vert_falloff);
expand_cache->falloff_type = falloff_type;
SculptSession *ss = ob->sculpt;
@ -1131,7 +1127,6 @@ static void sculpt_expand_snap_initialize_from_enabled(SculptSession *ss, Cache
*/
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_colors);
MEM_delete<Cache>(expand_cache);

View File

@ -42,10 +42,10 @@ static bool sculpt_geodesic_mesh_test_dist_add(Span<float3> vert_positions,
const int v0,
const int v1,
const int v2,
float *dists,
GSet *initial_verts)
MutableSpan<float> dists,
const Set<int> &initial_verts)
{
if (BLI_gset_haskey(initial_verts, POINTER_FROM_INT(v0))) {
if (initial_verts.contains(v0)) {
return false;
}
@ -77,7 +77,9 @@ static bool sculpt_geodesic_mesh_test_dist_add(Span<float3> vert_positions,
return false;
}
static float *geodesic_mesh_create(Object *ob, GSet *initial_verts, const float limit_radius)
static Array<float> geodesic_mesh_create(Object *ob,
const Set<int> &initial_verts,
const float limit_radius)
{
SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob);
@ -95,7 +97,7 @@ static float *geodesic_mesh_create(Object *ob, GSet *initial_verts, const float
const bke::AttributeAccessor attributes = mesh->attributes();
const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
float *dists = static_cast<float *>(MEM_malloc_arrayN(totvert, sizeof(float), __func__));
Array<float> dists(totvert);
BitVector<> edge_tag(totedge);
if (ss->edge_to_face_map.is_empty()) {
@ -115,7 +117,7 @@ static float *geodesic_mesh_create(Object *ob, GSet *initial_verts, const float
BLI_LINKSTACK_INIT(queue_next);
for (int i = 0; i < totvert; i++) {
if (BLI_gset_haskey(initial_verts, POINTER_FROM_INT(i))) {
if (initial_verts.contains(i)) {
dists[i] = 0.0f;
}
else {
@ -126,7 +128,6 @@ static float *geodesic_mesh_create(Object *ob, GSet *initial_verts, const float
/* Masks vertices that are further than limit radius from an initial vertex. As there is no need
* to define a distance to them the algorithm can stop earlier by skipping them. */
BitVector<> affected_vert(totvert);
GSetIterator gs_iter;
if (limit_radius == FLT_MAX) {
/* In this case, no need to loop through all initial vertices to check distances as they are
@ -137,8 +138,7 @@ static float *geodesic_mesh_create(Object *ob, GSet *initial_verts, const float
/* This is an O(n^2) loop used to limit the geodesic distance calculation to a radius. When
* this optimization is needed, it is expected for the tool to request the distance to a low
* number of vertices (usually just 1 or 2). */
GSET_ITER (gs_iter, initial_verts) {
const int v = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
for (const int v : initial_verts) {
const float *v_co = vert_positions[v];
for (int i = 0; i < totvert; i++) {
if (len_squared_v3v3(v_co, vert_positions[i]) <= limit_radius_sq) {
@ -226,23 +226,15 @@ static float *geodesic_mesh_create(Object *ob, GSet *initial_verts, const float
/* For sculpt mesh data that does not support a geodesic distances algorithm, fallback to the
* distance to each vertex. In this case, only one of the initial vertices will be used to
* calculate the distance. */
static float *geodesic_fallback_create(Object *ob, GSet *initial_verts)
static Array<float> geodesic_fallback_create(Object *ob, const Set<int> &initial_verts)
{
SculptSession *ss = ob->sculpt;
Mesh *mesh = BKE_object_get_original_mesh(ob);
const int totvert = mesh->verts_num;
float *dists = static_cast<float *>(MEM_malloc_arrayN(totvert, sizeof(float), __func__));
int first_affected = SCULPT_GEODESIC_VERTEX_NONE;
GSetIterator gs_iter;
GSET_ITER (gs_iter, initial_verts) {
first_affected = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
break;
}
Array<float> dists(totvert, 0.0f);
const int first_affected = *initial_verts.begin();
if (first_affected == SCULPT_GEODESIC_VERTEX_NONE) {
for (int i = 0; i < totvert; i++) {
dists[i] = FLT_MAX;
}
dists.fill(FLT_MAX);
return dists;
}
@ -257,7 +249,7 @@ static float *geodesic_fallback_create(Object *ob, GSet *initial_verts)
return dists;
}
float *distances_create(Object *ob, GSet *initial_verts, const float limit_radius)
Array<float> distances_create(Object *ob, const Set<int> &initial_verts, const float limit_radius)
{
SculptSession *ss = ob->sculpt;
switch (BKE_pbvh_type(ss->pbvh)) {
@ -268,15 +260,15 @@ float *distances_create(Object *ob, GSet *initial_verts, const float limit_radiu
return geodesic_fallback_create(ob, initial_verts);
}
BLI_assert_unreachable();
return nullptr;
return {};
}
float *distances_create_from_vert_and_symm(Object *ob,
const PBVHVertRef vertex,
const float limit_radius)
Array<float> distances_create_from_vert_and_symm(Object *ob,
const PBVHVertRef vertex,
const float limit_radius)
{
SculptSession *ss = ob->sculpt;
GSet *initial_verts = BLI_gset_int_new("initial_verts");
Set<int> initial_verts;
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
for (char i = 0; i <= symm; ++i) {
@ -292,14 +284,12 @@ float *distances_create_from_vert_and_symm(Object *ob,
v = SCULPT_nearest_vertex_get(ob, location, FLT_MAX, false);
}
if (v.i != PBVH_REF_NONE) {
BLI_gset_add(initial_verts, POINTER_FROM_INT(BKE_pbvh_vertex_to_index(ss->pbvh, v)));
initial_verts.add(BKE_pbvh_vertex_to_index(ss->pbvh, v));
}
}
}
float *dists = distances_create(ob, initial_verts, limit_radius);
BLI_gset_free(initial_verts, nullptr);
return dists;
return distances_create(ob, initial_verts, limit_radius);
}
} // namespace blender::ed::sculpt_paint::geodesic

View File

@ -121,12 +121,6 @@ struct SculptOrigFaceData {
int face_set;
};
/* Flood Fill. */
struct SculptFloodFill {
std::queue<PBVHVertRef> queue;
blender::BitVector<> visited_verts;
};
enum eBoundaryAutomaskMode {
AUTOMASK_INIT_BOUNDARY_EDGES = 1,
AUTOMASK_INIT_BOUNDARY_FACE_SETS = 2,
@ -578,7 +572,7 @@ struct Cache {
/* Indexed by vertex index, precalculated falloff value of that vertex (without any falloff
* editing modification applied). */
float *vert_falloff;
Array<float> vert_falloff;
/* Max falloff value in *vert_falloff. */
float max_vert_falloff;
@ -1175,20 +1169,22 @@ void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brus
namespace blender::ed::sculpt_paint::flood_fill {
void init_fill(SculptSession *ss, SculptFloodFill *flood);
void add_active(Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius);
struct FillData {
std::queue<PBVHVertRef> queue;
blender::BitVector<> visited_verts;
};
void init_fill(SculptSession *ss, FillData *flood);
void add_active(Object *ob, SculptSession *ss, FillData *flood, float radius);
void add_initial_with_symmetry(
Object *ob, SculptSession *ss, SculptFloodFill *flood, PBVHVertRef vertex, float radius);
void add_initial(SculptFloodFill *flood, PBVHVertRef vertex);
void add_and_skip_initial(SculptFloodFill *flood, PBVHVertRef vertex);
void execute(SculptSession *ss,
SculptFloodFill *flood,
bool (*func)(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
void *userdata),
void *userdata);
Object *ob, SculptSession *ss, FillData *flood, PBVHVertRef vertex, float radius);
void add_initial(FillData *flood, PBVHVertRef vertex);
void add_and_skip_initial(FillData *flood, PBVHVertRef vertex);
void execute(
SculptSession *ss,
FillData *flood,
FunctionRef<bool(SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate)>
func);
}
@ -1362,8 +1358,10 @@ namespace blender::ed::sculpt_paint::geodesic {
* Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will
* fallback to euclidean distances to one of the initial vertices in the set.
*/
float *distances_create(Object *ob, GSet *initial_verts, float limit_radius);
float *distances_create_from_vert_and_symm(Object *ob, PBVHVertRef vertex, float limit_radius);
Array<float> distances_create(Object *ob, const Set<int> &initial_verts, float limit_radius);
Array<float> distances_create_from_vert_and_symm(Object *ob,
PBVHVertRef vertex,
float limit_radius);
}

View File

@ -781,14 +781,15 @@ static void do_mask_by_color_contiguous_update_node(Object *ob,
}
}
static bool sculpt_mask_by_color_contiguous_floodfill(
SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool sculpt_mask_by_color_contiguous_floodfill(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
MaskByColorContiguousFloodFillData *data)
{
int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
MaskByColorContiguousFloodFillData *data = static_cast<MaskByColorContiguousFloodFillData *>(
userdata);
float current_color[4];
SCULPT_vertex_color_get(ss, to_v, current_color);
@ -825,7 +826,7 @@ static void sculpt_mask_by_color_contiguous(Object *object,
}
}
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
flood_fill::add_initial(&flood, vertex);
@ -839,7 +840,10 @@ static void sculpt_mask_by_color_contiguous(Object *object,
copy_v3_v3(ffd.initial_color, color);
flood_fill::execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill, &ffd);
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return sculpt_mask_by_color_contiguous_floodfill(ss, from_v, to_v, is_duplicate, &ffd);
});
Vector<PBVHNode *> nodes = blender::bke::pbvh::search_gather(ss->pbvh, {});
const SculptMaskWriteInfo mask_write = SCULPT_mask_get_for_write(ss);

View File

@ -379,12 +379,14 @@ struct PoseFloodFillData {
int target_face_set;
};
static bool pose_topology_floodfill_cb(
SculptSession *ss, PBVHVertRef /*from_v*/, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool pose_topology_floodfill_cb(SculptSession *ss,
PBVHVertRef /*from_v*/,
PBVHVertRef to_v,
bool is_duplicate,
PoseFloodFillData *data)
{
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
PoseFloodFillData *data = static_cast<PoseFloodFillData *>(userdata);
const float *co = SCULPT_vertex_co_get(ss, to_v);
if (data->pose_factor) {
@ -412,11 +414,12 @@ static bool pose_topology_floodfill_cb(
return false;
}
static bool pose_face_sets_floodfill_cb(
SculptSession *ss, PBVHVertRef /*from_v*/, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool pose_face_sets_floodfill_cb(SculptSession *ss,
PBVHVertRef /*from_v*/,
PBVHVertRef to_v,
bool is_duplicate,
PoseFloodFillData *data)
{
PoseFloodFillData *data = static_cast<PoseFloodFillData *>(userdata);
const int index = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
const PBVHVertRef vertex = to_v;
bool visit_next = false;
@ -524,7 +527,7 @@ void calc_pose_data(Object *ob,
SCULPT_vertex_random_access_ensure(ss);
/* Calculate the pose rotation point based on the boundaries of the brush factor. */
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
flood_fill::add_active(ob, ss, &flood, (r_pose_factor) ? radius : 0.0f);
@ -537,7 +540,10 @@ void calc_pose_data(Object *ob,
zero_v3(fdata.pose_origin);
copy_v3_v3(fdata.pose_initial_co, initial_location);
copy_v3_v3(fdata.fallback_floodfill_origin, initial_location);
flood_fill::execute(ss, &flood, pose_topology_floodfill_cb, &fdata);
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return pose_topology_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
});
if (fdata.tot_co > 0) {
mul_v3_fl(fdata.pose_origin, 1.0f / float(fdata.tot_co));
@ -728,7 +734,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(Object *ob,
for (int s = 0; s < ik_chain->tot_segments; s++) {
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
flood_fill::add_initial_with_symmetry(ob, ss, &flood, current_vertex, FLT_MAX);
@ -750,7 +756,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(Object *ob,
zero_v3(fdata.pose_origin);
zero_v3(fdata.fallback_origin);
copy_v3_v3(fdata.pose_initial_co, SCULPT_vertex_co_get(ss, current_vertex));
flood_fill::execute(ss, &flood, pose_face_sets_floodfill_cb, &fdata);
flood_fill::execute(
ss,
&flood,
[&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return pose_face_sets_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
});
if (fdata.tot_co > 0) {
mul_v3_fl(fdata.pose_origin, 1.0f / float(fdata.tot_co));
@ -776,11 +787,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(Object *ob,
return ik_chain;
}
static bool pose_face_sets_fk_find_masked_floodfill_cb(
SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate, void *userdata)
static bool pose_face_sets_fk_find_masked_floodfill_cb(SculptSession *ss,
PBVHVertRef from_v,
PBVHVertRef to_v,
bool is_duplicate,
PoseFloodFillData *data)
{
PoseFloodFillData *data = static_cast<PoseFloodFillData *>(userdata);
int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
@ -817,11 +829,8 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
static bool pose_face_sets_fk_set_weights_floodfill_cb(SculptSession *ss,
PBVHVertRef /*from_v*/,
PBVHVertRef to_v,
bool /*is_duplicate*/,
void *userdata)
PoseFloodFillData *data)
{
PoseFloodFillData *data = static_cast<PoseFloodFillData *>(userdata);
int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v);
data->fk_weights[to_v_i] = 1.0f;
@ -842,7 +851,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(Object *ob,
const int active_face_set = face_set::active_face_set_get(ss);
SculptFloodFill flood;
flood_fill::FillData flood;
flood_fill::init_fill(ss, &flood);
flood_fill::add_initial(&flood, active_vertex);
PoseFloodFillData fdata;
@ -853,7 +862,10 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(Object *ob,
fdata.target_face_set = SCULPT_FACE_SET_NONE;
fdata.masked_face_set_it = 0;
fdata.visited_face_sets = BLI_gset_int_new_ex("visited_face_sets", 3);
flood_fill::execute(ss, &flood, pose_face_sets_fk_find_masked_floodfill_cb, &fdata);
flood_fill::execute(
ss, &flood, [&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool is_duplicate) {
return pose_face_sets_fk_find_masked_floodfill_cb(ss, from_v, to_v, is_duplicate, &fdata);
});
BLI_gset_free(fdata.visited_face_sets, nullptr);
int origin_count = 0;
@ -908,7 +920,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(Object *ob,
flood_fill::init_fill(ss, &flood);
flood_fill::add_active(ob, ss, &flood, radius);
fdata.fk_weights = ik_chain->segments[0].weights;
flood_fill::execute(ss, &flood, pose_face_sets_fk_set_weights_floodfill_cb, &fdata);
flood_fill::execute(
ss,
&flood,
[&](SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/) {
return pose_face_sets_fk_set_weights_floodfill_cb(ss, from_v, to_v, &fdata);
});
pose_ik_chain_origin_heads_init(ik_chain, ik_chain->segments[0].head);
return ik_chain;