Overlay: Move 3D cursor drawing to the overlay engine

This is the more logical place and remove the use of the global
batch cache.
This commit is contained in:
Clément Foucault
2025-02-14 18:38:52 +01:00
parent 28ad3736e8
commit 38ce310c17
9 changed files with 262 additions and 152 deletions

View File

@@ -250,6 +250,7 @@ set(SRC
engines/overlay/overlay_next_background.hh
engines/overlay/overlay_next_bounds.hh
engines/overlay/overlay_next_camera.hh
engines/overlay/overlay_next_cursor.hh
engines/overlay/overlay_next_curve.hh
engines/overlay/overlay_next_edit_text.hh
engines/overlay/overlay_next_empty.hh

View File

@@ -0,0 +1,193 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include "BKE_paint.hh"
#include "DNA_brush_types.h"
#include "DNA_screen_types.h"
#include "ED_view3d.hh"
#include "UI_view2d.hh"
#include "overlay_next_base.hh"
namespace blender::draw::overlay {
/**
* Draw the 2D/3D cursor.
* Controlled by (Overlay > 3D Cursor)
*/
class Cursor : Overlay {
private:
PassSimple ps_ = {"Cursor"};
bool enabled_ = false;
public:
Cursor() {}
void begin_sync(Resources &res, const State &state) final
{
if (state.is_space_v3d()) {
enabled_ = is_cursor_visible_3d(state);
}
else {
enabled_ = is_cursor_visible_2d(state);
}
if (!enabled_) {
return;
}
/* 2D coordinate of the cursor in screen space pixel. */
int2 pixel_coord;
float3x3 rotation = float3x3::identity();
/* TODO(fclem): This is against design. Sync shouldn't depend on view. */
if (state.is_space_v3d()) {
const View3DCursor *cursor = &state.scene->cursor;
rotation = float3x3(float4x4(state.rv3d->viewmat).view<3, 3>()) *
math::from_rotation<float3x3>(cursor->rotation());
eV3DProjStatus status = ED_view3d_project_int_global(
state.region, cursor->location, pixel_coord, V3D_PROJ_TEST_CLIP_NEAR);
if (status != V3D_PROJ_RET_OK) {
/* Clipped. */
return;
}
}
else {
const SpaceImage *sima = (SpaceImage *)state.space_data;
UI_view2d_view_to_region(
&state.region->v2d, sima->cursor[0], sima->cursor[1], &pixel_coord[0], &pixel_coord[1]);
}
float4x4 cursor_mat = math::from_scale<float4x4>(float2(U.widget_unit));
cursor_mat.location()[0] = pixel_coord[0] + 0.5f;
cursor_mat.location()[1] = pixel_coord[1] + 0.5f;
/* Copy of wmOrtho2_region_pixelspace but without GPU_matrix_ortho_set. */
const float ofs = -0.01f;
float4x4 proj_mat = math::projection::orthographic(
ofs, state.region->winx + ofs, ofs, state.region->winy + ofs, -100.0f, 100.0f);
float4x4 mvp = proj_mat * cursor_mat;
PassSimple &pass = ps_;
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
pass.shader_set(GPU_shader_get_builtin_shader(GPU_SHADER_3D_POLYLINE_FLAT_COLOR));
pass.push_constant("ModelViewProjectionMatrix", mvp);
pass.push_constant("viewportSize", float2(state.region->winx, state.region->winy));
pass.push_constant("lineWidth", U.pixelsize);
pass.push_constant("lineSmooth", true);
/* See `polyline_draw_workaround`. */
int3 vert_stride_count_line = {2, 9999 /* Doesn't matter. */, 0};
int3 vert_stride_count_circle = {1, 9999 /* Doesn't matter. */, 0};
if (state.is_space_v3d()) {
/* Render line first to avoid Z fighting. */
pass.push_constant("ModelViewProjectionMatrix", mvp * float4x4(rotation));
pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_line);
pass.draw_expand(res.shapes.cursor_lines.get(), GPU_PRIM_TRIS, 2, 1, ResourceHandle(0));
pass.push_constant("ModelViewProjectionMatrix", mvp);
pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_circle);
pass.draw_expand(res.shapes.cursor_circle.get(), GPU_PRIM_TRIS, 2, 1, ResourceHandle(0));
}
else {
pass.push_constant("ModelViewProjectionMatrix", mvp);
pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_circle);
pass.draw_expand(res.shapes.cursor_circle.get(), GPU_PRIM_TRIS, 2, 1, ResourceHandle(0));
pass.push_constant("gpu_vert_stride_count_offset", vert_stride_count_line);
pass.draw_expand(res.shapes.cursor_lines.get(), GPU_PRIM_TRIS, 2, 1, ResourceHandle(0));
}
}
void draw_output(Framebuffer &framebuffer, Manager &manager, View & /*view*/) final
{
if (!enabled_) {
return;
}
GPU_framebuffer_bind(framebuffer);
manager.submit(ps_);
}
private:
bool is_cursor_visible_3d(const State &state)
{
if (G.moving & G_TRANSFORM_CURSOR) {
return true;
}
const View3D *v3d = state.v3d;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_CURSOR)) {
return false;
}
/* don't draw cursor in paint modes, but with a few exceptions */
if ((state.object_mode & (OB_MODE_ALL_PAINT | OB_MODE_SCULPT_CURVES)) != 0) {
/* exception: object is in weight paint and has deforming armature in pose mode */
if (state.object_mode & OB_MODE_WEIGHT_PAINT) {
if (BKE_object_pose_armature_get(const_cast<Object *>(state.object_active)) != nullptr) {
return true;
}
}
/* exception: object in texture paint mode, clone brush, use_clone_layer disabled */
else if (state.object_mode & OB_MODE_TEXTURE_PAINT) {
const Paint *paint = BKE_paint_get_active(const_cast<Scene *>(state.scene),
const_cast<ViewLayer *>(state.view_layer));
const Brush *brush = (paint) ? BKE_paint_brush_for_read(paint) : nullptr;
if (brush && brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_CLONE) {
if ((state.scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
return true;
}
}
}
/* no exception met? then don't draw cursor! */
return false;
}
if (state.object_mode & OB_MODE_WEIGHT_GREASE_PENCIL) {
/* grease pencil hide always in some modes */
return false;
}
return true;
}
static bool is_cursor_visible_2d(const State &state)
{
SpaceInfo *space_data = (SpaceInfo *)state.space_data;
if (space_data == nullptr) {
return false;
}
if (space_data->spacetype != SPACE_IMAGE) {
return false;
}
SpaceImage *sima = (SpaceImage *)space_data;
switch (sima->mode) {
case SI_MODE_VIEW:
return false;
break;
case SI_MODE_PAINT:
return false;
break;
case SI_MODE_MASK:
break;
case SI_MODE_UV:
break;
}
return (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS) != 0;
}
};
} // namespace blender::draw::overlay

View File

@@ -130,6 +130,7 @@ void Instance::begin_sync()
resources.begin_sync();
background.begin_sync(resources, state);
cursor.begin_sync(resources, state);
image_prepass.begin_sync(resources, state);
motion_paths.begin_sync(resources, state);
origins.begin_sync(resources, state);
@@ -465,6 +466,8 @@ void Instance::draw_v2d(Manager &manager, View &view)
background.draw_output(resources.overlay_output_color_only_fb, manager, view);
grid.draw_color_only(resources.overlay_output_color_only_fb, manager, view);
regular.mesh_uvs.draw(resources.overlay_output_fb, manager, view);
cursor.draw_output(resources.overlay_output_color_only_fb, manager, view);
}
void Instance::draw_v3d(Manager &manager, View &view)
@@ -609,6 +612,7 @@ void Instance::draw_v3d(Manager &manager, View &view)
background.draw_output(resources.overlay_output_color_only_fb, manager, view);
anti_aliasing.draw_output(resources.overlay_output_color_only_fb, manager, view);
cursor.draw_output(resources.overlay_output_color_only_fb, manager, view);
}
}

View File

@@ -18,6 +18,7 @@
#include "overlay_next_background.hh"
#include "overlay_next_bounds.hh"
#include "overlay_next_camera.hh"
#include "overlay_next_cursor.hh"
#include "overlay_next_curve.hh"
#include "overlay_next_edit_text.hh"
#include "overlay_next_empty.hh"
@@ -74,6 +75,7 @@ class Instance {
Origins origins = {selection_type_};
Outline outline;
MotionPath motion_paths;
Cursor cursor;
struct OverlayLayer {
const SelectionType selection_type_;

View File

@@ -303,6 +303,9 @@ class ShapeCache {
BatchPtr grid;
BatchPtr cube_solid;
BatchPtr cursor_circle;
BatchPtr cursor_lines;
BatchPtr quad_wire;
BatchPtr quad_solid;
BatchPtr plain_axes;

View File

@@ -19,6 +19,11 @@ struct Vertex {
int vclass;
};
struct VertexWithColor {
float3 pos;
float3 color;
};
struct VertShaded {
float3 pos;
int v_class;
@@ -77,6 +82,20 @@ static gpu::VertBuf *vbo_from_vector(Vector<VertexTriple> &vector)
return vbo;
}
static gpu::VertBuf *vbo_from_vector(Vector<VertexWithColor> &vector)
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
gpu::VertBuf *vbo = GPU_vertbuf_create_with_format(format);
GPU_vertbuf_data_alloc(*vbo, vector.size());
vbo->data<VertexWithColor>().copy_from(vector);
return vbo;
}
enum VertexClass {
VCLASS_NONE = 0,
@@ -1412,6 +1431,46 @@ ShapeCache::ShapeCache()
grid = BatchPtr(
GPU_batch_create_ex(GPU_PRIM_TRIS, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
}
/* cursor circle */
{
const int segments = 16;
const float red[3] = {1.0f, 0.0f, 0.0f};
const float white[3] = {1.0f, 1.0f, 1.0f};
Vector<VertexWithColor> verts;
for (int i = 0; i < segments + 1; i++) {
float angle = float(2 * M_PI) * (float(i) / float(segments));
verts.append({0.5f * float3(cosf(angle), sinf(angle), 0.0f), (i % 2 == 0) ? red : white});
}
cursor_circle = BatchPtr(GPU_batch_create_ex(
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
}
/* cursor lines */
{
const float f5 = 0.25f;
const float f20 = 1.0f;
float crosshair_color[3];
UI_GetThemeColor3fv(TH_VIEW_OVERLAY, crosshair_color);
Vector<VertexWithColor> verts;
for (int i = 0; i < 3; i++) {
float3 axis(0.0f);
axis[i] = 1.0f;
verts.append({f5 * axis, crosshair_color});
verts.append({f20 * axis, crosshair_color});
axis[i] = -1.0f;
verts.append({f5 * axis, crosshair_color});
verts.append({f20 * axis, crosshair_color});
}
cursor_lines = BatchPtr(
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
}
}
} // namespace blender::draw::overlay

View File

@@ -41,11 +41,6 @@ void DRW_shape_cache_free();
/* 3D cursor */
blender::gpu::Batch *DRW_cache_cursor_get(bool crosshair_lines);
/* Just a regular quad with 4 vertices. */
blender::gpu::Batch *DRW_cache_quad_get();
blender::gpu::Batch *DRW_cache_cube_get();
/* Common Object */
blender::gpu::Batch *DRW_cache_object_all_edges_get(Object *ob);

View File

@@ -2111,7 +2111,6 @@ void DRW_draw_render_loop_2d_ex(Depsgraph *depsgraph,
}
}
DRW_draw_cursor_2d();
ED_region_pixelspace(DST.draw_ctx.region);
if (do_draw_gizmos) {

View File

@@ -50,156 +50,10 @@ void DRW_draw_region_info()
const DRWContextState *draw_ctx = DRW_context_state_get();
ARegion *region = draw_ctx->region;
DRW_draw_cursor();
view3d_draw_region_info(draw_ctx->evil_C, region);
GPU_debug_group_end();
}
/* **************************** 3D Cursor ******************************** */
static bool is_cursor_visible(const DRWContextState *draw_ctx, Scene *scene, ViewLayer *view_layer)
{
if (G.moving & G_TRANSFORM_CURSOR) {
return true;
}
View3D *v3d = draw_ctx->v3d;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_CURSOR)) {
return false;
}
/* don't draw cursor in paint modes, but with a few exceptions */
if ((draw_ctx->object_mode & (OB_MODE_ALL_PAINT | OB_MODE_SCULPT_CURVES)) != 0) {
/* exception: object is in weight paint and has deforming armature in pose mode */
if (draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) {
if (BKE_object_pose_armature_get(draw_ctx->obact) != nullptr) {
return true;
}
}
/* exception: object in texture paint mode, clone brush, use_clone_layer disabled */
else if (draw_ctx->object_mode & OB_MODE_TEXTURE_PAINT) {
const Paint *paint = BKE_paint_get_active(scene, view_layer);
const Brush *brush = (paint) ? BKE_paint_brush_for_read(paint) : nullptr;
if (brush && brush->image_brush_type == IMAGE_PAINT_BRUSH_TYPE_CLONE) {
if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
return true;
}
}
}
/* no exception met? then don't draw cursor! */
return false;
}
if (draw_ctx->object_mode & OB_MODE_WEIGHT_GREASE_PENCIL) {
/* grease pencil hide always in some modes */
return false;
}
return true;
}
void DRW_draw_cursor()
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ARegion *region = draw_ctx->region;
Scene *scene = draw_ctx->scene;
ViewLayer *view_layer = draw_ctx->view_layer;
if (!is_cursor_visible(draw_ctx, scene, view_layer)) {
return;
}
GPU_color_mask(true, true, true, true);
GPU_depth_mask(false);
GPU_depth_test(GPU_DEPTH_NONE);
/* Get cursor data into quaternion form */
const View3DCursor *cursor = &scene->cursor;
int co[2];
if (ED_view3d_project_int_global(
region, cursor->location, co, V3D_PROJ_TEST_NOP | V3D_PROJ_TEST_CLIP_NEAR) !=
V3D_PROJ_RET_OK)
{
return;
}
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
blender::math::Quaternion cursor_quat = cursor->rotation();
/* Draw nice Anti Aliased cursor. */
GPU_line_width(1.0f);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
float eps = 1e-5f;
rv3d->viewquat[0] = -rv3d->viewquat[0];
bool is_aligned = compare_v4v4(&cursor_quat.w, rv3d->viewquat, eps);
if (is_aligned == false) {
float tquat[4];
rotation_between_quats_to_quat(tquat, rv3d->viewquat, &cursor_quat.w);
is_aligned = tquat[0] - eps < -1.0f;
}
rv3d->viewquat[0] = -rv3d->viewquat[0];
/* Draw lines */
if (is_aligned == false) {
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColor3(TH_VIEW_OVERLAY);
immBegin(GPU_PRIM_LINES, 12);
const float scale = ED_view3d_pixel_size_no_ui_scale(rv3d, cursor->location) * U.widget_unit;
#define CURSOR_VERT(axis_vec, axis, fac) \
immVertex3f(pos, \
cursor->location[0] + axis_vec[0] * (fac), \
cursor->location[1] + axis_vec[1] * (fac), \
cursor->location[2] + axis_vec[2] * (fac))
#define CURSOR_EDGE(axis_vec, axis, sign) \
{ \
CURSOR_VERT(axis_vec, axis, sign 1.0f); \
CURSOR_VERT(axis_vec, axis, sign 0.25f); \
} \
((void)0)
for (int axis = 0; axis < 3; axis++) {
float axis_vec[3] = {0};
axis_vec[axis] = scale;
mul_qt_v3(&cursor_quat.w, axis_vec);
CURSOR_EDGE(axis_vec, axis, +);
CURSOR_EDGE(axis_vec, axis, -);
}
#undef CURSOR_VERT
#undef CURSOR_EDGE
immEnd();
immUnbindProgram();
}
float original_proj[4][4];
GPU_matrix_projection_get(original_proj);
GPU_matrix_push();
ED_region_pixelspace(region);
GPU_matrix_translate_2f(co[0] + 0.5f, co[1] + 0.5f);
GPU_matrix_scale_2f(U.widget_unit, U.widget_unit);
blender::gpu::Batch *cursor_batch = DRW_cache_cursor_get(is_aligned);
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
GPU_batch_set_shader(cursor_batch, shader);
GPU_batch_draw(cursor_batch);
GPU_blend(GPU_BLEND_NONE);
GPU_line_smooth(false);
GPU_matrix_pop();
GPU_matrix_projection_set(original_proj);
}
/* -------------------------------------------------------------------- */
/** \name 2D Cursor
* \{ */