diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_vertex.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex.c | 759 |
1 files changed, 587 insertions, 172 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 90ca1a6b18a..197231124fc 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -43,6 +43,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_math_color.h" #include "BLI_memarena.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -224,7 +225,7 @@ static void do_shared_vertex_tesscol(Mesh *me) { /* if no mcol: do not do */ /* if tface: only the involved faces, otherwise all */ - const int use_face_sel = (me->editflag & ME_EDIT_PAINT_MASK); + const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL); MFace *mface; int a; short *scolmain, *scol; @@ -284,7 +285,7 @@ static void do_shared_vertex_tesscol(Mesh *me) static void do_shared_vertexcol(Mesh *me, int do_tessface) { - const int use_face_sel = (me->editflag & ME_EDIT_PAINT_MASK); + const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL); MPoly *mp; float (*scol)[4]; int i, j, has_shared = 0; @@ -292,7 +293,7 @@ static void do_shared_vertexcol(Mesh *me, int do_tessface) /* if no mloopcol: do not do */ /* if mtexpoly: only the involved faces, otherwise all */ - if (me->mloopcol == 0 || me->totvert == 0 || me->totpoly == 0) return; + if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return; scol = MEM_callocN(sizeof(float) * me->totvert * 5, "scol"); @@ -346,14 +347,14 @@ static void make_vertexcol(Object *ob) /* single ob */ if (me->edit_btmesh) return; /* copies from shadedisplist to mcol */ - if (!me->mloopcol) { + if (!me->mloopcol && me->totloop) { if (!me->mcol) { CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface); } if (!me->mloopcol) { CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop); } - mesh_update_customdata_pointers(me, TRUE); + BKE_mesh_update_customdata_pointers(me, true); } update_tessface_data(ob, me); @@ -372,42 +373,49 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); if (defgroup) { - bDeformGroup *curdef; int mirrdef; char name[MAXBONENAME]; flip_side_name(name, defgroup->name, FALSE); - - if (strcmp(name, defgroup->name) != 0) { - for (curdef = ob->defbase.first, mirrdef = 0; curdef; curdef = curdef->next, mirrdef++) { - if (!strcmp(curdef->name, name)) { - break; - } - } - - if (curdef == NULL) { - int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ - curdef = ED_vgroup_add_name(ob, name); - ob->actdef = olddef; - } - - /* curdef should never be NULL unless this is - * a lamp and ED_vgroup_add_name fails */ - if (curdef) { - return mirrdef; + mirrdef = defgroup_name_index(ob, name); + if (mirrdef == -1) { + int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ + if (ED_vgroup_add_name(ob, name)) { + mirrdef = BLI_countlist(&ob->defbase) - 1; } + ob->actdef = olddef; } + + /* curdef should never be NULL unless this is + * a lamp and ED_vgroup_add_name fails */ + return mirrdef; } return -1; } -static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot) +static void free_vpaint_prev(VPaint *vp) { if (vp->vpaint_prev) { MEM_freeN(vp->vpaint_prev); vp->vpaint_prev = NULL; + vp->tot = 0; } +} + +static void free_wpaint_prev(VPaint *vp) +{ + if (vp->wpaint_prev) { + BKE_defvert_array_free(vp->wpaint_prev, vp->tot); + vp->wpaint_prev = NULL; + vp->tot = 0; + } +} + +static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot) +{ + free_vpaint_prev(vp); + vp->tot = tot; if (lcol == NULL || tot == 0) return; @@ -419,20 +427,16 @@ static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot) static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount) { - if (wp->wpaint_prev) { - free_dverts(wp->wpaint_prev, wp->tot); - wp->wpaint_prev = NULL; - } + free_wpaint_prev(wp); if (dverts && dcount) { wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev"); wp->tot = dcount; - copy_dverts(wp->wpaint_prev, dverts, dcount); + BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount); } } - void vpaint_fill(Object *ob, unsigned int paintcol) { Mesh *me; @@ -447,7 +451,7 @@ void vpaint_fill(Object *ob, unsigned int paintcol) if (!me->mloopcol) return; /* possible we can't make mcol's */ - selected = (me->editflag & ME_EDIT_PAINT_MASK); + selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL); mp = me->mpoly; for (i = 0; i < me->totpoly; i++, mp++) { @@ -657,11 +661,11 @@ BLI_INLINE unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac) cp = (unsigned char *)&col; temp = cp1[0] - ((fac * cp2[0]) / 255); - cp1[0] = (temp < 0) ? 0 : temp; + cp[0] = (temp < 0) ? 0 : temp; temp = cp1[1] - ((fac * cp2[1]) / 255); - cp1[1] = (temp < 0) ? 0 : temp; + cp[1] = (temp < 0) ? 0 : temp; temp = cp1[2] - ((fac * cp2[2]) / 255); - cp1[2] = (temp < 0) ? 0 : temp; + cp[2] = (temp < 0) ? 0 : temp; cp[3] = 255; return col; @@ -851,46 +855,58 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x } /* whats _dl mean? */ -static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float vert_nor[3], - const float mval[2], const float brush_size_pressure) +static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3], + const float mval[2], const float brush_size_pressure, float rgba[4]) { - float vertco[2]; + float co_ss[2]; /* screenspace */ - if (ED_view3d_project_float_global(vc->ar, vert_nor, vertco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object(vc->ar, + co, co_ss, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { float delta[2]; float dist_squared; - sub_v2_v2v2(delta, mval, vertco); + sub_v2_v2v2(delta, mval, co_ss); dist_squared = dot_v2v2(delta, delta); /* len squared */ if (dist_squared <= brush_size_pressure * brush_size_pressure) { Brush *brush = paint_brush(&vp->paint); const float dist = sqrtf(dist_squared); + if (brush->mtex.tex && rgba) { + if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { + BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL); + } + else { + const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */ + BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL); + } + } return BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); } } - + if (rgba) + zero_v4(rgba); return 0.0f; } -static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, - float vpimat[3][3], const float *vert_nor, +static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc, + float vpimat[3][3], const DMCoNo *v_co_no, const float mval[2], - const float brush_size_pressure, const float brush_alpha_pressure) + const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4]) { - float strength = calc_vp_strength_dl(vp, vc, vert_nor, mval, brush_size_pressure); + float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba); if (strength > 0.0f) { float alpha = brush_alpha_pressure * strength; if (vp->flag & VP_NORMALS) { float dvec[3]; - const float *no = vert_nor + 3; /* transpose ! */ - dvec[2] = dot_v3v3(vpimat[2], no); + dvec[2] = dot_v3v3(vpimat[2], v_co_no->no); if (dvec[2] > 0.0f) { - dvec[0] = dot_v3v3(vpimat[0], no); - dvec[1] = dot_v3v3(vpimat[1], no); + dvec[0] = dot_v3v3(vpimat[0], v_co_no->no); + dvec[1] = dot_v3v3(vpimat[1], v_co_no->no); alpha *= dvec[2] / len_v3(dvec); } @@ -908,7 +924,8 @@ static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha) { - return (paintval * alpha) + (weight * (1.0f - alpha)); + const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */ + return (paintval * talpha) + (weight * (1.0f - talpha)); } BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha) { @@ -1009,7 +1026,7 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev, /* sets wp->weight to the closest weight value to vertex */ /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ -static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; Mesh *me; @@ -1019,22 +1036,23 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) me = BKE_mesh_from_object(vc.obact); if (me && me->dvert && vc.v3d && vc.rv3d) { - const int use_vert_sel = (me->editflag & ME_EDIT_VERT_SEL) != 0; + const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; int v_idx_best = -1; unsigned int index; view3d_operator_needs_opengl(C); + ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); if (use_vert_sel) { - if (ED_mesh_pick_vert(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) { v_idx_best = index; } } else { - if (ED_mesh_pick_face_vert(C, me, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { v_idx_best = index; } - else if (ED_mesh_pick_face(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */ BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); } @@ -1104,7 +1122,7 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { const int defbase_tot = BLI_countlist(&vc.obact->defbase); - const int use_vert_sel = (me->editflag & ME_EDIT_VERT_SEL) != 0; + const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups"); int found = FALSE; unsigned int index; @@ -1113,15 +1131,16 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA win->eventstate->y - vc.ar->winrct.ymin}; view3d_operator_needs_opengl(C); + ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d); if (use_vert_sel) { - if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) { MDeformVert *dvert = &me->dvert[index]; found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); } } else { - if (ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { MPoly *mp = &me->mpoly[index]; unsigned int fidx = mp->totloop - 1; @@ -1459,7 +1478,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, MDeformWeight *ndw; MDeformWeight *odw; - float changed_sum = 0.0f; + // float changed_sum = 0.0f; // UNUSED char *change_status; @@ -1488,7 +1507,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, } else if (ndw->weight != odw->weight) { /* changed groups are handled here */ totchange += ndw->weight - odw->weight; - changed_sum += ndw->weight; + // changed_sum += ndw->weight; // UNUSED change_status[i] = 2; /* was altered already */ total_changed++; } /* unchanged, unlocked bone groups are handled here */ @@ -1994,6 +2013,13 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */ else { mesh_octree_table(NULL, NULL, NULL, 'e'); mesh_mirrtopo_table(NULL, 'e'); + + if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { + BKE_mesh_flush_select_from_verts(me); + } + else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { + BKE_mesh_flush_select_from_polys(me); + } } WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); @@ -2038,34 +2064,30 @@ struct WPaintData { int *indexar; int vgroup_active; int vgroup_mirror; - float *vertexcosnos; + DMCoNo *vertexcosnos; float wpimat[3][3]; - + /* variables for auto normalize */ const char *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */ const char *lock_flags; int defbase_tot; }; -static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +/* ensure we have data on wpaint start, add if needed */ +static int wpaint_ensure_data(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - struct PaintStroke *stroke = op->customdata; - ToolSettings *ts = scene->toolsettings; - VPaint *wp = ts->wpaint; Object *ob = CTX_data_active_object(C); - struct WPaintData *wpd; - Mesh *me; + Mesh *me = BKE_mesh_from_object(ob); - float mat[4][4], imat[4][4]; - if (scene->obedit) { return FALSE; } - - me = BKE_mesh_from_object(ob); - if (me == NULL || me->totpoly == 0) return OPERATOR_PASS_THROUGH; - + + if (me == NULL || me->totpoly == 0) { + return FALSE; + } + /* if nothing was added yet, we make dverts and a vertex deform group */ if (!me->dvert) { ED_vgroup_data_create(&me->id); @@ -2104,6 +2126,25 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNU return FALSE; } + return TRUE; +} + +static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +{ + Scene *scene = CTX_data_scene(C); + struct PaintStroke *stroke = op->customdata; + ToolSettings *ts = scene->toolsettings; + VPaint *wp = ts->wpaint; + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + struct WPaintData *wpd; + + float mat[4][4], imat[4][4]; + + if (wpaint_ensure_data(C, op) == FALSE) { + return FALSE; + } + { /* check if we are attempting to paint onto a locked vertex group, * and other options disallow it from doing anything useful */ @@ -2145,6 +2186,11 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNU if (me->editflag & ME_EDIT_MIRROR_X) { wpd->vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, wpd->vgroup_active); } + + { + UnifiedPaintSettings *ups = &ts->unified_paint_settings; + ups->draw_pressure = true; + } return TRUE; } @@ -2166,7 +2212,15 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P unsigned int index, totindex; float alpha; float mval[2]; - int use_vert_sel; + bool use_vert_sel; + bool use_face_sel; + bool use_depth; + + MDeformWeight *(*dw_func)(MDeformVert *, const int) = + (brush->vertexpaint_tool == PAINT_BLEND_BLUR) ? + ((wp->flag & VP_ONLYVGROUP) ? + (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index : + defvert_verify_index) : NULL; const float pressure = RNA_float_get(itemptr, "pressure"); const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f); @@ -2183,23 +2237,19 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P ED_region_tag_redraw(CTX_wm_region(C)); return; } - + vc = &wpd->vc; ob = vc->obact; me = ob->data; indexar = wpd->indexar; view3d_operator_needs_opengl(C); - + ED_view3d_init_mats_rv3d(ob, vc->rv3d); + /* load projection matrix */ mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); RNA_float_get_array(itemptr, "mouse", mval); - mval[0] -= vc->ar->winrct.xmin; - mval[1] -= vc->ar->winrct.ymin; - - - /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ wpi.defbase_tot = wpd->defbase_tot; @@ -2223,32 +2273,39 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P swap_m4m4(wpd->vc.rv3d->persmat, mat); - use_vert_sel = (me->editflag & ME_EDIT_VERT_SEL) != 0; + use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT); /* which faces are involved */ - if (wp->flag & VP_AREA) { - /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ - me->editflag &= ~ME_EDIT_VERT_SEL; - totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); - me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0; - } - else { - indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]); - if (indexar[0]) totindex = 1; - else totindex = 0; - } + if (use_depth) { + if (wp->flag & VP_AREA) { + /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ + me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; + totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); + me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0; + } + else { + indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]); + if (indexar[0]) totindex = 1; + else totindex = 0; + } - if ((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) { - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1); - - if ((mpoly->flag & ME_FACE_SEL) == 0) { - indexar[index] = 0; + if (use_face_sel && me->mpoly) { + for (index = 0; index < totindex; index++) { + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1); + + if ((mpoly->flag & ME_FACE_SEL) == 0) { + indexar[index] = 0; + } } } } } + else { + indexar = NULL; + } /* make sure each vertex gets treated only once */ /* and calculate filter weight */ @@ -2257,80 +2314,126 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P paintweight = 0.0f; else paintweight = BKE_brush_weight_get(scene, brush); - - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - if (use_vert_sel) { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); +#define WP_BLUR_ACCUM(v_idx_var) \ + { \ + const unsigned int vidx = v_idx_var; \ + const float fac = calc_vp_strength_col_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure, NULL); \ + if (fac > 0.0f) { \ + MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \ + paintweight += dw ? (dw->weight * fac) : 0.0f; \ + totw += fac; \ + } \ + } (void)0 + + + if (use_depth) { + for (index = 0; index < totindex; index++) { + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = me->mpoly + (indexar[index] - 1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; + + if (use_vert_sel) { + for (i = 0; i < mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); + } } - } - else { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = 1; + else { + for (i = 0; i < mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = 1; + } } - } - - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int); - - if (wp->flag & VP_ONLYVGROUP) - dw_func = (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index; - else - dw_func = defvert_verify_index; - - ml = me->mloop + mpoly->loopstart; - for (i = 0; i < mpoly->totloop; i++, ml++) { - unsigned int vidx = ml->v; - const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos + 6 * vidx, mval, brush_size_pressure); - if (fac > 0.0f) { - dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); - paintweight += dw ? (dw->weight * fac) : 0.0f; - totw += fac; + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + ml = me->mloop + mpoly->loopstart; + for (i = 0; i < mpoly->totloop; i++, ml++) { + WP_BLUR_ACCUM(ml->v); } } } } } - + else { + const unsigned int totvert = me->totvert; + unsigned int i; + + /* in the case of face selection we need to flush */ + if (use_vert_sel || use_face_sel) { + for (i = 0; i < totvert; i++) { + me->dvert[i].flag = me->mvert[i].flag & SELECT; + } + } + else { + for (i = 0; i < totvert; i++) { + me->dvert[i].flag = SELECT; + } + } + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + for (i = 0; i < totvert; i++) { + WP_BLUR_ACCUM(i); + } + } + } + +#undef WP_BLUR_ACCUM + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { paintweight /= totw; } - for (index = 0; index < totindex; index++) { +#define WP_PAINT(v_idx_var) \ + { \ + unsigned int vidx = v_idx_var; \ + if (me->dvert[vidx].flag) { \ + alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ + mval, brush_size_pressure, brush_alpha_pressure, NULL); \ + if (alpha) { \ + do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \ + } \ + me->dvert[vidx].flag = 0; \ + } \ + } (void)0 + + if (use_depth) { + for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - - for (i = 0; i < mpoly->totloop; i++, ml++) { - unsigned int vidx = ml->v; - - if (me->dvert[vidx].flag) { - alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos + 6 * vidx, - mval, brush_size_pressure, brush_alpha_pressure); - if (alpha) { - do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); - } - me->dvert[vidx].flag = 0; + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = me->mpoly + (indexar[index] - 1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; + + for (i = 0; i < mpoly->totloop; i++, ml++) { + WP_PAINT(ml->v); } } } } + else { + const unsigned int totvert = me->totvert; + unsigned int i; + + for (i = 0; i < totvert; i++) { + WP_PAINT(i); + } + } +#undef WP_PAINT /* *** free wpi members */ MEM_freeN((void *)wpi.defbase_sel); - /* *** don't freeing wpi members */ + /* *** done freeing wpi members */ swap_m4m4(vc->rv3d->persmat, mat); - + + { + UnifiedPaintSettings *ups = &ts->unified_paint_settings; + ups->pressure_value = pressure; + } + DAG_id_tag_update(ob->data, 0); ED_region_tag_redraw(vc->ar); } @@ -2371,14 +2474,19 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) } } } - + + { + UnifiedPaintSettings *ups = &ts->unified_paint_settings; + ups->draw_pressure = false; + } + DAG_id_tag_update(ob->data, 0); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); } -static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; @@ -2424,7 +2532,7 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); } -static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) +static int weight_paint_set_exec(bContext *C, wmOperator *op) { struct Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); @@ -2432,6 +2540,10 @@ static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) Brush *brush = paint_brush(&ts->wpaint->paint); float vgroup_weight = BKE_brush_weight_get(scene, brush); + if (wpaint_ensure_data(C, op) == FALSE) { + return OPERATOR_CANCELLED; + } + wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight); ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ return OPERATOR_FINISHED; @@ -2477,6 +2589,10 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ if (ob->mode & OB_MODE_VERTEX_PAINT) { ob->mode &= ~OB_MODE_VERTEX_PAINT; + + if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { + BKE_mesh_flush_select_from_polys(me); + } } else { ob->mode |= OB_MODE_VERTEX_PAINT; @@ -2492,9 +2608,8 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ BKE_paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT); } - if (me) - /* update modifier stack for mapping requirements */ - DAG_id_tag_update(&me->id, 0); + /* update modifier stack for mapping requirements */ + DAG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); @@ -2548,7 +2663,7 @@ typedef struct VPaintData { ViewContext vc; unsigned int paintcol; int *indexar; - float *vertexcosnos; + DMCoNo *vertexcosnos; float vpimat[3][3]; /* modify 'me->mcol' directly, since the derived mesh is drawing from this array, @@ -2558,6 +2673,8 @@ typedef struct VPaintData { /* mpoly -> mface mapping */ MemArena *polyfacemap_arena; ListBase *polyfacemap; + + bool is_texbrush; } VPaintData; static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me) @@ -2594,6 +2711,7 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl ToolSettings *ts = CTX_data_tool_settings(C); struct PaintStroke *stroke = op->customdata; VPaint *vp = ts->vpaint; + Brush *brush = paint_brush(&vp->paint); struct VPaintData *vpd; Object *ob = CTX_data_active_object(C); Mesh *me; @@ -2623,6 +2741,8 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl vpd->indexar = get_indexarray(me); vpd->paintcol = vpaint_get_current_col(vp); + vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && + brush->mtex.tex; /* are we painting onto a modified mesh?, * if not we can skip face map trickyness */ @@ -2644,16 +2764,20 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl invert_m4_m4(imat, mat); copy_m3_m4(vpd->vpimat, imat); + { + UnifiedPaintSettings *ups = &ts->unified_paint_settings; + ups->draw_pressure = true; + } + return 1; } -static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Object *ob, +static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me, const unsigned int index, const float mval[2], const float brush_size_pressure, const float brush_alpha_pressure) { ViewContext *vc = &vpd->vc; Brush *brush = paint_brush(&vp->paint); - Mesh *me = BKE_mesh_from_object(ob); MPoly *mpoly = &me->mpoly[index]; MFace *mf; MCol *mc; @@ -2695,12 +2819,24 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Object *ob, ml = me->mloop + mpoly->loopstart; for (i = 0; i < mpoly->totloop; i++, ml++) { - alpha = calc_vp_alpha_dl(vp, vc, vpd->vpimat, - vpd->vertexcosnos + 6 * ml->v, mval, - brush_size_pressure, brush_alpha_pressure); + float rgba[4]; + unsigned int paintcol; + alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat, + &vpd->vertexcosnos[ml->v], mval, + brush_size_pressure, brush_alpha_pressure, rgba); + + if (vpd->is_texbrush) { + float rgba_br[3]; + rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol); + mul_v3_v3(rgba_br, rgba); + rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br); + } + else + paintcol = vpd->paintcol; + if (alpha > 0.0f) { const int alpha_i = (int)(alpha * 255.0f); - lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], vpd->paintcol, alpha_i, brush_alpha_pressure_i); + lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i); } } @@ -2754,14 +2890,11 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P RNA_float_get_array(itemptr, "mouse", mval); view3d_operator_needs_opengl(C); - + ED_view3d_init_mats_rv3d(ob, vc->rv3d); + /* load projection matrix */ mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); - mval[0] -= vc->ar->winrct.xmin; - mval[1] -= vc->ar->winrct.ymin; - - /* which faces are involved */ if (vp->flag & VP_AREA) { totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); @@ -2772,7 +2905,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P else totindex = 0; } - if ((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) { + if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) { for (index = 0; index < totindex; index++) { if (indexar[index] && indexar[index] <= me->totpoly) { MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1); @@ -2787,7 +2920,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P for (index = 0; index < totindex; index++) { if (indexar[index] && indexar[index] <= me->totpoly) { - vpaint_paint_poly(vp, vpd, ob, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure); + vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure); } } @@ -2799,6 +2932,11 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P do_shared_vertexcol(me, do_tessface); } + { + UnifiedPaintSettings *ups = &ts->unified_paint_settings; + ups->pressure_value = pressure; + } + ED_region_tag_redraw(vc->ar); if (vpd->use_fast_update == FALSE) { @@ -2830,12 +2968,17 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) BLI_memarena_free(vpd->polyfacemap_arena); } + { + UnifiedPaintSettings *ups = &ts->unified_paint_settings; + ups->draw_pressure = false; + } + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); MEM_freeN(vpd); } -static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; @@ -2929,3 +3072,275 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot) /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights"); } + +/* *** VGroups Gradient *** */ +typedef struct DMGradient_vertStore { + float sco[2]; + float weight_orig; + enum { + VGRAD_STORE_NOP = 0, + VGRAD_STORE_DW_EXIST = (1 << 0) + } flag; +} DMGradient_vertStore; + +typedef struct DMGradient_userData { + struct ARegion *ar; + Scene *scene; + Mesh *me; + Brush *brush; + const float *sco_start; /* [2] */ + const float *sco_end; /* [2] */ + float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */ + int def_nr; + short is_init; + DMGradient_vertStore *vert_cache; + + /* options */ + short use_select; + short type; + float weightpaint; +} DMGradient_userData; + +static void gradientVert__mapFunc(void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + DMGradient_userData *grad_data = userData; + Mesh *me = grad_data->me; + + if (grad_data->use_select == FALSE || (me->mvert[index].flag & SELECT)) { + DMGradient_vertStore *vs = &grad_data->vert_cache[index]; + + /* run first pass only, could be split into its own mapFunc + * the screen coords of the verts need to be cached because + * updating the mesh may move them about (entering feedback loop) */ + if (grad_data->is_init) { + if (ED_view3d_project_float_object(grad_data->ar, + co, vs->sco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { + /* ok */ + MDeformVert *dv = &me->dvert[index]; + MDeformWeight *dw; + dw = defvert_find_index(dv, grad_data->def_nr); + if (dw) { + vs->weight_orig = dw->weight; + vs->flag = VGRAD_STORE_DW_EXIST; + } + else { + vs->weight_orig = 0.0f; + vs->flag = VGRAD_STORE_NOP; + } + } + else { + /* no go */ + copy_v2_fl(vs->sco, FLT_MAX); + } + } + /* end init */ + + if (vs->sco[0] != FLT_MAX) { + float alpha; + + if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { + alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); + } + else { + BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); + alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; + } + /* no need to clamp 'alpha' yet */ + + /* adjust weight */ + alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f); + + if (alpha != 0.0f) { + MDeformVert *dv = &me->dvert[index]; + MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr); + // dw->weight = alpha; // testing + int tool = grad_data->brush->vertexpaint_tool; + float testw; + + /* init if we just added */ + testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha); + CLAMP(testw, 0.0f, 1.0f); + dw->weight = testw; + } + else { + MDeformVert *dv = &me->dvert[index]; + if (vs->flag & VGRAD_STORE_DW_EXIST) { + /* normally we NULL check, but in this case we know it exists */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + dw->weight = vs->weight_orig; + } + else { + /* wasn't originally existing, remove */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + if (dw) { + defvert_remove_group(dv, dw); + } + } + } + } + } +} + +static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret = WM_gesture_straightline_modal(C, op, event); + + if (ret & OPERATOR_RUNNING_MODAL) { + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */ + /* generally crap! redo! */ + WM_gesture_straightline_cancel(C, op); + ret &= ~OPERATOR_RUNNING_MODAL; + ret |= OPERATOR_FINISHED; + } + } + + if (ret & OPERATOR_CANCELLED) { + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *wp = ts->wpaint; + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + if (wp->wpaint_prev) { + BKE_defvert_array_free_elems(me->dvert, me->totvert); + BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert); + free_wpaint_prev(wp); + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + else if (ret & OPERATOR_FINISHED) { + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *wp = ts->wpaint; + free_wpaint_prev(wp); + } + + return ret; +} + +static int paint_weight_gradient_exec(bContext *C, wmOperator *op) +{ + wmGesture *gesture = op->customdata; + DMGradient_vertStore *vert_cache; + struct ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + int x_start = RNA_int_get(op->ptr, "xstart"); + int y_start = RNA_int_get(op->ptr, "ystart"); + int x_end = RNA_int_get(op->ptr, "xend"); + int y_end = RNA_int_get(op->ptr, "yend"); + float sco_start[2] = {x_start, y_start}; + float sco_end[2] = {x_end, y_end}; + const bool is_interactive = (gesture != NULL); + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + + DMGradient_userData data = {0}; + + if (is_interactive) { + if (gesture->userdata == NULL) { + VPaint *wp = scene->toolsettings->wpaint; + + gesture->userdata = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__); + data.is_init = true; + + copy_wpaint_prev(wp, me->dvert, me->totvert); + + /* on init only, convert face -> vert sel */ + if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { + BKE_mesh_flush_select_from_polys(me); + } + } + + vert_cache = gesture->userdata; + } + else { + data.is_init = true; + vert_cache = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__); + } + + data.ar = ar; + data.scene = scene; + data.me = ob->data; + data.sco_start = sco_start; + data.sco_end = sco_end; + data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end); + data.def_nr = ob->actdef - 1; + data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)); + data.vert_cache = vert_cache; + data.type = RNA_enum_get(op->ptr, "type"); + + { + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *wp = ts->wpaint; + struct Brush *brush = paint_brush(&wp->paint); + data.brush = brush; + data.weightpaint = BKE_brush_weight_get(scene, brush); + } + + dm->foreachMappedVert(dm, gradientVert__mapFunc, &data); + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + if (is_interactive == false) { + MEM_freeN(vert_cache); + } + + return OPERATOR_FINISHED; +} + +static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret; + + if (wpaint_ensure_data(C, op) == FALSE) { + return OPERATOR_CANCELLED; + } + + ret = WM_gesture_straightline_invoke(C, op, event); + if (ret & OPERATOR_RUNNING_MODAL) { + struct ARegion *ar = CTX_wm_region(C); + if (ar->regiontype == RGN_TYPE_WINDOW) { + if (event->type == LEFTMOUSE && event->val == KM_PRESS) { /* TODO, hardcoded, extend WM_gesture_straightline_ */ + wmGesture *gesture = op->customdata; + gesture->mode = 1; + } + } + } + return ret; +} + +void PAINT_OT_weight_gradient(wmOperatorType *ot) +{ + /* defined in DNA_space_types.h */ + static EnumPropertyItem gradient_types[] = { + {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""}, + {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""}, + {0, NULL, 0, NULL, NULL} + }; + + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Weight Gradient"; + ot->idname = "PAINT_OT_weight_gradient"; + ot->description = "Sample a line and show it in Scope panels"; + + /* api callbacks */ + ot->invoke = paint_weight_gradient_invoke; + ot->modal = paint_weight_gradient_modal; + ot->exec = paint_weight_gradient_exec; + ot->poll = weight_paint_poll; + ot->cancel = WM_gesture_straightline_cancel; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); +} |