Blender V4.3
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
9#include "MEM_guardedalloc.h"
10
11#include "BLI_math_rotation.h"
12#include "BLI_rect.h"
13#include "BLI_task.h"
14#include "BLI_utildefines.h"
15
16#include "DNA_brush_types.h"
17#include "DNA_material_types.h"
18#include "DNA_mesh_types.h"
19#include "DNA_object_types.h"
20#include "DNA_scene_types.h"
21#include "DNA_screen_types.h"
22#include "DNA_space_types.h"
23#include "DNA_userdef_types.h"
24#include "DNA_view3d_types.h"
25
26#include "BKE_brush.hh"
27#include "BKE_colortools.hh"
28#include "BKE_context.hh"
29#include "BKE_curve.hh"
30#include "BKE_grease_pencil.hh"
31#include "BKE_image.hh"
32#include "BKE_node_runtime.hh"
33#include "BKE_object.hh"
34#include "BKE_paint.hh"
35
36#include "NOD_texture.h"
37
38#include "WM_api.hh"
39#include "wm_cursors.hh"
40
42#include "IMB_imbuf_types.hh"
43
44#include "ED_grease_pencil.hh"
45#include "ED_image.hh"
46#include "ED_view3d.hh"
47
48#include "GPU_immediate.hh"
49#include "GPU_immediate_util.hh"
50#include "GPU_matrix.hh"
51#include "GPU_state.hh"
52#include "GPU_texture.hh"
53
54#include "UI_resources.hh"
55
56#include "paint_intern.hh"
57#include "sculpt_boundary.hh"
58#include "sculpt_cloth.hh"
59#include "sculpt_expand.hh"
60/* still needed for sculpt_stroke_get_location, should be
61 * removed eventually (TODO) */
62#include "sculpt_intern.hh"
63#include "sculpt_pose.hh"
64
65/* TODOs:
66 *
67 * Some of the cursor drawing code is doing non-draw stuff
68 * (e.g. updating the brush rake angle). This should be cleaned up
69 * still.
70 *
71 * There is also some ugliness with sculpt-specific code.
72 */
73
75 GPUTexture *overlay_texture;
76 int winx;
77 int winy;
79 float old_zoom;
80 bool old_col;
81};
82
84 GPUTexture *overlay_texture;
85 int size;
86 int zoom;
88};
89
90static TexSnapshot primary_snap = {nullptr};
91static TexSnapshot secondary_snap = {nullptr};
92static CursorSnapshot cursor_snap = {nullptr};
93
112
114
115static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom)
116{
117 return (/* make brush smaller shouldn't cause a resample */
118 //(mtex->brush_map_mode != MTEX_MAP_MODE_VIEW ||
119 //(BKE_brush_size_get(vc->scene, brush) <= snap->BKE_brush_size_get)) &&
120
122 (vc->region->winx == snap->winx && vc->region->winy == snap->winy)) &&
123 (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL || snap->old_zoom == zoom) &&
124 snap->old_col == col);
125}
126
127static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
128{
129 snap->old_zoom = zoom;
130 snap->winx = vc->region->winx;
131 snap->winy = vc->region->winy;
132}
133
147
148static void load_tex_task_cb_ex(void *__restrict userdata,
149 const int j,
150 const TaskParallelTLS *__restrict tls)
151{
152 LoadTexData *data = static_cast<LoadTexData *>(userdata);
153 Brush *br = data->br;
154 ViewContext *vc = data->vc;
155
156 MTex *mtex = data->mtex;
157 uchar *buffer = data->buffer;
158 const bool col = data->col;
159
160 ImagePool *pool = data->pool;
161 const int size = data->size;
162 const float rotation = data->rotation;
163 const float radius = data->radius;
164
165 bool convert_to_linear = false;
166 ColorSpace *colorspace = nullptr;
167
168 const int thread_id = BLI_task_parallel_thread_id(tls);
169
170 if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
171 ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
172 /* For consistency, sampling always returns color in linear space. */
173 if (tex_ibuf && tex_ibuf->float_buffer.data == nullptr) {
174 convert_to_linear = true;
175 colorspace = tex_ibuf->byte_buffer.colorspace;
176 }
177 BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
178 }
179
180 for (int i = 0; i < size; i++) {
181 /* Largely duplicated from tex_strength. */
182
183 int index = j * size + i;
184
185 float x = float(i) / size;
186 float y = float(j) / size;
187 float len;
188
189 if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
190 x *= vc->region->winx / radius;
191 y *= vc->region->winy / radius;
192 }
193 else {
194 x = (x - 0.5f) * 2.0f;
195 y = (y - 0.5f) * 2.0f;
196 }
197
198 len = sqrtf(x * x + y * y);
199
201 /* It is probably worth optimizing for those cases where the texture is not rotated by
202 * skipping the calls to atan2, sqrtf, sin, and cos. */
203 if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
204 const float angle = atan2f(y, x) + rotation;
205
206 x = len * cosf(angle);
207 y = len * sinf(angle);
208 }
209
210 float avg;
211 float rgba[4];
212 paint_get_tex_pixel(mtex, x, y, pool, thread_id, &avg, rgba);
213
214 if (col) {
215 if (convert_to_linear) {
217 }
218
219 linearrgb_to_srgb_v3_v3(rgba, rgba);
220
221 clamp_v4(rgba, 0.0f, 1.0f);
222
223 buffer[index * 4] = rgba[0] * 255;
224 buffer[index * 4 + 1] = rgba[1] * 255;
225 buffer[index * 4 + 2] = rgba[2] * 255;
226 buffer[index * 4 + 3] = rgba[3] * 255;
227 }
228 else {
229 avg += br->texture_sample_bias;
230
231 /* Clamp to avoid precision overflow. */
232 CLAMP(avg, 0.0f, 1.0f);
233 buffer[index] = 255 - uchar(255 * avg);
234 }
235 }
236 else {
237 if (col) {
238 buffer[index * 4] = 0;
239 buffer[index * 4 + 1] = 0;
240 buffer[index * 4 + 2] = 0;
241 buffer[index * 4 + 3] = 0;
242 }
243 else {
244 buffer[index] = 0;
245 }
246 }
247 }
248}
249
250static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary)
251{
252 bool init;
253 TexSnapshot *target;
254
255 MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
257 uchar *buffer = nullptr;
258
259 int size;
260 bool refresh;
264 target = (primary) ? &primary_snap : &secondary_snap;
265
266 refresh = !target->overlay_texture || (invalid != 0) ||
267 !same_tex_snap(target, mtex, vc, col, zoom);
268
269 init = (target->overlay_texture != nullptr);
270
271 if (refresh) {
272 ImagePool *pool = nullptr;
273 /* Stencil is rotated later. */
274 const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
275 const float radius = BKE_brush_size_get(vc->scene, br) * zoom;
276
277 make_tex_snap(target, vc, zoom);
278
279 if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
280 int s = BKE_brush_size_get(vc->scene, br);
281 int r = 1;
282
283 for (s >>= 1; s > 0; s >>= 1) {
284 r++;
285 }
286
287 size = (1 << r);
288
289 if (size < 256) {
290 size = 256;
291 }
292
293 if (size < target->old_size) {
294 size = target->old_size;
295 }
296 }
297 else {
298 size = 512;
299 }
300
301 if (target->old_size != size || target->old_col != col) {
302 if (target->overlay_texture) {
303 GPU_texture_free(target->overlay_texture);
304 target->overlay_texture = nullptr;
305 }
306 init = false;
307
308 target->old_size = size;
309 target->old_col = col;
310 }
311 if (col) {
312 buffer = static_cast<uchar *>(MEM_mallocN(sizeof(uchar) * size * size * 4, "load_tex"));
313 }
314 else {
315 buffer = static_cast<uchar *>(MEM_mallocN(sizeof(uchar) * size * size, "load_tex"));
316 }
317
318 pool = BKE_image_pool_new();
319
320 if (mtex->tex && mtex->tex->nodetree) {
321 /* Has internal flag to detect it only does it once. */
323 }
324
325 LoadTexData data{};
326 data.br = br;
327 data.vc = vc;
328 data.mtex = mtex;
329 data.buffer = buffer;
330 data.col = col;
331 data.pool = pool;
332 data.size = size;
333 data.rotation = rotation;
334 data.radius = radius;
335
336 TaskParallelSettings settings;
338 BLI_task_parallel_range(0, size, &data, load_tex_task_cb_ex, &settings);
339
340 if (mtex->tex && mtex->tex->nodetree) {
341 ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
342 }
343
344 if (pool) {
346 }
347
348 if (!target->overlay_texture) {
351 target->overlay_texture = GPU_texture_create_2d(
352 "paint_cursor_overlay", size, size, 1, format, usage, nullptr);
353 GPU_texture_update(target->overlay_texture, GPU_DATA_UBYTE, buffer);
354
355 if (!col) {
356 GPU_texture_swizzle_set(target->overlay_texture, "rrrr");
357 }
358 }
359
360 if (init) {
361 GPU_texture_update(target->overlay_texture, GPU_DATA_UBYTE, buffer);
362 }
363
364 if (buffer) {
365 MEM_freeN(buffer);
366 }
367 }
368 else {
369 size = target->old_size;
370 }
371
373
374 return 1;
375}
376
377static void load_tex_cursor_task_cb(void *__restrict userdata,
378 const int j,
379 const TaskParallelTLS *__restrict /*tls*/)
380{
381 LoadTexData *data = static_cast<LoadTexData *>(userdata);
382 Brush *br = data->br;
383
384 uchar *buffer = data->buffer;
385
386 const int size = data->size;
387
388 for (int i = 0; i < size; i++) {
389 /* Largely duplicated from tex_strength. */
390
391 const int index = j * size + i;
392 const float x = ((float(i) / size) - 0.5f) * 2.0f;
393 const float y = ((float(j) / size) - 0.5f) * 2.0f;
394 const float len = sqrtf(x * x + y * y);
395
396 if (len <= 1.0f) {
397
398 /* Falloff curve. */
399 float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f);
400
401 buffer[index] = uchar(255 * avg);
402 }
403 else {
404 buffer[index] = 0;
405 }
406 }
407}
408
409static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
410{
411 bool init;
412
414 uchar *buffer = nullptr;
415
416 int size;
417 const bool refresh = !cursor_snap.overlay_texture ||
420
421 init = (cursor_snap.overlay_texture != nullptr);
422
423 if (refresh) {
424 int s, r;
425
426 cursor_snap.zoom = zoom;
427
428 s = BKE_brush_size_get(vc->scene, br);
429 r = 1;
430
431 for (s >>= 1; s > 0; s >>= 1) {
432 r++;
433 }
434
435 size = (1 << r);
436
437 if (size < 256) {
438 size = 256;
439 }
440
441 if (size < cursor_snap.size) {
442 size = cursor_snap.size;
443 }
444
445 if (cursor_snap.size != size) {
449 }
450
451 init = false;
452
454 }
455 buffer = static_cast<uchar *>(MEM_mallocN(sizeof(uchar) * size * size, "load_tex"));
456
458
459 LoadTexData data{};
460 data.br = br;
461 data.buffer = buffer;
462 data.size = size;
463
464 TaskParallelSettings settings;
466 BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, &settings);
467
471 "cursor_snap_overaly", size, size, 1, GPU_R8, usage, nullptr);
473
475 }
476
477 if (init) {
479 }
480
481 if (buffer) {
482 MEM_freeN(buffer);
483 }
484 }
485 else {
486 size = cursor_snap.size;
487 }
488
491
492 return 1;
493}
494
495static int project_brush_radius(ViewContext *vc, float radius, const float location[3])
496{
497 float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
498
499 ED_view3d_global_to_vector(vc->rv3d, location, view);
500
501 /* Create a vector that is not orthogonal to view. */
502
503 if (fabsf(view[0]) < 0.1f) {
504 nonortho[0] = view[0] + 1.0f;
505 nonortho[1] = view[1];
506 nonortho[2] = view[2];
507 }
508 else if (fabsf(view[1]) < 0.1f) {
509 nonortho[0] = view[0];
510 nonortho[1] = view[1] + 1.0f;
511 nonortho[2] = view[2];
512 }
513 else {
514 nonortho[0] = view[0];
515 nonortho[1] = view[1];
516 nonortho[2] = view[2] + 1.0f;
517 }
518
519 /* Get a vector in the plane of the view. */
520 cross_v3_v3v3(ortho, nonortho, view);
521 normalize_v3(ortho);
522
523 /* Make a point on the surface of the brush tangent to the view. */
524 mul_v3_fl(ortho, radius);
525 add_v3_v3v3(offset, location, ortho);
526
527 /* Project the center of the brush, and the tangent point to the view onto the screen. */
532 {
533 /* The distance between these points is the size of the projected brush in pixels. */
534 return len_v2v2(p1, p2);
535 }
536 /* Assert because the code that sets up the vectors should disallow this. */
537 BLI_assert(0);
538 return 0;
539}
540
541/* Draw an overlay that shows what effect the brush's texture will
542 * have on brush strength. */
544 Brush *brush,
545 ViewContext *vc,
546 int x,
547 int y,
548 float zoom,
549 const PaintMode mode,
550 bool col,
551 bool primary)
552{
553 rctf quad;
554 /* Check for overlay mode. */
555
556 MTex *mtex = (primary) ? &brush->mtex : &brush->mask_mtex;
557 bool valid = ((primary) ? (brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) != 0 :
558 (brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0);
559 int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha;
560
561 if (mode == PaintMode::Texture3D) {
562 if (primary && brush->image_brush_type != IMAGE_PAINT_BRUSH_TYPE_DRAW) {
563 /* All non-draw tools don't use the primary texture (clone, smear, soften.. etc). */
564 return false;
565 }
566 }
567
568 if (!(mtex->tex) ||
571 {
572 return false;
573 }
574
575 if (load_tex(brush, vc, zoom, col, primary)) {
576 GPU_color_mask(true, true, true, true);
578
579 if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
581
582 float center[2] = {
583 ups->draw_anchored ? ups->anchored_initial_mouse[0] : x,
584 ups->draw_anchored ? ups->anchored_initial_mouse[1] : y,
585 };
586
587 /* Brush rotation. */
590 GPU_matrix_translate_2f(-center[0], -center[1]);
591
592 /* Scale based on tablet pressure. */
593 if (primary && ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
594 const float scale = ups->size_pressure_value;
596 GPU_matrix_scale_2f(scale, scale);
597 GPU_matrix_translate_2f(-center[0], -center[1]);
598 }
599
600 if (ups->draw_anchored) {
601 quad.xmin = center[0] - ups->anchored_size;
602 quad.ymin = center[1] - ups->anchored_size;
603 quad.xmax = center[0] + ups->anchored_size;
604 quad.ymax = center[1] + ups->anchored_size;
605 }
606 else {
607 const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
608 quad.xmin = center[0] - radius;
609 quad.ymin = center[1] - radius;
610 quad.xmax = center[0] + radius;
611 quad.ymax = center[1] + radius;
612 }
613 }
614 else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
615 quad.xmin = 0;
616 quad.ymin = 0;
617 quad.xmax = BLI_rcti_size_x(&vc->region->winrct);
618 quad.ymax = BLI_rcti_size_y(&vc->region->winrct);
619 }
620 /* Stencil code goes here. */
621 else {
622 if (primary) {
623 quad.xmin = -brush->stencil_dimension[0];
624 quad.ymin = -brush->stencil_dimension[1];
625 quad.xmax = brush->stencil_dimension[0];
626 quad.ymax = brush->stencil_dimension[1];
627 }
628 else {
629 quad.xmin = -brush->mask_stencil_dimension[0];
630 quad.ymin = -brush->mask_stencil_dimension[1];
631 quad.xmax = brush->mask_stencil_dimension[0];
632 quad.ymax = brush->mask_stencil_dimension[1];
633 }
635 if (primary) {
637 }
638 else {
640 }
642 }
643
644 /* Set quad color. Colored overlay does not get blending. */
648
649 /* Premultiplied alpha blending. */
651
653
654 float final_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
655 if (!col) {
656 copy_v3_v3(final_color, U.sculpt_paint_overlay_col);
657 }
658 mul_v4_fl(final_color, overlay_alpha * 0.01f);
659 immUniformColor4fv(final_color);
660
661 GPUTexture *texture = (primary) ? primary_snap.overlay_texture :
663
668 "image", texture, {GPU_SAMPLER_FILTERING_LINEAR, extend_mode, extend_mode});
669
670 /* Draw textured quad. */
672 immAttr2f(texCoord, 0.0f, 0.0f);
673 immVertex2f(pos, quad.xmin, quad.ymin);
674 immAttr2f(texCoord, 1.0f, 0.0f);
675 immVertex2f(pos, quad.xmax, quad.ymin);
676 immAttr2f(texCoord, 1.0f, 1.0f);
677 immVertex2f(pos, quad.xmax, quad.ymax);
678 immAttr2f(texCoord, 0.0f, 1.0f);
679 immVertex2f(pos, quad.xmin, quad.ymax);
680 immEnd();
681
683
684 GPU_texture_unbind(texture);
685
688 }
689 }
690 return true;
691}
692
693/* Draw an overlay that shows what effect the brush's texture will
694 * have on brush strength. */
696 UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom)
697{
698 rctf quad;
699 /* Check for overlay mode. */
700
701 if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
702 return false;
703 }
704
705 if (load_tex_cursor(brush, vc, zoom)) {
706 bool do_pop = false;
707 float center[2];
708
709 GPU_color_mask(true, true, true, true);
711
712 if (ups->draw_anchored) {
714 quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
715 quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
716 quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
717 quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
718 }
719 else {
720 const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
721 center[0] = x;
722 center[1] = y;
723
724 quad.xmin = x - radius;
725 quad.ymin = y - radius;
726 quad.xmax = x + radius;
727 quad.ymax = y + radius;
728 }
729
730 /* Scale based on tablet pressure. */
731 if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
732 do_pop = true;
736 GPU_matrix_translate_2f(-center[0], -center[1]);
737 }
738
742
744
746
747 float final_color[4] = {UNPACK3(U.sculpt_paint_overlay_col), 1.0f};
748 mul_v4_fl(final_color, brush->cursor_overlay_alpha * 0.01f);
749 immUniformColor4fv(final_color);
750
751 /* Draw textured quad. */
752 immBindTextureSampler("image",
754 {GPU_SAMPLER_FILTERING_LINEAR,
755 GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER,
756 GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER});
757
759 immAttr2f(texCoord, 0.0f, 0.0f);
760 immVertex2f(pos, quad.xmin, quad.ymin);
761 immAttr2f(texCoord, 1.0f, 0.0f);
762 immVertex2f(pos, quad.xmax, quad.ymin);
763 immAttr2f(texCoord, 1.0f, 1.0f);
764 immVertex2f(pos, quad.xmax, quad.ymax);
765 immAttr2f(texCoord, 0.0f, 1.0f);
766 immVertex2f(pos, quad.xmin, quad.ymax);
767 immEnd();
768
770
772
773 if (do_pop) {
775 }
776 }
777 return true;
778}
779
781 Brush *brush,
782 ViewContext *vc,
783 int x,
784 int y,
785 float zoom,
786 PaintMode mode)
787{
788 /* Color means that primary brush texture is colored and
789 * secondary is used for alpha/mask control. */
791
792 bool alpha_overlay_active = false;
793
795 eGPUBlend blend_state = GPU_blend_get();
796 eGPUDepthTest depth_test = GPU_depth_test_get();
797
798 /* Translate to region. */
801 x -= vc->region->winrct.xmin;
802 y -= vc->region->winrct.ymin;
803
804 /* Colored overlay should be drawn separately. */
805 if (col) {
806 if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY)) {
807 alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, mode, true, true);
808 }
809 if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY)) {
810 alpha_overlay_active = paint_draw_tex_overlay(
811 ups, brush, vc, x, y, zoom, mode, false, false);
812 }
813 if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
814 alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
815 }
816 }
817 else {
818 if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PaintMode::Weight)) {
819 alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, mode, false, true);
820 }
821 if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
822 alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
823 }
824 }
825
827 GPU_blend(blend_state);
828 GPU_depth_test(depth_test);
829
830 return alpha_overlay_active;
831}
832
834 const float sel_col[4],
835 const float pivot_col[4],
836 float *co,
837 float width,
838 bool selected)
839{
840 immUniformColor4fv(selected ? sel_col : pivot_col);
841
842 GPU_line_width(3.0f);
843
844 float w = width / 2.0f;
845 const float tri[3][2] = {
846 {co[0], co[1] + w},
847 {co[0] - w, co[1] - w},
848 {co[0] + w, co[1] - w},
849 };
850
852 immVertex2fv(pos, tri[0]);
853 immVertex2fv(pos, tri[1]);
854 immVertex2fv(pos, tri[2]);
855 immEnd();
856
857 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
858 GPU_line_width(1.0f);
859
861 immVertex2fv(pos, tri[0]);
862 immVertex2fv(pos, tri[1]);
863 immVertex2fv(pos, tri[2]);
864 immEnd();
865}
866
868 const float sel_col[4],
869 const float handle_col[4],
870 const float *co,
871 float width,
872 bool selected)
873{
874 immUniformColor4fv(selected ? sel_col : handle_col);
875
876 GPU_line_width(3.0f);
877
878 float w = width / 2.0f;
879 float minx = co[0] - w;
880 float miny = co[1] - w;
881 float maxx = co[0] + w;
882 float maxy = co[1] + w;
883
884 imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
885
886 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
887 GPU_line_width(1.0f);
888
889 imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
890}
891
892BLI_INLINE void draw_bezier_handle_lines(uint pos, const float sel_col[4], BezTriple *bez)
893{
894 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
895 GPU_line_width(3.0f);
896
898 immVertex2fv(pos, bez->vec[0]);
899 immVertex2fv(pos, bez->vec[1]);
900 immVertex2fv(pos, bez->vec[2]);
901 immEnd();
902
903 GPU_line_width(1.0f);
904
905 if (bez->f1 || bez->f2) {
906 immUniformColor4fv(sel_col);
907 }
908 else {
909 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
910 }
912 immVertex2fv(pos, bez->vec[0]);
913 immVertex2fv(pos, bez->vec[1]);
914 immEnd();
915
916 if (bez->f3 || bez->f2) {
917 immUniformColor4fv(sel_col);
918 }
919 else {
920 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
921 }
923 immVertex2fv(pos, bez->vec[1]);
924 immVertex2fv(pos, bez->vec[2]);
925 immEnd();
926}
927
929{
932
933 if (brush->paint_curve && brush->paint_curve->points) {
934 PaintCurve *pc = brush->paint_curve;
935 PaintCurvePoint *cp = pc->points;
936
937 GPU_line_smooth(true);
939
940 /* Draw the bezier handles and the curve segment between the current and next point. */
942
944
945 float selec_col[4], handle_col[4], pivot_col[4];
949
950 for (int i = 0; i < pc->tot_points - 1; i++, cp++) {
951 int j;
952 PaintCurvePoint *cp_next = cp + 1;
953 float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
954 /* Use color coding to distinguish handles vs curve segments. */
955 draw_bezier_handle_lines(pos, selec_col, &cp->bez);
956 draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
958 pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
960 pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
961
962 for (j = 0; j < 2; j++) {
964 cp->bez.vec[2][j],
965 cp_next->bez.vec[0][j],
966 cp_next->bez.vec[1][j],
967 data + j,
969 sizeof(float[2]));
970 }
971
972 float(*v)[2] = (float(*)[2])data;
973
974 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
975 GPU_line_width(3.0f);
977 for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
978 immVertex2fv(pos, v[j]);
979 }
980 immEnd();
981
982 immUniformColor4f(0.9f, 0.9f, 1.0f, 0.5f);
983 GPU_line_width(1.0f);
985 for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
986 immVertex2fv(pos, v[j]);
987 }
988 immEnd();
989 }
990
991 /* Draw last line segment. */
992 draw_bezier_handle_lines(pos, selec_col, &cp->bez);
993 draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
995 pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
997 pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
998
1000 GPU_line_smooth(false);
1001
1003 }
1005}
1006
1007/* Special actions taken when paint cursor goes over mesh */
1008/* TODO: sculpt only for now. */
1010 Brush &brush,
1011 ViewContext &vc,
1012 const float location[3])
1013{
1014 float unprojected_radius, projected_radius;
1015
1016 /* Update the brush's cached 3D radius. */
1017 if (!BKE_brush_use_locked_size(vc.scene, &brush)) {
1018 /* Get 2D brush radius. */
1019 if (ups.draw_anchored) {
1020 projected_radius = ups.anchored_size;
1021 }
1022 else {
1023 if (brush.flag & BRUSH_ANCHORED) {
1024 projected_radius = 8;
1025 }
1026 else {
1027 projected_radius = BKE_brush_size_get(vc.scene, &brush);
1028 }
1029 }
1030
1031 /* Convert brush radius from 2D to 3D. */
1032 unprojected_radius = paint_calc_object_space_radius(vc, location, projected_radius);
1033
1034 /* Scale 3D brush radius by pressure. */
1035 if (ups.stroke_active && BKE_brush_use_size_pressure(&brush)) {
1036 unprojected_radius *= ups.size_pressure_value;
1037 }
1038
1039 /* Set cached value in either Brush or UnifiedPaintSettings. */
1040 BKE_brush_unprojected_radius_set(vc.scene, &brush, unprojected_radius);
1041 }
1042}
1043
1044static void cursor_draw_point_screen_space(const uint gpuattr,
1045 const ARegion *region,
1046 const float true_location[3],
1047 const float obmat[4][4],
1048 const int size)
1049{
1050 float translation_vertex_cursor[3], location[3];
1051 copy_v3_v3(location, true_location);
1052 mul_m4_v3(obmat, location);
1053 ED_view3d_project_v3(region, location, translation_vertex_cursor);
1054 /* Do not draw points behind the view. Z [near, far] is mapped to [-1, 1]. */
1055 if (translation_vertex_cursor[2] <= 1.0f) {
1057 gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
1058 }
1059}
1060
1061static void cursor_draw_tiling_preview(const uint gpuattr,
1062 const ARegion *region,
1063 const float true_location[3],
1064 const Sculpt &sd,
1065 const Object &ob,
1066 const float radius)
1067{
1068 BLI_assert(ob.type == OB_MESH);
1070 if (!mesh) {
1071 mesh = static_cast<const Mesh *>(ob.data);
1072 }
1073 const Bounds<float3> bounds = *mesh->bounds_min_max();
1074 float orgLoc[3], location[3];
1075 int tile_pass = 0;
1076 int start[3];
1077 int end[3];
1078 int cur[3];
1079 const float *step = sd.paint.tile_offset;
1080
1081 copy_v3_v3(orgLoc, true_location);
1082 for (int dim = 0; dim < 3; dim++) {
1083 if ((sd.paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
1084 start[dim] = (bounds.min[dim] - orgLoc[dim] - radius) / step[dim];
1085 end[dim] = (bounds.max[dim] - orgLoc[dim] + radius) / step[dim];
1086 }
1087 else {
1088 start[dim] = end[dim] = 0;
1089 }
1090 }
1091 copy_v3_v3_int(cur, start);
1092 for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
1093 for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
1094 for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
1095 if (!cur[0] && !cur[1] && !cur[2]) {
1096 /* Skip tile at orgLoc, this was already handled before all others. */
1097 continue;
1098 }
1099 tile_pass++;
1100 for (int dim = 0; dim < 3; dim++) {
1101 location[dim] = cur[dim] * step[dim] + orgLoc[dim];
1102 }
1103 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1104 }
1105 }
1106 }
1107 (void)tile_pass; /* Quiet set-but-unused warning (may be removed). */
1108}
1109
1110static void cursor_draw_point_with_symmetry(const uint gpuattr,
1111 const ARegion *region,
1112 const float true_location[3],
1113 const Sculpt &sd,
1114 const Object &ob,
1115 const float radius)
1116{
1117 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
1118 float3 location;
1119 float symm_rot_mat[4][4];
1120
1121 for (int i = 0; i <= symm; i++) {
1122 if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5)))) {
1123
1124 /* Axis Symmetry. */
1125 location = symmetry_flip(true_location, ePaintSymmetryFlags(i));
1126 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1127
1128 /* Tiling. */
1129 cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
1130
1131 /* Radial Symmetry. */
1132 for (char raxis = 0; raxis < 3; raxis++) {
1133 for (int r = 1; r < sd.radial_symm[raxis]; r++) {
1134 float angle = 2 * M_PI * r / sd.radial_symm[int(raxis)];
1135 location = symmetry_flip(true_location, ePaintSymmetryFlags(i));
1136 unit_m4(symm_rot_mat);
1137 rotate_m4(symm_rot_mat, raxis + 'X', angle);
1138 mul_m4_v3(symm_rot_mat, location);
1139
1140 cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
1141 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1142 }
1143 }
1144 }
1145 }
1146}
1147
1149 const uint gpuattr,
1150 const Brush &brush,
1151 const Object &object)
1152{
1153 if (!(brush.flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
1154 return;
1155 }
1156
1157 const SculptSession &ss = *object.sculpt;
1158 if (bke::object::pbvh_get(object)->type() != bke::pbvh::Type::Mesh) {
1159 return;
1160 }
1161
1162 if (!ss.deform_modifiers_active) {
1163 return;
1164 }
1165
1166 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
1167
1168 /* Cursor normally draws on top, but for this part we need depth tests. */
1169 const eGPUDepthTest depth_test = GPU_depth_test_get();
1170 if (!depth_test) {
1172 }
1173
1174 GPU_line_width(1.0f);
1175 if (!ss.preview_verts.is_empty()) {
1178 for (const int vert : ss.preview_verts) {
1179 immVertex3fv(gpuattr, positions[vert]);
1180 }
1181 immEnd();
1182 }
1183
1184 /* Restore depth test value. */
1185 if (!depth_test) {
1187 }
1188}
1189
1191 const Brush &brush,
1192 const float rds,
1193 const float line_width,
1194 const float outline_col[3],
1195 const float alpha)
1196{
1197 float cursor_trans[4][4];
1198 unit_m4(cursor_trans);
1199 translate_m4(cursor_trans, 0.0f, 0.0f, brush.height);
1201 GPU_matrix_mul(cursor_trans);
1202
1203 GPU_line_width(line_width);
1204 immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
1205 imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
1207}
1208
1210{
1211 switch (mode) {
1212 case PaintMode::Sculpt:
1213 case PaintMode::Vertex:
1214 case PaintMode::Weight:
1215 return false;
1223 case PaintMode::GPencil:
1224 return true;
1225 case PaintMode::Invalid:
1227 }
1228 return true;
1229}
1230
1236
1242 Depsgraph *depsgraph;
1249
1250 /* Sculpt related data. */
1253
1258
1261 float radius;
1262
1263 /* 3D view cursor position and normal. */
1264 float location[3];
1266 float normal[3];
1267
1268 /* Cursor main colors. */
1269 float outline_col[3];
1271
1272 /* GPU attribute for drawing. */
1274
1276
1277 /* This variable is set after drawing the overlay, not on initialization. It can't be used for
1278 * checking if alpha overlay is enabled before drawing it. */
1280
1281 float zoomx;
1282 int x, y;
1283 float translation[2];
1284
1287};
1288
1290 const int x,
1291 const int y,
1292 PaintCursorContext *pcontext)
1293{
1294 ARegion *region = CTX_wm_region(C);
1295 if (region && region->regiontype != RGN_TYPE_WINDOW) {
1296 return false;
1297 }
1298
1299 pcontext->C = C;
1300 pcontext->region = region;
1301 pcontext->wm = CTX_wm_manager(C);
1302 pcontext->win = CTX_wm_window(C);
1304 pcontext->scene = CTX_data_scene(C);
1305 pcontext->ups = &pcontext->scene->toolsettings->unified_paint_settings;
1307 if (pcontext->paint == nullptr) {
1308 return false;
1309 }
1310 pcontext->brush = BKE_paint_brush(pcontext->paint);
1311 if (pcontext->brush == nullptr) {
1312 return false;
1313 }
1315
1316 pcontext->vc = ED_view3d_viewcontext_init(C, pcontext->depsgraph);
1317
1318 if (pcontext->brush->flag & BRUSH_CURVE) {
1319 pcontext->cursor_type = PAINT_CURSOR_CURVE;
1320 }
1321 else if (paint_use_2d_cursor(pcontext->mode)) {
1322 pcontext->cursor_type = PAINT_CURSOR_2D;
1323 }
1324 else {
1325 pcontext->cursor_type = PAINT_CURSOR_3D;
1326 }
1327
1328 pcontext->x = x;
1329 pcontext->y = y;
1330 pcontext->translation[0] = float(x);
1331 pcontext->translation[1] = float(y);
1332
1333 float zoomx, zoomy;
1334 get_imapaint_zoom(C, &zoomx, &zoomy);
1335 pcontext->zoomx = max_ff(zoomx, zoomy);
1336 pcontext->final_radius = (BKE_brush_size_get(pcontext->scene, pcontext->brush) * zoomx);
1337
1338 /* There is currently no way to check if the direction is inverted before starting the stroke,
1339 * so this does not reflect the state of the brush in the UI. */
1340 if (((pcontext->ups->draw_inverted == 0) ^ ((pcontext->brush->flag & BRUSH_DIR_IN) == 0)) &&
1342 {
1343 copy_v3_v3(pcontext->outline_col, pcontext->brush->sub_col);
1344 }
1345 else {
1346 copy_v3_v3(pcontext->outline_col, pcontext->brush->add_col);
1347 }
1348 pcontext->outline_alpha = pcontext->brush->add_col[3];
1349
1350 Object *active_object = pcontext->vc.obact;
1351 pcontext->ss = active_object ? active_object->sculpt : nullptr;
1352
1353 if (pcontext->ss && pcontext->ss->draw_faded_cursor) {
1354 pcontext->outline_alpha = 0.3f;
1355 copy_v3_fl(pcontext->outline_col, 0.8f);
1356 }
1357
1358 const bool is_brush_tool = paint_brush_tool_poll(C);
1359 if (!is_brush_tool) {
1360 /* Use a default color for tools that are not brushes. */
1361 pcontext->outline_alpha = 0.8f;
1362 copy_v3_fl(pcontext->outline_col, 0.8f);
1363 }
1364
1365 pcontext->is_stroke_active = pcontext->ups->stroke_active;
1366
1367 return true;
1368}
1369
1371{
1372 if (pcontext->is_cursor_over_mesh) {
1373 Brush *brush = BKE_paint_brush(pcontext->paint);
1375 &pcontext->vc,
1376 BKE_brush_unprojected_radius_get(pcontext->scene, brush),
1377 pcontext->location);
1378
1379 if (pcontext->pixel_radius == 0) {
1380 pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush);
1381 }
1382
1383 copy_v3_v3(pcontext->scene_space_location, pcontext->location);
1384 mul_m4_v3(pcontext->vc.obact->object_to_world().ptr(), pcontext->scene_space_location);
1385 }
1386 else {
1387 Sculpt *sd = CTX_data_tool_settings(pcontext->C)->sculpt;
1388 Brush *brush = BKE_paint_brush(&sd->paint);
1389
1390 pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush);
1391 }
1392}
1393
1395{
1396 BLI_assert(pcontext->ss != nullptr);
1397 BLI_assert(pcontext->mode == PaintMode::Sculpt);
1398
1399 bContext *C = pcontext->C;
1400 SculptSession &ss = *pcontext->ss;
1401 Brush &brush = *pcontext->brush;
1402 Scene &scene = *pcontext->scene;
1403 UnifiedPaintSettings &ups = *pcontext->ups;
1404 ViewContext &vc = pcontext->vc;
1406
1407 const float mval_fl[2] = {
1408 float(pcontext->x - pcontext->region->winrct.xmin),
1409 float(pcontext->y - pcontext->region->winrct.ymin),
1410 };
1411
1412 /* Ensure that the PBVH is generated before we call #SCULPT_cursor_geometry_info_update because
1413 * the PBVH is needed to do a ray-cast to find the active vertex. */
1414 bke::object::pbvh_ensure(*pcontext->depsgraph, *pcontext->vc.obact);
1415
1416 /* This updates the active vertex, which is needed for most of the Sculpt/Vertex Colors tools to
1417 * work correctly */
1419 if (!ups.stroke_active) {
1421 C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
1422 copy_v3_v3(pcontext->location, gi.location);
1423 copy_v3_v3(pcontext->normal, gi.normal);
1424 }
1425 else {
1426 pcontext->is_cursor_over_mesh = ups.last_hit;
1427 copy_v3_v3(pcontext->location, ups.last_location);
1428 }
1429
1431
1432 if (BKE_brush_use_locked_size(&scene, &brush)) {
1433 BKE_brush_size_set(&scene, &brush, pcontext->pixel_radius);
1434 }
1435
1436 if (pcontext->is_cursor_over_mesh) {
1438 }
1439
1440 pcontext->sd = CTX_data_tool_settings(pcontext->C)->sculpt;
1441}
1442
1444{
1445 if (pcontext->win->grabcursor != 0) {
1446 /* Don't set the cursor while it's grabbed, since this will show the cursor when interacting
1447 * with the UI (dragging a number button for e.g.), see: #102792. */
1448 return;
1449 }
1451 WM_cursor_set(pcontext->win, WM_CURSOR_DOT);
1452 }
1453 else {
1454 WM_cursor_set(pcontext->win, WM_CURSOR_PAINT);
1455 }
1456}
1457
1459{
1461
1462 /* Draw brush outline. */
1463 if (pcontext->ups->stroke_active && BKE_brush_use_size_pressure(pcontext->brush)) {
1464 imm_draw_circle_wire_2d(pcontext->pos,
1465 pcontext->translation[0],
1466 pcontext->translation[1],
1467 pcontext->final_radius * pcontext->ups->size_pressure_value,
1468 40);
1469 /* Outer at half alpha. */
1470 immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.5f);
1471 }
1472
1473 GPU_line_width(1.0f);
1474 imm_draw_circle_wire_2d(pcontext->pos,
1475 pcontext->translation[0],
1476 pcontext->translation[1],
1477 pcontext->final_radius,
1478 40);
1479}
1480
1482{
1483 float radius = float(pcontext->pixel_radius);
1484
1485 /* Red-ish color with alpha. */
1486 immUniformColor4ub(255, 100, 100, 20);
1487 imm_draw_circle_fill_2d(pcontext->pos, pcontext->x, pcontext->y, radius, 40);
1488
1490
1492
1493 float viewport_size[4];
1494 GPU_viewport_size_get_f(viewport_size);
1495 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1496
1497 immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1498 immUniform1i("colors_len", 0); /* "simple" mode */
1499 immUniform1f("dash_width", 12.0f);
1500 immUniform1f("udash_factor", 0.5f);
1501
1502 /* XXX Dashed shader gives bad results with sets of small segments
1503 * currently, temp hack around the issue. :( */
1504 const int nsegments = max_ii(8, radius / 2);
1505 imm_draw_circle_wire_2d(pcontext->pos, pcontext->x, pcontext->y, radius, nsegments);
1506}
1507
1509{
1510 if (pcontext->region && !BLI_rcti_isect_pt(&pcontext->region->winrct, pcontext->x, pcontext->y))
1511 {
1512 return;
1513 }
1514
1515 Object *object = CTX_data_active_object(pcontext->C);
1516 if (object->type != OB_GREASE_PENCIL) {
1517 return;
1518 }
1519
1520 GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
1521 Paint *paint = pcontext->paint;
1522 Brush *brush = pcontext->brush;
1523 if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) {
1524 return;
1525 }
1526
1527 float3 color(1.0f);
1528 const int x = pcontext->x;
1529 const int y = pcontext->y;
1530
1531 if (pcontext->mode == PaintMode::GPencil) {
1532 /* Hide the cursor while drawing. */
1533 if (grease_pencil->runtime->is_drawing_stroke) {
1534 return;
1535 }
1536
1537 /* Eraser has a special shape and uses a different shader program. */
1539 grease_pencil->runtime->temp_use_eraser)
1540 {
1541 /* If we use the eraser from the draw tool with a "scene" radius unit, we need to draw the
1542 * cursor with the appropriate size. */
1543 if (grease_pencil->runtime->temp_use_eraser && (brush->flag & BRUSH_LOCK_SIZE) != 0) {
1544 pcontext->pixel_radius = int(grease_pencil->runtime->temp_eraser_size);
1545 }
1546 else {
1547 pcontext->pixel_radius = brush->size;
1548 }
1549 grease_pencil_eraser_draw(pcontext);
1550 return;
1551 }
1552
1554 /* The fill tool doesn't use a brush size currently, but not showing any brush means that it
1555 * can be hard to see where the cursor is. Use a fixed size that's not too big (10px). By
1556 * disabling the "Display Cursor" option, this can still be turned off. */
1557 pcontext->pixel_radius = 10;
1558 }
1559
1561 pcontext->pixel_radius = brush->size;
1562 }
1563
1565 if ((brush->flag & BRUSH_LOCK_SIZE) != 0) {
1566 const bke::greasepencil::Layer *layer = grease_pencil->get_active_layer();
1567 const ed::greasepencil::DrawingPlacement placement(
1568 *pcontext->scene, *pcontext->region, *pcontext->vc.v3d, *object, layer);
1569 const float3 location = placement.project(float2(pcontext->x, pcontext->y));
1571 &pcontext->vc, brush->unprojected_radius, location);
1572 brush->size = std::max(pcontext->pixel_radius, 1);
1573 }
1574 else {
1575 pcontext->pixel_radius = brush->size;
1576 }
1577 }
1578
1579 /* Get current drawing material. */
1581 MaterialGPencilStyle *gp_style = ma->gp_style;
1582
1583 /* Follow user settings for the size of the draw cursor:
1584 * - Fixed size, or
1585 * - Brush size (i.e. stroke thickness)
1586 */
1587 if ((gp_style) && ((brush->flag & BRUSH_SMOOTH_STROKE) == 0) &&
1589 {
1590
1591 const bool use_vertex_color = (pcontext->scene->toolsettings->gp_paint->mode ==
1593 const bool use_vertex_color_stroke = use_vertex_color &&
1597 color = use_vertex_color_stroke ? float3(brush->rgb) : float4(gp_style->stroke_rgba).xyz();
1598 }
1599 }
1600
1601 if ((brush->flag & BRUSH_SMOOTH_STROKE) != 0) {
1602 const float scale = 1.0f / 255.0f;
1603 color = scale * float3(paint->paint_cursor_col);
1604 }
1605 }
1606 else if (pcontext->mode == PaintMode::VertexGPencil) {
1607 pcontext->pixel_radius = BKE_brush_size_get(pcontext->vc.scene, brush);
1608 color = BKE_brush_color_get(pcontext->vc.scene, paint, brush);
1609 }
1610
1611 GPU_line_width(1.0f);
1612 /* Inner Ring: Color from UI panel */
1613 immUniformColor4f(color.x, color.y, color.z, 0.8f);
1614 imm_draw_circle_wire_2d(pcontext->pos, x, y, pcontext->pixel_radius, 32);
1615
1616 /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
1617 const float3 darkcolor = color * 0.40f;
1618 immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
1619 imm_draw_circle_wire_2d(pcontext->pos, x, y, pcontext->pixel_radius + 1, 32);
1620}
1621
1623{
1624 switch (pcontext->mode) {
1625 case PaintMode::GPencil:
1628 break;
1629 default:
1631 }
1632}
1633
1635{
1636 GPU_line_width(1.0f);
1638 imm_draw_circle_wire_3d(pcontext->pos,
1639 pcontext->translation[0],
1640 pcontext->translation[1],
1641 pcontext->final_radius,
1642 40);
1643}
1644
1646{
1647 GPU_line_width(1.0f);
1648 /* Reduce alpha to increase the contrast when the cursor is over the mesh. */
1649 immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.8);
1650 imm_draw_circle_wire_3d(pcontext->pos,
1651 pcontext->translation[0],
1652 pcontext->translation[1],
1653 pcontext->final_radius,
1654 80);
1655 immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.35f);
1656 imm_draw_circle_wire_3d(pcontext->pos,
1657 pcontext->translation[0],
1658 pcontext->translation[1],
1659 pcontext->final_radius * clamp_f(pcontext->brush->alpha, 0.0f, 1.0f),
1660 80);
1661}
1662
1664{
1665 if (!BKE_brush_use_locked_size(pcontext->scene, pcontext->brush)) {
1667 pcontext->vc, pcontext->location, BKE_brush_size_get(pcontext->scene, pcontext->brush));
1668 }
1669 else {
1670 pcontext->radius = BKE_brush_unprojected_radius_get(pcontext->scene, pcontext->brush);
1671 }
1672}
1673
1675{
1676 float cursor_trans[4][4], cursor_rot[4][4];
1677 const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
1678 float quat[4];
1679 copy_m4_m4(cursor_trans, pcontext->vc.obact->object_to_world().ptr());
1680 translate_m4(cursor_trans, pcontext->location[0], pcontext->location[1], pcontext->location[2]);
1681 rotation_between_vecs_to_quat(quat, z_axis, pcontext->normal);
1682 quat_to_mat4(cursor_rot, quat);
1683 GPU_matrix_mul(cursor_trans);
1684 GPU_matrix_mul(cursor_rot);
1685}
1686
1688{
1690 GPU_line_width(2.0f);
1691 imm_draw_circle_wire_3d(pcontext->pos, 0, 0, pcontext->radius, 80);
1692
1693 GPU_line_width(1.0f);
1694 immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.5f);
1696 pcontext->pos, 0, 0, pcontext->radius * clamp_f(pcontext->brush->alpha, 0.0f, 1.0f), 80);
1697}
1698
1700{
1701 SculptSession &ss = *pcontext->ss;
1702 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1703 GPU_line_width(2.0f);
1704
1705 BLI_assert(ss.pose_ik_chain_preview->initial_head_coords.size() ==
1706 ss.pose_ik_chain_preview->initial_orig_coords.size());
1707
1708 immBegin(GPU_PRIM_LINES, ss.pose_ik_chain_preview->initial_head_coords.size() * 2);
1709 for (const int i : ss.pose_ik_chain_preview->initial_head_coords.index_range()) {
1710 immVertex3fv(pcontext->pos, ss.pose_ik_chain_preview->initial_orig_coords[i]);
1711 immVertex3fv(pcontext->pos, ss.pose_ik_chain_preview->initial_head_coords[i]);
1712 }
1713
1714 immEnd();
1715}
1716
1718{
1719
1720 SculptSession &ss = *pcontext->ss;
1721 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1722 for (const int i : ss.pose_ik_chain_preview->initial_orig_coords.index_range()) {
1724 pcontext->region,
1725 ss.pose_ik_chain_preview->initial_orig_coords[i],
1726 pcontext->vc.obact->object_to_world().ptr(),
1727 3);
1728 }
1729}
1730
1732{
1733 if (!pcontext->ss->boundary_preview) {
1734 /* There is no guarantee that a boundary preview exists as there may be no boundaries
1735 * inside the brush radius. */
1736 return;
1737 }
1738 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1740 pcontext->region,
1741 pcontext->ss->boundary_preview->pivot_position,
1742 pcontext->vc.obact->object_to_world().ptr(),
1743 3);
1744}
1745
1747{
1748 SculptSession &ss = *pcontext->ss;
1749 /* Needed for updating the necessary SculptSession data in order to initialize the
1750 * boundary data for the preview. */
1751 BKE_sculpt_update_object_for_edit(pcontext->depsgraph, pcontext->vc.obact, false);
1752
1754 *pcontext->depsgraph, *pcontext->vc.obact, pcontext->brush, pcontext->radius);
1755}
1756
1758{
1759 const Brush &brush = *pcontext->brush;
1760
1761 /* 2D falloff is better represented with the default 2D cursor,
1762 * there is no need to draw anything else. */
1765 return;
1766 }
1767
1768 if (pcontext->alpha_overlay_drawn) {
1770 return;
1771 }
1772
1773 if (!pcontext->is_cursor_over_mesh) {
1775 return;
1776 }
1777
1778 BLI_assert(pcontext->vc.obact);
1779 Object &active_object = *pcontext->vc.obact;
1781
1783
1784 /* Setup drawing. */
1785 wmViewport(&pcontext->region->winrct);
1786
1787 /* Drawing of Cursor overlays in 2D screen space. */
1788
1789 /* Cursor location symmetry points. */
1790
1791 float3 active_vertex_co;
1793 SculptSession &ss = *pcontext->ss;
1794 if (bke::object::pbvh_get(active_object)->type() == bke::pbvh::Type::Mesh) {
1795 const Span<float3> positions = vert_positions_for_grab_active_get(*pcontext->depsgraph,
1796 active_object);
1797 active_vertex_co = positions[std::get<int>(ss.active_vert())];
1798 }
1799 else {
1800 active_vertex_co = pcontext->ss->active_vert_position(*pcontext->depsgraph, active_object);
1801 }
1802 }
1803 else {
1804 active_vertex_co = pcontext->ss->active_vert_position(*pcontext->depsgraph, active_object);
1805 }
1806 if (len_v3v3(active_vertex_co, pcontext->location) < pcontext->radius) {
1809 pcontext->region,
1810 active_vertex_co,
1811 *pcontext->sd,
1812 active_object,
1813 pcontext->radius);
1814 }
1815
1816 const bool is_brush_tool = paint_brush_tool_poll(pcontext->C);
1817
1818 /* Pose brush updates and rotation origins. */
1819
1820 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_POSE) {
1821 /* Just after switching to the Pose Brush, the active vertex can be the same and the
1822 * cursor won't be tagged to update, so always initialize the preview chain if it is
1823 * nullptr before drawing it. */
1824 SculptSession &ss = *pcontext->ss;
1825 const bool update_previews = pcontext->prev_active_vert_index !=
1826 pcontext->ss->active_vert_index();
1827 if (update_previews || !ss.pose_ik_chain_preview) {
1828 BKE_sculpt_update_object_for_edit(pcontext->depsgraph, &active_object, false);
1829
1830 /* Free the previous pose brush preview. */
1831 if (ss.pose_ik_chain_preview) {
1832 ss.pose_ik_chain_preview.reset();
1833 }
1834
1835 /* Generate a new pose brush preview from the current cursor location. */
1837 *pcontext->depsgraph, active_object, ss, brush, pcontext->location, pcontext->radius);
1838 }
1839
1840 /* Draw the pose brush rotation origins. */
1842 }
1843
1844 /* Expand operation origin. */
1845 if (pcontext->ss->expand_cache) {
1846 const int vert = pcontext->ss->expand_cache->initial_active_vert;
1847
1848 float3 position;
1849 switch (bke::object::pbvh_get(active_object)->type()) {
1850 case bke::pbvh::Type::Mesh: {
1851 const Span positions = bke::pbvh::vert_positions_eval(*pcontext->depsgraph, active_object);
1852 position = positions[vert];
1853 break;
1854 }
1856 const SubdivCCG &subdiv_ccg = *pcontext->ss->subdiv_ccg;
1857 position = subdiv_ccg.positions[vert];
1858 break;
1859 }
1861 BMesh &bm = *pcontext->ss->bm;
1862 position = BM_vert_at_index(&bm, vert)->co;
1863 break;
1864 }
1865 }
1867 pcontext->pos, pcontext->region, position, active_object.object_to_world().ptr(), 2);
1868 }
1869
1870 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_BOUNDARY) {
1873 }
1874
1875 /* Setup 3D perspective drawing. */
1877 ED_view3d_draw_setup_view(pcontext->wm,
1878 pcontext->win,
1879 pcontext->depsgraph,
1880 pcontext->scene,
1881 pcontext->region,
1882 CTX_wm_view3d(pcontext->C),
1883 nullptr,
1884 nullptr,
1885 nullptr);
1886
1888 GPU_matrix_mul(active_object.object_to_world().ptr());
1889
1890 /* Drawing Cursor overlays in 3D object space. */
1891 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_GRAB &&
1893 {
1895 *pcontext->depsgraph, *pcontext->vc.obact, *pcontext->ss, pcontext->radius);
1897 *pcontext->depsgraph, pcontext->pos, *pcontext->brush, active_object);
1898 }
1899
1900 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_POSE) {
1902 }
1903
1904 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_BOUNDARY) {
1906 pcontext->pos, *pcontext->ss, pcontext->outline_col, pcontext->outline_alpha);
1907 boundary::pivot_line_preview_draw(pcontext->pos, *pcontext->ss);
1908 }
1909
1911
1912 /* Drawing Cursor overlays in Paint Cursor space (as additional info on top of the brush cursor)
1913 */
1916 /* Main inactive cursor. */
1918
1919 /* Cloth brush local simulation areas. */
1920 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_CLOTH &&
1922 {
1923 const float white[3] = {1.0f, 1.0f, 1.0f};
1924 const float zero_v[3] = {0.0f};
1925 /* This functions sets its own drawing space in order to draw the simulation limits when the
1926 * cursor is active. When used here, this cursor overlay is already in cursor space, so its
1927 * position and normal should be set to 0. */
1929 pcontext->pos, brush, zero_v, zero_v, pcontext->radius, 1.0f, white, 0.25f);
1930 }
1931
1932 /* Layer brush height. */
1933 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_LAYER) {
1935 brush,
1936 pcontext->radius,
1937 1.0f,
1938 pcontext->outline_col,
1939 pcontext->outline_alpha);
1940 }
1941
1943
1944 /* Reset drawing. */
1946 wmWindowViewport(pcontext->win);
1947}
1948
1950{
1951 BLI_assert(pcontext->ss != nullptr);
1952 BLI_assert(pcontext->mode == PaintMode::Sculpt);
1953
1954 SculptSession &ss = *pcontext->ss;
1955 Brush &brush = *pcontext->brush;
1956
1957 /* The cursor can be updated as active before creating the StrokeCache, so this needs to be
1958 * checked. */
1959 if (!ss.cache) {
1960 return;
1961 }
1962
1963 /* Most of the brushes initialize the necessary data for the custom cursor drawing after the
1964 * first brush step, so make sure that it is not drawn before being initialized. */
1966 return;
1967 }
1968
1969 /* Setup drawing. */
1970 wmViewport(&pcontext->region->winrct);
1972 ED_view3d_draw_setup_view(pcontext->wm,
1973 pcontext->win,
1974 pcontext->depsgraph,
1975 pcontext->scene,
1976 pcontext->region,
1977 CTX_wm_view3d(pcontext->C),
1978 nullptr,
1979 nullptr,
1980 nullptr);
1982 GPU_matrix_mul(pcontext->vc.obact->object_to_world().ptr());
1983
1984 /* Draw the special active cursors different brush types may have. */
1985
1988 *pcontext->depsgraph, pcontext->pos, brush, *pcontext->vc.obact);
1989 }
1990
1993 pcontext->pos, brush, ss, pcontext->outline_col, pcontext->outline_alpha);
1994 }
1995
1999 pcontext->pos, ss, pcontext->outline_col, pcontext->outline_alpha);
2000 }
2003 {
2004 /* Display the simulation limits if sculpting outside them. */
2005 /* This does not makes much sense of plane falloff as the falloff is infinite or global. */
2006
2008 ss.cache->radius * (1.0f + brush.cloth_sim_limit))
2009 {
2010 const float red[3] = {1.0f, 0.2f, 0.2f};
2012 brush,
2015 ss.cache->radius,
2016 2.0f,
2017 red,
2018 0.8f);
2019 }
2020 }
2021 }
2022
2024
2026 wmWindowViewport(pcontext->win);
2027}
2028
2030{
2031
2032 /* These paint tools are not using the SculptSession, so they need to use the default 2D brush
2033 * cursor in the 3D view. */
2034 if (pcontext->mode != PaintMode::Sculpt || !pcontext->ss) {
2036 return;
2037 }
2038
2040
2041 if (pcontext->is_stroke_active) {
2043 }
2044 else {
2046 }
2047}
2048
2050{
2051 ViewContext *vc = &pcontext->vc;
2052 return vc->rv3d && (vc->rv3d->rflag & RV3D_NAVIGATING);
2053}
2054
2056{
2057 if (pcontext->paint->flags & PAINT_SHOW_BRUSH) {
2060 {
2061 return false;
2062 }
2063 return true;
2064 }
2065 return false;
2066}
2067
2069{
2070 /* Don't calculate rake angles while a stroke is active because the rake variables are global
2071 * and we may get interference with the stroke itself.
2072 * For line strokes, such interference is visible. */
2073 if (!pcontext->ups->stroke_active) {
2075 *pcontext->ups, *pcontext->brush, pcontext->translation, pcontext->mode, true);
2076 }
2077}
2078
2080{
2081 pcontext->alpha_overlay_drawn = paint_draw_alpha_overlay(pcontext->ups,
2082 pcontext->brush,
2083 &pcontext->vc,
2084 pcontext->x,
2085 pcontext->y,
2086 pcontext->zoomx,
2087 pcontext->mode);
2088}
2089
2091{
2092 UnifiedPaintSettings *ups = pcontext->ups;
2093 if (ups->draw_anchored) {
2094 pcontext->final_radius = ups->anchored_size;
2095 copy_v2_fl2(pcontext->translation,
2096 ups->anchored_initial_mouse[0] + pcontext->region->winrct.xmin,
2097 ups->anchored_initial_mouse[1] + pcontext->region->winrct.ymin);
2098 }
2099}
2100
2110
2120
2127
2128static void paint_draw_cursor(bContext *C, int x, int y, void * /*unused*/)
2129{
2130 PaintCursorContext pcontext;
2131 if (!paint_cursor_context_init(C, x, y, &pcontext)) {
2132 return;
2133 }
2134
2135 if (!paint_cursor_is_brush_cursor_enabled(&pcontext)) {
2136 /* For Grease Pencil draw mode, we want to we only render a small mouse cursor (dot) if the
2137 * paint cursor is disabled so that the default mouse cursor doesn't get in the way of tablet
2138 * users. See #130089. */
2139 if (pcontext.mode == PaintMode::GPencil) {
2140 WM_cursor_set(pcontext.win, WM_CURSOR_DOT);
2141 }
2142 return;
2143 }
2144 if (paint_cursor_is_3d_view_navigating(&pcontext)) {
2145 return;
2146 }
2147
2148 switch (pcontext.cursor_type) {
2149 case PAINT_CURSOR_CURVE:
2150 paint_draw_curve_cursor(pcontext.brush, &pcontext.vc);
2151 break;
2152 case PAINT_CURSOR_2D:
2153 paint_update_mouse_cursor(&pcontext);
2154
2158
2162 break;
2163 case PAINT_CURSOR_3D:
2164 paint_update_mouse_cursor(&pcontext);
2165
2169
2173 break;
2174 }
2175}
2176
2177} // namespace blender::ed::sculpt_paint
2178
2179/* Public API */
2180
2181void ED_paint_cursor_start(Paint *paint, bool (*poll)(bContext *C))
2182{
2183 if (paint && !paint->paint_cursor) {
2186 }
2187
2188 /* Invalidate the paint cursors. */
2190}
float BKE_brush_unprojected_radius_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1133
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
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1091
bool BKE_brush_sculpt_has_secondary_color(const Brush *brush)
Definition brush.cc:1101
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1029
bool BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
Definition brush.cc:1083
float BKE_brush_curve_strength_clamped(const Brush *br, float p, float len)
Definition brush.cc:1444
void BKE_curvemapping_init(CurveMapping *cumap)
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:1663
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)
void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
ImagePool * BKE_image_pool_new(void)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh_no_subsurf(const Object *object_eval)
PaintMode
Definition BKE_paint.hh:99
@ SculptGreasePencil
ePaintOverlayControlFlags BKE_paint_get_overlay_flags()
Definition paint.cc:292
ePaintOverlayControlFlags
Definition BKE_paint.hh:123
@ PAINT_OVERLAY_INVALID_CURVE
Definition BKE_paint.hh:126
@ PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY
Definition BKE_paint.hh:125
@ PAINT_OVERLAY_OVERRIDE_CURSOR
Definition BKE_paint.hh:127
@ PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY
Definition BKE_paint.hh:124
@ PAINT_OVERLAY_OVERRIDE_SECONDARY
Definition BKE_paint.hh:129
@ PAINT_OVERLAY_OVERRIDE_PRIMARY
Definition BKE_paint.hh:128
void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag)
Definition paint.cc:315
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:477
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
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:2005
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:506
void BKE_paint_invalidate_overlay_all()
Definition paint.cc:286
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
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)
#define M_PI
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
void unit_m4(float m[4][4])
Definition rct.c:1127
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void rotate_m4(float mat[4][4], char axis, float angle)
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
void quat_to_mat4(float m[4][4], const float q[4])
#define RAD2DEGF(_rad)
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_fl2(float v[2], float x, float y)
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 void copy_v3_fl(float r[3], float f)
MINLINE float normalize_v3(float n[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
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:189
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:230
#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
@ GPPAINT_FLAG_USE_VERTEXCOLOR
@ PAINT_SHOW_BRUSH
@ RGN_TYPE_WINDOW
#define RGN_TYPE_ANY
@ SPACE_VIEW3D
#define SPACE_TYPE_ANY
@ TEX_IMAGE
@ MTEX_MAP_MODE_STENCIL
@ MTEX_MAP_MODE_TILED
@ MTEX_MAP_MODE_VIEW
@ 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:266
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:243
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
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)
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)
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:161
eGPUBlend GPU_blend_get()
Definition gpu_state.cc:221
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
eGPUDepthTest GPU_depth_test_get()
Definition gpu_state.cc:239
void GPU_color_mask(bool r, bool g, bool b, bool a)
Definition gpu_state.cc:98
eGPUDepthTest
Definition GPU_state.hh:107
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:111
@ GPU_DEPTH_NONE
Definition GPU_state.hh:108
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
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_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 *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
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 red
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])
ATTR_WARN_UNUSED_RESULT BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
ATTR_WARN_UNUSED_RESULT const BMVert * v
void init()
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
unsigned int U
Definition btGjkEpa3.h:78
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
const Depsgraph * depsgraph
#define sinf(x)
#define cosf(x)
#define atan2f(x, y)
#define fabsf(x)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
RAYTRACE_GROUP_SIZE additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "eevee_utility_texture", "eevee_hiz_data", "draw_view") .specialization_constant(Type RAYTRACE_GROUP_SIZE in_sh_0_tx in_sh_2_tx screen_normal_tx GPU_RGBA8
blender::gpu::Batch * quad
uint col
format
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
pbvh::Tree & pbvh_ensure(Depsgraph &depsgraph, Object &object)
Definition paint.cc:2811
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
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 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)
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)
static void paint_cursor_preview_boundary_data_update(PaintCursorContext *pcontext)
static void paint_cursor_update_unprojected_radius(UnifiedPaintSettings &ups, Brush &brush, ViewContext &vc, const float location[3])
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(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 SCULPT_layer_brush_height_preview_draw(const uint gpuattr, const Brush &brush, const float rds, const float line_width, const float outline_col[3], const float alpha)
static void load_tex_task_cb_ex(void *__restrict userdata, const int j, const TaskParallelTLS *__restrict tls)
static void grease_pencil_eraser_draw(PaintCursorContext *pcontext)
static void paint_draw_cursor(bContext *C, int x, int y, void *)
static void paint_cursor_pose_brush_origins_draw(PaintCursorContext *pcontext)
static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom)
static void sculpt_geometry_preview_lines_draw(const Depsgraph &depsgraph, const uint gpuattr, const Brush &brush, const Object &object)
static void paint_draw_legacy_3D_view_brush_cursor(PaintCursorContext *pcontext)
static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
static void paint_draw_2D_view_brush_cursor_default(PaintCursorContext *pcontext)
static void paint_cursor_update_rake_rotation(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 grease_pencil_brush_cursor_draw(PaintCursorContext *pcontext)
static void paint_cursor_restore_drawing_state()
static void paint_draw_3D_view_inactive_brush_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)
BLI_INLINE void draw_bezier_handle_lines(uint pos, const float sel_col[4], BezTriple *bez)
static void paint_cursor_draw_3d_view_brush_cursor_inactive(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 void paint_cursor_setup_3D_drawing(PaintCursorContext *pcontext)
static void paint_draw_2D_view_brush_cursor(PaintCursorContext *pcontext)
static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom, PaintMode mode)
static void paint_cursor_preview_boundary_data_pivot_draw(PaintCursorContext *pcontext)
static void paint_cursor_cursor_draw_3d_view_brush_cursor_active(PaintCursorContext *pcontext)
static void paint_cursor_update_object_space_radius(PaintCursorContext *pcontext)
static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcontext)
static void paint_update_mouse_cursor(PaintCursorContext *pcontext)
static bool paint_cursor_is_3d_view_navigating(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 void paint_cursor_check_and_draw_alpha_overlays(PaintCursorContext *pcontext)
static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc)
static bool paint_cursor_context_init(bContext *C, const int x, const int y, 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_draw_main_inactive_cursor(PaintCursorContext *pcontext)
void multiplane_scrape_preview_draw(const uint gpuattr, const Brush &brush, const SculptSession &ss, const float outline_col[3], const float outline_alpha)
static void paint_cursor_drawing_setup_cursor_space(PaintCursorContext *pcontext)
static void paint_cursor_setup_2D_drawing(PaintCursorContext *pcontext)
bool paint_brush_tool_poll(bContext *C)
static void paint_cursor_draw_3D_view_brush_cursor(PaintCursorContext *pcontext)
static void paint_cursor_update_anchored_location(PaintCursorContext *pcontext)
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:227
static bool paint_cursor_is_brush_cursor_enabled(PaintCursorContext *pcontext)
Span< float3 > vert_positions_for_grab_active_get(const Depsgraph &depsgraph, const Object &object)
Definition sculpt.cc:171
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
vector snap(vector a, vector b)
Definition node_math.h:65
static ePaintOverlayControlFlags overlay_flags
Definition paint.cc:251
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:513
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:186
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
Definition sculpt.cc:4580
void SCULPT_vertex_random_access_ensure(Object &object)
Definition sculpt.cc:144
float co[3]
float vec[3][3]
float alpha
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 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
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
unsigned char paint_cursor_col[4]
struct ToolSettings * toolsettings
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
std::unique_ptr< SculptBoundaryPreview > boundary_preview
Definition BKE_paint.hh:456
bool draw_faded_cursor
Definition BKE_paint.hh:438
blender::Array< int > preview_verts
Definition BKE_paint.hh:450
ActiveVert active_vert() const
Definition paint.cc:2180
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2224
std::unique_ptr< SculptPoseIKChainPreview > pose_ik_chain_preview
Definition BKE_paint.hh:453
blender::ed::sculpt_paint::expand::Cache * expand_cache
Definition BKE_paint.hh:429
int active_vert_index() const
Definition paint.cc:2190
bool deform_modifiers_active
Definition BKE_paint.hh:411
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:76
ARegion * region
Definition ED_view3d.hh:73
Scene * scene
Definition ED_view3d.hh:69
View3D * v3d
Definition ED_view3d.hh:74
Object * obact
Definition ED_view3d.hh:71
bNodeTreeRuntimeHandle * runtime
VecBase< T, 3 > xyz() const
int ymin
int xmin
void WM_cursor_set(wmWindow *win, int curs)
@ WM_CURSOR_PAINT
Definition wm_cursors.hh:27
@ WM_CURSOR_DOT
Definition wm_cursors.hh:28
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)