Implement boundary expand
This commit is contained in:
parent
a9f6ab7357
commit
81ac9f61b6
|
@ -517,11 +517,12 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object,
|
|||
|
||||
SculptBoundary *boundary = MEM_callocN(sizeof(SculptBoundary), "Boundary edit data");
|
||||
|
||||
const bool init_boundary_distances = brush->boundary_falloff_type !=
|
||||
BRUSH_BOUNDARY_FALLOFF_CONSTANT;
|
||||
const bool init_boundary_distances = brush ? brush->boundary_falloff_type !=
|
||||
BRUSH_BOUNDARY_FALLOFF_CONSTANT :
|
||||
false;
|
||||
sculpt_boundary_indices_init(ss, boundary, init_boundary_distances, boundary_initial_vertex);
|
||||
|
||||
const float boundary_radius = radius * (1.0f + brush->boundary_offset);
|
||||
const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
|
||||
sculpt_boundary_edit_data_init(ss, boundary, boundary_initial_vertex, boundary_radius);
|
||||
|
||||
return boundary;
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SCULPT_EXPAND_VERTEX_NONE -1
|
||||
|
||||
static EnumPropertyItem prop_sculpt_expand_faloff_type_items[] = {
|
||||
{SCULPT_EXPAND_FALLOFF_GEODESICS, "GEODESICS", 0, "Surface", ""},
|
||||
|
@ -78,8 +79,9 @@ static EnumPropertyItem prop_sculpt_expand_faloff_type_items[] = {
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const int vertex) {
|
||||
return SCULPT_geodesic_from_vertex_and_symm(sd, ob, vertex, FLT_MAX);
|
||||
static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const int vertex)
|
||||
{
|
||||
return SCULPT_geodesic_from_vertex_and_symm(sd, ob, vertex, FLT_MAX);
|
||||
}
|
||||
|
||||
typedef struct ExpandFloodFillData {
|
||||
|
@ -103,10 +105,11 @@ static bool mask_expand_topology_floodfill_cb(
|
|||
return true;
|
||||
}
|
||||
|
||||
static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const int vertex) {
|
||||
static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const int vertex)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
float *dists = MEM_malloc_arrayN(sizeof (float), totvert, "spherical dist");
|
||||
float *dists = MEM_malloc_arrayN(sizeof(float), totvert, "spherical dist");
|
||||
|
||||
SculptFloodFill flood;
|
||||
SCULPT_floodfill_init(ss, &flood);
|
||||
|
@ -121,20 +124,19 @@ static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, cons
|
|||
return dists;
|
||||
}
|
||||
|
||||
static bool mask_expand_normals_floodfill_cb(
|
||||
static bool mask_expand_normal_floodfill_cb(
|
||||
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
|
||||
{
|
||||
ExpandFloodFillData *data = userdata;
|
||||
if (!is_duplicate) {
|
||||
float current_normal[3], prev_normal[3];
|
||||
SCULPT_vertex_normal_get(ss, to_v, current_normal);
|
||||
SCULPT_vertex_normal_get(ss, from_v, prev_normal);
|
||||
const float from_edge_factor = data->edge_factor[from_v];
|
||||
data->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
|
||||
from_edge_factor;
|
||||
data->dists[to_v] = dot_v3v3(data->original_normal, current_normal) *
|
||||
powf(from_edge_factor, data->edge_sensitivity);
|
||||
CLAMP(data->dists[to_v], 0.0f, 1.0f);
|
||||
float current_normal[3], prev_normal[3];
|
||||
SCULPT_vertex_normal_get(ss, to_v, current_normal);
|
||||
SCULPT_vertex_normal_get(ss, from_v, prev_normal);
|
||||
const float from_edge_factor = data->edge_factor[from_v];
|
||||
data->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * from_edge_factor;
|
||||
data->dists[to_v] = dot_v3v3(data->original_normal, current_normal) *
|
||||
powf(from_edge_factor, data->edge_sensitivity);
|
||||
CLAMP(data->dists[to_v], 0.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
/* PBVH_GRIDS duplicate handling. */
|
||||
|
@ -145,15 +147,18 @@ static bool mask_expand_normals_floodfill_cb(
|
|||
return true;
|
||||
}
|
||||
|
||||
static float *sculpt_expand_normal_falloff_create(Sculpt *sd, Object *ob, const int vertex, const float edge_sensitivity) {
|
||||
static float *sculpt_expand_normal_falloff_create(Sculpt *sd,
|
||||
Object *ob,
|
||||
const int vertex,
|
||||
const float edge_sensitivity)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
float *dists = MEM_malloc_arrayN(sizeof (float), totvert, "normal dist");
|
||||
float *edge_factor = MEM_callocN(sizeof(float) * totvert,
|
||||
"mask edge factor");
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
edge_factor[i] = 1.0f;
|
||||
}
|
||||
float *dists = MEM_malloc_arrayN(sizeof(float), totvert, "normal dist");
|
||||
float *edge_factor = MEM_callocN(sizeof(float) * totvert, "mask edge factor");
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
edge_factor[i] = 1.0f;
|
||||
}
|
||||
|
||||
SculptFloodFill flood;
|
||||
SCULPT_floodfill_init(ss, &flood);
|
||||
|
@ -165,53 +170,54 @@ static float *sculpt_expand_normal_falloff_create(Sculpt *sd, Object *ob, const
|
|||
fdata.edge_sensitivity = edge_sensitivity;
|
||||
SCULPT_vertex_normal_get(ss, vertex, fdata.original_normal);
|
||||
|
||||
SCULPT_floodfill_execute(ss, &flood, mask_expand_topology_floodfill_cb, &fdata);
|
||||
SCULPT_floodfill_execute(ss, &flood, mask_expand_normal_floodfill_cb, &fdata);
|
||||
SCULPT_floodfill_free(&flood);
|
||||
|
||||
for (int repeat = 0; repeat < 2; repeat++) {
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
float avg = 0.0f;
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
|
||||
avg += dists[ni.index];
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
dists[i] = avg / ni.size;
|
||||
for (int repeat = 0; repeat < 2; repeat++) {
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
float avg = 0.0f;
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
|
||||
avg += dists[ni.index];
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
dists[i] = avg / ni.size;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(edge_factor);
|
||||
MEM_SAFE_FREE(edge_factor);
|
||||
|
||||
return dists;
|
||||
}
|
||||
|
||||
|
||||
static float *sculpt_expand_spherical_falloff_create(Sculpt *sd, Object *ob, const int vertex) {
|
||||
static float *sculpt_expand_spherical_falloff_create(Sculpt *sd, Object *ob, const int vertex)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
|
||||
float *dists = MEM_malloc_arrayN(sizeof (float), totvert, "spherical dist");
|
||||
float *dists = MEM_malloc_arrayN(sizeof(float), totvert, "spherical dist");
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
dists[i] = FLT_MAX;
|
||||
dists[i] = FLT_MAX;
|
||||
}
|
||||
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
|
||||
for (char symm_it = 0; symm_it <= symm; symm_it++) {
|
||||
if (SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
|
||||
int v = -1;
|
||||
if (symm_it == 0) {
|
||||
v = vertex;
|
||||
}
|
||||
else {
|
||||
float location[3];
|
||||
flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), symm_it);
|
||||
v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false);
|
||||
}
|
||||
if (v != -1) {
|
||||
const float *co = SCULPT_vertex_co_get(ss, v);
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, i)));
|
||||
}
|
||||
if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
|
||||
continue;
|
||||
}
|
||||
int v = SCULPT_EXPAND_VERTEX_NONE;
|
||||
if (symm_it == 0) {
|
||||
v = vertex;
|
||||
}
|
||||
else {
|
||||
float location[3];
|
||||
flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), symm_it);
|
||||
v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false);
|
||||
}
|
||||
if (v != -1) {
|
||||
const float *co = SCULPT_vertex_co_get(ss, v);
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,59 +225,123 @@ static float *sculpt_expand_spherical_falloff_create(Sculpt *sd, Object *ob, con
|
|||
return dists;
|
||||
}
|
||||
|
||||
static void sculpt_expand_update_max_falloff_factor(SculptSession *ss, ExpandCache *expand_cache) {
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
expand_cache->max_falloff_factor = -FLT_MAX;
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
expand_cache->max_falloff_factor = max_ff(expand_cache->max_falloff_factor, expand_cache->falloff_factor[i]);
|
||||
static float *sculpt_expand_boundary_topology_falloff_create(Sculpt *sd,
|
||||
Object *ob,
|
||||
const int vertex)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "spherical dist");
|
||||
BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices");
|
||||
GSQueue *queue = BLI_gsqueue_new(sizeof(int));
|
||||
|
||||
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
for (char symm_it = 0; symm_it <= symm; symm_it++) {
|
||||
if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) {
|
||||
continue;
|
||||
}
|
||||
int v = SCULPT_EXPAND_VERTEX_NONE;
|
||||
if (symm_it == 0) {
|
||||
v = vertex;
|
||||
}
|
||||
else {
|
||||
float location[3];
|
||||
flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), symm_it);
|
||||
v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false);
|
||||
}
|
||||
|
||||
SculptBoundary *boundary = SCULPT_boundary_data_init(ob, NULL, v, FLT_MAX);
|
||||
for (int i = 0; i < boundary->num_vertices; i++) {
|
||||
BLI_gsqueue_push(queue, &boundary->vertices[i]);
|
||||
BLI_BITMAP_ENABLE(visited_vertices, boundary->vertices[i]);
|
||||
}
|
||||
SCULPT_boundary_data_free(boundary);
|
||||
}
|
||||
|
||||
if (BLI_gsqueue_is_empty(queue)) {
|
||||
return dists;
|
||||
}
|
||||
|
||||
while (!BLI_gsqueue_is_empty(queue)) {
|
||||
int v;
|
||||
BLI_gsqueue_pop(queue, &v);
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v, ni) {
|
||||
if (BLI_BITMAP_TEST(visited_vertices, ni.index)) {
|
||||
continue;
|
||||
}
|
||||
dists[ni.index] = dists[v] + 1.0f;
|
||||
BLI_BITMAP_ENABLE(visited_vertices, ni.index);
|
||||
BLI_gsqueue_push(queue, &ni.index);
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
}
|
||||
|
||||
BLI_gsqueue_free(queue);
|
||||
MEM_freeN(visited_vertices);
|
||||
return dists;
|
||||
}
|
||||
|
||||
static void sculpt_expand_update_max_falloff_factor(SculptSession *ss, ExpandCache *expand_cache)
|
||||
{
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
expand_cache->max_falloff_factor = -FLT_MAX;
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
expand_cache->max_falloff_factor = max_ff(expand_cache->max_falloff_factor,
|
||||
expand_cache->falloff_factor[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void sculpt_expand_falloff_factors_from_vertex_and_symm_create(ExpandCache *expand_cache, Sculpt *sd, Object *ob, const int vertex, eSculptExpandFalloffType falloff_type) {
|
||||
if (expand_cache->falloff_factor && expand_cache->falloff_factor_type == falloff_type) {
|
||||
/* Falloffs are already initialize with the current falloff type, nothing to do. */
|
||||
return;
|
||||
}
|
||||
static void sculpt_expand_falloff_factors_from_vertex_and_symm_create(
|
||||
ExpandCache *expand_cache,
|
||||
Sculpt *sd,
|
||||
Object *ob,
|
||||
const int vertex,
|
||||
eSculptExpandFalloffType falloff_type)
|
||||
{
|
||||
if (expand_cache->falloff_factor && expand_cache->falloff_factor_type == falloff_type) {
|
||||
/* Falloffs are already initialize with the current falloff type, nothing to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (expand_cache->falloff_factor) {
|
||||
MEM_freeN(expand_cache->falloff_factor);
|
||||
}
|
||||
if (expand_cache->falloff_factor) {
|
||||
MEM_freeN(expand_cache->falloff_factor);
|
||||
}
|
||||
|
||||
switch (falloff_type) {
|
||||
switch (falloff_type) {
|
||||
case SCULPT_EXPAND_FALLOFF_GEODESICS:
|
||||
expand_cache->falloff_factor = sculpt_expand_geodesic_falloff_create(sd, ob, vertex);
|
||||
break;
|
||||
expand_cache->falloff_factor = sculpt_expand_geodesic_falloff_create(sd, ob, vertex);
|
||||
break;
|
||||
case SCULPT_EXPAND_FALLOFF_TOPOLOGY:
|
||||
expand_cache->falloff_factor = sculpt_expand_topology_falloff_create(sd, ob, vertex);
|
||||
break;
|
||||
expand_cache->falloff_factor = sculpt_expand_topology_falloff_create(sd, ob, vertex);
|
||||
break;
|
||||
case SCULPT_EXPAND_FALLOFF_NORMALS:
|
||||
expand_cache->falloff_factor = sculpt_expand_normal_falloff_create(sd, ob, vertex, 300.0f);
|
||||
break;
|
||||
expand_cache->falloff_factor = sculpt_expand_normal_falloff_create(sd, ob, vertex, 300.0f);
|
||||
break;
|
||||
case SCULPT_EXPAND_FALLOFF_SPHERICAL:
|
||||
expand_cache->falloff_factor = sculpt_expand_spherical_falloff_create(sd, ob, vertex);
|
||||
break;
|
||||
expand_cache->falloff_factor = sculpt_expand_spherical_falloff_create(sd, ob, vertex);
|
||||
break;
|
||||
case SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY:
|
||||
expand_cache->falloff_factor = sculpt_expand_boundary_topology_falloff_create(
|
||||
sd, ob, vertex);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
expand_cache->falloff_factor_type = falloff_type;
|
||||
|
||||
expand_cache->falloff_factor_type = falloff_type;
|
||||
|
||||
SculptSession *ss = ob->sculpt;
|
||||
sculpt_expand_update_max_falloff_factor(ss, expand_cache);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
sculpt_expand_update_max_falloff_factor(ss, expand_cache);
|
||||
}
|
||||
|
||||
void sculpt_expand_cache_free(ExpandCache *expand_cache) {
|
||||
MEM_SAFE_FREE(expand_cache->nodes);
|
||||
MEM_SAFE_FREE(expand_cache->falloff_factor);
|
||||
MEM_SAFE_FREE(expand_cache->initial_mask);
|
||||
MEM_SAFE_FREE(expand_cache->initial_face_sets);
|
||||
MEM_SAFE_FREE(expand_cache);
|
||||
void sculpt_expand_cache_free(ExpandCache *expand_cache)
|
||||
{
|
||||
MEM_SAFE_FREE(expand_cache->nodes);
|
||||
MEM_SAFE_FREE(expand_cache->falloff_factor);
|
||||
MEM_SAFE_FREE(expand_cache->initial_mask);
|
||||
MEM_SAFE_FREE(expand_cache->initial_face_sets);
|
||||
MEM_SAFE_FREE(expand_cache);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
@ -308,8 +378,8 @@ static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
|
|||
ED_workspace_status_text(C, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void sculpt_expand_cancel(bContext *C, wmOperator *op) {
|
||||
static void sculpt_expand_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
|
@ -317,19 +387,18 @@ static void sculpt_expand_cancel(bContext *C, wmOperator *op) {
|
|||
ED_workspace_status_text(C, NULL);
|
||||
}
|
||||
|
||||
|
||||
static bool sculpt_expand_state_get(ExpandCache *expand_cache, int i) {
|
||||
bool enabled = expand_cache->falloff_factor[i] <= expand_cache->active_factor;
|
||||
if (expand_cache->invert) {
|
||||
enabled = !enabled;
|
||||
}
|
||||
return enabled;
|
||||
static bool sculpt_expand_state_get(ExpandCache *expand_cache, int i)
|
||||
{
|
||||
bool enabled = expand_cache->falloff_factor[i] <= expand_cache->active_factor;
|
||||
if (expand_cache->invert) {
|
||||
enabled = !enabled;
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
||||
static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
|
||||
const int i,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
const int i,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
SculptThreadedTaskData *data = userdata;
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
|
@ -341,74 +410,74 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
|
|||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
|
||||
{
|
||||
const float initial_mask = *vd.mask;
|
||||
const bool enabled = sculpt_expand_state_get(expand_cache, vd.index);
|
||||
const float initial_mask = *vd.mask;
|
||||
const bool enabled = sculpt_expand_state_get(expand_cache, vd.index);
|
||||
|
||||
if (enabled){
|
||||
if (expand_cache->mask_preserve_previous) {
|
||||
*vd.mask = max_ff(initial_mask, expand_cache->initial_mask[vd.index]);
|
||||
if (enabled) {
|
||||
if (expand_cache->mask_preserve_previous) {
|
||||
*vd.mask = max_ff(initial_mask, expand_cache->initial_mask[vd.index]);
|
||||
}
|
||||
else {
|
||||
*vd.mask = 1.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*vd.mask = 0.0f;
|
||||
*vd.mask = 1.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*vd.mask = 0.0f;
|
||||
}
|
||||
|
||||
if (*vd.mask != initial_mask) {
|
||||
any_changed = true;
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
if (*vd.mask != initial_mask) {
|
||||
any_changed = true;
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
if (any_changed) {
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define SCULPT_EXPAND_VERTEX_NONE -1
|
||||
|
||||
static void sculpt_expand_flush_updates(bContext *C) {
|
||||
static void sculpt_expand_flush_updates(bContext *C)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
for (int i = 0; i < ss->expand_cache->totnode; i++) {
|
||||
BKE_pbvh_node_mark_redraw(ss->expand_cache->nodes[i]);
|
||||
BKE_pbvh_node_mark_redraw(ss->expand_cache->nodes[i]);
|
||||
}
|
||||
SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
|
||||
}
|
||||
|
||||
static void sculpt_expand_initial_state_store(Object *ob, ExpandCache *expand_cache) {
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
const int totface = ss->totfaces;
|
||||
static void sculpt_expand_initial_state_store(Object *ob, ExpandCache *expand_cache)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
const int totface = ss->totfaces;
|
||||
|
||||
expand_cache->initial_mask = MEM_malloc_arrayN(totvert, sizeof (float), "initial mask");
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
expand_cache->initial_mask[i] = SCULPT_vertex_mask_get(ss, i);
|
||||
}
|
||||
expand_cache->initial_mask = MEM_malloc_arrayN(totvert, sizeof(float), "initial mask");
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
expand_cache->initial_mask[i] = SCULPT_vertex_mask_get(ss, i);
|
||||
}
|
||||
|
||||
expand_cache->initial_face_sets = MEM_malloc_arrayN(totvert, sizeof (int), "initial face set");
|
||||
for (int i = 0; i < totface; i++) {
|
||||
expand_cache->initial_face_sets[i] = ss->face_sets[i];
|
||||
}
|
||||
expand_cache->initial_face_sets = MEM_malloc_arrayN(totvert, sizeof(int), "initial face set");
|
||||
for (int i = 0; i < totface; i++) {
|
||||
expand_cache->initial_face_sets[i] = ss->face_sets[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int vertex) {
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
ExpandCache *expand_cache = ss->expand_cache;
|
||||
static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int vertex)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
ExpandCache *expand_cache = ss->expand_cache;
|
||||
|
||||
/* Update the active factor in the cache. */
|
||||
if (vertex == SCULPT_EXPAND_VERTEX_NONE) {
|
||||
expand_cache->active_factor = expand_cache->max_falloff_factor;
|
||||
}
|
||||
else {
|
||||
expand_cache->active_factor = expand_cache->falloff_factor[vertex];
|
||||
}
|
||||
/* Update the active factor in the cache. */
|
||||
if (vertex == SCULPT_EXPAND_VERTEX_NONE) {
|
||||
expand_cache->active_factor = expand_cache->max_falloff_factor;
|
||||
}
|
||||
else {
|
||||
expand_cache->active_factor = expand_cache->falloff_factor[vertex];
|
||||
}
|
||||
|
||||
SculptThreadedTaskData data = {
|
||||
.sd = sd,
|
||||
|
@ -418,22 +487,24 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
|
|||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, expand_cache->totnode);
|
||||
BLI_task_parallel_range(0, expand_cache->totnode, &data, sculpt_expand_mask_update_task_cb, &settings);
|
||||
|
||||
BLI_task_parallel_range(
|
||||
0, expand_cache->totnode, &data, sculpt_expand_mask_update_task_cb, &settings);
|
||||
|
||||
sculpt_expand_flush_updates(C);
|
||||
}
|
||||
|
||||
|
||||
static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const wmEvent *event) {
|
||||
static int sculpt_expand_target_vertex_update_and_get(bContext *C,
|
||||
Object *ob,
|
||||
const wmEvent *event)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptCursorGeometryInfo sgi;
|
||||
float mouse[2] = {event->mval[0], event->mval[1]};
|
||||
if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
|
||||
return SCULPT_active_vertex_get(ss);
|
||||
return SCULPT_active_vertex_get(ss);
|
||||
}
|
||||
else {
|
||||
return SCULPT_EXPAND_VERTEX_NONE;
|
||||
return SCULPT_EXPAND_VERTEX_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,19 +547,22 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
|
|||
/* Set the initial element for expand. */
|
||||
int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, event);
|
||||
if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) {
|
||||
/* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active vertex in the sculpt session. */
|
||||
initial_vertex = SCULPT_active_vertex_get(ss);
|
||||
/* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active
|
||||
* vertex in the sculpt session. */
|
||||
initial_vertex = SCULPT_active_vertex_get(ss);
|
||||
}
|
||||
ss->expand_cache->initial_active_vertex = initial_vertex;
|
||||
|
||||
/* Cache PBVH nodes. */
|
||||
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &ss->expand_cache->nodes, &ss->expand_cache->totnode);
|
||||
BKE_pbvh_search_gather(
|
||||
ss->pbvh, NULL, NULL, &ss->expand_cache->nodes, &ss->expand_cache->totnode);
|
||||
|
||||
/* Store initial state. */
|
||||
sculpt_expand_initial_state_store(ob, ss->expand_cache);
|
||||
|
||||
/* Initialize the factors. */
|
||||
sculpt_expand_falloff_factors_from_vertex_and_symm_create(ss->expand_cache, sd, ob, initial_vertex, SCULPT_EXPAND_FALLOFF_GEODESICS);
|
||||
sculpt_expand_falloff_factors_from_vertex_and_symm_create(
|
||||
ss->expand_cache, sd, ob, initial_vertex, SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY);
|
||||
|
||||
/* Initial update. */
|
||||
sculpt_expand_update_for_vertex(C, ob, initial_vertex);
|
||||
|
|
|
@ -1164,23 +1164,23 @@ typedef enum eSculptExpandTargetType {
|
|||
} eSculptExpandTargetType;
|
||||
|
||||
typedef struct ExpandCache {
|
||||
eSculptExpandFalloffType falloff_factor_type;
|
||||
float *falloff_factor;
|
||||
float max_falloff_factor;
|
||||
eSculptExpandFalloffType falloff_factor_type;
|
||||
float *falloff_factor;
|
||||
float max_falloff_factor;
|
||||
|
||||
int initial_active_vertex;
|
||||
float active_factor;
|
||||
int initial_active_vertex;
|
||||
float active_factor;
|
||||
|
||||
PBVHNode **nodes;
|
||||
int totnode;
|
||||
PBVHNode **nodes;
|
||||
int totnode;
|
||||
|
||||
bool invert;
|
||||
bool invert;
|
||||
|
||||
bool mask_preserve_previous;
|
||||
bool mask_preserve_previous;
|
||||
|
||||
eSculptExpandTargetType target;
|
||||
float *initial_mask;
|
||||
int *initial_face_sets;
|
||||
eSculptExpandTargetType target;
|
||||
float *initial_mask;
|
||||
int *initial_face_sets;
|
||||
} ExpandCache;
|
||||
|
||||
typedef struct FilterCache {
|
||||
|
|
Loading…
Reference in New Issue