Blender V4.3
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
14#include "MEM_guardedalloc.h"
15
16#include "CLG_log.h"
17
18#include "BLI_array_utils.h"
19#include "BLI_color.hh"
20#include "BLI_color_mix.hh"
22#include "BLI_listbase.h"
23#include "BLI_math_geom.h"
24#include "BLI_math_matrix.hh"
25#include "BLI_math_rotation.h"
26#include "BLI_rect.h"
27#include "BLI_string.h"
28#include "BLI_task.h"
29#include "BLI_task.hh"
30#include "BLI_vector.hh"
31
32#include "DNA_brush_types.h"
33#include "DNA_mesh_types.h"
34#include "DNA_meshdata_types.h"
35#include "DNA_object_types.h"
36#include "DNA_scene_types.h"
37
38#include "RNA_access.hh"
39#include "RNA_define.hh"
40
41#include "BKE_attribute.hh"
42#include "BKE_brush.hh"
43#include "BKE_colortools.hh"
44#include "BKE_context.hh"
45#include "BKE_deform.hh"
46#include "BKE_editmesh.hh"
47#include "BKE_lib_id.hh"
48#include "BKE_mesh.hh"
49#include "BKE_object.hh"
50#include "BKE_object_deform.h"
51#include "BKE_object_types.hh"
52#include "BKE_paint.hh"
53#include "BKE_report.hh"
54
55#include "DEG_depsgraph.hh"
56
57#include "WM_api.hh"
58#include "WM_message.hh"
59#include "WM_toolsystem.hh"
60#include "WM_types.hh"
61
62#include "ED_image.hh"
63#include "ED_mesh.hh"
64#include "ED_object.hh"
65#include "ED_object_vgroup.hh"
66#include "ED_paint.hh"
67#include "ED_screen.hh"
68#include "ED_sculpt.hh"
69#include "ED_view3d.hh"
70
71/* For IMB_BlendMode only. */
72#include "IMB_imbuf.hh"
73
74#include "BKE_ccg.hh"
75#include "bmesh.hh"
76
77#include "mesh_brush_common.hh"
78#include "paint_intern.hh" /* own include */
79#include "sculpt_automask.hh"
80#include "sculpt_boundary.hh"
81#include "sculpt_cloth.hh"
82#include "sculpt_intern.hh"
83#include "sculpt_pose.hh"
84#include "sculpt_undo.hh"
85
88using namespace blender;
89using namespace blender::color;
90using namespace blender::ed::sculpt_paint; /* For vwpaint namespace. */
92
93static CLG_LogRef LOG = {"ed.sculpt_paint"};
94
95/* -------------------------------------------------------------------- */
99static bool isZero(ColorPaint4f c)
100{
101 return c.r == 0.0f && c.g == 0.0f && c.b == 0.0f && c.a == 0.0f;
102}
103
104static bool isZero(ColorPaint4b c)
105{
106 return c.r == 0 && c.g == 0 && c.b == 0 && c.a == 0;
107}
108
109template<typename Color> static ColorPaint4f toFloat(const Color &c)
110{
111 if constexpr (std::is_same_v<Color, ColorPaint4b>) {
112 return c.decode();
113 }
114 else {
115 return c;
116 }
117}
118
119template<typename Color> static Color fromFloat(const ColorPaint4f &c)
120{
121 if constexpr (std::is_same_v<Color, ColorPaint4b>) {
122 return c.encode();
123 }
124 else {
125 return c;
126 }
127}
128
129/* Use for 'blur' brush, align with pbvh::Tree nodes, created and freed on each update. */
130template<typename BlendType> struct VPaintAverageAccum {
131 BlendType len;
132 BlendType value[3];
133};
134
136
137/* -------------------------------------------------------------------- */
141void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
142{
143 angle = RAD2DEGF(angle);
144 a->do_mask_normal = do_mask_normal;
145 if (do_mask_normal) {
146 a->angle_inner = angle;
147 a->angle = (a->angle_inner + 90.0f) * 0.5f;
148 }
149 else {
150 a->angle_inner = a->angle = angle;
151 }
152
153 a->angle_inner *= float(M_PI_2 / 90);
154 a->angle *= float(M_PI_2 / 90);
155 a->angle_range = a->angle - a->angle_inner;
156
157 if (a->angle_range <= 0.0f) {
158 a->do_mask_normal = false; /* no need to do blending */
159 }
160
161 a->angle__cos = cosf(a->angle);
162 a->angle_inner__cos = cosf(a->angle_inner);
163}
164
165float view_angle_limits_apply_falloff(const NormalAnglePrecalc *a, float angle_cos, float *mask_p)
166{
167 if (angle_cos <= a->angle__cos) {
168 /* outsize the normal limit */
169 return false;
170 }
171 if (angle_cos < a->angle_inner__cos) {
172 *mask_p *= (a->angle - acosf(angle_cos)) / a->angle_range;
173 return true;
174 }
175 return true;
176}
177
179 const NormalAnglePrecalc &normal_angle_precalc,
180 const float angle_cos,
181 float *brush_strength)
182{
183 if (((brush.flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
184 ((brush.flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
185 vwpaint::view_angle_limits_apply_falloff(&normal_angle_precalc, angle_cos, brush_strength)))
186 {
187 return true;
188 }
189 return false;
190}
191
192bool use_normal(const VPaint &vp)
193{
194 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
195 return ((brush.flag & BRUSH_FRONTFACE) != 0) || ((brush.flag & BRUSH_FRONTFACE_FALLOFF) != 0);
196}
197
198bool brush_use_accumulate_ex(const Brush &brush, const eObjectMode ob_mode)
199{
200 return ((brush.flag & BRUSH_ACCUMULATE) != 0 ||
201 (ob_mode == OB_MODE_VERTEX_PAINT ?
204}
205
207{
208 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
210}
211
212void init_stroke(Depsgraph &depsgraph, Object &ob)
213{
215 SculptSession &ss = *ob.sculpt;
216
217 /* Ensure ss.cache is allocated. It will mostly be initialized in
218 * vwpaint::update_cache_invariants and vwpaint::update_cache_variants.
219 */
220 if (!ss.cache) {
221 ss.cache = MEM_new<StrokeCache>(__func__);
222 }
223}
224
226 Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, eObjectMode object_mode)
227{
228 /* Create persistent sculpt mode data */
230
231 BLI_assert(ob.sculpt == nullptr);
232 ob.sculpt = MEM_new<SculptSession>(__func__);
233 ob.sculpt->mode_type = object_mode;
235
236 ensure_valid_pivot(ob, scene);
237}
238
240{
241 /* Create maps */
242 if (ob.mode == OB_MODE_VERTEX_PAINT) {
244 }
245 else if (ob.mode == OB_MODE_WEIGHT_PAINT) {
247 }
248 else {
250 BLI_assert(0);
251 return;
252 }
253
254 Mesh *mesh = (Mesh *)ob.data;
255
256 /* Create average brush arrays */
257 if (ob.mode == OB_MODE_WEIGHT_PAINT) {
258 SculptSession &ss = *ob.sculpt;
260 if (ss.mode.wpaint.alpha_weight == nullptr) {
261 ss.mode.wpaint.alpha_weight = (float *)MEM_callocN(mesh->verts_num * sizeof(float),
262 __func__);
263 }
264 if (ss.mode.wpaint.dvert_prev.is_empty()) {
265 MDeformVert initial_value{};
266 /* Use to show this isn't initialized, never apply to the mesh data. */
267 initial_value.flag = 1;
268 ss.mode.wpaint.dvert_prev = Array<MDeformVert>(mesh->verts_num, initial_value);
269 }
270 }
271 else {
273 if (!ss.mode.wpaint.dvert_prev.is_empty()) {
276 ss.mode.wpaint.dvert_prev = {};
277 }
278 }
279 }
280}
281
283 const Object &ob,
284 const VPaint &wp,
285 const Brush &brush,
286 IndexMaskMemory &memory)
287{
288 SculptSession &ss = *ob.sculpt;
289 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
290 const bool use_normal = vwpaint::use_normal(wp);
291 IndexMask nodes;
292
293 /* Build a list of all nodes that are potentially within the brush's area of influence */
295 nodes = bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
296 return node_in_sphere(node, ss.cache->location_symm, ss.cache->radius_squared, true);
297 });
298
300 use_normal ? calc_area_normal(depsgraph, brush, ob, nodes).value_or(float3(0)) : float3(0);
301 }
302 else {
305 nodes = bke::pbvh::search_nodes(pbvh, memory, [&](const bke::pbvh::Node &node) {
306 return node_in_cylinder(ray_dist_precalc, node, ss.cache->radius_squared, true);
307 });
308
310 }
311 return nodes;
312}
313
315 Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, const eObjectMode mode_flag)
316{
317 ob.mode |= mode_flag;
318 Mesh *mesh = BKE_mesh_from_object(&ob);
319
320 /* Same as sculpt mode, make sure we don't have cached derived mesh which
321 * points to freed arrays.
322 */
324
325 if (mode_flag == OB_MODE_VERTEX_PAINT) {
326 const PaintMode paint_mode = PaintMode::Vertex;
327 ED_mesh_color_ensure(mesh, nullptr);
328
329 BKE_paint_ensure(scene.toolsettings, (Paint **)&scene.toolsettings->vpaint);
330 Paint *paint = BKE_paint_get_active_from_paintmode(&scene, paint_mode);
332 BKE_paint_init(&bmain, &scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
333 }
334 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
335 const PaintMode paint_mode = PaintMode::Weight;
336
337 BKE_paint_ensure(scene.toolsettings, (Paint **)&scene.toolsettings->wpaint);
338 Paint *paint = BKE_paint_get_active_from_paintmode(&scene, paint_mode);
340 BKE_paint_init(&bmain, &scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
341
342 /* weight paint specific */
345 }
346 else {
347 BLI_assert(0);
348 }
349
350 /* Create vertex/weight paint mode session data */
351 if (ob.sculpt) {
352 MEM_delete(ob.sculpt->cache);
353 ob.sculpt->cache = nullptr;
355 }
356
357 vwpaint::init_session(bmain, depsgraph, scene, ob, mode_flag);
358
359 /* Flush object mode. */
361}
362
363void mode_exit_generic(Object &ob, const eObjectMode mode_flag)
364{
365 using namespace blender;
366 Mesh *mesh = BKE_mesh_from_object(&ob);
367 ob.mode &= ~mode_flag;
368
369 if (mode_flag == OB_MODE_VERTEX_PAINT) {
370 if (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
372 }
373 else if (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
375 }
376 }
377 else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
378 if (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
380 }
381 else if (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
383 }
384 }
385 else {
386 BLI_assert(0);
387 }
388
389 /* If the cache is not released by a cancel or a done, free it now. */
390 if (ob.sculpt) {
391 MEM_delete(ob.sculpt->cache);
392 ob.sculpt->cache = nullptr;
393 }
394
396
398
399 if (mode_flag == OB_MODE_WEIGHT_PAINT) {
402 }
403
404 /* Never leave derived meshes behind. */
406
407 /* Flush object mode. */
409}
410
412{
414 if (ob == nullptr || ob->type != OB_MESH) {
415 return false;
416 }
417 if (!ob->data || !ID_IS_EDITABLE(ob->data)) {
418 return false;
419 }
420 return true;
421}
422
423void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
424{
425 Brush *brush = BKE_paint_brush(paint);
426 /* The current brush should match with what we have stored in the cache. */
427 BLI_assert(brush == cache->brush);
428
429 /* If saved_active_brush is not set, brush was not switched/affected in
430 * smooth_brush_toggle_on(). */
431 if (cache->saved_active_brush) {
432 Scene *scene = CTX_data_scene(C);
433 BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
435 cache->saved_active_brush = nullptr;
436 }
437}
439 bContext *C, VPaint &vp, SculptSession &ss, wmOperator *op, const float mval[2])
440{
441 StrokeCache *cache;
442 const Scene *scene = CTX_data_scene(C);
446 float mat[3][3];
447 float view_dir[3] = {0.0f, 0.0f, 1.0f};
448 int mode;
449
450 /* VW paint needs to allocate stroke cache before update is called. */
451 if (!ss.cache) {
452 cache = MEM_new<StrokeCache>(__func__);
453 ss.cache = cache;
454 }
455 else {
456 cache = ss.cache;
457 }
458
459 /* Initial mouse location */
460 if (mval) {
461 copy_v2_v2(cache->initial_mouse, mval);
462 }
463 else {
464 zero_v2(cache->initial_mouse);
465 }
466
467 mode = RNA_enum_get(op->ptr, "mode");
468 cache->invert = mode == BRUSH_STROKE_INVERT;
469 cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
470 /* not very nice, but with current events system implementation
471 * we can't handle brush appearance inversion hotkey separately (sergey) */
472 if (cache->invert) {
473 ups->draw_inverted = true;
474 }
475 else {
476 ups->draw_inverted = false;
477 }
478
479 if (cache->alt_smooth) {
481 }
482
483 copy_v2_v2(cache->mouse, cache->initial_mouse);
484 const Brush *brush = BKE_paint_brush(&vp.paint);
485 /* Truly temporary data that isn't stored in properties */
486 cache->vc = vc;
487 cache->brush = brush;
488 cache->first_time = true;
489
490 /* cache projection matrix */
491 cache->projection_mat = ED_view3d_ob_project_mat_get(cache->vc->rv3d, &ob);
492
493 invert_m4_m4(ob.runtime->world_to_object.ptr(), ob.object_to_world().ptr());
494 copy_m3_m4(mat, cache->vc->rv3d->viewinv);
495 mul_m3_v3(mat, view_dir);
496 copy_m3_m4(mat, ob.world_to_object().ptr());
497 mul_m3_v3(mat, view_dir);
498 normalize_v3_v3(cache->view_normal, view_dir);
499
500 cache->view_normal_symm = cache->view_normal;
501 cache->bstrength = BKE_brush_alpha_get(scene, brush);
502 cache->is_last_valid = false;
503
504 cache->accum = true;
505}
506
508{
509 using namespace blender;
510 Scene *scene = CTX_data_scene(C);
511 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
512 SculptSession &ss = *ob.sculpt;
513 StrokeCache *cache = ss.cache;
514 Brush &brush = *BKE_paint_brush(&vp.paint);
515
516 /* This effects the actual brush radius, so things farther away
517 * are compared with a larger radius and vice versa. */
518 if (cache->first_time) {
519 RNA_float_get_array(ptr, "location", cache->location);
520 }
521
522 RNA_float_get_array(ptr, "mouse", cache->mouse);
523
524 /* XXX: Use pressure value from first brush step for brushes which don't
525 * support strokes (grab, thumb). They depends on initial state and
526 * brush coord/pressure/etc.
527 * It's more an events design issue, which doesn't split coordinate/pressure/angle
528 * changing events. We should avoid this after events system re-design */
530 cache->pressure = RNA_float_get(ptr, "pressure");
531 }
532
533 /* Truly temporary data that isn't stored in properties */
534 if (cache->first_time) {
536 *cache->vc, cache->location, BKE_brush_size_get(scene, &brush));
538 }
539
541 {
542 cache->radius = cache->initial_radius * cache->pressure;
543 }
544 else {
545 cache->radius = cache->initial_radius;
546 }
547
548 cache->radius_squared = cache->radius * cache->radius;
549
550 if (bke::pbvh::Tree *pbvh = bke::object::pbvh_get(ob)) {
552 }
553}
554
555void get_brush_alpha_data(const Scene &scene,
556 const SculptSession &ss,
557 const Brush &brush,
558 float *r_brush_size_pressure,
559 float *r_brush_alpha_value,
560 float *r_brush_alpha_pressure)
561{
562 *r_brush_size_pressure = BKE_brush_size_get(&scene, &brush) *
563 (BKE_brush_use_size_pressure(&brush) ? ss.cache->pressure : 1.0f);
564 *r_brush_alpha_value = BKE_brush_alpha_get(&scene, &brush);
565 *r_brush_alpha_pressure = (BKE_brush_use_alpha_pressure(&brush) ? ss.cache->pressure : 1.0f);
566}
567
568void last_stroke_update(Scene &scene, const float location[3])
569{
570 UnifiedPaintSettings &ups = scene.toolsettings->unified_paint_settings;
572 add_v3_v3(ups.average_stroke_accum, location);
573 ups.last_stroke_valid = true;
574}
575
576/* -------------------------------------------------------------------- */
577
578void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
579{
580 Main *bmain = CTX_data_main(C);
581 Scene *scene = CTX_data_scene(C);
582 Brush *cur_brush = BKE_paint_brush(paint);
583
584 /* Switch to the blur (smooth) brush if possible. */
585 BKE_paint_brush_set_essentials(bmain, paint, "Blur");
586 Brush *smooth_brush = BKE_paint_brush(paint);
587
588 if (!smooth_brush) {
589 BKE_paint_brush_set(paint, cur_brush);
590 CLOG_WARN(&LOG, "Switching to the blur (smooth) brush not possible, corresponding brush not");
591 cache->saved_active_brush = nullptr;
592 return;
593 }
594
595 int cur_brush_size = BKE_brush_size_get(scene, cur_brush);
596
597 cache->saved_active_brush = cur_brush;
598 cache->saved_smooth_size = BKE_brush_size_get(scene, smooth_brush);
599 BKE_brush_size_set(scene, smooth_brush, cur_brush_size);
600 BKE_curvemapping_init(smooth_brush->curve);
601}
603} // namespace blender::ed::sculpt_paint::vwpaint
604
606{
607 const Object *ob = CTX_data_active_object(C);
608 if (!ob) {
609 return false;
610 }
611 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
612
613 if (!(ob->mode == OB_MODE_VERTEX_PAINT && mesh->faces_num)) {
614 return false;
615 }
616
617 if (!BKE_color_attribute_supported(*mesh, mesh->active_color_attribute)) {
618 return false;
619 }
620
621 return true;
622}
623
624static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
625{
626 if (vertex_paint_mode_poll(C) && BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
627 ScrArea *area = CTX_wm_area(C);
628 if (area && area->spacetype == SPACE_VIEW3D) {
629 ARegion *region = CTX_wm_region(C);
630 if (region->regiontype == RGN_TYPE_WINDOW) {
631 if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
632 return true;
633 }
634 }
635 }
636 }
637 return false;
638}
639
641{
642 return vertex_paint_poll_ex(C, true);
643}
644
646{
647 return vertex_paint_poll_ex(C, false);
648}
649
650static ColorPaint4f vpaint_get_current_col(Scene &scene, VPaint &vp, bool secondary)
651{
652 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
653 float color[4];
654 const float *brush_color = secondary ? BKE_brush_secondary_color_get(&scene, &vp.paint, brush) :
655 BKE_brush_color_get(&scene, &vp.paint, brush);
657
658 color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */
659
660 return ColorPaint4f(color);
661}
662
663/* wpaint has 'wpaint_blend' */
664template<typename Color, typename Traits>
665static Color vpaint_blend(const VPaint &vp,
666 Color color_curr,
667 Color color_orig,
668 Color color_paint,
669 const typename Traits::ValueType alpha,
670 const typename Traits::BlendType brush_alpha_value)
671{
672 using Value = typename Traits::ValueType;
673
674 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
675 const IMB_BlendMode blend = (IMB_BlendMode)brush.blend;
676
677 const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
678
679 /* If no accumulate, clip color adding with `color_orig` & `color_test`. */
681 uint a;
682 Color color_test;
683 Value *cp, *ct, *co;
684
685 color_test = BLI_mix_colors<Color, Traits>(blend, color_orig, color_paint, brush_alpha_value);
686
687 cp = (Value *)&color_blend;
688 ct = (Value *)&color_test;
689 co = (Value *)&color_orig;
690
691 for (a = 0; a < 4; a++) {
692 if (ct[a] < co[a]) {
693 if (cp[a] < ct[a]) {
694 cp[a] = ct[a];
695 }
696 else if (cp[a] > co[a]) {
697 cp[a] = co[a];
698 }
699 }
700 else {
701 if (cp[a] < co[a]) {
702 cp[a] = co[a];
703 }
704 else if (cp[a] > ct[a]) {
705 cp[a] = ct[a];
706 }
707 }
708 }
709 }
710
712 {
713 Value *cp, *cc;
714 cp = (Value *)&color_blend;
715 cc = (Value *)&color_curr;
716 cp[3] = cc[3];
717 }
718
719 return color_blend;
720}
721
723 const ViewContext *vc,
724 const float co[3],
725 float r_rgba[4])
726{
727 const Brush *brush = BKE_paint_brush_for_read(&vp.paint);
728 const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
729 BLI_assert(mtex->tex != nullptr);
730 if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
731 BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co, r_rgba, 0, nullptr);
732 }
733 else {
734 float co_ss[2]; /* screenspace */
736 vc->region,
737 co,
738 co_ss,
740 {
741 const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
742 BKE_brush_sample_tex_3d(vc->scene, brush, mtex, co_ss_3d, r_rgba, 0, nullptr);
743 }
744 else {
745 zero_v4(r_rgba);
746 }
747 }
748}
749
750static void vertex_paint_init_stroke(Depsgraph &depsgraph, Object &ob)
751{
753}
754
757/* -------------------------------------------------------------------- */
761void ED_object_vpaintmode_enter_ex(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
762{
764}
766{
767 Main &bmain = *CTX_data_main(C);
768 Scene &scene = *CTX_data_scene(C);
770 ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
771}
772
775/* -------------------------------------------------------------------- */
788
791/* -------------------------------------------------------------------- */
799{
800 Main &bmain = *CTX_data_main(C);
801 wmMsgBus *mbus = CTX_wm_message_bus(C);
803 const int mode_flag = OB_MODE_VERTEX_PAINT;
804 const bool is_mode_set = (ob.mode & mode_flag) != 0;
805 Scene &scene = *CTX_data_scene(C);
806 ToolSettings &ts = *scene.toolsettings;
807
808 if (!is_mode_set) {
809 if (!blender::ed::object::mode_compat_set(C, &ob, (eObjectMode)mode_flag, op->reports)) {
810 return OPERATOR_CANCELLED;
811 }
812 }
813
814 Mesh *mesh = BKE_mesh_from_object(&ob);
815
816 if (is_mode_set) {
818 }
819 else {
821 if (depsgraph) {
823 }
824 ED_object_vpaintmode_enter_ex(bmain, *depsgraph, scene, ob);
826 }
827
829
830 /* update modifier stack for mapping requirements */
831 DEG_id_tag_update(&mesh->id, 0);
832
834 WM_msg_publish_rna_prop(mbus, &ob.id, &ob, Object, mode);
835
837
838 return OPERATOR_FINISHED;
839}
840
842{
843 ot->name = "Vertex Paint Mode";
844 ot->idname = "PAINT_OT_vertex_paint_toggle";
845 ot->description = "Toggle the vertex paint mode in 3D view";
846
849
851}
852
855/* -------------------------------------------------------------------- */
859/* Implementation notes:
860 *
861 * Operator->invoke()
862 * - Validate context (add #Mesh.mloopcol).
863 * - Create custom-data storage.
864 * - Call paint once (mouse click).
865 * - Add modal handler.
866 *
867 * Operator->modal()
868 * - For every mouse-move, apply vertex paint.
869 * - Exit on mouse release, free custom-data.
870 * (return OPERATOR_FINISHED also removes handler and operator)
871 *
872 * For future:
873 * - implement a stroke event (or mouse-move with past positions).
874 * - revise whether op->customdata should be added in object, in set_vpaint.
875 */
876
877template<typename Func>
878static void to_static_color_type(const eCustomDataType type, const Func &func)
879{
880 switch (type) {
881 case CD_PROP_COLOR:
882 func(ColorGeometry4f());
883 break;
885 func(ColorGeometry4b());
886 break;
887 default:
889 break;
890 }
891}
892
893struct VPaintData : public PaintModeData {
895 AttrDomain domain;
897
899
901
909
911
912 /* Special storage for smear brush, avoid feedback loop - update each step. */
913 struct {
917
918 /* For brushes that don't use accumulation, a temporary holding array */
920
922 {
923 if (vp_handle) {
925 }
926 }
927};
928
929static std::unique_ptr<VPaintData> vpaint_init_vpaint(bContext *C,
930 wmOperator *op,
931 Scene &scene,
932 Depsgraph &depsgraph,
933 VPaint &vp,
934 Object &ob,
935 Mesh &mesh,
936 const AttrDomain domain,
937 const eCustomDataType type,
938 const Brush &brush)
939{
940 std::unique_ptr<VPaintData> vpd = std::make_unique<VPaintData>();
941
942 vpd->type = type;
943 vpd->domain = domain;
944
946
947 vwpaint::view_angle_limits_init(&vpd->normal_angle_precalc,
948 brush.falloff_angle,
949 (brush.flag & BRUSH_FRONTFACE_FALLOFF) != 0);
950
951 vpd->paintcol = vpaint_get_current_col(
952 scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
953
954 vpd->is_texbrush = !(brush.vertex_brush_type == VPAINT_BRUSH_TYPE_BLUR) && brush.mtex.tex;
955
957 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute, domain);
958 vpd->smear.color_prev = GArray(attribute.type(), attribute.size());
959 attribute.materialize(vpd->smear.color_prev.data());
960
961 vpd->smear.color_curr = vpd->smear.color_prev;
962 }
963
964 /* Create projection handle */
965 if (vpd->is_texbrush) {
966 ob.sculpt->building_vp_handle = true;
967 vpd->vp_handle = ED_vpaint_proj_handle_create(
968 depsgraph, scene, ob, vpd->vert_positions, vpd->vert_normals);
969 ob.sculpt->building_vp_handle = false;
970 }
971
973 if (vpd->prev_colors.is_empty()) {
974 const GVArray attribute = *mesh.attributes().lookup(mesh.active_color_attribute);
975 vpd->prev_colors = GArray(attribute.type(), attribute.size());
976 attribute.type().value_initialize_n(vpd->prev_colors.data(), vpd->prev_colors.size());
977 }
978 }
979 else {
980 vpd->prev_colors = {};
981 }
982
983 return vpd;
984}
985
986static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
987{
988 Scene &scene = *CTX_data_scene(C);
989 ToolSettings &ts = *scene.toolsettings;
990 PaintStroke *stroke = (PaintStroke *)op->customdata;
991 VPaint &vp = *ts.vpaint;
992 Brush &brush = *BKE_paint_brush(&vp.paint);
994 SculptSession &ss = *ob.sculpt;
996
997 /* context checks could be a poll() */
998 Mesh *mesh = BKE_mesh_from_object(&ob);
999 if (mesh == nullptr || mesh->faces_num == 0) {
1000 return false;
1001 }
1002
1003 ED_mesh_color_ensure(mesh, nullptr);
1004
1005 const std::optional<bke::AttributeMetaData> meta_data = *mesh->attributes().lookup_meta_data(
1006 mesh->active_color_attribute);
1007 if (!BKE_color_attribute_supported(*mesh, mesh->active_color_attribute)) {
1008 return false;
1009 }
1010
1011 std::unique_ptr<VPaintData> vpd = vpaint_init_vpaint(
1012 C, op, scene, depsgraph, vp, ob, *mesh, meta_data->domain, meta_data->data_type, brush);
1013
1014 paint_stroke_set_mode_data(stroke, std::move(vpd));
1015
1016 /* If not previously created, create vertex/weight paint mode session data */
1018 vwpaint::update_cache_invariants(C, vp, ss, op, mouse);
1020
1021 return true;
1022}
1023
1024static void filter_factors_with_selection(const Span<bool> select_vert,
1025 const Span<int> verts,
1026 const MutableSpan<float> factors)
1027{
1028 BLI_assert(verts.size() == factors.size());
1029
1030 for (const int i : verts.index_range()) {
1031 if (!select_vert[verts[i]]) {
1032 factors[i] = 0.0f;
1033 }
1034 }
1035}
1036
1038 const VPaint &vp,
1039 VPaintData &vpd,
1040 Object &ob,
1041 Mesh &mesh,
1042 const Span<bke::pbvh::MeshNode> nodes,
1043 const IndexMask &node_mask,
1044 GMutableSpan attribute)
1045{
1046 SculptSession &ss = *ob.sculpt;
1047 const StrokeCache &cache = *ss.cache;
1048
1049 const Brush &brush = *ob.sculpt->cache->brush;
1050 const Scene &scene = *CTX_data_scene(C);
1051 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1052
1053 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1055 scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1056 const bool use_normal = vwpaint::use_normal(vp);
1057 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1058 0;
1059 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1060
1061 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1062 ss, brush.falloff_shape);
1063
1064 GMutableSpan g_previous_color = vpd.prev_colors;
1065
1066 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1067 const OffsetIndices faces = mesh.faces();
1068 const Span<int> corner_verts = mesh.corner_verts();
1069 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1070 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1071 const bke::AttributeAccessor attributes = mesh.attributes();
1072 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1073 VArraySpan<bool> select_vert;
1074 if (use_vert_sel) {
1075 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1076 }
1077 VArraySpan<bool> select_poly;
1078 if (use_face_sel) {
1079 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1080 }
1081
1082 struct LocalData {
1085 };
1087 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1088 LocalData &tls = all_tls.local();
1089 const Span<int> verts = nodes[i].verts();
1090 tls.factors.resize(verts.size());
1091 const MutableSpan<float> factors = tls.factors;
1092 fill_factor_from_hide(hide_vert, verts, factors);
1093 if (!select_vert.is_empty()) {
1094 filter_factors_with_selection(select_vert, verts, factors);
1095 }
1096
1097 tls.distances.resize(verts.size());
1098 const MutableSpan<float> distances = tls.distances;
1100 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1101 filter_distances_with_radius(cache.radius, distances, factors);
1102 calc_brush_strength_factors(cache, brush, distances, factors);
1103
1104 for (const int i : verts.index_range()) {
1105 const int vert = verts[i];
1106 if (factors[i] == 0.0f) {
1107 continue;
1108 }
1109
1110 float brush_strength = cache.bstrength;
1111 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1112 1.0f;
1114 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1115 {
1116 continue;
1117 }
1118
1119 const float brush_fade = factors[i];
1120
1121 to_static_color_type(vpd.type, [&](auto dummy) {
1122 using T = decltype(dummy);
1123 using Color =
1124 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1125 using Traits = blender::color::Traits<Color>;
1126 using Blend = typename Traits::BlendType;
1127 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1128 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1129 /* Get the average face color */
1130 Color color_final(0, 0, 0, 0);
1131
1132 int total_hit_loops = 0;
1133 Blend blend[4] = {0};
1134
1135 for (const int face : vert_to_face[vert]) {
1136 if (!select_poly.is_empty() && !select_poly[face]) {
1137 return;
1138 }
1139 total_hit_loops += faces[face].size();
1140 for (const int corner : faces[face]) {
1141 const Color &col = colors[corner];
1142
1143 /* Color is squared to compensate the `sqrt` color encoding. */
1144 blend[0] += (Blend)col.r * (Blend)col.r;
1145 blend[1] += (Blend)col.g * (Blend)col.g;
1146 blend[2] += (Blend)col.b * (Blend)col.b;
1147 blend[3] += (Blend)col.a * (Blend)col.a;
1148 }
1149 }
1150
1151 if (total_hit_loops == 0) {
1152 return;
1153 }
1154
1155 /* Use rgb^2 color averaging. */
1156 Color *col = &color_final;
1157
1158 color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
1159 color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
1160 color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
1161 color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
1162
1163 /* For each face owning this vert,
1164 * paint each loop belonging to this vert. */
1165 for (const int face : vert_to_face[vert]) {
1166 const int corner = bke::mesh::face_find_corner_from_vert(
1167 faces[face], corner_verts, vert);
1168 if (!select_poly.is_empty() && !select_poly[face]) {
1169 continue;
1170 }
1171 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1172
1173 if (!previous_color.is_empty()) {
1174 /* Get the previous loop color */
1175 if (isZero(previous_color[corner])) {
1176 previous_color[corner] = colors[corner];
1177 }
1178 color_orig = previous_color[corner];
1179 }
1180 const float final_alpha = Traits::range * brush_fade * brush_strength *
1181 brush_alpha_pressure;
1182 /* Mix the new color with the original
1183 * based on the brush strength and the curve. */
1184 colors[corner] = vpaint_blend<Color, Traits>(
1185 vp, colors[corner], color_orig, *col, final_alpha, Traits::range * brush_strength);
1186 }
1187 });
1188 }
1189 });
1190}
1191
1193 const VPaint &vp,
1194 VPaintData &vpd,
1195 Object &ob,
1196 Mesh &mesh,
1197 const Span<bke::pbvh::MeshNode> nodes,
1198 const IndexMask &node_mask,
1199 GMutableSpan attribute)
1200{
1201 SculptSession &ss = *ob.sculpt;
1202 const StrokeCache &cache = *ss.cache;
1203
1204 const Brush &brush = *ss.cache->brush;
1205 const Scene &scene = *CTX_data_scene(C);
1206 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1207
1208 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1210 scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1211 const bool use_normal = vwpaint::use_normal(vp);
1212 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1213 0;
1214 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1215
1216 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1217 ss, brush.falloff_shape);
1218
1219 GMutableSpan g_previous_color = vpd.prev_colors;
1220
1221 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1222 const OffsetIndices faces = mesh.faces();
1223 const Span<int> corner_verts = mesh.corner_verts();
1224 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1225 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1226 const bke::AttributeAccessor attributes = mesh.attributes();
1227 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1228 VArraySpan<bool> select_vert;
1229 if (use_vert_sel) {
1230 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1231 }
1232 VArraySpan<bool> select_poly;
1233 if (use_face_sel) {
1234 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1235 }
1236
1237 struct LocalData {
1240 };
1242 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1243 LocalData &tls = all_tls.local();
1244 const Span<int> verts = nodes[i].verts();
1245 tls.factors.resize(verts.size());
1246 const MutableSpan<float> factors = tls.factors;
1247 fill_factor_from_hide(hide_vert, verts, factors);
1248 if (!select_vert.is_empty()) {
1249 filter_factors_with_selection(select_vert, verts, factors);
1250 }
1251
1252 tls.distances.resize(verts.size());
1253 const MutableSpan<float> distances = tls.distances;
1255 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1256 filter_distances_with_radius(cache.radius, distances, factors);
1257 calc_brush_strength_factors(cache, brush, distances, factors);
1258
1259 for (const int i : verts.index_range()) {
1260 const int vert = verts[i];
1261 if (factors[i] == 0.0f) {
1262 continue;
1263 }
1264
1265 float brush_strength = cache.bstrength;
1266 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1267 1.0f;
1269 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1270 {
1271 continue;
1272 }
1273 const float brush_fade = factors[i];
1274
1275 /* Get the average face color */
1276 to_static_color_type(vpd.type, [&](auto dummy) {
1277 using T = decltype(dummy);
1278 using Color =
1279 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1280 using Traits = blender::color::Traits<Color>;
1281 using Blend = typename Traits::BlendType;
1282 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1283 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1284 Color color_final(0, 0, 0, 0);
1285
1286 int total_hit_loops = 0;
1287 Blend blend[4] = {0};
1288
1289 for (const int face : vert_to_face[vert]) {
1290 if (!select_poly.is_empty() && !select_poly[face]) {
1291 continue;
1292 }
1293 total_hit_loops += faces[face].size();
1294 for (const int vert : corner_verts.slice(faces[face])) {
1295 const Color &col = colors[vert];
1296
1297 /* Color is squared to compensate the `sqrt` color encoding. */
1298 blend[0] += (Blend)col.r * (Blend)col.r;
1299 blend[1] += (Blend)col.g * (Blend)col.g;
1300 blend[2] += (Blend)col.b * (Blend)col.b;
1301 blend[3] += (Blend)col.a * (Blend)col.a;
1302 }
1303 }
1304
1305 if (total_hit_loops == 0) {
1306 return;
1307 }
1308 /* Use rgb^2 color averaging. */
1309 color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops)));
1310 color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops)));
1311 color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops)));
1312 color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops)));
1313
1314 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1315
1316 if (!previous_color.is_empty()) {
1317 /* Get the previous loop color */
1318 if (isZero(previous_color[vert])) {
1319 previous_color[vert] = colors[vert];
1320 }
1321 color_orig = previous_color[vert];
1322 }
1323 const float final_alpha = Traits::range * brush_fade * brush_strength *
1324 brush_alpha_pressure;
1325 /* Mix the new color with the original
1326 * based on the brush strength and the curve. */
1327 colors[vert] = vpaint_blend<Color, Traits>(vp,
1328 colors[vert],
1329 color_orig,
1330 color_final,
1331 final_alpha,
1332 Traits::range * brush_strength);
1333 });
1334 }
1335 });
1336}
1337
1338static void do_vpaint_brush_smear(const bContext *C,
1339 const VPaint &vp,
1340 VPaintData &vpd,
1341 Object &ob,
1342 Mesh &mesh,
1343 const Span<bke::pbvh::MeshNode> nodes,
1344 const IndexMask &node_mask,
1345 GMutableSpan attribute)
1346{
1347 SculptSession &ss = *ob.sculpt;
1348 StrokeCache &cache = *ss.cache;
1349 if (!cache.is_last_valid) {
1350 return;
1351 }
1352
1353 const Brush &brush = *cache.brush;
1354 const Scene &scene = *CTX_data_scene(C);
1355 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1356 GMutableSpan g_color_curr = vpd.smear.color_curr;
1357 GMutableSpan g_color_prev_smear = vpd.smear.color_prev;
1358 GMutableSpan g_color_prev = vpd.prev_colors;
1359
1360 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1361
1363 scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1364 const bool use_normal = vwpaint::use_normal(vp);
1365 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1366 0;
1367 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1368
1369 float brush_dir[3];
1370 sub_v3_v3v3(brush_dir, cache.location_symm, cache.last_location_symm);
1371 project_plane_v3_v3v3(brush_dir, brush_dir, cache.view_normal_symm);
1372 if (normalize_v3(brush_dir) == 0.0f) {
1373 return;
1374 }
1375
1376 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1377 ss, brush.falloff_shape);
1378
1379 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1380 const OffsetIndices faces = mesh.faces();
1381 const Span<int> corner_verts = mesh.corner_verts();
1382 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1383 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1384 const bke::AttributeAccessor attributes = mesh.attributes();
1385 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1386 VArraySpan<bool> select_vert;
1387 if (use_vert_sel) {
1388 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1389 }
1390 VArraySpan<bool> select_poly;
1391 if (use_face_sel) {
1392 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1393 }
1394
1395 struct LocalData {
1398 };
1400 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1401 LocalData &tls = all_tls.local();
1402 const Span<int> verts = nodes[i].verts();
1403 tls.factors.resize(verts.size());
1404 const MutableSpan<float> factors = tls.factors;
1405 fill_factor_from_hide(hide_vert, verts, factors);
1406 if (!select_vert.is_empty()) {
1407 filter_factors_with_selection(select_vert, verts, factors);
1408 }
1409
1410 tls.distances.resize(verts.size());
1411 const MutableSpan<float> distances = tls.distances;
1413 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1414 filter_distances_with_radius(cache.radius, distances, factors);
1415 calc_brush_strength_factors(cache, brush, distances, factors);
1416
1417 for (const int i : verts.index_range()) {
1418 const int vert = verts[i];
1419 if (factors[i] == 0.0f) {
1420 continue;
1421 }
1422
1423 /* Calculate the dot prod. between ray norm on surf and current vert
1424 * (ie splash prevention factor), and only paint front facing verts. */
1425 float brush_strength = cache.bstrength;
1426 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1427 1.0f;
1429 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1430 {
1431 continue;
1432 }
1433 const float brush_fade = factors[i];
1434
1435 bool do_color = false;
1436 /* Minimum dot product between brush direction and current
1437 * to neighbor direction is 0.0, meaning orthogonal. */
1438 float stroke_dot_max = 0.0f;
1439
1440 /* Get the color of the loop in the opposite
1441 * direction of the brush movement */
1442 to_static_color_type(vpd.type, [&](auto dummy) {
1443 using T = decltype(dummy);
1444 using Color =
1445 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1446 using Traits = blender::color::Traits<Color>;
1447 MutableSpan<Color> color_curr = g_color_curr.typed<T>().template cast<Color>();
1448 MutableSpan<Color> color_prev_smear = g_color_prev_smear.typed<T>().template cast<Color>();
1449 MutableSpan<Color> color_prev = g_color_prev.typed<T>().template cast<Color>();
1450 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1451
1452 Color color_final(0, 0, 0, 0);
1453
1454 for (const int face : vert_to_face[vert]) {
1455 if (!select_poly.is_empty() && !select_poly[face]) {
1456 continue;
1457 }
1458 for (const int corner : faces[face]) {
1459 const int v_other_index = corner_verts[corner];
1460 if (v_other_index == vert) {
1461 continue;
1462 }
1463
1464 /* Get the direction from the
1465 * selected vert to the neighbor. */
1466 float other_dir[3];
1467 sub_v3_v3v3(other_dir, vert_positions[vert], vert_positions[v_other_index]);
1468 project_plane_v3_v3v3(other_dir, other_dir, cache.view_normal_symm);
1469
1470 normalize_v3(other_dir);
1471
1472 const float stroke_dot = dot_v3v3(other_dir, brush_dir);
1473 int elem_index;
1474
1475 if (vpd.domain == AttrDomain::Point) {
1476 elem_index = v_other_index;
1477 }
1478 else {
1479 elem_index = corner;
1480 }
1481
1482 if (stroke_dot > stroke_dot_max) {
1483 stroke_dot_max = stroke_dot;
1484 color_final = color_prev_smear[elem_index];
1485 do_color = true;
1486 }
1487 }
1488 }
1489
1490 if (!do_color) {
1491 return;
1492 }
1493
1494 const float final_alpha = Traits::range * brush_fade * brush_strength *
1495 brush_alpha_pressure;
1496
1497 /* For each face owning this vert,
1498 * paint each loop belonging to this vert. */
1499 for (const int face : vert_to_face[vert]) {
1500
1501 int elem_index;
1502 if (vpd.domain == AttrDomain::Point) {
1503 elem_index = vert;
1504 }
1505 else {
1506 elem_index = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
1507 }
1508 if (!select_poly.is_empty() && !select_poly[face]) {
1509 continue;
1510 }
1511
1512 /* Get the previous element color */
1513 Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
1514
1515 if (!color_prev.is_empty()) {
1516 /* Get the previous element color */
1517 if (isZero(color_prev[elem_index])) {
1518 color_prev[elem_index] = colors[elem_index];
1519 }
1520 color_orig = color_prev[elem_index];
1521 }
1522 /* Mix the new color with the original
1523 * based on the brush strength and the curve. */
1524 colors[elem_index] = vpaint_blend<Color, Traits>(vp,
1525 colors[elem_index],
1526 color_orig,
1527 color_final,
1528 final_alpha,
1529 Traits::range * brush_strength);
1530
1531 color_curr[elem_index] = colors[elem_index];
1532 }
1533 });
1534 }
1535 });
1536}
1537
1539 Object &ob,
1540 Mesh &mesh,
1541 const Brush &brush,
1542 const GSpan attribute,
1543 const Span<bke::pbvh::MeshNode> nodes,
1544 const IndexMask &node_mask)
1545{
1546 SculptSession &ss = *ob.sculpt;
1547 const StrokeCache &cache = *ss.cache;
1548 const Depsgraph &depsgraph = *vpd.vc.depsgraph;
1549
1550 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1551 0;
1552
1553 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1554 const OffsetIndices faces = mesh.faces();
1555 const Span<int> corner_verts = mesh.corner_verts();
1556 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1557 const bke::AttributeAccessor attributes = mesh.attributes();
1558 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1559 VArraySpan<bool> select_vert;
1560 if (use_vert_sel) {
1561 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1562 }
1563
1564 struct LocalData {
1567 };
1569 to_static_color_type(vpd.type, [&](auto dummy) {
1570 using T = decltype(dummy);
1571 using Color =
1572 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1573 using Traits = blender::color::Traits<Color>;
1574 using Blend = typename Traits::BlendType;
1575 const Span<Color> colors = attribute.typed<T>().template cast<Color>();
1576
1577 Array<VPaintAverageAccum<Blend>> accum(nodes.size());
1578 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1579 LocalData &tls = all_tls.local();
1580 VPaintAverageAccum<Blend> &accum2 = accum[i];
1581 accum2.len = 0;
1582 memset(accum2.value, 0, sizeof(accum2.value));
1583
1584 const Span<int> verts = nodes[i].verts();
1585 tls.factors.resize(verts.size());
1586 const MutableSpan<float> factors = tls.factors;
1587 fill_factor_from_hide(hide_vert, verts, factors);
1588 if (!select_vert.is_empty()) {
1589 filter_factors_with_selection(select_vert, verts, factors);
1590 }
1591
1592 tls.distances.resize(verts.size());
1593 const MutableSpan<float> distances = tls.distances;
1594 calc_brush_distances(
1595 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1596 filter_distances_with_radius(cache.radius, distances, factors);
1597 calc_brush_strength_factors(cache, brush, distances, factors);
1598
1599 for (const int i : verts.index_range()) {
1600 const int vert = verts[i];
1601 if (factors[i] == 0.0f) {
1602 continue;
1603 }
1604
1605 accum2.len += vert_to_face[vert].size();
1606 /* if a vertex is within the brush region, then add its color to the blend. */
1607 for (const int face : vert_to_face[vert]) {
1608 int elem_index;
1609 if (vpd.domain == AttrDomain::Corner) {
1610 elem_index = bke::mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
1611 }
1612 else {
1613 elem_index = vert;
1614 }
1615
1616 /* Color is squared to compensate the `sqrt` color encoding. */
1617 const Color &col = colors[elem_index];
1618 accum2.value[0] += col.r * col.r;
1619 accum2.value[1] += col.g * col.g;
1620 accum2.value[2] += col.b * col.b;
1621 }
1622 }
1623 });
1624
1625 Blend accum_len = 0;
1626 Blend accum_value[3] = {0};
1627 Color blend(0, 0, 0, 0);
1628
1629 for (int i = 0; i < nodes.size(); i++) {
1630 accum_len += accum[i].len;
1631 accum_value[0] += accum[i].value[0];
1632 accum_value[1] += accum[i].value[1];
1633 accum_value[2] += accum[i].value[2];
1634 }
1635 if (accum_len != 0) {
1636 blend.r = Traits::round(sqrtf(Traits::divide_round(accum_value[0], accum_len)));
1637 blend.g = Traits::round(sqrtf(Traits::divide_round(accum_value[1], accum_len)));
1638 blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len)));
1639 blend.a = Traits::range;
1640
1641 vpd.paintcol = toFloat(blend);
1642 }
1643 });
1644}
1645
1646template<typename Color>
1647static float paint_and_tex_color_alpha(const VPaint &vp,
1648 VPaintData &vpd,
1649 const float v_co[3],
1650 Color *r_color)
1651{
1652 ColorPaint4f rgba;
1653 paint_and_tex_color_alpha_intern(vp, &vpd.vc, v_co, &rgba.r);
1654
1655 ColorPaint4f rgba_br = toFloat(vpd.paintcol);
1656 mul_v3_v3(rgba_br, rgba);
1657
1658 *r_color = fromFloat<Color>(rgba_br);
1659 return rgba[3];
1660}
1661
1662static void vpaint_do_draw(const bContext *C,
1663 const VPaint &vp,
1664 VPaintData &vpd,
1665 Object &ob,
1666 Mesh &mesh,
1667 const Span<bke::pbvh::MeshNode> nodes,
1668 const IndexMask &node_mask,
1669 GMutableSpan attribute)
1670{
1671 SculptSession &ss = *ob.sculpt;
1672 const StrokeCache &cache = *ss.cache;
1673 const Brush &brush = *ob.sculpt->cache->brush;
1674 const Scene &scene = *CTX_data_scene(C);
1675 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1676
1677 float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
1679 scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure);
1680 const bool use_normal = vwpaint::use_normal(vp);
1681 const bool use_vert_sel = (mesh.editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) !=
1682 0;
1683 const bool use_face_sel = (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
1684
1685 const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape(
1686 ss, brush.falloff_shape);
1687
1688 GMutableSpan g_previous_color = vpd.prev_colors;
1689
1690 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval(depsgraph, ob);
1691 const OffsetIndices faces = mesh.faces();
1692 const Span<int> corner_verts = mesh.corner_verts();
1693 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, ob);
1694 const GroupedSpan<int> vert_to_face = mesh.vert_to_face_map();
1695 const bke::AttributeAccessor attributes = mesh.attributes();
1696 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1697 VArraySpan<bool> select_vert;
1698 if (use_vert_sel) {
1699 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
1700 }
1701 VArraySpan<bool> select_poly;
1702 if (use_face_sel) {
1703 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
1704 }
1705
1706 struct LocalData {
1709 };
1711 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1712 LocalData &tls = all_tls.local();
1713 const Span<int> verts = nodes[i].verts();
1714 tls.factors.resize(verts.size());
1715 const MutableSpan<float> factors = tls.factors;
1716 fill_factor_from_hide(hide_vert, verts, factors);
1717 if (!select_vert.is_empty()) {
1718 filter_factors_with_selection(select_vert, verts, factors);
1719 }
1720
1721 tls.distances.resize(verts.size());
1722 const MutableSpan<float> distances = tls.distances;
1724 ss, vert_positions, verts, eBrushFalloffShape(brush.falloff_shape), distances);
1725 filter_distances_with_radius(cache.radius, distances, factors);
1726 calc_brush_strength_factors(cache, brush, distances, factors);
1727
1728 for (const int i : verts.index_range()) {
1729 const int vert = verts[i];
1730 if (factors[i] == 0.0f) {
1731 continue;
1732 }
1733
1734 /* Calculate the dot product between ray normal on surface and current vertex
1735 * (ie splash prevention factor), and only paint front facing verts. */
1736 float brush_strength = cache.bstrength;
1737 const float angle_cos = use_normal ? dot_v3v3(sculpt_normal_frontface, vert_normals[vert]) :
1738 1.0f;
1740 brush, vpd.normal_angle_precalc, angle_cos, &brush_strength))
1741 {
1742 continue;
1743 }
1744 const float brush_fade = factors[i];
1745
1746 to_static_color_type(vpd.type, [&](auto dummy) {
1747 using T = decltype(dummy);
1748 using Color =
1749 std::conditional_t<std::is_same_v<T, ColorGeometry4f>, ColorPaint4f, ColorPaint4b>;
1750 using Traits = blender::color::Traits<Color>;
1751 MutableSpan<Color> colors = attribute.typed<T>().template cast<Color>();
1752 MutableSpan<Color> previous_color = g_previous_color.typed<T>().template cast<Color>();
1753 Color color_final = fromFloat<Color>(vpd.paintcol);
1754
1755 /* If we're painting with a texture, sample the texture color and alpha. */
1756 float tex_alpha = 1.0;
1757 if (vpd.is_texbrush) {
1758 /* NOTE: we may want to paint alpha as vertex color alpha. */
1759
1760 /* If the active area is being applied for symmetry, flip it
1761 * across the symmetry axis and rotate it back to the original
1762 * position in order to project it. This ensures that the
1763 * brush texture will be oriented correctly.
1764 * This is the method also used in #sculpt_apply_texture(). */
1765 float3 position = vpd.vert_positions[vert];
1766 if (cache.radial_symmetry_pass) {
1767 position = blender::math::transform_point(cache.symm_rot_mat_inv, position);
1768 }
1769 const float3 symm_point = blender::ed::sculpt_paint::symmetry_flip(
1770 position, cache.mirror_symmetry_pass);
1771
1772 tex_alpha = paint_and_tex_color_alpha<Color>(vp, vpd, symm_point, &color_final);
1773 }
1774
1775 Color color_orig(0, 0, 0, 0);
1776
1777 if (vpd.domain == AttrDomain::Point) {
1778 if (!previous_color.is_empty()) {
1779 if (isZero(previous_color[vert])) {
1780 previous_color[vert] = colors[vert];
1781 }
1782 color_orig = previous_color[vert];
1783 }
1784 const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha *
1785 brush_alpha_pressure;
1786
1787 colors[vert] = vpaint_blend<Color, Traits>(vp,
1788 colors[vert],
1789 color_orig,
1790 color_final,
1791 final_alpha,
1792 Traits::range * brush_strength);
1793 }
1794 else {
1795 /* For each face owning this vert, paint each loop belonging to this vert. */
1796 for (const int face : vert_to_face[vert]) {
1797 const int corner = bke::mesh::face_find_corner_from_vert(
1798 faces[face], corner_verts, vert);
1799 if (!select_poly.is_empty() && !select_poly[face]) {
1800 continue;
1801 }
1802 Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */
1803
1804 if (!previous_color.is_empty()) {
1805 if (isZero(previous_color[corner])) {
1806 previous_color[corner] = colors[corner];
1807 }
1808 color_orig = previous_color[corner];
1809 }
1810 const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha *
1811 brush_alpha_pressure;
1812
1813 colors[corner] = vpaint_blend<Color, Traits>(vp,
1814 colors[corner],
1815 color_orig,
1816 color_final,
1817 final_alpha,
1818 Traits::range * brush_strength);
1819 }
1820 }
1821 });
1822 }
1823 });
1824}
1825
1826static void vpaint_do_blur(const bContext *C,
1827 const VPaint &vp,
1828 VPaintData &vpd,
1829 Object &ob,
1830 Mesh &mesh,
1831 const Span<bke::pbvh::MeshNode> nodes,
1832 const IndexMask &node_mask,
1833 GMutableSpan attribute)
1834{
1835 if (vpd.domain == AttrDomain::Point) {
1836 do_vpaint_brush_blur_verts(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1837 }
1838 else {
1839 do_vpaint_brush_blur_loops(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1840 }
1841}
1842
1844 const VPaint &vp,
1845 VPaintData &vpd,
1846 Object &ob,
1847 Mesh &mesh,
1848 GMutableSpan attribute,
1849 const Span<bke::pbvh::MeshNode> nodes,
1850 const IndexMask &node_mask)
1851{
1852 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1853 undo::push_nodes(depsgraph, ob, node_mask, undo::Type::Color);
1854
1855 const Brush &brush = *ob.sculpt->cache->brush;
1856
1859 calculate_average_color(vpd, ob, mesh, brush, attribute, nodes, node_mask);
1860 vpaint_do_draw(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1861 break;
1863 vpaint_do_draw(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1864 break;
1866 vpaint_do_blur(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1867 break;
1869 do_vpaint_brush_smear(C, vp, vpd, ob, mesh, nodes, node_mask, attribute);
1870 break;
1871 }
1872}
1873
1875 const VPaint &vp,
1876 VPaintData &vpd,
1877 Object &ob,
1878 Mesh &mesh,
1879 const Brush &brush,
1880 const ePaintSymmetryFlags symm,
1881 const int axis,
1882 const int i,
1883 const float angle)
1884{
1885 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
1886 SculptSession &ss = *ob.sculpt;
1888 SCULPT_cache_calc_brushdata_symm(*ss.cache, symm, axis, angle);
1889
1890 IndexMaskMemory memory;
1891 const IndexMask node_mask = vwpaint::pbvh_gather_generic(depsgraph, ob, vp, brush, memory);
1892
1893 bke::GSpanAttributeWriter attribute = mesh.attributes_for_write().lookup_for_write_span(
1894 mesh.active_color_attribute);
1895 BLI_assert(attribute.domain == vpd.domain);
1896
1897 /* Paint those leaves. */
1899 vp,
1900 vpd,
1901 ob,
1902 mesh,
1903 attribute.span,
1905 node_mask);
1906
1907 attribute.finish();
1908}
1909
1911 const VPaint &vp,
1912 VPaintData &vpd,
1913 Object &ob,
1914 Mesh &mesh,
1915 const Brush &brush,
1916 const ePaintSymmetryFlags symm,
1917 const int axis)
1918{
1919 for (int i = 1; i < vp.radial_symm[axis - 'X']; i++) {
1920 const float angle = (2.0 * M_PI) * i / vp.radial_symm[axis - 'X'];
1921 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm, axis, i, angle);
1922 }
1923}
1924
1925/* near duplicate of: sculpt.cc's,
1926 * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
1928 const VPaint &vp,
1929 VPaintData &vpd,
1930 Object &ob)
1931{
1932 const Brush &brush = *BKE_paint_brush_for_read(&vp.paint);
1933 Mesh &mesh = *(Mesh *)ob.data;
1934 SculptSession &ss = *ob.sculpt;
1935 StrokeCache &cache = *ss.cache;
1936 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
1937 int i = 0;
1938
1939 /* initial stroke */
1940 const ePaintSymmetryFlags initial_symm = ePaintSymmetryFlags(0);
1942 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, initial_symm, 'X', 0, 0);
1943 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'X');
1944 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Y');
1945 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, initial_symm, 'Z');
1946
1947 cache.symmetry = symm;
1948
1949 /* symm is a bit combination of XYZ - 1 is mirror
1950 * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
1951 for (i = 1; i <= symm; i++) {
1952 if (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5))) {
1953 const ePaintSymmetryFlags symm_pass = ePaintSymmetryFlags(i);
1954 cache.mirror_symmetry_pass = symm_pass;
1955 cache.radial_symmetry_pass = 0;
1956 SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0);
1957
1958 if (i & (1 << 0)) {
1959 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'X', 0, 0);
1960 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'X');
1961 }
1962 if (i & (1 << 1)) {
1963 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y', 0, 0);
1964 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Y');
1965 }
1966 if (i & (1 << 2)) {
1967 vpaint_do_paint(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z', 0, 0);
1968 vpaint_do_radial_symmetry(C, vp, vpd, ob, mesh, brush, symm_pass, 'Z');
1969 }
1970 }
1971 }
1972
1973 copy_v3_v3(cache.last_location, cache.location);
1974 cache.is_last_valid = true;
1975}
1976
1978 wmOperator * /*op*/,
1979 PaintStroke *stroke,
1980 PointerRNA *itemptr)
1981{
1982 Scene &scene = *CTX_data_scene(C);
1984 VPaintData &vpd = *static_cast<VPaintData *>(paint_stroke_mode_data(stroke));
1985 VPaint &vp = *ts->vpaint;
1986 ViewContext &vc = vpd.vc;
1987 Object &ob = *vc.obact;
1988 SculptSession &ss = *ob.sculpt;
1989
1990 vwpaint::update_cache_variants(C, vp, ob, itemptr);
1991
1992 float mat[4][4];
1993
1995
1996 mul_m4_m4m4(mat, vc.rv3d->persmat, ob.object_to_world().ptr());
1997
1998 swap_m4m4(vc.rv3d->persmat, mat);
1999
2001
2002 swap_m4m4(vc.rv3d->persmat, mat);
2003
2005
2006 Brush &brush = *BKE_paint_brush(&vp.paint);
2008 vpd.smear.color_prev = vpd.smear.color_curr;
2009 }
2010
2011 /* Calculate pivot for rotation around selection if needed.
2012 * also needed for "Frame Selected" on last stroke. */
2013 float loc_world[3];
2014 mul_v3_m4v3(loc_world, ob.object_to_world().ptr(), ss.cache->location);
2015 vwpaint::last_stroke_update(scene, loc_world);
2016
2018
2020}
2021
2022static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke)
2023{
2024 VPaintData *vpd = static_cast<VPaintData *>(paint_stroke_mode_data(stroke));
2025 Object &ob = *vpd->vc.obact;
2026
2027 SculptSession &ss = *ob.sculpt;
2028
2029 if (ss.cache && ss.cache->alt_smooth) {
2031 VPaint &vp = *ts->vpaint;
2033 }
2034
2036
2037 undo::push_end(ob);
2038
2039 MEM_delete(ob.sculpt->cache);
2040 ob.sculpt->cache = nullptr;
2041}
2042
2043static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2044{
2045 int retval;
2046
2048 op,
2052 nullptr,
2054 event->type);
2055
2056 const Scene &scene = *CTX_data_scene(C);
2058
2059 undo::push_begin_ex(scene, ob, "Vertex Paint");
2060
2061 if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
2063 return OPERATOR_FINISHED;
2064 }
2065
2067
2068 OPERATOR_RETVAL_CHECK(retval);
2070
2072}
2073
2075{
2077 op,
2081 nullptr,
2083 0);
2084
2086
2087 return OPERATOR_FINISHED;
2088}
2089
2091{
2093 MEM_delete(ob.sculpt->cache);
2094 ob.sculpt->cache = nullptr;
2095
2097}
2098
2099static int vpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
2100{
2101 return paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata);
2102}
2103
2105{
2106 ot->name = "Vertex Paint";
2107 ot->idname = "PAINT_OT_vertex_paint";
2108 ot->description = "Paint a stroke in the active color attribute layer";
2109
2112 ot->exec = vpaint_exec;
2115
2117
2119}
2120
2123/* -------------------------------------------------------------------- */
2127namespace blender::ed::sculpt_paint {
2128
2129template<typename T>
2131 const T &value,
2132 const AttrDomain domain,
2133 const int cd_offset,
2134 const bool use_vert_sel)
2135{
2136 BMFace *f;
2137 BMIter iter;
2138 BM_ITER_MESH (f, &iter, &bm, BM_FACES_OF_MESH) {
2139 BMLoop *l = f->l_first;
2140 do {
2141 if (!(use_vert_sel && !BM_elem_flag_test(l->v, BM_ELEM_SELECT))) {
2142 if (domain == AttrDomain::Corner) {
2143 *static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset)) = value;
2144 }
2145 else if (domain == AttrDomain::Point) {
2146 *static_cast<T *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset)) = value;
2147 }
2148 }
2149 } while ((l = l->next) != f->l_first);
2150 }
2151}
2152
2153template<typename T>
2155 const T &value,
2156 const AttrDomain domain,
2157 const MutableSpan<T> data,
2158 const bool use_vert_sel,
2159 const bool use_face_sel,
2160 const bool affect_alpha)
2161{
2162 const bke::AttributeAccessor attributes = mesh.attributes();
2163 VArraySpan<bool> select_vert;
2164 if (use_vert_sel) {
2165 select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
2166 }
2167 VArraySpan<bool> select_poly;
2168 if (use_face_sel) {
2169 select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
2170 }
2171
2172 const OffsetIndices faces = mesh.faces();
2173 const Span<int> corner_verts = mesh.corner_verts();
2174
2175 for (const int i : faces.index_range()) {
2176 if (!select_poly.is_empty() && !select_poly[i]) {
2177 continue;
2178 }
2179 for (const int corner : faces[i]) {
2180 const int vert = corner_verts[corner];
2181 if (!select_vert.is_empty() && !select_vert[vert]) {
2182 continue;
2183 }
2184 const int data_index = domain == AttrDomain::Corner ? corner : vert;
2185 data[data_index].r = value.r;
2186 data[data_index].g = value.g;
2187 data[data_index].b = value.b;
2188 if (affect_alpha) {
2189 data[data_index].a = value.a;
2190 }
2191 }
2192 }
2193
2195}
2196
2197static void fill_mesh_color(Mesh &mesh,
2198 const ColorPaint4f &color,
2199 const StringRef attribute_name,
2200 const bool use_vert_sel,
2201 const bool use_face_sel,
2202 const bool affect_alpha)
2203{
2204 if (BMEditMesh *em = mesh.runtime->edit_mesh.get()) {
2205 BMesh *bm = em->bm;
2206 const std::string name = attribute_name;
2207 const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh.id, name.c_str());
2208 AttributeOwner owner = AttributeOwner::from_id(&mesh.id);
2209 const AttrDomain domain = BKE_attribute_domain(owner, layer);
2210 if (layer->type == CD_PROP_COLOR) {
2212 *bm, color, domain, layer->offset, use_vert_sel);
2213 }
2214 else if (layer->type == CD_PROP_BYTE_COLOR) {
2216 *bm, color.encode(), domain, layer->offset, use_vert_sel);
2217 }
2218 }
2219 else {
2220 bke::GSpanAttributeWriter attribute = mesh.attributes_for_write().lookup_for_write_span(
2221 attribute_name);
2222 if (attribute.span.type().is<ColorGeometry4f>()) {
2224 mesh,
2225 color,
2226 attribute.domain,
2227 attribute.span.typed<ColorGeometry4f>().cast<ColorPaint4f>(),
2228 use_vert_sel,
2229 use_face_sel,
2230 affect_alpha);
2231 }
2232 else if (attribute.span.type().is<ColorGeometry4b>()) {
2234 mesh,
2235 color.encode(),
2236 attribute.domain,
2237 attribute.span.typed<ColorGeometry4b>().cast<ColorPaint4b>(),
2238 use_vert_sel,
2239 use_face_sel,
2240 affect_alpha);
2241 }
2242 attribute.finish();
2243 }
2244}
2245
2247 ColorPaint4f fill_color,
2248 bool only_selected = true,
2249 bool affect_alpha = true)
2250{
2251 Mesh *mesh = BKE_mesh_from_object(&ob);
2252 if (!mesh) {
2253 return false;
2254 }
2255
2256 const bool use_face_sel = only_selected ? (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) != 0 : false;
2257 const bool use_vert_sel = only_selected ? (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) != 0 : false;
2259 *mesh, fill_color, mesh->active_color_attribute, use_vert_sel, use_face_sel, affect_alpha);
2260
2262
2263 /* NOTE: Original mesh is used for display, so tag it directly here. */
2265
2266 return true;
2267}
2268
2269bool object_active_color_fill(Object &ob, const float fill_color[4], bool only_selected)
2270{
2271 return fill_active_color(ob, ColorPaint4f(fill_color), only_selected);
2272}
2273
2274} // namespace blender::ed::sculpt_paint
2275
2277{
2278 using namespace blender::ed::sculpt_paint;
2279 Scene &scene = *CTX_data_scene(C);
2280 Object &obact = *CTX_data_active_object(C);
2281 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
2282 if (!BKE_mesh_from_object(&obact)) {
2283 return OPERATOR_CANCELLED;
2284 }
2285
2286 ColorPaint4f paintcol = vpaint_get_current_col(scene, *scene.toolsettings->vpaint, false);
2287 const bool affect_alpha = RNA_boolean_get(op->ptr, "use_alpha");
2288
2289 /* Ensure valid sculpt state. */
2291
2292 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(obact);
2293
2294 undo::push_begin(scene, obact, op);
2295 IndexMaskMemory memory;
2296 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
2297
2298 undo::push_nodes(depsgraph, obact, node_mask, undo::Type::Color);
2299
2300 Mesh &mesh = *static_cast<Mesh *>(obact.data);
2301
2302 fill_active_color(obact, paintcol, true, affect_alpha);
2303
2304 pbvh.tag_attribute_changed(node_mask, mesh.active_color_attribute);
2305 undo::push_end(obact);
2306
2308 return OPERATOR_FINISHED;
2309}
2310
2312{
2313 ot->name = "Set Vertex Colors";
2314 ot->idname = "PAINT_OT_vertex_color_set";
2315 ot->description = "Fill the active vertex color layer with the current paint color";
2316
2319
2321
2323 "use_alpha",
2324 true,
2325 "Affect Alpha",
2326 "Set color completely opaque instead of reusing existing alpha");
2327}
2328
const struct CustomDataLayer * BKE_id_attributes_color_find(const struct ID *id, const char *name)
bool BKE_color_attribute_supported(const struct Mesh &mesh, const blender::StringRef name)
blender::bke::AttrDomain BKE_attribute_domain(const AttributeOwner &owner, const struct CustomDataLayer *layer)
const MTex * BKE_brush_mask_texture_get(const Brush *brush, const eObjectMode object_mode)
Definition brush.cc:762
bool BKE_brush_use_alpha_pressure(const Brush *brush)
Definition brush.cc:1096
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1075
void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
Definition brush.cc:1120
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
Definition brush.cc:1059
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:778
const float * BKE_brush_secondary_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1037
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1091
float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1153
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1029
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:1048
void BKE_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode)
void BKE_mesh_tessface_clear(Mesh *mesh)
Mesh * BKE_mesh_from_object(Object *ob)
@ BKE_MESH_BATCH_DIRTY_ALL
Definition BKE_mesh.h:38
General operations, lookup, etc. for blender objects.
void BKE_object_free_derived_caches(Object *ob)
Functions for dealing with objects and deform verts, used by painting and tools.
bool BKE_paint_brush_set_essentials(Main *bmain, Paint *paint, const char *name)
Definition paint.cc:1102
PaintMode
Definition BKE_paint.hh:99
bool BKE_paint_brush_set(Paint *paint, Brush *brush)
Definition paint.cc:714
void BKE_sculptsession_free(Object *ob)
Definition paint.cc:2145
const uchar PAINT_CURSOR_WEIGHT_PAINT[3]
Definition paint.cc:245
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
Paint * BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
Definition paint.cc:371
void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3], bool ensure_brushes=true)
Definition paint.cc:1779
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
Definition paint.cc:1685
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
void BKE_sculpt_toolsettings_data_ensure(Main *bmain, Scene *scene)
Definition paint.cc:2678
const uchar PAINT_CURSOR_VERTEX_PAINT[3]
Definition paint.cc:244
void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
Definition paint.cc:1108
Generic array manipulation API.
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define M_PI_2
#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:683
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])
#define RAD2DEGF(_rad)
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:181
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ 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_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:423
void ED_mesh_mirror_topo_table_end(Object *ob)
Definition meshtools.cc:857
void ED_mesh_mirror_spatial_table_end(Object *ob)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
eV3DProjTest
Definition ED_view3d.hh:265
@ V3D_PROJ_TEST_CLIP_NEAR
Definition ED_view3d.hh:269
@ V3D_PROJ_TEST_CLIP_BB
Definition ED_view3d.hh:267
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:243
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:125
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
IMB_BlendMode
Definition IMB_imbuf.hh:186
@ IMB_BLEND_ERASE_ALPHA
Definition IMB_imbuf.hh:193
@ IMB_BLEND_ADD_ALPHA
Definition IMB_imbuf.hh:194
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DRAW
Definition WM_types.hh:428
#define ND_MODE
Definition WM_types.hh:412
#define NC_SCENE
Definition WM_types.hh:345
#define NC_OBJECT
Definition WM_types.hh:346
@ 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
ATTR_WARN_UNUSED_RESULT BMesh * bm
ATTR_WARN_UNUSED_RESULT const BMLoop * l
SIMD_FORCE_INLINE bool isZero() const
Definition btVector3.h:683
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
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
ChannelStorageType r
Definition BLI_color.hh:88
ChannelStorageType g
Definition BLI_color.hh:88
ChannelStorageType b
Definition BLI_color.hh:88
ChannelStorageType a
Definition BLI_color.hh:88
ColorSceneLinearByteEncoded4b< Alpha > encode() const
Definition BLI_color.hh:163
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr bool is_empty() const
Definition BLI_span.hh:261
void resize(const int64_t new_size)
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:593
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
#define cosf(x)
#define acosf(x)
#define sqrtf(x)
draw_view in_light_buf[] float
static float verts[][3]
uint col
#define LOG(severity)
Definition log.h:33
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
int face_find_corner_from_vert(const IndexRange face, const Span< int > corner_verts, const int vert)
Definition BKE_mesh.hh:264
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
IndexMask search_nodes(const Tree &pbvh, IndexMaskMemory &memory, FunctionRef< bool(const Node &)> filter_fn)
Definition pbvh.cc:2647
void update_bounds(const Depsgraph &depsgraph, const Object &object, Tree &pbvh)
Definition pbvh.cc:1183
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2612
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2502
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
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)
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
void push_begin_ex(const Scene &, Object &ob, const char *name)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
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])
int paint_stroke_exec(bContext *C, wmOperator *op, PaintStroke *stroke)
bool node_in_sphere(const bke::pbvh::Node &node, const float3 &location, const float radius_sq, const bool original)
Definition sculpt.cc:2326
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:2337
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6889
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6772
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 calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert_indices, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:6722
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)
std::optional< float3 > calc_area_normal(const Depsgraph &depsgraph, const Brush &brush, const Object &ob, const IndexMask &node_mask)
Definition sculpt.cc:1848
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)
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintStroke **stroke_p)
void * paint_stroke_mode_data(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:6442
void paint_stroke_set_mode_data(PaintStroke *stroke, std::unique_ptr< PaintModeData > mode_data)
ColorSceneLinear4f< eAlpha::Straight > ColorPaint4f
Definition BLI_color.hh:339
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
VecBase< float, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
Definition BLI_color.hh:338
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)
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 int vertex_color_set_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 int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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 int vpaint_exec(bContext *C, wmOperator *op)
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 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)
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 CLG_LogRef LOG
static Color fromFloat(const ColorPaint4f &c)
void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
static int vpaint_modal(bContext *C, wmOperator *op, const wmEvent *event)
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)
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)
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:186
bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2], bool force_original)
Definition sculpt.cc:4732
const float * SCULPT_brush_frontface_normal_from_falloff_shape(const SculptSession &ss, char falloff_shape)
Definition sculpt.cc:1212
void SCULPT_cache_calc_brushdata_symm(blender::ed::sculpt_paint::StrokeCache &cache, const ePaintSymmetryFlags symm, const char axis, const float angle)
Definition sculpt.cc:3346
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:2067
BMLoop * l_first
struct BMVert * v
struct BMLoop * next
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:413
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]
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
blender::Array< MDeformVert > dvert_prev
Definition BKE_paint.hh:481
float * alpha_weight
Definition BKE_paint.hh:477
struct SculptSession::@49 mode
eObjectMode mode_type
Definition BKE_paint.hh:487
struct SculptSession::@49::@50 wpaint
bool building_vp_handle
Definition BKE_paint.hh:491
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::@471 smear
ColorPaint4f paintcol
NormalAnglePrecalc normal_angle_precalc
GArray prev_colors
ViewContext vc
int radial_symm[3]
RegionView3D * rv3d
Definition ED_view3d.hh:76
ARegion * region
Definition ED_view3d.hh:73
Scene * scene
Definition ED_view3d.hh:69
Object * obact
Definition ED_view3d.hh:71
Depsgraph * depsgraph
Definition ED_view3d.hh:68
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
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:4126
wmOperatorType * ot
Definition wm_files.cc:4125
#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)