Blender V5.0
overlay_cursor.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include "BKE_paint.hh"
12
13#include "DNA_brush_types.h"
14#include "DNA_screen_types.h"
15#include "DNA_space_types.h"
16
17#include "ED_view3d.hh"
18#include "UI_view2d.hh"
19
20#include "overlay_base.hh"
21
22namespace blender::draw::overlay {
23
28class Cursor : Overlay {
29 private:
30 PassSimple ps_ = {"Cursor"};
31
32 bool enabled_ = false;
33
34 public:
35 Cursor() {}
36
37 void begin_sync(Resources &res, const State &state) final
38 {
39 if (state.is_space_v3d()) {
40 enabled_ = is_cursor_visible_3d(state);
41 }
42 else {
43 enabled_ = is_cursor_visible_2d(state);
44 }
45
46 if (!enabled_) {
47 return;
48 }
49
50 /* 2D coordinate of the cursor in screen space pixel. */
51 int2 pixel_coord;
52
53 float3x3 rotation = float3x3::identity();
54
55 /* TODO(fclem): This is against design. Sync shouldn't depend on view. */
56 if (state.is_space_v3d()) {
57 const View3DCursor *cursor = &state.scene->cursor;
58 rotation = float3x3(float4x4(state.rv3d->viewmat).view<3, 3>()) *
59 math::from_rotation<float3x3>(cursor->rotation());
60
62 state.region, cursor->location, pixel_coord, V3D_PROJ_TEST_CLIP_NEAR);
63 if (status != V3D_PROJ_RET_OK) {
64 /* Clipped. */
65 enabled_ = false;
66 return;
67 }
68 }
69 else {
70 const SpaceImage *sima = (SpaceImage *)state.space_data;
72 &state.region->v2d, sima->cursor[0], sima->cursor[1], &pixel_coord[0], &pixel_coord[1]);
73 }
74
75 float4x4 cursor_mat = math::from_scale<float4x4>(float2(U.widget_unit));
76 cursor_mat.location()[0] = pixel_coord[0] + 0.5f;
77 cursor_mat.location()[1] = pixel_coord[1] + 0.5f;
78
79 /* Copy of wmOrtho2_region_pixelspace but without GPU_matrix_ortho_set. */
80 const float ofs = -0.01f;
82 ofs, state.region->winx + ofs, ofs, state.region->winy + ofs, -100.0f, 100.0f);
83
84 float4x4 mvp = proj_mat * cursor_mat;
85
86 PassSimple &pass = ps_;
87 pass.init();
90 pass.push_constant("viewportSize", float2(state.region->winx, state.region->winy));
91 pass.push_constant("lineWidth", U.pixelsize);
92 pass.push_constant("lineSmooth", true);
93 /* WORKAROUND: This is normally set by the GPUBatch or IMM API but we don't use them here.
94 * So make sure it is set otherwise it can be in undefined state (see #136911). */
95 pass.push_constant("gpu_attr_0_fetch_int", false);
96 pass.push_constant("gpu_attr_1_fetch_unorm8", false);
97 pass.push_constant("gpu_attr_0_len", 3);
98 pass.push_constant("gpu_attr_1_len", 3);
99 /* See `polyline_draw_workaround`. */
100 int3 vert_stride_count_line = {2, 9999 /* Doesn't matter. */, 0};
101 int3 vert_stride_count_circle = {1, 9999 /* Doesn't matter. */, 0};
102
103 if (state.is_space_v3d()) {
104 const View3DCursor *cursor = &state.scene->cursor;
105 const float scale = ED_view3d_pixel_size_no_ui_scale(state.rv3d, cursor->location);
106 /* Only draw the axes lines in 3D with the correct perspective. */
108 cursor->location, cursor->rotation(), float3(scale * U.widget_unit));
109
110 float4x4 mvp_lines = float4x4(state.rv3d->winmat) * float4x4(state.rv3d->viewmat) *
111 cursor_mat;
112
113 pass.push_constant("ModelViewProjectionMatrix", mvp);
114 pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_circle);
115 pass.draw_expand(res.shapes.cursor_circle.get(), GPU_PRIM_TRIS, 2, 1);
116 pass.push_constant("ModelViewProjectionMatrix", mvp_lines);
117 pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_line);
118 pass.draw_expand(res.shapes.cursor_lines.get(), GPU_PRIM_TRIS, 2, 1);
119 }
120 else {
121 pass.push_constant("ModelViewProjectionMatrix", mvp);
122 pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_circle);
123 pass.draw_expand(res.shapes.cursor_circle.get(), GPU_PRIM_TRIS, 2, 1);
124 pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_line);
125 pass.draw_expand(res.shapes.cursor_lines.get(), GPU_PRIM_TRIS, 2, 1);
126 }
127 }
128
129 void draw_output(Framebuffer &framebuffer, Manager &manager, View & /*view*/) final
130 {
131 if (!enabled_) {
132 return;
133 }
134
135 GPU_framebuffer_bind(framebuffer);
136 manager.submit(ps_);
137 }
138
139 private:
140 bool is_cursor_visible_3d(const State &state)
141 {
142 if (G.moving & G_TRANSFORM_CURSOR) {
143 return true;
144 }
145
146 const View3D *v3d = state.v3d;
148 return false;
149 }
150
151 /* don't draw cursor in paint modes, but with a few exceptions */
152 if ((state.object_mode & (OB_MODE_ALL_PAINT | OB_MODE_SCULPT_CURVES)) != 0) {
153 /* exception: object is in weight paint and has deforming armature in pose mode */
154 if (state.object_mode & OB_MODE_WEIGHT_PAINT) {
155 if (BKE_object_pose_armature_get(const_cast<Object *>(state.object_active)) != nullptr) {
156 return true;
157 }
158 }
159 /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */
160 else if (state.object_mode & OB_MODE_TEXTURE_PAINT) {
161 const Paint *paint = BKE_paint_get_active(const_cast<Scene *>(state.scene),
162 const_cast<ViewLayer *>(state.view_layer));
163 const Brush *brush = (paint) ? BKE_paint_brush_for_read(paint) : nullptr;
164
165 if (brush && brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_CLONE) {
166 if ((state.scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
167 return true;
168 }
169 }
170 }
171
172 /* no exception met? then don't draw cursor! */
173 return false;
174 }
175
176 if (state.object_mode & OB_MODE_WEIGHT_GREASE_PENCIL) {
177 /* grease pencil hide always in some modes */
178 return false;
179 }
180
181 return true;
182 }
183
184 static bool is_cursor_visible_2d(const State &state)
185 {
186 SpaceInfo *space_data = (SpaceInfo *)state.space_data;
187 if (space_data == nullptr) {
188 return false;
189 }
190 if (space_data->spacetype != SPACE_IMAGE) {
191 return false;
192 }
193 SpaceImage *sima = (SpaceImage *)space_data;
194 switch (sima->mode) {
195 case SI_MODE_VIEW:
196 return false;
197 break;
198 case SI_MODE_PAINT:
199 return false;
200 break;
201 case SI_MODE_MASK:
202 break;
203 case SI_MODE_UV:
204 break;
205 }
206 return (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS) != 0;
207 }
208};
209
210} // namespace blender::draw::overlay
@ G_TRANSFORM_CURSOR
Object * BKE_object_pose_armature_get(Object *ob)
Paint * BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
Definition paint.cc:437
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
@ IMAGE_PAINT_BRUSH_TYPE_CLONE
struct Brush Brush
struct ViewLayer ViewLayer
#define OB_MODE_ALL_PAINT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_SCULPT_CURVES
@ OB_MODE_TEXTURE_PAINT
@ OB_MODE_WEIGHT_GREASE_PENCIL
struct Scene Scene
@ IMAGEPAINT_PROJECT_LAYER_CLONE
struct Paint Paint
@ SI_OVERLAY_SHOW_OVERLAYS
@ SPACE_IMAGE
@ SI_MODE_PAINT
@ SI_MODE_VIEW
@ SI_MODE_MASK
@ SI_MODE_UV
struct SpaceInfo SpaceInfo
struct SpaceImage SpaceImage
@ V3D_HIDE_OVERLAYS
@ V3D_OVERLAY_HIDE_CURSOR
@ V3D_PROJ_TEST_CLIP_NEAR
Definition ED_view3d.hh:282
float ED_view3d_pixel_size_no_ui_scale(const RegionView3D *rv3d, const float co[3])
eV3DProjStatus
Definition ED_view3d.hh:255
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
eV3DProjStatus ED_view3d_project_int_global(const ARegion *region, const float co[3], int r_co[2], eV3DProjTest flag)
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
@ GPU_PRIM_TRIS
blender::gpu::Shader * GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
@ GPU_SHADER_3D_POLYLINE_FLAT_COLOR
void UI_view2d_view_to_region(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1723
#define U
void shader_set(gpu::Shader *shader)
void draw_expand(gpu::Batch *batch, GPUPrimType primitive_type, uint primitive_len, uint instance_len, uint vertex_len, uint vertex_first, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:925
void state_set(DRWState state, int clip_plane_count=0)
void push_constant(const char *name, const float &data)
void begin_sync(Resources &res, const State &state) final
void draw_output(Framebuffer &framebuffer, Manager &manager, View &) final
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
static ulong state[N]
#define G(x, y, z)
detail::Pass< command::DrawCommandBuf > PassSimple
MatBase< T, 4, 4 > orthographic(T left, T right, T bottom, T top, T near_clip, T far_clip)
Create an orthographic projection matrix using OpenGL coordinate convention: Maps each axis range to ...
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
MatT from_rotation(const RotationT &rotation)
MatT from_loc_rot_scale(const typename MatT::loc_type &location, const RotationT &rotation, const VecBase< typename MatT::base_type, ScaleDim > &scale)
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
const int status
char image_brush_type
float cursor[2]
SpaceImageOverlay overlay
View3DOverlay overlay
const MatView< T, ViewNumCol, ViewNumRow, NumCol, NumRow, SrcStartCol, SrcStartRow, Alignment > view() const