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:
authorCampbell Barton <ideasman42@gmail.com>2017-10-03 15:04:22 +0300
committerCampbell Barton <ideasman42@gmail.com>2017-10-03 15:07:13 +0300
commit6a7dc3348ad9ad00d2827372bd4860dc36dc4163 (patch)
tree439802c6f720e01337a7b80c5a7bfa2bbb046164 /source/blender/editors/sculpt_paint/paint_vertex.c
parent314d93838e2766e02a6a272d397bf610aa3888fd (diff)
Vertex Paint: fix feedback loop w/ smear tool
Was reading and writing from same array, this also makes smear thread-safe.
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_vertex.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c64
1 files changed, 61 insertions, 3 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 98732e0bb9e..ce232030819 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1198,6 +1198,12 @@ struct WPaintData {
bool do_multipaint; /* true if multipaint enabled and multiple groups selected */
int defbase_tot;
+
+ /* Special storage for smear brush, avoid feedback loop - update each step and swap. */
+ struct {
+ float *weight_prev;
+ float *weight_curr;
+ } smear;
};
/* Initialize the stroke cache invariants from operator properties */
@@ -1422,6 +1428,26 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
wpd->mirror.lock = tmpflags;
}
+ if (vp->paint.brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ wpd->smear.weight_prev = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ const MDeformVert *dv = me->dvert;
+ if (wpd->do_multipaint) {
+ const bool do_auto_normalize = ((ts->auto_normalize != 0) && (wpd->vgroup_validmap != NULL));
+ for (int i = 0; i < me->totvert; i++, dv++) {
+ float weight = BKE_defvert_multipaint_collective_weight(
+ dv, wpd->defbase_tot, wpd->defbase_sel, wpd->defbase_tot_sel, do_auto_normalize);
+ CLAMP(weight, 0.0f, 1.0f);
+ wpd->smear.weight_prev[i] = weight;
+ }
+ }
+ else {
+ for (int i = 0; i < me->totvert; i++, dv++) {
+ wpd->smear.weight_prev[i] = defvert_find_weight(dv, wpd->active.index);
+ }
+ }
+ wpd->smear.weight_curr = MEM_dupallocN(wpd->smear.weight_prev);
+ }
+
/* painting on subsurfs should give correct points too, this returns me->totvert amount */
ob->sculpt->building_vp_handle = true;
wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->vertexcosnos);
@@ -1663,8 +1689,7 @@ static void do_wpaint_brush_smear_task_cb_ex(
if (stroke_dot > stroke_dot_max) {
stroke_dot_max = stroke_dot;
- MDeformVert *dv = &data->me->dvert[v_other_index];
- weight_final = wpaint_get_active_weight(dv, data->wpi);
+ weight_final = data->wpd->smear.weight_prev[v_other_index];
do_color = true;
}
}
@@ -1679,6 +1704,9 @@ static void do_wpaint_brush_smear_task_cb_ex(
do_weight_paint_vertex(
data->vp, data->ob, data->wpi,
v_index, final_alpha, (float)weight_final);
+ /* Access the weight again because it might not have been applied completely. */
+ data->wpd->smear.weight_curr[v_index] =
+ wpaint_get_active_weight(&data->me->dvert[v_index], data->wpi);
}
}
}
@@ -2044,6 +2072,10 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
swap_m4m4(vc->rv3d->persmat, mat);
+ if (wp->paint.brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ SWAP(float *, wpd->smear.weight_curr, wpd->smear.weight_prev);
+ }
+
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
paint_last_stroke_update(scene, vc->ar, mval);
@@ -2093,6 +2125,10 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN((void *)wpd->active.lock);
if (wpd->mirror.lock)
MEM_freeN((void *)wpd->mirror.lock);
+ if (wpd->smear.weight_prev)
+ MEM_freeN(wpd->smear.weight_prev);
+ if (wpd->smear.weight_curr)
+ MEM_freeN(wpd->smear.weight_curr);
MEM_freeN(wpd);
}
@@ -2323,6 +2359,12 @@ struct VPaintData {
bool *mlooptag;
bool is_texbrush;
+
+ /* Special storage for smear brush, avoid feedback loop - update each step and swap. */
+ struct {
+ uint *color_prev;
+ uint *color_curr;
+ } smear;
};
static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
@@ -2374,6 +2416,12 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
}
+ if (brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ vpd->smear.color_prev = MEM_mallocN(sizeof(uint) * me->totloop, __func__);
+ memcpy(vpd->smear.color_prev, me->mloopcol, sizeof(uint) * me->totloop);
+ vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
+ }
+
/* Create projection handle */
if (vpd->is_texbrush) {
ob->sculpt->building_vp_handle = true;
@@ -2747,7 +2795,7 @@ static void do_vpaint_brush_smear_task_cb_ex(
if (stroke_dot > stroke_dot_max) {
stroke_dot_max = stroke_dot;
- color_final = lcol[mp->loopstart + k];
+ color_final = data->vpd->smear.color_prev[mp->loopstart + k];
do_color = true;
}
}
@@ -2780,6 +2828,8 @@ static void do_vpaint_brush_smear_task_cb_ex(
lcol[l_index] = vpaint_blend(
data->vp, lcol[l_index], color_orig, color_final,
final_alpha, 255 * brush_strength);
+
+ data->vpd->smear.color_curr[l_index] = lcol[l_index];
}
}
}
@@ -2955,6 +3005,10 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
swap_m4m4(vc->rv3d->persmat, mat);
+ if (vp->paint.brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ SWAP(uint *, vpd->smear.color_curr, vpd->smear.color_prev);
+ }
+
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
paint_last_stroke_update(scene, vc->ar, mval);
@@ -2980,6 +3034,10 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
if (vpd->mlooptag)
MEM_freeN(vpd->mlooptag);
+ if (vpd->smear.color_prev)
+ MEM_freeN(vpd->smear.color_prev);
+ if (vpd->smear.color_curr)
+ MEM_freeN(vpd->smear.color_curr);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);