2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/sculpt_paint/paint_vertex.c
31 * Used for vertex color & weight paint and mode switching.
33 * \note This file is already big,
34 * use `paint_vertex_color_ops.c` & `paint_vertex_weight_ops.c` for general purpose operators.
37 #include "MEM_guardedalloc.h"
39 #include "BLI_listbase.h"
42 #include "BLI_array_utils.h"
45 #include "DNA_armature_types.h"
46 #include "DNA_mesh_types.h"
47 #include "DNA_particle_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_brush_types.h"
50 #include "DNA_object_types.h"
52 #include "RNA_access.h"
53 #include "RNA_define.h"
55 #include "BKE_brush.h"
56 #include "BKE_context.h"
57 #include "BKE_deform.h"
58 #include "BKE_global.h"
61 #include "BKE_mesh_mapping.h"
62 #include "BKE_object_deform.h"
63 #include "BKE_paint.h"
64 #include "BKE_report.h"
65 #include "BKE_subsurf.h"
67 #include "DEG_depsgraph.h"
72 #include "ED_object.h"
74 #include "ED_screen.h"
75 #include "ED_view3d.h"
80 #include "sculpt_intern.h"
81 #include "paint_intern.h" /* own include */
83 /* Use for 'blur' brush, align with PBVH nodes, created and freed on each update. */
84 struct VPaintAverageAccum {
89 struct WPaintAverageAccum {
94 struct NormalAnglePrecalc {
96 /* what angle to mask at */
98 /* cos(angle), faster to compare */
101 float angle_inner__cos;
102 /* difference between angle and angle_inner, for easy access */
107 static void view_angle_limits_init(
108 struct NormalAnglePrecalc *a, float angle, bool do_mask_normal)
110 angle = RAD2DEGF(angle);
111 a->do_mask_normal = do_mask_normal;
112 if (do_mask_normal) {
113 a->angle_inner = angle;
114 a->angle = (a->angle_inner + 90.0f) * 0.5f;
117 a->angle_inner = a->angle = angle;
120 a->angle_inner *= (float)(M_PI_2 / 90);
121 a->angle *= (float)(M_PI_2 / 90);
122 a->angle_range = a->angle - a->angle_inner;
124 if (a->angle_range <= 0.0f) {
125 a->do_mask_normal = false; /* no need to do blending */
128 a->angle__cos = cosf(a->angle);
129 a->angle_inner__cos = cosf(a->angle_inner);
132 static float view_angle_limits_apply_falloff(
133 const struct NormalAnglePrecalc *a, float angle_cos, float *mask_p)
135 if (angle_cos <= a->angle__cos) {
136 /* outsize the normal limit */
139 else if (angle_cos < a->angle_inner__cos) {
140 *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
148 static bool vwpaint_use_normal(const VPaint *vp)
150 return ((vp->paint.brush->flag & BRUSH_FRONTFACE) != 0) ||
151 ((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
154 static bool brush_use_accumulate(const Brush *brush)
156 return (brush->flag & BRUSH_ACCUMULATE) != 0 || brush->vertexpaint_tool == PAINT_BLEND_SMEAR;
159 static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev, MDeformVert *dvert_curr, int index)
161 MDeformVert *dv_curr = &dvert_curr[index];
162 MDeformVert *dv_prev = &dvert_prev[index];
163 if (dv_prev->flag == 1) {
165 defvert_copy(dv_prev, dv_curr);
170 /* check if we can do partial updates and have them draw realtime
171 * (without rebuilding the 'derivedFinal') */
172 static bool vertex_paint_use_fast_update_check(Object *ob)
174 DerivedMesh *dm = ob->derivedFinal;
177 Mesh *me = BKE_mesh_from_object(ob);
178 if (me && me->mloopcol) {
179 return (me->mloopcol == CustomData_get_layer(&dm->loopData, CD_MLOOPCOL));
186 static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2])
188 const int mval_i[2] = {mval[0], mval[1]};
191 if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
192 UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
193 ups->average_stroke_counter++;
194 add_v3_v3(ups->average_stroke_accum, world);
195 ups->last_stroke_valid = true;
199 /* polling - retrieve whether cursor should be set or operator should be done */
201 /* Returns true if vertex paint mode is active */
202 int vertex_paint_mode_poll(bContext *C)
204 const WorkSpace *workspace = CTX_wm_workspace(C);
205 Object *ob = CTX_data_active_object(C);
207 (ob->type == OB_MESH) &&
208 ((Mesh *)ob->data)->totpoly &&
209 (workspace->object_mode & OB_MODE_VERTEX_PAINT));
212 int vertex_paint_poll(bContext *C)
214 if (vertex_paint_mode_poll(C) &&
215 BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint))
217 ScrArea *sa = CTX_wm_area(C);
218 if (sa && sa->spacetype == SPACE_VIEW3D) {
219 ARegion *ar = CTX_wm_region(C);
220 if (ar->regiontype == RGN_TYPE_WINDOW)
227 int weight_paint_mode_poll(bContext *C)
229 const WorkSpace *workspace = CTX_wm_workspace(C);
230 Object *ob = CTX_data_active_object(C);
232 (ob->type == OB_MESH) &&
233 ((Mesh *)ob->data)->totpoly &&
234 (workspace->object_mode == OB_MODE_WEIGHT_PAINT));
237 int weight_paint_poll(bContext *C)
239 const WorkSpace *workspace = CTX_wm_workspace(C);
240 Object *ob = CTX_data_active_object(C);
244 (workspace->object_mode & OB_MODE_WEIGHT_PAINT) &&
245 (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
246 (sa = CTX_wm_area(C)) &&
247 (sa->spacetype == SPACE_VIEW3D))
249 ARegion *ar = CTX_wm_region(C);
250 if (ar->regiontype == RGN_TYPE_WINDOW) {
257 static VPaint *new_vpaint(void)
259 VPaint *vp = MEM_callocN(sizeof(VPaint), "VPaint");
261 vp->paint.flags |= PAINT_SHOW_BRUSH;
266 uint vpaint_get_current_col(Scene *scene, VPaint *vp)
268 Brush *brush = BKE_paint_brush(&vp->paint);
270 rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush));
271 col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
275 /* wpaint has 'wpaint_blend' */
276 static uint vpaint_blend(
277 const VPaint *vp, uint color_curr, uint color_orig,
278 uint color_paint, const int alpha_i,
279 /* pre scaled from [0-1] --> [0-255] */
280 const int brush_alpha_value_i)
282 const Brush *brush = vp->paint.brush;
283 const int tool = brush->vertexpaint_tool;
285 uint color_blend = ED_vpaint_blend_tool(tool, color_curr, color_paint, alpha_i);
287 /* if no accumulate, clip color adding with colorig & orig alpha */
288 if (!brush_use_accumulate(brush)) {
292 color_test = ED_vpaint_blend_tool(tool, color_orig, color_paint, brush_alpha_value_i);
294 cp = (char *)&color_blend;
295 ct = (char *)&color_test;
296 co = (char *)&color_orig;
298 for (a = 0; a < 4; a++) {
300 if (cp[a] < ct[a]) cp[a] = ct[a];
301 else if (cp[a] > co[a]) cp[a] = co[a];
304 if (cp[a] < co[a]) cp[a] = co[a];
305 else if (cp[a] > ct[a]) cp[a] = ct[a];
310 if ((brush->flag & BRUSH_LOCK_ALPHA) &&
311 !ELEM(tool, PAINT_BLEND_ALPHA_SUB, PAINT_BLEND_ALPHA_ADD))
314 cp = (char *)&color_blend;
315 cc = (char *)&color_curr;
322 static void tex_color_alpha(
323 VPaint *vp, const ViewContext *vc, const float co[3],
326 const Brush *brush = BKE_paint_brush(&vp->paint);
327 BLI_assert(brush->mtex.tex != NULL);
328 if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
329 BKE_brush_sample_tex_3D(vc->scene, brush, co, r_rgba, 0, NULL);
332 float co_ss[2]; /* screenspace */
333 if (ED_view3d_project_float_object(
336 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
338 const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
339 BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, r_rgba, 0, NULL);
347 /* vpaint has 'vpaint_blend' */
348 static float wpaint_blend(
349 const VPaint *wp, float weight,
350 const float alpha, float paintval,
351 const float UNUSED(brush_alpha_value),
354 const Brush *brush = wp->paint.brush;
355 int tool = brush->vertexpaint_tool;
359 case PAINT_BLEND_MIX:
360 paintval = 1.f - paintval; break;
361 case PAINT_BLEND_ADD:
362 tool = PAINT_BLEND_SUB; break;
363 case PAINT_BLEND_SUB:
364 tool = PAINT_BLEND_ADD; break;
365 case PAINT_BLEND_LIGHTEN:
366 tool = PAINT_BLEND_DARKEN; break;
367 case PAINT_BLEND_DARKEN:
368 tool = PAINT_BLEND_LIGHTEN; break;
372 weight = ED_wpaint_blend_tool(tool, weight, paintval, alpha);
374 CLAMP(weight, 0.0f, 1.0f);
379 static float wpaint_clamp_monotonic(float oldval, float curval, float newval)
382 return MIN2(newval, curval);
383 else if (newval > oldval)
384 return MAX2(newval, curval);
389 /* ----------------------------------------------------- */
391 static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap)
393 float sum = 0.0f, fac;
397 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
398 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
404 if ((tot == 0) || (sum == 1.0f)) {
411 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
412 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
418 /* hrmf, not a factor in this case */
421 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
422 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
430 * A version of #do_weight_paint_normalize_all that includes locked weights
431 * but only changes unlocked weights.
433 static bool do_weight_paint_normalize_all_locked(
434 MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
435 const bool *lock_flags)
437 float sum = 0.0f, fac;
438 float sum_unlock = 0.0f;
439 float lock_weight = 0.0f;
443 if (lock_flags == NULL) {
444 do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_validmap);
448 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
449 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
452 if (lock_flags[dw->def_nr]) {
453 lock_weight += dw->weight;
457 sum_unlock += dw->weight;
470 if (lock_weight >= 1.0f) {
471 /* locked groups make it impossible to fully normalize,
472 * zero out what we can and return false */
473 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
474 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
475 if (lock_flags[dw->def_nr] == false) {
481 return (lock_weight == 1.0f);
483 else if (sum_unlock != 0.0f) {
484 fac = (1.0f - lock_weight) / sum_unlock;
486 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
487 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
488 if (lock_flags[dw->def_nr] == false) {
490 /* paranoid but possibly with float error */
491 CLAMP(dw->weight, 0.0f, 1.0f);
497 /* hrmf, not a factor in this case */
498 fac = (1.0f - lock_weight) / tot;
499 /* paranoid but possibly with float error */
500 CLAMP(fac, 0.0f, 1.0f);
502 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
503 if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
504 if (lock_flags[dw->def_nr] == false) {
515 * \note same as function above except it does a second pass without active group
516 * if normalize fails with it.
518 static void do_weight_paint_normalize_all_locked_try_active(
519 MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
520 const bool *lock_flags, const bool *lock_with_active)
522 /* first pass with both active and explicitly locked groups restricted from change */
524 bool success = do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_with_active);
528 * Locks prevented the first pass from full completion, so remove restriction on active group; e.g:
530 * - With 1.0 weight painted into active:
531 * nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit.
532 * - With 0.0 weight painted into active:
533 * no unlocked groups; first pass did nothing; increase 0 to fit.
535 do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
540 static bool has_unselected_unlocked_bone_group(
541 int defbase_tot, bool *defbase_sel, int selected,
542 const bool *lock_flags, const bool *vgroup_validmap)
545 if (defbase_tot == selected) {
548 for (i = 0; i < defbase_tot; i++) {
549 if (vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
557 static void multipaint_clamp_change(
558 MDeformVert *dvert, const int defbase_tot, const bool *defbase_sel,
564 float change = *change_p;
566 /* verify that the change does not cause values exceeding 1 and clamp it */
567 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
568 if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
570 val = dw->weight * change;
572 change = 1.0f / dw->weight;
581 static bool multipaint_verify_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
587 /* in case the change is reduced, you need to recheck
588 * the earlier values to make sure they are not 0
589 * (precision error) */
590 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
591 if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
593 val = dw->weight * change;
594 /* the value should never reach zero while multi-painting if it
595 * was nonzero beforehand */
606 static void multipaint_apply_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
611 /* apply the valid change */
612 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
613 if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
615 dw->weight = dw->weight * change;
616 CLAMP(dw->weight, 0.0f, 1.0f);
623 * Variables stored both for 'active' and 'mirror' sides.
625 struct WeightPaintGroupData {
626 /** index of active group or its mirror
628 * - 'active' is always `ob->actdef`.
629 * - 'mirror' is -1 when 'ME_EDIT_MIRROR_X' flag id disabled,
630 * otherwise this will be set to the mirror or the active group (if the group isn't mirrored).
633 /** lock that includes the 'index' as locked too
635 * - 'active' is set of locked or active/selected groups
636 * - 'mirror' is set of locked or mirror groups
641 /* struct to avoid passing many args each call to do_weight_paint_vertex()
642 * this _could_ be made a part of the operators 'WPaintData' struct, or at
643 * least a member, but for now keep its own struct, initialized on every
644 * paint stroke update - campbell */
645 typedef struct WeightPaintInfo {
649 /* both must add up to 'defbase_tot' */
651 int defbase_tot_unsel;
653 struct WeightPaintGroupData active, mirror;
655 /* boolean array for locked bones,
656 * length of defbase_tot */
657 const bool *lock_flags;
658 /* boolean array for selected bones,
659 * length of defbase_tot, cant be const because of how its passed */
660 const bool *defbase_sel;
661 /* same as WeightPaintData.vgroup_validmap,
662 * only added here for convenience */
663 const bool *vgroup_validmap;
667 bool do_auto_normalize;
669 float brush_alpha_value; /* result of BKE_brush_alpha_get() */
672 static void do_weight_paint_vertex_single(
673 /* vars which remain the same for every vert */
674 const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
675 /* vars which change on each stroke */
676 const uint index, float alpha, float paintweight)
679 MDeformVert *dv = &me->dvert[index];
680 bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
689 MDeformVert *dv_mirr;
690 MDeformWeight *dw_mirr;
692 /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
693 if (me->editflag & ME_EDIT_MIRROR_X) {
694 index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
695 vgroup_mirr = wpi->mirror.index;
697 /* another possible error - mirror group _and_ active group are the same (which is fine),
698 * but we also are painting onto a center vertex - this would paint the same weight twice */
699 if (index_mirr == index && vgroup_mirr == wpi->active.index) {
700 index_mirr = vgroup_mirr = -1;
704 index_mirr = vgroup_mirr = -1;
707 if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
708 dw = defvert_find_index(dv, wpi->active.index);
711 dw = defvert_verify_index(dv, wpi->active.index);
718 /* get the mirror def vars */
719 if (index_mirr != -1) {
720 dv_mirr = &me->dvert[index_mirr];
721 if (wp->flag & VP_FLAG_VGROUP_RESTRICT) {
722 dw_mirr = defvert_find_index(dv_mirr, vgroup_mirr);
724 if (dw_mirr == NULL) {
725 index_mirr = vgroup_mirr = -1;
730 if (index != index_mirr) {
731 dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
734 /* dv and dv_mirr are the same */
735 int totweight_prev = dv_mirr->totweight;
736 int dw_offset = (int)(dw - dv_mirr->dw);
737 dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
739 /* if we added another, get our old one back */
740 if (totweight_prev != dv_mirr->totweight) {
741 dw = &dv_mirr->dw[dw_offset];
751 if (!brush_use_accumulate(wp->paint.brush)) {
752 MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
753 MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
754 if (index_mirr != -1) {
755 defweight_prev_init(dvert_prev, me->dvert, index_mirr);
758 weight_prev = defvert_find_weight(dv_prev, wpi->active.index);
761 weight_prev = dw->weight;
764 /* If there are no normalize-locks or multipaint,
765 * then there is no need to run the more complicated checks */
768 float new_weight = wpaint_blend(
769 wp, weight_prev, alpha, paintweight,
770 wpi->brush_alpha_value, wpi->do_flip);
772 dw->weight = wpaint_clamp_monotonic(weight_prev, dw->weight, new_weight);
774 /* WATCH IT: take care of the ordering of applying mirror -> normalize,
775 * can give wrong results [#26193], least confusing if normalize is done last */
778 if (index_mirr != -1) {
779 /* copy, not paint again */
780 dw_mirr->weight = dw->weight;
783 /* apply normalize */
784 if (wpi->do_auto_normalize) {
785 /* note on normalize - this used to be applied after painting and normalize all weights,
786 * in some ways this is good because there is feedback where the more weights involved would
787 * 'resist' so you couldn't instantly zero out other weights by painting 1.0 on the active.
789 * However this gave a problem since applying mirror, then normalize both verts
790 * the resulting weight wont match on both sides.
792 * If this 'resisting', slower normalize is nicer, we could call
793 * do_weight_paint_normalize_all() and only use...
794 * do_weight_paint_normalize_all_active() when normalizing the mirror vertex.
797 do_weight_paint_normalize_all_locked_try_active(
798 dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
800 if (index_mirr != -1) {
801 /* only normalize if this is not a center vertex, else we get a conflict, normalizing twice */
802 if (index != index_mirr) {
803 do_weight_paint_normalize_all_locked_try_active(
804 dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->mirror.lock);
807 /* this case accounts for...
808 * - painting onto a center vertex of a mesh
809 * - x mirror is enabled
810 * - auto normalize is enabled
811 * - the group you are painting onto has a L / R version
813 * We want L/R vgroups to have the same weight but this cant be if both are over 0.5,
814 * We _could_ have special check for that, but this would need its own normalize function which
815 * holds 2 groups from changing at once.
817 * So! just balance out the 2 weights, it keeps them equal and everything normalized.
819 * While it wont hit the desired weight immediately as the user waggles their mouse,
820 * constant painting and re-normalizing will get there. this is also just simpler logic.
822 dw_mirr->weight = dw->weight = (dw_mirr->weight + dw->weight) * 0.5f;
829 static void do_weight_paint_vertex_multi(
830 /* vars which remain the same for every vert */
831 const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
832 /* vars which change on each stroke */
833 const uint index, float alpha, float paintweight)
836 MDeformVert *dv = &me->dvert[index];
837 bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
841 MDeformVert *dv_mirr = NULL;
844 float curw, oldw, neww, change, curw_mirr, change_mirr;
846 /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
847 if (me->editflag & ME_EDIT_MIRROR_X) {
848 index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
850 if (index_mirr != -1 && index_mirr != index) {
851 dv_mirr = &me->dvert[index_mirr];
858 /* compute weight change by applying the brush to average or sum of group weights */
859 curw = BKE_defvert_multipaint_collective_weight(
860 dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
863 /* note: no weight to assign to this vertex, could add all groups? */
867 if (!brush_use_accumulate(wp->paint.brush)) {
868 MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
869 MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
870 if (index_mirr != -1) {
871 defweight_prev_init(dvert_prev, me->dvert, index_mirr);
874 oldw = BKE_defvert_multipaint_collective_weight(
875 dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
881 neww = wpaint_blend(wp, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
882 neww = wpaint_clamp_monotonic(oldw, curw, neww);
884 change = neww / curw;
886 /* verify for all groups that 0 < result <= 1 */
887 multipaint_clamp_change(dv, wpi->defbase_tot, wpi->defbase_sel, &change);
889 if (dv_mirr != NULL) {
890 curw_mirr = BKE_defvert_multipaint_collective_weight(
891 dv_mirr, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
893 if (curw_mirr == 0.0f) {
894 /* can't mirror into a zero weight vertex */
898 /* mirror is changed to achieve the same collective weight value */
899 float orig = change_mirr = curw * change / curw_mirr;
901 multipaint_clamp_change(dv_mirr, wpi->defbase_tot, wpi->defbase_sel, &change_mirr);
903 if (!multipaint_verify_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel)) {
907 change *= change_mirr / orig;
911 if (!multipaint_verify_change(dv, wpi->defbase_tot, change, wpi->defbase_sel)) {
915 /* apply validated change to vertex and mirror */
916 multipaint_apply_change(dv, wpi->defbase_tot, change, wpi->defbase_sel);
918 if (dv_mirr != NULL) {
919 multipaint_apply_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel);
923 if (wpi->do_auto_normalize) {
924 do_weight_paint_normalize_all_locked_try_active(
925 dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
927 if (dv_mirr != NULL) {
928 do_weight_paint_normalize_all_locked_try_active(
929 dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
934 static void do_weight_paint_vertex(
935 /* vars which remain the same for every vert */
936 const VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
937 /* vars which change on each stroke */
938 const uint index, float alpha, float paintweight)
940 if (wpi->do_multipaint) {
941 do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight);
944 do_weight_paint_vertex_single(wp, ob, wpi, index, alpha, paintweight);
949 /* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */
950 static void vertex_paint_init_session(const EvaluationContext *eval_ctx, Scene *scene, Object *ob)
952 /* Create persistent sculpt mode data */
953 BKE_sculpt_toolsettings_data_ensure(scene);
955 if (ob->sculpt == NULL) {
956 ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
957 BKE_sculpt_update_mesh_elements(eval_ctx, scene, scene->toolsettings->sculpt, ob, 0, false);
961 static void vertex_paint_init_session_data(
962 const EvaluationContext *eval_ctx, const ToolSettings *ts, Object *ob)
965 struct SculptVertexPaintGeomMap *gmap = NULL;
966 const Brush *brush = NULL;
967 if (eval_ctx->object_mode == OB_MODE_VERTEX_PAINT) {
968 gmap = &ob->sculpt->mode.vpaint.gmap;
969 brush = BKE_paint_brush(&ts->vpaint->paint);
970 ob->sculpt->mode_type = OB_MODE_VERTEX_PAINT;
972 else if (eval_ctx->object_mode == OB_MODE_WEIGHT_PAINT) {
973 gmap = &ob->sculpt->mode.wpaint.gmap;
974 brush = BKE_paint_brush(&ts->wpaint->paint);
975 ob->sculpt->mode_type = OB_MODE_WEIGHT_PAINT;
978 ob->sculpt->mode_type = 0;
985 if (gmap->vert_to_loop == NULL) {
986 gmap->vert_map_mem = NULL;
987 gmap->vert_to_loop = NULL;
988 gmap->poly_map_mem = NULL;
989 gmap->vert_to_poly = NULL;
990 BKE_mesh_vert_loop_map_create(
993 me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
994 BKE_mesh_vert_poly_map_create(
997 me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
1000 /* Create average brush arrays */
1001 if (eval_ctx->object_mode == OB_MODE_VERTEX_PAINT) {
1002 if (!brush_use_accumulate(brush)) {
1003 if (ob->sculpt->mode.vpaint.previous_color == NULL) {
1004 ob->sculpt->mode.vpaint.previous_color =
1005 MEM_callocN(me->totloop * sizeof(uint), __func__);
1009 MEM_SAFE_FREE(ob->sculpt->mode.vpaint.previous_color);
1012 else if (eval_ctx->object_mode == OB_MODE_WEIGHT_PAINT) {
1013 if (!brush_use_accumulate(brush)) {
1014 if (ob->sculpt->mode.wpaint.alpha_weight == NULL) {
1015 ob->sculpt->mode.wpaint.alpha_weight =
1016 MEM_callocN(me->totvert * sizeof(float), __func__);
1018 if (ob->sculpt->mode.wpaint.dvert_prev == NULL) {
1019 ob->sculpt->mode.wpaint.dvert_prev =
1020 MEM_callocN(me->totvert * sizeof(MDeformVert), __func__);
1021 MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
1022 for (int i = 0; i < me->totvert; i++, dv++) {
1023 /* Use to show this isn't initialized, never apply to the mesh data. */
1029 MEM_SAFE_FREE(ob->sculpt->mode.wpaint.alpha_weight);
1030 if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
1031 BKE_defvert_array_free_elems(ob->sculpt->mode.wpaint.dvert_prev, me->totvert);
1032 MEM_freeN(ob->sculpt->mode.wpaint.dvert_prev);
1033 ob->sculpt->mode.wpaint.dvert_prev = NULL;
1040 /* -------------------------------------------------------------------- */
1041 /** \name Enter Vertex/Weight Paint Mode
1044 static void ed_vwpaintmode_enter_generic(
1045 const EvaluationContext *eval_ctx,
1046 wmWindowManager *wm,
1047 WorkSpace *workspace, Scene *scene,
1048 Object *ob, const eObjectMode mode_flag)
1050 workspace->object_mode |= mode_flag;
1051 Mesh *me = BKE_mesh_from_object(ob);
1053 if (mode_flag == OB_MODE_VERTEX_PAINT) {
1054 const ePaintMode paint_mode = ePaintVertex;
1055 ED_mesh_color_ensure(me, NULL);
1057 if (scene->toolsettings->vpaint == NULL) {
1058 scene->toolsettings->vpaint = new_vpaint();
1061 Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
1062 paint_cursor_start_explicit(paint, wm, vertex_paint_poll);
1063 BKE_paint_init(scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
1065 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
1066 const ePaintMode paint_mode = ePaintWeight;
1068 if (scene->toolsettings->wpaint == NULL) {
1069 scene->toolsettings->wpaint = new_vpaint();
1072 Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
1073 paint_cursor_start_explicit(paint, wm, weight_paint_poll);
1074 BKE_paint_init(scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
1076 /* weight paint specific */
1077 ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
1078 ED_vgroup_sync_from_pose(ob);
1084 /* Create vertex/weight paint mode session data */
1086 if (ob->sculpt->cache) {
1087 sculpt_cache_free(ob->sculpt->cache);
1088 ob->sculpt->cache = NULL;
1090 BKE_sculptsession_free(ob);
1093 vertex_paint_init_session(eval_ctx, scene, ob);
1095 ED_workspace_object_mode_sync_from_object(wm, workspace, ob);
1098 void ED_object_vpaintmode_enter_ex(
1099 const EvaluationContext *eval_ctx, wmWindowManager *wm,
1100 WorkSpace *workspace, Scene *scene, Object *ob)
1102 ed_vwpaintmode_enter_generic(
1103 eval_ctx, wm, workspace, scene, ob, OB_MODE_VERTEX_PAINT);
1105 void ED_object_vpaintmode_enter(struct bContext *C)
1107 EvaluationContext eval_ctx;
1108 CTX_data_eval_ctx(C, &eval_ctx);
1109 wmWindowManager *wm = CTX_wm_manager(C);
1110 WorkSpace *workspace = CTX_wm_workspace(C);
1111 Scene *scene = CTX_data_scene(C);
1112 Object *ob = CTX_data_active_object(C);
1113 ED_object_vpaintmode_enter_ex(&eval_ctx, wm, workspace, scene, ob);
1116 void ED_object_wpaintmode_enter_ex(
1117 const EvaluationContext *eval_ctx, wmWindowManager *wm,
1118 WorkSpace *workspace, Scene *scene, Object *ob)
1120 ed_vwpaintmode_enter_generic(
1121 eval_ctx, wm, workspace, scene, ob, OB_MODE_WEIGHT_PAINT);
1123 void ED_object_wpaintmode_enter(struct bContext *C)
1125 EvaluationContext eval_ctx;
1126 CTX_data_eval_ctx(C, &eval_ctx);
1127 wmWindowManager *wm = CTX_wm_manager(C);
1128 WorkSpace *workspace = CTX_wm_workspace(C);
1129 Scene *scene = CTX_data_scene(C);
1130 Object *ob = CTX_data_active_object(C);
1131 ED_object_wpaintmode_enter_ex(&eval_ctx, wm, workspace, scene, ob);
1136 /* -------------------------------------------------------------------- */
1137 /** \name Exit Vertex/Weight Paint Mode
1140 static void ed_vwpaintmode_exit_generic(
1141 WorkSpace *workspace,
1142 Object *ob, const eObjectMode mode_flag)
1144 Mesh *me = BKE_mesh_from_object(ob);
1145 workspace->object_mode &= ~mode_flag;
1147 if (mode_flag == OB_MODE_VERTEX_PAINT) {
1148 if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
1149 BKE_mesh_flush_select_from_polys(me);
1151 else if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
1152 BKE_mesh_flush_select_from_verts(me);
1155 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
1156 if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
1157 BKE_mesh_flush_select_from_verts(me);
1159 else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
1160 BKE_mesh_flush_select_from_polys(me);
1167 /* If the cache is not released by a cancel or a done, free it now. */
1168 if (ob->sculpt->cache) {
1169 sculpt_cache_free(ob->sculpt->cache);
1170 ob->sculpt->cache = NULL;
1173 BKE_sculptsession_free(ob);
1175 paint_cursor_delete_textures();
1177 if (mode_flag == OB_MODE_WEIGHT_PAINT) {
1178 ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
1179 ED_mesh_mirror_topo_table(NULL, NULL, 'e');
1182 ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob);
1185 void ED_object_vpaintmode_exit_ex(WorkSpace *workspace, Object *ob)
1187 ed_vwpaintmode_exit_generic(workspace, ob, OB_MODE_VERTEX_PAINT);
1189 void ED_object_vpaintmode_exit(struct bContext *C)
1191 WorkSpace *workspace = CTX_wm_workspace(C);
1192 Object *ob = CTX_data_active_object(C);
1193 ED_object_vpaintmode_exit_ex(workspace, ob);
1196 void ED_object_wpaintmode_exit_ex(WorkSpace *workspace, Object *ob)
1198 ed_vwpaintmode_exit_generic(workspace, ob, OB_MODE_WEIGHT_PAINT);
1200 void ED_object_wpaintmode_exit(struct bContext *C)
1202 WorkSpace *workspace = CTX_wm_workspace(C);
1203 Object *ob = CTX_data_active_object(C);
1204 ED_object_wpaintmode_exit_ex(workspace, ob);
1209 /* *************** set wpaint operator ****************** */
1212 * \note Keep in sync with #vpaint_mode_toggle_exec
1214 static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
1216 WorkSpace *workspace = CTX_wm_workspace(C);
1217 Object *ob = CTX_data_active_object(C);
1218 const int mode_flag = OB_MODE_WEIGHT_PAINT;
1219 const bool is_mode_set = (workspace->object_mode & mode_flag) != 0;
1220 Scene *scene = CTX_data_scene(C);
1223 if (!ED_object_mode_compat_set(C, workspace, mode_flag, op->reports)) {
1224 return OPERATOR_CANCELLED;
1228 Mesh *me = BKE_mesh_from_object(ob);
1231 ED_object_wpaintmode_exit_ex(workspace, ob);
1234 EvaluationContext eval_ctx;
1235 CTX_data_eval_ctx(C, &eval_ctx);
1236 wmWindowManager *wm = CTX_wm_manager(C);
1237 ED_object_wpaintmode_enter_ex(&eval_ctx, wm, workspace, scene, ob);
1240 BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
1242 /* Weightpaint works by overriding colors in mesh,
1243 * so need to make sure we recalc on enter and
1244 * exit (exit needs doing regardless because we
1247 DEG_id_tag_update(&me->id, 0);
1249 WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
1251 return OPERATOR_FINISHED;
1254 /* for switching to/from mode */
1255 static int paint_poll_test(bContext *C)
1257 Object *ob = CTX_data_active_object(C);
1258 if (ob == NULL || ob->type != OB_MESH)
1260 if (!ob->data || ID_IS_LINKED(ob->data))
1262 if (CTX_data_edit_object(C))
1267 void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
1271 ot->name = "Weight Paint Mode";
1272 ot->idname = "PAINT_OT_weight_paint_toggle";
1273 ot->description = "Toggle weight paint mode in 3D view";
1276 ot->exec = wpaint_mode_toggle_exec;
1277 ot->poll = paint_poll_test;
1280 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1283 /* ************ weight paint operator ********** */
1287 struct NormalAnglePrecalc normal_angle_precalc;
1289 struct WeightPaintGroupData active, mirror;
1291 /* variables for auto normalize */
1292 const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
1293 const bool *lock_flags;
1295 /* variables for multipaint */
1296 const bool *defbase_sel; /* set of selected groups */
1297 int defbase_tot_sel; /* number of selected groups */
1298 bool do_multipaint; /* true if multipaint enabled and multiple groups selected */
1302 /* original weight values for use in blur/smear */
1303 float *precomputed_weight;
1304 bool precomputed_weight_ready;
1307 /* Initialize the stroke cache invariants from operator properties */
1308 static void vwpaint_update_cache_invariants(
1309 bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
1312 Scene *scene = CTX_data_scene(C);
1313 UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
1314 const Brush *brush = vp->paint.brush;
1315 ViewContext *vc = paint_stroke_view_context(op->customdata);
1316 Object *ob = CTX_data_active_object(C);
1318 float view_dir[3] = {0.0f, 0.0f, 1.0f};
1321 /* VW paint needs to allocate stroke cache before update is called. */
1323 cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
1330 /* Initial mouse location */
1332 copy_v2_v2(cache->initial_mouse, mouse);
1334 zero_v2(cache->initial_mouse);
1336 mode = RNA_enum_get(op->ptr, "mode");
1337 cache->invert = mode == BRUSH_STROKE_INVERT;
1338 cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
1339 /* not very nice, but with current events system implementation
1340 * we can't handle brush appearance inversion hotkey separately (sergey) */
1341 if (cache->invert) ups->draw_inverted = true;
1342 else ups->draw_inverted = false;
1344 copy_v2_v2(cache->mouse, cache->initial_mouse);
1345 /* Truly temporary data that isn't stored in properties */
1347 cache->brush = brush;
1348 cache->first_time = 1;
1350 /* cache projection matrix */
1351 ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat);
1353 invert_m4_m4(ob->imat, ob->obmat);
1354 copy_m3_m4(mat, cache->vc->rv3d->viewinv);
1355 mul_m3_v3(mat, view_dir);
1356 copy_m3_m4(mat, ob->imat);
1357 mul_m3_v3(mat, view_dir);
1358 normalize_v3_v3(cache->true_view_normal, view_dir);
1360 copy_v3_v3(cache->view_normal, cache->true_view_normal);
1361 cache->bstrength = BKE_brush_alpha_get(scene, brush);
1362 cache->is_last_valid = false;
1365 /* Initialize the stroke cache variants from operator properties */
1366 static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, PointerRNA *ptr)
1368 Scene *scene = CTX_data_scene(C);
1369 SculptSession *ss = ob->sculpt;
1370 StrokeCache *cache = ss->cache;
1371 Brush *brush = BKE_paint_brush(&vp->paint);
1373 /* This effects the actual brush radius, so things farther away
1374 * are compared with a larger radius and vise versa. */
1375 if (cache->first_time) {
1376 RNA_float_get_array(ptr, "location", cache->true_location);
1379 RNA_float_get_array(ptr, "mouse", cache->mouse);
1381 /* XXX: Use pressure value from first brush step for brushes which don't
1382 * support strokes (grab, thumb). They depends on initial state and
1383 * brush coord/pressure/etc.
1384 * It's more an events design issue, which doesn't split coordinate/pressure/angle
1385 * changing events. We should avoid this after events system re-design */
1386 if (paint_supports_dynamic_size(brush, ePaintSculpt) || cache->first_time) {
1387 cache->pressure = RNA_float_get(ptr, "pressure");
1390 /* Truly temporary data that isn't stored in properties */
1391 if (cache->first_time) {
1392 if (!BKE_brush_use_locked_size(scene, brush)) {
1393 cache->initial_radius = paint_calc_object_space_radius(
1394 cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
1395 BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
1398 cache->initial_radius = BKE_brush_unprojected_radius_get(scene, brush);
1402 if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, ePaintSculpt)) {
1403 cache->radius = cache->initial_radius * cache->pressure;
1406 cache->radius = cache->initial_radius;
1409 cache->radius_squared = cache->radius * cache->radius;
1412 BKE_pbvh_update(ss->pbvh, PBVH_UpdateRedraw, NULL);
1413 BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
1417 static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
1419 Scene *scene = CTX_data_scene(C);
1420 struct PaintStroke *stroke = op->customdata;
1421 ToolSettings *ts = scene->toolsettings;
1422 Object *ob = CTX_data_active_object(C);
1423 Mesh *me = BKE_mesh_from_object(ob);
1424 struct WPaintData *wpd;
1425 struct WPaintVGroupIndex vgroup_index;
1426 int defbase_tot, defbase_tot_sel;
1428 SculptSession *ss = ob->sculpt;
1429 VPaint *vp = CTX_data_tool_settings(C)->wpaint;
1430 EvaluationContext eval_ctx;
1432 if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
1436 CTX_data_eval_ctx(C, &eval_ctx);
1439 /* check if we are attempting to paint onto a locked vertex group,
1440 * and other options disallow it from doing anything useful */
1442 dg = BLI_findlink(&ob->defbase, vgroup_index.active);
1443 if (dg->flag & DG_LOCK_WEIGHT) {
1444 BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
1447 if (vgroup_index.mirror != -1) {
1448 dg = BLI_findlink(&ob->defbase, vgroup_index.mirror);
1449 if (dg->flag & DG_LOCK_WEIGHT) {
1450 BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting");
1456 /* check that multipaint groups are unlocked */
1457 defbase_tot = BLI_listbase_count(&ob->defbase);
1458 defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_tot_sel);
1460 if (ts->multipaint && defbase_tot_sel > 1) {
1464 if (me->editflag & ME_EDIT_MIRROR_X) {
1465 BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
1468 for (i = 0; i < defbase_tot; i++) {
1469 if (defbase_sel[i]) {
1470 dg = BLI_findlink(&ob->defbase, i);
1471 if (dg->flag & DG_LOCK_WEIGHT) {
1472 BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting");
1473 MEM_freeN(defbase_sel);
1480 /* ALLOCATIONS! no return after this line */
1481 /* make mode data storage */
1482 wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
1483 paint_stroke_set_mode_data(stroke, wpd);
1484 view3d_set_viewcontext(C, &wpd->vc);
1485 view_angle_limits_init(&wpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
1486 (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
1488 wpd->active.index = vgroup_index.active;
1489 wpd->mirror.index = vgroup_index.mirror;
1492 wpd->defbase_tot = defbase_tot;
1493 wpd->defbase_sel = defbase_sel;
1494 wpd->defbase_tot_sel = defbase_tot_sel > 1 ? defbase_tot_sel : 1;
1495 wpd->do_multipaint = (ts->multipaint && defbase_tot_sel > 1);
1497 /* set up auto-normalize, and generate map for detecting which
1498 * vgroups affect deform bones */
1499 wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot);
1500 if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) {
1501 wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot);
1504 if (wpd->do_multipaint && ts->auto_normalize) {
1506 tmpflags = MEM_mallocN(sizeof(bool) * defbase_tot, __func__);
1507 if (wpd->lock_flags) {
1508 BLI_array_binary_or(tmpflags, wpd->defbase_sel, wpd->lock_flags, wpd->defbase_tot);
1511 memcpy(tmpflags, wpd->defbase_sel, sizeof(*tmpflags) * wpd->defbase_tot);
1513 wpd->active.lock = tmpflags;
1515 else if (ts->auto_normalize) {
1518 tmpflags = wpd->lock_flags ?
1519 MEM_dupallocN(wpd->lock_flags) :
1520 MEM_callocN(sizeof(bool) * defbase_tot, __func__);
1521 tmpflags[wpd->active.index] = true;
1522 wpd->active.lock = tmpflags;
1524 tmpflags = wpd->lock_flags ?
1525 MEM_dupallocN(wpd->lock_flags) :
1526 MEM_callocN(sizeof(bool) * defbase_tot, __func__);
1527 tmpflags[(wpd->mirror.index != -1) ? wpd->mirror.index : wpd->active.index] = true;
1528 wpd->mirror.lock = tmpflags;
1531 if (ELEM(vp->paint.brush->vertexpaint_tool, PAINT_BLEND_SMEAR, PAINT_BLEND_BLUR)) {
1532 wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
1535 /* If not previously created, create vertex/weight paint mode session data */
1536 vertex_paint_init_session(&eval_ctx, scene, ob);
1537 vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
1538 vertex_paint_init_session_data(&eval_ctx, ts, ob);
1540 if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
1541 MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
1542 for (int i = 0; i < me->totvert; i++, dv++) {
1543 /* Use to show this isn't initialized, never apply to the mesh data. */
1551 static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3])
1554 normal_short_to_float_v3(normal, vertexNormal);
1555 return dot_v3v3(brushNormal, normal);
1558 static void get_brush_alpha_data(
1559 const Scene *scene, const SculptSession *ss, const Brush *brush,
1560 float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure)
1562 *r_brush_size_pressure =
1563 BKE_brush_size_get(scene, brush) *
1564 (BKE_brush_use_size_pressure(scene, brush) ? ss->cache->pressure : 1.0f);
1565 *r_brush_alpha_value =
1566 BKE_brush_alpha_get(scene, brush);
1567 *r_brush_alpha_pressure =
1568 (BKE_brush_use_alpha_pressure(scene, brush) ? ss->cache->pressure : 1.0f);
1571 static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintInfo *wpi)
1573 if (wpi->do_multipaint) {
1574 float weight = BKE_defvert_multipaint_collective_weight(
1575 dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
1577 CLAMP(weight, 0.0f, 1.0f);
1581 return defvert_find_weight(dv, wpi->active.index);
1585 static void do_wpaint_precompute_weight_cb_ex(
1586 void *__restrict userdata,
1588 const ParallelRangeTLS *__restrict UNUSED(tls))
1590 SculptThreadedTaskData *data = userdata;
1591 const MDeformVert *dv = &data->me->dvert[n];
1593 data->wpd->precomputed_weight[n] = wpaint_get_active_weight(dv, data->wpi);
1596 static void precompute_weight_values(
1597 bContext *C, Object *ob, Brush *brush, struct WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
1599 if (wpd->precomputed_weight_ready && !brush_use_accumulate(brush))
1602 /* threaded loop over vertices */
1603 SculptThreadedTaskData data = {
1604 .C = C, .ob = ob, .wpd = wpd, .wpi = wpi, .me = me,
1607 ParallelRangeSettings settings;
1608 BLI_parallel_range_settings_defaults(&settings);
1609 BLI_task_parallel_range(
1612 do_wpaint_precompute_weight_cb_ex,
1615 wpd->precomputed_weight_ready = true;
1618 static void do_wpaint_brush_blur_task_cb_ex(
1619 void *__restrict userdata,
1621 const ParallelRangeTLS *__restrict UNUSED(tls))
1623 SculptThreadedTaskData *data = userdata;
1624 SculptSession *ss = data->ob->sculpt;
1625 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
1626 const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
1628 const Brush *brush = data->brush;
1629 const StrokeCache *cache = ss->cache;
1630 Scene *scene = CTX_data_scene(data->C);
1632 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1633 get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1634 const bool use_normal = vwpaint_use_normal(data->vp);
1635 const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1636 const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
1638 SculptBrushTest test;
1639 SculptBrushTestFn sculpt_brush_test_sq_fn =
1640 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
1641 const float *sculpt_normal_frontface =
1642 sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
1644 /* For each vertex */
1646 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
1648 /* Test to see if the vertex coordinates are within the spherical brush region. */
1649 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
1650 /* For grid based pbvh, take the vert whose loop coopresponds to the current grid.
1651 * Otherwise, take the current vert. */
1652 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
1653 const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
1654 const char v_flag = data->me->mvert[v_index].flag;
1655 /* If the vertex is selected */
1656 if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
1657 /* Get the average poly weight */
1658 int total_hit_loops = 0;
1659 float weight_final = 0.0f;
1660 for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
1661 const int p_index = gmap->vert_to_poly[v_index].indices[j];
1662 const MPoly *mp = &data->me->mpoly[p_index];
1664 total_hit_loops += mp->totloop;
1665 for (int k = 0; k < mp->totloop; k++) {
1666 const int l_index = mp->loopstart + k;
1667 const MLoop *ml = &data->me->mloop[l_index];
1668 weight_final += data->wpd->precomputed_weight[ml->v];
1672 /* Apply the weight to the vertex. */
1673 if (total_hit_loops != 0) {
1674 float brush_strength = cache->bstrength;
1675 const float angle_cos = (use_normal && vd.no) ?
1676 dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
1677 if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
1678 (angle_cos > 0.0f)) &&
1679 ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
1680 view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
1682 const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
1683 const float final_alpha =
1684 brush_fade * brush_strength *
1685 grid_alpha * brush_alpha_pressure;
1687 if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
1688 if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
1689 ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
1696 weight_final /= total_hit_loops;
1697 /* Only paint visable verts */
1698 do_weight_paint_vertex(
1699 data->vp, data->ob, data->wpi,
1700 v_index, final_alpha, weight_final);
1706 BKE_pbvh_vertex_iter_end;
1709 static void do_wpaint_brush_smear_task_cb_ex(
1710 void *__restrict userdata,
1712 const ParallelRangeTLS *__restrict UNUSED(tls))
1714 SculptThreadedTaskData *data = userdata;
1715 SculptSession *ss = data->ob->sculpt;
1716 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
1717 const struct SculptVertexPaintGeomMap *gmap = &ss->mode.wpaint.gmap;
1719 const Brush *brush = data->brush;
1720 const Scene *scene = CTX_data_scene(data->C);
1721 const StrokeCache *cache = ss->cache;
1722 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1723 get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1724 const bool use_normal = vwpaint_use_normal(data->vp);
1725 const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1726 const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
1729 sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
1730 project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
1732 if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
1734 SculptBrushTest test;
1735 SculptBrushTestFn sculpt_brush_test_sq_fn =
1736 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
1737 const float *sculpt_normal_frontface =
1738 sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
1740 /* For each vertex */
1742 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
1744 /* Test to see if the vertex coordinates are within the spherical brush region. */
1745 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
1746 /* For grid based pbvh, take the vert whose loop cooresponds to the current grid.
1747 * Otherwise, take the current vert. */
1748 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
1749 const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
1750 const MVert *mv_curr = &data->me->mvert[v_index];
1752 /* If the vertex is selected */
1753 if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
1754 float brush_strength = cache->bstrength;
1755 const float angle_cos = (use_normal && vd.no) ?
1756 dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
1757 if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
1758 (angle_cos > 0.0f)) &&
1759 ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
1760 view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
1762 bool do_color = false;
1763 /* Minimum dot product between brush direction and current
1764 * to neighbor direction is 0.0, meaning orthogonal. */
1765 float stroke_dot_max = 0.0f;
1767 /* Get the color of the loop in the opposite direction of the brush movement
1768 * (this callback is specifically for smear.) */
1769 float weight_final = 0.0;
1770 for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
1771 const int p_index = gmap->vert_to_poly[v_index].indices[j];
1772 const MPoly *mp = &data->me->mpoly[p_index];
1773 const MLoop *ml_other = &data->me->mloop[mp->loopstart];
1774 for (int k = 0; k < mp->totloop; k++, ml_other++) {
1775 const uint v_other_index = ml_other->v;
1776 if (v_other_index != v_index) {
1777 const MVert *mv_other = &data->me->mvert[v_other_index];
1779 /* Get the direction from the selected vert to the neighbor. */
1781 sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
1782 project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
1784 normalize_v3(other_dir);
1786 const float stroke_dot = dot_v3v3(other_dir, brush_dir);
1788 if (stroke_dot > stroke_dot_max) {
1789 stroke_dot_max = stroke_dot;
1790 weight_final = data->wpd->precomputed_weight[v_other_index];
1796 /* Apply weight to vertex */
1798 const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
1799 const float final_alpha =
1800 brush_fade * brush_strength *
1801 grid_alpha * brush_alpha_pressure;
1803 if (final_alpha <= 0.0f)
1806 do_weight_paint_vertex(
1807 data->vp, data->ob, data->wpi,
1808 v_index, final_alpha, (float)weight_final);
1814 BKE_pbvh_vertex_iter_end;
1818 static void do_wpaint_brush_draw_task_cb_ex(
1819 void *__restrict userdata,
1821 const ParallelRangeTLS *__restrict UNUSED(tls))
1823 SculptThreadedTaskData *data = userdata;
1824 SculptSession *ss = data->ob->sculpt;
1825 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
1826 const Scene *scene = CTX_data_scene(data->C);
1828 const Brush *brush = data->brush;
1829 const StrokeCache *cache = ss->cache;
1830 /* note: normally `BKE_brush_weight_get(scene, brush)` is used,
1831 * however in this case we calculate a new weight each time. */
1832 const float paintweight = data->strength;
1833 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1834 get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1835 const bool use_normal = vwpaint_use_normal(data->vp);
1836 const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1837 const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
1839 SculptBrushTest test;
1840 SculptBrushTestFn sculpt_brush_test_sq_fn =
1841 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
1842 const float *sculpt_normal_frontface =
1843 sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
1845 /* For each vertex */
1847 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
1849 /* Test to see if the vertex coordinates are within the spherical brush region. */
1850 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
1851 /* Note: grids are 1:1 with corners (aka loops).
1852 * For multires, take the vert whose loop cooresponds to the current grid.
1853 * Otherwise, take the current vert. */
1854 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
1855 const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
1857 const char v_flag = data->me->mvert[v_index].flag;
1858 /* If the vertex is selected */
1859 if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
1860 float brush_strength = cache->bstrength;
1861 const float angle_cos = (use_normal && vd.no) ?
1862 dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
1863 if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
1864 (angle_cos > 0.0f)) &&
1865 ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
1866 view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength)))
1868 const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
1869 const float final_alpha = brush_fade * brush_strength * grid_alpha * brush_alpha_pressure;
1871 if ((brush->flag & BRUSH_ACCUMULATE) == 0) {
1872 if (ss->mode.wpaint.alpha_weight[v_index] < final_alpha) {
1873 ss->mode.wpaint.alpha_weight[v_index] = final_alpha;
1880 do_weight_paint_vertex(
1881 data->vp, data->ob, data->wpi,
1882 v_index, final_alpha, paintweight);
1887 BKE_pbvh_vertex_iter_end;
1890 static void do_wpaint_brush_calc_average_weight_cb_ex(
1891 void *__restrict userdata,
1893 const ParallelRangeTLS *__restrict UNUSED(tls))
1895 SculptThreadedTaskData *data = userdata;
1896 SculptSession *ss = data->ob->sculpt;
1897 StrokeCache *cache = ss->cache;
1898 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
1900 const bool use_normal = vwpaint_use_normal(data->vp);
1901 const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1902 const bool use_vert_sel = (data->me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
1904 struct WPaintAverageAccum *accum = (struct WPaintAverageAccum *)data->custom_data + n;
1908 SculptBrushTest test;
1909 SculptBrushTestFn sculpt_brush_test_sq_fn =
1910 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
1911 const float *sculpt_normal_frontface =
1912 sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
1914 /* For each vertex */
1916 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
1918 /* Test to see if the vertex coordinates are within the spherical brush region. */
1919 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
1920 const float angle_cos = (use_normal && vd.no) ?
1921 dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
1922 if (angle_cos > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
1923 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
1924 // const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
1925 const char v_flag = data->me->mvert[v_index].flag;
1927 /* If the vertex is selected. */
1928 if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
1929 const MDeformVert *dv = &data->me->dvert[v_index];
1931 accum->value += wpaint_get_active_weight(dv, data->wpi);
1936 BKE_pbvh_vertex_iter_end;
1939 static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UNUSED(nodes), int totnode)
1941 struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
1942 data->custom_data = accum;
1944 ParallelRangeSettings settings;
1945 BLI_parallel_range_settings_defaults(&settings);
1946 settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
1947 BLI_task_parallel_range(
1950 do_wpaint_brush_calc_average_weight_cb_ex,
1954 double accum_weight = 0.0;
1955 for (int i = 0; i < totnode; i++) {
1956 accum_len += accum[i].len;
1957 accum_weight += accum[i].value;
1959 if (accum_len != 0) {
1960 accum_weight /= accum_len;
1961 data->strength = (float)accum_weight;
1964 MEM_SAFE_FREE(data->custom_data); /* 'accum' */
1968 static void wpaint_paint_leaves(
1969 bContext *C, Object *ob, Sculpt *sd, VPaint *vp, struct WPaintData *wpd, WeightPaintInfo *wpi,
1970 Mesh *me, PBVHNode **nodes, int totnode)
1972 Scene *scene = CTX_data_scene(C);
1973 const Brush *brush = ob->sculpt->cache->brush;
1975 /* threaded loop over nodes */
1976 SculptThreadedTaskData data = {
1977 .C = C, .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
1978 .vp = vp, .wpd = wpd, .wpi = wpi, .me = me,
1981 /* Use this so average can modify its weight without touching the brush. */
1982 data.strength = BKE_brush_weight_get(scene, brush);
1984 ParallelRangeSettings settings;
1985 BLI_parallel_range_settings_defaults(&settings);
1986 /* NOTE: current mirroring code cannot be run in parallel */
1987 settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
1989 switch (brush->vertexpaint_tool) {
1990 case PAINT_BLEND_AVERAGE:
1991 calculate_average_weight(&data, nodes, totnode);
1992 BLI_task_parallel_range(
1995 do_wpaint_brush_draw_task_cb_ex,
1998 case PAINT_BLEND_SMEAR:
1999 BLI_task_parallel_range(
2002 do_wpaint_brush_smear_task_cb_ex,
2005 case PAINT_BLEND_BLUR:
2006 BLI_task_parallel_range(
2009 do_wpaint_brush_blur_task_cb_ex,
2013 BLI_task_parallel_range(
2016 do_wpaint_brush_draw_task_cb_ex,
2022 static PBVHNode **vwpaint_pbvh_gather_generic(
2023 Object *ob, VPaint *wp, Sculpt *sd, Brush *brush, int *r_totnode)
2025 SculptSession *ss = ob->sculpt;
2026 const bool use_normal = vwpaint_use_normal(wp);
2027 PBVHNode **nodes = NULL;
2029 /* Build a list of all nodes that are potentially within the brush's area of influence */
2030 if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
2031 SculptSearchSphereData data = {
2034 .radius_squared = ss->cache->radius_squared,
2037 BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
2039 sculpt_pbvh_calc_area_normal(brush, ob, nodes, *r_totnode, true, ss->cache->sculpt_normal_symm);
2042 zero_v3(ss->cache->sculpt_normal_symm);
2046 struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
2047 dist_squared_ray_to_aabb_v3_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal);
2048 SculptSearchCircleData data = {
2051 .radius_squared = ss->cache->radius_squared,
2053 .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
2055 BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
2057 copy_v3_v3(ss->cache->sculpt_normal_symm, ss->cache->view_normal);
2060 zero_v3(ss->cache->sculpt_normal_symm);
2066 static void wpaint_do_paint(
2067 bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi,
2068 Mesh *me, Brush *brush, const char symm, const int axis, const int i, const float angle)
2070 SculptSession *ss = ob->sculpt;
2071 ss->cache->radial_symmetry_pass = i;
2072 sculpt_cache_calc_brushdata_symm(ss->cache, symm, axis, angle);
2075 PBVHNode **nodes = vwpaint_pbvh_gather_generic(ob, wp, sd, brush, &totnode);
2077 wpaint_paint_leaves(C, ob, sd, wp, wpd, wpi, me, nodes, totnode);
2083 static void wpaint_do_radial_symmetry(
2084 bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi,
2085 Mesh *me, Brush *brush, const char symm, const int axis)
2087 for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) {
2088 const float angle = (2.0 * M_PI) * i / wp->radial_symm[axis - 'X'];
2089 wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, axis, i, angle);
2093 /* near duplicate of: sculpt.c's, 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */
2094 static void wpaint_do_symmetrical_brush_actions(
2095 bContext *C, Object *ob, VPaint *wp, Sculpt *sd, struct WPaintData *wpd, WeightPaintInfo *wpi)
2097 Brush *brush = BKE_paint_brush(&wp->paint);
2098 Mesh *me = ob->data;
2099 SculptSession *ss = ob->sculpt;
2100 StrokeCache *cache = ss->cache;
2101 const char symm = wp->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
2104 /* initial stroke */
2105 wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0);
2106 wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X');
2107 wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y');
2108 wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z');
2110 cache->symmetry = symm;
2112 /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
2113 for (i = 1; i <= symm; i++) {
2114 if ((symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
2115 cache->mirror_symmetry_pass = i;
2116 cache->radial_symmetry_pass = 0;
2117 sculpt_cache_calc_brushdata_symm(cache, i, 0, 0);
2120 wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0);
2121 wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X');
2124 wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0);
2125 wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y');
2128 wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0);
2129 wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z');
2133 copy_v3_v3(cache->true_last_location, cache->true_location);
2134 cache->is_last_valid = true;
2137 static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
2139 Scene *scene = CTX_data_scene(C);
2140 ToolSettings *ts = CTX_data_tool_settings(C);
2141 VPaint *wp = ts->wpaint;
2142 Brush *brush = BKE_paint_brush(&wp->paint);
2143 struct WPaintData *wpd = paint_stroke_mode_data(stroke);
2145 Object *ob = CTX_data_active_object(C);
2147 SculptSession *ss = ob->sculpt;
2148 Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
2150 vwpaint_update_cache_variants(C, wp, ob, itemptr);
2155 const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
2157 /* intentionally don't initialize as NULL, make sure we initialize all members below */
2158 WeightPaintInfo wpi;
2160 /* cannot paint if there is no stroke data */
2162 /* XXX: force a redraw here, since even though we can't paint,
2163 * at least view won't freeze until stroke ends */
2164 ED_region_tag_redraw(CTX_wm_region(C));
2171 view3d_operator_needs_opengl(C);
2172 ED_view3d_init_mats_rv3d(ob, vc->rv3d);
2174 /* load projection matrix */
2175 mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
2178 /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
2179 wpi.defbase_tot = wpd->defbase_tot;
2180 wpi.defbase_sel = wpd->defbase_sel;
2181 wpi.defbase_tot_sel = wpd->defbase_tot_sel;
2183 wpi.defbase_tot_unsel = wpi.defbase_tot - wpi.defbase_tot_sel;
2184 wpi.active = wpd->active;
2185 wpi.mirror = wpd->mirror;
2186 wpi.lock_flags = wpd->lock_flags;
2187 wpi.vgroup_validmap = wpd->vgroup_validmap;
2188 wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
2189 wpi.do_multipaint = wpd->do_multipaint;
2190 wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL));
2191 wpi.brush_alpha_value = brush_alpha_value;
2192 /* *** done setting up WeightPaintInfo *** */
2194 if (wpd->precomputed_weight) {
2195 precompute_weight_values(C, ob, brush, wpd, &wpi, ob->data);
2198 wpaint_do_symmetrical_brush_actions(C, ob, wp, sd, wpd, &wpi);
2200 swap_m4m4(vc->rv3d->persmat, mat);
2202 /* calculate pivot for rotation around seletion if needed */
2203 /* also needed for "View Selected" on last stroke */
2204 paint_last_stroke_update(scene, vc->ar, mval);
2206 BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
2208 DEG_id_tag_update(ob->data, 0);
2209 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
2210 swap_m4m4(wpd->vc.rv3d->persmat, mat);
2213 if (sculpt_get_redraw_rect(vc->ar, CTX_wm_region_view3d(C), ob, &r)) {
2215 ss->cache->current_r = r;
2218 /* previous is not set in the current cache else
2219 * the partial rect will always grow */
2221 if (!BLI_rcti_is_empty(&ss->cache->previous_r))
2222 BLI_rcti_union(&r, &ss->cache->previous_r);
2225 r.xmin += vc->ar->winrct.xmin - 2;
2226 r.xmax += vc->ar->winrct.xmin + 2;
2227 r.ymin += vc->ar->winrct.ymin - 2;
2228 r.ymax += vc->ar->winrct.ymin + 2;
2230 ss->partial_redraw = 1;
2232 ED_region_tag_redraw_partial(vc->ar, &r);
2235 static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
2237 Object *ob = CTX_data_active_object(C);
2238 struct WPaintData *wpd = paint_stroke_mode_data(stroke);
2241 if (wpd->defbase_sel)
2242 MEM_freeN((void *)wpd->defbase_sel);
2243 if (wpd->vgroup_validmap)
2244 MEM_freeN((void *)wpd->vgroup_validmap);
2245 if (wpd->lock_flags)
2246 MEM_freeN((void *)wpd->lock_flags);
2247 if (wpd->active.lock)
2248 MEM_freeN((void *)wpd->active.lock);
2249 if (wpd->mirror.lock)
2250 MEM_freeN((void *)wpd->mirror.lock);
2251 if (wpd->precomputed_weight)
2252 MEM_freeN(wpd->precomputed_weight);
2257 /* and particles too */
2258 if (ob->particlesystem.first) {
2259 ParticleSystem *psys;
2262 for (psys = ob->particlesystem.first; psys; psys = psys->next) {
2263 for (i = 0; i < PSYS_TOT_VG; i++) {
2264 if (psys->vgroup[i] == ob->actdef) {
2265 psys->recalc |= PSYS_RECALC_RESET;
2272 DEG_id_tag_update(ob->data, 0);
2274 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
2276 sculpt_cache_free(ob->sculpt->cache);
2277 ob->sculpt->cache = NULL;
2281 static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2285 op->customdata = paint_stroke_new(
2286 C, op, sculpt_stroke_get_location, wpaint_stroke_test_start,
2287 wpaint_stroke_update_step, NULL,
2288 wpaint_stroke_done, event->type);
2290 if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
2291 paint_stroke_data_free(op);
2292 return OPERATOR_FINISHED;
2294 /* add modal handler */
2295 WM_event_add_modal_handler(C, op);
2297 OPERATOR_RETVAL_CHECK(retval);
2298 BLI_assert(retval == OPERATOR_RUNNING_MODAL);
2300 return OPERATOR_RUNNING_MODAL;
2303 static int wpaint_exec(bContext *C, wmOperator *op)
2305 op->customdata = paint_stroke_new(
2306 C, op, sculpt_stroke_get_location, wpaint_stroke_test_start,
2307 wpaint_stroke_update_step, NULL,
2308 wpaint_stroke_done, 0);
2310 /* frees op->customdata */
2311 paint_stroke_exec(C, op);
2313 return OPERATOR_FINISHED;
2316 static void wpaint_cancel(bContext *C, wmOperator *op)
2318 Object *ob = CTX_data_active_object(C);
2319 if (ob->sculpt->cache) {
2320 sculpt_cache_free(ob->sculpt->cache);
2321 ob->sculpt->cache = NULL;
2324 paint_stroke_cancel(C, op);
2327 void PAINT_OT_weight_paint(wmOperatorType *ot)
2330 ot->name = "Weight Paint";
2331 ot->idname = "PAINT_OT_weight_paint";
2332 ot->description = "Paint a stroke in the current vertex group's weights";
2335 ot->invoke = wpaint_invoke;
2336 ot->modal = paint_stroke_modal;
2337 ot->exec = wpaint_exec;
2338 ot->poll = weight_paint_poll;
2339 ot->cancel = wpaint_cancel;
2342 ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
2344 paint_stroke_operator_properties(ot);
2347 /* ************ set / clear vertex paint mode ********** */
2350 * \note Keep in sync with #wpaint_mode_toggle_exec
2352 static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
2354 WorkSpace *workspace = CTX_wm_workspace(C);
2355 Object *ob = CTX_data_active_object(C);
2356 const int mode_flag = OB_MODE_VERTEX_PAINT;
2357 const bool is_mode_set = (workspace->object_mode & mode_flag) != 0;
2358 Scene *scene = CTX_data_scene(C);
2361 if (!ED_object_mode_compat_set(C, workspace, mode_flag, op->reports)) {
2362 return OPERATOR_CANCELLED;
2366 Mesh *me = BKE_mesh_from_object(ob);
2368 /* toggle: end vpaint */
2370 ED_object_vpaintmode_exit_ex(workspace, ob);
2373 EvaluationContext eval_ctx;
2374 CTX_data_eval_ctx(C, &eval_ctx);
2375 wmWindowManager *wm = CTX_wm_manager(C);
2376 ED_object_vpaintmode_enter_ex(&eval_ctx, wm, workspace, scene, ob);
2379 BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
2381 /* update modifier stack for mapping requirements */
2382 DEG_id_tag_update(&me->id, 0);
2384 WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
2386 return OPERATOR_FINISHED;
2389 void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
2392 ot->name = "Vertex Paint Mode";
2393 ot->idname = "PAINT_OT_vertex_paint_toggle";
2394 ot->description = "Toggle the vertex paint mode in 3D view";
2397 ot->exec = vpaint_mode_toggle_exec;
2398 ot->poll = paint_poll_test;
2401 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2406 /* ********************** vertex paint operator ******************* */
2408 /* Implementation notes:
2410 * Operator->invoke()
2411 * - validate context (add mcol)
2412 * - create customdata storage
2413 * - call paint once (mouse click)
2414 * - add modal handler
2417 * - for every mousemove, apply vertex paint
2418 * - exit on mouse release, free customdata
2419 * (return OPERATOR_FINISHED also removes handler and operator)
2422 * - implement a stroke event (or mousemove with past positons)
2423 * - revise whether op->customdata should be added in object, in set_vpaint
2426 typedef struct PolyFaceMap {
2427 struct PolyFaceMap *next, *prev;
2433 struct NormalAnglePrecalc normal_angle_precalc;
2437 struct VertProjHandle *vp_handle;
2438 struct DMCoNo *vertexcosnos;
2440 /* modify 'me->mcol' directly, since the derived mesh is drawing from this
2441 * array, otherwise we need to refresh the modifier stack */
2442 bool use_fast_update;
2444 /* loops tagged as having been painted, to apply shared vertex color
2445 * blending only to modified loops */
2450 /* Special storage for smear brush, avoid feedback loop - update each step. */
2457 static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
2459 Scene *scene = CTX_data_scene(C);
2460 ToolSettings *ts = scene->toolsettings;
2461 struct PaintStroke *stroke = op->customdata;
2462 VPaint *vp = ts->vpaint;
2463 Brush *brush = BKE_paint_brush(&vp->paint);
2464 struct VPaintData *vpd;
2465 Object *ob = CTX_data_active_object(C);
2467 SculptSession *ss = ob->sculpt;
2468 EvaluationContext eval_ctx;
2470 CTX_data_eval_ctx(C, &eval_ctx);
2472 /* context checks could be a poll() */
2473 me = BKE_mesh_from_object(ob);
2474 if (me == NULL || me->totpoly == 0)
2477 ED_mesh_color_ensure(me, NULL);
2478 if (me->mloopcol == NULL)
2481 /* make mode data storage */
2482 vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
2483 paint_stroke_set_mode_data(stroke, vpd);
2484 view3d_set_viewcontext(C, &vpd->vc);
2485 view_angle_limits_init(&vpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
2486 (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
2488 vpd->paintcol = vpaint_get_current_col(scene, vp);
2490 vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
2493 /* are we painting onto a modified mesh?,
2494 * if not we can skip face map trickiness */
2495 if (vertex_paint_use_fast_update_check(ob)) {
2496 vpd->use_fast_update = true;
2497 /* printf("Fast update!\n");*/
2500 vpd->use_fast_update = false;
2501 /* printf("No fast update!\n");*/
2504 /* to keep tracked of modified loops for shared vertex color blending */
2505 if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
2506 vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
2509 if (brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
2510 vpd->smear.color_prev = MEM_mallocN(sizeof(uint) * me->totloop, __func__);
2511 memcpy(vpd->smear.color_prev, me->mloopcol, sizeof(uint) * me->totloop);
2512 vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
2515 /* Create projection handle */
2516 if (vpd->is_texbrush) {
2517 ob->sculpt->building_vp_handle = true;
2518 vpd->vp_handle = ED_vpaint_proj_handle_create(&eval_ctx, scene, ob, &vpd->vertexcosnos);
2519 ob->sculpt->building_vp_handle = false;
2522 /* If not previously created, create vertex/weight paint mode session data */
2523 vertex_paint_init_session(&eval_ctx, scene, ob);
2524 vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
2525 vertex_paint_init_session_data(&eval_ctx, ts, ob);
2527 if (ob->sculpt->mode.vpaint.previous_color != NULL) {
2528 memset(ob->sculpt->mode.vpaint.previous_color, 0, sizeof(uint) * me->totloop);
2534 static void do_vpaint_brush_calc_average_color_cb_ex(
2535 void *__restrict userdata,
2537 const ParallelRangeTLS *__restrict UNUSED(tls))
2539 SculptThreadedTaskData *data = userdata;
2540 SculptSession *ss = data->ob->sculpt;
2541 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
2542 const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
2544 StrokeCache *cache = ss->cache;
2545 uint *lcol = data->lcol;
2547 const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
2549 struct VPaintAverageAccum *accum = (struct VPaintAverageAccum *)data->custom_data + n;
2551 memset(accum->value, 0, sizeof(accum->value));
2553 SculptBrushTest test;
2554 SculptBrushTestFn sculpt_brush_test_sq_fn =
2555 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
2557 /* For each vertex */
2559 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
2561 /* Test to see if the vertex coordinates are within the spherical brush region. */
2562 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2563 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
2564 if (BKE_brush_curve_strength(data->brush, 0.0, cache->radius) > 0.0) {
2565 /* If the vertex is selected for painting. */
2566 const MVert *mv = &data->me->mvert[v_index];
2567 if (!use_vert_sel || mv->flag & SELECT) {
2568 accum->len += gmap->vert_to_loop[v_index].count;
2569 /* if a vertex is within the brush region, then add it's color to the blend. */
2570 for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) {
2571 const int l_index = gmap->vert_to_loop[v_index].indices[j];
2572 col = (char *)(&lcol[l_index]);
2573 /* Color is squared to compensate the sqrt color encoding. */
2574 accum->value[0] += col[0] * col[0];
2575 accum->value[1] += col[1] * col[1];
2576 accum->value[2] += col[2] * col[2];
2582 BKE_pbvh_vertex_iter_end;
2585 static float tex_color_alpha_ubyte(
2586 SculptThreadedTaskData *data, const float v_co[3],
2591 tex_color_alpha(data->vp, &data->vpd->vc, v_co, rgba);
2592 rgb_uchar_to_float(rgba_br, (const uchar *)&data->vpd->paintcol);
2593 mul_v3_v3(rgba_br, rgba);
2594 rgb_float_to_uchar((uchar *)r_color, rgba_br);
2598 static void do_vpaint_brush_draw_task_cb_ex(
2599 void *__restrict userdata,
2601 const ParallelRangeTLS *__restrict UNUSED(tls))
2603 SculptThreadedTaskData *data = userdata;
2604 SculptSession *ss = data->ob->sculpt;
2605 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
2606 const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
2608 const Brush *brush = data->brush;
2609 const StrokeCache *cache = ss->cache;
2610 uint *lcol = data->lcol;
2611 const Scene *scene = CTX_data_scene(data->C);
2612 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
2613 get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
2614 const bool use_normal = vwpaint_use_normal(data->vp);
2615 const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
2616 const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
2618 SculptBrushTest test;
2619 SculptBrushTestFn sculpt_brush_test_sq_fn =
2620 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
2621 const float *sculpt_normal_frontface =
2622 sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
2624 /* For each vertex */
2626 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
2628 /* Test to see if the vertex coordinates are within the spherical brush region. */
2629 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2630 /* Note: Grids are 1:1 with corners (aka loops).
2631 * For grid based pbvh, take the vert whose loop cooresponds to the current grid.
2632 * Otherwise, take the current vert. */
2633 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
2634 const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
2635 const MVert *mv = &data->me->mvert[v_index];
2637 /* If the vertex is selected for painting. */
2638 if (!use_vert_sel || mv->flag & SELECT) {
2639 /* Calc the dot prod. between ray norm on surf and current vert
2640 * (ie splash prevention factor), and only paint front facing verts. */
2641 float brush_strength = cache->bstrength;
2642 const float angle_cos = (use_normal && vd.no) ?
2643 dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
2644 if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
2645 (angle_cos > 0.0f)) &&
2646 ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
2647 view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
2649 const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
2650 uint color_final = data->vpd->paintcol;
2652 /* If we're painting with a texture, sample the texture color and alpha. */
2653 float tex_alpha = 1.0;
2654 if (data->vpd->is_texbrush) {
2655 /* Note: we may want to paint alpha as vertex color alpha. */
2656 tex_alpha = tex_color_alpha_ubyte(
2657 data, data->vpd->vertexcosnos[v_index].co,
2660 /* For each poly owning this vert, paint each loop belonging to this vert. */
2661 for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
2662 const int p_index = gmap->vert_to_poly[v_index].indices[j];
2663 const int l_index = gmap->vert_to_loop[v_index].indices[j];
2664 BLI_assert(data->me->mloop[l_index].v == v_index);
2665 const MPoly *mp = &data->me->mpoly[p_index];
2666 if (!use_face_sel || mp->flag & ME_FACE_SEL) {
2667 uint color_orig = 0; /* unused when array is NULL */
2668 if (ss->mode.vpaint.previous_color != NULL) {
2669 /* Get the previous loop color */
2670 if (ss->mode.vpaint.previous_color[l_index] == 0) {
2671 ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
2673 color_orig = ss->mode.vpaint.previous_color[l_index];
2675 const float final_alpha =
2676 255 * brush_fade * brush_strength *
2677 tex_alpha * brush_alpha_pressure * grid_alpha;
2679 /* Mix the new color with the original based on final_alpha. */
2680 lcol[l_index] = vpaint_blend(
2681 data->vp, lcol[l_index], color_orig, color_final,
2682 final_alpha, 255 * brush_strength);
2689 BKE_pbvh_vertex_iter_end;
2692 static void do_vpaint_brush_blur_task_cb_ex(
2693 void *__restrict userdata,
2695 const ParallelRangeTLS *__restrict UNUSED(tls))
2697 SculptThreadedTaskData *data = userdata;
2698 SculptSession *ss = data->ob->sculpt;
2699 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
2701 Scene *scene = CTX_data_scene(data->C);
2702 const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
2703 const Brush *brush = data->brush;
2704 const StrokeCache *cache = ss->cache;
2705 uint *lcol = data->lcol;
2706 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
2707 get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
2708 const bool use_normal = vwpaint_use_normal(data->vp);
2709 const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
2710 const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
2712 SculptBrushTest test;
2713 SculptBrushTestFn sculpt_brush_test_sq_fn =
2714 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
2715 const float *sculpt_normal_frontface =
2716 sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
2718 /* For each vertex */
2720 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
2722 /* Test to see if the vertex coordinates are within the spherical brush region. */
2723 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2724 /* For grid based pbvh, take the vert whose loop cooresponds to the current grid.
2725 * Otherwise, take the current vert. */
2726 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
2727 const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
2728 const MVert *mv = &data->me->mvert[v_index];
2730 /* If the vertex is selected for painting. */
2731 if (!use_vert_sel || mv->flag & SELECT) {
2732 float brush_strength = cache->bstrength;
2733 const float angle_cos = (use_normal && vd.no) ?
2734 dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
2735 if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
2736 (angle_cos > 0.0f)) &&
2737 ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
2738 view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
2740 const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
2742 /* Get the average poly color */
2743 uint color_final = 0;
2744 int total_hit_loops = 0;
2745 uint blend[4] = {0};
2746 for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
2747 int p_index = gmap->vert_to_poly[v_index].indices[j];
2748 const MPoly *mp = &data->me->mpoly[p_index];
2749 if (!use_face_sel || mp->flag & ME_FACE_SEL) {
2750 total_hit_loops += mp->totloop;
2751 for (int k = 0; k < mp->totloop; k++) {
2752 const uint l_index = mp->loopstart + k;
2753 const char *col = (const char *)(&lcol[l_index]);
2754 /* Color is squared to compensate the sqrt color encoding. */
2755 blend[0] += (uint)col[0] * (uint)col[0];
2756 blend[1] += (uint)col[1] * (uint)col[1];
2757 blend[2] += (uint)col[2] * (uint)col[2];
2758 blend[3] += (uint)col[3] * (uint)col[3];
2762 if (total_hit_loops != 0) {
2763 /* Use rgb^2 color averaging. */
2764 char *col = (char *)(&color_final);
2765 col[0] = round_fl_to_uchar(sqrtf(divide_round_i(blend[0], total_hit_loops)));
2766 col[1] = round_fl_to_uchar(sqrtf(divide_round_i(blend[1], total_hit_loops)));
2767 col[2] = round_fl_to_uchar(sqrtf(divide_round_i(blend[2], total_hit_loops)));
2768 col[3] = round_fl_to_uchar(sqrtf(divide_round_i(blend[3], total_hit_loops)));
2770 /* For each poly owning this vert, paint each loop belonging to this vert. */
2771 for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
2772 const int p_index = gmap->vert_to_poly[v_index].indices[j];
2773 const int l_index = gmap->vert_to_loop[v_index].indices[j];
2774 BLI_assert(data->me->mloop[l_index].v == v_index);
2775 const MPoly *mp = &data->me->mpoly[p_index];
2776 if (!use_face_sel || mp->flag & ME_FACE_SEL) {
2777 uint color_orig = 0; /* unused when array is NULL */
2778 if (ss->mode.vpaint.previous_color != NULL) {
2779 /* Get the previous loop color */
2780 if (ss->mode.vpaint.previous_color[l_index] == 0) {
2781 ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
2783 color_orig = ss->mode.vpaint.previous_color[l_index];
2785 const float final_alpha =
2786 255 * brush_fade * brush_strength *
2787 brush_alpha_pressure * grid_alpha;
2788 /* Mix the new color with the original
2789 * based on the brush strength and the curve. */
2790 lcol[l_index] = vpaint_blend(
2791 data->vp, lcol[l_index], color_orig, *((uint *)col),
2792 final_alpha, 255 * brush_strength);
2800 BKE_pbvh_vertex_iter_end;
2803 static void do_vpaint_brush_smear_task_cb_ex(
2804 void *__restrict userdata,
2806 const ParallelRangeTLS *__restrict UNUSED(tls))
2808 SculptThreadedTaskData *data = userdata;
2809 SculptSession *ss = data->ob->sculpt;
2810 CCGDerivedMesh *ccgdm = BKE_pbvh_get_ccgdm(ss->pbvh);
2812 Scene *scene = CTX_data_scene(data->C);
2813 const struct SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap;
2814 const Brush *brush = data->brush;
2815 const StrokeCache *cache = ss->cache;
2816 uint *lcol = data->lcol;
2817 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
2818 get_brush_alpha_data(scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
2820 const bool use_normal = vwpaint_use_normal(data->vp);
2821 const bool use_vert_sel = (data->me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
2822 const bool use_face_sel = (data->me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
2824 sub_v3_v3v3(brush_dir, cache->location, cache->last_location);
2825 project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal);
2827 if (cache->is_last_valid && (normalize_v3(brush_dir) != 0.0f)) {
2829 SculptBrushTest test;
2830 SculptBrushTestFn sculpt_brush_test_sq_fn =
2831 sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape);
2832 const float *sculpt_normal_frontface =
2833 sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape);
2835 /* For each vertex */
2837 BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
2839 /* Test to see if the vertex coordinates are within the spherical brush region. */
2840 if (sculpt_brush_test_sq_fn(&test, vd.co)) {
2841 /* For grid based pbvh, take the vert whose loop cooresponds to the current grid.
2842 * Otherwise, take the current vert. */
2843 const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i];
2844 const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f;
2845 const MVert *mv_curr = &data->me->mvert[v_index];
2847 /* if the vertex is selected for painting. */
2848 if (!use_vert_sel || mv_curr->flag & SELECT) {
2849 /* Calc the dot prod. between ray norm on surf and current vert
2850 * (ie splash prevention factor), and only paint front facing verts. */
2851 float brush_strength = cache->bstrength;
2852 const float angle_cos = (use_normal && vd.no) ?
2853 dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f;
2854 if (((brush->flag & BRUSH_FRONTFACE) == 0 ||
2855 (angle_cos > 0.0f)) &&
2856 ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
2857 view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength)))
2859 const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius);
2861 bool do_color = false;
2862 /* Minimum dot product between brush direction and current
2863 * to neighbor direction is 0.0, meaning orthogonal. */
2864 float stroke_dot_max = 0.0f;
2866 /* Get the color of the loop in the opposite direction of the brush movement */
2867 uint color_final = 0;
2868 for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
2869 const int p_index = gmap->vert_to_poly[v_index].indices[j];
2870 const int l_index = gmap->vert_to_loop[v_index].indices[j];
2871 BLI_assert(data->me->mloop[l_index].v == v_index);
2872 UNUSED_VARS_NDEBUG(l_index);
2873 const MPoly *mp = &data->me->mpoly[p_index];
2874 if (!use_face_sel || mp->flag & ME_FACE_SEL) {
2875 const MLoop *ml_other = &data->me->mloop[mp->loopstart];
2876 for (int k = 0; k < mp->totloop; k++, ml_other++) {
2877 const uint v_other_index = ml_other->v;
2878 if (v_other_index != v_index) {
2879 const MVert *mv_other = &data->me->mvert[v_other_index];
2881 /* Get the direction from the selected vert to the neighbor. */
2883 sub_v3_v3v3(other_dir, mv_curr->co, mv_other->co);
2884 project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal);
2886 normalize_v3(other_dir);
2888 const float stroke_dot = dot_v3v3(other_dir, brush_dir);
2890 if (stroke_dot > stroke_dot_max) {
2891 stroke_dot_max = stroke_dot;
2892 color_final = data->vpd->smear.color_prev[mp->loopstart + k];
2901 const float final_alpha =
2902 255 * brush_fade * brush_strength *
2903 brush_alpha_pressure * grid_alpha;
2905 /* For each poly owning this vert, paint each loop belonging to this vert. */
2906 for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) {
2907 const int p_index = gmap->vert_to_poly[v_index].indices[j];
2908 const int l_index = gmap->vert_to_loop[v_index].indices[j];
2909 BLI_assert(data->me->mloop[l_index].v == v_index);
2910 const MPoly *mp = &data->me->mpoly[p_index];
2911 if (!use_face_sel || mp->flag & ME_FACE_SEL) {
2912 /* Get the previous loop color */
2913 uint color_orig = 0; /* unused when array is NULL */
2914 if (ss->mode.vpaint.previous_color != NULL) {
2915 /* Get the previous loop color */
2916 if (ss->mode.vpaint.previous_color[l_index] == 0) {
2917 ss->mode.vpaint.previous_color[l_index] = lcol[l_index];
2919 color_orig = ss->mode.vpaint.previous_color[l_index];