Sculpt: support automasking, pose and mask expand for multires

These were the last remaining new sculpt tools that did not support multires.
Performance could be improved still, but it should work.

Fixes T68899
This commit is contained in:
Brecht Van Lommel 2019-09-30 16:33:04 +02:00
parent 52c02dc311
commit 10ec207a6b
Notes: blender-bot 2023-02-14 06:00:50 +01:00
Referenced by issue #68899,  Multires support for new sculpt tools
4 changed files with 158 additions and 75 deletions

View File

@ -265,6 +265,7 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg,
typedef struct SubdivCCGNeighbors {
SubdivCCGCoord *coords;
int size;
int num_duplicates;
SubdivCCGCoord coords_fixed[256];
} SubdivCCGNeighbors;
@ -288,9 +289,13 @@ bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivC
/* Get actual neighbors of the given coordinate.
*
* SubdivCCGNeighbors.neighbors must be freed if it is not equal to
* SubdivCCGNeighbors.fixed_neighbors. */
* SubdivCCGNeighbors.fixed_neighbors.
*
* If include_duplicates is true, vertices in other grids that match
* the current vertex are added at the end of the coords array. */
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors);
#endif /* __BKE_SUBDIV_CCG_H__ */

View File

@ -1268,9 +1268,13 @@ bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivC
return true;
}
BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors *neighbors, int size)
BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors *neighbors,
const int num_unique,
const int num_duplicates)
{
const int size = num_unique + num_duplicates;
neighbors->size = size;
neighbors->num_duplicates = num_duplicates;
if (size < ARRAY_SIZE(neighbors->coords_fixed)) {
neighbors->coords = neighbors->coords_fixed;
}
@ -1397,18 +1401,27 @@ BLI_INLINE int prev_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const Sub
* can only iterate over grid of a single face, without looking into adjacency. */
static void neighbor_coords_corner_center_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index];
const int num_adjacent_grids = face->num_grids;
subdiv_ccg_neighbors_init(r_neighbors, face->num_grids);
subdiv_ccg_neighbors_init(
r_neighbors, num_adjacent_grids, (include_duplicates) ? num_adjacent_grids - 1 : 0);
for (int face_grid_index = 0; face_grid_index < face->num_grids; ++face_grid_index) {
int duplicate_face_grid_index = num_adjacent_grids;
for (int face_grid_index = 0; face_grid_index < num_adjacent_grids; ++face_grid_index) {
SubdivCCGCoord neighbor_coord;
neighbor_coord.grid_index = face->start_grid_index + face_grid_index;
neighbor_coord.x = 1;
neighbor_coord.y = 0;
r_neighbors->coords[face_grid_index] = neighbor_coord;
if (include_duplicates && neighbor_coord.grid_index != coord->grid_index) {
neighbor_coord.x = 0;
r_neighbors->coords[duplicate_face_grid_index++] = neighbor_coord;
}
}
}
@ -1439,6 +1452,7 @@ static int adjacent_vertex_index_from_coord(const SubdivCCG *subdiv_ccg,
/* The corner is adjacent to a coarse vertex. */
static void neighbor_coords_corner_vertex_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
Subdiv *subdiv = subdiv_ccg->subdiv;
@ -1450,7 +1464,11 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG *subdiv_ccg,
const int num_vertex_edges = topology_refiner->getNumVertexEdges(topology_refiner,
adjacent_vertex_index);
subdiv_ccg_neighbors_init(r_neighbors, num_vertex_edges);
SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[adjacent_vertex_index];
const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces;
subdiv_ccg_neighbors_init(
r_neighbors, num_vertex_edges, (include_duplicates) ? num_adjacent_faces - 1 : 0);
StaticOrHeapIntStorage vertex_edges_storage;
static_or_heap_storage_init(&vertex_edges_storage);
@ -1467,21 +1485,33 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG *subdiv_ccg,
/* Depending edge orientation we use first (zero-based) or previous-to-last point. */
int edge_vertices_indices[2];
topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices_indices);
int edge_point_index;
int edge_point_index, duplicate_edge_point_index;
if (edge_vertices_indices[0] == adjacent_vertex_index) {
edge_point_index = 1;
duplicate_edge_point_index = 0;
edge_point_index = duplicate_edge_point_index + 1;
}
else {
/* Edge "consists" of 2 grids, which makes it 2 * grid_size elements per edge.
* The index of last edge element is 2 * grid_size - 1 (due to zero-based indices),
* and we are interested in previous to last element. */
edge_point_index = subdiv_ccg->grid_size * 2 - 2;
duplicate_edge_point_index = subdiv_ccg->grid_size * 2 - 1;
edge_point_index = duplicate_edge_point_index - 1;
}
SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index];
r_neighbors->coords[i] = adjacent_edge->boundary_coords[edge_face_index][edge_point_index];
}
if (include_duplicates) {
/* Add duplicates of the current grid vertex in adjacent faces if requested. */
for (int i = 0, duplicate_i = num_vertex_edges; i < num_adjacent_faces; i++) {
SubdivCCGCoord neighbor_coord = adjacent_vertex->corner_coords[i];
if (neighbor_coord.grid_index != coord->grid_index) {
r_neighbors->coords[duplicate_i++] = neighbor_coord;
}
}
}
static_or_heap_storage_free(&vertex_edges_storage);
}
@ -1577,6 +1607,7 @@ static int prev_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int
* coarse faces, but is not at the coarse vertex. */
static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
@ -1586,46 +1617,59 @@ static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[adjacent_edge_index];
/* 2 neighbor points along the edge, plus one inner point per every adjacent grid. */
const int num_neighbor_coord = adjacent_edge->num_adjacent_faces + 2;
subdiv_ccg_neighbors_init(r_neighbors, num_neighbor_coord);
const int num_adjacent_faces = adjacent_edge->num_adjacent_faces;
subdiv_ccg_neighbors_init(
r_neighbors, num_adjacent_faces + 2, (include_duplicates) ? num_adjacent_faces - 1 : 0);
const int point_index = adjacent_edge_point_index_from_coord(
subdiv_ccg, coord, adjacent_edge_index);
const int next_point_index = next_adjacent_edge_point_index(subdiv_ccg, point_index);
const int prev_point_index = prev_adjacent_edge_point_index(subdiv_ccg, point_index);
r_neighbors->coords[0] = adjacent_edge->boundary_coords[0][prev_point_index];
r_neighbors->coords[1] = adjacent_edge->boundary_coords[0][next_point_index];
for (int i = 0; i < adjacent_edge->num_adjacent_faces; ++i) {
SubdivCCGCoord grid_coord = adjacent_edge->boundary_coords[i][point_index];
for (int i = 0, duplicate_i = num_adjacent_faces; i < num_adjacent_faces; ++i) {
SubdivCCGCoord *boundary_coords = adjacent_edge->boundary_coords[i];
/* One step into the grid from the edge for each adjacent face. */
SubdivCCGCoord grid_coord = boundary_coords[point_index];
r_neighbors->coords[i + 2] = coord_step_inside_from_boundary(subdiv_ccg, &grid_coord);
if (grid_coord.grid_index == coord->grid_index) {
/* Prev and next along the edge for the current grid. */
r_neighbors->coords[0] = boundary_coords[prev_point_index];
r_neighbors->coords[1] = boundary_coords[next_point_index];
}
else if (include_duplicates) {
/* Same coordinate on neighboring grids if requested. */
r_neighbors->coords[duplicate_i + 2] = grid_coord;
duplicate_i++;
}
}
}
/* The corner is at the middle of edge between faces. */
static void neighbor_coords_corner_edge_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
neighbor_coords_edge_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
/* Input coordinate is at one of 4 corners of its grid corners. */
static void neighbor_coords_corner_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
if (coord->x == 0 && coord->y == 0) {
neighbor_coords_corner_center_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_corner_center_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
else {
const int grid_size_1 = subdiv_ccg->grid_size - 1;
if (coord->x == grid_size_1 && coord->y == grid_size_1) {
neighbor_coords_corner_vertex_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_corner_vertex_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
else {
neighbor_coords_corner_edge_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_corner_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
}
}
@ -1635,9 +1679,10 @@ static void neighbor_coords_corner_get(const SubdivCCG *subdiv_ccg,
* other faces. */
static void neighbor_coords_boundary_inner_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
subdiv_ccg_neighbors_init(r_neighbors, 4);
subdiv_ccg_neighbors_init(r_neighbors, 4, (include_duplicates) ? 1 : 0);
if (coord->x == 0) {
r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord);
@ -1647,6 +1692,11 @@ static void neighbor_coords_boundary_inner_get(const SubdivCCG *subdiv_ccg,
r_neighbors->coords[3].grid_index = prev_grid_index_from_coord(subdiv_ccg, coord);
r_neighbors->coords[3].x = coord->y;
r_neighbors->coords[3].y = 1;
if (include_duplicates) {
r_neighbors->coords[4] = r_neighbors->coords[3];
r_neighbors->coords[4].y = 0;
}
}
else if (coord->y == 0) {
r_neighbors->coords[0] = coord_at_prev_col(subdiv_ccg, coord);
@ -1656,15 +1706,21 @@ static void neighbor_coords_boundary_inner_get(const SubdivCCG *subdiv_ccg,
r_neighbors->coords[3].grid_index = next_grid_index_from_coord(subdiv_ccg, coord);
r_neighbors->coords[3].x = 1;
r_neighbors->coords[3].y = coord->x;
if (include_duplicates) {
r_neighbors->coords[4] = r_neighbors->coords[3];
r_neighbors->coords[4].x = 0;
}
}
}
/* Input coordinate is on an edge between two faces. Need to check adjacency. */
static void neighbor_coords_boundary_outer_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
neighbor_coords_edge_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
/* Input coordinate is at one of 4 boundaries of its grid.
@ -1672,13 +1728,14 @@ static void neighbor_coords_boundary_outer_get(const SubdivCCG *subdiv_ccg,
* a part of coarse face edge. */
static void neighbor_coords_boundary_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
if (is_inner_edge_grid_coordinate(subdiv_ccg, coord)) {
neighbor_coords_boundary_inner_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_boundary_inner_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
else {
neighbor_coords_boundary_outer_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_boundary_outer_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
}
@ -1687,7 +1744,7 @@ static void neighbor_coords_inner_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
SubdivCCGNeighbors *r_neighbors)
{
subdiv_ccg_neighbors_init(r_neighbors, 4);
subdiv_ccg_neighbors_init(r_neighbors, 4, 0);
r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord);
r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord);
@ -1697,6 +1754,7 @@ static void neighbor_coords_inner_get(const SubdivCCG *subdiv_ccg,
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors)
{
BLI_assert(coord->grid_index >= 0);
@ -1707,10 +1765,10 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
BLI_assert(coord->y < subdiv_ccg->grid_size);
if (is_corner_grid_coord(subdiv_ccg, coord)) {
neighbor_coords_corner_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_corner_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
else if (is_boundary_grid_coord(subdiv_ccg, coord)) {
neighbor_coords_boundary_get(subdiv_ccg, coord, r_neighbors);
neighbor_coords_boundary_get(subdiv_ccg, coord, include_duplicates, r_neighbors);
}
else {
neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors);

View File

@ -1393,7 +1393,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* Draw pose brush origin */
if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
if (update_previews) {
BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
@ -1446,7 +1446,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* Draw pose brush line preview */
if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) {
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
GPU_line_width(2.0f);
immBegin(GPU_PRIM_LINES, 2);

View File

@ -211,14 +211,19 @@ static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3])
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
/* Storage */
int *neighbors;
int size;
int capacity;
int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
int index;
/* Internal iterator. */
int num_duplicates;
int i;
/* Public */
int index;
bool is_duplicate;
} SculptVertexNeighborIter;
static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index)
@ -254,6 +259,7 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
BMIter liter;
BMLoop *l;
iter->size = 0;
iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
@ -276,6 +282,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
int i;
MeshElemMap *vert_map = &ss->pmap[(int)index];
iter->size = 0;
iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
@ -294,7 +301,8 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
}
static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
int index,
const int index,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
/* TODO: optimize this. We could fill SculptVertexNeighborIter directly,
@ -309,9 +317,10 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
.y = vertex_index / key->grid_size};
SubdivCCGNeighbors neighbors;
BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, &neighbors);
BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors);
iter->size = 0;
iter->num_duplicates = neighbors.num_duplicates;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
@ -327,7 +336,8 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
}
static void sculpt_vertex_neighbors_get(SculptSession *ss,
int index,
const int index,
const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
switch (BKE_pbvh_type(ss->pbvh)) {
@ -338,17 +348,28 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss,
sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
return;
case PBVH_GRIDS:
sculpt_vertex_neighbors_get_grids(ss, index, iter);
sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter);
return;
}
}
/* Iterator over neighboring vertices. */
#define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \
sculpt_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
neighbor_iterator.index = ni.neighbors[ni.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
#define sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
sculpt_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
neighbor_iterator.index = ni.neighbors[ni.i]; \
neighbor_iterator.is_duplicate = (ni.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
#define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
} \
if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
@ -533,22 +554,20 @@ static void sculpt_floodfill_add_active(
static void sculpt_floodfill_execute(
SculptSession *ss,
SculptFloodFill *flood,
bool (*func)(SculptSession *ss, int from_v, int to_v, void *userdata),
bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
void *userdata)
{
/* TODO: multires support, taking into account duplicate vertices and
* correctly handling them in the pose, automask and mask expand callbacks. */
while (!BLI_gsqueue_is_empty(flood->queue)) {
int from_v;
BLI_gsqueue_pop(flood->queue, &from_v);
SculptVertexNeighborIter ni;
sculpt_vertex_neighbors_iter_begin(ss, from_v, ni)
sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni)
{
const int to_v = ni.index;
if (flood->visited_vertices[to_v] == 0) {
flood->visited_vertices[to_v] = 1;
if (func(ss, from_v, to_v, userdata)) {
if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
BLI_gsqueue_push(flood->queue, &to_v);
}
}
@ -1199,11 +1218,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
{
// REMOVE WITH PBVH_GRIDS
if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
return false;
}
if (sculpt_stroke_is_dynamic_topology(ss, br)) {
return false;
}
@ -1252,7 +1266,8 @@ typedef struct AutomaskFloodFillData {
char symm;
} AutomaskFloodFillData;
static bool automask_floodfill_cb(SculptSession *ss, int UNUSED(from_v), int to_v, void *userdata)
static bool automask_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
{
AutomaskFloodFillData *data = userdata;
@ -3638,10 +3653,6 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float pose_initial_co[3];
float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4];
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
return;
}
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
copy_v3_v3(pose_origin, ss->cache->pose_origin);
@ -3816,7 +3827,8 @@ typedef struct PoseFloodFillData {
int tot_co;
} PoseFloodFillData;
static bool pose_floodfill_cb(SculptSession *ss, int UNUSED(from_v), int to_v, void *userdata)
static bool pose_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
@ -3830,8 +3842,10 @@ static bool pose_floodfill_cb(SculptSession *ss, int UNUSED(from_v), int to_v, v
return true;
}
else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) {
add_v3_v3(data->pose_origin, co);
data->tot_co++;
if (!is_duplicate) {
add_v3_v3(data->pose_origin, co);
data->tot_co++;
}
}
return false;
@ -5318,9 +5332,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time &&
ss->cache->mirror_symmetry_pass == 0) {
if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
}
sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
}
/* Apply one type of brush action */
@ -9130,25 +9142,37 @@ typedef struct MaskExpandFloodFillData {
bool use_normals;
} MaskExpandFloodFillData;
static bool mask_expand_floodfill_cb(SculptSession *ss, int from_v, int to_v, void *userdata)
static bool mask_expand_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
{
MaskExpandFloodFillData *data = userdata;
int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
ss->filter_cache->mask_update_it[to_v] = to_it;
if (to_it > ss->filter_cache->mask_update_last_it) {
ss->filter_cache->mask_update_last_it = to_it;
if (!is_duplicate) {
int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
ss->filter_cache->mask_update_it[to_v] = to_it;
if (to_it > ss->filter_cache->mask_update_last_it) {
ss->filter_cache->mask_update_last_it = to_it;
}
if (data->use_normals) {
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 = ss->filter_cache->edge_factor[from_v];
ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
from_edge_factor;
ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) *
powf(from_edge_factor, data->edge_sensitivity);
CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f);
}
}
if (data->use_normals) {
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 = ss->filter_cache->edge_factor[from_v];
ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * from_edge_factor;
ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) *
powf(from_edge_factor, data->edge_sensitivity);
CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f);
else {
/* PBVH_GRIDS duplicate handling */
ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v];
if (data->use_normals) {
ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v];
ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v];
}
}
return true;
@ -9169,10 +9193,6 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
mouse[0] = event->mval[0];
mouse[1] = event->mval[1];
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
return OPERATOR_CANCELLED;
}
sculpt_vertex_random_access_init(ss);
op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");