Blender V4.5
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#include "DNA_brush_types.h"
13
14#include "DNA_screen_types.h"
15#include "DNA_space_types.h"
16#include "ED_view3d.hh"
17#include "UI_view2d.hh"
18
19#include "overlay_base.hh"
20
21namespace blender::draw::overlay {
22
27class Cursor : Overlay {
28 private:
29 PassSimple ps_ = {"Cursor"};
30
31 bool enabled_ = false;
32
33 public:
34 Cursor() {}
35
36 void begin_sync(Resources &res, const State &state) final
37 {
38 if (state.is_space_v3d()) {
39 enabled_ = is_cursor_visible_3d(state);
40 }
41 else {
42 enabled_ = is_cursor_visible_2d(state);
43 }
44
45 if (!enabled_) {
46 return;
47 }
48
49 /* 2D coordinate of the cursor in screen space pixel. */
50 int2 pixel_coord;
51
52 float3x3 rotation = float3x3::identity();
53
54 /* TODO(fclem): This is against design. Sync shouldn't depend on view. */
55 if (state.is_space_v3d()) {
56 const View3DCursor *cursor = &state.scene->cursor;
57 rotation = float3x3(float4x4(state.rv3d->viewmat).view<3, 3>()) *
58 math::from_rotation<float3x3>(cursor->rotation());
59
61 state.region, cursor->location, pixel_coord, V3D_PROJ_TEST_CLIP_NEAR);
62 if (status != V3D_PROJ_RET_OK) {
63 /* Clipped. */
64 return;
65 }
66 }
67 else {
68 const SpaceImage *sima = (SpaceImage *)state.space_data;
70 &state.region->v2d, sima->cursor[0], sima->cursor[1], &pixel_coord[0], &pixel_coord[1]);
71 }
72
73 float4x4 cursor_mat = math::from_scale<float4x4>(float2(U.widget_unit));
74 cursor_mat.location()[0] = pixel_coord[0] + 0.5f;
75 cursor_mat.location()[1] = pixel_coord[1] + 0.5f;
76
77 /* Copy of wmOrtho2_region_pixelspace but without GPU_matrix_ortho_set. */
78 const float ofs = -0.01f;
80 ofs, state.region->winx + ofs, ofs, state.region->winy + ofs, -100.0f, 100.0f);
81
82 float4x4 mvp = proj_mat * cursor_mat;
83
84 PassSimple &pass = ps_;
85 pass.init();
88 pass.push_constant("viewportSize", float2(state.region->winx, state.region->winy));
89 pass.push_constant("lineWidth", U.pixelsize);
90 pass.push_constant("lineSmooth", true);
91 /* WORKAROUND: This is normally set by the GPUBatch or IMM API but we don't use them here.
92 * So make sure it is set otherwise it can be in undefined state (see #136911). */
93 pass.push_constant("gpu_attr_0_fetch_int", false);
94 pass.push_constant("gpu_attr_1_fetch_unorm8", false);
95 /* See `polyline_draw_workaround`. */
96 int3 vert_stride_count_line = {2, 9999 /* Doesn't matter. */, 0};
97 int3 vert_stride_count_circle = {1, 9999 /* Doesn't matter. */, 0};
98
99 if (state.is_space_v3d()) {
100 const View3DCursor *cursor = &state.scene->cursor;
101 const float scale = ED_view3d_pixel_size_no_ui_scale(state.rv3d, cursor->location);
102 /* Only draw the axes lines in 3D with the correct perspective. */
104 cursor->location, cursor->rotation(), float3(scale * U.widget_unit));
105
106 float4x4 mvp_lines = float4x4(state.rv3d->winmat) * float4x4(state.rv3d->viewmat) *
107 cursor_mat;
108
109 /* Render line first to avoid Z fighting. */
110 pass.push_constant("ModelViewProjectionMatrix", mvp_lines);
111 pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_line);
112 pass.draw_expand(res.shapes.cursor_lines.get(), GPU_PRIM_TRIS, 2, 1, ResourceHandle(0));
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, ResourceHandle(0));
116 }
117 else {
118 pass.push_constant("ModelViewProjectionMatrix", mvp);
119 pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_circle);
120 pass.draw_expand(res.shapes.cursor_circle.get(), GPU_PRIM_TRIS, 2, 1, ResourceHandle(0));
121 pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_line);
122 pass.draw_expand(res.shapes.cursor_lines.get(), GPU_PRIM_TRIS, 2, 1, ResourceHandle(0));
123 }
124 }
125
126 void draw_output(Framebuffer &framebuffer, Manager &manager, View & /*view*/) final
127 {
128 if (!enabled_) {
129 return;
130 }
131
132 GPU_framebuffer_bind(framebuffer);
133 manager.submit(ps_);
134 }
135
136 private:
137 bool is_cursor_visible_3d(const State &state)
138 {
139 if (G.moving & G_TRANSFORM_CURSOR) {
140 return true;
141 }
142
143 const View3D *v3d = state.v3d;
145 return false;
146 }
147
148 /* don't draw cursor in paint modes, but with a few exceptions */
149 if ((state.object_mode & (OB_MODE_ALL_PAINT | OB_MODE_SCULPT_CURVES)) != 0) {
150 /* exception: object is in weight paint and has deforming armature in pose mode */
151 if (state.object_mode & OB_MODE_WEIGHT_PAINT) {
152 if (BKE_object_pose_armature_get(const_cast<Object *>(state.object_active)) != nullptr) {
153 return true;
154 }
155 }
156 /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */
157 else if (state.object_mode & OB_MODE_TEXTURE_PAINT) {
158 const Paint *paint = BKE_paint_get_active(const_cast<Scene *>(state.scene),
159 const_cast<ViewLayer *>(state.view_layer));
160 const Brush *brush = (paint) ? BKE_paint_brush_for_read(paint) : nullptr;
161
162 if (brush && brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_CLONE) {
163 if ((state.scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
164 return true;
165 }
166 }
167 }
168
169 /* no exception met? then don't draw cursor! */
170 return false;
171 }
172
173 if (state.object_mode & OB_MODE_WEIGHT_GREASE_PENCIL) {
174 /* grease pencil hide always in some modes */
175 return false;
176 }
177
178 return true;
179 }
180
181 static bool is_cursor_visible_2d(const State &state)
182 {
183 SpaceInfo *space_data = (SpaceInfo *)state.space_data;
184 if (space_data == nullptr) {
185 return false;
186 }
187 if (space_data->spacetype != SPACE_IMAGE) {
188 return false;
189 }
190 SpaceImage *sima = (SpaceImage *)space_data;
191 switch (sima->mode) {
192 case SI_MODE_VIEW:
193 return false;
194 break;
195 case SI_MODE_PAINT:
196 return false;
197 break;
198 case SI_MODE_MASK:
199 break;
200 case SI_MODE_UV:
201 break;
202 }
203 return (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS) != 0;
204 }
205};
206
207} // 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:428
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:641
@ 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
@ IMAGEPAINT_PROJECT_LAYER_CLONE
struct Scene Scene
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_OVERLAY_HIDE_CURSOR
@ V3D_HIDE_OVERLAYS
@ 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(GPUFrameBuffer *fb)
@ GPU_PRIM_TRIS
GPUShader * GPU_shader_get_builtin_shader(eGPUBuiltinShader 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:1722
#define U
void state_set(DRWState state, int clip_plane_count=0)
void draw_expand(gpu::Batch *batch, GPUPrimType primitive_type, uint primitive_len, uint instance_len, uint vertex_len=-1, uint vertex_first=-1, ResourceHandleRange handle={0}, uint custom_id=0)
Definition draw_pass.hh:915
void push_constant(const char *name, const float &data)
void shader_set(GPUShader *shader)
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
char image_brush_type
float cursor[2]
SpaceImageOverlay overlay
View3DOverlay overlay
const MatView< T, ViewNumCol, ViewNumRow, NumCol, NumRow, SrcStartCol, SrcStartRow, Alignment > view() const