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:
@@ -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
|
||||
|
||||
193
source/blender/draw/engines/overlay/overlay_next_cursor.hh
Normal file
193
source/blender/draw/engines/overlay/overlay_next_cursor.hh
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
* \{ */
|
||||
|
||||
Reference in New Issue
Block a user