Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_boundary.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c419
1 files changed, 259 insertions, 160 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index c86e922a347..5e01e034715 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -130,34 +130,39 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
* deformations usually need in the boundary. */
static int BOUNDARY_INDICES_BLOCK_SIZE = 300;
-static void sculpt_boundary_index_add(SculptBoundary *bdata,
+static void sculpt_boundary_index_add(SculptBoundary *boundary,
const int new_index,
+ const float distance,
GSet *included_vertices)
{
- bdata->vertices[bdata->num_vertices] = new_index;
+ boundary->vertices[boundary->num_vertices] = new_index;
+ if (boundary->distance) {
+ boundary->distance[new_index] = distance;
+ }
if (included_vertices) {
BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index));
}
- bdata->num_vertices++;
- if (bdata->num_vertices >= bdata->vertices_capacity) {
- bdata->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
- bdata->vertices = MEM_reallocN_id(
- bdata->vertices, bdata->vertices_capacity * sizeof(int), "boundary indices");
+ boundary->num_vertices++;
+ if (boundary->num_vertices >= boundary->vertices_capacity) {
+ boundary->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
+ boundary->vertices = MEM_reallocN_id(
+ boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices");
}
};
-static void sculpt_boundary_preview_edge_add(SculptBoundary *bdata, const int v1, const int v2)
+static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2)
{
- bdata->edges[bdata->num_edges].v1 = v1;
- bdata->edges[bdata->num_edges].v2 = v2;
- bdata->num_edges++;
+ boundary->edges[boundary->num_edges].v1 = v1;
+ boundary->edges[boundary->num_edges].v2 = v2;
+ boundary->num_edges++;
- if (bdata->num_edges >= bdata->edges_capacity) {
- bdata->edges_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
- bdata->edges = MEM_reallocN_id(
- bdata->edges, bdata->edges_capacity * sizeof(SculptBoundaryPreviewEdge), "boundary edges");
+ if (boundary->num_edges >= boundary->edges_capacity) {
+ boundary->edges_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
+ boundary->edges = MEM_reallocN_id(boundary->edges,
+ boundary->edges_capacity * sizeof(SculptBoundaryPreviewEdge),
+ "boundary edges");
}
};
@@ -199,7 +204,7 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
*/
typedef struct BoundaryFloodFillData {
- SculptBoundary *bdata;
+ SculptBoundary *boundary;
GSet *included_vertices;
EdgeSet *preview_edges;
@@ -211,11 +216,16 @@ static bool boundary_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
{
BoundaryFloodFillData *data = userdata;
- SculptBoundary *bdata = data->bdata;
+ SculptBoundary *boundary = data->boundary;
if (SCULPT_vertex_is_boundary(ss, to_v)) {
- sculpt_boundary_index_add(bdata, to_v, data->included_vertices);
+ const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v),
+ SCULPT_vertex_co_get(ss, to_v));
+ const float distance_boundary_to_dst = boundary->distance ?
+ boundary->distance[from_v] + edge_len :
+ 0.0f;
+ sculpt_boundary_index_add(boundary, to_v, distance_boundary_to_dst, data->included_vertices);
if (!is_duplicate) {
- sculpt_boundary_preview_edge_add(bdata, from_v, to_v);
+ sculpt_boundary_preview_edge_add(boundary, from_v, to_v);
}
return sculpt_boundary_is_vertex_in_editable_boundary(ss, to_v);
}
@@ -223,26 +233,32 @@ static bool boundary_floodfill_cb(
}
static void sculpt_boundary_indices_init(SculptSession *ss,
- SculptBoundary *bdata,
+ SculptBoundary *boundary,
+ const bool init_boundary_distances,
const int initial_boundary_index)
{
- bdata->vertices = MEM_malloc_arrayN(
+ const int totvert = SCULPT_vertex_count_get(ss);
+ boundary->vertices = MEM_malloc_arrayN(
BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices");
- bdata->edges = MEM_malloc_arrayN(
+ if (init_boundary_distances) {
+ boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances");
+ }
+ boundary->edges = MEM_malloc_arrayN(
BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptBoundaryPreviewEdge), "boundary edges");
GSet *included_vertices = BLI_gset_int_new_ex("included vertices", BOUNDARY_INDICES_BLOCK_SIZE);
SculptFloodFill flood;
SCULPT_floodfill_init(ss, &flood);
- bdata->initial_vertex = initial_boundary_index;
- copy_v3_v3(bdata->initial_vertex_position, SCULPT_vertex_co_get(ss, bdata->initial_vertex));
- sculpt_boundary_index_add(bdata, initial_boundary_index, included_vertices);
+ boundary->initial_vertex = initial_boundary_index;
+ copy_v3_v3(boundary->initial_vertex_position,
+ SCULPT_vertex_co_get(ss, boundary->initial_vertex));
+ sculpt_boundary_index_add(boundary, initial_boundary_index, 0.0f, included_vertices);
SCULPT_floodfill_add_initial(&flood, initial_boundary_index);
BoundaryFloodFillData fdata = {
- .bdata = bdata,
+ .boundary = boundary,
.included_vertices = included_vertices,
.last_visited_vertex = BOUNDARY_VERTEX_NONE,
@@ -258,8 +274,8 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, fdata.last_visited_vertex, ni) {
if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.index)) &&
sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.index)) {
- sculpt_boundary_preview_edge_add(bdata, fdata.last_visited_vertex, ni.index);
- bdata->forms_loop = true;
+ sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.index);
+ boundary->forms_loop = true;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@@ -275,7 +291,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
* the closest one.
*/
static void sculpt_boundary_edit_data_init(SculptSession *ss,
- SculptBoundary *bdata,
+ SculptBoundary *boundary,
const int initial_vertex,
const float radius)
{
@@ -283,12 +299,12 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
const bool has_duplicates = BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
- bdata->edit_info = MEM_malloc_arrayN(
+ boundary->edit_info = MEM_malloc_arrayN(
totvert, sizeof(SculptBoundaryEditInfo), "Boundary edit info");
for (int i = 0; i < totvert; i++) {
- bdata->edit_info[i].original_vertex = BOUNDARY_VERTEX_NONE;
- bdata->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE;
+ boundary->edit_info[i].original_vertex = BOUNDARY_VERTEX_NONE;
+ boundary->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE;
}
GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int));
@@ -297,23 +313,23 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Initialized the first iteration with the vertices already in the boundary. This is propagation
* step 0. */
BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
- for (int i = 0; i < bdata->num_vertices; i++) {
- bdata->edit_info[bdata->vertices[i]].original_vertex = bdata->vertices[i];
- bdata->edit_info[bdata->vertices[i]].num_propagation_steps = 0;
+ for (int i = 0; i < boundary->num_vertices; i++) {
+ boundary->edit_info[boundary->vertices[i]].original_vertex = boundary->vertices[i];
+ boundary->edit_info[boundary->vertices[i]].num_propagation_steps = 0;
/* This ensures that all duplicate vertices in the boundary have the same original_vertex
* index, so the deformation for them will be the same. */
if (has_duplicates) {
SculptVertexNeighborIter ni_duplis;
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, bdata->vertices[i], ni_duplis) {
+ SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->vertices[i], ni_duplis) {
if (ni_duplis.is_duplicate) {
- bdata->edit_info[ni_duplis.index].original_vertex = bdata->vertices[i];
+ boundary->edit_info[ni_duplis.index].original_vertex = boundary->vertices[i];
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
}
- BLI_gsqueue_push(current_iteration, &bdata->vertices[i]);
+ BLI_gsqueue_push(current_iteration, &boundary->vertices[i]);
}
int num_propagation_steps = 0;
@@ -323,7 +339,7 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* This steps is further away from the boundary than the brush radius, so stop adding more
* steps. */
if (accum_distance > radius) {
- bdata->max_propagation_steps = num_propagation_steps;
+ boundary->max_propagation_steps = num_propagation_steps;
break;
}
@@ -333,19 +349,20 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- if (bdata->edit_info[ni.index].num_propagation_steps == BOUNDARY_STEPS_NONE) {
- bdata->edit_info[ni.index].original_vertex = bdata->edit_info[from_v].original_vertex;
+ if (boundary->edit_info[ni.index].num_propagation_steps == BOUNDARY_STEPS_NONE) {
+ boundary->edit_info[ni.index].original_vertex =
+ boundary->edit_info[from_v].original_vertex;
BLI_BITMAP_ENABLE(visited_vertices, ni.index);
if (ni.is_duplicate) {
/* Grids duplicates handling. */
- bdata->edit_info[ni.index].num_propagation_steps =
- bdata->edit_info[from_v].num_propagation_steps;
+ boundary->edit_info[ni.index].num_propagation_steps =
+ boundary->edit_info[from_v].num_propagation_steps;
}
else {
- bdata->edit_info[ni.index].num_propagation_steps =
- bdata->edit_info[from_v].num_propagation_steps + 1;
+ boundary->edit_info[ni.index].num_propagation_steps =
+ boundary->edit_info[from_v].num_propagation_steps + 1;
BLI_gsqueue_push(next_iteration, &ni.index);
@@ -357,10 +374,10 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptVertexNeighborIter ni_duplis;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.index, ni_duplis) {
if (ni_duplis.is_duplicate) {
- bdata->edit_info[ni_duplis.index].original_vertex =
- bdata->edit_info[from_v].original_vertex;
- bdata->edit_info[ni_duplis.index].num_propagation_steps =
- bdata->edit_info[from_v].num_propagation_steps + 1;
+ boundary->edit_info[ni_duplis.index].original_vertex =
+ boundary->edit_info[from_v].original_vertex;
+ boundary->edit_info[ni_duplis.index].num_propagation_steps =
+ boundary->edit_info[from_v].num_propagation_steps + 1;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
@@ -368,9 +385,9 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Check the distance using the vertex that was propagated from the initial vertex that
* was used to initialize the boundary. */
- if (bdata->edit_info[from_v].original_vertex == initial_vertex) {
- bdata->pivot_vertex = ni.index;
- copy_v3_v3(bdata->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.index));
+ if (boundary->edit_info[from_v].original_vertex == initial_vertex) {
+ boundary->pivot_vertex = ni.index;
+ copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.index));
accum_distance += len_v3v3(SCULPT_vertex_co_get(ss, from_v),
SCULPT_vertex_co_get(ss, ni.index));
}
@@ -406,23 +423,67 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
* on the brush curve and its propagation steps. The falloff goes from the boundary into the mesh.
*/
static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
- SculptBoundary *bdata,
- Brush *brush)
+ SculptBoundary *boundary,
+ Brush *brush,
+ const float radius)
{
const int totvert = SCULPT_vertex_count_get(ss);
BKE_curvemapping_init(brush->curve);
for (int i = 0; i < totvert; i++) {
- if (bdata->edit_info[i].num_propagation_steps != -1) {
- bdata->edit_info[i].strength_factor = BKE_brush_curve_strength(
- brush, bdata->edit_info[i].num_propagation_steps, bdata->max_propagation_steps);
+ if (boundary->edit_info[i].num_propagation_steps != -1) {
+ boundary->edit_info[i].strength_factor = BKE_brush_curve_strength(
+ brush, boundary->edit_info[i].num_propagation_steps, boundary->max_propagation_steps);
+ }
+
+ if (boundary->edit_info[i].original_vertex == boundary->initial_vertex) {
+ /* All vertices that are propagated from the original vertex won't be affected by the
+ * boundary falloff, so there is no need to calculate anything else. */
+ continue;
+ }
+
+ if (!boundary->distance) {
+ /* There are falloff modes that do not require to modify the previously calculated falloff
+ * based on boundary distances. */
+ continue;
+ }
+
+ const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex];
+ float falloff_distance = 0.0f;
+ float direction = 1.0f;
+
+ switch (brush->boundary_falloff_type) {
+ case BRUSH_BOUNDARY_FALLOFF_RADIUS:
+ falloff_distance = boundary_distance;
+ break;
+ case BRUSH_BOUNDARY_FALLOFF_LOOP: {
+ const int div = boundary_distance / radius;
+ const float mod = fmodf(boundary_distance, radius);
+ falloff_distance = div % 2 == 0 ? mod : radius - mod;
+ } break;
+ case BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT: {
+ const int div = boundary_distance / radius;
+ const float mod = fmodf(boundary_distance, radius);
+ falloff_distance = div % 2 == 0 ? mod : radius - mod;
+ /* Inverts the faloff in the intervals 1 2 5 6 9 10 ... */
+ if (((div - 1) & 2) == 0) {
+ direction = -1.0f;
+ }
+ } break;
+ case BRUSH_BOUNDARY_FALLOFF_CONSTANT:
+ /* For constant falloff distances are not allocated, so this should never happen. */
+ BLI_assert(false);
}
+
+ boundary->edit_info[i].strength_factor *= direction * BKE_brush_curve_strength(
+ brush, falloff_distance, radius);
}
}
/* Main function to get SculptBoundary data both for brush deformation and viewport preview. Can
* return NULL if there is no boundary from the given vertex using the given radius. */
SculptBoundary *SCULPT_boundary_data_init(Object *object,
+ Brush *brush,
const int initial_vertex,
const float radius)
{
@@ -444,111 +505,118 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object,
return NULL;
}
- SculptBoundary *bdata = MEM_callocN(sizeof(SculptBoundary), "Boundary edit data");
+ SculptBoundary *boundary = MEM_callocN(sizeof(SculptBoundary), "Boundary edit data");
+
+ const bool init_boundary_distances = brush->boundary_falloff_type !=
+ BRUSH_BOUNDARY_FALLOFF_CONSTANT;
+ sculpt_boundary_indices_init(ss, boundary, init_boundary_distances, boundary_initial_vertex);
- sculpt_boundary_indices_init(ss, bdata, boundary_initial_vertex);
- sculpt_boundary_edit_data_init(ss, bdata, boundary_initial_vertex, radius);
+ const float boundary_radius = radius * (1.0f + brush->boundary_offset);
+ sculpt_boundary_edit_data_init(ss, boundary, boundary_initial_vertex, boundary_radius);
- return bdata;
+ return boundary;
}
-void SCULPT_boundary_data_free(SculptBoundary *bdata)
+void SCULPT_boundary_data_free(SculptBoundary *boundary)
{
- MEM_SAFE_FREE(bdata->vertices);
- MEM_SAFE_FREE(bdata->edit_info);
- MEM_SAFE_FREE(bdata->bend.pivot_positions);
- MEM_SAFE_FREE(bdata->bend.pivot_rotation_axis);
- MEM_SAFE_FREE(bdata->slide.directions);
- MEM_SAFE_FREE(bdata);
+ MEM_SAFE_FREE(boundary->vertices);
+ MEM_SAFE_FREE(boundary->distance);
+ MEM_SAFE_FREE(boundary->edit_info);
+ MEM_SAFE_FREE(boundary->bend.pivot_positions);
+ MEM_SAFE_FREE(boundary->bend.pivot_rotation_axis);
+ MEM_SAFE_FREE(boundary->slide.directions);
+ MEM_SAFE_FREE(boundary);
}
/* These functions initialize the required vectors for the desired deformation using the
* SculptBoundaryEditInfo. They calculate the data using the vertices that have the
* max_propagation_steps value and them this data is copied to the rest of the vertices using the
* original vertex index. */
-static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bdata)
+static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *boundary)
{
const int totvert = SCULPT_vertex_count_get(ss);
- bdata->bend.pivot_rotation_axis = MEM_calloc_arrayN(
+ boundary->bend.pivot_rotation_axis = MEM_calloc_arrayN(
totvert, 3 * sizeof(float), "pivot rotation axis");
- bdata->bend.pivot_positions = MEM_calloc_arrayN(totvert, 3 * sizeof(float), "pivot positions");
+ boundary->bend.pivot_positions = MEM_calloc_arrayN(
+ totvert, 3 * sizeof(float), "pivot positions");
for (int i = 0; i < totvert; i++) {
- if (bdata->edit_info[i].num_propagation_steps == bdata->max_propagation_steps) {
+ if (boundary->edit_info[i].num_propagation_steps == boundary->max_propagation_steps) {
float dir[3];
float normal[3];
SCULPT_vertex_normal_get(ss, i, normal);
sub_v3_v3v3(dir,
- SCULPT_vertex_co_get(ss, bdata->edit_info[i].original_vertex),
+ SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
SCULPT_vertex_co_get(ss, i));
cross_v3_v3v3(
- bdata->bend.pivot_rotation_axis[bdata->edit_info[i].original_vertex], dir, normal);
- normalize_v3(bdata->bend.pivot_rotation_axis[bdata->edit_info[i].original_vertex]);
- copy_v3_v3(bdata->bend.pivot_positions[bdata->edit_info[i].original_vertex],
+ boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex], dir, normal);
+ normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
+ copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex],
SCULPT_vertex_co_get(ss, i));
}
}
for (int i = 0; i < totvert; i++) {
- if (bdata->edit_info[i].num_propagation_steps != BOUNDARY_STEPS_NONE) {
- copy_v3_v3(bdata->bend.pivot_positions[i],
- bdata->bend.pivot_positions[bdata->edit_info[i].original_vertex]);
- copy_v3_v3(bdata->bend.pivot_rotation_axis[i],
- bdata->bend.pivot_rotation_axis[bdata->edit_info[i].original_vertex]);
+ if (boundary->edit_info[i].num_propagation_steps != BOUNDARY_STEPS_NONE) {
+ copy_v3_v3(boundary->bend.pivot_positions[i],
+ boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex]);
+ copy_v3_v3(boundary->bend.pivot_rotation_axis[i],
+ boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
}
}
}
-static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *bdata)
+static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *boundary)
{
const int totvert = SCULPT_vertex_count_get(ss);
- bdata->slide.directions = MEM_calloc_arrayN(totvert, 3 * sizeof(float), "slide directions");
+ boundary->slide.directions = MEM_calloc_arrayN(totvert, 3 * sizeof(float), "slide directions");
for (int i = 0; i < totvert; i++) {
- if (bdata->edit_info[i].num_propagation_steps == bdata->max_propagation_steps) {
- sub_v3_v3v3(bdata->slide.directions[bdata->edit_info[i].original_vertex],
- SCULPT_vertex_co_get(ss, bdata->edit_info[i].original_vertex),
+ if (boundary->edit_info[i].num_propagation_steps == boundary->max_propagation_steps) {
+ sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex],
+ SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
SCULPT_vertex_co_get(ss, i));
- normalize_v3(bdata->slide.directions[bdata->edit_info[i].original_vertex]);
+ normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex]);
}
}
for (int i = 0; i < totvert; i++) {
- if (bdata->edit_info[i].num_propagation_steps != BOUNDARY_STEPS_NONE) {
- copy_v3_v3(bdata->slide.directions[i],
- bdata->slide.directions[bdata->edit_info[i].original_vertex]);
+ if (boundary->edit_info[i].num_propagation_steps != BOUNDARY_STEPS_NONE) {
+ copy_v3_v3(boundary->slide.directions[i],
+ boundary->slide.directions[boundary->edit_info[i].original_vertex]);
}
}
}
-static void sculpt_boundary_twist_data_init(SculptSession *ss, SculptBoundary *bdata)
+static void sculpt_boundary_twist_data_init(SculptSession *ss, SculptBoundary *boundary)
{
- zero_v3(bdata->twist.pivot_position);
- float(*poly_verts)[3] = MEM_malloc_arrayN(bdata->num_vertices, sizeof(float) * 3, "poly verts");
- for (int i = 0; i < bdata->num_vertices; i++) {
- add_v3_v3(bdata->twist.pivot_position, SCULPT_vertex_co_get(ss, bdata->vertices[i]));
- copy_v3_v3(poly_verts[i], SCULPT_vertex_co_get(ss, bdata->vertices[i]));
+ zero_v3(boundary->twist.pivot_position);
+ float(*poly_verts)[3] = MEM_malloc_arrayN(
+ boundary->num_vertices, sizeof(float) * 3, "poly verts");
+ for (int i = 0; i < boundary->num_vertices; i++) {
+ add_v3_v3(boundary->twist.pivot_position, SCULPT_vertex_co_get(ss, boundary->vertices[i]));
+ copy_v3_v3(poly_verts[i], SCULPT_vertex_co_get(ss, boundary->vertices[i]));
}
- mul_v3_fl(bdata->twist.pivot_position, 1.0f / bdata->num_vertices);
- if (bdata->forms_loop) {
- normal_poly_v3(bdata->twist.rotation_axis, poly_verts, bdata->num_vertices);
+ mul_v3_fl(boundary->twist.pivot_position, 1.0f / boundary->num_vertices);
+ if (boundary->forms_loop) {
+ normal_poly_v3(boundary->twist.rotation_axis, poly_verts, boundary->num_vertices);
}
else {
- sub_v3_v3v3(bdata->twist.rotation_axis,
- SCULPT_vertex_co_get(ss, bdata->pivot_vertex),
- SCULPT_vertex_co_get(ss, bdata->initial_vertex));
- normalize_v3(bdata->twist.rotation_axis);
+ sub_v3_v3v3(boundary->twist.rotation_axis,
+ SCULPT_vertex_co_get(ss, boundary->pivot_vertex),
+ SCULPT_vertex_co_get(ss, boundary->initial_vertex));
+ normalize_v3(boundary->twist.rotation_axis);
}
MEM_freeN(poly_verts);
}
static float sculpt_boundary_displacement_from_grab_delta_get(SculptSession *ss,
- SculptBoundary *bdata)
+ SculptBoundary *boundary)
{
float plane[4];
float pos[3];
float normal[3];
- sub_v3_v3v3(normal, ss->cache->initial_location, bdata->initial_pivot_position);
+ sub_v3_v3v3(normal, ss->cache->initial_location, boundary->initial_pivot_position);
normalize_v3(normal);
plane_from_point_normal_v3(plane, ss->cache->initial_location, normal);
add_v3_v3v3(pos, ss->cache->initial_location, ss->cache->grab_delta_symmetry);
@@ -563,7 +631,9 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
const int symm_area = ss->cache->mirror_symmetry_pass;
- SculptBoundary *bdata = ss->cache->bdata[symm_area];
+ SculptBoundary *boundary = ss->cache->boundaries[symm_area];
+ const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const Brush *brush = data->brush;
const float strength = ss->cache->bstrength;
@@ -571,7 +641,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, bdata);
+ const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
/* Angle Snapping when inverting the brush. */
if (ss->cache->invert) {
@@ -582,16 +652,20 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (bdata->edit_info[vd.index].num_propagation_steps != -1) {
+ if (boundary->edit_info[vd.index].num_propagation_steps != -1) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- float t_orig_co[3];
- sub_v3_v3v3(t_orig_co, orig_data.co, bdata->bend.pivot_positions[vd.index]);
- rotate_v3_v3v3fl(vd.co,
- t_orig_co,
- bdata->bend.pivot_rotation_axis[vd.index],
- angle * bdata->edit_info[vd.index].strength_factor * mask);
- add_v3_v3(vd.co, bdata->bend.pivot_positions[vd.index]);
+ if (SCULPT_check_vertex_pivot_symmetry(
+ orig_data.co, boundary->initial_vertex_position, symm)) {
+ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
+ float t_orig_co[3];
+ float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
+ sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]);
+ rotate_v3_v3v3fl(target_co,
+ t_orig_co,
+ boundary->bend.pivot_rotation_axis[vd.index],
+ angle * boundary->edit_info[vd.index].strength_factor * mask);
+ add_v3_v3(target_co, boundary->bend.pivot_positions[vd.index]);
+ }
}
if (vd.mvert) {
@@ -608,7 +682,9 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
const int symm_area = ss->cache->mirror_symmetry_pass;
- SculptBoundary *bdata = ss->cache->bdata[symm_area];
+ SculptBoundary *boundary = ss->cache->boundaries[symm_area];
+ const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const Brush *brush = data->brush;
const float strength = ss->cache->bstrength;
@@ -616,18 +692,22 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, bdata);
+ const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (bdata->edit_info[vd.index].num_propagation_steps != -1) {
+ if (boundary->edit_info[vd.index].num_propagation_steps != -1) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- madd_v3_v3v3fl(vd.co,
- orig_data.co,
- bdata->slide.directions[vd.index],
- bdata->edit_info[vd.index].strength_factor * disp * mask * strength);
+ if (SCULPT_check_vertex_pivot_symmetry(
+ orig_data.co, boundary->initial_vertex_position, symm)) {
+ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
+ float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
+ madd_v3_v3v3fl(target_co,
+ orig_data.co,
+ boundary->slide.directions[vd.index],
+ boundary->edit_info[vd.index].strength_factor * disp * mask * strength);
+ }
}
if (vd.mvert) {
@@ -644,7 +724,9 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
const int symm_area = ss->cache->mirror_symmetry_pass;
- SculptBoundary *bdata = ss->cache->bdata[symm_area];
+ SculptBoundary *boundary = ss->cache->boundaries[symm_area];
+ const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const Brush *brush = data->brush;
const float strength = ss->cache->bstrength;
@@ -652,20 +734,24 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, bdata);
+ const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (bdata->edit_info[vd.index].num_propagation_steps != -1) {
+ if (boundary->edit_info[vd.index].num_propagation_steps != -1) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- float normal[3];
- normal_short_to_float_v3(normal, orig_data.no);
- madd_v3_v3v3fl(vd.co,
- orig_data.co,
- normal,
- bdata->edit_info[vd.index].strength_factor * disp * mask * strength);
+ if (SCULPT_check_vertex_pivot_symmetry(
+ orig_data.co, boundary->initial_vertex_position, symm)) {
+ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
+ float normal[3];
+ normal_short_to_float_v3(normal, orig_data.no);
+ float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
+ madd_v3_v3v3fl(target_co,
+ orig_data.co,
+ normal,
+ boundary->edit_info[vd.index].strength_factor * disp * mask * strength);
+ }
}
if (vd.mvert) {
@@ -682,7 +768,9 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
const int symm_area = ss->cache->mirror_symmetry_pass;
- SculptBoundary *bdata = ss->cache->bdata[symm_area];
+ SculptBoundary *boundary = ss->cache->boundaries[symm_area];
+ const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const Brush *brush = data->brush;
const float strength = ss->cache->bstrength;
@@ -693,13 +781,17 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (bdata->edit_info[vd.index].num_propagation_steps != -1) {
+ if (boundary->edit_info[vd.index].num_propagation_steps != -1) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
- madd_v3_v3v3fl(vd.co,
- orig_data.co,
- ss->cache->grab_delta_symmetry,
- bdata->edit_info[vd.index].strength_factor * mask * strength);
+ if (SCULPT_check_vertex_pivot_symmetry(
+ orig_data.co, boundary->initial_vertex_position, symm)) {
+ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
+ float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
+ madd_v3_v3v3fl(target_co,
+ orig_data.co,
+ ss->cache->grab_delta_symmetry,
+ boundary->edit_info[vd.index].strength_factor * mask * strength);
+ }
}
if (vd.mvert) {
@@ -716,7 +808,9 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
const int symm_area = ss->cache->mirror_symmetry_pass;
- SculptBoundary *bdata = ss->cache->bdata[symm_area];
+ SculptBoundary *boundary = ss->cache->boundaries[symm_area];
+ const ePaintSymmetryFlags symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const Brush *brush = data->brush;
const float strength = ss->cache->bstrength;
@@ -724,7 +818,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, bdata);
+ const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
/* Angle Snapping when inverting the brush. */
if (ss->cache->invert) {
@@ -735,16 +829,20 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (bdata->edit_info[vd.index].num_propagation_steps != -1) {
- const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
+ if (boundary->edit_info[vd.index].num_propagation_steps != -1) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- float t_orig_co[3];
- sub_v3_v3v3(t_orig_co, orig_data.co, bdata->twist.pivot_position);
- rotate_v3_v3v3fl(vd.co,
- t_orig_co,
- bdata->twist.rotation_axis,
- angle * mask * bdata->edit_info[vd.index].strength_factor);
- add_v3_v3(vd.co, bdata->twist.pivot_position);
+ if (SCULPT_check_vertex_pivot_symmetry(
+ orig_data.co, boundary->initial_vertex_position, symm)) {
+ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
+ float t_orig_co[3];
+ float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
+ sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position);
+ rotate_v3_v3v3fl(target_co,
+ t_orig_co,
+ boundary->twist.rotation_axis,
+ angle * mask * boundary->edit_info[vd.index].strength_factor);
+ add_v3_v3(target_co, boundary->twist.pivot_position);
+ }
}
if (vd.mvert) {
@@ -774,20 +872,20 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
sd, ob, location, ss->cache->radius_squared, false);
}
- ss->cache->bdata[symm_area] = SCULPT_boundary_data_init(
- ob, initial_vertex, ss->cache->initial_radius);
+ ss->cache->boundaries[symm_area] = SCULPT_boundary_data_init(
+ ob, brush, initial_vertex, ss->cache->initial_radius);
- if (ss->cache->bdata[symm_area]) {
+ if (ss->cache->boundaries[symm_area]) {
switch (brush->boundary_deform_type) {
case BRUSH_BOUNDARY_DEFORM_BEND:
- sculpt_boundary_bend_data_init(ss, ss->cache->bdata[symm_area]);
+ sculpt_boundary_bend_data_init(ss, ss->cache->boundaries[symm_area]);
break;
case BRUSH_BOUNDARY_DEFORM_EXPAND:
- sculpt_boundary_slide_data_init(ss, ss->cache->bdata[symm_area]);
+ sculpt_boundary_slide_data_init(ss, ss->cache->boundaries[symm_area]);
break;
case BRUSH_BOUNDARY_DEFORM_TWIST:
- sculpt_boundary_twist_data_init(ss, ss->cache->bdata[symm_area]);
+ sculpt_boundary_twist_data_init(ss, ss->cache->boundaries[symm_area]);
break;
case BRUSH_BOUNDARY_DEFORM_INFLATE:
case BRUSH_BOUNDARY_DEFORM_GRAB:
@@ -795,12 +893,13 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
break;
}
- sculpt_boundary_falloff_factor_init(ss, ss->cache->bdata[symm_area], brush);
+ sculpt_boundary_falloff_factor_init(
+ ss, ss->cache->boundaries[symm_area], brush, ss->cache->initial_radius);
}
}
/* No active boundary under the cursor. */
- if (!ss->cache->bdata[symm_area]) {
+ if (!ss->cache->boundaries[symm_area]) {
return;
}