Vertex Paint: fix feedback loop w/ smear tool
Was reading and writing from same array, this also makes smear thread-safe.
This commit is contained in:
parent
314d93838e
commit
6a7dc3348a
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user