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
13
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/* -------------------------------------------------------------------- */
98
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/* -------------------------------------------------------------------- */
140
141void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal)
142{
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);
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);
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;
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
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
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;
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
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{
572 add_v3_v3(ups.average_stroke_accum, location);
573 ups.last_stroke_valid = true;
574}
575
576/* -------------------------------------------------------------------- */
577
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. */
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}
602
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{
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
756
757/* -------------------------------------------------------------------- */
760
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
774
775/* -------------------------------------------------------------------- */
778
788
790
791/* -------------------------------------------------------------------- */
794
799{
800 Main &bmain = *CTX_data_main(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
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
854
855/* -------------------------------------------------------------------- */
858
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 {
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() */
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,
1043 const IndexMask &node_mask,
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,
1198 const IndexMask &node_mask,
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
1339 const VPaint &vp,
1340 VPaintData &vpd,
1341 Object &ob,
1342 Mesh &mesh,
1344 const IndexMask &node_mask,
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,
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,
1668 const IndexMask &node_mask,
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,
1832 const IndexMask &node_mask,
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,
1850 const IndexMask &node_mask)
1851{
1852 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
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;
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
2110 ot->invoke = vpaint_invoke;
2111 ot->modal = vpaint_modal;
2112 ot->exec = vpaint_exec;
2113 ot->poll = vertex_paint_poll;
2114 ot->cancel = vpaint_cancel;
2115
2116 ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
2117
2119}
2120
2122
2123/* -------------------------------------------------------------------- */
2126
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
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());
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{
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
2317 ot->exec = vertex_color_set_exec;
2318 ot->poll = vertex_paint_mode_poll;
2319
2320 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2321
2322 RNA_def_boolean(ot->srna,
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:274
@ V3D_PROJ_TEST_CLIP_NEAR
Definition ED_view3d.hh:278
@ V3D_PROJ_TEST_CLIP_BB
Definition ED_view3d.hh:276
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:252
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)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Color
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue Hue Saturation Value
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
#define C
Definition RandGen.cpp:29
#define ND_DRAW
Definition WM_types.hh:428
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#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
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
void resize(const int64_t new_size)
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
GAttributeReader lookup(const StringRef attribute_id) const
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Definition pbvh.cc:593
void foreach_index(Fn &&fn) const
#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
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: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:6903
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6786
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:6736
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:6456
void paint_stroke_set_mode_data(PaintStroke *stroke, std::unique_ptr< PaintModeData > mode_data)
ColorSceneLinearByteEncoded4b< eAlpha::Straight > ColorPaint4b
Definition BLI_color.hh:340
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)
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 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 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
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]
struct ToolSettings * toolsettings
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
struct SculptSession::@254261273135317060024017237233241042170104042124 mode
blender::Array< MDeformVert > dvert_prev
Definition BKE_paint.hh:481
float * alpha_weight
Definition BKE_paint.hh:477
eObjectMode mode_type
Definition BKE_paint.hh:487
struct SculptSession::@254261273135317060024017237233241042170104042124::@371103373316252122004227004340313020053342354301 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
ColorPaint4f paintcol
struct VPaintData::@341330046143040350365232142014327335313250000335 smear
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
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
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)