Blender V5.0
paint_vertex.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13
14#include "MEM_guardedalloc.h"
15
16#include "CLG_log.h"
17
18#include "BLI_color.hh"
19#include "BLI_color_mix.hh"
21#include "BLI_math_geom.h"
22#include "BLI_math_matrix.hh"
23#include "BLI_task.hh"
24#include "BLI_vector.hh"
25
26#include "DNA_brush_types.h"
27#include "DNA_mesh_types.h"
28#include "DNA_meshdata_types.h"
29#include "DNA_object_types.h"
30#include "DNA_scene_types.h"
31
32#include "RNA_access.hh"
33#include "RNA_define.hh"
34
35#include "BKE_attribute.hh"
36#include "BKE_brush.hh"
37#include "BKE_colortools.hh"
38#include "BKE_context.hh"
39#include "BKE_deform.hh"
40#include "BKE_editmesh.hh"
41#include "BKE_library.hh"
42#include "BKE_mesh.hh"
43#include "BKE_object.hh"
44#include "BKE_object_types.hh"
45#include "BKE_paint.hh"
46#include "BKE_paint_types.hh"
47
48#include "DEG_depsgraph.hh"
49
50#include "WM_api.hh"
51#include "WM_message.hh"
52#include "WM_toolsystem.hh"
53#include "WM_types.hh"
54
55#include "ED_image.hh"
56#include "ED_mesh.hh"
57#include "ED_object.hh"
58#include "ED_object_vgroup.hh"
59#include "ED_paint.hh"
60#include "ED_screen.hh"
61#include "ED_sculpt.hh"
62#include "ED_view3d.hh"
63
64/* For IMB_BlendMode only. */
65#include "IMB_imbuf.hh"
66
67#include "bmesh.hh"
68
69#include "mesh_brush_common.hh"
70#include "paint_intern.hh" /* own include */
71#include "sculpt_automask.hh"
72#include "sculpt_intern.hh"
73#include "sculpt_pose.hh"
74
77using namespace blender;
78using namespace blender::color;
79using namespace blender::ed::sculpt_paint; /* For vwpaint namespace. */
81
82static CLG_LogRef LOG = {"paint.vertex"};
83
84/* -------------------------------------------------------------------- */
87
88static bool isZero(ColorPaint4f c)
89{
90 return c.r == 0.0f && c.g == 0.0f && c.b == 0.0f && c.a == 0.0f;
91}
92
93static bool isZero(ColorPaint4b c)
94{
95 return c.r == 0 && c.g == 0 && c.b == 0 && c.a == 0;
96}
97
98template<typename Color> static ColorPaint4f toFloat(const Color &c)
99{
100 if constexpr (std::is_same_v<Color, ColorPaint4b>) {
101 return blender::color::decode(c);
102 }
103 else {
104 return c;
105 }
106}
107
108template<typename Color> static Color fromFloat(const ColorPaint4f &c)
109{
110 if constexpr (std::is_same_v<Color, ColorPaint4b>) {
111 return blender::color::encode(c);
112 }
113 else {
114 return c;
115 }
116}
117
118/* Use for 'blur' brush, align with pbvh::Tree nodes, created and freed on each update. */
119template<typename BlendType> struct VPaintAverageAccum {
120 BlendType len;
121 BlendType value[3];
122};
123
125
126/* -------------------------------------------------------------------- */
129
130void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
131{
133 a->do_mask_normal = do_mask_normal;
134 if (do_mask_normal) {
135 a->angle_inner = angle;
136 a->angle = (a->angle_inner + 90.0f) * 0.5f;
137 }
138 else {
139 a->angle_inner = a->angle = angle;
140 }
141
142 a->angle_inner *= float(M_PI_2 / 90);
143 a->angle *= float(M_PI_2 / 90);
144 a->angle_range = a->angle - a->angle_inner;
145
146 if (a->angle_range <= 0.0f) {
147 a->do_mask_normal = false; /* no need to do blending */
148 }
149
150 a->angle__cos = cosf(a->angle);
152}
153
154float view_angle_limits_apply_falloff(const NormalAnglePrecalc *a, float angle_cos, float *mask_p)
155{
156 if (angle_cos <= a->angle__cos) {
157 /* outsize the normal limit */
158 return false;
159 }
160 if (angle_cos < a->angle_inner__cos) {
161 *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
162 return true;
163 }
164 return true;
165}
166
168 const NormalAnglePrecalc &normal_angle_precalc,
169 const float angle_cos,
170 float *brush_strength)
171{
172 if (((brush.flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
173 ((brush.flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
174 vwpaint::view_angle_limits_apply_falloff(&normal_angle_precalc, angle_cos, brush_strength)))
175 {
176 return true;
177 }
178 return false;
179}
180
181bool use_normal(const VPaint &vp)
182{
183 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
184 return ((brush.flag & BRUSH_FRONTFACE) != 0) || ((brush.flag & BRUSH_FRONTFACE_FALLOFF) != 0);
185}
186
187bool brush_use_accumulate_ex(const Brush &brush, const eObjectMode ob_mode)
188{
189 return ((brush.flag & BRUSH_ACCUMULATE) != 0 ||
190 (ob_mode == OB_MODE_VERTEX_PAINT ?
193}
194
196{
197 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
198 return brush_use_accumulate_ex(*brush, eObjectMode(vp.paint.runtime->ob_mode));
199}
200
201void init_stroke(Depsgraph &depsgraph, Object &ob)
202{
204 SculptSession &ss = *ob.sculpt;
205
206 /* Ensure ss.cache is allocated. It will mostly be initialized in
207 * vwpaint::update_cache_invariants and vwpaint::update_cache_variants.
208 */
209 if (!ss.cache) {
210 ss.cache = MEM_new<StrokeCache>(__func__);
211 }
212}
213
214void init_session(Main &bmain,
215 Depsgraph &depsgraph,
216 Scene &scene,
217 Paint &paint,
218 Object &ob,
219 eObjectMode object_mode)
220{
221 /* Create persistent sculpt mode data */
223
224 BLI_assert(ob.sculpt == nullptr);
225 ob.sculpt = MEM_new<SculptSession>(__func__);
226 ob.sculpt->mode_type = object_mode;
228
230}
231
233{
234 /* Create maps */
235 if (ob.mode == OB_MODE_VERTEX_PAINT) {
237 }
238 else if (ob.mode == OB_MODE_WEIGHT_PAINT) {
240 }
241 else {
243 BLI_assert(0);
244 return;
245 }
246
247 Mesh *mesh = (Mesh *)ob.data;
248
249 /* Create average brush arrays */
250 if (ob.mode == OB_MODE_WEIGHT_PAINT) {
251 SculptSession &ss = *ob.sculpt;
253 if (ss.mode.wpaint.alpha_weight == nullptr) {
254 ss.mode.wpaint.alpha_weight = MEM_calloc_arrayN<float>(mesh->verts_num, __func__);
255 }
256 if (ss.mode.wpaint.dvert_prev.is_empty()) {
257 MDeformVert initial_value{};
258 /* Use to show this isn't initialized, never apply to the mesh data. */
259 initial_value.flag = 1;
260 ss.mode.wpaint.dvert_prev = Array<MDeformVert>(mesh->verts_num, initial_value);
261 }
262 }
263 else {
265 if (!ss.mode.wpaint.dvert_prev.is_empty()) {
268 ss.mode.wpaint.dvert_prev = {};
269 }
270 }
271 }
272}
273
275 const Object &ob,
276 const VPaint &wp,
277 const Brush &brush,
278 IndexMaskMemory &memory)
279{
280 SculptSession &ss = *ob.sculpt;
281 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
282 const bool use_normal = vwpaint::use_normal(wp);
284
285 /* Build a list of all nodes that are potentially within the brush's area of influence */
287 nodes = bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
288 return node_in_sphere(node, ss.cache->location_symm, ss.cache->radius_squared, true);
289 });
290
292 use_normal ? calc_area_normal(depsgraph, brush, ob, nodes).value_or(float3(0)) : float3(0);
293 }
294 else {
297 nodes = bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
298 return node_in_cylinder(ray_dist_precalc, node, ss.cache->radius_squared, true);
299 });
300
302 }
303 return nodes;
304}
305
307 Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, const eObjectMode mode_flag)
308{
309 ob.mode |= mode_flag;
311
312 /* Same as sculpt mode, make sure we don't have cached derived mesh which
313 * points to freed arrays.
314 */
316
317 Paint *paint = nullptr;
318 if (mode_flag == OB_MODE_VERTEX_PAINT) {
319 const PaintMode paint_mode = PaintMode::Vertex;
320 ED_mesh_color_ensure(mesh, nullptr);
321
323 paint = BKE_paint_get_active_from_paintmode(&scene, paint_mode);
325 BKE_paint_init(&bmain, &scene, paint_mode);
326 }
327 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
328 const PaintMode paint_mode = PaintMode::Weight;
329
331 paint = BKE_paint_get_active_from_paintmode(&scene, paint_mode);
333 BKE_paint_init(&bmain, &scene, paint_mode);
334
335 /* weight paint specific */
338 }
339 else {
340 BLI_assert(0);
341 }
342
343 /* Create vertex/weight paint mode session data */
344 if (ob.sculpt) {
345 MEM_delete(ob.sculpt->cache);
346 ob.sculpt->cache = nullptr;
348 }
349
350 BLI_assert(paint != nullptr);
351 vwpaint::init_session(bmain, depsgraph, scene, *paint, ob, mode_flag);
352
353 /* Flush object mode. */
355}
356
357void mode_exit_generic(Object &ob, const eObjectMode mode_flag)
358{
359 using namespace blender;
361 ob.mode &= ~mode_flag;
362
363 if (mode_flag == OB_MODE_VERTEX_PAINT) {
364 if (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
366 }
367 else if (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
369 }
370 }
371 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
372 if (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
374 }
375 else if (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
377 }
378 }
379 else {
380 BLI_assert(0);
381 }
382
383 /* If the cache is not released by a cancel or a done, free it now. */
384 if (ob.sculpt) {
385 MEM_delete(ob.sculpt->cache);
386 ob.sculpt->cache = nullptr;
387 }
388
390
392
393 if (mode_flag == OB_MODE_WEIGHT_PAINT) {
396 }
397
398 /* Never leave derived meshes behind. */
400
401 /* Flush object mode. */
403}
404
406{
408 if (ob == nullptr || ob->type != OB_MESH) {
409 return false;
410 }
411 if (!ob->data || !ID_IS_EDITABLE(ob->data)) {
412 return false;
413 }
414 return true;
415}
416
418{
419 Brush *brush = BKE_paint_brush(paint);
420 /* The current brush should match with what we have stored in the cache. */
421 BLI_assert(brush == cache->brush);
422
423 /* If saved_active_brush is not set, brush was not switched/affected in
424 * smooth_brush_toggle_on(). */
425 if (cache->saved_active_brush) {
428 cache->saved_active_brush = nullptr;
429 }
430}
432 bContext *C, VPaint &vp, SculptSession &ss, wmOperator *op, const float mval[2])
433{
434 StrokeCache *cache;
435 bke::PaintRuntime &paint_runtime = *vp.paint.runtime;
438 float mat[3][3];
439 float view_dir[3] = {0.0f, 0.0f, 1.0f};
440 int mode;
441
442 /* VW paint needs to allocate stroke cache before update is called. */
443 if (!ss.cache) {
444 cache = MEM_new<StrokeCache>(__func__);
445 ss.cache = cache;
446 }
447 else {
448 cache = ss.cache;
449 }
450
451 /* Initial mouse location */
452 if (mval) {
453 copy_v2_v2(cache->initial_mouse, mval);
454 }
455 else {
456 zero_v2(cache->initial_mouse);
457 }
458
459 mode = RNA_enum_get(op->ptr, "mode");
460 cache->invert = mode == BRUSH_STROKE_INVERT;
461 cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
462 /* not very nice, but with current events system implementation
463 * we can't handle brush appearance inversion hotkey separately (sergey) */
464 if (cache->invert) {
465 paint_runtime.draw_inverted = true;
466 }
467 else {
468 paint_runtime.draw_inverted = false;
469 }
470
471 if (cache->alt_smooth) {
473 }
474
475 copy_v2_v2(cache->mouse, cache->initial_mouse);
476 const Brush *brush = BKE_paint_brush(&vp.paint);
477 /* Truly temporary data that isn't stored in properties */
478 cache->vc = vc;
479 cache->brush = brush;
480 cache->paint = &vp.paint;
481 cache->first_time = true;
482
483 /* cache projection matrix */
484 cache->projection_mat = ED_view3d_ob_project_mat_get(cache->vc->rv3d, &ob);
485
486 invert_m4_m4(ob.runtime->world_to_object.ptr(), ob.object_to_world().ptr());
487 copy_m3_m4(mat, cache->vc->rv3d->viewinv);
488 mul_m3_v3(mat, view_dir);
489 copy_m3_m4(mat, ob.world_to_object().ptr());
490 mul_m3_v3(mat, view_dir);
491 normalize_v3_v3(cache->view_normal, view_dir);
492
493 cache->view_normal_symm = cache->view_normal;
494 cache->bstrength = BKE_brush_alpha_get(&vp.paint, brush);
495 cache->is_last_valid = false;
496
497 cache->accum = true;
498
501 }
502}
503
505{
506 using namespace blender;
507 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
509 SculptSession &ss = *ob.sculpt;
510 StrokeCache *cache = ss.cache;
511 Brush &brush = *BKE_paint_brush(&vp.paint);
512
513 /* This effects the actual brush radius, so things farther away
514 * are compared with a larger radius and vice versa. */
515 if (cache->first_time) {
516 RNA_float_get_array(ptr, "location", cache->location);
517 }
518
519 RNA_float_get_array(ptr, "mouse", cache->mouse);
520
521 /* XXX: Use pressure value from first brush step for brushes which don't
522 * support strokes (grab, thumb). They depends on initial state and
523 * brush coord/pressure/etc.
524 * It's more an events design issue, which doesn't split coordinate/pressure/angle
525 * changing events. We should avoid this after events system re-design */
526 if (paint_supports_dynamic_size(brush, paint_mode) || cache->first_time) {
527 cache->pressure = RNA_float_get(ptr, "pressure");
528 }
529
530 /* Truly temporary data that isn't stored in properties */
531 if (cache->first_time) {
533 *cache->vc, cache->location, BKE_brush_radius_get(&vp.paint, &brush));
534 BKE_brush_unprojected_size_set(&vp.paint, &brush, cache->initial_radius * 2.0f);
535 }
536
537 if (BKE_brush_use_size_pressure(&brush) && paint_supports_dynamic_size(brush, paint_mode)) {
538 cache->radius = cache->initial_radius *
540 }
541 else {
542 cache->radius = cache->initial_radius;
543 }
544
545 cache->radius_squared = cache->radius * cache->radius;
546
547 if (bke::pbvh::Tree *pbvh = bke::object::pbvh_get(ob)) {
548 pbvh->update_bounds(depsgraph, ob);
549 }
550}
551
553 const Paint &paint,
554 const Brush &brush,
555 float *r_brush_size_pressure,
556 float *r_brush_alpha_value,
557 float *r_brush_alpha_pressure)
558{
559 *r_brush_size_pressure = BKE_brush_radius_get(&paint, &brush) *
562 brush.curve_size, 0, ss.cache->pressure) :
563 1.0f);
564 *r_brush_alpha_value = BKE_brush_alpha_get(&paint, &brush);
565 *r_brush_alpha_pressure = BKE_brush_use_alpha_pressure(&brush) ?
567 brush.curve_strength, 0, ss.cache->pressure) :
568 1.0f;
569}
570
571void last_stroke_update(const float location[3], Paint &paint)
572{
573 bke::PaintRuntime &paint_runtime = *paint.runtime;
574 paint_runtime.average_stroke_counter++;
575 add_v3_v3(paint_runtime.average_stroke_accum, location);
576 paint_runtime.last_stroke_valid = true;
577}
578
579/* -------------------------------------------------------------------- */
580
582{
583 Main *bmain = CTX_data_main(C);
584 Brush *cur_brush = BKE_paint_brush(paint);
585
586 /* Switch to the blur (smooth) brush if possible. */
588 Brush *smooth_brush = BKE_paint_brush(paint);
589
590 if (!smooth_brush) {
591 BKE_paint_brush_set(paint, cur_brush);
592 CLOG_WARN(&LOG, "Switching to the blur (smooth) brush not possible, corresponding brush not");
593 cache->saved_active_brush = nullptr;
594 return;
595 }
596
597 int cur_brush_size = BKE_brush_size_get(paint, cur_brush);
598
599 cache->saved_active_brush = cur_brush;
600 cache->saved_smooth_size = BKE_brush_size_get(paint, smooth_brush);
601 BKE_brush_size_set(paint, smooth_brush, cur_brush_size);
603}
604
605} // namespace blender::ed::sculpt_paint::vwpaint
606
608{
609 const Object *ob = CTX_data_active_object(C);
610 if (!ob) {
611 return false;
612 }
613 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
614
615 if (!(ob->mode == OB_MODE_VERTEX_PAINT && mesh->faces_num)) {
616 return false;
617 }
618
619 if (!BKE_color_attribute_supported(*mesh, mesh->active_color_attribute)) {
620 return false;
621 }
622
623 return true;
624}
625
626static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
627{
629 ScrArea *area = CTX_wm_area(C);
630 if (area && area->spacetype == SPACE_VIEW3D) {
631 ARegion *region = CTX_wm_region(C);
632 if (region->regiontype == RGN_TYPE_WINDOW) {
633 if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
634 return true;
635 }
636 }
637 }
638 }
639 return false;
640}
641
643{
644 return vertex_paint_poll_ex(C, true);
645}
646
648{
649 return vertex_paint_poll_ex(C, false);
650}
651
652static ColorPaint4f vpaint_get_current_col(VPaint &vp, bool secondary)
653{
654 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
655 float color[4];
656 const float *brush_color = secondary ? BKE_brush_secondary_color_get(&vp.paint, brush) :
657 BKE_brush_color_get(&vp.paint, brush);
658 copy_v3_v3(color, brush_color);
659
660 color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */
661
662 return ColorPaint4f(color);
663}
664
665/* wpaint has 'wpaint_blend' */
666template<typename Color, typename Traits>
667static Color vpaint_blend(const VPaint &vp,
668 Color color_curr,
669 Color color_orig,
670 Color color_paint,
671 const typename Traits::ValueType alpha,
672 const typename Traits::BlendType brush_alpha_value)
673{
674 using Value = typename Traits::ValueType;
675
676 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
677 const IMB_BlendMode blend = (IMB_BlendMode)brush.blend;
678
679 const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
680
681 /* If no accumulate, clip color adding with `color_orig` & `color_test`. */
683 uint a;
684 Color color_test;
685 Value *cp, *ct, *co;
686
687 color_test = BLI_mix_colors<Color, Traits>(blend, color_orig, color_paint, brush_alpha_value);
688
689 cp = (Value *)&color_blend;
690 ct = (Value *)&color_test;
691 co = (Value *)&color_orig;
692
693 for (a = 0; a < 4; a++) {
694 if (ct[a] < co[a]) {
695 if (cp[a] < ct[a]) {
696 cp[a] = ct[a];
697 }
698 else if (cp[a] > co[a]) {
699 cp[a] = co[a];
700 }
701 }
702 else {
703 if (cp[a] < co[a]) {
704 cp[a] = co[a];
705 }
706 else if (cp[a] > ct[a]) {
707 cp[a] = ct[a];
708 }
709 }
710 }
711 }
712
714 {
715 Value *cp, *cc;
716 cp = (Value *)&color_blend;
717 cc = (Value *)&color_curr;
718 cp[3] = cc[3];
719 }
720
721 return color_blend;
722}
723
731template<typename Color, typename Traits>
733 MutableSpan<Color> prev_vertex_colors,
734 MutableSpan<Color> vertex_colors,
735 MutableSpan<Color> stroke_buffer,
736 Color brush_mark_color,
737 float brush_mark_alpha,
738 float brush_strength,
739 int index)
740{
743 BLI_assert(!stroke_buffer.is_empty());
744 BLI_assert(!prev_vertex_colors.is_empty());
745
746 if (isZero(prev_vertex_colors[index])) {
747 prev_vertex_colors[index] = vertex_colors[index];
748 }
749
750 /* Mix with mesh color under the stroke (a bit easier than trying to premultiply
751 * byte Color types */
752 if (isZero(stroke_buffer[index])) {
753 stroke_buffer[index] = vertex_colors[index];
754 stroke_buffer[index].a = 0;
755 }
756
758 brush_mark_color,
759 stroke_buffer[index],
760 stroke_buffer[index].a);
761
763 vertex_colors[index],
764 prev_vertex_colors[index],
765 stroke_buffer[index],
766 brush_mark_alpha,
767 Traits::range * brush_strength);
768 }
769 else {
771 vertex_colors[index],
772 Color() /* unused in accumulate mode */,
773 brush_mark_color,
774 brush_mark_alpha,
775 Traits::range * brush_strength);
776 }
777 return result;
778}
779
781 const ViewContext *vc,
782 const float co[3],
783 float r_rgba[4])
784{
785 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
786 const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
787 BLI_assert(mtex->tex != nullptr);
788 if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
789 BKE_brush_sample_tex_3d(&vp.paint, brush, mtex, co, r_rgba, 0, nullptr);
790 }
791 else {
792 float co_ss[2]; /* screenspace */
796 {
797 const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
798 BKE_brush_sample_tex_3d(&vp.paint, brush, mtex, co_ss_3d, r_rgba, 0, nullptr);
799 }
800 else {
801 zero_v4(r_rgba);
802 }
803 }
804}
805
806static void vertex_paint_init_stroke(Depsgraph &depsgraph, Object &ob)
807{
809}
810
812
813/* -------------------------------------------------------------------- */
816
817void ED_object_vpaintmode_enter_ex(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
818{
820}
822{
823 Main &bmain = *CTX_data_main(C);
824 Scene &scene = *CTX_data_scene(C);
826 ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
827}
828
830
831/* -------------------------------------------------------------------- */
834
844
846
847/* -------------------------------------------------------------------- */
850
855{
856 Main &bmain = *CTX_data_main(C);
859 const int mode_flag = OB_MODE_VERTEX_PAINT;
860 const bool is_mode_set = (ob.mode & mode_flag) != 0;
861 Scene &scene = *CTX_data_scene(C);
862 ToolSettings &ts = *scene.toolsettings;
863
864 if (!is_mode_set) {
865 if (!blender::ed::object::mode_compat_set(C, &ob, (eObjectMode)mode_flag, op->reports)) {
866 return OPERATOR_CANCELLED;
867 }
868 }
869
871
872 if (is_mode_set) {
874 }
875 else {
877 if (depsgraph) {
879 }
880 ED_object_vpaintmode_enter_ex(bmain, *depsgraph, scene, ob);
882 }
883
885
886 /* update modifier stack for mapping requirements */
887 DEG_id_tag_update(&mesh->id, 0);
888
890 WM_msg_publish_rna_prop(mbus, &ob.id, &ob, Object, mode);
891
893
894 return OPERATOR_FINISHED;
895}
896
898{
899 ot->name = "Vertex Paint Mode";
900 ot->idname = "PAINT_OT_vertex_paint_toggle";
901 ot->description = "Toggle the vertex paint mode in 3D view";
902
905
907}
908
910
911/* -------------------------------------------------------------------- */
914
915/* Implementation notes:
916 *
917 * Operator->invoke()
918 * - Validate context (add #Mesh.mloopcol).
919 * - Create custom-data storage.
920 * - Call paint once (mouse click).
921 * - Add modal handler.
922 *
923 * Operator->modal()
924 * - For every mouse-move, apply vertex paint.
925 * - Exit on mouse release, free custom-data.
926 * (return OPERATOR_FINISHED also removes handler and operator)
927 *
928 * For future:
929 * - implement a stroke event (or mouse-move with past positions).
930 * - revise whether op->customdata should be added in object, in set_vpaint.
931 */
932
933template<typename Func>
934static void to_static_color_type(const bke::AttrType type, const Func &func)
935{
936 switch (type) {
938 func(ColorGeometry4f());
939 break;
941 func(ColorGeometry4b());
942 break;
943 default:
945 break;
946 }
947}
948
949struct VPaintData : public PaintModeData {
953
955
957
965
967
968 /* Special storage for smear brush, avoid feedback loop - update each step. */
969 struct {
973
974 /* For brushes that don't use accumulation, a temporary holding array */
977
978 ~VPaintData() override
979 {
980 if (vp_handle) {
982 }
983 }
984};
985
986static std::unique_ptr<VPaintData> vpaint_init_vpaint(bContext *C,
987 wmOperator *op,
988 Scene &scene,
989 Depsgraph &depsgraph,
990 VPaint &vp,
991 Object &ob,
992 Mesh &mesh,
993 const AttrDomain domain,
994 const bke::AttrType type,
995 const Brush &brush)
996{
997 std::unique_ptr<VPaintData> vpd = std::make_unique<VPaintData>();
998
999 vpd->type = type;
1000 vpd->domain = domain;
1001
1003
1004 vwpaint::view_angle_limits_init(&vpd->normal_angle_precalc,
1005 brush.falloff_angle,
1006 (brush.flag & BRUSH_FRONTFACE_FALLOFF) != 0);
1007
1008 vpd->paintcol = vpaint_get_current_col(vp,
1009 (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
1010
1011 vpd->is_texbrush = !(brush.vertex_brush_type == VPAINT_BRUSH_TYPE_BLUR) && brush.mtex.tex;
1012
1014 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute, domain);
1015 vpd->smear.color_prev = GArray(attribute.type(), attribute.size());
1016 attribute.materialize(vpd->smear.color_prev.data());
1017
1018 vpd->smear.color_curr = vpd->smear.color_prev;
1019 }
1020
1021 /* Create projection handle */
1022 if (vpd->is_texbrush) {
1023 ob.sculpt->building_vp_handle = true;
1024 vpd->vp_handle = ED_vpaint_proj_handle_create(
1025 depsgraph, scene, ob, vpd->vert_positions, vpd->vert_normals);
1026 ob.sculpt->building_vp_handle = false;
1027 }
1028
1030 if (vpd->prev_colors.is_empty()) {
1031 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute);
1032 vpd->prev_colors = GArray(attribute.type(), attribute.size());
1033 attribute.type().value_initialize_n(vpd->prev_colors.data(), vpd->prev_colors.size());
1034 }
1035
1036 if (vpd->stroke_buffer.is_empty()) {
1037 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute);
1038 vpd->stroke_buffer = GArray(attribute.type(), attribute.size());
1039 attribute.type().value_initialize_n(vpd->stroke_buffer.data(), vpd->stroke_buffer.size());
1040 }
1041 }
1042 else {
1043 vpd->prev_colors = {};
1044 vpd->stroke_buffer = {};
1045 }
1046
1047 return vpd;
1048}
1049
1050static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
1051{
1052 Scene &scene = *CTX_data_scene(C);
1053 ToolSettings &ts = *scene.toolsettings;
1054 PaintStroke *stroke = (PaintStroke *)op->customdata;
1055 VPaint &vp = *ts.vpaint;
1056 Brush &brush = *BKE_paint_brush(&vp.paint);
1058 SculptSession &ss = *ob.sculpt;
1060
1061 /* context checks could be a poll() */
1063 if (mesh == nullptr || mesh->faces_num == 0) {
1064 return false;
1065 }
1066
1067 ED_mesh_color_ensure(mesh, nullptr);
1068
1069 const std::optional<bke::AttributeMetaData> meta_data = mesh->attributes().lookup_meta_data(
1070 mesh->active_color_attribute);
1071 if (!BKE_color_attribute_supported(*mesh, mesh->active_color_attribute)) {
1072 return false;
1073 }
1074
1075 std::unique_ptr<VPaintData> vpd = vpaint_init_vpaint(
1076 C, op, scene, depsgraph, vp, ob, *mesh, meta_data->domain, meta_data->data_type, brush);
1077
1078 paint_stroke_set_mode_data(stroke, std::move(vpd));
1079
1080 /* If not previously created, create vertex/weight paint mode session data */
1082 vwpaint::update_cache_invariants(C, vp, ss, op, mouse);
1084
1085 return true;
1086}
1087
1088static void filter_factors_with_selection(const Span<bool> select_vert,
1089 const Span<int> verts,
1090 const MutableSpan<float> factors)
1091{
1092 BLI_assert(verts.size() == factors.size());
1093
1094 for (const int i : verts.index_range()) {
1095 if (!select_vert[verts[i]]) {
1096 factors[i] = 0.0f;
1097 }
1098 }
1099}
1100
1102 const VPaint &vp,
1103 VPaintData &vpd,
1104 Object &ob,
1105 Mesh &mesh,
1107 const IndexMask &node_mask,
1108 GMutableSpan attribute)
1109{
1110 SculptSession &ss = *ob.sculpt;
1111 const StrokeCache &cache = *ss.cache;
1112
1113 const Brush &brush = *ob.sculpt->cache->brush;
1114 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1115
1116 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1118 ss, vp.paint, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1119 const bool use_normal = vwpaint::use_normal(vp);
1120 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1121 0;
1122 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1123
1124 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1125 ss, brush.falloff_shape);
1126
1127 GMutableSpan g_previous_color = vpd.prev_colors;
1128
1129 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1130 const OffsetIndices faces = mesh.faces();
1131 const Span<int> corner_verts = mesh.corner_verts();
1132 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1133 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1134 const bke::AttributeAccessor attributes = mesh.attributes();
1135 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1136 VArraySpan<bool> select_vert;
1137 if (use_vert_sel) {
1138 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1139 }
1140 VArraySpan<bool> select_poly;
1141 if (use_face_sel) {
1142 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1143 }
1144
1145 struct LocalData {
1146 Vector<float> factors;
1147 Vector<float> distances;
1148 };
1150 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1151 LocalData &tls = all_tls.local();
1152 const Span<int> verts = nodes[i].verts();
1153 tls.factors.resize(verts.size());
1154 const MutableSpan<float> factors = tls.factors;
1155 fill_factor_from_hide(hide_vert, verts, factors);
1156 filter_region_clip_factors(ss, vert_positions, verts, factors);
1157 if (!select_vert.is_empty()) {
1158 filter_factors_with_selection(select_vert, verts, factors);
1159 }
1160
1161 tls.distances.resize(verts.size());
1162 const MutableSpan<float> distances = tls.distances;
1164 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1165 filter_distances_with_radius(cache.radius, distances, factors);
1166 calc_brush_strength_factors(cache, brush, distances, factors);
1167
1168 for (const int i : verts.index_range()) {
1169 const int vert = verts[i];
1170 if (factors[i] == 0.0f) {
1171 continue;
1172 }
1173
1174 float brush_strength = cache.bstrength;
1175 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1176 1.0f;
1178 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1179 {
1180 continue;
1181 }
1182
1183 const float brush_fade = factors[i];
1184
1185 to_static_color_type(vpd.type, [&](auto dummy) {
1186 using T = decltype(dummy);
1187 using Color =
1188 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1189 using Traits = blender::color::Traits<Color>;
1190 using Blend = typename Traits::BlendType;
1191 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1192 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1193 /* Get the average face color */
1194 Color color_final(0, 0, 0, 0);
1195
1196 int total_hit_loops = 0;
1197 Blend blend[4] = {0};
1198
1199 for (const int face : vert_to_face[vert]) {
1200 if (!select_poly.is_empty() && !select_poly[face]) {
1201 return;
1202 }
1203 total_hit_loops += faces[face].size();
1204 for (const int corner : faces[face]) {
1205 const Color &col = colors[corner];
1206
1207 /* Color is squared to compensate the `sqrt` color encoding. */
1208 blend[0] += (Blend)col.r * (Blend)col.r;
1209 blend[1] += (Blend)col.g * (Blend)col.g;
1210 blend[2] += (Blend)col.b * (Blend)col.b;
1211 blend[3] += (Blend)col.a * (Blend)col.a;
1212 }
1213 }
1214
1215 if (total_hit_loops == 0) {
1216 return;
1217 }
1218
1219 /* Use rgb^2 color averaging. */
1220 Color *col = &color_final;
1221
1222 color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
1223 color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
1224 color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
1225 color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
1226
1227 /* For each face owning this vert,
1228 * paint each loop belonging to this vert. */
1229 for (const int face : vert_to_face[vert]) {
1230 const int corner = bke::mesh::face_find_corner_from_vert(
1231 faces[face], corner_verts, vert);
1232 if (!select_poly.is_empty() && !select_poly[face]) {
1233 continue;
1234 }
1235 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1236
1237 if (!previous_color.is_empty()) {
1238 /* Get the previous loop color */
1239 if (isZero(previous_color[corner])) {
1240 previous_color[corner] = colors[corner];
1241 }
1242 color_orig = previous_color[corner];
1243 }
1244 const float final_alpha = Traits::range * brush_fade * brush_strength *
1245 brush_alpha_pressure;
1246 /* Mix the new color with the original
1247 * based on the brush strength and the curve. */
1248 colors[corner] = vpaint_blend<Color, Traits>(
1249 vp, colors[corner], color_orig, *col, final_alpha, Traits::range * brush_strength);
1250 }
1251 });
1252 }
1253 });
1254}
1255
1257 const VPaint &vp,
1258 VPaintData &vpd,
1259 Object &ob,
1260 Mesh &mesh,
1262 const IndexMask &node_mask,
1263 GMutableSpan attribute)
1264{
1265 SculptSession &ss = *ob.sculpt;
1266 const StrokeCache &cache = *ss.cache;
1267
1268 const Brush &brush = *ss.cache->brush;
1269 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1270
1271 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1273 ss, vp.paint, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1274 const bool use_normal = vwpaint::use_normal(vp);
1275 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1276 0;
1277 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1278
1279 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1280 ss, brush.falloff_shape);
1281
1282 GMutableSpan g_previous_color = vpd.prev_colors;
1283
1284 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1285 const OffsetIndices faces = mesh.faces();
1286 const Span<int> corner_verts = mesh.corner_verts();
1287 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1288 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1289 const bke::AttributeAccessor attributes = mesh.attributes();
1290 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1291 VArraySpan<bool> select_vert;
1292 if (use_vert_sel) {
1293 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1294 }
1295 VArraySpan<bool> select_poly;
1296 if (use_face_sel) {
1297 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1298 }
1299
1300 struct LocalData {
1301 Vector<float> factors;
1302 Vector<float> distances;
1303 };
1305 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1306 LocalData &tls = all_tls.local();
1307 const Span<int> verts = nodes[i].verts();
1308 tls.factors.resize(verts.size());
1309 const MutableSpan<float> factors = tls.factors;
1310 fill_factor_from_hide(hide_vert, verts, factors);
1311 filter_region_clip_factors(ss, vert_positions, verts, factors);
1312 if (!select_vert.is_empty()) {
1313 filter_factors_with_selection(select_vert, verts, factors);
1314 }
1315
1316 tls.distances.resize(verts.size());
1317 const MutableSpan<float> distances = tls.distances;
1319 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1320 filter_distances_with_radius(cache.radius, distances, factors);
1321 calc_brush_strength_factors(cache, brush, distances, factors);
1322
1323 for (const int i : verts.index_range()) {
1324 const int vert = verts[i];
1325 if (factors[i] == 0.0f) {
1326 continue;
1327 }
1328
1329 float brush_strength = cache.bstrength;
1330 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1331 1.0f;
1333 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1334 {
1335 continue;
1336 }
1337 const float brush_fade = factors[i];
1338
1339 /* Get the average face color */
1340 to_static_color_type(vpd.type, [&](auto dummy) {
1341 using T = decltype(dummy);
1342 using Color =
1343 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1344 using Traits = blender::color::Traits<Color>;
1345 using Blend = typename Traits::BlendType;
1346 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1347 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1348 Color color_final(0, 0, 0, 0);
1349
1350 int total_hit_loops = 0;
1351 Blend blend[4] = {0};
1352
1353 for (const int face : vert_to_face[vert]) {
1354 if (!select_poly.is_empty() && !select_poly[face]) {
1355 continue;
1356 }
1357 total_hit_loops += faces[face].size();
1358 for (const int vert : corner_verts.slice(faces[face])) {
1359 const Color &col = colors[vert];
1360
1361 /* Color is squared to compensate the `sqrt` color encoding. */
1362 blend[0] += (Blend)col.r * (Blend)col.r;
1363 blend[1] += (Blend)col.g * (Blend)col.g;
1364 blend[2] += (Blend)col.b * (Blend)col.b;
1365 blend[3] += (Blend)col.a * (Blend)col.a;
1366 }
1367 }
1368
1369 if (total_hit_loops == 0) {
1370 return;
1371 }
1372 /* Use rgb^2 color averaging. */
1373 color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
1374 color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
1375 color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
1376 color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
1377
1378 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1379
1380 if (!previous_color.is_empty()) {
1381 /* Get the previous loop color */
1382 if (isZero(previous_color[vert])) {
1383 previous_color[vert] = colors[vert];
1384 }
1385 color_orig = previous_color[vert];
1386 }
1387 const float final_alpha = Traits::range * brush_fade * brush_strength *
1388 brush_alpha_pressure;
1389 /* Mix the new color with the original
1390 * based on the brush strength and the curve. */
1391 colors[vert] = vpaint_blend<Color, Traits>(vp,
1392 colors[vert],
1393 color_orig,
1394 color_final,
1395 final_alpha,
1396 Traits::range * brush_strength);
1397 });
1398 }
1399 });
1400}
1401
1403 const VPaint &vp,
1404 VPaintData &vpd,
1405 Object &ob,
1406 Mesh &mesh,
1408 const IndexMask &node_mask,
1409 GMutableSpan attribute)
1410{
1411 SculptSession &ss = *ob.sculpt;
1412 StrokeCache &cache = *ss.cache;
1413 if (!cache.is_last_valid) {
1414 return;
1415 }
1416
1417 const Brush &brush = *cache.brush;
1418 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1419 GMutableSpan g_color_curr = vpd.smear.color_curr;
1420 GMutableSpan g_color_prev_smear = vpd.smear.color_prev;
1421 GMutableSpan g_color_prev = vpd.prev_colors;
1422
1423 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1424
1426 ss, vp.paint, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1427 const bool use_normal = vwpaint::use_normal(vp);
1428 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1429 0;
1430 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1431
1432 float brush_dir[3];
1433 sub_v3_v3v3(brush_dir, cache.location_symm, cache.last_location_symm);
1434 project_plane_v3_v3v3(brush_dir, brush_dir, cache.view_normal_symm);
1435 if (normalize_v3(brush_dir) == 0.0f) {
1436 return;
1437 }
1438
1439 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1440 ss, brush.falloff_shape);
1441
1442 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1443 const OffsetIndices faces = mesh.faces();
1444 const Span<int> corner_verts = mesh.corner_verts();
1445 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1446 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1447 const bke::AttributeAccessor attributes = mesh.attributes();
1448 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1449 VArraySpan<bool> select_vert;
1450 if (use_vert_sel) {
1451 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1452 }
1453 VArraySpan<bool> select_poly;
1454 if (use_face_sel) {
1455 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1456 }
1457
1458 struct LocalData {
1459 Vector<float> factors;
1460 Vector<float> distances;
1461 };
1463 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1464 LocalData &tls = all_tls.local();
1465 const Span<int> verts = nodes[i].verts();
1466 tls.factors.resize(verts.size());
1467 const MutableSpan<float> factors = tls.factors;
1468 fill_factor_from_hide(hide_vert, verts, factors);
1469 filter_region_clip_factors(ss, vert_positions, verts, factors);
1470 if (!select_vert.is_empty()) {
1471 filter_factors_with_selection(select_vert, verts, factors);
1472 }
1473
1474 tls.distances.resize(verts.size());
1475 const MutableSpan<float> distances = tls.distances;
1477 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1478 filter_distances_with_radius(cache.radius, distances, factors);
1479 calc_brush_strength_factors(cache, brush, distances, factors);
1480
1481 for (const int i : verts.index_range()) {
1482 const int vert = verts[i];
1483 if (factors[i] == 0.0f) {
1484 continue;
1485 }
1486
1487 /* Calculate the dot prod. between ray norm on surf and current vert
1488 * (ie splash prevention factor), and only paint front facing verts. */
1489 float brush_strength = cache.bstrength;
1490 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1491 1.0f;
1493 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1494 {
1495 continue;
1496 }
1497 const float brush_fade = factors[i];
1498
1499 bool do_color = false;
1500 /* Minimum dot product between brush direction and current
1501 * to neighbor direction is 0.0, meaning orthogonal. */
1502 float stroke_dot_max = 0.0f;
1503
1504 /* Get the color of the loop in the opposite
1505 * direction of the brush movement */
1506 to_static_color_type(vpd.type, [&](auto dummy) {
1507 using T = decltype(dummy);
1508 using Color =
1509 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1510 using Traits = blender::color::Traits<Color>;
1511 MutableSpan<Color> color_curr = g_color_curr.typed<T>().template cast<Color>();
1512 MutableSpan<Color> color_prev_smear = g_color_prev_smear.typed<T>().template cast<Color>();
1513 MutableSpan<Color> color_prev = g_color_prev.typed<T>().template cast<Color>();
1514 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1515
1516 Color color_final(0, 0, 0, 0);
1517
1518 for (const int face : vert_to_face[vert]) {
1519 if (!select_poly.is_empty() && !select_poly[face]) {
1520 continue;
1521 }
1522 for (const int corner : faces[face]) {
1523 const int v_other_index = corner_verts[corner];
1524 if (v_other_index == vert) {
1525 continue;
1526 }
1527
1528 /* Get the direction from the
1529 * selected vert to the neighbor. */
1530 float other_dir[3];
1531 sub_v3_v3v3(other_dir, vert_positions[vert], vert_positions[v_other_index]);
1532 project_plane_v3_v3v3(other_dir, other_dir, cache.view_normal_symm);
1533
1534 normalize_v3(other_dir);
1535
1536 const float stroke_dot = dot_v3v3(other_dir, brush_dir);
1537 int elem_index;
1538
1539 if (vpd.domain == AttrDomain::Point) {
1540 elem_index = v_other_index;
1541 }
1542 else {
1543 elem_index = corner;
1544 }
1545
1546 if (stroke_dot > stroke_dot_max) {
1547 stroke_dot_max = stroke_dot;
1548 color_final = color_prev_smear[elem_index];
1549 do_color = true;
1550 }
1551 }
1552 }
1553
1554 if (!do_color) {
1555 return;
1556 }
1557
1558 const float final_alpha = Traits::range * brush_fade * brush_strength *
1559 brush_alpha_pressure;
1560
1561 /* For each face owning this vert,
1562 * paint each loop belonging to this vert. */
1563 for (const int face : vert_to_face[vert]) {
1564
1565 int elem_index;
1566 if (vpd.domain == AttrDomain::Point) {
1567 elem_index = vert;
1568 }
1569 else {
1570 elem_index = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
1571 }
1572 if (!select_poly.is_empty() && !select_poly[face]) {
1573 continue;
1574 }
1575
1576 /* Get the previous element color */
1577 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1578
1579 if (!color_prev.is_empty()) {
1580 /* Get the previous element color */
1581 if (isZero(color_prev[elem_index])) {
1582 color_prev[elem_index] = colors[elem_index];
1583 }
1584 color_orig = color_prev[elem_index];
1585 }
1586 /* Mix the new color with the original
1587 * based on the brush strength and the curve. */
1588 colors[elem_index] = vpaint_blend<Color, Traits>(vp,
1589 colors[elem_index],
1590 color_orig,
1591 color_final,
1592 final_alpha,
1593 Traits::range * brush_strength);
1594
1595 color_curr[elem_index] = colors[elem_index];
1596 }
1597 });
1598 }
1599 });
1600}
1601
1603 Object &ob,
1604 Mesh &mesh,
1605 const Brush &brush,
1606 const GSpan attribute,
1608 const IndexMask &node_mask)
1609{
1610 SculptSession &ss = *ob.sculpt;
1611 const StrokeCache &cache = *ss.cache;
1612 const Depsgraph &depsgraph = *vpd.vc.depsgraph;
1613
1614 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1615 0;
1616
1617 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1618 const OffsetIndices faces = mesh.faces();
1619 const Span<int> corner_verts = mesh.corner_verts();
1620 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1621 const bke::AttributeAccessor attributes = mesh.attributes();
1622 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1623 VArraySpan<bool> select_vert;
1624 if (use_vert_sel) {
1625 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1626 }
1627
1628 struct LocalData {
1629 Vector<float> factors;
1630 Vector<float> distances;
1631 };
1633 to_static_color_type(vpd.type, [&](auto dummy) {
1634 using T = decltype(dummy);
1635 using Color =
1636 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1637 using Traits = blender::color::Traits<Color>;
1638 using Blend = typename Traits::BlendType;
1639 const Span<Color> colors = attribute.typed<T>().template cast<Color>();
1640
1641 Array<VPaintAverageAccum<Blend>> accum(nodes.size(), {0, {0, 0, 0}});
1642 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1643 VPaintAverageAccum<Blend> &accum2 = accum[i];
1644 LocalData &tls = all_tls.local();
1645
1646 const Span<int> verts = nodes[i].verts();
1647 tls.factors.resize(verts.size());
1648 const MutableSpan<float> factors = tls.factors;
1649 fill_factor_from_hide(hide_vert, verts, factors);
1650 filter_region_clip_factors(ss, vert_positions, verts, factors);
1651 if (!select_vert.is_empty()) {
1652 filter_factors_with_selection(select_vert, verts, factors);
1653 }
1654
1655 tls.distances.resize(verts.size());
1656 const MutableSpan<float> distances = tls.distances;
1658 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1659 filter_distances_with_radius(cache.radius, distances, factors);
1660 calc_brush_strength_factors(cache, brush, distances, factors);
1661
1662 for (const int i : verts.index_range()) {
1663 const int vert = verts[i];
1664 if (factors[i] == 0.0f) {
1665 continue;
1666 }
1667
1668 accum2.len += vert_to_face[vert].size();
1669 /* if a vertex is within the brush region, then add its color to the blend. */
1670 for (const int face : vert_to_face[vert]) {
1671 int elem_index;
1672 if (vpd.domain == AttrDomain::Corner) {
1673 elem_index = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
1674 }
1675 else {
1676 elem_index = vert;
1677 }
1678
1679 /* Color is squared to compensate the `sqrt` color encoding. */
1680 const Color &col = colors[elem_index];
1681 accum2.value[0] += col.r * col.r;
1682 accum2.value[1] += col.g * col.g;
1683 accum2.value[2] += col.b * col.b;
1684 }
1685 }
1686 });
1687
1688 Blend accum_len = 0;
1689 Blend accum_value[3] = {0};
1690 Color blend(0, 0, 0, 0);
1691
1692 node_mask.foreach_index([&](const int i) {
1693 accum_len += accum[i].len;
1694 accum_value[0] += accum[i].value[0];
1695 accum_value[1] += accum[i].value[1];
1696 accum_value[2] += accum[i].value[2];
1697 });
1698 if (accum_len != 0) {
1699 blend.r = Traits::round(sqrtf(Traits::divide_round(accum_value[0], accum_len)));
1700 blend.g = Traits::round(sqrtf(Traits::divide_round(accum_value[1], accum_len)));
1701 blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len)));
1702 blend.a = Traits::range;
1703
1704 vpd.paintcol = toFloat(blend);
1705 }
1706 });
1707}
1708
1709template<typename Color>
1710static float paint_and_tex_color_alpha(const VPaint &vp,
1711 VPaintData &vpd,
1712 const float v_co[3],
1713 Color *r_color)
1714{
1715 ColorPaint4f rgba;
1716 paint_and_tex_color_alpha_intern(vp, &vpd.vc, v_co, &rgba.r);
1717
1718 ColorPaint4f rgba_br = toFloat(vpd.paintcol);
1719 mul_v3_v3(rgba_br, rgba);
1720
1721 *r_color = fromFloat<Color>(rgba_br);
1722 return rgba[3];
1723}
1724
1725/* Compute brush color, using jitter if it's enabled */
1727 const Brush *brush,
1728 const StrokeCache &cache,
1729 const ColorPaint4f &paint_color)
1730{
1731 blender::float3 brush_color = blender::float3(paint_color.r, paint_color.g, paint_color.b);
1732 const std::optional<BrushColorJitterSettings> color_jitter_settings =
1734 if (color_jitter_settings) {
1735 brush_color = BKE_paint_randomize_color(*color_jitter_settings,
1736 *cache.initial_hsv_jitter,
1737 cache.stroke_distance,
1738 cache.pressure,
1739 brush_color);
1740 }
1741 return brush_color;
1742}
1743
1744static void vpaint_do_draw(const bContext *C,
1745 const VPaint &vp,
1746 VPaintData &vpd,
1747 Object &ob,
1748 Mesh &mesh,
1750 const IndexMask &node_mask,
1751 GMutableSpan attribute)
1752{
1753 SculptSession &ss = *ob.sculpt;
1754 const StrokeCache &cache = *ss.cache;
1755 const Brush &brush = *ob.sculpt->cache->brush;
1756 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1757
1758 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1760 ss, vp.paint, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1761 const bool use_normal = vwpaint::use_normal(vp);
1762 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1763 0;
1764 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1765
1766 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1767 ss, brush.falloff_shape);
1768
1769 GMutableSpan g_previous_color = vpd.prev_colors;
1770 GMutableSpan g_stroke_buffer = vpd.stroke_buffer;
1771
1772 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1773 const OffsetIndices faces = mesh.faces();
1774 const Span<int> corner_verts = mesh.corner_verts();
1775 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1776 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1777 const bke::AttributeAccessor attributes = mesh.attributes();
1778 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1779 VArraySpan<bool> select_vert;
1780 if (use_vert_sel) {
1781 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1782 }
1783 VArraySpan<bool> select_poly;
1784 if (use_face_sel) {
1785 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1786 }
1787
1788 const blender::float3 brush_color = get_brush_color(&vp.paint, &brush, cache, vpd.paintcol);
1789
1790 struct LocalData {
1791 Vector<float> factors;
1792 Vector<float> distances;
1793 };
1795 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1796 LocalData &tls = all_tls.local();
1797 const Span<int> verts = nodes[i].verts();
1798 tls.factors.resize(verts.size());
1799 const MutableSpan<float> factors = tls.factors;
1800 fill_factor_from_hide(hide_vert, verts, factors);
1801 filter_region_clip_factors(ss, vert_positions, verts, factors);
1802 if (!select_vert.is_empty()) {
1803 filter_factors_with_selection(select_vert, verts, factors);
1804 }
1805
1806 tls.distances.resize(verts.size());
1807 const MutableSpan<float> distances = tls.distances;
1809 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1810 filter_distances_with_radius(cache.radius, distances, factors);
1811 calc_brush_strength_factors(cache, brush, distances, factors);
1812
1813 for (const int i : verts.index_range()) {
1814 const int vert = verts[i];
1815 if (factors[i] == 0.0f) {
1816 continue;
1817 }
1818
1819 /* Calculate the dot product between ray normal on surface and current vertex
1820 * (ie splash prevention factor), and only paint front facing verts. */
1821 float brush_strength = cache.bstrength;
1822 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1823 1.0f;
1825 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1826 {
1827 continue;
1828 }
1829 const float brush_fade = factors[i];
1830
1831 to_static_color_type(vpd.type, [&](auto dummy) {
1832 using T = decltype(dummy);
1833 using Color =
1834 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1835 using Traits = blender::color::Traits<Color>;
1836 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1837 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1838 MutableSpan<Color> stroke_buffer = g_stroke_buffer.typed<T>().template cast<Color>();
1839
1840 Color color_final = fromFloat<Color>(
1841 ColorPaint4f(brush_color[0], brush_color[1], brush_color[2], 1.0));
1842
1843 /* If we're painting with a texture, sample the texture color and alpha. */
1844 float tex_alpha = 1.0;
1845 if (vpd.is_texbrush) {
1846 /* NOTE: we may want to paint alpha as vertex color alpha. */
1847
1848 /* If the active area is being applied for symmetry, flip it
1849 * across the symmetry axis and rotate it back to the original
1850 * position in order to project it. This ensures that the
1851 * brush texture will be oriented correctly.
1852 * This is the method also used in #sculpt_apply_texture(). */
1853 float3 position = vpd.vert_positions[vert];
1854 if (cache.radial_symmetry_pass) {
1855 position = blender::math::transform_point(cache.symm_rot_mat_inv, position);
1856 }
1857 const float3 symm_point = blender::ed::sculpt_paint::symmetry_flip(
1858 position, cache.mirror_symmetry_pass);
1859
1860 tex_alpha = paint_and_tex_color_alpha<Color>(vp, vpd, symm_point, &color_final);
1861 }
1862
1863 const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha *
1864 brush_alpha_pressure;
1865
1866 if (vpd.domain == AttrDomain::Point) {
1867 colors[vert] = vpaint_blend_stroke<Color, Traits>(vp,
1868 previous_color,
1869 colors,
1870 stroke_buffer,
1871 color_final,
1872 final_alpha,
1873 brush_strength,
1874 vert);
1875 }
1876 else {
1877 /* For each face owning this vert, paint each loop belonging to this vert. */
1878 for (const int face : vert_to_face[vert]) {
1879 const int corner = bke::mesh::face_find_corner_from_vert(
1880 faces[face], corner_verts, vert);
1881 if (!select_poly.is_empty() && !select_poly[face]) {
1882 continue;
1883 }
1884 colors[corner] = vpaint_blend_stroke<Color, Traits>(vp,
1885 previous_color,
1886 colors,
1887 stroke_buffer,
1888 color_final,
1889 final_alpha,
1890 brush_strength,
1891 corner);
1892 }
1893 }
1894 });
1895 }
1896 });
1897}
1898
1899static void vpaint_do_blur(const bContext *C,
1900 const VPaint &vp,
1901 VPaintData &vpd,
1902 Object &ob,
1903 Mesh &mesh,
1905 const IndexMask &node_mask,
1906 GMutableSpan attribute)
1907{
1908 if (vpd.domain == AttrDomain::Point) {
1909 do_vpaint_brush_blur_verts(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1910 }
1911 else {
1912 do_vpaint_brush_blur_loops(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1913 }
1914}
1915
1917 const VPaint &vp,
1918 VPaintData &vpd,
1919 Object &ob,
1920 Mesh &mesh,
1921 GMutableSpan attribute,
1923 const IndexMask &node_mask)
1924{
1925 const Brush &brush = *ob.sculpt->cache->brush;
1926
1929 calculate_average_color(vpd, ob, mesh, brush, attribute, nodes, node_mask);
1930 vpaint_do_draw(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1931 break;
1933 vpaint_do_draw(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1934 break;
1936 vpaint_do_blur(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1937 break;
1939 do_vpaint_brush_smear(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1940 break;
1941 }
1942}
1943
1945 const VPaint &vp,
1946 VPaintData &vpd,
1947 Object &ob,
1948 Mesh &mesh,
1949 const Brush &brush,
1950 const ePaintSymmetryFlags symm,
1951 const int axis,
1952 const int i,
1953 const float angle)
1954{
1955 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1956 SculptSession &ss = *ob.sculpt;
1959
1960 IndexMaskMemory memory;
1961 const IndexMask node_mask = vwpaint::pbvh_gather_generic(depsgraph, ob, vp, brush, memory);
1962
1963 bke::GSpanAttributeWriter attribute = mesh.attributes_for_write().lookup_for_write_span(
1964 mesh.active_color_attribute);
1965 BLI_assert(attribute.domain == vpd.domain);
1966
1967 /* Paint those leaves. */
1969 vp,
1970 vpd,
1971 ob,
1972 mesh,
1973 attribute.span,
1975 node_mask);
1976
1977 attribute.finish();
1978}
1979
1981 const VPaint &vp,
1982 VPaintData &vpd,
1983 Object &ob,
1984 Mesh &mesh,
1985 const Brush &brush,
1986 const ePaintSymmetryFlags symm,
1987 const int axis)
1988{
1989 for (int i = 1; i < mesh.radial_symmetry[axis - 'X']; i++) {
1990 const float angle = (2.0 * M_PI) * i / mesh.radial_symmetry[axis - 'X'];
1991 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm, axis, i, angle);
1992 }
1993}
1994
1995/* near duplicate of: sculpt.cc's,
1996 * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
1998 const VPaint &vp,
1999 VPaintData &vpd,
2000 Object &ob)
2001{
2002 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
2003 Mesh &mesh = *(Mesh *)ob.data;
2004 SculptSession &ss = *ob.sculpt;
2005 StrokeCache &cache = *ss.cache;
2006 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
2007 int i = 0;
2008
2009 /* initial stroke */
2010 const ePaintSymmetryFlags initial_symm = ePaintSymmetryFlags(0);
2012 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, initial_symm, 'X', 0, 0);
2013 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'X');
2014 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Y');
2015 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Z');
2016
2017 cache.symmetry = symm;
2018
2019 for (i = 1; i <= symm; i++) {
2020 if (is_symmetry_iteration_valid(i, symm)) {
2021 const ePaintSymmetryFlags symm_pass = ePaintSymmetryFlags(i);
2022 cache.mirror_symmetry_pass = symm_pass;
2023 cache.radial_symmetry_pass = 0;
2024 SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0);
2025
2026 if (i & (1 << 0)) {
2027 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'X', 0, 0);
2028 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'X');
2029 }
2030 if (i & (1 << 1)) {
2031 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y', 0, 0);
2032 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y');
2033 }
2034 if (i & (1 << 2)) {
2035 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z', 0, 0);
2036 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z');
2037 }
2038 }
2039 }
2040
2041 copy_v3_v3(cache.last_location, cache.location);
2042 cache.is_last_valid = true;
2043}
2044
2046 wmOperator * /*op*/,
2047 PaintStroke *stroke,
2048 PointerRNA *itemptr)
2049{
2051 VPaintData &vpd = *static_cast<VPaintData *>(paint_stroke_mode_data(stroke));
2052 VPaint &vp = *ts->vpaint;
2053 ViewContext &vc = vpd.vc;
2054 Object &ob = *vc.obact;
2055 SculptSession &ss = *ob.sculpt;
2056
2058
2059 vwpaint::update_cache_variants(C, vp, ob, itemptr);
2060
2061 float mat[4][4];
2062
2064
2065 mul_m4_m4m4(mat, vc.rv3d->persmat, ob.object_to_world().ptr());
2066
2067 swap_m4m4(vc.rv3d->persmat, mat);
2068
2070
2071 swap_m4m4(vc.rv3d->persmat, mat);
2072
2074
2075 Brush &brush = *BKE_paint_brush(&vp.paint);
2077 vpd.smear.color_prev = vpd.smear.color_curr;
2078 }
2079
2080 /* Calculate pivot for rotation around selection if needed.
2081 * also needed for "Frame Selected" on last stroke. */
2082 float loc_world[3];
2083 mul_v3_m4v3(loc_world, ob.object_to_world().ptr(), ss.cache->location);
2084 vwpaint::last_stroke_update(loc_world, vp.paint);
2085
2087
2089}
2090
2091static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke)
2092{
2093 VPaintData *vpd = static_cast<VPaintData *>(paint_stroke_mode_data(stroke));
2094 Object &ob = *vpd->vc.obact;
2095
2096 SculptSession &ss = *ob.sculpt;
2097
2098 if (ss.cache && ss.cache->alt_smooth) {
2100 VPaint &vp = *ts->vpaint;
2102 }
2103
2105
2106 MEM_delete(ob.sculpt->cache);
2107 ob.sculpt->cache = nullptr;
2108}
2109
2111{
2113 op,
2117 nullptr,
2119 event->type);
2120
2121 const wmOperatorStatus retval = op->type->modal(C, op, event);
2122 OPERATOR_RETVAL_CHECK(retval);
2123
2124 if (retval == OPERATOR_FINISHED) {
2126 return OPERATOR_FINISHED;
2127 }
2128
2130
2132
2134}
2135
2137{
2139 op,
2143 nullptr,
2145 0);
2146
2148
2149 return OPERATOR_FINISHED;
2150}
2151
2153{
2155 MEM_delete(ob.sculpt->cache);
2156 ob.sculpt->cache = nullptr;
2157
2159}
2160
2162{
2163 return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
2164}
2165
2167{
2168 ot->name = "Vertex Paint";
2169 ot->idname = "PAINT_OT_vertex_paint";
2170 ot->description = "Paint a stroke in the active color attribute layer";
2171
2172 ot->invoke = vpaint_invoke;
2173 ot->modal = vpaint_modal;
2174 ot->exec = vpaint_exec;
2175 ot->poll = vertex_paint_poll;
2176 ot->cancel = vpaint_cancel;
2177
2178 ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
2179
2182 ot->srna,
2183 "override_location",
2184 false,
2185 "Override Location",
2186 "Override the given \"location\" array by recalculating object space positions from the "
2187 "provided \"mouse_event\" positions");
2189}
2190
2192
2193/* -------------------------------------------------------------------- */
2196
2197namespace blender::ed::sculpt_paint {
2198
2199template<typename T>
2201 const T &value,
2202 const AttrDomain domain,
2203 const int cd_offset,
2204 const bool use_vert_sel)
2205{
2206 BMFace *f;
2207 BMIter iter;
2208 BM_ITER_MESH (f, &iter, &bm, BM_FACES_OF_MESH) {
2209 BMLoop *l = f->l_first;
2210 do {
2211 if (!(use_vert_sel && !BM_elem_flag_test(l->v, BM_ELEM_SELECT))) {
2212 if (domain == AttrDomain::Corner) {
2213 *static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset)) = value;
2214 }
2215 else if (domain == AttrDomain::Point) {
2216 *static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset)) = value;
2217 }
2218 }
2219 } while ((l = l->next) != f->l_first);
2220 }
2221}
2222
2223template<typename T>
2225 const T &value,
2226 const AttrDomain domain,
2227 const MutableSpan<T> data,
2228 const bool use_vert_sel,
2229 const bool use_face_sel,
2230 const bool affect_alpha)
2231{
2232 const bke::AttributeAccessor attributes = mesh.attributes();
2233 VArraySpan<bool> select_vert;
2234 if (use_vert_sel) {
2235 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
2236 }
2237 VArraySpan<bool> select_poly;
2238 if (use_face_sel) {
2239 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
2240 }
2241
2242 const OffsetIndices faces = mesh.faces();
2243 const Span<int> corner_verts = mesh.corner_verts();
2244
2245 for (const int i : faces.index_range()) {
2246 if (!select_poly.is_empty() && !select_poly[i]) {
2247 continue;
2248 }
2249 for (const int corner : faces[i]) {
2250 const int vert = corner_verts[corner];
2251 if (!select_vert.is_empty() && !select_vert[vert]) {
2252 continue;
2253 }
2254 const int data_index = domain == AttrDomain::Corner ? corner : vert;
2255 data[data_index].r = value.r;
2256 data[data_index].g = value.g;
2257 data[data_index].b = value.b;
2258 if (affect_alpha) {
2259 data[data_index].a = value.a;
2260 }
2261 }
2262 }
2263
2265}
2266
2268 const ColorPaint4f &color,
2269 const StringRef attribute_name,
2270 const bool use_vert_sel,
2271 const bool use_face_sel,
2272 const bool affect_alpha)
2273{
2274 if (BMEditMesh *em = mesh.runtime->edit_mesh.get()) {
2275 BMesh *bm = em->bm;
2276 const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh.id, attribute_name);
2278 const AttrDomain domain = BKE_attribute_domain(owner, layer);
2279 if (layer->type == CD_PROP_COLOR) {
2281 *bm, color, domain, layer->offset, use_vert_sel);
2282 }
2283 else if (layer->type == CD_PROP_BYTE_COLOR) {
2285 *bm, blender::color::encode(color), domain, layer->offset, use_vert_sel);
2286 }
2287 }
2288 else {
2289 bke::GSpanAttributeWriter attribute = mesh.attributes_for_write().lookup_for_write_span(
2290 attribute_name);
2291 if (attribute.span.type().is<ColorGeometry4f>()) {
2293 mesh,
2294 color,
2295 attribute.domain,
2296 attribute.span.typed<ColorGeometry4f>().cast<ColorPaint4f>(),
2297 use_vert_sel,
2298 use_face_sel,
2299 affect_alpha);
2300 }
2301 else if (attribute.span.type().is<ColorGeometry4b>()) {
2303 mesh,
2305 attribute.domain,
2306 attribute.span.typed<ColorGeometry4b>().cast<ColorPaint4b>(),
2307 use_vert_sel,
2308 use_face_sel,
2309 affect_alpha);
2310 }
2311 attribute.finish();
2312 }
2313}
2314
2316 ColorPaint4f fill_color,
2317 bool only_selected = true,
2318 bool affect_alpha = true)
2319{
2321 if (!mesh) {
2322 return false;
2323 }
2324
2325 const bool use_face_sel = only_selected ? (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) != 0 : false;
2326 const bool use_vert_sel = only_selected ? (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) != 0 : false;
2328 *mesh, fill_color, mesh->active_color_attribute, use_vert_sel, use_face_sel, affect_alpha);
2329
2331
2332 /* NOTE: Original mesh is used for display, so tag it directly here. */
2334
2335 return true;
2336}
2337
2338bool object_active_color_fill(Object &ob, const float fill_color[4], bool only_selected)
2339{
2340 return fill_active_color(ob, ColorPaint4f(fill_color), only_selected);
2341}
2342
2343} // namespace blender::ed::sculpt_paint
2344
2346{
2347 using namespace blender::ed::sculpt_paint;
2348 Scene &scene = *CTX_data_scene(C);
2349 Object &obact = *CTX_data_active_object(C);
2350 if (!BKE_mesh_from_object(&obact)) {
2351 return OPERATOR_CANCELLED;
2352 }
2353
2354 ColorPaint4f paintcol = vpaint_get_current_col(*scene.toolsettings->vpaint, false);
2355 const bool affect_alpha = RNA_boolean_get(op->ptr, "use_alpha");
2356
2357 /* Ensure valid sculpt state. */
2359
2360 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(obact);
2361
2362 IndexMaskMemory memory;
2363 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
2364
2365 Mesh &mesh = *static_cast<Mesh *>(obact.data);
2366
2367 fill_active_color(obact, paintcol, true, affect_alpha);
2368
2369 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
2370
2372 return OPERATOR_FINISHED;
2373}
2374
2376{
2377 ot->name = "Set Vertex Colors";
2378 ot->idname = "PAINT_OT_vertex_color_set";
2379 ot->description = "Fill the active vertex color layer with the current paint color";
2380
2381 ot->exec = vertex_color_set_exec;
2382 ot->poll = vertex_paint_mode_poll;
2383
2384 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2385
2386 RNA_def_boolean(ot->srna,
2387 "use_alpha",
2388 true,
2389 "Affect Alpha",
2390 "Set color completely opaque instead of reusing existing alpha");
2391}
2392
blender::bke::AttrDomain BKE_attribute_domain(const AttributeOwner &owner, const struct CustomDataLayer *layer)
const struct CustomDataLayer * BKE_id_attributes_color_find(const struct ID *id, blender::StringRef name)
bool BKE_color_attribute_supported(const struct Mesh &mesh, blender::StringRef name)
bool BKE_brush_use_alpha_pressure(const Brush *brush)
Definition brush.cc:1290
float BKE_brush_alpha_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1357
float BKE_brush_sample_tex_3d(const Paint *paint, const Brush *br, const MTex *mtex, const float point[3], float rgba[4], int thread, ImagePool *pool)
Definition brush.cc:920
const float * BKE_brush_color_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1161
const float * BKE_brush_secondary_color_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1205
std::optional< BrushColorJitterSettings > BKE_brush_color_jitter_get_settings(const Paint *paint, const Brush *brush)
Definition brush.cc:1170
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1285
float BKE_brush_radius_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1272
void BKE_brush_size_set(Paint *paint, Brush *brush, int size)
Definition brush.cc:1248
void BKE_brush_unprojected_size_set(Paint *paint, Brush *brush, float unprojected_size)
Definition brush.cc:1295
int BKE_brush_size_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1264
const MTex * BKE_brush_mask_texture_get(const Brush *brush, eObjectMode object_mode)
Definition brush.cc:904
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_init(CurveMapping *cumap)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Depsgraph * CTX_data_depsgraph_on_load(const bContext *C)
wmMsgBus * CTX_wm_message_bus(const bContext *C)
support for deformation groups and hooks.
void BKE_defvert_array_free_elems(MDeformVert *dvert, int totvert)
Definition deform.cc:1056
void BKE_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode)
void BKE_mesh_tessface_clear(Mesh *mesh)
@ BKE_MESH_BATCH_DIRTY_ALL
Definition BKE_mesh.h:38
Mesh * BKE_mesh_from_object(Object *ob)
General operations, lookup, etc. for blender objects.
void BKE_object_free_derived_caches(Object *ob)
bool BKE_paint_brush_set_essentials(Main *bmain, Paint *paint, const char *name)
Definition paint.cc:1105
blender::float3 BKE_paint_randomize_color(const BrushColorJitterSettings &color_jitter, const blender::float3 &initial_hsv_jitter, const float distance, const float pressure, const blender::float3 &color)
Definition paint.cc:1964
bool BKE_paint_brush_set(Paint *paint, Brush *brush)
Definition paint.cc:710
void BKE_sculptsession_free(Object *ob)
Definition paint.cc:2332
blender::float3 seed_hsv_jitter()
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, bool ensure_brushes=true)
Definition paint.cc:1840
Paint * BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
Definition paint.cc:374
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2797
bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
Definition paint.cc:1738
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:645
void BKE_sculpt_toolsettings_data_ensure(Main *bmain, Scene *scene)
Definition paint.cc:2884
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:505
void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
Definition paint.cc:1125
PaintMode
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define M_PI_2
#define RAD2DEGF(_rad)
#define M_PI
struct DistRayAABB_Precalc dist_squared_ray_to_aabb_v3_precalc(const float ray_origin[3], const float ray_direction[3])
Definition math_geom.cc:685
void mul_m3_v3(const float M[3][3], float r[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void swap_m4m4(float m1[4][4], float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v4(float r[4])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void zero_v2(float r[2])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
unsigned int uint
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ WPAINT_BRUSH_TYPE_SMEAR
@ BRUSH_LOCK_ALPHA
@ BRUSH_FRONTFACE
@ BRUSH_ACCUMULATE
@ BRUSH_FRONTFACE_FALLOFF
eBrushVertexPaintType
@ VPAINT_BRUSH_TYPE_AVERAGE
@ VPAINT_BRUSH_TYPE_DRAW
@ VPAINT_BRUSH_TYPE_SMEAR
@ VPAINT_BRUSH_TYPE_BLUR
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ CD_PROP_BYTE_COLOR
@ CD_PROP_COLOR
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
eObjectMode
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_SCULPT
@ OB_MODE_VERTEX_PAINT
Object is a sort of wrapper for general info.
@ OB_MESH
ePaintSymmetryFlags
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
@ MTEX_MAP_MODE_3D
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
#define OPERATOR_RETVAL_CHECK(ret)
void ED_paint_cursor_start(Paint *paint, bool(*poll)(bContext *C))
bool ED_mesh_color_ensure(Mesh *mesh, const char *name)
Definition mesh_data.cc:382
void ED_mesh_mirror_topo_table_end(Object *ob)
Definition meshtools.cc:258
void ED_mesh_mirror_spatial_table_end(Object *ob)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
@ V3D_PROJ_TEST_CLIP_NEAR
Definition ED_view3d.hh:282
@ V3D_PROJ_TEST_CLIP_BB
Definition ED_view3d.hh:280
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void ED_view3d_init_mats_rv3d(const Object *ob, RegionView3D *rv3d)
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
IMB_BlendMode
Definition IMB_imbuf.hh:178
@ IMB_BLEND_ERASE_ALPHA
Definition IMB_imbuf.hh:185
@ IMB_BLEND_ADD_ALPHA
Definition IMB_imbuf.hh:186
@ IMB_BLEND_MIX
Definition IMB_imbuf.hh:179
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
#define ND_DRAW
Definition WM_types.hh:461
#define ND_MODE
Definition WM_types.hh:445
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_OBJECT
Definition WM_types.hh:379
@ BM_ELEM_SELECT
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
BMesh const char void * data
BMesh * bm
ATTR_WARN_UNUSED_RESULT const BMLoop * l
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE bool isZero() const
Definition btVector3.h:683
int64_t size() const
Definition BLI_array.hh:256
const T * data() const
Definition BLI_array.hh:312
bool is_empty() const
Definition BLI_array.hh:264
static AttributeOwner from_id(ID *id)
Definition attribute.cc:44
bool is() const
void value_initialize_n(void *ptr, int64_t n) const
ChannelStorageType r
ChannelStorageType g
ChannelStorageType b
ChannelStorageType a
const CPPType & type() const
MutableSpan< T > typed() const
void materialize(void *dst) const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr bool is_empty() const
Definition BLI_span.hh:509
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr bool is_empty() const
Definition BLI_span.hh:260
GAttributeReader lookup(const StringRef attribute_id) const
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:676
void foreach_index(Fn &&fn) const
nullptr float
#define acosf(x)
static float verts[][3]
uint col
#define LOG(level)
Definition log.h:97
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
static char faces[256]
int face_find_corner_from_vert(const IndexRange face, const Span< int > corner_verts, const int vert)
Definition BKE_mesh.hh:327
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2663
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2628
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
void mesh_select_vert_flush(Mesh &mesh)
void mesh_select_face_flush(Mesh &mesh)
BLI_INLINE ColorSceneLinear4f< Alpha > decode(const ColorSceneLinearByteEncoded4b< Alpha > &color)
Definition BLI_color.hh:77
BLI_INLINE Color BLI_mix_colors(const IMB_BlendMode tool, const Color a, const Color b, const typename Traits::BlendType alpha)
BLI_INLINE ColorSceneLinearByteEncoded4b< Alpha > encode(const ColorSceneLinear4f< Alpha > &color)
Definition BLI_color.hh:50
bool vgroup_sync_from_pose(Object *ob)
bool mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports)
float view_angle_limits_apply_falloff(const NormalAnglePrecalc *a, float angle_cos, float *mask_p)
bool brush_use_accumulate_ex(const Brush &brush, eObjectMode ob_mode)
void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
bool use_normal(const VPaint &vp)
void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
void mode_exit_generic(Object &ob, eObjectMode mode_flag)
bool test_brush_angle_falloff(const Brush &brush, const NormalAnglePrecalc &normal_angle_precalc, float angle_cos, float *brush_strength)
void init_session_data(const ToolSettings &ts, Object &ob)
void mode_enter_generic(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, eObjectMode mode_flag)
void update_cache_invariants(bContext *C, VPaint &vp, SculptSession &ss, wmOperator *op, const float mval[2])
void get_brush_alpha_data(const SculptSession &ss, const Paint &paint, const Brush &brush, float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure)
void init_session(Main &bmain, Depsgraph &depsgraph, Scene &scene, Paint &paint, Object &ob, eObjectMode object_mode)
bool brush_use_accumulate(const VPaint &vp)
void init_stroke(Depsgraph &depsgraph, Object &ob)
void update_cache_variants(bContext *C, VPaint &vp, Object &ob, PointerRNA *ptr)
void last_stroke_update(const float location[3], Paint &paint)
IndexMask pbvh_gather_generic(const Depsgraph &depsgraph, const Object &ob, const VPaint &wp, const Brush &brush, IndexMaskMemory &memory)
void smooth_brush_toggle_off(Paint *paint, StrokeCache *cache)
bool stroke_get_location_bvh(bContext *C, float out[3], const float mval[2], const bool force_original)
Definition sculpt.cc:4940
bool node_in_sphere(const bke::pbvh::Node &node, const float3 &location, const float radius_sq, const bool original)
Definition sculpt.cc:2429
bool node_in_cylinder(const DistRayAABB_Precalc &ray_dist_precalc, const bke::pbvh::Node &node, const float radius_sq, const bool original)
Definition sculpt.cc:2439
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7183
wmOperatorStatus paint_stroke_exec(bContext *C, wmOperator *op, PaintStroke *stroke)
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7105
static bool fill_active_color(Object &ob, ColorPaint4f fill_color, bool only_selected=true, bool affect_alpha=true)
static void fill_mesh_face_or_corner_attribute(Mesh &mesh, const T &value, const AttrDomain domain, const MutableSpan< T > data, const bool use_vert_sel, const bool use_face_sel, const bool affect_alpha)
static void fill_mesh_color(Mesh &mesh, const ColorPaint4f &color, const StringRef attribute_name, const bool use_vert_sel, const bool use_face_sel, const bool affect_alpha)
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6972
void paint_stroke_cancel(bContext *C, wmOperator *op, PaintStroke *stroke)
void ensure_valid_pivot(const Object &ob, Paint &paint)
bool paint_supports_dynamic_size(const Brush &br, PaintMode mode)
wmOperatorStatus paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintStroke **stroke_p)
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7055
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1833
ViewContext * paint_stroke_view_context(PaintStroke *stroke)
static void fill_bm_face_or_corner_attribute(BMesh &bm, const T &value, const AttrDomain domain, const int cd_offset, const bool use_vert_sel)
void * paint_stroke_mode_data(PaintStroke *stroke)
float paint_stroke_distance_get(PaintStroke *stroke)
bool object_active_color_fill(Object &ob, const float fill_color[4], bool only_selected)
void paint_stroke_free(bContext *C, wmOperator *op, PaintStroke *stroke)
PaintStroke * paint_stroke_new(bContext *C, wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeRedraw redraw, StrokeDone done, int event_type)
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6775
void paint_stroke_set_mode_data(PaintStroke *stroke, std::unique_ptr< PaintModeData > mode_data)
bool is_symmetry_iteration_valid(const char i, const char symm)
ColorSceneLinearByteEncoded4b< eAlpha::Straight > ColorPaint4b
ColorSceneLinear4f< eAlpha::Straight > ColorPaint4f
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
void paint_cursor_delete_textures()
VertProjHandle * ED_vpaint_proj_handle_create(Depsgraph &depsgraph, Scene &scene, Object &ob, blender::Span< blender::float3 > &r_vert_positions, blender::Span< blender::float3 > &r_vert_normals)
bool weight_paint_poll(bContext *C)
@ BRUSH_STROKE_SMOOTH
@ BRUSH_STROKE_INVERT
float paint_calc_object_space_radius(const ViewContext &vc, const blender::float3 &center, float pixel_radius)
bool vertex_paint_mode_poll(bContext *C)
void ED_vpaint_proj_handle_free(VertProjHandle *vp_handle)
void paint_stroke_operator_properties(wmOperatorType *ot)
bool vertex_paint_poll(bContext *C)
static ColorPaint4f vpaint_get_current_col(VPaint &vp, bool secondary)
static float paint_and_tex_color_alpha(const VPaint &vp, VPaintData &vpd, const float v_co[3], Color *r_color)
void PAINT_OT_vertex_color_set(wmOperatorType *ot)
static void calculate_average_color(VPaintData &vpd, Object &ob, Mesh &mesh, const Brush &brush, const GSpan attribute, const Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask)
static wmOperatorStatus vpaint_exec(bContext *C, wmOperator *op)
static void to_static_color_type(const bke::AttrType type, const Func &func)
static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
void PAINT_OT_vertex_paint(wmOperatorType *ot)
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
static void do_vpaint_brush_blur_loops(const bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, const Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, GMutableSpan attribute)
static void filter_factors_with_selection(const Span< bool > select_vert, const Span< int > verts, const MutableSpan< float > factors)
static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke)
static void do_vpaint_brush_blur_verts(const bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, const Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, GMutableSpan attribute)
static Color vpaint_blend(const VPaint &vp, Color color_curr, Color color_orig, Color color_paint, const typename Traits::ValueType alpha, const typename Traits::BlendType brush_alpha_value)
static Color vpaint_blend_stroke(const VPaint &vp, MutableSpan< Color > prev_vertex_colors, MutableSpan< Color > vertex_colors, MutableSpan< Color > stroke_buffer, Color brush_mark_color, float brush_mark_alpha, float brush_strength, int index)
bool vertex_paint_poll_ignore_tool(bContext *C)
void ED_object_vpaintmode_enter(bContext *C, Depsgraph &depsgraph)
static wmOperatorStatus vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
static ColorPaint4f toFloat(const Color &c)
static void vpaint_do_blur(const bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, const Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, GMutableSpan attribute)
static void vpaint_do_symmetrical_brush_actions(bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob)
void ED_object_vpaintmode_exit(bContext *C)
static void vpaint_do_draw(const bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, const Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, GMutableSpan attribute)
bool vertex_paint_mode_poll(bContext *C)
void ED_object_vpaintmode_exit_ex(Object &ob)
void ED_object_vpaintmode_enter_ex(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
static void do_vpaint_brush_smear(const bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, const Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, GMutableSpan attribute)
static void vertex_paint_init_stroke(Depsgraph &depsgraph, Object &ob)
static void vpaint_do_radial_symmetry(bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, const Brush &brush, const ePaintSymmetryFlags symm, const int axis)
static std::unique_ptr< VPaintData > vpaint_init_vpaint(bContext *C, wmOperator *op, Scene &scene, Depsgraph &depsgraph, VPaint &vp, Object &ob, Mesh &mesh, const AttrDomain domain, const bke::AttrType type, const Brush &brush)
static void vpaint_paint_leaves(bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, GMutableSpan attribute, const Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask)
static wmOperatorStatus vpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
static blender::float3 get_brush_color(const Paint *paint, const Brush *brush, const StrokeCache &cache, const ColorPaint4f &paint_color)
static wmOperatorStatus vertex_color_set_exec(bContext *C, wmOperator *op)
static Color fromFloat(const ColorPaint4f &c)
void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
static void vpaint_stroke_update_step(bContext *C, wmOperator *, PaintStroke *stroke, PointerRNA *itemptr)
static void vpaint_do_paint(bContext *C, const VPaint &vp, VPaintData &vpd, Object &ob, Mesh &mesh, const Brush &brush, const ePaintSymmetryFlags symm, const int axis, const int i, const float angle)
static void vpaint_cancel(bContext *C, wmOperator *op)
static wmOperatorStatus vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool vertex_paint_poll(bContext *C)
static void paint_and_tex_color_alpha_intern(const VPaint &vp, const ViewContext *vc, const float co[3], float r_rgba[4])
#define sqrtf
#define cosf
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:184
const float * SCULPT_brush_frontface_normal_from_falloff_shape(const SculptSession &ss, char falloff_shape)
Definition sculpt.cc:1180
void SCULPT_cache_calc_brushdata_symm(blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis, const float angle)
Definition sculpt.cc:3465
static float brush_strength(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const float feather, const PaintModeSettings &)
Definition sculpt.cc:2175
BMLoop * l_first
float falloff_angle
struct MTex mtex
char falloff_shape
struct CurveMapping * curve_distance_falloff
short blend
char weight_brush_type
struct CurveMapping * curve_size
char vertex_brush_type
struct CurveMapping * curve_strength
Definition DNA_ID.h:414
char brush_map_mode
struct Tex * tex
ObjectRuntimeHandle * runtime
struct SculptSession * sculpt
PaintRuntimeHandle * runtime
float persmat[4][4]
float viewinv[4][4]
struct ToolSettings * toolsettings
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
blender::Array< MDeformVert > dvert_prev
Definition BKE_paint.hh:485
float * alpha_weight
Definition BKE_paint.hh:481
struct SculptSession::@362240011116215270333121305340144315201335267314::@377352350121204263020240366015362210376116055117 wpaint
eObjectMode mode_type
Definition BKE_paint.hh:491
struct SculptSession::@362240011116215270333121305340144315201335267314 mode
bool building_vp_handle
Definition BKE_paint.hh:495
AttrDomain domain
Span< float3 > vert_positions
Span< float3 > vert_normals
GArray color_curr
VertProjHandle * vp_handle
GArray color_prev
ColorPaint4f paintcol
GArray stroke_buffer
struct VPaintData::@051050346210221040071306373266116077075360370265 smear
NormalAnglePrecalc normal_angle_precalc
~VPaintData() override
GArray prev_colors
bke::AttrType type
ViewContext vc
RegionView3D * rv3d
Definition ED_view3d.hh:80
ARegion * region
Definition ED_view3d.hh:77
Object * obact
Definition ED_view3d.hh:75
Depsgraph * depsgraph
Definition ED_view3d.hh:72
blender::float3 average_stroke_accum
std::optional< blender::float3 > initial_hsv_jitter
wmEventType type
Definition WM_types.hh:757
wmOperatorStatus(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1081
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
bool WM_toolsystem_active_tool_is_brush(const bContext *C)
void WM_toolsystem_update_from_context_view3d(bContext *C)