Blender V4.5
paint_cursor.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 by Nicholas Bishop. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_listbase.h"
15#include "BLI_math_matrix.hh"
16#include "BLI_math_rotation.h"
17#include "BLI_rect.h"
18#include "BLI_task.h"
19#include "BLI_utildefines.h"
20
21#include "DNA_brush_types.h"
22#include "DNA_material_types.h"
23#include "DNA_mesh_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26#include "DNA_screen_types.h"
27#include "DNA_space_types.h"
28#include "DNA_userdef_types.h"
29#include "DNA_view3d_types.h"
30
31#include "BKE_brush.hh"
32#include "BKE_colortools.hh"
33#include "BKE_context.hh"
34#include "BKE_curve.hh"
35#include "BKE_grease_pencil.hh"
36#include "BKE_image.hh"
37#include "BKE_node_runtime.hh"
38#include "BKE_object.hh"
39#include "BKE_paint.hh"
40#include "BKE_screen.hh"
41
42#include "NOD_texture.h"
43
44#include "WM_api.hh"
45#include "WM_toolsystem.hh"
46#include "wm_cursors.hh"
47
49#include "IMB_imbuf_types.hh"
50
51#include "ED_grease_pencil.hh"
52#include "ED_image.hh"
53#include "ED_view3d.hh"
54
55#include "GPU_immediate.hh"
56#include "GPU_immediate_util.hh"
57#include "GPU_matrix.hh"
58#include "GPU_state.hh"
59#include "GPU_texture.hh"
60
61#include "UI_resources.hh"
62
63#include "paint_intern.hh"
64#include "sculpt_boundary.hh"
65#include "sculpt_cloth.hh"
66#include "sculpt_expand.hh"
67/* still needed for sculpt_stroke_get_location, should be
68 * removed eventually (TODO) */
69#include "sculpt_intern.hh"
70#include "sculpt_pose.hh"
71
72#include "bmesh.hh"
73
74/* Needed for determining tool material/vertex-color pinning. */
76
77#include "brushes/brushes.hh"
78
79/* TODOs:
80 *
81 * Some of the cursor drawing code is doing non-draw stuff
82 * (e.g. updating the brush rake angle). This should be cleaned up
83 * still.
84 *
85 * There is also some ugliness with sculpt-specific code.
86 */
87
89 GPUTexture *overlay_texture;
90 int winx;
91 int winy;
93 float old_zoom;
94 bool old_col;
95};
96
98 GPUTexture *overlay_texture;
99 int size;
100 int zoom;
102};
103
104static TexSnapshot primary_snap = {nullptr};
105static TexSnapshot secondary_snap = {nullptr};
106static CursorSnapshot cursor_snap = {nullptr};
107
109{
110 if (primary_snap.overlay_texture) {
111 GPU_texture_free(primary_snap.overlay_texture);
112 }
113 if (secondary_snap.overlay_texture) {
114 GPU_texture_free(secondary_snap.overlay_texture);
115 }
116 if (cursor_snap.overlay_texture) {
117 GPU_texture_free(cursor_snap.overlay_texture);
118 }
119
120 memset(&primary_snap, 0, sizeof(TexSnapshot));
121 memset(&secondary_snap, 0, sizeof(TexSnapshot));
122 memset(&cursor_snap, 0, sizeof(CursorSnapshot));
123
125}
126
128
129static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom)
130{
131 return (/* make brush smaller shouldn't cause a resample */
132 //(mtex->brush_map_mode != MTEX_MAP_MODE_VIEW ||
133 //(BKE_brush_size_get(vc->scene, brush) <= snap->BKE_brush_size_get)) &&
134
136 (vc->region->winx == snap->winx && vc->region->winy == snap->winy)) &&
137 (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL || snap->old_zoom == zoom) &&
138 snap->old_col == col);
139}
140
141static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
142{
143 snap->old_zoom = zoom;
144 snap->winx = vc->region->winx;
145 snap->winy = vc->region->winy;
146}
147
161
162static void load_tex_task_cb_ex(void *__restrict userdata,
163 const int j,
164 const TaskParallelTLS *__restrict tls)
165{
166 LoadTexData *data = static_cast<LoadTexData *>(userdata);
167 Brush *br = data->br;
168 ViewContext *vc = data->vc;
169
170 MTex *mtex = data->mtex;
171 uchar *buffer = data->buffer;
172 const bool col = data->col;
173
174 ImagePool *pool = data->pool;
175 const int size = data->size;
176 const float rotation = data->rotation;
177 const float radius = data->radius;
178
179 bool convert_to_linear = false;
180 const ColorSpace *colorspace = nullptr;
181
182 const int thread_id = BLI_task_parallel_thread_id(tls);
183
184 if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
185 ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
186 /* For consistency, sampling always returns color in linear space. */
187 if (tex_ibuf && tex_ibuf->float_buffer.data == nullptr) {
188 convert_to_linear = true;
189 colorspace = tex_ibuf->byte_buffer.colorspace;
190 }
191 BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
192 }
193
194 for (int i = 0; i < size; i++) {
195 /* Largely duplicated from tex_strength. */
196
197 int index = j * size + i;
198
199 float x = float(i) / size;
200 float y = float(j) / size;
201 float len;
202
203 if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
204 x *= vc->region->winx / radius;
205 y *= vc->region->winy / radius;
206 }
207 else {
208 x = (x - 0.5f) * 2.0f;
209 y = (y - 0.5f) * 2.0f;
210 }
211
212 len = sqrtf(x * x + y * y);
213
215 /* It is probably worth optimizing for those cases where the texture is not rotated by
216 * skipping the calls to atan2, sqrtf, sin, and cos. */
217 if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
218 const float angle = atan2f(y, x) + rotation;
219
220 x = len * cosf(angle);
221 y = len * sinf(angle);
222 }
223
224 float avg;
225 float rgba[4];
226 paint_get_tex_pixel(mtex, x, y, pool, thread_id, &avg, rgba);
227
228 if (col) {
229 if (convert_to_linear) {
231 }
232
233 linearrgb_to_srgb_v3_v3(rgba, rgba);
234
235 clamp_v4(rgba, 0.0f, 1.0f);
236
237 buffer[index * 4] = rgba[0] * 255;
238 buffer[index * 4 + 1] = rgba[1] * 255;
239 buffer[index * 4 + 2] = rgba[2] * 255;
240 buffer[index * 4 + 3] = rgba[3] * 255;
241 }
242 else {
243 avg += br->texture_sample_bias;
244
245 /* Clamp to avoid precision overflow. */
246 CLAMP(avg, 0.0f, 1.0f);
247 buffer[index] = 255 - uchar(255 * avg);
248 }
249 }
250 else {
251 if (col) {
252 buffer[index * 4] = 0;
253 buffer[index * 4 + 1] = 0;
254 buffer[index * 4 + 2] = 0;
255 buffer[index * 4 + 3] = 0;
256 }
257 else {
258 buffer[index] = 0;
259 }
260 }
261 }
262}
263
264static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary)
265{
266 bool init;
267 TexSnapshot *target;
268
269 MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
271 uchar *buffer = nullptr;
272
273 int size;
274 bool refresh;
278 target = (primary) ? &primary_snap : &secondary_snap;
279
280 refresh = !target->overlay_texture || (invalid != 0) ||
281 !same_tex_snap(target, mtex, vc, col, zoom);
282
283 init = (target->overlay_texture != nullptr);
284
285 if (refresh) {
286 ImagePool *pool = nullptr;
287 /* Stencil is rotated later. */
288 const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
289 const float radius = BKE_brush_size_get(vc->scene, br) * zoom;
290
291 make_tex_snap(target, vc, zoom);
292
293 if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
294 int s = BKE_brush_size_get(vc->scene, br);
295 int r = 1;
296
297 for (s >>= 1; s > 0; s >>= 1) {
298 r++;
299 }
300
301 size = (1 << r);
302
303 size = std::max(size, 256);
304 size = std::max(size, target->old_size);
305 }
306 else {
307 size = 512;
308 }
309
310 if (target->old_size != size || target->old_col != col) {
311 if (target->overlay_texture) {
313 target->overlay_texture = nullptr;
314 }
315 init = false;
316
317 target->old_size = size;
318 target->old_col = col;
319 }
320 if (col) {
321 buffer = MEM_malloc_arrayN<uchar>(size * size * 4, "load_tex");
322 }
323 else {
324 buffer = MEM_malloc_arrayN<uchar>(size * size, "load_tex");
325 }
326
327 pool = BKE_image_pool_new();
328
329 if (mtex->tex && mtex->tex->nodetree) {
330 /* Has internal flag to detect it only does it once. */
332 }
333
335 data.br = br;
336 data.vc = vc;
337 data.mtex = mtex;
338 data.buffer = buffer;
339 data.col = col;
340 data.pool = pool;
341 data.size = size;
342 data.rotation = rotation;
343 data.radius = radius;
344
345 TaskParallelSettings settings;
348
349 if (mtex->tex && mtex->tex->nodetree) {
350 ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
351 }
352
353 if (pool) {
355 }
356
357 if (!target->overlay_texture) {
361 "paint_cursor_overlay", size, size, 1, format, usage, nullptr);
363
364 if (!col) {
366 }
367 }
368
369 if (init) {
371 }
372
373 if (buffer) {
374 MEM_freeN(buffer);
375 }
376 }
377 else {
378 size = target->old_size;
379 }
380
382
383 return 1;
384}
385
386static void load_tex_cursor_task_cb(void *__restrict userdata,
387 const int j,
388 const TaskParallelTLS *__restrict /*tls*/)
389{
390 LoadTexData *data = static_cast<LoadTexData *>(userdata);
391 Brush *br = data->br;
392
393 uchar *buffer = data->buffer;
394
395 const int size = data->size;
396
397 for (int i = 0; i < size; i++) {
398 /* Largely duplicated from tex_strength. */
399
400 const int index = j * size + i;
401 const float x = ((float(i) / size) - 0.5f) * 2.0f;
402 const float y = ((float(j) / size) - 0.5f) * 2.0f;
403 const float len = sqrtf(x * x + y * y);
404
405 if (len <= 1.0f) {
406
407 /* Falloff curve. */
408 float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f);
409
410 buffer[index] = uchar(255 * avg);
411 }
412 else {
413 buffer[index] = 0;
414 }
415 }
416}
417
418static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
419{
420 bool init;
421
423 uchar *buffer = nullptr;
424
425 int size;
426 const bool refresh = !cursor_snap.overlay_texture ||
428 cursor_snap.curve_preset != br->curve_preset;
429
430 init = (cursor_snap.overlay_texture != nullptr);
431
432 if (refresh) {
433 int s, r;
434
435 cursor_snap.zoom = zoom;
436
437 s = BKE_brush_size_get(vc->scene, br);
438 r = 1;
439
440 for (s >>= 1; s > 0; s >>= 1) {
441 r++;
442 }
443
444 size = (1 << r);
445
446 size = std::max(size, 256);
447 size = std::max(size, cursor_snap.size);
448
449 if (cursor_snap.size != size) {
450 if (cursor_snap.overlay_texture) {
451 GPU_texture_free(cursor_snap.overlay_texture);
452 cursor_snap.overlay_texture = nullptr;
453 }
454
455 init = false;
456
457 cursor_snap.size = size;
458 }
459 buffer = MEM_malloc_arrayN<uchar>(size * size, "load_tex");
460
462
464 data.br = br;
465 data.buffer = buffer;
466 data.size = size;
467
468 TaskParallelSettings settings;
471
472 if (!cursor_snap.overlay_texture) {
474 cursor_snap.overlay_texture = GPU_texture_create_2d(
475 "cursor_snap_overaly", size, size, 1, GPU_R8, usage, nullptr);
476 GPU_texture_update(cursor_snap.overlay_texture, GPU_DATA_UBYTE, buffer);
477
478 GPU_texture_swizzle_set(cursor_snap.overlay_texture, "rrrr");
479 }
480
481 if (init) {
482 GPU_texture_update(cursor_snap.overlay_texture, GPU_DATA_UBYTE, buffer);
483 }
484
485 if (buffer) {
486 MEM_freeN(buffer);
487 }
488 }
489 else {
490 size = cursor_snap.size;
491 }
492
493 cursor_snap.curve_preset = br->curve_preset;
495
496 return 1;
497}
498
499static int project_brush_radius(ViewContext *vc, float radius, const float location[3])
500{
501 float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
502
503 ED_view3d_global_to_vector(vc->rv3d, location, view);
504
505 /* Create a vector that is not orthogonal to view. */
506
507 if (fabsf(view[0]) < 0.1f) {
508 nonortho[0] = view[0] + 1.0f;
509 nonortho[1] = view[1];
510 nonortho[2] = view[2];
511 }
512 else if (fabsf(view[1]) < 0.1f) {
513 nonortho[0] = view[0];
514 nonortho[1] = view[1] + 1.0f;
515 nonortho[2] = view[2];
516 }
517 else {
518 nonortho[0] = view[0];
519 nonortho[1] = view[1];
520 nonortho[2] = view[2] + 1.0f;
521 }
522
523 /* Get a vector in the plane of the view. */
524 cross_v3_v3v3(ortho, nonortho, view);
525 normalize_v3(ortho);
526
527 /* Make a point on the surface of the brush tangent to the view. */
528 mul_v3_fl(ortho, radius);
529 add_v3_v3v3(offset, location, ortho);
530
531 /* Project the center of the brush, and the tangent point to the view onto the screen. */
536 {
537 /* The distance between these points is the size of the projected brush in pixels. */
538 return len_v2v2(p1, p2);
539 }
540 /* Assert because the code that sets up the vectors should disallow this. */
541 BLI_assert(0);
542 return 0;
543}
544
546 const float radius,
547 const float3 world_location,
548 const float4x4 &to_world)
549{
550 const float2 xy_delta = float2(1.0f, 0.0f);
551
552 bool z_flip;
553 const float zfac = ED_view3d_calc_zfac_ex(vc->rv3d, world_location, &z_flip);
554 if (z_flip) {
555 /* Location is behind camera. Return 0 to make the cursor disappear. */
556 return 0;
557 }
558 float3 delta;
559 ED_view3d_win_to_delta(vc->region, xy_delta, zfac, delta);
560
561 const float scale = math::length(
563 return math::safe_divide(scale * radius, math::length(delta));
564}
565
566/* Draw an overlay that shows what effect the brush's texture will
567 * have on brush strength. */
569 Brush *brush,
570 ViewContext *vc,
571 int x,
572 int y,
573 float zoom,
574 const PaintMode mode,
575 bool col,
576 bool primary)
577{
578 rctf quad;
579 /* Check for overlay mode. */
580
581 MTex *mtex = (primary) ? &brush->mtex : &brush->mask_mtex;
582 bool valid = ((primary) ? (brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) != 0 :
583 (brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0);
584 int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha;
585
586 if (mode == PaintMode::Texture3D) {
587 if (primary && brush->image_brush_type != IMAGE_PAINT_BRUSH_TYPE_DRAW) {
588 /* All non-draw tools don't use the primary texture (clone, smear, soften.. etc). */
589 return false;
590 }
591 }
592
593 if (!(mtex->tex) ||
596 {
597 return false;
598 }
599
601 return false;
602 }
603
604 if (load_tex(brush, vc, zoom, col, primary)) {
605 GPU_color_mask(true, true, true, true);
607
608 if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
610
611 float center[2] = {
612 ups->draw_anchored ? ups->anchored_initial_mouse[0] : x,
613 ups->draw_anchored ? ups->anchored_initial_mouse[1] : y,
614 };
615
616 /* Brush rotation. */
619 GPU_matrix_translate_2f(-center[0], -center[1]);
620
621 /* Scale based on tablet pressure. */
622 if (primary && ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
623 const float scale = ups->size_pressure_value;
625 GPU_matrix_scale_2f(scale, scale);
626 GPU_matrix_translate_2f(-center[0], -center[1]);
627 }
628
629 if (ups->draw_anchored) {
630 quad.xmin = center[0] - ups->anchored_size;
631 quad.ymin = center[1] - ups->anchored_size;
632 quad.xmax = center[0] + ups->anchored_size;
633 quad.ymax = center[1] + ups->anchored_size;
634 }
635 else {
636 const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
637 quad.xmin = center[0] - radius;
638 quad.ymin = center[1] - radius;
639 quad.xmax = center[0] + radius;
640 quad.ymax = center[1] + radius;
641 }
642 }
643 else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
644 quad.xmin = 0;
645 quad.ymin = 0;
646 quad.xmax = BLI_rcti_size_x(&vc->region->winrct);
647 quad.ymax = BLI_rcti_size_y(&vc->region->winrct);
648 }
649 /* Stencil code goes here. */
650 else {
651 if (primary) {
652 quad.xmin = -brush->stencil_dimension[0];
653 quad.ymin = -brush->stencil_dimension[1];
654 quad.xmax = brush->stencil_dimension[0];
655 quad.ymax = brush->stencil_dimension[1];
656 }
657 else {
658 quad.xmin = -brush->mask_stencil_dimension[0];
659 quad.ymin = -brush->mask_stencil_dimension[1];
660 quad.xmax = brush->mask_stencil_dimension[0];
661 quad.ymax = brush->mask_stencil_dimension[1];
662 }
664 if (primary) {
666 }
667 else {
669 }
671 }
672
673 /* Set quad color. Colored overlay does not get blending. */
677
678 /* Premultiplied alpha blending. */
680
682
683 float final_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
684 if (!col) {
685 copy_v3_v3(final_color, U.sculpt_paint_overlay_col);
686 }
687 mul_v4_fl(final_color, overlay_alpha * 0.01f);
688 immUniformColor4fv(final_color);
689
690 GPUTexture *texture = (primary) ? primary_snap.overlay_texture :
691 secondary_snap.overlay_texture;
692
697 "image", texture, {GPU_SAMPLER_FILTERING_LINEAR, extend_mode, extend_mode});
698
699 /* Draw textured quad. */
701 immAttr2f(texCoord, 0.0f, 0.0f);
702 immVertex2f(pos, quad.xmin, quad.ymin);
703 immAttr2f(texCoord, 1.0f, 0.0f);
704 immVertex2f(pos, quad.xmax, quad.ymin);
705 immAttr2f(texCoord, 1.0f, 1.0f);
706 immVertex2f(pos, quad.xmax, quad.ymax);
707 immAttr2f(texCoord, 0.0f, 1.0f);
708 immVertex2f(pos, quad.xmin, quad.ymax);
709 immEnd();
710
712
714
717 }
718 }
719 return true;
720}
721
722/* Draw an overlay that shows what effect the brush's texture will
723 * have on brush strength. */
725 UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom)
726{
727 rctf quad;
728 /* Check for overlay mode. */
729
730 if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
731 return false;
732 }
733
734 if (load_tex_cursor(brush, vc, zoom)) {
735 bool do_pop = false;
736 float center[2];
737
738 GPU_color_mask(true, true, true, true);
740
741 if (ups->draw_anchored) {
743 quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
744 quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
745 quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
746 quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
747 }
748 else {
749 const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
750 center[0] = x;
751 center[1] = y;
752
753 quad.xmin = x - radius;
754 quad.ymin = y - radius;
755 quad.xmax = x + radius;
756 quad.ymax = y + radius;
757 }
758
759 /* Scale based on tablet pressure. */
760 if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
761 do_pop = true;
765 GPU_matrix_translate_2f(-center[0], -center[1]);
766 }
767
771
773
775
776 float final_color[4] = {UNPACK3(U.sculpt_paint_overlay_col), 1.0f};
777 mul_v4_fl(final_color, brush->cursor_overlay_alpha * 0.01f);
778 immUniformColor4fv(final_color);
779
780 /* Draw textured quad. */
781 immBindTextureSampler("image",
782 cursor_snap.overlay_texture,
783 {GPU_SAMPLER_FILTERING_LINEAR,
784 GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER,
785 GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER});
786
788 immAttr2f(texCoord, 0.0f, 0.0f);
789 immVertex2f(pos, quad.xmin, quad.ymin);
790 immAttr2f(texCoord, 1.0f, 0.0f);
791 immVertex2f(pos, quad.xmax, quad.ymin);
792 immAttr2f(texCoord, 1.0f, 1.0f);
793 immVertex2f(pos, quad.xmax, quad.ymax);
794 immAttr2f(texCoord, 0.0f, 1.0f);
795 immVertex2f(pos, quad.xmin, quad.ymax);
796 immEnd();
797
798 GPU_texture_unbind(cursor_snap.overlay_texture);
799
801
802 if (do_pop) {
804 }
805 }
806 return true;
807}
808
810 Brush *brush,
811 ViewContext *vc,
812 int x,
813 int y,
814 float zoom,
815 PaintMode mode)
816{
817 /* Color means that primary brush texture is colored and
818 * secondary is used for alpha/mask control. */
820
821 bool alpha_overlay_active = false;
822
824 eGPUBlend blend_state = GPU_blend_get();
825 eGPUDepthTest depth_test = GPU_depth_test_get();
826
827 /* Translate to region. */
830 x -= vc->region->winrct.xmin;
831 y -= vc->region->winrct.ymin;
832
833 /* Colored overlay should be drawn separately. */
834 if (col) {
835 if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY)) {
836 alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, mode, true, true);
837 }
838 if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY)) {
839 alpha_overlay_active = paint_draw_tex_overlay(
840 ups, brush, vc, x, y, zoom, mode, false, false);
841 }
842 if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
843 alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
844 }
845 }
846 else {
847 if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PaintMode::Weight)) {
848 alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, mode, false, true);
849 }
850 if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
851 alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
852 }
853 }
854
856 GPU_blend(blend_state);
857 GPU_depth_test(depth_test);
858
859 return alpha_overlay_active;
860}
861
863 const float sel_col[4],
864 const float pivot_col[4],
865 float *co,
866 float width,
867 bool selected)
868{
869 immUniformColor4fv(selected ? sel_col : pivot_col);
870
871 GPU_line_width(3.0f);
872
873 float w = width / 2.0f;
874 const float tri[3][2] = {
875 {co[0], co[1] + w},
876 {co[0] - w, co[1] - w},
877 {co[0] + w, co[1] - w},
878 };
879
881 immVertex2fv(pos, tri[0]);
882 immVertex2fv(pos, tri[1]);
883 immVertex2fv(pos, tri[2]);
884 immEnd();
885
886 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
887 GPU_line_width(1.0f);
888
890 immVertex2fv(pos, tri[0]);
891 immVertex2fv(pos, tri[1]);
892 immVertex2fv(pos, tri[2]);
893 immEnd();
894}
895
897 const float sel_col[4],
898 const float handle_col[4],
899 const float *co,
900 float width,
901 bool selected)
902{
903 immUniformColor4fv(selected ? sel_col : handle_col);
904
905 GPU_line_width(3.0f);
906
907 float w = width / 2.0f;
908 float minx = co[0] - w;
909 float miny = co[1] - w;
910 float maxx = co[0] + w;
911 float maxy = co[1] + w;
912
913 imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
914
915 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
916 GPU_line_width(1.0f);
917
918 imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
919}
920
921BLI_INLINE void draw_bezier_handle_lines(uint pos, const float sel_col[4], BezTriple *bez)
922{
923 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
924 GPU_line_width(3.0f);
925
927 immVertex2fv(pos, bez->vec[0]);
928 immVertex2fv(pos, bez->vec[1]);
929 immVertex2fv(pos, bez->vec[2]);
930 immEnd();
931
932 GPU_line_width(1.0f);
933
934 if (bez->f1 || bez->f2) {
935 immUniformColor4fv(sel_col);
936 }
937 else {
938 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
939 }
941 immVertex2fv(pos, bez->vec[0]);
942 immVertex2fv(pos, bez->vec[1]);
943 immEnd();
944
945 if (bez->f3 || bez->f2) {
946 immUniformColor4fv(sel_col);
947 }
948 else {
949 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
950 }
952 immVertex2fv(pos, bez->vec[1]);
953 immVertex2fv(pos, bez->vec[2]);
954 immEnd();
955}
956
958{
961
962 if (brush->paint_curve && brush->paint_curve->points) {
963 PaintCurve *pc = brush->paint_curve;
964 PaintCurvePoint *cp = pc->points;
965
966 GPU_line_smooth(true);
968
969 /* Draw the bezier handles and the curve segment between the current and next point. */
971
973
974 float selec_col[4], handle_col[4], pivot_col[4];
978
979 for (int i = 0; i < pc->tot_points - 1; i++, cp++) {
980 int j;
981 PaintCurvePoint *cp_next = cp + 1;
982 float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
983 /* Use color coding to distinguish handles vs curve segments. */
984 draw_bezier_handle_lines(pos, selec_col, &cp->bez);
985 draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
987 pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
989 pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
990
991 for (j = 0; j < 2; j++) {
993 cp->bez.vec[2][j],
994 cp_next->bez.vec[0][j],
995 cp_next->bez.vec[1][j],
996 data + j,
998 sizeof(float[2]));
999 }
1000
1001 float(*v)[2] = (float(*)[2])data;
1002
1003 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
1004 GPU_line_width(3.0f);
1006 for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
1007 immVertex2fv(pos, v[j]);
1008 }
1009 immEnd();
1010
1011 immUniformColor4f(0.9f, 0.9f, 1.0f, 0.5f);
1012 GPU_line_width(1.0f);
1014 for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
1015 immVertex2fv(pos, v[j]);
1016 }
1017 immEnd();
1018 }
1019
1020 /* Draw last line segment. */
1021 draw_bezier_handle_lines(pos, selec_col, &cp->bez);
1022 draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
1024 pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
1026 pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
1027
1029 GPU_line_smooth(false);
1030
1032 }
1034}
1035
1036/* Special actions taken when paint cursor goes over mesh */
1037/* TODO: sculpt only for now. */
1039 Brush &brush,
1040 const ViewContext &vc,
1041 const float location[3])
1042{
1043
1044 /* Update the brush's cached 3D radius. */
1045 if (!BKE_brush_use_locked_size(vc.scene, &brush)) {
1046 float projected_radius;
1047 /* Get 2D brush radius. */
1048 if (ups.draw_anchored) {
1049 projected_radius = ups.anchored_size;
1050 }
1051 else {
1052 if (brush.flag & BRUSH_ANCHORED) {
1053 projected_radius = 8;
1054 }
1055 else {
1056 projected_radius = BKE_brush_size_get(vc.scene, &brush);
1057 }
1058 }
1059
1060 /* Convert brush radius from 2D to 3D. */
1061 float unprojected_radius = paint_calc_object_space_radius(vc, location, projected_radius);
1062
1063 /* Scale 3D brush radius by pressure. */
1064 if (ups.stroke_active && BKE_brush_use_size_pressure(&brush)) {
1065 unprojected_radius *= ups.size_pressure_value;
1066 }
1067
1068 /* Set cached value in either Brush or UnifiedPaintSettings. */
1069 BKE_brush_unprojected_radius_set(vc.scene, &brush, unprojected_radius);
1070 }
1071}
1072
1073static void cursor_draw_point_screen_space(const uint gpuattr,
1074 const ARegion *region,
1075 const float true_location[3],
1076 const float obmat[4][4],
1077 const int size)
1078{
1079 float translation_vertex_cursor[3], location[3];
1080 copy_v3_v3(location, true_location);
1081 mul_m4_v3(obmat, location);
1082 ED_view3d_project_v3(region, location, translation_vertex_cursor);
1083 /* Do not draw points behind the view. Z [near, far] is mapped to [-1, 1]. */
1084 if (translation_vertex_cursor[2] <= 1.0f) {
1086 gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
1087 }
1088}
1089
1090static void cursor_draw_tiling_preview(const uint gpuattr,
1091 const ARegion *region,
1092 const float true_location[3],
1093 const Sculpt &sd,
1094 const Object &ob,
1095 const float radius)
1096{
1097 BLI_assert(ob.type == OB_MESH);
1099 if (!mesh) {
1100 mesh = static_cast<const Mesh *>(ob.data);
1101 }
1102 const Bounds<float3> bounds = *mesh->bounds_min_max();
1103 float orgLoc[3], location[3];
1104 int tile_pass = 0;
1105 int start[3];
1106 int end[3];
1107 int cur[3];
1108 const float *step = sd.paint.tile_offset;
1109
1110 copy_v3_v3(orgLoc, true_location);
1111 for (int dim = 0; dim < 3; dim++) {
1112 if ((sd.paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
1113 start[dim] = (bounds.min[dim] - orgLoc[dim] - radius) / step[dim];
1114 end[dim] = (bounds.max[dim] - orgLoc[dim] + radius) / step[dim];
1115 }
1116 else {
1117 start[dim] = end[dim] = 0;
1118 }
1119 }
1120 copy_v3_v3_int(cur, start);
1121 for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
1122 for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
1123 for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
1124 if (!cur[0] && !cur[1] && !cur[2]) {
1125 /* Skip tile at orgLoc, this was already handled before all others. */
1126 continue;
1127 }
1128 tile_pass++;
1129 for (int dim = 0; dim < 3; dim++) {
1130 location[dim] = cur[dim] * step[dim] + orgLoc[dim];
1131 }
1132 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1133 }
1134 }
1135 }
1136 (void)tile_pass; /* Quiet set-but-unused warning (may be removed). */
1137}
1138
1139static void cursor_draw_point_with_symmetry(const uint gpuattr,
1140 const ARegion *region,
1141 const float true_location[3],
1142 const Sculpt &sd,
1143 const Object &ob,
1144 const float radius)
1145{
1146 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
1147 float3 location;
1148 float symm_rot_mat[4][4];
1149
1150 for (int i = 0; i <= symm; i++) {
1151 if (is_symmetry_iteration_valid(i, symm)) {
1152
1153 /* Axis Symmetry. */
1154 location = symmetry_flip(true_location, ePaintSymmetryFlags(i));
1155 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1156
1157 /* Tiling. */
1158 cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
1159
1160 /* Radial Symmetry. */
1161 for (char raxis = 0; raxis < 3; raxis++) {
1162 for (int r = 1; r < sd.radial_symm[raxis]; r++) {
1163 float angle = 2 * M_PI * r / sd.radial_symm[int(raxis)];
1164 location = symmetry_flip(true_location, ePaintSymmetryFlags(i));
1165 unit_m4(symm_rot_mat);
1166 rotate_m4(symm_rot_mat, raxis + 'X', angle);
1167 mul_m4_v3(symm_rot_mat, location);
1168
1169 cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
1170 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1171 }
1172 }
1173 }
1174 }
1175}
1176
1178 const uint gpuattr,
1179 const Brush &brush,
1180 const Object &object)
1181{
1182 if (!(brush.flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
1183 return;
1184 }
1185
1186 const SculptSession &ss = *object.sculpt;
1187 if (bke::object::pbvh_get(object)->type() != bke::pbvh::Type::Mesh) {
1188 return;
1189 }
1190
1191 if (!ss.deform_modifiers_active) {
1192 return;
1193 }
1194
1195 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
1196
1197 /* Cursor normally draws on top, but for this part we need depth tests. */
1198 const eGPUDepthTest depth_test = GPU_depth_test_get();
1199 if (!depth_test) {
1201 }
1202
1203 GPU_line_width(1.0f);
1204 if (!ss.preview_verts.is_empty()) {
1207 for (const int vert : ss.preview_verts) {
1208 immVertex3fv(gpuattr, positions[vert]);
1209 }
1210 immEnd();
1211 }
1212
1213 /* Restore depth test value. */
1214 if (!depth_test) {
1216 }
1217}
1218
1220 const Brush &brush,
1221 const float rds,
1222 const float line_width,
1223 const float3 &outline_col,
1224 const float alpha)
1225{
1226 const float4x4 cursor_trans = math::translate(float4x4::identity(),
1227 float3(0.0f, 0.0f, brush.height));
1229 GPU_matrix_mul(cursor_trans.ptr());
1230
1231 GPU_line_width(line_width);
1232 immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
1233 imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
1235}
1236
1238{
1239 switch (mode) {
1240 case PaintMode::Sculpt:
1241 case PaintMode::Vertex:
1242 case PaintMode::Weight:
1243 return false;
1250 case PaintMode::GPencil:
1251 return true;
1252 case PaintMode::Invalid:
1254 }
1255 return true;
1256}
1257
1263
1270 Depsgraph *depsgraph;
1277
1278 /* Sculpt related data. */
1281
1286
1289 float radius;
1290
1291 /* 3D view cursor position and normal. */
1295
1296 /* Cursor main colors. */
1299
1300 /* GPU attribute for drawing. */
1302
1304
1305 /* This variable is set after drawing the overlay, not on initialization. It can't be used for
1306 * checking if alpha overlay is enabled before drawing it. */
1308
1309 float zoomx;
1310 /* Coordinates in region space */
1312
1313 /* TODO: Figure out why this and mval are used interchangeably */
1315
1317
1320};
1321
1323 const blender::int2 &xy,
1324 const blender::float2 &tilt,
1325 PaintCursorContext &pcontext)
1326{
1327 ARegion *region = CTX_wm_region(C);
1328 if (region && region->regiontype != RGN_TYPE_WINDOW) {
1329 return false;
1330 }
1331
1332 pcontext.C = C;
1333 pcontext.region = region;
1334 pcontext.wm = CTX_wm_manager(C);
1335 pcontext.win = CTX_wm_window(C);
1336 pcontext.screen = CTX_wm_screen(C);
1338 pcontext.scene = CTX_data_scene(C);
1339 pcontext.ups = &pcontext.scene->toolsettings->unified_paint_settings;
1341 if (pcontext.paint == nullptr) {
1342 return false;
1343 }
1344 pcontext.brush = BKE_paint_brush(pcontext.paint);
1345 if (pcontext.brush == nullptr) {
1346 return false;
1347 }
1349
1350 pcontext.vc = ED_view3d_viewcontext_init(C, pcontext.depsgraph);
1351
1352 if (pcontext.brush->flag & BRUSH_CURVE) {
1354 }
1355 else if (paint_use_2d_cursor(pcontext.mode)) {
1357 }
1358 else {
1360 }
1361
1362 pcontext.mval = xy;
1363 pcontext.translation = {float(xy[0]), float(xy[1])};
1364 pcontext.tilt = tilt;
1365
1366 float zoomx, zoomy;
1367 get_imapaint_zoom(C, &zoomx, &zoomy);
1368 pcontext.zoomx = max_ff(zoomx, zoomy);
1369 pcontext.final_radius = (BKE_brush_size_get(pcontext.scene, pcontext.brush) * zoomx);
1370
1371 /* There is currently no way to check if the direction is inverted before starting the stroke,
1372 * so this does not reflect the state of the brush in the UI. */
1373 if (((pcontext.ups->draw_inverted == 0) ^ ((pcontext.brush->flag & BRUSH_DIR_IN) == 0)) &&
1375 {
1376 pcontext.outline_col = float3(pcontext.brush->sub_col);
1377 }
1378 else {
1379 pcontext.outline_col = float3(pcontext.brush->add_col);
1380 }
1381 pcontext.outline_alpha = pcontext.brush->add_col[3];
1382
1383 Object *active_object = pcontext.vc.obact;
1384 pcontext.ss = active_object ? active_object->sculpt : nullptr;
1385
1386 if (pcontext.ss && pcontext.ss->draw_faded_cursor) {
1387 pcontext.outline_alpha = 0.3f;
1388 pcontext.outline_col = float3(0.8f);
1389 }
1390
1391 const bool is_brush_tool = paint_brush_tool_poll(C);
1392 if (!is_brush_tool) {
1393 /* Use a default color for tools that are not brushes. */
1394 pcontext.outline_alpha = 0.8f;
1395 pcontext.outline_col = float3(0.8f);
1396 }
1397
1398 pcontext.is_stroke_active = pcontext.ups->stroke_active;
1399
1400 return true;
1401}
1402
1404{
1405 if (pcontext.is_cursor_over_mesh) {
1406 Brush *brush = BKE_paint_brush(pcontext.paint);
1408 &pcontext.vc, BKE_brush_unprojected_radius_get(pcontext.scene, brush), pcontext.location);
1409
1410 if (pcontext.pixel_radius == 0) {
1411 pcontext.pixel_radius = BKE_brush_size_get(pcontext.scene, brush);
1412 }
1413
1414 pcontext.scene_space_location = math::transform_point(pcontext.vc.obact->object_to_world(),
1415 pcontext.location);
1416 }
1417 else {
1418 Sculpt *sd = CTX_data_tool_settings(pcontext.C)->sculpt;
1419 Brush *brush = BKE_paint_brush(&sd->paint);
1420
1421 pcontext.pixel_radius = BKE_brush_size_get(pcontext.scene, brush);
1422 }
1423}
1424
1426{
1427 BLI_assert(pcontext.ss != nullptr);
1428 BLI_assert(pcontext.mode == PaintMode::Sculpt);
1429
1430 bContext *C = pcontext.C;
1431 SculptSession &ss = *pcontext.ss;
1432 Brush &brush = *pcontext.brush;
1433 Scene &scene = *pcontext.scene;
1434 UnifiedPaintSettings &ups = *pcontext.ups;
1435 ViewContext &vc = pcontext.vc;
1437
1438 const float2 mval_fl = {
1439 float(pcontext.mval.x - pcontext.region->winrct.xmin),
1440 float(pcontext.mval.y - pcontext.region->winrct.ymin),
1441 };
1442
1443 /* Ensure that the PBVH is generated before we call #cursor_geometry_info_update because
1444 * the PBVH is needed to do a ray-cast to find the active vertex. */
1445 bke::object::pbvh_ensure(*pcontext.depsgraph, *pcontext.vc.obact);
1446
1447 /* This updates the active vertex, which is needed for most of the Sculpt/Vertex Colors tools to
1448 * work correctly */
1451 if (!ups.stroke_active) {
1453 C, &gi, mval_fl, (pcontext.brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
1454 pcontext.location = gi.location;
1455 pcontext.normal = gi.normal;
1456 }
1457 else {
1458 pcontext.is_cursor_over_mesh = ups.last_hit;
1459 pcontext.location = ups.last_location;
1460 }
1461
1463
1464 if (BKE_brush_use_locked_size(&scene, &brush)) {
1465 BKE_brush_size_set(&scene, &brush, pcontext.pixel_radius);
1466 }
1467
1468 if (pcontext.is_cursor_over_mesh) {
1470 }
1471
1472 pcontext.sd = CTX_data_tool_settings(pcontext.C)->sculpt;
1473}
1474
1476{
1477 if (pcontext.win->grabcursor != 0 || pcontext.win->modalcursor != 0) {
1478 /* Don't set the cursor while it's grabbed, since this will show the cursor when interacting
1479 * with the UI (dragging a number button for example), see: #102792.
1480 * And don't overwrite a modal cursor, allowing modal operators to set a cursor temporarily. */
1481 return;
1482 }
1483
1484 /* Don't set the cursor when a temporary popup is opened (e.g. a context menu, pie menu or
1485 * dialog), see: #137386. */
1486 if (!BLI_listbase_is_empty(&pcontext.screen->regionbase) &&
1488 {
1489 return;
1490 }
1491
1493 WM_cursor_set(pcontext.win, WM_CURSOR_DOT);
1494 }
1495 else {
1497 }
1498}
1499
1501{
1503
1504 /* Draw brush outline. */
1505 if (pcontext.ups->stroke_active && BKE_brush_use_size_pressure(pcontext.brush)) {
1507 pcontext.translation[0],
1508 pcontext.translation[1],
1509 pcontext.final_radius * pcontext.ups->size_pressure_value,
1510 40);
1511 /* Outer at half alpha. */
1512 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.5f);
1513 }
1514
1515 GPU_line_width(1.0f);
1517 pcontext.pos, pcontext.translation[0], pcontext.translation[1], pcontext.final_radius, 40);
1518}
1519
1521{
1522 float radius = float(pcontext.pixel_radius);
1523
1524 /* Red-ish color with alpha. */
1525 immUniformColor4ub(255, 100, 100, 20);
1526 imm_draw_circle_fill_2d(pcontext.pos, pcontext.mval.x, pcontext.mval.y, radius, 40);
1527
1529
1531
1532 float viewport_size[4];
1533 GPU_viewport_size_get_f(viewport_size);
1534 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1535
1536 immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1537 immUniform1i("colors_len", 0); /* "simple" mode */
1538 immUniform1f("dash_width", 12.0f);
1539 immUniform1f("udash_factor", 0.5f);
1540
1541 /* XXX Dashed shader gives bad results with sets of small segments
1542 * currently, temp hack around the issue. :( */
1543 const int nsegments = max_ii(8, radius / 2);
1544 imm_draw_circle_wire_2d(pcontext.pos, pcontext.mval.x, pcontext.mval.y, radius, nsegments);
1545}
1546
1548{
1549 if (pcontext.region &&
1550 !BLI_rcti_isect_pt(&pcontext.region->winrct, pcontext.mval.x, pcontext.mval.y))
1551 {
1552 return;
1553 }
1554
1555 Object *object = CTX_data_active_object(pcontext.C);
1556 if (object->type != OB_GREASE_PENCIL) {
1557 return;
1558 }
1559
1560 GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
1561 Paint *paint = pcontext.paint;
1562 Brush *brush = pcontext.brush;
1563 if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) {
1564 return;
1565 }
1566
1567 float3 color(1.0f);
1568 const int2 mval = pcontext.mval;
1569
1570 if (pcontext.mode == PaintMode::GPencil) {
1571 /* Hide the cursor while drawing. */
1572 if (grease_pencil->runtime->is_drawing_stroke) {
1573 return;
1574 }
1575
1576 /* Eraser has a special shape and uses a different shader program. */
1578 grease_pencil->runtime->temp_use_eraser)
1579 {
1580 /* If we use the eraser from the draw tool with a "scene" radius unit, we need to draw the
1581 * cursor with the appropriate size. */
1582 if (grease_pencil->runtime->temp_use_eraser && (brush->flag & BRUSH_LOCK_SIZE) != 0) {
1583 pcontext.pixel_radius = int(grease_pencil->runtime->temp_eraser_size);
1584 }
1585 else {
1586 pcontext.pixel_radius = brush->size;
1587 }
1588 grease_pencil_eraser_draw(pcontext);
1589 return;
1590 }
1591
1593 /* The fill tool doesn't use a brush size currently, but not showing any brush means that it
1594 * can be hard to see where the cursor is. Use a fixed size that's not too big (10px). By
1595 * disabling the "Display Cursor" option, this can still be turned off. */
1596 pcontext.pixel_radius = 10;
1597 }
1598
1600 pcontext.pixel_radius = brush->size;
1601 }
1602
1604 if ((brush->flag & BRUSH_LOCK_SIZE) != 0) {
1605 const bke::greasepencil::Layer *layer = grease_pencil->get_active_layer();
1606 const ed::greasepencil::DrawingPlacement placement(
1607 *pcontext.scene, *pcontext.region, *pcontext.vc.v3d, *object, layer);
1608 const float2 coordinate = float2(pcontext.mval.x - pcontext.region->winrct.xmin,
1609 pcontext.mval.y - pcontext.region->winrct.ymin);
1610 bool clipped = false;
1611 const float3 pos = placement.project(coordinate, clipped);
1612 if (!clipped) {
1613 const float3 world_location = math::transform_point(placement.to_world_space(), pos);
1615 &pcontext.vc, brush->unprojected_radius, world_location, placement.to_world_space());
1616 }
1617 else {
1618 pcontext.pixel_radius = 0;
1619 }
1620 brush->size = std::max(pcontext.pixel_radius, 1);
1621 }
1622 else {
1623 pcontext.pixel_radius = brush->size;
1624 }
1625 }
1626
1627 /* Get current drawing material. */
1629 MaterialGPencilStyle *gp_style = ma->gp_style;
1630
1631 /* Follow user settings for the size of the draw cursor:
1632 * - Fixed size, or
1633 * - Brush size (i.e. stroke thickness)
1634 */
1635 if ((gp_style) && ((brush->flag & BRUSH_SMOOTH_STROKE) == 0) &&
1637 {
1638
1640 pcontext.scene->toolsettings->gp_paint, brush);
1641 const bool use_vertex_color_stroke = use_vertex_color &&
1645 color = use_vertex_color_stroke ? float3(brush->rgb) : float4(gp_style->stroke_rgba).xyz();
1646 }
1647 }
1648
1649 if ((brush->flag & BRUSH_SMOOTH_STROKE) != 0) {
1650 const float scale = 1.0f / 255.0f;
1651 color = scale * float3(paint->paint_cursor_col);
1652 }
1653 }
1654 else if (pcontext.mode == PaintMode::VertexGPencil) {
1655 pcontext.pixel_radius = BKE_brush_size_get(pcontext.vc.scene, brush);
1656 color = BKE_brush_color_get(pcontext.vc.scene, paint, brush);
1657 }
1658
1659 GPU_line_width(1.0f);
1660 /* Inner Ring: Color from UI panel */
1661 immUniformColor4f(color.x, color.y, color.z, 0.8f);
1662 imm_draw_circle_wire_2d(pcontext.pos, mval.x, mval.y, pcontext.pixel_radius, 32);
1663
1664 /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
1665 const float3 darkcolor = color * 0.40f;
1666 immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
1667 imm_draw_circle_wire_2d(pcontext.pos, mval.x, mval.y, pcontext.pixel_radius + 1, 32);
1668}
1669
1671{
1672 switch (pcontext.mode) {
1673 case PaintMode::GPencil:
1676 break;
1677 default:
1679 }
1680}
1681
1683{
1684 GPU_line_width(1.0f);
1687 pcontext.pos, pcontext.translation[0], pcontext.translation[1], pcontext.final_radius, 40);
1688}
1689
1691{
1692 GPU_line_width(1.0f);
1693 /* Reduce alpha to increase the contrast when the cursor is over the mesh. */
1694 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.8);
1696 pcontext.pos, pcontext.translation[0], pcontext.translation[1], pcontext.final_radius, 80);
1697 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.35f);
1699 pcontext.pos,
1700 pcontext.translation[0],
1701 pcontext.translation[1],
1702 pcontext.final_radius *
1703 clamp_f(BKE_brush_alpha_get(pcontext.scene, pcontext.brush), 0.0f, 1.0f),
1704 80);
1705}
1706
1708{
1710 pcontext.vc, *pcontext.scene, *pcontext.brush, pcontext.location);
1711}
1712
1714{
1715 const float4x4 cursor_trans = math::translate(pcontext.vc.obact->object_to_world(),
1716 pcontext.location);
1717
1718 const float3 z_axis = {0.0f, 0.0f, 1.0f};
1719
1720 const float3 normal = bke::brush::supports_tilt(*pcontext.brush) ?
1721 tilt_apply_to_normal(*pcontext.vc.obact,
1722 float4x4(pcontext.vc.rv3d->viewinv),
1723 pcontext.normal,
1724 pcontext.tilt,
1725 pcontext.brush->tilt_strength_factor) :
1726 pcontext.normal;
1727
1728 const math::AxisAngle between_vecs(z_axis, normal);
1729 const float4x4 cursor_rot = math::from_rotation<float4x4>(between_vecs);
1730
1731 GPU_matrix_mul(cursor_trans.ptr());
1732 GPU_matrix_mul(cursor_rot.ptr());
1733}
1734
1736{
1738 GPU_line_width(2.0f);
1739 imm_draw_circle_wire_3d(pcontext.pos, 0, 0, pcontext.radius, 80);
1740
1741 GPU_line_width(1.0f);
1742 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.5f);
1744 pcontext.pos,
1745 0,
1746 0,
1747 pcontext.radius * clamp_f(BKE_brush_alpha_get(pcontext.scene, pcontext.brush), 0.0f, 1.0f),
1748 80);
1749}
1750
1752{
1753 SculptSession &ss = *pcontext.ss;
1754 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1755 GPU_line_width(2.0f);
1756
1757 BLI_assert(ss.pose_ik_chain_preview->initial_head_coords.size() ==
1758 ss.pose_ik_chain_preview->initial_orig_coords.size());
1759
1760 immBegin(GPU_PRIM_LINES, ss.pose_ik_chain_preview->initial_head_coords.size() * 2);
1761 for (const int i : ss.pose_ik_chain_preview->initial_head_coords.index_range()) {
1762 immVertex3fv(pcontext.pos, ss.pose_ik_chain_preview->initial_orig_coords[i]);
1763 immVertex3fv(pcontext.pos, ss.pose_ik_chain_preview->initial_head_coords[i]);
1764 }
1765
1766 immEnd();
1767}
1768
1770{
1771
1772 SculptSession &ss = *pcontext.ss;
1773 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1774 for (const int i : ss.pose_ik_chain_preview->initial_orig_coords.index_range()) {
1776 pcontext.region,
1777 ss.pose_ik_chain_preview->initial_orig_coords[i],
1778 pcontext.vc.obact->object_to_world().ptr(),
1779 3);
1780 }
1781}
1782
1784{
1785 if (!pcontext.ss->boundary_preview) {
1786 /* There is no guarantee that a boundary preview exists as there may be no boundaries
1787 * inside the brush radius. */
1788 return;
1789 }
1790 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1792 pcontext.region,
1793 pcontext.ss->boundary_preview->pivot_position,
1794 pcontext.vc.obact->object_to_world().ptr(),
1795 3);
1796}
1797
1799{
1800 SculptSession &ss = *pcontext.ss;
1801 /* Needed for updating the necessary SculptSession data in order to initialize the
1802 * boundary data for the preview. */
1803 BKE_sculpt_update_object_for_edit(pcontext.depsgraph, pcontext.vc.obact, false);
1804
1806 *pcontext.depsgraph, *pcontext.vc.obact, pcontext.brush, pcontext.radius);
1807}
1808
1810{
1811 const Brush &brush = *pcontext.brush;
1812
1813 /* 2D falloff is better represented with the default 2D cursor,
1814 * there is no need to draw anything else. */
1817 return;
1818 }
1819
1820 if (pcontext.alpha_overlay_drawn) {
1822 return;
1823 }
1824
1825 if (!pcontext.is_cursor_over_mesh) {
1827 return;
1828 }
1829
1830 BLI_assert(pcontext.vc.obact);
1831 Object &active_object = *pcontext.vc.obact;
1833
1834 vert_random_access_ensure(active_object);
1835
1836 /* Setup drawing. */
1837 wmViewport(&pcontext.region->winrct);
1838
1839 /* Drawing of Cursor overlays in 2D screen space. */
1840
1841 /* Cursor location symmetry points. */
1842
1843 float3 active_vertex_co;
1845 SculptSession &ss = *pcontext.ss;
1846 if (bke::object::pbvh_get(active_object)->type() == bke::pbvh::Type::Mesh) {
1847 const Span<float3> positions = vert_positions_for_grab_active_get(*pcontext.depsgraph,
1848 active_object);
1849 active_vertex_co = positions[std::get<int>(ss.active_vert())];
1850 }
1851 else {
1852 active_vertex_co = pcontext.ss->active_vert_position(*pcontext.depsgraph, active_object);
1853 }
1854 }
1855 else {
1856 active_vertex_co = pcontext.ss->active_vert_position(*pcontext.depsgraph, active_object);
1857 }
1858 if (math::distance(active_vertex_co, pcontext.location) < pcontext.radius) {
1861 pcontext.region,
1862 active_vertex_co,
1863 *pcontext.sd,
1864 active_object,
1865 pcontext.radius);
1866 }
1867
1868 const bool is_brush_tool = paint_brush_tool_poll(pcontext.C);
1869
1870 /* Pose brush updates and rotation origins. */
1871
1872 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_POSE) {
1873 /* Just after switching to the Pose Brush, the active vertex can be the same and the
1874 * cursor won't be tagged to update, so always initialize the preview chain if it is
1875 * nullptr before drawing it. */
1876 SculptSession &ss = *pcontext.ss;
1877 const bool update_previews = pcontext.prev_active_vert_index !=
1878 pcontext.ss->active_vert_index();
1879 if (update_previews || !ss.pose_ik_chain_preview) {
1880 BKE_sculpt_update_object_for_edit(pcontext.depsgraph, &active_object, false);
1881
1882 /* Free the previous pose brush preview. */
1883 if (ss.pose_ik_chain_preview) {
1884 ss.pose_ik_chain_preview.reset();
1885 }
1886
1887 /* Generate a new pose brush preview from the current cursor location. */
1889 *pcontext.depsgraph, active_object, ss, brush, pcontext.location, pcontext.radius);
1890 }
1891
1892 /* Draw the pose brush rotation origins. */
1894 }
1895
1896 /* Expand operation origin. */
1897 if (pcontext.ss->expand_cache) {
1898 const int vert = pcontext.ss->expand_cache->initial_active_vert;
1899
1900 float3 position;
1901 switch (bke::object::pbvh_get(active_object)->type()) {
1902 case bke::pbvh::Type::Mesh: {
1903 const Span positions = bke::pbvh::vert_positions_eval(*pcontext.depsgraph, active_object);
1904 position = positions[vert];
1905 break;
1906 }
1908 const SubdivCCG &subdiv_ccg = *pcontext.ss->subdiv_ccg;
1909 position = subdiv_ccg.positions[vert];
1910 break;
1911 }
1913 BMesh &bm = *pcontext.ss->bm;
1914 position = BM_vert_at_index(&bm, vert)->co;
1915 break;
1916 }
1917 }
1919 pcontext.pos, pcontext.region, position, active_object.object_to_world().ptr(), 2);
1920 }
1921
1922 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_BOUNDARY) {
1925 }
1926
1927 /* Setup 3D perspective drawing. */
1930 pcontext.win,
1931 pcontext.depsgraph,
1932 pcontext.scene,
1933 pcontext.region,
1934 CTX_wm_view3d(pcontext.C),
1935 nullptr,
1936 nullptr,
1937 nullptr);
1938
1940 GPU_matrix_mul(active_object.object_to_world().ptr());
1941
1942 /* Drawing Cursor overlays in 3D object space. */
1943 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_GRAB &&
1945 {
1947 *pcontext.depsgraph, *pcontext.vc.obact, *pcontext.ss, pcontext.radius);
1949 *pcontext.depsgraph, pcontext.pos, *pcontext.brush, active_object);
1950 }
1951
1952 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_POSE) {
1954 }
1955
1956 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_BOUNDARY) {
1958 pcontext.pos, *pcontext.ss, pcontext.outline_col, pcontext.outline_alpha);
1959 boundary::pivot_line_preview_draw(pcontext.pos, *pcontext.ss);
1960 }
1961
1963
1964 /* Drawing Cursor overlays in Paint Cursor space (as additional info on top of the brush cursor)
1965 */
1968 /* Main inactive cursor. */
1970
1971 /* Cloth brush local simulation areas. */
1972 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_CLOTH &&
1974 {
1975 const float3 white = {1.0f, 1.0f, 1.0f};
1976 const float3 zero_v = float3(0.0f);
1977 /* This functions sets its own drawing space in order to draw the simulation limits when the
1978 * cursor is active. When used here, this cursor overlay is already in cursor space, so its
1979 * position and normal should be set to 0. */
1981 pcontext.pos, brush, zero_v, zero_v, pcontext.radius, 1.0f, white, 0.25f);
1982 }
1983
1984 /* Layer brush height. */
1985 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_LAYER) {
1987 pcontext.pos, brush, pcontext.radius, 1.0f, pcontext.outline_col, pcontext.outline_alpha);
1988 }
1989
1991
1992 /* Reset drawing. */
1994 wmWindowViewport(pcontext.win);
1995}
1996
1998{
1999 BLI_assert(pcontext.ss != nullptr);
2000 BLI_assert(pcontext.mode == PaintMode::Sculpt);
2001
2002 SculptSession &ss = *pcontext.ss;
2003 Brush &brush = *pcontext.brush;
2004
2005 /* The cursor can be updated as active before creating the StrokeCache, so this needs to be
2006 * checked. */
2007 if (!ss.cache) {
2008 return;
2009 }
2010
2011 /* Most of the brushes initialize the necessary data for the custom cursor drawing after the
2012 * first brush step, so make sure that it is not drawn before being initialized. */
2014 return;
2015 }
2016
2017 /* Setup drawing. */
2018 wmViewport(&pcontext.region->winrct);
2021 pcontext.win,
2022 pcontext.depsgraph,
2023 pcontext.scene,
2024 pcontext.region,
2025 CTX_wm_view3d(pcontext.C),
2026 nullptr,
2027 nullptr,
2028 nullptr);
2030 GPU_matrix_mul(pcontext.vc.obact->object_to_world().ptr());
2031
2032 /* Draw the special active cursors different brush types may have. */
2033
2036 *pcontext.depsgraph, pcontext.pos, brush, *pcontext.vc.obact);
2037 }
2038
2041 pcontext.pos, brush, ss, pcontext.outline_col, pcontext.outline_alpha);
2042 }
2043
2047 pcontext.pos, ss, pcontext.outline_col, pcontext.outline_alpha);
2048 }
2051 {
2052 /* Display the simulation limits if sculpting outside them. */
2053 /* This does not makes much sense of plane falloff as the falloff is infinite or global. */
2054
2056 ss.cache->radius * (1.0f + brush.cloth_sim_limit))
2057 {
2058 const float3 red = {1.0f, 0.2f, 0.2f};
2060 brush,
2063 ss.cache->radius,
2064 2.0f,
2065 red,
2066 0.8f);
2067 }
2068 }
2069 }
2070
2072
2074 wmWindowViewport(pcontext.win);
2075}
2076
2078{
2079
2080 /* These paint tools are not using the SculptSession, so they need to use the default 2D brush
2081 * cursor in the 3D view. */
2082 if (pcontext.mode != PaintMode::Sculpt || !pcontext.ss) {
2084 return;
2085 }
2086
2088
2089 if (pcontext.is_stroke_active) {
2091 }
2092 else {
2094 }
2095}
2096
2098{
2099 const ViewContext *vc = &pcontext.vc;
2100 return vc->rv3d && (vc->rv3d->rflag & RV3D_NAVIGATING);
2101}
2102
2104{
2105 if (pcontext.paint->flags & PAINT_SHOW_BRUSH) {
2108 {
2109 return false;
2110 }
2111 return true;
2112 }
2113 return false;
2114}
2115
2117{
2118 /* Don't calculate rake angles while a stroke is active because the rake variables are global
2119 * and we may get interference with the stroke itself.
2120 * For line strokes, such interference is visible. */
2121 if (!pcontext.ups->stroke_active) {
2123 *pcontext.ups, *pcontext.brush, pcontext.translation, pcontext.mode, true);
2124 }
2125}
2126
2128{
2130 pcontext.brush,
2131 &pcontext.vc,
2132 pcontext.mval.x,
2133 pcontext.mval.y,
2134 pcontext.zoomx,
2135 pcontext.mode);
2136}
2137
2139{
2140 UnifiedPaintSettings *ups = pcontext.ups;
2141 if (ups->draw_anchored) {
2142 pcontext.final_radius = ups->anchored_size;
2143 pcontext.translation = {ups->anchored_initial_mouse[0] + pcontext.region->winrct.xmin,
2144 ups->anchored_initial_mouse[1] + pcontext.region->winrct.ymin};
2145 }
2146}
2147
2157
2167
2174
2176 const blender::int2 &xy,
2177 const blender::float2 &tilt,
2178 void * /*unused*/)
2179{
2180 PaintCursorContext pcontext;
2181 if (!paint_cursor_context_init(C, xy, tilt, pcontext)) {
2182 return;
2183 }
2184
2185 if (!paint_cursor_is_brush_cursor_enabled(pcontext)) {
2186 /* For Grease Pencil draw mode, we want to we only render a small mouse cursor (dot) if the
2187 * paint cursor is disabled so that the default mouse cursor doesn't get in the way of tablet
2188 * users. See #130089. But don't overwrite a modal cursor, allowing modal operators to set one
2189 * temporarily. */
2190 if (pcontext.mode == PaintMode::GPencil && pcontext.win->modalcursor == 0) {
2191 WM_cursor_set(pcontext.win, WM_CURSOR_DOT);
2192 }
2193 return;
2194 }
2195 if (paint_cursor_is_3d_view_navigating(pcontext)) {
2196 /* Still draw stencil while navigating. */
2198 return;
2199 }
2200
2201 switch (pcontext.cursor_type) {
2203 paint_draw_curve_cursor(pcontext.brush, &pcontext.vc);
2204 break;
2206 paint_update_mouse_cursor(pcontext);
2207
2211
2215 break;
2217 paint_update_mouse_cursor(pcontext);
2218
2222
2226 break;
2227 default:
2229 }
2230}
2231
2232} // namespace blender::ed::sculpt_paint
2233
2234/* Public API */
2235
2236void ED_paint_cursor_start(Paint *paint, bool (*poll)(bContext *C))
2237{
2238 if (paint && !paint->paint_cursor) {
2241 }
2242
2243 /* Invalidate the paint cursors. */
2245}
float BKE_brush_unprojected_radius_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1249
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1210
void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
Definition brush.cc:1236
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
Definition brush.cc:1194
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1226
float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1269
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1128
bool BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
Definition brush.cc:1218
float BKE_brush_curve_strength_clamped(const Brush *br, float p, float len)
Definition brush.cc:1566
void BKE_curvemapping_init(CurveMapping *cumap)
bScreen * CTX_wm_screen(const bContext *C)
wmWindow * CTX_wm_window(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)
ToolSettings * CTX_data_tool_settings(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition curve.cc:1673
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_from_brush_get(Object *ob, Brush *brush)
void BKE_image_pool_free(ImagePool *pool)
ImBuf * BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
ImagePool * BKE_image_pool_new()
void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh_no_subsurf(const Object *object_eval)
PaintMode
Definition BKE_paint.hh:93
ePaintOverlayControlFlags BKE_paint_get_overlay_flags()
Definition paint.cc:289
ePaintOverlayControlFlags
Definition BKE_paint.hh:115
@ PAINT_OVERLAY_INVALID_CURVE
Definition BKE_paint.hh:118
@ PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY
Definition BKE_paint.hh:117
@ PAINT_OVERLAY_OVERRIDE_CURSOR
Definition BKE_paint.hh:119
@ PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY
Definition BKE_paint.hh:116
@ PAINT_OVERLAY_OVERRIDE_SECONDARY
Definition BKE_paint.hh:121
@ PAINT_OVERLAY_OVERRIDE_PRIMARY
Definition BKE_paint.hh:120
void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag)
Definition paint.cc:312
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2657
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:467
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:636
bool paint_calculate_rake_rotation(UnifiedPaintSettings &ups, const Brush &brush, const float mouse_pos[2], PaintMode paint_mode, bool stroke_has_started)
Definition paint.cc:2052
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:496
void BKE_paint_invalidate_overlay_all()
Definition paint.cc:283
ARegion * BKE_screen_find_region_type(const bScreen *screen, int region_type) ATTR_NONNULL(1)
Definition screen.cc:885
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE int max_ii(int a, int b)
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
#define RAD2DEGF(_rad)
#define M_PI
void mul_m4_v3(const float M[4][4], float r[3])
void rotate_m4(float mat[4][4], char axis, float angle)
void unit_m4(float m[4][4])
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void clamp_v4(float vec[4], float min, float max)
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_v3_int(int r[3], const int a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float n[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
unsigned char uchar
unsigned int uint
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls)
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:221
#define CLAMP(a, b, c)
#define UNPACK3(a)
#define ELEM(...)
@ GPAINT_BRUSH_TYPE_TINT
@ GPAINT_BRUSH_TYPE_FILL
@ GPAINT_BRUSH_TYPE_DRAW
@ GPAINT_BRUSH_TYPE_ERASE
@ SCULPT_BRUSH_TYPE_GRAB
@ SCULPT_BRUSH_TYPE_BOUNDARY
@ SCULPT_BRUSH_TYPE_CLOTH
@ SCULPT_BRUSH_TYPE_POSE
@ SCULPT_BRUSH_TYPE_MULTIPLANE_SCRAPE
@ SCULPT_BRUSH_TYPE_LAYER
@ BRUSH_CURVE
@ BRUSH_GRAB_ACTIVE_VERTEX
@ BRUSH_SMOOTH_STROKE
@ BRUSH_DIR_IN
@ BRUSH_ANCHORED
@ BRUSH_LOCK_SIZE
@ IMAGE_PAINT_BRUSH_TYPE_FILL
@ IMAGE_PAINT_BRUSH_TYPE_DRAW
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
@ BRUSH_OVERLAY_SECONDARY
@ BRUSH_OVERLAY_CURSOR
@ BRUSH_OVERLAY_PRIMARY
@ BRUSH_CLOTH_FORCE_FALLOFF_RADIAL
@ BRUSH_CLOTH_FORCE_FALLOFF_PLANE
@ GPPAINT_MODE_STROKE
@ GPPAINT_MODE_BOTH
@ BRUSH_CLOTH_SIMULATION_AREA_LOCAL
@ BRUSH_CLOTH_SIMULATION_AREA_GLOBAL
Object is a sort of wrapper for general info.
@ OB_GREASE_PENCIL
@ OB_MESH
ePaintSymmetryFlags
@ PAINT_TILE_X
@ PAINT_SHOW_BRUSH
@ RGN_TYPE_TEMPORARY
@ RGN_TYPE_WINDOW
#define RGN_TYPE_ANY
@ SPACE_VIEW3D
#define SPACE_TYPE_ANY
@ MTEX_MAP_MODE_STENCIL
@ MTEX_MAP_MODE_TILED
@ MTEX_MAP_MODE_VIEW
@ TEX_IMAGE
@ RV3D_NAVIGATING
void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float r_out[3])
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:279
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3])
void ED_view3d_draw_setup_view(const wmWindowManager *wm, wmWindow *win, Depsgraph *depsgraph, Scene *scene, ARegion *region, View3D *v3d, const float viewmat[4][4], const float winmat[4][4], const rcti *rect)
float ED_view3d_calc_zfac_ex(const RegionView3D *rv3d, const float co[3], bool *r_flip)
void ED_view3d_project_v3(const ARegion *region, const float world[3], float r_region_co[3])
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
static AppView * view
void immEnd()
void immUnbindProgram()
void immUniform2f(const char *name, float x, float y)
void immUniformColor4f(float r, float g, float b, float a)
void immBindTextureSampler(const char *name, GPUTexture *tex, GPUSamplerState state)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immVertex2fv(uint attr_id, const float data[2])
void immUniform1i(const char *name, int x)
void immUniform1f(const char *name, float x)
void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immAttr2f(uint attr_id, float x, float y)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fvAlpha(const float rgb[3], float a)
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments)
void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments)
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
void GPU_matrix_translate_2fv(const float vec[2])
void GPU_matrix_scale_2f(float x, float y)
void GPU_matrix_push()
void GPU_matrix_push_projection()
#define GPU_matrix_mul(x)
void GPU_matrix_scale_1f(float factor)
void GPU_matrix_rotate_2d(float deg)
void GPU_matrix_pop_projection()
void GPU_matrix_pop()
void GPU_matrix_translate_2f(float x, float y)
@ GPU_PRIM_TRI_FAN
@ GPU_PRIM_LINE_LOOP
@ GPU_PRIM_LINES
@ GPU_PRIM_LINE_STRIP
@ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_IMAGE_COLOR
eGPUBlend
Definition GPU_state.hh:84
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
@ GPU_BLEND_ALPHA_PREMULT
Definition GPU_state.hh:88
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:166
eGPUBlend GPU_blend_get()
Definition gpu_state.cc:226
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
eGPUDepthTest GPU_depth_test_get()
Definition gpu_state.cc:244
void GPU_color_mask(bool r, bool g, bool b, bool a)
Definition gpu_state.cc:98
eGPUDepthTest
Definition GPU_state.hh:110
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:114
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_DATA_UBYTE
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
GPUSamplerExtendMode
@ GPU_SAMPLER_EXTEND_MODE_REPEAT
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
eGPUTextureFormat
@ GPU_R8
@ GPU_RGBA8
@ GPU_SAMPLER_FILTERING_LINEAR
void GPU_texture_update(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
void GPU_texture_swizzle_set(GPUTexture *texture, const char swizzle[4])
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], const ColorSpace *colorspace)
blender::ocio::ColorSpace ColorSpace
Read Guarded memory(de)allocation.
void ntreeTexEndExecTree(struct bNodeTreeExec *exec)
struct bNodeTreeExec * ntreeTexBeginExecTree(struct bNodeTree *ntree)
#define C
Definition RandGen.cpp:29
@ TH_PAINT_CURVE_HANDLE
@ TH_VERTEX_SELECT
@ TH_PAINT_CURVE_PIVOT
void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4])
#define U
BMesh const char void * data
BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
int64_t size() const
Definition BLI_array.hh:245
bool is_empty() const
Definition BLI_array.hh:253
float3 project(float2 co, bool &clipped) const
#define sinf(x)
#define cosf(x)
#define atan2f(x, y)
#define fabsf(x)
#define sqrtf(x)
uint pos
blender::gpu::Batch * quad
uint col
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
format
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool supports_secondary_cursor_color(const Brush &brush)
Definition brush.cc:1796
bool supports_tilt(const Brush &brush)
Definition brush.cc:1864
pbvh::Tree & pbvh_ensure(Depsgraph &depsgraph, Object &object)
Definition paint.cc:2877
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2416
void pivot_line_preview_draw(const uint gpuattr, SculptSession &ss)
std::unique_ptr< SculptBoundaryPreview > preview_data_init(const Depsgraph &depsgraph, Object &object, const Brush *brush, const float radius)
void edges_preview_draw(const uint gpuattr, SculptSession &ss, const float outline_col[3], const float outline_alpha)
void multiplane_scrape_preview_draw(uint gpuattr, const Brush &brush, const SculptSession &ss, const float outline_col[3], float outline_alpha)
void plane_falloff_preview_draw(const uint gpuattr, SculptSession &ss, const float outline_col[3], float outline_alpha)
void simulation_limits_draw(const uint gpuattr, const Brush &brush, const float location[3], const float normal[3], const float rds, const float line_width, const float outline_col[3], const float alpha)
bool brush_using_vertex_color(const GpPaint *gp_paint, const Brush *brush)
std::unique_ptr< SculptPoseIKChainPreview > preview_ik_chain_init(const Depsgraph &depsgraph, Object &ob, SculptSession &ss, const Brush &brush, const float3 &initial_location, const float radius)
float object_space_radius_get(const ViewContext &vc, const Scene &scene, const Brush &brush, const float3 &location, const float scale_factor)
Definition sculpt.cc:115
static bool paint_cursor_context_init(bContext *C, const blender::int2 &xy, const blender::float2 &tilt, PaintCursorContext &pcontext)
static void grease_pencil_brush_cursor_draw(PaintCursorContext &pcontext)
static void paint_draw_2D_view_brush_cursor(PaintCursorContext &pcontext)
static void SCULPT_layer_brush_height_preview_draw(const uint gpuattr, const Brush &brush, const float rds, const float line_width, const float3 &outline_col, const float alpha)
static void load_tex_cursor_task_cb(void *__restrict userdata, const int j, const TaskParallelTLS *__restrict)
static bool paint_use_2d_cursor(PaintMode mode)
static void paint_cursor_pose_brush_segments_draw(const PaintCursorContext &pcontext)
static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom, const PaintMode mode, bool col, bool primary)
static void load_tex_task_cb_ex(void *__restrict userdata, const int j, const TaskParallelTLS *__restrict tls)
static void paint_update_mouse_cursor(PaintCursorContext &pcontext)
static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext &pcontext)
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:142
static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom)
static void grease_pencil_eraser_draw(PaintCursorContext &pcontext)
static void paint_cursor_update_object_space_radius(PaintCursorContext &pcontext)
static void sculpt_geometry_preview_lines_draw(const Depsgraph &depsgraph, const uint gpuattr, const Brush &brush, const Object &object)
static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
static void paint_cursor_draw_3D_view_brush_cursor(PaintCursorContext &pcontext)
static void cursor_draw_point_screen_space(const uint gpuattr, const ARegion *region, const float true_location[3], const float obmat[4][4], const int size)
float3 symmetry_flip(const float3 &src, const ePaintSymmetryFlags symm)
static void paint_cursor_pose_brush_origins_draw(const PaintCursorContext &pcontext)
static void paint_cursor_restore_drawing_state()
static void paint_cursor_draw_main_inactive_cursor(PaintCursorContext &pcontext)
static void cursor_draw_tiling_preview(const uint gpuattr, const ARegion *region, const float true_location[3], const Sculpt &sd, const Object &ob, const float radius)
static void paint_cursor_drawing_setup_cursor_space(const PaintCursorContext &pcontext)
BLI_INLINE void draw_bezier_handle_lines(uint pos, const float sel_col[4], BezTriple *bez)
static void paint_cursor_update_anchored_location(PaintCursorContext &pcontext)
static void paint_cursor_update_rake_rotation(PaintCursorContext &pcontext)
static bool paint_cursor_is_3d_view_navigating(const PaintCursorContext &pcontext)
BLI_INLINE void draw_tri_point(uint pos, const float sel_col[4], const float pivot_col[4], float *co, float width, bool selected)
BLI_INLINE void draw_rect_point(uint pos, const float sel_col[4], const float handle_col[4], const float *co, float width, bool selected)
static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom, PaintMode mode)
static void paint_cursor_setup_3D_drawing(PaintCursorContext &pcontext)
static void paint_cursor_check_and_draw_alpha_overlays(PaintCursorContext &pcontext)
bool cursor_geometry_info_update(bContext *C, CursorGeometryInfo *out, const float2 &mval, const bool use_sampled_normal)
Definition sculpt.cc:4662
static void paint_cursor_preview_boundary_data_pivot_draw(const PaintCursorContext &pcontext)
static bool paint_cursor_is_brush_cursor_enabled(const PaintCursorContext &pcontext)
static void paint_cursor_preview_boundary_data_update(const PaintCursorContext &pcontext)
static void paint_draw_cursor(bContext *C, const blender::int2 &xy, const blender::float2 &tilt, void *)
static int project_brush_radius_grease_pencil(ViewContext *vc, const float radius, const float3 world_location, const float4x4 &to_world)
static void paint_cursor_setup_2D_drawing(PaintCursorContext &pcontext)
static void paint_draw_3D_view_inactive_brush_cursor(PaintCursorContext &pcontext)
static void paint_cursor_cursor_draw_3d_view_brush_cursor_active(PaintCursorContext &pcontext)
static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext &pcontext)
static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary)
static void cursor_draw_point_with_symmetry(const uint gpuattr, const ARegion *region, const float true_location[3], const Sculpt &sd, const Object &ob, const float radius)
static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc)
static void paint_draw_legacy_3D_view_brush_cursor(PaintCursorContext &pcontext)
static void paint_cursor_update_pixel_radius(PaintCursorContext &pcontext)
static int project_brush_radius(ViewContext *vc, float radius, const float location[3])
static void paint_cursor_update_unprojected_radius(const UnifiedPaintSettings &ups, Brush &brush, const ViewContext &vc, const float location[3])
static void paint_draw_2D_view_brush_cursor_default(PaintCursorContext &pcontext)
bool paint_brush_tool_poll(bContext *C)
static bool paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom)
void geometry_preview_lines_update(Depsgraph &depsgraph, Object &object, SculptSession &ss, float radius)
Definition grab.cc:231
Span< float3 > vert_positions_for_grab_active_get(const Depsgraph &depsgraph, const Object &object)
Definition sculpt.cc:170
float3 tilt_apply_to_normal(const Object &object, const float4x4 &view_inverse, const float3 &normal, const float2 &tilt, const float tilt_strength)
Definition sculpt.cc:2671
bool is_symmetry_iteration_valid(const char i, const char symm)
constexpr double inv_sqrt3
T safe_divide(const T &a, const T &b)
T distance(const T &a, const T &b)
T length(const VecBase< T, Size > &a)
AxisAngleBase< float, AngleRadianBase< float > > AxisAngle
MatBase< T, NumCol, NumRow > translate(const MatBase< T, NumCol, NumRow > &mat, const VectorT &translation)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
MatT from_rotation(const RotationT &rotation)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
vector snap(vector a, vector b)
Definition node_math.h:65
static void init(bNodeTree *, bNode *node)
static ePaintOverlayControlFlags overlay_flags
Definition paint.cc:248
void paint_cursor_delete_textures()
static CursorSnapshot cursor_snap
static TexSnapshot primary_snap
static TexSnapshot secondary_snap
void ED_paint_cursor_start(Paint *paint, bool(*poll)(bContext *C))
bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
float paint_calc_object_space_radius(const ViewContext &vc, const blender::float3 &center, float pixel_radius)
#define PAINT_CURVE_NUM_SEGMENTS
bool paint_get_tex_pixel(const MTex *mtex, float u, float v, ImagePool *pool, int thread, float *r_intensity, float r_rgba[4])
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:543
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:185
float co[3]
float vec[3][3]
char sculpt_brush_type
int mask_overlay_alpha
float add_col[4]
struct MTex mtex
float stencil_pos[2]
int texture_overlay_alpha
float unprojected_radius
float stencil_dimension[2]
int cursor_overlay_alpha
char image_brush_type
int curve_preset
struct CurveMapping * curve
float texture_sample_bias
char falloff_shape
float tilt_strength_factor
float mask_stencil_pos[2]
float rgb[3]
struct BrushGpencilSettings * gpencil_settings
float cloth_sim_limit
float height
float sub_col[4]
struct MTex mask_mtex
float mask_stencil_dimension[2]
int cloth_simulation_area_type
char gpencil_brush_type
struct PaintCurve * paint_curve
int cloth_force_falloff_type
int overlay_flags
GPUTexture * overlay_texture
GreasePencilRuntimeHandle * runtime
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
char brush_map_mode
struct Tex * tex
struct SculptSession * sculpt
PaintCurvePoint * points
float tile_offset[3]
int symmetry_flags
void * paint_cursor
float viewinv[4][4]
struct ToolSettings * toolsettings
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:437
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
std::unique_ptr< SculptBoundaryPreview > boundary_preview
Definition BKE_paint.hh:466
bool draw_faded_cursor
Definition BKE_paint.hh:448
blender::Array< int > preview_verts
Definition BKE_paint.hh:460
ActiveVert active_vert() const
Definition paint.cc:2227
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2263
std::unique_ptr< SculptPoseIKChainPreview > pose_ik_chain_preview
Definition BKE_paint.hh:463
blender::ed::sculpt_paint::expand::Cache * expand_cache
Definition BKE_paint.hh:439
int active_vert_index() const
Definition paint.cc:2237
bool deform_modifiers_active
Definition BKE_paint.hh:421
int radial_symm[3]
blender::Array< blender::float3 > positions
GPUTexture * overlay_texture
struct ImageUser iuser
struct bNodeTree * nodetree
struct Image * ima
struct UnifiedPaintSettings unified_paint_settings
RegionView3D * rv3d
Definition ED_view3d.hh:80
ARegion * region
Definition ED_view3d.hh:77
Scene * scene
Definition ED_view3d.hh:73
bContext * C
Definition ED_view3d.hh:66
View3D * v3d
Definition ED_view3d.hh:78
Object * obact
Definition ED_view3d.hh:75
bNodeTreeRuntimeHandle * runtime
ListBase regionbase
const c_style_mat & ptr() const
VecBase< T, 3 > xyz() const
int ymin
int xmin
i
Definition text_draw.cc:230
uint len
void WM_cursor_set(wmWindow *win, int curs)
@ WM_CURSOR_PAINT
Definition wm_cursors.hh:27
@ WM_CURSOR_DOT
Definition wm_cursors.hh:28
int xy[2]
Definition wm_draw.cc:174
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)
void wmViewport(const rcti *winrct)
void wmWindowViewport(const wmWindow *win)
bool WM_toolsystem_active_tool_is_brush(const bContext *C)