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')
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c203
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c17
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c12
12 files changed, 202 insertions, 81 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 892aea6048f..be7b824fc3e 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -875,8 +875,12 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
return alpha_overlay_active;
}
-BLI_INLINE void draw_tri_point(
- uint pos, const float sel_col[4], float pivot_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_tri_point(uint pos,
+ const float sel_col[4],
+ const float pivot_col[4],
+ float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : pivot_col);
@@ -905,8 +909,12 @@ BLI_INLINE void draw_tri_point(
immEnd();
}
-BLI_INLINE void draw_rect_point(
- uint pos, const float sel_col[4], float handle_col[4], float *co, float width, bool selected)
+BLI_INLINE void draw_rect_point(uint pos,
+ const float sel_col[4],
+ const float handle_col[4],
+ const float *co,
+ float width,
+ bool selected)
{
immUniformColor4fv(selected ? sel_col : handle_col);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 16ccfaf8286..a7f09390a3d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -257,7 +257,7 @@ static ushort *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size
/* update rectangular section of the brush image */
static void brush_painter_mask_imbuf_update(BrushPainter *painter,
ImagePaintTile *tile,
- ushort *tex_mask_old,
+ const ushort *tex_mask_old,
int origx,
int origy,
int w,
@@ -1052,7 +1052,7 @@ static void paint_2d_lift_soften(ImagePaintState *s,
ImagePaintTile *tile,
ImBuf *ibuf,
ImBuf *ibufb,
- int *pos,
+ const int *pos,
const short paint_tile)
{
bool sharpen = (tile->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
@@ -1255,7 +1255,7 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short paint
}
}
-static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, const int *pos)
{
/* note: allocImbuf returns zero'd memory, so regions outside image will
* have zero alpha, and hence not be blended onto the image */
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 83620b4bc56..5af3a3f4241 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -1426,7 +1426,7 @@ static void insert_seam_vert_array(const ProjPaintState *ps,
* Be tricky with flags, first 4 bits are #PROJ_FACE_SEAM0 to 4,
* last 4 bits are #PROJ_FACE_NOSEAM0 to 4. `1 << i` - where i is `(0..3)`.
*
- * If we're multithreadng, make sure threads are locked when this is called.
+ * If we're multi-threading, make sure threads are locked when this is called.
*/
static void project_face_seams_init(const ProjPaintState *ps,
MemArena *arena,
@@ -3566,8 +3566,8 @@ static bool project_bucket_face_isect(ProjPaintState *ps,
int bucket_y,
const MLoopTri *lt)
{
- /* TODO - replace this with a tricker method that uses sideofline for all
- * screenCoords's edges against the closest bucket corner */
+ /* TODO - replace this with a trickier method that uses side-of-line for all
+ * #ProjPaintState.screenCoords edges against the closest bucket corner. */
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
rctf bucket_bounds;
float p1[2], p2[2], p3[2], p4[2];
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index be545600e6e..d65f158174f 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -246,7 +246,11 @@ static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
color = BKE_palette_color_add(palette);
palette->active_color = BLI_listbase_count(&palette->colors) - 1;
- if (ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX)) {
+ if (ELEM(mode,
+ PAINT_MODE_TEXTURE_3D,
+ PAINT_MODE_TEXTURE_2D,
+ PAINT_MODE_VERTEX,
+ PAINT_MODE_SCULPT)) {
copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
color->value = 0.0;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 048f11c92d7..d05b1673c9a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -206,7 +206,7 @@ void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
/** \name Smooth Vertex Colors Operator
* \{ */
-static void vertex_color_smooth_looptag(Mesh *me, bool *mlooptag)
+static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
{
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const MPoly *mp;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 6d83e88b556..ffdf2c1e7c0 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -547,28 +547,81 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
}
}
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
+static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES: {
- MeshElemMap *vert_map = &ss->pmap[index];
- int face_set = -1;
- for (int i = 0; i < ss->pmap[index].count; i++) {
- if (face_set == -1) {
- face_set = abs(ss->face_sets[vert_map->indices[i]]);
+ MeshElemMap *vert_map = &ss->pmap[index];
+ int face_set = -1;
+ for (int i = 0; i < ss->pmap[index].count; i++) {
+ if (face_set == -1) {
+ face_set = abs(ss->face_sets[vert_map->indices[i]]);
+ }
+ else {
+ if (abs(ss->face_sets[vert_map->indices[i]]) != face_set) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * Checks if the face sets of the adjacent faces to the edge between \a v1 and \a v2
+ * in the base mesh are equal.
+ */
+static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss, int v1, int v2)
+{
+ MeshElemMap *vert_map = &ss->pmap[v1];
+ int p1 = -1, p2 = -1;
+ for (int i = 0; i < ss->pmap[v1].count; i++) {
+ MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ for (int l = 0; l < p->totloop; l++) {
+ MLoop *loop = &ss->mloop[p->loopstart + l];
+ if (loop->v == v2) {
+ if (p1 == -1) {
+ p1 = vert_map->indices[i];
+ break;
}
- else {
- if (abs(ss->face_sets[vert_map->indices[i]]) != face_set) {
- return false;
- }
+ else if (p2 == -1) {
+ p2 = vert_map->indices[i];
+ break;
}
}
- return true;
+ }
+ }
+
+ if (p1 != -1 && p2 != -1) {
+ return abs(ss->face_sets[p1]) == (ss->face_sets[p2]);
+ }
+ return true;
+}
+
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES: {
+ return sculpt_check_unique_face_set_in_base_mesh(ss, index);
}
case PBVH_BMESH:
return false;
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ const SubdivCCGCoord coord = {.grid_index = grid_index,
+ .x = vertex_index % key->grid_size,
+ .y = vertex_index / key->grid_size};
+ int v1, v2;
+ const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
+ ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
+ switch (adjacency) {
+ case SUBDIV_CCG_ADJACENT_VERTEX:
+ return sculpt_check_unique_face_set_in_base_mesh(ss, v1);
+ case SUBDIV_CCG_ADJACENT_EDGE:
+ return sculpt_check_unique_face_set_for_edge_in_base_mesh(ss, v1, v2);
+ case SUBDIV_CCG_ADJACENT_NONE:
+ return true;
+ }
+ }
}
return false;
}
@@ -735,44 +788,64 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss,
}
}
+static bool sculpt_check_boundary_vertex_in_base_mesh(SculptSession *ss, const int index)
+{
+ const MeshElemMap *vert_map = &ss->pmap[index];
+ if (vert_map->count <= 1) {
+ return true;
+ }
+ for (int i = 0; i < vert_map->count; i++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ unsigned f_adj_v[2];
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
+ int j;
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+ if (!(vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
- const MeshElemMap *vert_map = &ss->pmap[index];
-
- if (vert_map->count <= 1) {
- return false;
- }
-
if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) {
- return false;
- }
-
- for (int i = 0; i < vert_map->count; i++) {
- const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- unsigned f_adj_v[2];
- if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
- int j;
- for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (!(vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2)) {
- return false;
- }
- }
- }
+ return true;
}
- return true;
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, index);
}
case PBVH_BMESH: {
BMVert *v = BM_vert_at_index(ss->bm, index);
return BM_vert_is_boundary(v);
}
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ const SubdivCCGCoord coord = {.grid_index = grid_index,
+ .x = vertex_index % key->grid_size,
+ .y = vertex_index / key->grid_size};
+ int v1, v2;
+ const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get(
+ ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2);
+ switch (adjacency) {
+ case SUBDIV_CCG_ADJACENT_VERTEX:
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, v1);
+ case SUBDIV_CCG_ADJACENT_EDGE:
+ return sculpt_check_boundary_vertex_in_base_mesh(ss, v1) &&
+ sculpt_check_boundary_vertex_in_base_mesh(ss, v2);
+ case SUBDIV_CCG_ADJACENT_NONE:
+ return false;
+ }
+ }
}
- return true;
+ return false;
}
/* Utilities */
@@ -2400,7 +2473,10 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
}
float t[3], bb_min[3], bb_max[3];
- if (data->ignore_fully_masked) {
+ if (data->ignore_fully_ineffective) {
+ if (BKE_pbvh_node_fully_hidden_get(node)) {
+ return false;
+ }
if (BKE_pbvh_node_fully_masked_get(node)) {
return false;
}
@@ -2436,7 +2512,7 @@ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
SculptSearchCircleData *data = data_v;
float bb_min[3], bb_max[3];
- if (data->ignore_fully_masked) {
+ if (data->ignore_fully_ineffective) {
if (BKE_pbvh_node_fully_masked_get(node)) {
return false;
}
@@ -2489,7 +2565,7 @@ static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
.sd = sd,
.radius_squared = ss->cursor_radius,
.original = use_original,
- .ignore_fully_masked = false,
+ .ignore_fully_ineffective = false,
.center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
@@ -2514,7 +2590,7 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
.sd = sd,
.radius_squared = square_f(ss->cache->radius * radius_scale),
.original = use_original,
- .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
+ .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
.center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode);
@@ -2530,7 +2606,7 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
ss->cursor_radius,
.original = use_original,
.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
- .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
+ .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode);
}
@@ -5387,11 +5463,15 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
if (brush->sculpt_tool == SCULPT_TOOL_PAINT && type != PBVH_FACES) {
- return;
+ if (!U.experimental.use_sculpt_vertex_colors) {
+ return;
+ }
}
if (brush->sculpt_tool == SCULPT_TOOL_SMEAR && type != PBVH_FACES) {
- return;
+ if (!U.experimental.use_sculpt_vertex_colors) {
+ return;
+ }
}
/* Build a list of all nodes that are potentially within the brush's area of influence */
@@ -5411,7 +5491,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.sd = sd,
.radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)),
.original = false,
- .ignore_fully_masked = false,
+ .ignore_fully_ineffective = false,
.center = ss->cache->initial_location,
};
BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode);
@@ -6046,6 +6126,14 @@ bool SCULPT_mode_poll(bContext *C)
return ob && ob->mode & OB_MODE_SCULPT;
}
+bool SCULPT_vertex_colors_poll(bContext *C)
+{
+ if (!U.experimental.use_sculpt_vertex_colors) {
+ return false;
+ }
+ return SCULPT_mode_poll(C);
+}
+
bool SCULPT_mode_poll_view3d(bContext *C)
{
return (SCULPT_mode_poll(C) && CTX_wm_region_view3d(C));
@@ -8096,7 +8184,7 @@ static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_vertex_to_loop_colors";
/* api callbacks */
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->exec = vertex_to_loop_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8159,7 +8247,7 @@ static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
ot->idname = "SCULPT_OT_loop_to_vertex_colors";
/* api callbacks */
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->exec = loop_to_vertex_colors_exec;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8184,7 +8272,6 @@ static int sculpt_sample_color_invoke(bContext *C,
copy_v3_v3(color_srgb, active_vertex_color);
IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
BKE_brush_color_set(scene, brush, color_srgb);
- BKE_brush_alpha_set(scene, brush, active_vertex_color[3]);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
@@ -8200,7 +8287,7 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
/* api callbacks */
ot->invoke = sculpt_sample_color_invoke;
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->flag = OPTYPE_REGISTER;
}
@@ -8209,7 +8296,7 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
/* This allows the sculpt tools to work on meshes with multiple connected components as they had
* only one connected component. When initialized and enabled, the sculpt API will return extra
* connectivity neighbors that are not in the real mesh. These neighbors are calculated for each
- * vertex using the minimun distance to a vertex that is in a different connected component. */
+ * vertex using the minimum distance to a vertex that is in a different connected component. */
/* The fake neighbors first need to be ensured to be initialized.
* After that tools which needs fake neighbors functionality need to
@@ -8224,7 +8311,7 @@ static void SCULPT_OT_sample_color(wmOperatorType *ot)
* }
*
* Such approach allows to keep all the connectivity information ready for reuse
- * (withouy having lag prior to every stroke), but also makes it so the affect
+ * (without having lag prior to every stroke), but also makes it so the affect
* is localized to a specific brushes and tools only. */
enum {
@@ -8681,6 +8768,11 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+ /* Color data is not available in Multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ return OPERATOR_CANCELLED;
+ }
+
if (!ss->vcol) {
return OPERATOR_CANCELLED;
}
@@ -8726,12 +8818,12 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
/* api callbacks */
ot->invoke = sculpt_mask_by_color_invoke;
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->flag = OPTYPE_REGISTER;
ot->prop = RNA_def_boolean(
- ot->srna, "contiguous", false, "Contiguous", "Mask only contiguos color areas");
+ ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
ot->prop = RNA_def_boolean(
@@ -8774,6 +8866,7 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_face_sets_init);
WM_operatortype_append(SCULPT_OT_cloth_filter);
WM_operatortype_append(SCULPT_OT_face_sets_edit);
+
WM_operatortype_append(SCULPT_OT_sample_color);
WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c
index 7c79c1d7a2f..48b278e52b6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.c
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c
@@ -209,7 +209,7 @@ float *SCULPT_boundary_automasking_init(Object *ob,
{
SculptSession *ss = ob->sculpt;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ if (!ss->pmap) {
BLI_assert(!"Boundary Edges masking: pmap missing");
return NULL;
}
@@ -221,7 +221,7 @@ float *SCULPT_boundary_automasking_init(Object *ob,
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
- if (!SCULPT_vertex_is_boundary(ss, i)) {
+ if (SCULPT_vertex_is_boundary(ss, i)) {
edge_distance[i] = 0;
}
break;
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 6ca45ee0fb8..6a2137b6626 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -437,13 +437,16 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
BKE_pbvh_vertex_iter_end;
}
-static void cloth_brush_build_nodes_constraints(Sculpt *sd,
- Object *ob,
- PBVHNode **nodes,
- int totnode,
- SculptClothSimulation *cloth_sim,
- float initial_location[3],
- const float radius)
+static void cloth_brush_build_nodes_constraints(
+ Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ SculptClothSimulation *cloth_sim,
+ /* Cannot be const, because it is assigned to a non-const variable.
+ * NOLINTNEXTLINE: readability-non-const-parameter. */
+ float initial_location[3],
+ const float radius)
{
Brush *brush = BKE_paint_brush(&sd->paint);
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 5f7805af347..556b73b0ea5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -308,7 +308,7 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sculpt_color_filter_invoke;
ot->modal = sculpt_color_filter_modal;
- ot->poll = SCULPT_mode_poll;
+ ot->poll = SCULPT_vertex_colors_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index 494588d0996..27dd0ab3e71 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -87,7 +87,7 @@ void SCULPT_filter_cache_init(Object *ob, Sculpt *sd, const int undo_type)
.original = true,
.center = center,
.radius_squared = FLT_MAX,
- .ignore_fully_masked = true,
+ .ignore_fully_ineffective = true,
};
BKE_pbvh_search_gather(pbvh,
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index c7e07721eb7..e943bd280a3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -51,6 +51,8 @@ bool SCULPT_mode_poll_view3d(struct bContext *C);
bool SCULPT_poll(struct bContext *C);
bool SCULPT_poll_view3d(struct bContext *C);
+bool SCULPT_vertex_colors_poll(struct bContext *C);
+
/* Updates */
typedef enum SculptUpdateType {
@@ -676,7 +678,8 @@ typedef struct {
float radius_squared;
const float *center;
bool original;
- bool ignore_fully_masked;
+ /* This ignores fully masked and fully hidden nodes. */
+ bool ignore_fully_ineffective;
} SculptSearchSphereData;
typedef struct {
@@ -684,7 +687,7 @@ typedef struct {
struct SculptSession *ss;
float radius_squared;
bool original;
- bool ignore_fully_masked;
+ bool ignore_fully_ineffective;
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index 5cf6a053382..608ba1b934e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -388,7 +388,17 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
float interp_color[4];
copy_v4_v4(interp_color, ss->cache->prev_colors[vd.index]);
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ switch (brush->smear_deform_type) {
+ case BRUSH_SMEAR_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SMEAR_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SMEAR_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
normalize_v3_v3(current_disp_norm, current_disp);
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);