Blender V5.0
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_color.h"
16#include "BLI_math_matrix.hh"
17#include "BLI_math_rotation.h"
18#include "BLI_rect.h"
19#include "BLI_task.h"
20#include "BLI_utildefines.h"
21
22#include "DNA_brush_types.h"
23#include "DNA_material_types.h"
24#include "DNA_mesh_types.h"
25#include "DNA_object_types.h"
26#include "DNA_scene_types.h"
27#include "DNA_screen_types.h"
28#include "DNA_space_types.h"
29#include "DNA_userdef_types.h"
30#include "DNA_view3d_types.h"
31
32#include "BKE_brush.hh"
33#include "BKE_colortools.hh"
34#include "BKE_context.hh"
35#include "BKE_curve.hh"
36#include "BKE_grease_pencil.hh"
37#include "BKE_image.hh"
38#include "BKE_node_runtime.hh"
39#include "BKE_object.hh"
40#include "BKE_paint.hh"
41#include "BKE_paint_types.hh"
42#include "BKE_screen.hh"
43
44#include "NOD_texture.h"
45
46#include "WM_api.hh"
47#include "WM_toolsystem.hh"
48#include "wm_cursors.hh"
49
51#include "IMB_imbuf_types.hh"
52
53#include "ED_grease_pencil.hh"
54#include "ED_image.hh"
55#include "ED_view3d.hh"
56
57#include "GPU_immediate.hh"
58#include "GPU_immediate_util.hh"
59#include "GPU_matrix.hh"
60#include "GPU_state.hh"
61#include "GPU_texture.hh"
62
63#include "UI_resources.hh"
64
65#include "paint_intern.hh"
66#include "sculpt_boundary.hh"
67#include "sculpt_cloth.hh"
68#include "sculpt_expand.hh"
69/* still needed for sculpt_stroke_get_location, should be
70 * removed eventually (TODO) */
71#include "sculpt_intern.hh"
72#include "sculpt_pose.hh"
73
74#include "bmesh.hh"
75
76/* Needed for determining tool material/vertex-color pinning. */
78
79#include "brushes/brushes.hh"
80
81/* TODOs:
82 *
83 * Some of the cursor drawing code is doing non-draw stuff
84 * (e.g. updating the brush rake angle). This should be cleaned up
85 * still.
86 *
87 * There is also some ugliness with sculpt-specific code.
88 */
89
98
105
106static TexSnapshot primary_snap = {nullptr};
107static TexSnapshot secondary_snap = {nullptr};
108static CursorSnapshot cursor_snap = {nullptr};
109
111{
112 if (primary_snap.overlay_texture) {
113 GPU_texture_free(primary_snap.overlay_texture);
114 }
115 if (secondary_snap.overlay_texture) {
116 GPU_texture_free(secondary_snap.overlay_texture);
117 }
118 if (cursor_snap.overlay_texture) {
119 GPU_texture_free(cursor_snap.overlay_texture);
120 }
121
122 memset(&primary_snap, 0, sizeof(TexSnapshot));
123 memset(&secondary_snap, 0, sizeof(TexSnapshot));
124 memset(&cursor_snap, 0, sizeof(CursorSnapshot));
125
127}
128
130
131static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom)
132{
133 return (/* make brush smaller shouldn't cause a resample */
134 //(mtex->brush_map_mode != MTEX_MAP_MODE_VIEW ||
135 //(BKE_brush_size_get(vc->scene, brush) <= snap->BKE_brush_size_get)) &&
136
138 (vc->region->winx == snap->winx && vc->region->winy == snap->winy)) &&
139 (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL || snap->old_zoom == zoom) &&
140 snap->old_col == col);
141}
142
143static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
144{
145 snap->old_zoom = zoom;
146 snap->winx = vc->region->winx;
147 snap->winy = vc->region->winy;
148}
149
163
164static void load_tex_task_cb_ex(void *__restrict userdata,
165 const int j,
166 const TaskParallelTLS *__restrict tls)
167{
168 LoadTexData *data = static_cast<LoadTexData *>(userdata);
169 Brush *br = data->br;
170 ViewContext *vc = data->vc;
171
172 MTex *mtex = data->mtex;
173 uchar *buffer = data->buffer;
174 const bool col = data->col;
175
176 ImagePool *pool = data->pool;
177 const int size = data->size;
178 const float rotation = data->rotation;
179 const float radius = data->radius;
180
181 bool convert_to_linear = false;
182 const ColorSpace *colorspace = nullptr;
183
184 const int thread_id = BLI_task_parallel_thread_id(tls);
185
186 if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
187 ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
188 /* For consistency, sampling always returns color in linear space. */
189 if (tex_ibuf && tex_ibuf->float_buffer.data == nullptr) {
190 convert_to_linear = true;
192 }
193 BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
194 }
195
196 for (int i = 0; i < size; i++) {
197 /* Largely duplicated from tex_strength. */
198
199 int index = j * size + i;
200
201 float x = float(i) / size;
202 float y = float(j) / size;
203 float len;
204
205 if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
206 x *= vc->region->winx / radius;
207 y *= vc->region->winy / radius;
208 }
209 else {
210 x = (x - 0.5f) * 2.0f;
211 y = (y - 0.5f) * 2.0f;
212 }
213
214 len = sqrtf(x * x + y * y);
215
217 /* It is probably worth optimizing for those cases where the texture is not rotated by
218 * skipping the calls to atan2, sqrtf, sin, and cos. */
219 if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
220 const float angle = atan2f(y, x) + rotation;
221
222 x = len * cosf(angle);
223 y = len * sinf(angle);
224 }
225
226 float avg;
227 float rgba[4];
228 paint_get_tex_pixel(mtex, x, y, pool, thread_id, &avg, rgba);
229
230 if (col) {
231 if (convert_to_linear) {
233 }
234
235 linearrgb_to_srgb_v3_v3(rgba, rgba);
236
237 clamp_v4(rgba, 0.0f, 1.0f);
238
239 buffer[index * 4] = rgba[0] * 255;
240 buffer[index * 4 + 1] = rgba[1] * 255;
241 buffer[index * 4 + 2] = rgba[2] * 255;
242 buffer[index * 4 + 3] = rgba[3] * 255;
243 }
244 else {
245 avg += br->texture_sample_bias;
246
247 /* Clamp to avoid precision overflow. */
248 CLAMP(avg, 0.0f, 1.0f);
249 buffer[index] = 255 - uchar(255 * avg);
250 }
251 }
252 else {
253 if (col) {
254 buffer[index * 4] = 0;
255 buffer[index * 4 + 1] = 0;
256 buffer[index * 4 + 2] = 0;
257 buffer[index * 4 + 3] = 0;
258 }
259 else {
260 buffer[index] = 0;
261 }
262 }
263 }
264}
265
266static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary)
267{
268 bool init;
269 TexSnapshot *target;
270
271 MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
273 uchar *buffer = nullptr;
274
275 int size;
276 bool refresh;
280 target = (primary) ? &primary_snap : &secondary_snap;
281
282 refresh = !target->overlay_texture || (invalid != 0) ||
283 !same_tex_snap(target, mtex, vc, col, zoom);
284
285 init = (target->overlay_texture != nullptr);
286
287 if (refresh) {
288 ImagePool *pool = nullptr;
290 /* Stencil is rotated later. */
291 const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
292 const float radius = BKE_brush_radius_get(paint, br) * zoom;
293
294 make_tex_snap(target, vc, zoom);
295
296 if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
297 int s = BKE_brush_radius_get(paint, br);
298 int r = 1;
299
300 for (s >>= 1; s > 0; s >>= 1) {
301 r++;
302 }
303
304 size = (1 << r);
305
306 size = std::max(size, 256);
307 size = std::max(size, target->old_size);
308 }
309 else {
310 size = 512;
311 }
312
313 if (target->old_size != size || target->old_col != col) {
314 if (target->overlay_texture) {
316 target->overlay_texture = nullptr;
317 }
318 init = false;
319
320 target->old_size = size;
321 target->old_col = col;
322 }
323 if (col) {
324 buffer = MEM_malloc_arrayN<uchar>(size * size * 4, "load_tex");
325 }
326 else {
327 buffer = MEM_malloc_arrayN<uchar>(size * size, "load_tex");
328 }
329
330 pool = BKE_image_pool_new();
331
332 if (mtex->tex && mtex->tex->nodetree) {
333 /* Has internal flag to detect it only does it once. */
335 }
336
338 data.br = br;
339 data.vc = vc;
340 data.mtex = mtex;
341 data.buffer = buffer;
342 data.col = col;
343 data.pool = pool;
344 data.size = size;
345 data.rotation = rotation;
346 data.radius = radius;
347
348 TaskParallelSettings settings;
351
352 if (mtex->tex && mtex->tex->nodetree) {
353 ntreeTexEndExecTree(mtex->tex->nodetree->runtime->execdata);
354 }
355
356 if (pool) {
358 }
359
360 if (!target->overlay_texture) {
361 blender::gpu::TextureFormat format = col ? blender::gpu::TextureFormat::UNORM_8_8_8_8 :
362 blender::gpu::TextureFormat::UNORM_8;
365 "paint_cursor_overlay", size, size, 1, format, usage, nullptr);
367
368 if (!col) {
370 }
371 }
372
373 if (init) {
375 }
376
377 if (buffer) {
378 MEM_freeN(buffer);
379 }
380 }
381 else {
382 size = target->old_size;
383 }
384
386
387 return 1;
388}
389
390static void load_tex_cursor_task_cb(void *__restrict userdata,
391 const int j,
392 const TaskParallelTLS *__restrict /*tls*/)
393{
394 LoadTexData *data = static_cast<LoadTexData *>(userdata);
395 Brush *br = data->br;
396
397 uchar *buffer = data->buffer;
398
399 const int size = data->size;
400
401 for (int i = 0; i < size; i++) {
402 /* Largely duplicated from tex_strength. */
403
404 const int index = j * size + i;
405 const float x = ((float(i) / size) - 0.5f) * 2.0f;
406 const float y = ((float(j) / size) - 0.5f) * 2.0f;
407 const float len = sqrtf(x * x + y * y);
408
409 if (len <= 1.0f) {
410
411 /* Falloff curve. */
412 float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f);
413
414 buffer[index] = uchar(255 * avg);
415 }
416 else {
417 buffer[index] = 0;
418 }
419 }
420}
421
422static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
423{
424 bool init;
425
427 uchar *buffer = nullptr;
428
429 int size;
430 const bool refresh = !cursor_snap.overlay_texture ||
432 cursor_snap.curve_preset != br->curve_distance_falloff_preset;
433
434 init = (cursor_snap.overlay_texture != nullptr);
435
436 if (refresh) {
438 int s, r;
439
440 cursor_snap.zoom = zoom;
441
443 r = 1;
444
445 for (s >>= 1; s > 0; s >>= 1) {
446 r++;
447 }
448
449 size = (1 << r);
450
451 size = std::max(size, 256);
452 size = std::max(size, cursor_snap.size);
453
454 if (cursor_snap.size != size) {
455 if (cursor_snap.overlay_texture) {
456 GPU_texture_free(cursor_snap.overlay_texture);
457 cursor_snap.overlay_texture = nullptr;
458 }
459
460 init = false;
461
462 cursor_snap.size = size;
463 }
464 buffer = MEM_malloc_arrayN<uchar>(size * size, "load_tex");
465
467
469 data.br = br;
470 data.buffer = buffer;
471 data.size = size;
472
473 TaskParallelSettings settings;
476
477 if (!cursor_snap.overlay_texture) {
479 cursor_snap.overlay_texture = GPU_texture_create_2d("cursor_snap_overaly",
480 size,
481 size,
482 1,
483 blender::gpu::TextureFormat::UNORM_8,
484 usage,
485 nullptr);
486 GPU_texture_update(cursor_snap.overlay_texture, GPU_DATA_UBYTE, buffer);
487
488 GPU_texture_swizzle_set(cursor_snap.overlay_texture, "rrrr");
489 }
490
491 if (init) {
492 GPU_texture_update(cursor_snap.overlay_texture, GPU_DATA_UBYTE, buffer);
493 }
494
495 if (buffer) {
496 MEM_freeN(buffer);
497 }
498 }
499 else {
500 size = cursor_snap.size;
501 }
502
505
506 return 1;
507}
508
509static int project_brush_radius(ViewContext *vc, float radius, const float location[3])
510{
511 float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
512
513 ED_view3d_global_to_vector(vc->rv3d, location, view);
514
515 /* Create a vector that is not orthogonal to view. */
516
517 if (fabsf(view[0]) < 0.1f) {
518 nonortho[0] = view[0] + 1.0f;
519 nonortho[1] = view[1];
520 nonortho[2] = view[2];
521 }
522 else if (fabsf(view[1]) < 0.1f) {
523 nonortho[0] = view[0];
524 nonortho[1] = view[1] + 1.0f;
525 nonortho[2] = view[2];
526 }
527 else {
528 nonortho[0] = view[0];
529 nonortho[1] = view[1];
530 nonortho[2] = view[2] + 1.0f;
531 }
532
533 /* Get a vector in the plane of the view. */
534 cross_v3_v3v3(ortho, nonortho, view);
535 normalize_v3(ortho);
536
537 /* Make a point on the surface of the brush tangent to the view. */
538 mul_v3_fl(ortho, radius);
539 add_v3_v3v3(offset, location, ortho);
540
541 /* Project the center of the brush, and the tangent point to the view onto the screen. */
546 {
547 /* The distance between these points is the size of the projected brush in pixels. */
548 return len_v2v2(p1, p2);
549 }
550 /* Assert because the code that sets up the vectors should disallow this. */
551 BLI_assert(0);
552 return 0;
553}
554
556 const float radius,
557 const float3 world_location,
558 const float4x4 &to_world)
559{
560 const float2 xy_delta = float2(1.0f, 0.0f);
561
562 bool z_flip;
563 const float zfac = ED_view3d_calc_zfac_ex(vc->rv3d, world_location, &z_flip);
564 if (z_flip) {
565 /* Location is behind camera. Return 0 to make the cursor disappear. */
566 return 0;
567 }
568 float3 delta;
569 ED_view3d_win_to_delta(vc->region, xy_delta, zfac, delta);
570
571 const float scale = math::length(
573 return math::safe_divide(scale * radius, math::length(delta));
574}
575
576/* Draw an overlay that shows what effect the brush's texture will
577 * have on brush strength. */
579 Brush *brush,
580 ViewContext *vc,
581 int x,
582 int y,
583 float zoom,
584 const PaintMode mode,
585 bool col,
586 bool primary)
587{
588 rctf quad;
589 /* Check for overlay mode. */
590
591 MTex *mtex = (primary) ? &brush->mtex : &brush->mask_mtex;
592 bool valid = ((primary) ? (brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) != 0 :
593 (brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0);
594 int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha;
595
596 if (mode == PaintMode::Texture3D) {
597 if (primary && brush->image_brush_type != IMAGE_PAINT_BRUSH_TYPE_DRAW) {
598 /* All non-draw tools don't use the primary texture (clone, smear, soften.. etc). */
599 return false;
600 }
601 }
602
603 if (!(mtex->tex) ||
606 {
607 return false;
608 }
609
611 return false;
612 }
613
614 bke::PaintRuntime *paint_runtime = paint->runtime;
615 if (load_tex(brush, vc, zoom, col, primary)) {
616 GPU_color_mask(true, true, true, true);
618
619 if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
621
622 float center[2] = {
623 paint_runtime->draw_anchored ? paint_runtime->anchored_initial_mouse[0] : x,
624 paint_runtime->draw_anchored ? paint_runtime->anchored_initial_mouse[1] : y,
625 };
626
627 /* Brush rotation. */
630 RAD2DEGF(primary ? paint_runtime->brush_rotation : paint_runtime->brush_rotation_sec));
631 GPU_matrix_translate_2f(-center[0], -center[1]);
632
633 /* Scale based on tablet pressure. */
634 if (primary && paint_runtime->stroke_active && BKE_brush_use_size_pressure(brush)) {
635 const float scale = paint_runtime->size_pressure_value;
637 GPU_matrix_scale_2f(scale, scale);
638 GPU_matrix_translate_2f(-center[0], -center[1]);
639 }
640
641 if (paint_runtime->draw_anchored) {
642 quad.xmin = center[0] - paint_runtime->anchored_size;
643 quad.ymin = center[1] - paint_runtime->anchored_size;
644 quad.xmax = center[0] + paint_runtime->anchored_size;
645 quad.ymax = center[1] + paint_runtime->anchored_size;
646 }
647 else {
648 const int radius = BKE_brush_radius_get(paint, brush) * zoom;
649 quad.xmin = center[0] - radius;
650 quad.ymin = center[1] - radius;
651 quad.xmax = center[0] + radius;
652 quad.ymax = center[1] + radius;
653 }
654 }
655 else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
656 quad.xmin = 0;
657 quad.ymin = 0;
658 quad.xmax = BLI_rcti_size_x(&vc->region->winrct);
659 quad.ymax = BLI_rcti_size_y(&vc->region->winrct);
660 }
661 /* Stencil code goes here. */
662 else {
663 if (primary) {
664 quad.xmin = -brush->stencil_dimension[0];
665 quad.ymin = -brush->stencil_dimension[1];
666 quad.xmax = brush->stencil_dimension[0];
667 quad.ymax = brush->stencil_dimension[1];
668 }
669 else {
670 quad.xmin = -brush->mask_stencil_dimension[0];
671 quad.ymin = -brush->mask_stencil_dimension[1];
672 quad.xmax = brush->mask_stencil_dimension[0];
673 quad.ymax = brush->mask_stencil_dimension[1];
674 }
676 if (primary) {
678 }
679 else {
681 }
683 }
684
685 /* Set quad color. Colored overlay does not get blending. */
687 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
688 uint texCoord = GPU_vertformat_attr_add(
689 format, "texCoord", blender::gpu::VertAttrType::SFLOAT_32_32);
690
691 /* Premultiplied alpha blending. */
693
695
696 float final_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
697 if (!col) {
698 copy_v3_v3(final_color, U.sculpt_paint_overlay_col);
699 }
700 mul_v4_fl(final_color, overlay_alpha * 0.01f);
701 immUniformColor4fv(final_color);
702
703 blender::gpu::Texture *texture = (primary) ? primary_snap.overlay_texture :
704 secondary_snap.overlay_texture;
705
710 "image", texture, {GPU_SAMPLER_FILTERING_LINEAR, extend_mode, extend_mode});
711
712 /* Draw textured quad. */
714 immAttr2f(texCoord, 0.0f, 0.0f);
715 immVertex2f(pos, quad.xmin, quad.ymin);
716 immAttr2f(texCoord, 1.0f, 0.0f);
717 immVertex2f(pos, quad.xmax, quad.ymin);
718 immAttr2f(texCoord, 1.0f, 1.0f);
719 immVertex2f(pos, quad.xmax, quad.ymax);
720 immAttr2f(texCoord, 0.0f, 1.0f);
721 immVertex2f(pos, quad.xmin, quad.ymax);
722 immEnd();
723
725
727
730 }
731 }
732 return true;
733}
734
735/* Draw an overlay that shows what effect the brush's texture will
736 * have on brush strength. */
738 Paint *paint, Brush *brush, ViewContext *vc, int x, int y, float zoom)
739{
740 rctf quad;
741 /* Check for overlay mode. */
742
743 if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
744 return false;
745 }
746
747 if (load_tex_cursor(brush, vc, zoom)) {
748 bool do_pop = false;
749 float center[2];
750
751 GPU_color_mask(true, true, true, true);
753
754 bke::PaintRuntime *paint_runtime = paint->runtime;
755 if (paint_runtime->draw_anchored) {
756 copy_v2_v2(center, paint_runtime->anchored_initial_mouse);
757 quad.xmin = paint_runtime->anchored_initial_mouse[0] - paint_runtime->anchored_size;
758 quad.ymin = paint_runtime->anchored_initial_mouse[1] - paint_runtime->anchored_size;
759 quad.xmax = paint_runtime->anchored_initial_mouse[0] + paint_runtime->anchored_size;
760 quad.ymax = paint_runtime->anchored_initial_mouse[1] + paint_runtime->anchored_size;
761 }
762 else {
763 const int radius = BKE_brush_radius_get(paint, brush) * zoom;
764 center[0] = x;
765 center[1] = y;
766
767 quad.xmin = x - radius;
768 quad.ymin = y - radius;
769 quad.xmax = x + radius;
770 quad.ymax = y + radius;
771 }
772
773 /* Scale based on tablet pressure. */
774 if (paint_runtime->stroke_active && BKE_brush_use_size_pressure(brush)) {
775 do_pop = true;
779 GPU_matrix_translate_2f(-center[0], -center[1]);
780 }
781
783 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
784 uint texCoord = GPU_vertformat_attr_add(
785 format, "texCoord", blender::gpu::VertAttrType::SFLOAT_32_32);
786
788
790
791 float final_color[4] = {UNPACK3(U.sculpt_paint_overlay_col), 1.0f};
792 mul_v4_fl(final_color, brush->cursor_overlay_alpha * 0.01f);
793 immUniformColor4fv(final_color);
794
795 /* Draw textured quad. */
796 immBindTextureSampler("image",
797 cursor_snap.overlay_texture,
798 {GPU_SAMPLER_FILTERING_LINEAR,
799 GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER,
800 GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER});
801
803 immAttr2f(texCoord, 0.0f, 0.0f);
804 immVertex2f(pos, quad.xmin, quad.ymin);
805 immAttr2f(texCoord, 1.0f, 0.0f);
806 immVertex2f(pos, quad.xmax, quad.ymin);
807 immAttr2f(texCoord, 1.0f, 1.0f);
808 immVertex2f(pos, quad.xmax, quad.ymax);
809 immAttr2f(texCoord, 0.0f, 1.0f);
810 immVertex2f(pos, quad.xmin, quad.ymax);
811 immEnd();
812
813 GPU_texture_unbind(cursor_snap.overlay_texture);
814
816
817 if (do_pop) {
819 }
820 }
821 return true;
822}
823
825 Paint *paint, Brush *brush, ViewContext *vc, int x, int y, float zoom, PaintMode mode)
826{
827 /* Color means that primary brush texture is colored and
828 * secondary is used for alpha/mask control. */
830
831 bool alpha_overlay_active = false;
832
834 GPUBlend blend_state = GPU_blend_get();
835 GPUDepthTest depth_test = GPU_depth_test_get();
836
837 /* Translate to region. */
840 x -= vc->region->winrct.xmin;
841 y -= vc->region->winrct.ymin;
842
843 /* Colored overlay should be drawn separately. */
844 if (col) {
845 if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY)) {
846 alpha_overlay_active = paint_draw_tex_overlay(
847 paint, brush, vc, x, y, zoom, mode, true, true);
848 }
849 if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY)) {
850 alpha_overlay_active = paint_draw_tex_overlay(
851 paint, brush, vc, x, y, zoom, mode, false, false);
852 }
853 if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
854 alpha_overlay_active = paint_draw_cursor_overlay(paint, brush, vc, x, y, zoom);
855 }
856 }
857 else {
858 if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PaintMode::Weight)) {
859 alpha_overlay_active = paint_draw_tex_overlay(
860 paint, brush, vc, x, y, zoom, mode, false, true);
861 }
862 if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
863 alpha_overlay_active = paint_draw_cursor_overlay(paint, brush, vc, x, y, zoom);
864 }
865 }
866
868 GPU_blend(blend_state);
869 GPU_depth_test(depth_test);
870
871 return alpha_overlay_active;
872}
873
875 const float sel_col[4],
876 const float pivot_col[4],
877 float *co,
878 float width,
879 bool selected)
880{
881 immUniformColor4fv(selected ? sel_col : pivot_col);
882
883 GPU_line_width(3.0f);
884
885 float w = width / 2.0f;
886 const float tri[3][2] = {
887 {co[0], co[1] + w},
888 {co[0] - w, co[1] - w},
889 {co[0] + w, co[1] - w},
890 };
891
893 immVertex2fv(pos, tri[0]);
894 immVertex2fv(pos, tri[1]);
895 immVertex2fv(pos, tri[2]);
896 immEnd();
897
898 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
899 GPU_line_width(1.0f);
900
902 immVertex2fv(pos, tri[0]);
903 immVertex2fv(pos, tri[1]);
904 immVertex2fv(pos, tri[2]);
905 immEnd();
906}
907
909 const float sel_col[4],
910 const float handle_col[4],
911 const float *co,
912 float width,
913 bool selected)
914{
915 immUniformColor4fv(selected ? sel_col : handle_col);
916
917 GPU_line_width(3.0f);
918
919 float w = width / 2.0f;
920 float minx = co[0] - w;
921 float miny = co[1] - w;
922 float maxx = co[0] + w;
923 float maxy = co[1] + w;
924
925 imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
926
927 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
928 GPU_line_width(1.0f);
929
930 imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
931}
932
933BLI_INLINE void draw_bezier_handle_lines(uint pos, const float sel_col[4], BezTriple *bez)
934{
935 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
936 GPU_line_width(3.0f);
937
939 immVertex2fv(pos, bez->vec[0]);
940 immVertex2fv(pos, bez->vec[1]);
941 immVertex2fv(pos, bez->vec[2]);
942 immEnd();
943
944 GPU_line_width(1.0f);
945
946 if (bez->f1 || bez->f2) {
947 immUniformColor4fv(sel_col);
948 }
949 else {
950 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
951 }
953 immVertex2fv(pos, bez->vec[0]);
954 immVertex2fv(pos, bez->vec[1]);
955 immEnd();
956
957 if (bez->f3 || bez->f2) {
958 immUniformColor4fv(sel_col);
959 }
960 else {
961 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
962 }
964 immVertex2fv(pos, bez->vec[1]);
965 immVertex2fv(pos, bez->vec[2]);
966 immEnd();
967}
968
970{
973
974 if (brush->paint_curve && brush->paint_curve->points) {
975 PaintCurve *pc = brush->paint_curve;
976 PaintCurvePoint *cp = pc->points;
977
978 GPU_line_smooth(true);
980
981 /* Draw the bezier handles and the curve segment between the current and next point. */
983 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
984
986
987 float selec_col[4], handle_col[4], pivot_col[4];
991
992 for (int i = 0; i < pc->tot_points - 1; i++, cp++) {
993 int j;
994 PaintCurvePoint *cp_next = cp + 1;
995 float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
996 /* Use color coding to distinguish handles vs curve segments. */
997 draw_bezier_handle_lines(pos, selec_col, &cp->bez);
998 draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
1000 pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
1002 pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
1003
1004 for (j = 0; j < 2; j++) {
1006 cp->bez.vec[2][j],
1007 cp_next->bez.vec[0][j],
1008 cp_next->bez.vec[1][j],
1009 data + j,
1011 sizeof(float[2]));
1012 }
1013
1014 float (*v)[2] = (float (*)[2])data;
1015
1016 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
1017 GPU_line_width(3.0f);
1019 for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
1020 immVertex2fv(pos, v[j]);
1021 }
1022 immEnd();
1023
1024 immUniformColor4f(0.9f, 0.9f, 1.0f, 0.5f);
1025 GPU_line_width(1.0f);
1027 for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
1028 immVertex2fv(pos, v[j]);
1029 }
1030 immEnd();
1031 }
1032
1033 /* Draw last line segment. */
1034 draw_bezier_handle_lines(pos, selec_col, &cp->bez);
1035 draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
1037 pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
1039 pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
1040
1042 GPU_line_smooth(false);
1043
1045 }
1047}
1048
1049/* Special actions taken when paint cursor goes over mesh */
1050/* TODO: sculpt only for now. */
1052 Brush &brush,
1053 const ViewContext &vc,
1054 const float location[3])
1055{
1056 const bke::PaintRuntime &paint_runtime = *paint.runtime;
1057 /* Update the brush's cached 3D radius. */
1058 if (!BKE_brush_use_locked_size(&paint, &brush)) {
1059 float projected_radius;
1060 /* Get 2D brush radius. */
1061 if (paint_runtime.draw_anchored) {
1062 projected_radius = paint_runtime.anchored_size;
1063 }
1064 else {
1065 if (brush.flag & BRUSH_ANCHORED) {
1066 projected_radius = 8;
1067 }
1068 else {
1069 projected_radius = BKE_brush_radius_get(&paint, &brush);
1070 }
1071 }
1072
1073 /* Convert brush radius from 2D to 3D. */
1074 float unprojected_radius = paint_calc_object_space_radius(vc, location, projected_radius);
1075
1076 /* Scale 3D brush radius by pressure. */
1077 if (paint_runtime.stroke_active && BKE_brush_use_size_pressure(&brush)) {
1078 unprojected_radius *= paint_runtime.size_pressure_value;
1079 }
1080
1081 /* Set cached value in either Brush or UnifiedPaintSettings. */
1082 BKE_brush_unprojected_size_set(&paint, &brush, unprojected_radius * 2.0f);
1083 }
1084}
1085
1086static void cursor_draw_point_screen_space(const uint gpuattr,
1087 const ARegion *region,
1088 const float true_location[3],
1089 const float obmat[4][4],
1090 const int size)
1091{
1092 float translation_vertex_cursor[3], location[3];
1093 copy_v3_v3(location, true_location);
1094 mul_m4_v3(obmat, location);
1095 ED_view3d_project_v3(region, location, translation_vertex_cursor);
1096 /* Do not draw points behind the view. Z [near, far] is mapped to [-1, 1]. */
1097 if (translation_vertex_cursor[2] <= 1.0f) {
1099 gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
1100 }
1101}
1102
1103static void cursor_draw_tiling_preview(const uint gpuattr,
1104 const ARegion *region,
1105 const float true_location[3],
1106 const Sculpt &sd,
1107 const Object &ob,
1108 const float radius)
1109{
1110 BLI_assert(ob.type == OB_MESH);
1112 if (!mesh) {
1113 mesh = static_cast<const Mesh *>(ob.data);
1114 }
1115 const Bounds<float3> bounds = *mesh->bounds_min_max();
1116 float orgLoc[3], location[3];
1117 int tile_pass = 0;
1118 int start[3];
1119 int end[3];
1120 int cur[3];
1121 const float *step = sd.paint.tile_offset;
1122
1123 copy_v3_v3(orgLoc, true_location);
1124 for (int dim = 0; dim < 3; dim++) {
1125 if ((sd.paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
1126 start[dim] = (bounds.min[dim] - orgLoc[dim] - radius) / step[dim];
1127 end[dim] = (bounds.max[dim] - orgLoc[dim] + radius) / step[dim];
1128 }
1129 else {
1130 start[dim] = end[dim] = 0;
1131 }
1132 }
1133 copy_v3_v3_int(cur, start);
1134 for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
1135 for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
1136 for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
1137 if (!cur[0] && !cur[1] && !cur[2]) {
1138 /* Skip tile at orgLoc, this was already handled before all others. */
1139 continue;
1140 }
1141 tile_pass++;
1142 for (int dim = 0; dim < 3; dim++) {
1143 location[dim] = cur[dim] * step[dim] + orgLoc[dim];
1144 }
1145 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1146 }
1147 }
1148 }
1149 (void)tile_pass; /* Quiet set-but-unused warning (may be removed). */
1150}
1151
1152static void cursor_draw_point_with_symmetry(const uint gpuattr,
1153 const ARegion *region,
1154 const float true_location[3],
1155 const Sculpt &sd,
1156 const Object &ob,
1157 const float radius)
1158{
1159 const Mesh *mesh = static_cast<const Mesh *>(ob.data);
1160 const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
1161 float3 location;
1162 float symm_rot_mat[4][4];
1163
1164 for (int i = 0; i <= symm; i++) {
1165 if (is_symmetry_iteration_valid(i, symm)) {
1166
1167 /* Axis Symmetry. */
1168 location = symmetry_flip(true_location, ePaintSymmetryFlags(i));
1169 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1170
1171 /* Tiling. */
1172 cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
1173
1174 /* Radial Symmetry. */
1175 for (char raxis = 0; raxis < 3; raxis++) {
1176 for (int r = 1; r < mesh->radial_symmetry[raxis]; r++) {
1177 float angle = 2 * M_PI * r / mesh->radial_symmetry[int(raxis)];
1178 location = symmetry_flip(true_location, ePaintSymmetryFlags(i));
1179 unit_m4(symm_rot_mat);
1180 rotate_m4(symm_rot_mat, raxis + 'X', angle);
1181 mul_m4_v3(symm_rot_mat, location);
1182
1183 cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
1184 cursor_draw_point_screen_space(gpuattr, region, location, ob.object_to_world().ptr(), 3);
1185 }
1186 }
1187 }
1188 }
1189}
1190
1192 const uint gpuattr,
1193 const Brush &brush,
1194 const Object &object)
1195{
1196 if (!(brush.flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
1197 return;
1198 }
1199
1200 const SculptSession &ss = *object.sculpt;
1201 if (bke::object::pbvh_get(object)->type() != bke::pbvh::Type::Mesh) {
1202 return;
1203 }
1204
1205 if (!ss.deform_modifiers_active) {
1206 return;
1207 }
1208
1209 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
1210
1211 /* Cursor normally draws on top, but for this part we need depth tests. */
1212 const GPUDepthTest depth_test = GPU_depth_test_get();
1213 if (!depth_test) {
1215 }
1216
1217 GPU_line_width(1.0f);
1218 if (!ss.preview_verts.is_empty()) {
1221 for (const int vert : ss.preview_verts) {
1222 immVertex3fv(gpuattr, positions[vert]);
1223 }
1224 immEnd();
1225 }
1226
1227 /* Restore depth test value. */
1228 if (!depth_test) {
1230 }
1231}
1232
1234 const Brush &brush,
1235 const float rds,
1236 const float line_width,
1237 const float3 &outline_col,
1238 const float alpha)
1239{
1240 const float4x4 cursor_trans = math::translate(float4x4::identity(),
1241 float3(0.0f, 0.0f, brush.height));
1243 GPU_matrix_mul(cursor_trans.ptr());
1244
1245 GPU_line_width(line_width);
1246 immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
1247 imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
1249}
1250
1252{
1253 switch (mode) {
1254 case PaintMode::Sculpt:
1255 case PaintMode::Vertex:
1256 case PaintMode::Weight:
1257 return false;
1264 case PaintMode::GPencil:
1265 return true;
1266 case PaintMode::Invalid:
1268 }
1269 return true;
1270}
1271
1277
1284 Depsgraph *depsgraph;
1291
1292 /* Sculpt related data. */
1295
1300
1303 float radius;
1304
1305 /* 3D view cursor position and normal. */
1309
1310 /* Cursor main colors. */
1313
1314 /* GPU attribute for drawing. */
1316
1318
1319 /* This variable is set after drawing the overlay, not on initialization. It can't be used for
1320 * checking if alpha overlay is enabled before drawing it. */
1322
1323 float zoomx;
1324 /* Coordinates in region space */
1326
1327 /* TODO: Figure out why this and mval are used interchangeably */
1329
1331
1334};
1335
1337 const blender::int2 &xy,
1338 const blender::float2 &tilt,
1339 PaintCursorContext &pcontext)
1340{
1341 ARegion *region = CTX_wm_region(C);
1342 if (region && region->regiontype != RGN_TYPE_WINDOW) {
1343 return false;
1344 }
1345
1346 pcontext.C = C;
1347 pcontext.region = region;
1348 pcontext.wm = CTX_wm_manager(C);
1349 pcontext.win = CTX_wm_window(C);
1350 pcontext.screen = CTX_wm_screen(C);
1352 pcontext.scene = CTX_data_scene(C);
1354 if (pcontext.paint == nullptr) {
1355 return false;
1356 }
1357 pcontext.ups = &pcontext.paint->unified_paint_settings;
1358 pcontext.brush = BKE_paint_brush(pcontext.paint);
1359 if (pcontext.brush == nullptr) {
1360 return false;
1361 }
1363
1364 pcontext.vc = ED_view3d_viewcontext_init(C, pcontext.depsgraph);
1365
1366 if (pcontext.brush->flag & BRUSH_CURVE) {
1368 }
1369 else if (paint_use_2d_cursor(pcontext.mode)) {
1371 }
1372 else {
1374 }
1375
1376 pcontext.mval = xy;
1377 pcontext.translation = {float(xy[0]), float(xy[1])};
1378 pcontext.tilt = tilt;
1379
1380 float zoomx, zoomy;
1381 get_imapaint_zoom(C, &zoomx, &zoomy);
1382 pcontext.zoomx = max_ff(zoomx, zoomy);
1383 pcontext.final_radius = (BKE_brush_radius_get(pcontext.paint, pcontext.brush) * zoomx);
1384
1385 const bke::PaintRuntime &paint_runtime = *pcontext.paint->runtime;
1386 /* There is currently no way to check if the direction is inverted before starting the stroke,
1387 * so this does not reflect the state of the brush in the UI. */
1388 if (((!paint_runtime.draw_inverted) ^ ((pcontext.brush->flag & BRUSH_DIR_IN) == 0)) &&
1390 {
1391 pcontext.outline_col = float3(pcontext.brush->sub_col);
1392 }
1393 else {
1394 pcontext.outline_col = float3(pcontext.brush->add_col);
1395 }
1396 pcontext.outline_alpha = pcontext.brush->add_col[3];
1397
1398 Object *active_object = pcontext.vc.obact;
1399 pcontext.ss = active_object ? active_object->sculpt : nullptr;
1400
1401 if (pcontext.ss && pcontext.ss->draw_faded_cursor) {
1402 pcontext.outline_alpha = 0.3f;
1403 pcontext.outline_col = float3(0.8f);
1404 }
1405
1406 const bool is_brush_tool = paint_brush_tool_poll(C);
1407 if (!is_brush_tool) {
1408 /* Use a default color for tools that are not brushes. */
1409 pcontext.outline_alpha = 0.8f;
1410 pcontext.outline_col = float3(0.8f);
1411 }
1412
1413 pcontext.is_stroke_active = paint_runtime.stroke_active;
1414
1415 return true;
1416}
1417
1419{
1420 if (pcontext.is_cursor_over_mesh) {
1421 Brush *brush = BKE_paint_brush(pcontext.paint);
1423 &pcontext.vc, BKE_brush_unprojected_radius_get(pcontext.paint, brush), pcontext.location);
1424
1425 if (pcontext.pixel_radius == 0) {
1426 pcontext.pixel_radius = BKE_brush_radius_get(pcontext.paint, brush);
1427 }
1428
1429 pcontext.scene_space_location = math::transform_point(pcontext.vc.obact->object_to_world(),
1430 pcontext.location);
1431 }
1432 else {
1433 Sculpt *sd = CTX_data_tool_settings(pcontext.C)->sculpt;
1434 Brush *brush = BKE_paint_brush(&sd->paint);
1435
1436 pcontext.pixel_radius = BKE_brush_radius_get(pcontext.paint, brush);
1437 }
1438}
1439
1441{
1442 BLI_assert(pcontext.ss != nullptr);
1443 BLI_assert(pcontext.mode == PaintMode::Sculpt);
1444
1445 bContext *C = pcontext.C;
1446 SculptSession &ss = *pcontext.ss;
1447 Brush &brush = *pcontext.brush;
1448 bke::PaintRuntime &paint_runtime = *pcontext.paint->runtime;
1449 ViewContext &vc = pcontext.vc;
1451
1452 const float2 mval_fl = {
1453 float(pcontext.mval.x - pcontext.region->winrct.xmin),
1454 float(pcontext.mval.y - pcontext.region->winrct.ymin),
1455 };
1456
1457 /* Ensure that the PBVH is generated before we call #cursor_geometry_info_update because
1458 * the PBVH is needed to do a ray-cast to find the active vertex. */
1459 bke::object::pbvh_ensure(*pcontext.depsgraph, *pcontext.vc.obact);
1460
1461 /* This updates the active vertex, which is needed for most of the Sculpt/Vertex Colors tools to
1462 * work correctly */
1465 if (!paint_runtime.stroke_active) {
1467 C, &gi, mval_fl, (pcontext.brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
1468 pcontext.location = gi.location;
1469 pcontext.normal = gi.normal;
1470 }
1471 else {
1472 pcontext.is_cursor_over_mesh = paint_runtime.last_hit;
1473 pcontext.location = paint_runtime.last_location;
1474 }
1475
1477
1478 if (BKE_brush_use_locked_size(pcontext.paint, &brush)) {
1479 BKE_brush_size_set(pcontext.paint, &brush, pcontext.pixel_radius * 2.0f);
1480 }
1481
1482 if (pcontext.is_cursor_over_mesh) {
1484 *pcontext.paint, brush, vc, pcontext.scene_space_location);
1485 }
1486
1487 pcontext.sd = CTX_data_tool_settings(pcontext.C)->sculpt;
1488}
1489
1491{
1492 if (pcontext.win->grabcursor != 0 || pcontext.win->modalcursor != 0) {
1493 /* Don't set the cursor while it's grabbed, since this will show the cursor when interacting
1494 * with the UI (dragging a number button for example), see: #102792.
1495 * And don't overwrite a modal cursor, allowing modal operators to set a cursor temporarily. */
1496 return;
1497 }
1498
1499 /* Don't set the cursor when a temporary popup is opened (e.g. a context menu, pie menu or
1500 * dialog), see: #137386. */
1501 if (!BLI_listbase_is_empty(&pcontext.screen->regionbase) &&
1503 {
1504 return;
1505 }
1506
1508 WM_cursor_set(pcontext.win, WM_CURSOR_DOT);
1509 }
1510 else {
1512 }
1513}
1514
1516{
1518 const bke::PaintRuntime *paint_runtime = pcontext.paint->runtime;
1519
1520 /* Draw brush outline. */
1521 if (paint_runtime->stroke_active && BKE_brush_use_size_pressure(pcontext.brush)) {
1523 pcontext.translation[0],
1524 pcontext.translation[1],
1525 pcontext.final_radius * paint_runtime->size_pressure_value,
1526 40);
1527 /* Outer at half alpha. */
1528 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.5f);
1529 }
1530
1531 GPU_line_width(1.0f);
1533 pcontext.pos, pcontext.translation[0], pcontext.translation[1], pcontext.final_radius, 40);
1534}
1535
1537{
1538 float radius = float(pcontext.pixel_radius);
1539
1540 /* Red-ish color with alpha. */
1541 immUniformColor4ub(255, 100, 100, 20);
1542 imm_draw_circle_fill_2d(pcontext.pos, pcontext.mval.x, pcontext.mval.y, radius, 40);
1543
1545
1547
1548 float viewport_size[4];
1549 GPU_viewport_size_get_f(viewport_size);
1550 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1551
1552 immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1553 immUniform1i("colors_len", 0); /* "simple" mode */
1554 immUniform1f("dash_width", 12.0f);
1555 immUniform1f("udash_factor", 0.5f);
1556
1557 /* XXX Dashed shader gives bad results with sets of small segments
1558 * currently, temp hack around the issue. :( */
1559 const int nsegments = max_ii(8, radius / 2);
1560 imm_draw_circle_wire_2d(pcontext.pos, pcontext.mval.x, pcontext.mval.y, radius, nsegments);
1561}
1562
1564{
1565 if (pcontext.region &&
1566 !BLI_rcti_isect_pt(&pcontext.region->winrct, pcontext.mval.x, pcontext.mval.y))
1567 {
1568 return;
1569 }
1570
1571 Object *object = CTX_data_active_object(pcontext.C);
1572 if (object->type != OB_GREASE_PENCIL) {
1573 return;
1574 }
1575
1576 GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
1577 Paint *paint = pcontext.paint;
1578 Brush *brush = pcontext.brush;
1579 if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) {
1580 return;
1581 }
1582
1583 float3 color(1.0f);
1584 const int2 mval = pcontext.mval;
1585
1586 if (pcontext.mode == PaintMode::GPencil) {
1587 /* Hide the cursor while drawing. */
1588 if (grease_pencil->runtime->is_drawing_stroke) {
1589 return;
1590 }
1591
1592 /* Eraser has a special shape and uses a different shader program. */
1594 grease_pencil->runtime->temp_use_eraser)
1595 {
1596 /* If we use the eraser from the draw tool with a "scene" radius unit, we need to draw the
1597 * cursor with the appropriate size. */
1598 if (grease_pencil->runtime->temp_use_eraser && (brush->flag & BRUSH_LOCK_SIZE) != 0) {
1599 pcontext.pixel_radius = std::max(int(grease_pencil->runtime->temp_eraser_size / 2.0f), 1);
1600 }
1601 else {
1602 pcontext.pixel_radius = std::max(1, int(brush->size / 2.0f));
1603 }
1604 grease_pencil_eraser_draw(pcontext);
1605 return;
1606 }
1607
1609 /* The fill tool doesn't use a brush size currently, but not showing any brush means that it
1610 * can be hard to see where the cursor is. Use a fixed size that's not too big (10px). By
1611 * disabling the "Display Cursor" option, this can still be turned off. */
1612 pcontext.pixel_radius = 10;
1613 }
1614
1616 pcontext.pixel_radius = std::max(int(brush->size / 2.0f), 1);
1617 }
1618
1620 if ((brush->flag & BRUSH_LOCK_SIZE) != 0) {
1621 const bke::greasepencil::Layer *layer = grease_pencil->get_active_layer();
1622 const ed::greasepencil::DrawingPlacement placement(
1623 *pcontext.scene, *pcontext.region, *pcontext.vc.v3d, *object, layer);
1624 const float2 coordinate = float2(pcontext.mval.x - pcontext.region->winrct.xmin,
1625 pcontext.mval.y - pcontext.region->winrct.ymin);
1626 bool clipped = false;
1627 const float3 pos = placement.project(coordinate, clipped);
1628 if (!clipped) {
1629 const float3 world_location = math::transform_point(placement.to_world_space(), pos);
1631 brush->unprojected_size /
1632 2.0f,
1633 world_location,
1634 placement.to_world_space());
1635 }
1636 else {
1637 pcontext.pixel_radius = 0;
1638 }
1639 brush->size = std::max(pcontext.pixel_radius * 2, 1);
1640 }
1641 else {
1642 pcontext.pixel_radius = brush->size / 2.0f;
1643 }
1644 }
1645
1646 /* Get current drawing material. */
1648 MaterialGPencilStyle *gp_style = ma->gp_style;
1649
1650 /* Follow user settings for the size of the draw cursor:
1651 * - Fixed size, or
1652 * - Brush size (i.e. stroke thickness)
1653 */
1654 if ((gp_style) && ((brush->flag & BRUSH_SMOOTH_STROKE) == 0) &&
1656 {
1657
1659 pcontext.scene->toolsettings->gp_paint, brush);
1660 const bool use_vertex_color_stroke = use_vertex_color &&
1664 if (use_vertex_color_stroke) {
1666 }
1667 else {
1668 color = float4(gp_style->stroke_rgba).xyz();
1669 }
1670 }
1671 }
1672
1673 if ((brush->flag & BRUSH_SMOOTH_STROKE) != 0) {
1674 color = float3(1.0f, 0.4f, 0.4f);
1675 }
1676 }
1677 else if (pcontext.mode == PaintMode::VertexGPencil) {
1678 pcontext.pixel_radius = BKE_brush_radius_get(pcontext.paint, brush);
1681 }
1682
1683 GPU_line_width(1.0f);
1684 /* Inner Ring: Color from UI panel */
1685 immUniformColor4f(color.x, color.y, color.z, 0.8f);
1686 imm_draw_circle_wire_2d(pcontext.pos, mval.x, mval.y, pcontext.pixel_radius, 32);
1687
1688 /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
1689 const float3 darkcolor = color * 0.40f;
1690 immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
1691 imm_draw_circle_wire_2d(pcontext.pos, mval.x, mval.y, pcontext.pixel_radius + 1, 32);
1692}
1693
1695{
1696 switch (pcontext.mode) {
1697 case PaintMode::GPencil:
1700 break;
1701 default:
1703 }
1704}
1705
1707{
1708 GPU_line_width(1.0f);
1711 pcontext.pos, pcontext.translation[0], pcontext.translation[1], pcontext.final_radius, 40);
1712}
1713
1715{
1716 GPU_line_width(1.0f);
1717 /* Reduce alpha to increase the contrast when the cursor is over the mesh. */
1718 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.8);
1720 pcontext.pos, pcontext.translation[0], pcontext.translation[1], pcontext.final_radius, 80);
1721 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.35f);
1723 pcontext.pos,
1724 pcontext.translation[0],
1725 pcontext.translation[1],
1726 pcontext.final_radius *
1727 clamp_f(BKE_brush_alpha_get(pcontext.paint, pcontext.brush), 0.0f, 1.0f),
1728 80);
1729}
1730
1732{
1734 pcontext.vc, *pcontext.paint, *pcontext.brush, pcontext.location);
1735}
1736
1738{
1739 const float4x4 cursor_trans = math::translate(pcontext.vc.obact->object_to_world(),
1740 pcontext.location);
1741
1742 const float3 z_axis = {0.0f, 0.0f, 1.0f};
1743
1744 const float3 normal = bke::brush::supports_tilt(*pcontext.brush) ?
1745 tilt_apply_to_normal(*pcontext.vc.obact,
1746 float4x4(pcontext.vc.rv3d->viewinv),
1747 pcontext.normal,
1748 pcontext.tilt,
1749 pcontext.brush->tilt_strength_factor) :
1750 pcontext.normal;
1751
1752 const math::AxisAngle between_vecs(z_axis, normal);
1753 const float4x4 cursor_rot = math::from_rotation<float4x4>(between_vecs);
1754
1755 GPU_matrix_mul(cursor_trans.ptr());
1756 GPU_matrix_mul(cursor_rot.ptr());
1757}
1758
1760{
1762 GPU_line_width(2.0f);
1763 imm_draw_circle_wire_3d(pcontext.pos, 0, 0, pcontext.radius, 80);
1764
1765 GPU_line_width(1.0f);
1766 immUniformColor3fvAlpha(pcontext.outline_col, pcontext.outline_alpha * 0.5f);
1768 pcontext.pos,
1769 0,
1770 0,
1771 pcontext.radius * clamp_f(BKE_brush_alpha_get(pcontext.paint, pcontext.brush), 0.0f, 1.0f),
1772 80);
1773}
1774
1776{
1777 SculptSession &ss = *pcontext.ss;
1778 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1779 GPU_line_width(2.0f);
1780
1781 BLI_assert(ss.pose_ik_chain_preview->initial_head_coords.size() ==
1782 ss.pose_ik_chain_preview->initial_orig_coords.size());
1783
1784 immBegin(GPU_PRIM_LINES, ss.pose_ik_chain_preview->initial_head_coords.size() * 2);
1785 for (const int i : ss.pose_ik_chain_preview->initial_head_coords.index_range()) {
1786 immVertex3fv(pcontext.pos, ss.pose_ik_chain_preview->initial_orig_coords[i]);
1787 immVertex3fv(pcontext.pos, ss.pose_ik_chain_preview->initial_head_coords[i]);
1788 }
1789
1790 immEnd();
1791}
1792
1794{
1795
1796 SculptSession &ss = *pcontext.ss;
1797 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1798 for (const int i : ss.pose_ik_chain_preview->initial_orig_coords.index_range()) {
1800 pcontext.region,
1801 ss.pose_ik_chain_preview->initial_orig_coords[i],
1802 pcontext.vc.obact->object_to_world().ptr(),
1803 3);
1804 }
1805}
1806
1808{
1809 if (!pcontext.ss->boundary_preview) {
1810 /* There is no guarantee that a boundary preview exists as there may be no boundaries
1811 * inside the brush radius. */
1812 return;
1813 }
1814 immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1816 pcontext.region,
1817 pcontext.ss->boundary_preview->pivot_position,
1818 pcontext.vc.obact->object_to_world().ptr(),
1819 3);
1820}
1821
1823{
1824 SculptSession &ss = *pcontext.ss;
1825 /* Needed for updating the necessary SculptSession data in order to initialize the
1826 * boundary data for the preview. */
1827 BKE_sculpt_update_object_for_edit(pcontext.depsgraph, pcontext.vc.obact, false);
1828
1830 *pcontext.depsgraph, *pcontext.vc.obact, pcontext.brush, pcontext.radius);
1831}
1832
1834{
1835 const Brush &brush = *pcontext.brush;
1836
1837 /* 2D falloff is better represented with the default 2D cursor,
1838 * there is no need to draw anything else. */
1841 return;
1842 }
1843
1844 if (pcontext.alpha_overlay_drawn) {
1846 return;
1847 }
1848
1849 if (!pcontext.is_cursor_over_mesh) {
1851 return;
1852 }
1853
1854 BLI_assert(pcontext.vc.obact);
1855 Object &active_object = *pcontext.vc.obact;
1857
1858 vert_random_access_ensure(active_object);
1859
1860 /* Setup drawing. */
1861 wmViewport(&pcontext.region->winrct);
1862
1863 /* Drawing of Cursor overlays in 2D screen space. */
1864
1865 /* Cursor location symmetry points. */
1866
1867 float3 active_vertex_co;
1869 SculptSession &ss = *pcontext.ss;
1870 if (bke::object::pbvh_get(active_object)->type() == bke::pbvh::Type::Mesh) {
1871 const Span<float3> positions = vert_positions_for_grab_active_get(*pcontext.depsgraph,
1872 active_object);
1873 active_vertex_co = positions[std::get<int>(ss.active_vert())];
1874 }
1875 else {
1876 active_vertex_co = pcontext.ss->active_vert_position(*pcontext.depsgraph, active_object);
1877 }
1878 }
1879 else {
1880 active_vertex_co = pcontext.ss->active_vert_position(*pcontext.depsgraph, active_object);
1881 }
1882 if (math::distance(active_vertex_co, pcontext.location) < pcontext.radius) {
1885 pcontext.region,
1886 active_vertex_co,
1887 *pcontext.sd,
1888 active_object,
1889 pcontext.radius);
1890 }
1891
1892 const bool is_brush_tool = paint_brush_tool_poll(pcontext.C);
1893
1894 /* Pose brush updates and rotation origins. */
1895
1896 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_POSE) {
1897 /* Just after switching to the Pose Brush, the active vertex can be the same and the
1898 * cursor won't be tagged to update, so always initialize the preview chain if it is
1899 * nullptr before drawing it. */
1900 SculptSession &ss = *pcontext.ss;
1901 const bool update_previews = pcontext.prev_active_vert_index !=
1902 pcontext.ss->active_vert_index();
1903 if (update_previews || !ss.pose_ik_chain_preview) {
1904 BKE_sculpt_update_object_for_edit(pcontext.depsgraph, &active_object, false);
1905
1906 /* Free the previous pose brush preview. */
1907 if (ss.pose_ik_chain_preview) {
1908 ss.pose_ik_chain_preview.reset();
1909 }
1910
1911 /* Generate a new pose brush preview from the current cursor location. */
1913 *pcontext.depsgraph, active_object, ss, brush, pcontext.location, pcontext.radius);
1914 }
1915
1916 /* Draw the pose brush rotation origins. */
1918 }
1919
1920 /* Expand operation origin. */
1921 if (pcontext.ss->expand_cache) {
1922 const int vert = pcontext.ss->expand_cache->initial_active_vert;
1923
1924 float3 position;
1925 switch (bke::object::pbvh_get(active_object)->type()) {
1926 case bke::pbvh::Type::Mesh: {
1927 const Span positions = bke::pbvh::vert_positions_eval(*pcontext.depsgraph, active_object);
1928 position = positions[vert];
1929 break;
1930 }
1932 const SubdivCCG &subdiv_ccg = *pcontext.ss->subdiv_ccg;
1933 position = subdiv_ccg.positions[vert];
1934 break;
1935 }
1937 BMesh &bm = *pcontext.ss->bm;
1938 position = BM_vert_at_index(&bm, vert)->co;
1939 break;
1940 }
1941 }
1943 pcontext.pos, pcontext.region, position, active_object.object_to_world().ptr(), 2);
1944 }
1945
1946 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_BOUNDARY) {
1949 }
1950
1951 /* Setup 3D perspective drawing. */
1954 pcontext.win,
1955 pcontext.depsgraph,
1956 pcontext.scene,
1957 pcontext.region,
1958 CTX_wm_view3d(pcontext.C),
1959 nullptr,
1960 nullptr,
1961 nullptr);
1962
1964 GPU_matrix_mul(active_object.object_to_world().ptr());
1965
1966 /* Drawing Cursor overlays in 3D object space. */
1967 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_GRAB &&
1969 {
1971 *pcontext.depsgraph, *pcontext.vc.obact, *pcontext.ss, pcontext.radius);
1973 *pcontext.depsgraph, pcontext.pos, *pcontext.brush, active_object);
1974 }
1975
1976 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_POSE) {
1978 }
1979
1980 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_BOUNDARY) {
1982 pcontext.pos, *pcontext.ss, pcontext.outline_col, pcontext.outline_alpha);
1983 boundary::pivot_line_preview_draw(pcontext.pos, *pcontext.ss);
1984 }
1985
1987
1988 /* Drawing Cursor overlays in Paint Cursor space (as additional info on top of the brush cursor)
1989 */
1992 /* Main inactive cursor. */
1994
1995 /* Cloth brush local simulation areas. */
1996 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_CLOTH &&
1998 {
1999 const float3 white = {1.0f, 1.0f, 1.0f};
2000 const float3 zero_v = float3(0.0f);
2001 /* This functions sets its own drawing space in order to draw the simulation limits when the
2002 * cursor is active. When used here, this cursor overlay is already in cursor space, so its
2003 * position and normal should be set to 0. */
2005 pcontext.pos, brush, zero_v, zero_v, pcontext.radius, 1.0f, white, 0.25f);
2006 }
2007
2008 /* Layer brush height. */
2009 if (is_brush_tool && brush.sculpt_brush_type == SCULPT_BRUSH_TYPE_LAYER) {
2011 pcontext.pos, brush, pcontext.radius, 1.0f, pcontext.outline_col, pcontext.outline_alpha);
2012 }
2013
2015
2016 /* Reset drawing. */
2018 wmWindowViewport(pcontext.win);
2019}
2020
2022{
2023 BLI_assert(pcontext.ss != nullptr);
2024 BLI_assert(pcontext.mode == PaintMode::Sculpt);
2025
2026 SculptSession &ss = *pcontext.ss;
2027 Brush &brush = *pcontext.brush;
2028
2029 /* The cursor can be updated as active before creating the StrokeCache, so this needs to be
2030 * checked. */
2031 if (!ss.cache) {
2032 return;
2033 }
2034
2035 /* Most of the brushes initialize the necessary data for the custom cursor drawing after the
2036 * first brush step, so make sure that it is not drawn before being initialized. */
2038 return;
2039 }
2040
2041 /* Setup drawing. */
2042 wmViewport(&pcontext.region->winrct);
2045 pcontext.win,
2046 pcontext.depsgraph,
2047 pcontext.scene,
2048 pcontext.region,
2049 CTX_wm_view3d(pcontext.C),
2050 nullptr,
2051 nullptr,
2052 nullptr);
2054 GPU_matrix_mul(pcontext.vc.obact->object_to_world().ptr());
2055
2056 /* Draw the special active cursors different brush types may have. */
2057
2060 *pcontext.depsgraph, pcontext.pos, brush, *pcontext.vc.obact);
2061 }
2062
2065 pcontext.pos, brush, ss, pcontext.outline_col, pcontext.outline_alpha);
2066 }
2067
2071 pcontext.pos, ss, pcontext.outline_col, pcontext.outline_alpha);
2072 }
2075 {
2076 /* Display the simulation limits if sculpting outside them. */
2077 /* This does not makes much sense of plane falloff as the falloff is infinite or global. */
2078
2080 ss.cache->radius * (1.0f + brush.cloth_sim_limit))
2081 {
2082 const float3 red = {1.0f, 0.2f, 0.2f};
2084 brush,
2087 ss.cache->radius,
2088 2.0f,
2089 red,
2090 0.8f);
2091 }
2092 }
2093 }
2094
2096
2098 wmWindowViewport(pcontext.win);
2099}
2100
2102{
2103
2104 /* These paint tools are not using the SculptSession, so they need to use the default 2D brush
2105 * cursor in the 3D view. */
2106 if (pcontext.mode != PaintMode::Sculpt || !pcontext.ss) {
2108 return;
2109 }
2110
2112
2113 if (pcontext.is_stroke_active) {
2115 }
2116 else {
2118 }
2119}
2120
2122{
2123 const ViewContext *vc = &pcontext.vc;
2124 return vc->rv3d && (vc->rv3d->rflag & RV3D_NAVIGATING);
2125}
2126
2128{
2129 if (pcontext.paint->flags & PAINT_SHOW_BRUSH) {
2132 {
2133 return false;
2134 }
2135 return true;
2136 }
2137 return false;
2138}
2139
2141{
2142 /* Don't calculate rake angles while a stroke is active because the rake variables are global
2143 * and we may get interference with the stroke itself.
2144 * For line strokes, such interference is visible. */
2145 const bke::PaintRuntime *paint_runtime = pcontext.paint->runtime;
2146 if (!paint_runtime->stroke_active) {
2148 *pcontext.paint, *pcontext.brush, pcontext.translation, pcontext.mode, true);
2149 }
2150}
2151
2153{
2155 pcontext.brush,
2156 &pcontext.vc,
2157 pcontext.mval.x,
2158 pcontext.mval.y,
2159 pcontext.zoomx,
2160 pcontext.mode);
2161}
2162
2164{
2165 bke::PaintRuntime *paint_runtime = pcontext.paint->runtime;
2166 if (paint_runtime->draw_anchored) {
2167 pcontext.final_radius = paint_runtime->anchored_size;
2168 pcontext.translation = {
2169 paint_runtime->anchored_initial_mouse[0] + pcontext.region->winrct.xmin,
2170 paint_runtime->anchored_initial_mouse[1] + pcontext.region->winrct.ymin};
2171 }
2172}
2173
2175{
2176 GPU_line_width(2.0f);
2178 GPU_line_smooth(true);
2179 pcontext.pos = GPU_vertformat_attr_add(
2180 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
2182}
2183
2185{
2186 GPU_line_width(2.0f);
2188 GPU_line_smooth(true);
2189 pcontext.pos = GPU_vertformat_attr_add(
2190 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
2192}
2193
2200
2202 const blender::int2 &xy,
2203 const blender::float2 &tilt,
2204 void * /*unused*/)
2205{
2206 PaintCursorContext pcontext;
2207 if (!paint_cursor_context_init(C, xy, tilt, pcontext)) {
2208 return;
2209 }
2210
2211 if (!paint_cursor_is_brush_cursor_enabled(pcontext)) {
2212 /* For Grease Pencil draw mode, we want to we only render a small mouse cursor (dot) if the
2213 * paint cursor is disabled so that the default mouse cursor doesn't get in the way of tablet
2214 * users. See #130089. But don't overwrite a modal cursor, allowing modal operators to set one
2215 * temporarily. */
2216 if (pcontext.mode == PaintMode::GPencil && pcontext.win->modalcursor == 0) {
2217 WM_cursor_set(pcontext.win, WM_CURSOR_DOT);
2218 }
2219 return;
2220 }
2221 if (paint_cursor_is_3d_view_navigating(pcontext)) {
2222 /* Still draw stencil while navigating. */
2224 return;
2225 }
2226
2227 switch (pcontext.cursor_type) {
2229 paint_draw_curve_cursor(pcontext.brush, &pcontext.vc);
2230 break;
2232 paint_update_mouse_cursor(pcontext);
2233
2237
2241 break;
2243 paint_update_mouse_cursor(pcontext);
2244
2248
2252 break;
2253 default:
2255 }
2256}
2257
2258} // namespace blender::ed::sculpt_paint
2259
2260/* Public API */
2261
2262void ED_paint_cursor_start(Paint *paint, bool (*poll)(bContext *C))
2263{
2264 if (paint && paint->runtime && !paint->runtime->paint_cursor) {
2265 paint->runtime->paint_cursor = WM_paint_cursor_activate(
2267 }
2268
2269 /* Invalidate the paint cursors. */
2271}
float BKE_brush_alpha_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1357
const float * BKE_brush_color_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1161
bool BKE_brush_use_locked_size(const Paint *paint, const Brush *brush)
Definition brush.cc:1277
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1285
float BKE_brush_radius_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1272
float BKE_brush_unprojected_radius_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1315
void BKE_brush_size_set(Paint *paint, Brush *brush, int size)
Definition brush.cc:1248
void BKE_brush_unprojected_size_set(Paint *paint, Brush *brush, float unprojected_size)
Definition brush.cc:1295
float BKE_brush_curve_strength_clamped(const Brush *br, float p, float len)
Definition brush.cc:1637
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:1669
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)
bool paint_calculate_rake_rotation(Paint &paint, const Brush &brush, const float mouse_pos[2], PaintMode paint_mode, bool stroke_has_started)
Definition paint.cc:2193
ePaintOverlayControlFlags BKE_paint_get_overlay_flags()
Definition paint.cc:298
ePaintOverlayControlFlags
Definition BKE_paint.hh:87
@ PAINT_OVERLAY_INVALID_CURVE
Definition BKE_paint.hh:90
@ PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY
Definition BKE_paint.hh:89
@ PAINT_OVERLAY_OVERRIDE_CURSOR
Definition BKE_paint.hh:91
@ PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY
Definition BKE_paint.hh:88
@ PAINT_OVERLAY_OVERRIDE_SECONDARY
Definition BKE_paint.hh:93
@ PAINT_OVERLAY_OVERRIDE_PRIMARY
Definition BKE_paint.hh:92
void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag)
Definition paint.cc:321
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2797
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:476
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:645
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:505
void BKE_paint_invalidate_overlay_all()
Definition paint.cc:292
PaintMode
ARegion * BKE_screen_find_region_type(const bScreen *screen, int region_type) ATTR_NONNULL(1)
Definition screen.cc:891
blender::ocio::ColorSpace ColorSpace
Definition BLF_api.hh:38
#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
@ 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])
void ED_view3d_win_to_delta(const ARegion *region, const float xy_delta[2], float zfac, float r_out[3], bool precise=false)
@ 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_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 immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immBindTextureSampler(const char *name, blender::gpu::Texture *tex, GPUSamplerState state)
void immUniform2f(const char *name, float x, float y)
void immUniformColor4f(float r, float g, float b, float a)
void immVertex2f(uint attr_id, float x, float y)
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
GPUDepthTest
Definition GPU_state.hh:110
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:114
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
void GPU_line_width(float width)
Definition gpu_state.cc:166
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
GPUBlend GPU_blend_get()
Definition gpu_state.cc:226
GPUBlend
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(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_depth_test(GPUDepthTest test)
Definition gpu_state.cc:68
void GPU_color_mask(bool r, bool g, bool b, bool a)
Definition gpu_state.cc:98
GPUDepthTest GPU_depth_test_get()
Definition gpu_state.cc:244
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
void GPU_texture_swizzle_set(blender::gpu::Texture *texture, const char swizzle[4])
void GPU_texture_unbind(blender::gpu::Texture *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
blender::gpu::Texture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
@ GPU_SAMPLER_FILTERING_LINEAR
void GPU_texture_free(blender::gpu::Texture *texture)
void GPU_texture_update(blender::gpu::Texture *texture, eGPUDataFormat data_format, const void *data)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
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)
BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
Read Guarded memory(de)allocation.
void ntreeTexEndExecTree(struct bNodeTreeExec *exec)
struct bNodeTreeExec * ntreeTexBeginExecTree(struct bNodeTree *ntree)
#define C
Definition RandGen.cpp:29
@ TH_VERTEX_SELECT
@ TH_GIZMO_PRIMARY
@ TH_GIZMO_SECONDARY
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:256
bool is_empty() const
Definition BLI_array.hh:264
float3 project(float2 co, bool &clipped) const
nullptr float
uint pos
blender::gpu::Batch * quad
uint col
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) 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:1867
bool supports_tilt(const Brush &brush)
Definition brush.cc:1967
pbvh::Tree & pbvh_ensure(Depsgraph &depsgraph, Object &object)
Definition paint.cc:3017
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
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)
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 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:141
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 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:4685
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 void paint_cursor_update_unprojected_size(Paint &paint, Brush &brush, const ViewContext &vc, const float location[3])
float object_space_radius_get(const ViewContext &vc, const Paint &paint, const Brush &brush, const float3 &location, const float scale_factor)
Definition sculpt.cc:114
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 bool paint_draw_alpha_overlay(Paint *paint, Brush *brush, ViewContext *vc, int x, int y, float zoom, PaintMode mode)
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 bool paint_draw_cursor_overlay(Paint *paint, Brush *brush, ViewContext *vc, int x, int y, float zoom)
static int project_brush_radius(ViewContext *vc, float radius, const float location[3])
static void paint_draw_2D_view_brush_cursor_default(PaintCursorContext &pcontext)
bool paint_brush_tool_poll(bContext *C)
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:169
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:2690
static bool paint_draw_tex_overlay(Paint *paint, Brush *brush, ViewContext *vc, int x, int y, float zoom, const PaintMode mode, bool col, bool primary)
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:97
static void init(bNodeTree *, bNode *node)
static ePaintOverlayControlFlags overlay_flags
Definition paint.cc:257
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])
#define fabsf
#define sqrtf
#define sinf
#define cosf
#define atan2f
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:542
ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(const Object &object)
Definition sculpt.cc:184
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 stencil_dimension[2]
int cursor_overlay_alpha
char image_brush_type
float texture_sample_bias
char falloff_shape
float tilt_strength_factor
struct CurveMapping * curve_distance_falloff
float mask_stencil_pos[2]
struct BrushGpencilSettings * gpencil_settings
float cloth_sim_limit
float height
float sub_col[4]
float unprojected_size
struct MTex mask_mtex
float mask_stencil_dimension[2]
int cloth_simulation_area_type
int curve_distance_falloff_preset
char gpencil_brush_type
struct PaintCurve * paint_curve
int cloth_force_falloff_type
float color[3]
int overlay_flags
blender::gpu::Texture * 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
struct UnifiedPaintSettings unified_paint_settings
PaintRuntimeHandle * runtime
float viewinv[4][4]
struct ToolSettings * toolsettings
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
std::unique_ptr< SculptBoundaryPreview > boundary_preview
Definition BKE_paint.hh:446
bool draw_faded_cursor
Definition BKE_paint.hh:428
blender::Array< int > preview_verts
Definition BKE_paint.hh:440
ActiveVert active_vert() const
Definition paint.cc:2367
blender::float3 active_vert_position(const Depsgraph &depsgraph, const Object &object) const
Definition paint.cc:2403
std::unique_ptr< SculptPoseIKChainPreview > pose_ik_chain_preview
Definition BKE_paint.hh:443
blender::ed::sculpt_paint::expand::Cache * expand_cache
Definition BKE_paint.hh:419
int active_vert_index() const
Definition paint.cc:2377
bool deform_modifiers_active
Definition BKE_paint.hh:401
blender::Array< blender::float3 > positions
blender::gpu::Texture * overlay_texture
struct ImageUser iuser
struct bNodeTree * nodetree
struct Image * ima
RegionView3D * rv3d
Definition ED_view3d.hh:80
ARegion * region
Definition ED_view3d.hh:77
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
blender::float2 anchored_initial_mouse
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:178
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)