Blender V4.5
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_listbase.h"
22#include "BLI_math_color.h"
23#include "BLI_math_geom.h"
24#include "BLI_math_matrix.hh"
25#include "BLI_math_rotation.h"
26#include "BLI_task.hh"
27#include "BLI_vector.hh"
28
29#include "DNA_brush_types.h"
30#include "DNA_mesh_types.h"
31#include "DNA_meshdata_types.h"
32#include "DNA_object_types.h"
33#include "DNA_scene_types.h"
34
35#include "RNA_access.hh"
36#include "RNA_define.hh"
37
38#include "BKE_attribute.hh"
39#include "BKE_brush.hh"
40#include "BKE_colortools.hh"
41#include "BKE_context.hh"
42#include "BKE_deform.hh"
43#include "BKE_editmesh.hh"
44#include "BKE_lib_id.hh"
45#include "BKE_library.hh"
46#include "BKE_mesh.hh"
47#include "BKE_object.hh"
48#include "BKE_object_types.hh"
49#include "BKE_paint.hh"
50
51#include "DEG_depsgraph.hh"
52
53#include "WM_api.hh"
54#include "WM_message.hh"
55#include "WM_toolsystem.hh"
56#include "WM_types.hh"
57
58#include "ED_image.hh"
59#include "ED_mesh.hh"
60#include "ED_object.hh"
61#include "ED_object_vgroup.hh"
62#include "ED_paint.hh"
63#include "ED_screen.hh"
64#include "ED_sculpt.hh"
65#include "ED_view3d.hh"
66
67/* For IMB_BlendMode only. */
68#include "IMB_imbuf.hh"
69
70#include "bmesh.hh"
71
72#include "mesh_brush_common.hh"
73#include "paint_intern.hh" /* own include */
74#include "sculpt_automask.hh"
75#include "sculpt_boundary.hh"
76#include "sculpt_cloth.hh"
77#include "sculpt_intern.hh"
78#include "sculpt_pose.hh"
79
82using namespace blender;
83using namespace blender::color;
84using namespace blender::ed::sculpt_paint; /* For vwpaint namespace. */
86
87static CLG_LogRef LOG = {"ed.sculpt_paint"};
88
89/* -------------------------------------------------------------------- */
92
93static bool isZero(ColorPaint4f c)
94{
95 return c.r == 0.0f && c.g == 0.0f && c.b == 0.0f && c.a == 0.0f;
96}
97
98static bool isZero(ColorPaint4b c)
99{
100 return c.r == 0 && c.g == 0 && c.b == 0 && c.a == 0;
101}
102
103template<typename Color> static ColorPaint4f toFloat(const Color &c)
104{
105 if constexpr (std::is_same_v<Color, ColorPaint4b>) {
106 return c.decode();
107 }
108 else {
109 return c;
110 }
111}
112
113template<typename Color> static Color fromFloat(const ColorPaint4f &c)
114{
115 if constexpr (std::is_same_v<Color, ColorPaint4b>) {
116 return c.encode();
117 }
118 else {
119 return c;
120 }
121}
122
123/* Use for 'blur' brush, align with pbvh::Tree nodes, created and freed on each update. */
124template<typename BlendType> struct VPaintAverageAccum {
125 BlendType len;
126 BlendType value[3];
127};
128
130
131/* -------------------------------------------------------------------- */
134
135void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
136{
138 a->do_mask_normal = do_mask_normal;
139 if (do_mask_normal) {
140 a->angle_inner = angle;
141 a->angle = (a->angle_inner + 90.0f) * 0.5f;
142 }
143 else {
144 a->angle_inner = a->angle = angle;
145 }
146
147 a->angle_inner *= float(M_PI_2 / 90);
148 a->angle *= float(M_PI_2 / 90);
149 a->angle_range = a->angle - a->angle_inner;
150
151 if (a->angle_range <= 0.0f) {
152 a->do_mask_normal = false; /* no need to do blending */
153 }
154
155 a->angle__cos = cosf(a->angle);
157}
158
159float view_angle_limits_apply_falloff(const NormalAnglePrecalc *a, float angle_cos, float *mask_p)
160{
161 if (angle_cos <= a->angle__cos) {
162 /* outsize the normal limit */
163 return false;
164 }
165 if (angle_cos < a->angle_inner__cos) {
166 *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
167 return true;
168 }
169 return true;
170}
171
173 const NormalAnglePrecalc &normal_angle_precalc,
174 const float angle_cos,
175 float *brush_strength)
176{
177 if (((brush.flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
178 ((brush.flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
179 vwpaint::view_angle_limits_apply_falloff(&normal_angle_precalc, angle_cos, brush_strength)))
180 {
181 return true;
182 }
183 return false;
184}
185
186bool use_normal(const VPaint &vp)
187{
188 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
189 return ((brush.flag & BRUSH_FRONTFACE) != 0) || ((brush.flag & BRUSH_FRONTFACE_FALLOFF) != 0);
190}
191
192bool brush_use_accumulate_ex(const Brush &brush, const eObjectMode ob_mode)
193{
194 return ((brush.flag & BRUSH_ACCUMULATE) != 0 ||
195 (ob_mode == OB_MODE_VERTEX_PAINT ?
198}
199
201{
202 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
204}
205
206void init_stroke(Depsgraph &depsgraph, Object &ob)
207{
209 SculptSession &ss = *ob.sculpt;
210
211 /* Ensure ss.cache is allocated. It will mostly be initialized in
212 * vwpaint::update_cache_invariants and vwpaint::update_cache_variants.
213 */
214 if (!ss.cache) {
215 ss.cache = MEM_new<StrokeCache>(__func__);
216 }
217}
218
220 Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, eObjectMode object_mode)
221{
222 /* Create persistent sculpt mode data */
224
225 BLI_assert(ob.sculpt == nullptr);
226 ob.sculpt = MEM_new<SculptSession>(__func__);
227 ob.sculpt->mode_type = object_mode;
229
230 ensure_valid_pivot(ob, scene);
231}
232
234{
235 /* Create maps */
236 if (ob.mode == OB_MODE_VERTEX_PAINT) {
238 }
239 else if (ob.mode == OB_MODE_WEIGHT_PAINT) {
241 }
242 else {
244 BLI_assert(0);
245 return;
246 }
247
248 Mesh *mesh = (Mesh *)ob.data;
249
250 /* Create average brush arrays */
251 if (ob.mode == OB_MODE_WEIGHT_PAINT) {
252 SculptSession &ss = *ob.sculpt;
254 if (ss.mode.wpaint.alpha_weight == nullptr) {
255 ss.mode.wpaint.alpha_weight = MEM_calloc_arrayN<float>(mesh->verts_num, __func__);
256 }
257 if (ss.mode.wpaint.dvert_prev.is_empty()) {
258 MDeformVert initial_value{};
259 /* Use to show this isn't initialized, never apply to the mesh data. */
260 initial_value.flag = 1;
261 ss.mode.wpaint.dvert_prev = Array<MDeformVert>(mesh->verts_num, initial_value);
262 }
263 }
264 else {
266 if (!ss.mode.wpaint.dvert_prev.is_empty()) {
269 ss.mode.wpaint.dvert_prev = {};
270 }
271 }
272 }
273}
274
276 const Object &ob,
277 const VPaint &wp,
278 const Brush &brush,
279 IndexMaskMemory &memory)
280{
281 SculptSession &ss = *ob.sculpt;
282 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
283 const bool use_normal = vwpaint::use_normal(wp);
285
286 /* Build a list of all nodes that are potentially within the brush's area of influence */
288 nodes = bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
289 return node_in_sphere(node, ss.cache->location_symm, ss.cache->radius_squared, true);
290 });
291
293 use_normal ? calc_area_normal(depsgraph, brush, ob, nodes).value_or(float3(0)) : float3(0);
294 }
295 else {
298 nodes = bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
299 return node_in_cylinder(ray_dist_precalc, node, ss.cache->radius_squared, true);
300 });
301
303 }
304 return nodes;
305}
306
308 Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, const eObjectMode mode_flag)
309{
310 ob.mode |= mode_flag;
312
313 /* Same as sculpt mode, make sure we don't have cached derived mesh which
314 * points to freed arrays.
315 */
317
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 *paint = BKE_paint_get_active_from_paintmode(&scene, paint_mode);
325 BKE_paint_init(&bmain, &scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
326 }
327 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
328 const PaintMode paint_mode = PaintMode::Weight;
329
331 Paint *paint = BKE_paint_get_active_from_paintmode(&scene, paint_mode);
333 BKE_paint_init(&bmain, &scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
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 vwpaint::init_session(bmain, depsgraph, scene, ob, mode_flag);
351
352 /* Flush object mode. */
354}
355
356void mode_exit_generic(Object &ob, const eObjectMode mode_flag)
357{
358 using namespace blender;
360 ob.mode &= ~mode_flag;
361
362 if (mode_flag == OB_MODE_VERTEX_PAINT) {
363 if (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
365 }
366 else if (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
368 }
369 }
370 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
371 if (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
373 }
374 else if (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
376 }
377 }
378 else {
379 BLI_assert(0);
380 }
381
382 /* If the cache is not released by a cancel or a done, free it now. */
383 if (ob.sculpt) {
384 MEM_delete(ob.sculpt->cache);
385 ob.sculpt->cache = nullptr;
386 }
387
389
391
392 if (mode_flag == OB_MODE_WEIGHT_PAINT) {
395 }
396
397 /* Never leave derived meshes behind. */
399
400 /* Flush object mode. */
402}
403
405{
407 if (ob == nullptr || ob->type != OB_MESH) {
408 return false;
409 }
410 if (!ob->data || !ID_IS_EDITABLE(ob->data)) {
411 return false;
412 }
413 return true;
414}
415
417{
418 Brush *brush = BKE_paint_brush(paint);
419 /* The current brush should match with what we have stored in the cache. */
420 BLI_assert(brush == cache->brush);
421
422 /* If saved_active_brush is not set, brush was not switched/affected in
423 * smooth_brush_toggle_on(). */
424 if (cache->saved_active_brush) {
425 Scene *scene = CTX_data_scene(C);
426 BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
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 const Scene *scene = CTX_data_scene(C);
439 float mat[3][3];
440 float view_dir[3] = {0.0f, 0.0f, 1.0f};
441 int mode;
442
443 /* VW paint needs to allocate stroke cache before update is called. */
444 if (!ss.cache) {
445 cache = MEM_new<StrokeCache>(__func__);
446 ss.cache = cache;
447 }
448 else {
449 cache = ss.cache;
450 }
451
452 /* Initial mouse location */
453 if (mval) {
454 copy_v2_v2(cache->initial_mouse, mval);
455 }
456 else {
457 zero_v2(cache->initial_mouse);
458 }
459
460 mode = RNA_enum_get(op->ptr, "mode");
461 cache->invert = mode == BRUSH_STROKE_INVERT;
462 cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
463 /* not very nice, but with current events system implementation
464 * we can't handle brush appearance inversion hotkey separately (sergey) */
465 if (cache->invert) {
466 ups->draw_inverted = true;
467 }
468 else {
469 ups->draw_inverted = false;
470 }
471
472 if (cache->alt_smooth) {
474 }
475
476 copy_v2_v2(cache->mouse, cache->initial_mouse);
477 const Brush *brush = BKE_paint_brush(&vp.paint);
478 /* Truly temporary data that isn't stored in properties */
479 cache->vc = vc;
480 cache->brush = brush;
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(scene, brush);
495 cache->is_last_valid = false;
496
497 cache->accum = true;
498
499 if (BKE_brush_color_jitter_get_settings(scene, &vp.paint, brush)) {
501 }
502}
503
505{
506 using namespace blender;
507 Scene *scene = CTX_data_scene(C);
508 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 */
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_size_get(scene, &brush));
535 }
536
538 {
539 cache->radius = cache->initial_radius * cache->pressure;
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
552void get_brush_alpha_data(const Scene &scene,
553 const SculptSession &ss,
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_size_get(&scene, &brush) *
560 (BKE_brush_use_size_pressure(&brush) ? ss.cache->pressure : 1.0f);
561 *r_brush_alpha_value = BKE_brush_alpha_get(&scene, &brush);
562 *r_brush_alpha_pressure = (BKE_brush_use_alpha_pressure(&brush) ? ss.cache->pressure : 1.0f);
563}
564
565void last_stroke_update(Scene &scene, const float location[3])
566{
569 add_v3_v3(ups.average_stroke_accum, location);
570 ups.last_stroke_valid = true;
571}
572
573/* -------------------------------------------------------------------- */
574
576{
577 Main *bmain = CTX_data_main(C);
578 Scene *scene = CTX_data_scene(C);
579 Brush *cur_brush = BKE_paint_brush(paint);
580
581 /* Switch to the blur (smooth) brush if possible. */
583 Brush *smooth_brush = BKE_paint_brush(paint);
584
585 if (!smooth_brush) {
586 BKE_paint_brush_set(paint, cur_brush);
587 CLOG_WARN(&LOG, "Switching to the blur (smooth) brush not possible, corresponding brush not");
588 cache->saved_active_brush = nullptr;
589 return;
590 }
591
592 int cur_brush_size = BKE_brush_size_get(scene, cur_brush);
593
594 cache->saved_active_brush = cur_brush;
595 cache->saved_smooth_size = BKE_brush_size_get(scene, smooth_brush);
596 BKE_brush_size_set(scene, smooth_brush, cur_brush_size);
597 BKE_curvemapping_init(smooth_brush->curve);
598}
599
600} // namespace blender::ed::sculpt_paint::vwpaint
601
603{
604 const Object *ob = CTX_data_active_object(C);
605 if (!ob) {
606 return false;
607 }
608 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
609
610 if (!(ob->mode == OB_MODE_VERTEX_PAINT && mesh->faces_num)) {
611 return false;
612 }
613
614 if (!BKE_color_attribute_supported(*mesh, mesh->active_color_attribute)) {
615 return false;
616 }
617
618 return true;
619}
620
621static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
622{
624 ScrArea *area = CTX_wm_area(C);
625 if (area && area->spacetype == SPACE_VIEW3D) {
626 ARegion *region = CTX_wm_region(C);
627 if (region->regiontype == RGN_TYPE_WINDOW) {
628 if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
629 return true;
630 }
631 }
632 }
633 }
634 return false;
635}
636
638{
639 return vertex_paint_poll_ex(C, true);
640}
641
643{
644 return vertex_paint_poll_ex(C, false);
645}
646
647static ColorPaint4f vpaint_get_current_col(Scene &scene, VPaint &vp, bool secondary)
648{
649 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
650 float color[4];
651 const float *brush_color = secondary ? BKE_brush_secondary_color_get(&scene, &vp.paint, brush) :
652 BKE_brush_color_get(&scene, &vp.paint, brush);
654
655 color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */
656
657 return ColorPaint4f(color);
658}
659
660/* wpaint has 'wpaint_blend' */
661template<typename Color, typename Traits>
662static Color vpaint_blend(const VPaint &vp,
663 Color color_curr,
664 Color color_orig,
665 Color color_paint,
666 const typename Traits::ValueType alpha,
667 const typename Traits::BlendType brush_alpha_value)
668{
669 using Value = typename Traits::ValueType;
670
671 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
672 const IMB_BlendMode blend = (IMB_BlendMode)brush.blend;
673
674 const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
675
676 /* If no accumulate, clip color adding with `color_orig` & `color_test`. */
678 uint a;
679 Color color_test;
680 Value *cp, *ct, *co;
681
682 color_test = BLI_mix_colors<Color, Traits>(blend, color_orig, color_paint, brush_alpha_value);
683
684 cp = (Value *)&color_blend;
685 ct = (Value *)&color_test;
686 co = (Value *)&color_orig;
687
688 for (a = 0; a < 4; a++) {
689 if (ct[a] < co[a]) {
690 if (cp[a] < ct[a]) {
691 cp[a] = ct[a];
692 }
693 else if (cp[a] > co[a]) {
694 cp[a] = co[a];
695 }
696 }
697 else {
698 if (cp[a] < co[a]) {
699 cp[a] = co[a];
700 }
701 else if (cp[a] > ct[a]) {
702 cp[a] = ct[a];
703 }
704 }
705 }
706 }
707
709 {
710 Value *cp, *cc;
711 cp = (Value *)&color_blend;
712 cc = (Value *)&color_curr;
713 cp[3] = cc[3];
714 }
715
716 return color_blend;
717}
718
726template<typename Color, typename Traits>
728 MutableSpan<Color> prev_vertex_colors,
729 MutableSpan<Color> vertex_colors,
730 MutableSpan<Color> stroke_buffer,
731 Color brush_mark_color,
732 float brush_mark_alpha,
733 float brush_strength,
734 int index)
735{
738 BLI_assert(!stroke_buffer.is_empty());
739 BLI_assert(!prev_vertex_colors.is_empty());
740
741 if (isZero(prev_vertex_colors[index])) {
742 prev_vertex_colors[index] = vertex_colors[index];
743 }
744
745 /* Mix with mesh color under the stroke (a bit easier than trying to premultiply
746 * byte Color types */
747 if (isZero(stroke_buffer[index])) {
748 stroke_buffer[index] = vertex_colors[index];
749 stroke_buffer[index].a = 0;
750 }
751
753 brush_mark_color,
754 stroke_buffer[index],
755 stroke_buffer[index].a);
756
758 vertex_colors[index],
759 prev_vertex_colors[index],
760 stroke_buffer[index],
761 brush_mark_alpha,
762 Traits::range * brush_strength);
763 }
764 else {
766 vertex_colors[index],
767 Color() /* unused in accumulate mode */,
768 brush_mark_color,
769 brush_mark_alpha,
770 Traits::range * brush_strength);
771 }
772 return result;
773}
774
776 const ViewContext *vc,
777 const float co[3],
778 float r_rgba[4])
779{
780 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
781 const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
782 BLI_assert(mtex->tex != nullptr);
783 if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
784 BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co, r_rgba, 0, nullptr);
785 }
786 else {
787 float co_ss[2]; /* screenspace */
791 {
792 const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
793 BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co_ss_3d, r_rgba, 0, nullptr);
794 }
795 else {
796 zero_v4(r_rgba);
797 }
798 }
799}
800
801static void vertex_paint_init_stroke(Depsgraph &depsgraph, Object &ob)
802{
804}
805
807
808/* -------------------------------------------------------------------- */
811
812void ED_object_vpaintmode_enter_ex(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
813{
815}
817{
818 Main &bmain = *CTX_data_main(C);
819 Scene &scene = *CTX_data_scene(C);
821 ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
822}
823
825
826/* -------------------------------------------------------------------- */
829
839
841
842/* -------------------------------------------------------------------- */
845
850{
851 Main &bmain = *CTX_data_main(C);
854 const int mode_flag = OB_MODE_VERTEX_PAINT;
855 const bool is_mode_set = (ob.mode & mode_flag) != 0;
856 Scene &scene = *CTX_data_scene(C);
857 ToolSettings &ts = *scene.toolsettings;
858
859 if (!is_mode_set) {
860 if (!blender::ed::object::mode_compat_set(C, &ob, (eObjectMode)mode_flag, op->reports)) {
861 return OPERATOR_CANCELLED;
862 }
863 }
864
866
867 if (is_mode_set) {
869 }
870 else {
872 if (depsgraph) {
874 }
875 ED_object_vpaintmode_enter_ex(bmain, *depsgraph, scene, ob);
877 }
878
880
881 /* update modifier stack for mapping requirements */
882 DEG_id_tag_update(&mesh->id, 0);
883
885 WM_msg_publish_rna_prop(mbus, &ob.id, &ob, Object, mode);
886
888
889 return OPERATOR_FINISHED;
890}
891
893{
894 ot->name = "Vertex Paint Mode";
895 ot->idname = "PAINT_OT_vertex_paint_toggle";
896 ot->description = "Toggle the vertex paint mode in 3D view";
897
900
902}
903
905
906/* -------------------------------------------------------------------- */
909
910/* Implementation notes:
911 *
912 * Operator->invoke()
913 * - Validate context (add #Mesh.mloopcol).
914 * - Create custom-data storage.
915 * - Call paint once (mouse click).
916 * - Add modal handler.
917 *
918 * Operator->modal()
919 * - For every mouse-move, apply vertex paint.
920 * - Exit on mouse release, free custom-data.
921 * (return OPERATOR_FINISHED also removes handler and operator)
922 *
923 * For future:
924 * - implement a stroke event (or mouse-move with past positions).
925 * - revise whether op->customdata should be added in object, in set_vpaint.
926 */
927
928template<typename Func>
929static void to_static_color_type(const eCustomDataType type, const Func &func)
930{
931 switch (type) {
932 case CD_PROP_COLOR:
933 func(ColorGeometry4f());
934 break;
936 func(ColorGeometry4b());
937 break;
938 default:
940 break;
941 }
942}
943
944struct VPaintData : public PaintModeData {
948
950
952
960
962
963 /* Special storage for smear brush, avoid feedback loop - update each step. */
964 struct {
968
969 /* For brushes that don't use accumulation, a temporary holding array */
972
973 ~VPaintData() override
974 {
975 if (vp_handle) {
977 }
978 }
979};
980
981static std::unique_ptr<VPaintData> vpaint_init_vpaint(bContext *C,
982 wmOperator *op,
983 Scene &scene,
984 Depsgraph &depsgraph,
985 VPaint &vp,
986 Object &ob,
987 Mesh &mesh,
988 const AttrDomain domain,
989 const eCustomDataType type,
990 const Brush &brush)
991{
992 std::unique_ptr<VPaintData> vpd = std::make_unique<VPaintData>();
993
994 vpd->type = type;
995 vpd->domain = domain;
996
998
999 vwpaint::view_angle_limits_init(&vpd->normal_angle_precalc,
1000 brush.falloff_angle,
1001 (brush.flag & BRUSH_FRONTFACE_FALLOFF) != 0);
1002
1003 vpd->paintcol = vpaint_get_current_col(
1004 scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
1005
1006 vpd->is_texbrush = !(brush.vertex_brush_type == VPAINT_BRUSH_TYPE_BLUR) && brush.mtex.tex;
1007
1009 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute, domain);
1010 vpd->smear.color_prev = GArray(attribute.type(), attribute.size());
1011 attribute.materialize(vpd->smear.color_prev.data());
1012
1013 vpd->smear.color_curr = vpd->smear.color_prev;
1014 }
1015
1016 /* Create projection handle */
1017 if (vpd->is_texbrush) {
1018 ob.sculpt->building_vp_handle = true;
1019 vpd->vp_handle = ED_vpaint_proj_handle_create(
1020 depsgraph, scene, ob, vpd->vert_positions, vpd->vert_normals);
1021 ob.sculpt->building_vp_handle = false;
1022 }
1023
1025 if (vpd->prev_colors.is_empty()) {
1026 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute);
1027 vpd->prev_colors = GArray(attribute.type(), attribute.size());
1028 attribute.type().value_initialize_n(vpd->prev_colors.data(), vpd->prev_colors.size());
1029 }
1030
1031 if (vpd->stroke_buffer.is_empty()) {
1032 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute);
1033 vpd->stroke_buffer = GArray(attribute.type(), attribute.size());
1034 attribute.type().value_initialize_n(vpd->stroke_buffer.data(), vpd->stroke_buffer.size());
1035 }
1036 }
1037 else {
1038 vpd->prev_colors = {};
1039 vpd->stroke_buffer = {};
1040 }
1041
1042 return vpd;
1043}
1044
1045static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
1046{
1047 Scene &scene = *CTX_data_scene(C);
1048 ToolSettings &ts = *scene.toolsettings;
1049 PaintStroke *stroke = (PaintStroke *)op->customdata;
1050 VPaint &vp = *ts.vpaint;
1051 Brush &brush = *BKE_paint_brush(&vp.paint);
1053 SculptSession &ss = *ob.sculpt;
1055
1056 /* context checks could be a poll() */
1058 if (mesh == nullptr || mesh->faces_num == 0) {
1059 return false;
1060 }
1061
1062 ED_mesh_color_ensure(mesh, nullptr);
1063
1064 const std::optional<bke::AttributeMetaData> meta_data = mesh->attributes().lookup_meta_data(
1065 mesh->active_color_attribute);
1066 if (!BKE_color_attribute_supported(*mesh, mesh->active_color_attribute)) {
1067 return false;
1068 }
1069
1070 std::unique_ptr<VPaintData> vpd = vpaint_init_vpaint(
1071 C, op, scene, depsgraph, vp, ob, *mesh, meta_data->domain, meta_data->data_type, brush);
1072
1073 paint_stroke_set_mode_data(stroke, std::move(vpd));
1074
1075 /* If not previously created, create vertex/weight paint mode session data */
1077 vwpaint::update_cache_invariants(C, vp, ss, op, mouse);
1079
1080 return true;
1081}
1082
1083static void filter_factors_with_selection(const Span<bool> select_vert,
1084 const Span<int> verts,
1085 const MutableSpan<float> factors)
1086{
1087 BLI_assert(verts.size() == factors.size());
1088
1089 for (const int i : verts.index_range()) {
1090 if (!select_vert[verts[i]]) {
1091 factors[i] = 0.0f;
1092 }
1093 }
1094}
1095
1097 const VPaint &vp,
1098 VPaintData &vpd,
1099 Object &ob,
1100 Mesh &mesh,
1102 const IndexMask &node_mask,
1103 GMutableSpan attribute)
1104{
1105 SculptSession &ss = *ob.sculpt;
1106 const StrokeCache &cache = *ss.cache;
1107
1108 const Brush &brush = *ob.sculpt->cache->brush;
1109 const Scene &scene = *CTX_data_scene(C);
1110 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1111
1112 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1114 scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1115 const bool use_normal = vwpaint::use_normal(vp);
1116 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1117 0;
1118 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1119
1120 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1121 ss, brush.falloff_shape);
1122
1123 GMutableSpan g_previous_color = vpd.prev_colors;
1124
1125 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1126 const OffsetIndices faces = mesh.faces();
1127 const Span<int> corner_verts = mesh.corner_verts();
1128 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1129 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1130 const bke::AttributeAccessor attributes = mesh.attributes();
1131 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1132 VArraySpan<bool> select_vert;
1133 if (use_vert_sel) {
1134 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1135 }
1136 VArraySpan<bool> select_poly;
1137 if (use_face_sel) {
1138 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1139 }
1140
1141 struct LocalData {
1142 Vector<float> factors;
1143 Vector<float> distances;
1144 };
1146 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1147 LocalData &tls = all_tls.local();
1148 const Span<int> verts = nodes[i].verts();
1149 tls.factors.resize(verts.size());
1150 const MutableSpan<float> factors = tls.factors;
1151 fill_factor_from_hide(hide_vert, verts, factors);
1152 filter_region_clip_factors(ss, vert_positions, verts, factors);
1153 if (!select_vert.is_empty()) {
1154 filter_factors_with_selection(select_vert, verts, factors);
1155 }
1156
1157 tls.distances.resize(verts.size());
1158 const MutableSpan<float> distances = tls.distances;
1160 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1161 filter_distances_with_radius(cache.radius, distances, factors);
1162 calc_brush_strength_factors(cache, brush, distances, factors);
1163
1164 for (const int i : verts.index_range()) {
1165 const int vert = verts[i];
1166 if (factors[i] == 0.0f) {
1167 continue;
1168 }
1169
1170 float brush_strength = cache.bstrength;
1171 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1172 1.0f;
1174 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1175 {
1176 continue;
1177 }
1178
1179 const float brush_fade = factors[i];
1180
1181 to_static_color_type(vpd.type, [&](auto dummy) {
1182 using T = decltype(dummy);
1183 using Color =
1184 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1185 using Traits = blender::color::Traits<Color>;
1186 using Blend = typename Traits::BlendType;
1187 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1188 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1189 /* Get the average face color */
1190 Color color_final(0, 0, 0, 0);
1191
1192 int total_hit_loops = 0;
1193 Blend blend[4] = {0};
1194
1195 for (const int face : vert_to_face[vert]) {
1196 if (!select_poly.is_empty() && !select_poly[face]) {
1197 return;
1198 }
1199 total_hit_loops += faces[face].size();
1200 for (const int corner : faces[face]) {
1201 const Color &col = colors[corner];
1202
1203 /* Color is squared to compensate the `sqrt` color encoding. */
1204 blend[0] += (Blend)col.r * (Blend)col.r;
1205 blend[1] += (Blend)col.g * (Blend)col.g;
1206 blend[2] += (Blend)col.b * (Blend)col.b;
1207 blend[3] += (Blend)col.a * (Blend)col.a;
1208 }
1209 }
1210
1211 if (total_hit_loops == 0) {
1212 return;
1213 }
1214
1215 /* Use rgb^2 color averaging. */
1216 Color *col = &color_final;
1217
1218 color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
1219 color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
1220 color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
1221 color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
1222
1223 /* For each face owning this vert,
1224 * paint each loop belonging to this vert. */
1225 for (const int face : vert_to_face[vert]) {
1226 const int corner = bke::mesh::face_find_corner_from_vert(
1227 faces[face], corner_verts, vert);
1228 if (!select_poly.is_empty() && !select_poly[face]) {
1229 continue;
1230 }
1231 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1232
1233 if (!previous_color.is_empty()) {
1234 /* Get the previous loop color */
1235 if (isZero(previous_color[corner])) {
1236 previous_color[corner] = colors[corner];
1237 }
1238 color_orig = previous_color[corner];
1239 }
1240 const float final_alpha = Traits::range * brush_fade * brush_strength *
1241 brush_alpha_pressure;
1242 /* Mix the new color with the original
1243 * based on the brush strength and the curve. */
1244 colors[corner] = vpaint_blend<Color, Traits>(
1245 vp, colors[corner], color_orig, *col, final_alpha, Traits::range * brush_strength);
1246 }
1247 });
1248 }
1249 });
1250}
1251
1253 const VPaint &vp,
1254 VPaintData &vpd,
1255 Object &ob,
1256 Mesh &mesh,
1258 const IndexMask &node_mask,
1259 GMutableSpan attribute)
1260{
1261 SculptSession &ss = *ob.sculpt;
1262 const StrokeCache &cache = *ss.cache;
1263
1264 const Brush &brush = *ss.cache->brush;
1265 const Scene &scene = *CTX_data_scene(C);
1266 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1267
1268 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1270 scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1271 const bool use_normal = vwpaint::use_normal(vp);
1272 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1273 0;
1274 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1275
1276 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1277 ss, brush.falloff_shape);
1278
1279 GMutableSpan g_previous_color = vpd.prev_colors;
1280
1281 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1282 const OffsetIndices faces = mesh.faces();
1283 const Span<int> corner_verts = mesh.corner_verts();
1284 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1285 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1286 const bke::AttributeAccessor attributes = mesh.attributes();
1287 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1288 VArraySpan<bool> select_vert;
1289 if (use_vert_sel) {
1290 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1291 }
1292 VArraySpan<bool> select_poly;
1293 if (use_face_sel) {
1294 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1295 }
1296
1297 struct LocalData {
1298 Vector<float> factors;
1299 Vector<float> distances;
1300 };
1302 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1303 LocalData &tls = all_tls.local();
1304 const Span<int> verts = nodes[i].verts();
1305 tls.factors.resize(verts.size());
1306 const MutableSpan<float> factors = tls.factors;
1307 fill_factor_from_hide(hide_vert, verts, factors);
1308 filter_region_clip_factors(ss, vert_positions, verts, factors);
1309 if (!select_vert.is_empty()) {
1310 filter_factors_with_selection(select_vert, verts, factors);
1311 }
1312
1313 tls.distances.resize(verts.size());
1314 const MutableSpan<float> distances = tls.distances;
1316 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1317 filter_distances_with_radius(cache.radius, distances, factors);
1318 calc_brush_strength_factors(cache, brush, distances, factors);
1319
1320 for (const int i : verts.index_range()) {
1321 const int vert = verts[i];
1322 if (factors[i] == 0.0f) {
1323 continue;
1324 }
1325
1326 float brush_strength = cache.bstrength;
1327 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1328 1.0f;
1330 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1331 {
1332 continue;
1333 }
1334 const float brush_fade = factors[i];
1335
1336 /* Get the average face color */
1337 to_static_color_type(vpd.type, [&](auto dummy) {
1338 using T = decltype(dummy);
1339 using Color =
1340 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1341 using Traits = blender::color::Traits<Color>;
1342 using Blend = typename Traits::BlendType;
1343 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1344 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1345 Color color_final(0, 0, 0, 0);
1346
1347 int total_hit_loops = 0;
1348 Blend blend[4] = {0};
1349
1350 for (const int face : vert_to_face[vert]) {
1351 if (!select_poly.is_empty() && !select_poly[face]) {
1352 continue;
1353 }
1354 total_hit_loops += faces[face].size();
1355 for (const int vert : corner_verts.slice(faces[face])) {
1356 const Color &col = colors[vert];
1357
1358 /* Color is squared to compensate the `sqrt` color encoding. */
1359 blend[0] += (Blend)col.r * (Blend)col.r;
1360 blend[1] += (Blend)col.g * (Blend)col.g;
1361 blend[2] += (Blend)col.b * (Blend)col.b;
1362 blend[3] += (Blend)col.a * (Blend)col.a;
1363 }
1364 }
1365
1366 if (total_hit_loops == 0) {
1367 return;
1368 }
1369 /* Use rgb^2 color averaging. */
1370 color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
1371 color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
1372 color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
1373 color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
1374
1375 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1376
1377 if (!previous_color.is_empty()) {
1378 /* Get the previous loop color */
1379 if (isZero(previous_color[vert])) {
1380 previous_color[vert] = colors[vert];
1381 }
1382 color_orig = previous_color[vert];
1383 }
1384 const float final_alpha = Traits::range * brush_fade * brush_strength *
1385 brush_alpha_pressure;
1386 /* Mix the new color with the original
1387 * based on the brush strength and the curve. */
1388 colors[vert] = vpaint_blend<Color, Traits>(vp,
1389 colors[vert],
1390 color_orig,
1391 color_final,
1392 final_alpha,
1393 Traits::range * brush_strength);
1394 });
1395 }
1396 });
1397}
1398
1400 const VPaint &vp,
1401 VPaintData &vpd,
1402 Object &ob,
1403 Mesh &mesh,
1405 const IndexMask &node_mask,
1406 GMutableSpan attribute)
1407{
1408 SculptSession &ss = *ob.sculpt;
1409 StrokeCache &cache = *ss.cache;
1410 if (!cache.is_last_valid) {
1411 return;
1412 }
1413
1414 const Brush &brush = *cache.brush;
1415 const Scene &scene = *CTX_data_scene(C);
1416 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1417 GMutableSpan g_color_curr = vpd.smear.color_curr;
1418 GMutableSpan g_color_prev_smear = vpd.smear.color_prev;
1419 GMutableSpan g_color_prev = vpd.prev_colors;
1420
1421 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1422
1424 scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1425 const bool use_normal = vwpaint::use_normal(vp);
1426 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1427 0;
1428 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1429
1430 float brush_dir[3];
1431 sub_v3_v3v3(brush_dir, cache.location_symm, cache.last_location_symm);
1432 project_plane_v3_v3v3(brush_dir, brush_dir, cache.view_normal_symm);
1433 if (normalize_v3(brush_dir) == 0.0f) {
1434 return;
1435 }
1436
1437 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1438 ss, brush.falloff_shape);
1439
1440 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1441 const OffsetIndices faces = mesh.faces();
1442 const Span<int> corner_verts = mesh.corner_verts();
1443 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1444 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1445 const bke::AttributeAccessor attributes = mesh.attributes();
1446 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1447 VArraySpan<bool> select_vert;
1448 if (use_vert_sel) {
1449 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1450 }
1451 VArraySpan<bool> select_poly;
1452 if (use_face_sel) {
1453 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1454 }
1455
1456 struct LocalData {
1457 Vector<float> factors;
1458 Vector<float> distances;
1459 };
1461 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1462 LocalData &tls = all_tls.local();
1463 const Span<int> verts = nodes[i].verts();
1464 tls.factors.resize(verts.size());
1465 const MutableSpan<float> factors = tls.factors;
1466 fill_factor_from_hide(hide_vert, verts, factors);
1467 filter_region_clip_factors(ss, vert_positions, verts, factors);
1468 if (!select_vert.is_empty()) {
1469 filter_factors_with_selection(select_vert, verts, factors);
1470 }
1471
1472 tls.distances.resize(verts.size());
1473 const MutableSpan<float> distances = tls.distances;
1475 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1476 filter_distances_with_radius(cache.radius, distances, factors);
1477 calc_brush_strength_factors(cache, brush, distances, factors);
1478
1479 for (const int i : verts.index_range()) {
1480 const int vert = verts[i];
1481 if (factors[i] == 0.0f) {
1482 continue;
1483 }
1484
1485 /* Calculate the dot prod. between ray norm on surf and current vert
1486 * (ie splash prevention factor), and only paint front facing verts. */
1487 float brush_strength = cache.bstrength;
1488 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1489 1.0f;
1491 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1492 {
1493 continue;
1494 }
1495 const float brush_fade = factors[i];
1496
1497 bool do_color = false;
1498 /* Minimum dot product between brush direction and current
1499 * to neighbor direction is 0.0, meaning orthogonal. */
1500 float stroke_dot_max = 0.0f;
1501
1502 /* Get the color of the loop in the opposite
1503 * direction of the brush movement */
1504 to_static_color_type(vpd.type, [&](auto dummy) {
1505 using T = decltype(dummy);
1506 using Color =
1507 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1508 using Traits = blender::color::Traits<Color>;
1509 MutableSpan<Color> color_curr = g_color_curr.typed<T>().template cast<Color>();
1510 MutableSpan<Color> color_prev_smear = g_color_prev_smear.typed<T>().template cast<Color>();
1511 MutableSpan<Color> color_prev = g_color_prev.typed<T>().template cast<Color>();
1512 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1513
1514 Color color_final(0, 0, 0, 0);
1515
1516 for (const int face : vert_to_face[vert]) {
1517 if (!select_poly.is_empty() && !select_poly[face]) {
1518 continue;
1519 }
1520 for (const int corner : faces[face]) {
1521 const int v_other_index = corner_verts[corner];
1522 if (v_other_index == vert) {
1523 continue;
1524 }
1525
1526 /* Get the direction from the
1527 * selected vert to the neighbor. */
1528 float other_dir[3];
1529 sub_v3_v3v3(other_dir, vert_positions[vert], vert_positions[v_other_index]);
1530 project_plane_v3_v3v3(other_dir, other_dir, cache.view_normal_symm);
1531
1532 normalize_v3(other_dir);
1533
1534 const float stroke_dot = dot_v3v3(other_dir, brush_dir);
1535 int elem_index;
1536
1537 if (vpd.domain == AttrDomain::Point) {
1538 elem_index = v_other_index;
1539 }
1540 else {
1541 elem_index = corner;
1542 }
1543
1544 if (stroke_dot > stroke_dot_max) {
1545 stroke_dot_max = stroke_dot;
1546 color_final = color_prev_smear[elem_index];
1547 do_color = true;
1548 }
1549 }
1550 }
1551
1552 if (!do_color) {
1553 return;
1554 }
1555
1556 const float final_alpha = Traits::range * brush_fade * brush_strength *
1557 brush_alpha_pressure;
1558
1559 /* For each face owning this vert,
1560 * paint each loop belonging to this vert. */
1561 for (const int face : vert_to_face[vert]) {
1562
1563 int elem_index;
1564 if (vpd.domain == AttrDomain::Point) {
1565 elem_index = vert;
1566 }
1567 else {
1568 elem_index = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
1569 }
1570 if (!select_poly.is_empty() && !select_poly[face]) {
1571 continue;
1572 }
1573
1574 /* Get the previous element color */
1575 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1576
1577 if (!color_prev.is_empty()) {
1578 /* Get the previous element color */
1579 if (isZero(color_prev[elem_index])) {
1580 color_prev[elem_index] = colors[elem_index];
1581 }
1582 color_orig = color_prev[elem_index];
1583 }
1584 /* Mix the new color with the original
1585 * based on the brush strength and the curve. */
1586 colors[elem_index] = vpaint_blend<Color, Traits>(vp,
1587 colors[elem_index],
1588 color_orig,
1589 color_final,
1590 final_alpha,
1591 Traits::range * brush_strength);
1592
1593 color_curr[elem_index] = colors[elem_index];
1594 }
1595 });
1596 }
1597 });
1598}
1599
1601 Object &ob,
1602 Mesh &mesh,
1603 const Brush &brush,
1604 const GSpan attribute,
1606 const IndexMask &node_mask)
1607{
1608 SculptSession &ss = *ob.sculpt;
1609 const StrokeCache &cache = *ss.cache;
1610 const Depsgraph &depsgraph = *vpd.vc.depsgraph;
1611
1612 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1613 0;
1614
1615 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1616 const OffsetIndices faces = mesh.faces();
1617 const Span<int> corner_verts = mesh.corner_verts();
1618 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1619 const bke::AttributeAccessor attributes = mesh.attributes();
1620 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1621 VArraySpan<bool> select_vert;
1622 if (use_vert_sel) {
1623 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1624 }
1625
1626 struct LocalData {
1627 Vector<float> factors;
1628 Vector<float> distances;
1629 };
1631 to_static_color_type(vpd.type, [&](auto dummy) {
1632 using T = decltype(dummy);
1633 using Color =
1634 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1635 using Traits = blender::color::Traits<Color>;
1636 using Blend = typename Traits::BlendType;
1637 const Span<Color> colors = attribute.typed<T>().template cast<Color>();
1638
1639 Array<VPaintAverageAccum<Blend>> accum(nodes.size(), {0, {0, 0, 0}});
1640 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1641 VPaintAverageAccum<Blend> &accum2 = accum[i];
1642 LocalData &tls = all_tls.local();
1643
1644 const Span<int> verts = nodes[i].verts();
1645 tls.factors.resize(verts.size());
1646 const MutableSpan<float> factors = tls.factors;
1647 fill_factor_from_hide(hide_vert, verts, factors);
1648 filter_region_clip_factors(ss, vert_positions, verts, factors);
1649 if (!select_vert.is_empty()) {
1650 filter_factors_with_selection(select_vert, verts, factors);
1651 }
1652
1653 tls.distances.resize(verts.size());
1654 const MutableSpan<float> distances = tls.distances;
1656 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1657 filter_distances_with_radius(cache.radius, distances, factors);
1658 calc_brush_strength_factors(cache, brush, distances, factors);
1659
1660 for (const int i : verts.index_range()) {
1661 const int vert = verts[i];
1662 if (factors[i] == 0.0f) {
1663 continue;
1664 }
1665
1666 accum2.len += vert_to_face[vert].size();
1667 /* if a vertex is within the brush region, then add its color to the blend. */
1668 for (const int face : vert_to_face[vert]) {
1669 int elem_index;
1670 if (vpd.domain == AttrDomain::Corner) {
1671 elem_index = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
1672 }
1673 else {
1674 elem_index = vert;
1675 }
1676
1677 /* Color is squared to compensate the `sqrt` color encoding. */
1678 const Color &col = colors[elem_index];
1679 accum2.value[0] += col.r * col.r;
1680 accum2.value[1] += col.g * col.g;
1681 accum2.value[2] += col.b * col.b;
1682 }
1683 }
1684 });
1685
1686 Blend accum_len = 0;
1687 Blend accum_value[3] = {0};
1688 Color blend(0, 0, 0, 0);
1689
1690 node_mask.foreach_index([&](const int i) {
1691 accum_len += accum[i].len;
1692 accum_value[0] += accum[i].value[0];
1693 accum_value[1] += accum[i].value[1];
1694 accum_value[2] += accum[i].value[2];
1695 });
1696 if (accum_len != 0) {
1697 blend.r = Traits::round(sqrtf(Traits::divide_round(accum_value[0], accum_len)));
1698 blend.g = Traits::round(sqrtf(Traits::divide_round(accum_value[1], accum_len)));
1699 blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len)));
1700 blend.a = Traits::range;
1701
1702 vpd.paintcol = toFloat(blend);
1703 }
1704 });
1705}
1706
1707template<typename Color>
1708static float paint_and_tex_color_alpha(const VPaint &vp,
1709 VPaintData &vpd,
1710 const float v_co[3],
1711 Color *r_color)
1712{
1713 ColorPaint4f rgba;
1714 paint_and_tex_color_alpha_intern(vp, &vpd.vc, v_co, &rgba.r);
1715
1716 ColorPaint4f rgba_br = toFloat(vpd.paintcol);
1717 mul_v3_v3(rgba_br, rgba);
1718
1719 *r_color = fromFloat<Color>(rgba_br);
1720 return rgba[3];
1721}
1722
1723/* Compute brush color, using jitter if it's enabled */
1725 const Brush *brush,
1726 const Paint *paint,
1727 const StrokeCache &cache,
1728 const ColorPaint4f &paint_color)
1729{
1730 blender::float3 brush_color = blender::float3(paint_color.r, paint_color.g, paint_color.b);
1731 const std::optional<BrushColorJitterSettings> color_jitter_settings =
1733 if (color_jitter_settings) {
1734 brush_color = BKE_paint_randomize_color(*color_jitter_settings,
1735 *cache.initial_hsv_jitter,
1736 cache.stroke_distance,
1737 cache.pressure,
1738 brush_color);
1739 }
1740 return brush_color;
1741}
1742
1743static void vpaint_do_draw(const bContext *C,
1744 const VPaint &vp,
1745 VPaintData &vpd,
1746 Object &ob,
1747 Mesh &mesh,
1749 const IndexMask &node_mask,
1750 GMutableSpan attribute)
1751{
1752 SculptSession &ss = *ob.sculpt;
1753 const StrokeCache &cache = *ss.cache;
1754 const Brush &brush = *ob.sculpt->cache->brush;
1755 const Scene &scene = *CTX_data_scene(C);
1756 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1757
1758 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1760 scene, ss, 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(
1789 &scene, &brush, &vp.paint, cache, vpd.paintcol);
1790
1791 struct LocalData {
1792 Vector<float> factors;
1793 Vector<float> distances;
1794 };
1796 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1797 LocalData &tls = all_tls.local();
1798 const Span<int> verts = nodes[i].verts();
1799 tls.factors.resize(verts.size());
1800 const MutableSpan<float> factors = tls.factors;
1801 fill_factor_from_hide(hide_vert, verts, factors);
1802 filter_region_clip_factors(ss, vert_positions, verts, factors);
1803 if (!select_vert.is_empty()) {
1804 filter_factors_with_selection(select_vert, verts, factors);
1805 }
1806
1807 tls.distances.resize(verts.size());
1808 const MutableSpan<float> distances = tls.distances;
1810 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1811 filter_distances_with_radius(cache.radius, distances, factors);
1812 calc_brush_strength_factors(cache, brush, distances, factors);
1813
1814 for (const int i : verts.index_range()) {
1815 const int vert = verts[i];
1816 if (factors[i] == 0.0f) {
1817 continue;
1818 }
1819
1820 /* Calculate the dot product between ray normal on surface and current vertex
1821 * (ie splash prevention factor), and only paint front facing verts. */
1822 float brush_strength = cache.bstrength;
1823 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1824 1.0f;
1826 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1827 {
1828 continue;
1829 }
1830 const float brush_fade = factors[i];
1831
1832 to_static_color_type(vpd.type, [&](auto dummy) {
1833 using T = decltype(dummy);
1834 using Color =
1835 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1836 using Traits = blender::color::Traits<Color>;
1837 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1838 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1839 MutableSpan<Color> stroke_buffer = g_stroke_buffer.typed<T>().template cast<Color>();
1840
1841 Color color_final = fromFloat<Color>(
1842 ColorPaint4f(brush_color[0], brush_color[1], brush_color[2], 1.0));
1843
1844 /* If we're painting with a texture, sample the texture color and alpha. */
1845 float tex_alpha = 1.0;
1846 if (vpd.is_texbrush) {
1847 /* NOTE: we may want to paint alpha as vertex color alpha. */
1848
1849 /* If the active area is being applied for symmetry, flip it
1850 * across the symmetry axis and rotate it back to the original
1851 * position in order to project it. This ensures that the
1852 * brush texture will be oriented correctly.
1853 * This is the method also used in #sculpt_apply_texture(). */
1854 float3 position = vpd.vert_positions[vert];
1855 if (cache.radial_symmetry_pass) {
1856 position = blender::math::transform_point(cache.symm_rot_mat_inv, position);
1857 }
1858 const float3 symm_point = blender::ed::sculpt_paint::symmetry_flip(
1859 position, cache.mirror_symmetry_pass);
1860
1861 tex_alpha = paint_and_tex_color_alpha<Color>(vp, vpd, symm_point, &color_final);
1862 }
1863
1864 const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha *
1865 brush_alpha_pressure;
1866
1867 if (vpd.domain == AttrDomain::Point) {
1868 colors[vert] = vpaint_blend_stroke<Color, Traits>(vp,
1869 previous_color,
1870 colors,
1871 stroke_buffer,
1872 color_final,
1873 final_alpha,
1874 brush_strength,
1875 vert);
1876 }
1877 else {
1878 /* For each face owning this vert, paint each loop belonging to this vert. */
1879 for (const int face : vert_to_face[vert]) {
1880 const int corner = bke::mesh::face_find_corner_from_vert(
1881 faces[face], corner_verts, vert);
1882 if (!select_poly.is_empty() && !select_poly[face]) {
1883 continue;
1884 }
1885 colors[corner] = vpaint_blend_stroke<Color, Traits>(vp,
1886 previous_color,
1887 colors,
1888 stroke_buffer,
1889 color_final,
1890 final_alpha,
1891 brush_strength,
1892 corner);
1893 }
1894 }
1895 });
1896 }
1897 });
1898}
1899
1900static void vpaint_do_blur(const bContext *C,
1901 const VPaint &vp,
1902 VPaintData &vpd,
1903 Object &ob,
1904 Mesh &mesh,
1906 const IndexMask &node_mask,
1907 GMutableSpan attribute)
1908{
1909 if (vpd.domain == AttrDomain::Point) {
1910 do_vpaint_brush_blur_verts(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1911 }
1912 else {
1913 do_vpaint_brush_blur_loops(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1914 }
1915}
1916
1918 const VPaint &vp,
1919 VPaintData &vpd,
1920 Object &ob,
1921 Mesh &mesh,
1922 GMutableSpan attribute,
1924 const IndexMask &node_mask)
1925{
1926 const Brush &brush = *ob.sculpt->cache->brush;
1927
1930 calculate_average_color(vpd, ob, mesh, brush, attribute, nodes, node_mask);
1931 vpaint_do_draw(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1932 break;
1934 vpaint_do_draw(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1935 break;
1937 vpaint_do_blur(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1938 break;
1940 do_vpaint_brush_smear(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1941 break;
1942 }
1943}
1944
1946 const VPaint &vp,
1947 VPaintData &vpd,
1948 Object &ob,
1949 Mesh &mesh,
1950 const Brush &brush,
1951 const ePaintSymmetryFlags symm,
1952 const int axis,
1953 const int i,
1954 const float angle)
1955{
1956 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1957 SculptSession &ss = *ob.sculpt;
1960
1961 IndexMaskMemory memory;
1962 const IndexMask node_mask = vwpaint::pbvh_gather_generic(depsgraph, ob, vp, brush, memory);
1963
1964 bke::GSpanAttributeWriter attribute = mesh.attributes_for_write().lookup_for_write_span(
1965 mesh.active_color_attribute);
1966 BLI_assert(attribute.domain == vpd.domain);
1967
1968 /* Paint those leaves. */
1970 vp,
1971 vpd,
1972 ob,
1973 mesh,
1974 attribute.span,
1976 node_mask);
1977
1978 attribute.finish();
1979}
1980
1982 const VPaint &vp,
1983 VPaintData &vpd,
1984 Object &ob,
1985 Mesh &mesh,
1986 const Brush &brush,
1987 const ePaintSymmetryFlags symm,
1988 const int axis)
1989{
1990 for (int i = 1; i < vp.radial_symm[axis - 'X']; i++) {
1991 const float angle = (2.0 * M_PI) * i / vp.radial_symm[axis - 'X'];
1992 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm, axis, i, angle);
1993 }
1994}
1995
1996/* near duplicate of: sculpt.cc's,
1997 * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
1999 const VPaint &vp,
2000 VPaintData &vpd,
2001 Object &ob)
2002{
2003 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
2004 Mesh &mesh = *(Mesh *)ob.data;
2005 SculptSession &ss = *ob.sculpt;
2006 StrokeCache &cache = *ss.cache;
2007 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
2008 int i = 0;
2009
2010 /* initial stroke */
2011 const ePaintSymmetryFlags initial_symm = ePaintSymmetryFlags(0);
2013 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, initial_symm, 'X', 0, 0);
2014 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'X');
2015 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Y');
2016 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Z');
2017
2018 cache.symmetry = symm;
2019
2020 for (i = 1; i <= symm; i++) {
2021 if (is_symmetry_iteration_valid(i, symm)) {
2022 const ePaintSymmetryFlags symm_pass = ePaintSymmetryFlags(i);
2023 cache.mirror_symmetry_pass = symm_pass;
2024 cache.radial_symmetry_pass = 0;
2025 SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0);
2026
2027 if (i & (1 << 0)) {
2028 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'X', 0, 0);
2029 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'X');
2030 }
2031 if (i & (1 << 1)) {
2032 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y', 0, 0);
2033 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y');
2034 }
2035 if (i & (1 << 2)) {
2036 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z', 0, 0);
2037 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z');
2038 }
2039 }
2040 }
2041
2042 copy_v3_v3(cache.last_location, cache.location);
2043 cache.is_last_valid = true;
2044}
2045
2047 wmOperator * /*op*/,
2048 PaintStroke *stroke,
2049 PointerRNA *itemptr)
2050{
2051 Scene &scene = *CTX_data_scene(C);
2053 VPaintData &vpd = *static_cast<VPaintData *>(paint_stroke_mode_data(stroke));
2054 VPaint &vp = *ts->vpaint;
2055 ViewContext &vc = vpd.vc;
2056 Object &ob = *vc.obact;
2057 SculptSession &ss = *ob.sculpt;
2058
2060
2061 vwpaint::update_cache_variants(C, vp, ob, itemptr);
2062
2063 float mat[4][4];
2064
2066
2067 mul_m4_m4m4(mat, vc.rv3d->persmat, ob.object_to_world().ptr());
2068
2069 swap_m4m4(vc.rv3d->persmat, mat);
2070
2072
2073 swap_m4m4(vc.rv3d->persmat, mat);
2074
2076
2077 Brush &brush = *BKE_paint_brush(&vp.paint);
2079 vpd.smear.color_prev = vpd.smear.color_curr;
2080 }
2081
2082 /* Calculate pivot for rotation around selection if needed.
2083 * also needed for "Frame Selected" on last stroke. */
2084 float loc_world[3];
2085 mul_v3_m4v3(loc_world, ob.object_to_world().ptr(), ss.cache->location);
2086 vwpaint::last_stroke_update(scene, loc_world);
2087
2089
2091}
2092
2093static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke)
2094{
2095 VPaintData *vpd = static_cast<VPaintData *>(paint_stroke_mode_data(stroke));
2096 Object &ob = *vpd->vc.obact;
2097
2098 SculptSession &ss = *ob.sculpt;
2099
2100 if (ss.cache && ss.cache->alt_smooth) {
2102 VPaint &vp = *ts->vpaint;
2104 }
2105
2107
2108 MEM_delete(ob.sculpt->cache);
2109 ob.sculpt->cache = nullptr;
2110}
2111
2113{
2115 op,
2119 nullptr,
2121 event->type);
2122
2123 const wmOperatorStatus retval = op->type->modal(C, op, event);
2124 OPERATOR_RETVAL_CHECK(retval);
2125
2126 if (retval == OPERATOR_FINISHED) {
2128 return OPERATOR_FINISHED;
2129 }
2130
2132
2134
2136}
2137
2139{
2141 op,
2145 nullptr,
2147 0);
2148
2150
2151 return OPERATOR_FINISHED;
2152}
2153
2155{
2157 MEM_delete(ob.sculpt->cache);
2158 ob.sculpt->cache = nullptr;
2159
2161}
2162
2164{
2165 return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
2166}
2167
2169{
2170 ot->name = "Vertex Paint";
2171 ot->idname = "PAINT_OT_vertex_paint";
2172 ot->description = "Paint a stroke in the active color attribute layer";
2173
2174 ot->invoke = vpaint_invoke;
2175 ot->modal = vpaint_modal;
2176 ot->exec = vpaint_exec;
2177 ot->poll = vertex_paint_poll;
2178 ot->cancel = vpaint_cancel;
2179
2180 ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
2181
2184 ot->srna,
2185 "override_location",
2186 false,
2187 "Override Location",
2188 "Override the given `location` array by recalculating object space positions from the "
2189 "provided `mouse_event` positions");
2191}
2192
2194
2195/* -------------------------------------------------------------------- */
2198
2199namespace blender::ed::sculpt_paint {
2200
2201template<typename T>
2203 const T &value,
2204 const AttrDomain domain,
2205 const int cd_offset,
2206 const bool use_vert_sel)
2207{
2208 BMFace *f;
2209 BMIter iter;
2210 BM_ITER_MESH (f, &iter, &bm, BM_FACES_OF_MESH) {
2211 BMLoop *l = f->l_first;
2212 do {
2213 if (!(use_vert_sel && !BM_elem_flag_test(l->v, BM_ELEM_SELECT))) {
2214 if (domain == AttrDomain::Corner) {
2215 *static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset)) = value;
2216 }
2217 else if (domain == AttrDomain::Point) {
2218 *static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset)) = value;
2219 }
2220 }
2221 } while ((l = l->next) != f->l_first);
2222 }
2223}
2224
2225template<typename T>
2227 const T &value,
2228 const AttrDomain domain,
2229 const MutableSpan<T> data,
2230 const bool use_vert_sel,
2231 const bool use_face_sel,
2232 const bool affect_alpha)
2233{
2234 const bke::AttributeAccessor attributes = mesh.attributes();
2235 VArraySpan<bool> select_vert;
2236 if (use_vert_sel) {
2237 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
2238 }
2239 VArraySpan<bool> select_poly;
2240 if (use_face_sel) {
2241 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
2242 }
2243
2244 const OffsetIndices faces = mesh.faces();
2245 const Span<int> corner_verts = mesh.corner_verts();
2246
2247 for (const int i : faces.index_range()) {
2248 if (!select_poly.is_empty() && !select_poly[i]) {
2249 continue;
2250 }
2251 for (const int corner : faces[i]) {
2252 const int vert = corner_verts[corner];
2253 if (!select_vert.is_empty() && !select_vert[vert]) {
2254 continue;
2255 }
2256 const int data_index = domain == AttrDomain::Corner ? corner : vert;
2257 data[data_index].r = value.r;
2258 data[data_index].g = value.g;
2259 data[data_index].b = value.b;
2260 if (affect_alpha) {
2261 data[data_index].a = value.a;
2262 }
2263 }
2264 }
2265
2267}
2268
2270 const ColorPaint4f &color,
2271 const StringRef attribute_name,
2272 const bool use_vert_sel,
2273 const bool use_face_sel,
2274 const bool affect_alpha)
2275{
2276 if (BMEditMesh *em = mesh.runtime->edit_mesh.get()) {
2277 BMesh *bm = em->bm;
2278 const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh.id, attribute_name);
2280 const AttrDomain domain = BKE_attribute_domain(owner, layer);
2281 if (layer->type == CD_PROP_COLOR) {
2283 *bm, color, domain, layer->offset, use_vert_sel);
2284 }
2285 else if (layer->type == CD_PROP_BYTE_COLOR) {
2287 *bm, color.encode(), domain, layer->offset, use_vert_sel);
2288 }
2289 }
2290 else {
2291 bke::GSpanAttributeWriter attribute = mesh.attributes_for_write().lookup_for_write_span(
2292 attribute_name);
2293 if (attribute.span.type().is<ColorGeometry4f>()) {
2295 mesh,
2296 color,
2297 attribute.domain,
2298 attribute.span.typed<ColorGeometry4f>().cast<ColorPaint4f>(),
2299 use_vert_sel,
2300 use_face_sel,
2301 affect_alpha);
2302 }
2303 else if (attribute.span.type().is<ColorGeometry4b>()) {
2305 mesh,
2306 color.encode(),
2307 attribute.domain,
2308 attribute.span.typed<ColorGeometry4b>().cast<ColorPaint4b>(),
2309 use_vert_sel,
2310 use_face_sel,
2311 affect_alpha);
2312 }
2313 attribute.finish();
2314 }
2315}
2316
2318 ColorPaint4f fill_color,
2319 bool only_selected = true,
2320 bool affect_alpha = true)
2321{
2323 if (!mesh) {
2324 return false;
2325 }
2326
2327 const bool use_face_sel = only_selected ? (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) != 0 : false;
2328 const bool use_vert_sel = only_selected ? (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) != 0 : false;
2330 *mesh, fill_color, mesh->active_color_attribute, use_vert_sel, use_face_sel, affect_alpha);
2331
2333
2334 /* NOTE: Original mesh is used for display, so tag it directly here. */
2336
2337 return true;
2338}
2339
2340bool object_active_color_fill(Object &ob, const float fill_color[4], bool only_selected)
2341{
2342 return fill_active_color(ob, ColorPaint4f(fill_color), only_selected);
2343}
2344
2345} // namespace blender::ed::sculpt_paint
2346
2348{
2349 using namespace blender::ed::sculpt_paint;
2350 Scene &scene = *CTX_data_scene(C);
2351 Object &obact = *CTX_data_active_object(C);
2352 if (!BKE_mesh_from_object(&obact)) {
2353 return OPERATOR_CANCELLED;
2354 }
2355
2356 ColorPaint4f paintcol = vpaint_get_current_col(scene, *scene.toolsettings->vpaint, false);
2357 const bool affect_alpha = RNA_boolean_get(op->ptr, "use_alpha");
2358
2359 /* Ensure valid sculpt state. */
2361
2362 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(obact);
2363
2364 IndexMaskMemory memory;
2365 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
2366
2367 Mesh &mesh = *static_cast<Mesh *>(obact.data);
2368
2369 fill_active_color(obact, paintcol, true, affect_alpha);
2370
2371 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
2372
2374 return OPERATOR_FINISHED;
2375}
2376
2378{
2379 ot->name = "Set Vertex Colors";
2380 ot->idname = "PAINT_OT_vertex_color_set";
2381 ot->description = "Fill the active vertex color layer with the current paint color";
2382
2383 ot->exec = vertex_color_set_exec;
2384 ot->poll = vertex_paint_mode_poll;
2385
2386 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2387
2388 RNA_def_boolean(ot->srna,
2389 "use_alpha",
2390 true,
2391 "Affect Alpha",
2392 "Set color completely opaque instead of reusing existing alpha");
2393}
2394
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:1231
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1210
void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
Definition brush.cc:1236
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
Definition brush.cc:1194
float BKE_brush_sample_tex_3d(const Scene *scene, const Brush *br, const MTex *mtex, const float point[3], float rgba[4], int thread, ImagePool *pool)
Definition brush.cc:877
const float * BKE_brush_secondary_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1172
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1226
const std::optional< BrushColorJitterSettings > BKE_brush_color_jitter_get_settings(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1137
float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1269
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1128
const MTex * BKE_brush_mask_texture_get(const Brush *brush, eObjectMode object_mode)
Definition brush.cc:861
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:1045
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:1089
PaintMode
Definition BKE_paint.hh:93
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:1853
bool BKE_paint_brush_set(Paint *paint, Brush *brush)
Definition paint.cc:701
void BKE_sculptsession_free(Object *ob)
Definition paint.cc:2192
const uchar PAINT_CURSOR_WEIGHT_PAINT[3]
Definition paint.cc:242
blender::float3 seed_hsv_jitter()
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:641
Paint * BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
Definition paint.cc:365
void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3], bool ensure_brushes=true)
Definition paint.cc:1769
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2657
bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
Definition paint.cc:1675
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:636
void BKE_sculpt_toolsettings_data_ensure(Main *bmain, Scene *scene)
Definition paint.cc:2744
const uchar PAINT_CURSOR_VERTEX_PAINT[3]
Definition paint.cc:241
void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
Definition paint.cc:1109
#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(...)
float[4] Color
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ 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:424
void ED_mesh_mirror_topo_table_end(Object *ob)
Definition meshtools.cc:867
void ED_mesh_mirror_spatial_table_end(Object *ob)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
@ 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
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
IMB_BlendMode
Definition IMB_imbuf.hh:185
@ IMB_BLEND_ERASE_ALPHA
Definition IMB_imbuf.hh:192
@ IMB_BLEND_ADD_ALPHA
Definition IMB_imbuf.hh:193
@ IMB_BLEND_MIX
Definition IMB_imbuf.hh:186
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
#define ND_DRAW
Definition WM_types.hh:458
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_MODE
Definition WM_types.hh:442
#define NC_SCENE
Definition WM_types.hh:375
#define NC_OBJECT
Definition WM_types.hh:376
for(;discarded_id_iter !=nullptr;discarded_id_iter=static_cast< ID * >(discarded_id_iter->next))
Definition blendfile.cc:634
@ 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:245
const T * data() const
Definition BLI_array.hh:301
bool is_empty() const
Definition BLI_array.hh:253
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
bool is() const
void value_initialize_n(void *ptr, int64_t n) const
ChannelStorageType r
Definition BLI_color.hh:93
ChannelStorageType g
Definition BLI_color.hh:93
ChannelStorageType b
Definition BLI_color.hh:93
ChannelStorageType a
Definition BLI_color.hh:93
ColorSceneLinearByteEncoded4b< Alpha > encode() const
Definition BLI_color.hh:168
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:600
void foreach_index(Fn &&fn) const
#define cosf(x)
#define acosf(x)
#define sqrtf(x)
static float verts[][3]
uint col
#define MEM_SAFE_FREE(v)
#define ID_IS_EDITABLE(_id)
#define LOG(severity)
Definition log.h:32
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:311
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2579
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2544
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2435
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2416
void mesh_select_vert_flush(Mesh &mesh)
void mesh_select_face_flush(Mesh &mesh)
BLI_INLINE Color BLI_mix_colors(const IMB_BlendMode tool, const Color a, const Color b, const typename Traits::BlendType alpha)
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)
void get_brush_alpha_data(const Scene &scene, const SculptSession &ss, const Brush &brush, float *r_brush_size_pressure, float *r_brush_alpha_value, float *r_brush_alpha_pressure)
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)
void init_session_data(const ToolSettings &ts, Object &ob)
bool test_brush_angle_falloff(const Brush &brush, const NormalAnglePrecalc &normal_angle_precalc, const float angle_cos, float *brush_strength)
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 smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
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)
IndexMask pbvh_gather_generic(const Depsgraph &depsgraph, const Object &ob, const VPaint &wp, const Brush &brush, IndexMaskMemory &memory)
void init_session(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, eObjectMode object_mode)
void last_stroke_update(Scene &scene, const float location[3])
bool stroke_get_location_bvh(bContext *C, float out[3], const float mval[2], const bool force_original)
Definition sculpt.cc:4919
bool node_in_sphere(const bke::pbvh::Node &node, const float3 &location, const float radius_sq, const bool original)
Definition sculpt.cc:2410
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:2420
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7167
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:7089
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:6956
void paint_stroke_cancel(bContext *C, wmOperator *op, PaintStroke *stroke)
bool paint_supports_dynamic_size(const Brush &br, PaintMode mode)
void ensure_valid_pivot(const Object &ob, Scene &scene)
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:7039
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1814
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:6759
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
Definition BLI_color.hh:345
ColorSceneLinear4f< eAlpha::Straight > ColorPaint4f
Definition BLI_color.hh:344
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
Definition BLI_color.hh:343
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 void to_static_color_type(const eCustomDataType type, const Func &func)
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 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)
static ColorPaint4f vpaint_get_current_col(Scene &scene, VPaint &vp, bool secondary)
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)
static blender::float3 get_brush_color(const Scene *scene, const Brush *brush, const Paint *paint, const StrokeCache &cache, const ColorPaint4f &paint_color)
void ED_object_vpaintmode_exit_ex(Object &ob)
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 eCustomDataType type, const Brush &brush)
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 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 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])
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:185
const float * SCULPT_brush_frontface_normal_from_falloff_shape(const SculptSession &ss, char falloff_shape)
Definition sculpt.cc:1181
void SCULPT_cache_calc_brushdata_symm(blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis, const float angle)
Definition sculpt.cc:3446
static float brush_strength(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const float feather, const UnifiedPaintSettings &ups, const PaintModeSettings &)
Definition sculpt.cc:2157
BMLoop * l_first
float falloff_angle
struct MTex mtex
struct CurveMapping * curve
char falloff_shape
short blend
char weight_brush_type
char vertex_brush_type
Definition DNA_ID.h:404
char brush_map_mode
struct Tex * tex
ObjectRuntimeHandle * runtime
struct SculptSession * sculpt
unsigned short ob_mode
struct Paint_Runtime runtime
float persmat[4][4]
float viewinv[4][4]
struct ToolSettings * toolsettings
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:437
blender::Array< MDeformVert > dvert_prev
Definition BKE_paint.hh:505
struct SculptSession::@277147341176372332050050347244236340077143206264 mode
float * alpha_weight
Definition BKE_paint.hh:501
eObjectMode mode_type
Definition BKE_paint.hh:511
struct SculptSession::@277147341176372332050050347244236340077143206264::@267002172247257132177045334232116313020165177372 wpaint
bool building_vp_handle
Definition BKE_paint.hh:515
struct UnifiedPaintSettings unified_paint_settings
AttrDomain domain
Span< float3 > vert_positions
Span< float3 > vert_normals
GArray color_curr
VertProjHandle * vp_handle
GArray color_prev
eCustomDataType type
struct VPaintData::@256174170253011351272116003037302224310107061335 smear
ColorPaint4f paintcol
GArray stroke_buffer
NormalAnglePrecalc normal_angle_precalc
~VPaintData() override
GArray prev_colors
ViewContext vc
int radial_symm[3]
RegionView3D * rv3d
Definition ED_view3d.hh:80
ARegion * region
Definition ED_view3d.hh:77
Scene * scene
Definition ED_view3d.hh:73
Object * obact
Definition ED_view3d.hh:75
Depsgraph * depsgraph
Definition ED_view3d.hh:72
std::optional< blender::float3 > initial_hsv_jitter
wmEventType type
Definition WM_types.hh:754
wmOperatorStatus(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1078
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:4226
wmOperatorType * ot
Definition wm_files.cc:4225
#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)