From cdb9b6a04172e6577dc4cf1a1642489d35b629a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 10 Feb 2023 18:46:05 +0100 Subject: [PATCH] Overlay-Next: Add support for empties Also added a shape cache and move the color selection to `Resources`. --- .../draw/engines/overlay/overlay_empty.hh | 147 ++++++++ .../draw/engines/overlay/overlay_grid.hh | 4 +- .../draw/engines/overlay/overlay_instance.cc | 14 +- .../draw/engines/overlay/overlay_instance.hh | 4 + .../draw/engines/overlay/overlay_metaball.hh | 5 +- .../draw/engines/overlay/overlay_private.hh | 90 ++++- .../draw/engines/overlay/overlay_shader.cc | 12 + .../engines/overlay/overlay_shader_shared.h | 17 + .../draw/engines/overlay/overlay_shape.hh | 330 ++++++++++++++++++ .../shaders/infos/overlay_extra_info.hh | 1 + source/blender/editors/include/ED_view3d.h | 6 +- .../editors/space_view3d/view3d_draw.cc | 6 +- 12 files changed, 619 insertions(+), 17 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_empty.hh create mode 100644 source/blender/draw/engines/overlay/overlay_shape.hh diff --git a/source/blender/draw/engines/overlay/overlay_empty.hh b/source/blender/draw/engines/overlay/overlay_empty.hh new file mode 100644 index 00000000000..1c28f0cbaa3 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_empty.hh @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "DNA_object_types.h" + +#include "draw_pass.hh" +#include "draw_shader_shared.h" +#include "overlay_private.hh" +#include "overlay_shape.hh" + +namespace blender::draw::overlay { + +class Empties { + + private: + PassSimple empty_ps_ = {"Empties"}; + PassSimple empty_in_front_ps_ = {"Empties_In_front"}; + + using EmptyInstanceBuf = StorageVectorBuffer; + + struct CallBuffers { + EmptyInstanceBuf plain_axes_buf = {"plain_axes_buf"}; + EmptyInstanceBuf single_arrow_buf = {"single_arrow_buf"}; + EmptyInstanceBuf cube_buf = {"cube_buf"}; + EmptyInstanceBuf circle_buf = {"circle_buf"}; + EmptyInstanceBuf sphere_buf = {"sphere_buf"}; + EmptyInstanceBuf cone_buf = {"cone_buf"}; + EmptyInstanceBuf arrows_buf = {"arrows_buf"}; + EmptyInstanceBuf image_buf = {"image_buf"}; + } call_buffers_[2]; + + public: + void begin_sync() + { + for (int i = 0; i < 2; i++) { + call_buffers_[i].plain_axes_buf.clear(); + call_buffers_[i].single_arrow_buf.clear(); + call_buffers_[i].cube_buf.clear(); + call_buffers_[i].circle_buf.clear(); + call_buffers_[i].sphere_buf.clear(); + call_buffers_[i].cone_buf.clear(); + call_buffers_[i].arrows_buf.clear(); + call_buffers_[i].image_buf.clear(); + } + } + + void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state) + { + CallBuffers &call_bufs = call_buffers_[int((ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0)]; + + float4 color = res.object_wire_color(ob_ref, state); + ExtraInstanceData data( + float4x4(ob_ref.object->object_to_world), color, ob_ref.object->empty_drawsize); + + switch (ob_ref.object->empty_drawtype) { + case OB_PLAINAXES: + call_bufs.plain_axes_buf.append(data); + break; + case OB_SINGLE_ARROW: + call_bufs.single_arrow_buf.append(data); + break; + case OB_CUBE: + call_bufs.cube_buf.append(data); + break; + case OB_CIRCLE: + call_bufs.circle_buf.append(data); + break; + case OB_EMPTY_SPHERE: + call_bufs.sphere_buf.append(data); + break; + case OB_EMPTY_CONE: + call_bufs.cone_buf.append(data); + break; + case OB_ARROWS: + call_bufs.arrows_buf.append(data); + break; + case OB_EMPTY_IMAGE: + /* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */ + call_bufs.image_buf.append(data); + break; + } + } + + void end_sync(Resources &res, ShapeCache &shapes, const State &state) + { + auto init_pass = [&](PassSimple &pass, CallBuffers &call_bufs) { + pass.init(); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + state.clipping_state); + pass.shader_set(OVERLAY_shader_extra(false)); + pass.bind_ubo("globalsBlock", &res.globals_buf); + + call_bufs.plain_axes_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.plain_axes_buf); + pass.draw(shapes.plain_axes, call_bufs.plain_axes_buf.size()); + + call_bufs.single_arrow_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.single_arrow_buf); + pass.draw(shapes.single_arrow, call_bufs.single_arrow_buf.size()); + + call_bufs.cube_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.cube_buf); + pass.draw(shapes.cube, call_bufs.cube_buf.size()); + + call_bufs.circle_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.circle_buf); + pass.draw(shapes.circle, call_bufs.circle_buf.size()); + + call_bufs.sphere_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.sphere_buf); + pass.draw(shapes.empty_sphere, call_bufs.sphere_buf.size()); + + call_bufs.cone_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.cone_buf); + pass.draw(shapes.empty_cone, call_bufs.cone_buf.size()); + + call_bufs.arrows_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.arrows_buf); + pass.draw(shapes.arrows, call_bufs.arrows_buf.size()); + + call_bufs.image_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.image_buf); + pass.draw(shapes.quad_wire, call_bufs.image_buf.size()); + }; + init_pass(empty_ps_, call_buffers_[0]); + init_pass(empty_in_front_ps_, call_buffers_[1]); + } + + void draw(Resources &res, Manager &manager, View &view) + { + GPU_framebuffer_bind(res.overlay_line_fb); + manager.submit(empty_ps_, view); + } + + void draw_in_front(Resources &res, Manager &manager, View &view) + { + GPU_framebuffer_bind(res.overlay_line_in_front_fb); + manager.submit(empty_in_front_ps_, view); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_grid.hh b/source/blender/draw/engines/overlay/overlay_grid.hh index 02de6f46e5e..25db8193b4d 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.hh +++ b/source/blender/draw/engines/overlay/overlay_grid.hh @@ -42,8 +42,8 @@ class Grid { /* Default, nothing is drawn. */ grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0); - View3D *v3d = state.v3d; - RegionView3D *rv3d = state.rv3d; + const View3D *v3d = state.v3d; + const RegionView3D *rv3d = state.rv3d; const bool show_axis_x = (state.v3d_gridflag & V3D_SHOW_X) != 0; const bool show_axis_y = (state.v3d_gridflag & V3D_SHOW_Y) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 417fcd45d4a..0726ea2b74a 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -4,9 +4,10 @@ * \ingroup overlay */ -#include "overlay_instance.hh" #include "draw_debug.hh" +#include "overlay_instance.hh" + namespace blender::draw::overlay { void Instance::init() @@ -18,12 +19,16 @@ void Instance::init() /* TODO(fclem): Remove DRW global usage. */ const DRWContextState *ctx = DRW_context_state_get(); + /* Was needed by `object_wire_theme_id()` when doing the port. Not sure if needed nowadays. */ + BKE_view_layer_synced_ensure(ctx->scene, ctx->view_layer); state.depsgraph = ctx->depsgraph; state.view_layer = ctx->view_layer; state.scene = ctx->scene; state.v3d = ctx->v3d; state.rv3d = ctx->rv3d; + state.active_base = BKE_view_layer_active_base_get(ctx->view_layer); + state.object_mode = ctx->object_mode; state.pixelsize = U.pixelsize; state.ctx_mode = CTX_data_mode_enum_ex(ctx->object_edit, ctx->obact, ctx->object_mode); @@ -66,6 +71,7 @@ void Instance::begin_sync() View view("OverlayView", view_legacy); background.begin_sync(resources, state); + empties.begin_sync(); metaballs.begin_sync(); grid.begin_sync(resources, state, view); } @@ -98,6 +104,9 @@ void Instance::object_sync(ObjectRef &ob_ref) if (!state.hide_overlays) { switch (ob_ref.object->type) { + case OB_EMPTY: + empties.object_sync(ob_ref, resources, state); + break; case OB_ARMATURE: break; case OB_MBALL: @@ -114,6 +123,7 @@ void Instance::object_sync(ObjectRef &ob_ref) void Instance::end_sync() { metaballs.end_sync(resources, state); + empties.end_sync(resources, shapes, state); } void Instance::draw(Manager &manager) @@ -158,10 +168,12 @@ void Instance::draw(Manager &manager) background.draw(resources, manager); + empties.draw(resources, manager, view); metaballs.draw(resources, manager, view); grid.draw(resources, manager, view); + empties.draw_in_front(resources, manager, view); metaballs.draw_in_front(resources, manager, view); // anti_aliasing.draw(resources, manager, view); diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index 1fb199e4e6e..c90494f6c75 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -9,8 +9,10 @@ #include "draw_manager.hh" #include "overlay_background.hh" +#include "overlay_empty.hh" #include "overlay_grid.hh" #include "overlay_metaball.hh" +#include "overlay_shape.hh" namespace blender::draw::overlay { @@ -49,6 +51,7 @@ class SceneResources { class Instance { public: ShaderCache shaders; + ShapeCache shapes; /* WORKAROUND: Legacy. Move to grid pass. */ GPUUniformBuf *grid_ubo = nullptr; @@ -60,6 +63,7 @@ class Instance { /** Overlay types. */ Background background; Metaballs metaballs; + Empties empties; Grid grid; ~Instance() diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index 6bd9811054e..df7bab02a70 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -86,10 +86,7 @@ class Metaballs { data_buf_; MetaBall *mb = static_cast(ob_ref.object->data); - float *color; - /* TODO(fclem): Remove DRW global usage. */ - UNUSED_VARS(res); - DRW_object_wire_theme_get(ob_ref.object, state.view_layer, &color); + const float4 &color = res.object_wire_color(ob_ref, state); LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { /* Draw radius only. */ diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index bd7ea90a90a..c015ee8abf5 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -7,9 +7,15 @@ #pragma once +#include "BKE_global.h" + #include "DRW_gpu_wrapper.hh" #include "DRW_render.h" +#include "UI_resources.h" + +#include "draw_handle.hh" + #include "overlay_shader_shared.h" #ifdef __cplusplus @@ -33,13 +39,15 @@ class Instance; struct State { Depsgraph *depsgraph; - ViewLayer *view_layer; - Scene *scene; - View3D *v3d; - RegionView3D *rv3d; + const ViewLayer *view_layer; + const Scene *scene; + const View3D *v3d; + const RegionView3D *rv3d; + const Base *active_base; View3DOverlay overlay; float pixelsize; enum eContextObjectMode ctx_mode; + enum eObjectMode object_mode; bool clear_in_front; bool use_in_front; bool is_wireframe_mode; @@ -79,6 +87,80 @@ struct Resources { TextureRef depth_in_front_tx; TextureRef color_overlay_tx; TextureRef color_render_tx; + + [[nodiscard]] ThemeColorID object_wire_theme_id(const ObjectRef &ob_ref, + const State &state) const + { + const bool is_edit = (state.object_mode & OB_MODE_EDIT) && + (ob_ref.object->mode & OB_MODE_EDIT); + const bool active = (state.active_base != nullptr) && + ((ob_ref.dupli_parent != nullptr) ? + (state.active_base->object == ob_ref.dupli_parent) : + (state.active_base->object == ob_ref.object)); + const bool is_selected = ((ob_ref.object->base_flag & BASE_SELECTED) != 0); + + /* Object in edit mode. */ + if (is_edit) { + return TH_WIRE_EDIT; + } + /* Transformed object during operators. */ + if (((G.moving & G_TRANSFORM_OBJ) != 0) && is_selected) { + return TH_TRANSFORM; + } + /* Sets the 'theme_id' or fallback to wire */ + if ((ob_ref.object->base_flag & BASE_SELECTED) != 0) { + return (active) ? TH_ACTIVE : TH_SELECT; + } + + switch (ob_ref.object->type) { + case OB_LAMP: + return TH_LIGHT; + case OB_SPEAKER: + return TH_SPEAKER; + case OB_CAMERA: + return TH_CAMERA; + case OB_LIGHTPROBE: + /* TODO: add light-probe color. Use empty color for now. */ + case OB_EMPTY: + return TH_EMPTY; + default: + return (is_edit) ? TH_WIRE_EDIT : TH_WIRE; + } + } + + [[nodiscard]] const float4 &object_wire_color(const ObjectRef &ob_ref, + ThemeColorID theme_id) const + { + if (UNLIKELY(ob_ref.object->base_flag & BASE_FROM_SET)) { + return theme_settings.color_wire; + } + switch (theme_id) { + case TH_WIRE_EDIT: + return theme_settings.color_wire_edit; + case TH_ACTIVE: + return theme_settings.color_active; + case TH_SELECT: + return theme_settings.color_select; + case TH_TRANSFORM: + return theme_settings.color_transform; + case TH_SPEAKER: + return theme_settings.color_speaker; + case TH_CAMERA: + return theme_settings.color_camera; + case TH_EMPTY: + return theme_settings.color_empty; + case TH_LIGHT: + return theme_settings.color_light; + default: + return theme_settings.color_wire; + } + } + + [[nodiscard]] const float4 &object_wire_color(const ObjectRef &ob_ref, const State &state) const + { + ThemeColorID theme_id = object_wire_theme_id(ob_ref, state); + return object_wire_color(ob_ref, theme_id); + } }; } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index 5bbed01d2e6..917c3636a4f 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -490,6 +490,18 @@ GPUShader *OVERLAY_shader_extra(bool is_select) OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra; if (!*sh) { + using namespace blender::gpu::shader; + ShaderCreateInfo &info = const_cast( + *reinterpret_cast(GPU_shader_create_info_get("overlay_extra"))); + + if (U.experimental.enable_overlay_next) { + info.storage_buf(0, Qualifier::READ, "ExtraInstanceData", "data_buf[]"); + info.define("color", "data_buf[gl_InstanceID].color_"); + info.define("inst_obmat", "data_buf[gl_InstanceID].object_to_world_"); + info.vertex_inputs_.pop_last(); + info.vertex_inputs_.pop_last(); + } + *sh = GPU_shader_create_from_info_name( (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? (is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") : diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h index 0b44b6ca356..5f00bec79c8 100644 --- a/source/blender/draw/engines/overlay/overlay_shader_shared.h +++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h @@ -15,6 +15,7 @@ typedef enum OVERLAY_GridBits OVERLAY_GridBits; # endif typedef struct OVERLAY_GridData OVERLAY_GridData; typedef struct ThemeColorData ThemeColorData; +typedef struct ExtraInstanceData ExtraInstanceData; #endif /* TODO(fclem): Should eventually become OVERLAY_BackgroundType. @@ -191,6 +192,22 @@ struct ThemeColorData { }; BLI_STATIC_ASSERT_ALIGN(ThemeColorData, 16) +/* TODO Move to overlay engine. */ +struct ExtraInstanceData { + float4 color_; + float4x4 object_to_world_; + +#if !defined(GPU_SHADER) && defined(__cplusplus) + ExtraInstanceData(const float4x4 &object_to_world, float4 &color, float draw_size) + { + this->color_ = color; + this->object_to_world_ = object_to_world; + this->object_to_world_[3][3] = draw_size; + }; +#endif +}; +BLI_STATIC_ASSERT_ALIGN(ExtraInstanceData, 16) + #ifndef GPU_SHADER # ifdef __cplusplus } diff --git a/source/blender/draw/engines/overlay/overlay_shape.hh b/source/blender/draw/engines/overlay/overlay_shape.hh new file mode 100644 index 00000000000..eb23d3e71a2 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_shape.hh @@ -0,0 +1,330 @@ + +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "BLI_vector.hh" +#include "GPU_batch.h" + +namespace blender::draw::overlay { + +/** + * Contains all overlay generic geometry batches. + */ +class ShapeCache { + private: + /* Needs to be first for other lambdas to access. */ + GPUVertFormat format = []() { + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "vclass", GPU_COMP_I32, 1, GPU_FETCH_INT); + return format; + }(); + + /* Matches Vertex Format. */ + struct Vertex { + float3 pos; + int vclass; + }; + + struct AutoFreeGPUBatch { + GPUBatch *batch; + + AutoFreeGPUBatch(GPUBatch *_batch) : batch(_batch){}; + + ~AutoFreeGPUBatch() + { + GPU_BATCH_DISCARD_SAFE(batch); + } + + operator GPUBatch *() + { + return batch; + } + }; + + /* Caller gets ownership of the #GPUVertBuf. */ + GPUVertBuf *vbo_from_vector(Vector &vector) + { + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, vector.size()); + Vertex *vbo_data = (Vertex *)GPU_vertbuf_get_data(vbo); + /* Copy data to VBO using a wrapper span. Could use memcpy if that's too slow. */ + MutableSpan span(vbo_data, vector.size()); + span.copy_from(vector); + return vbo; + } + + enum VertexClass { + VCLASS_LIGHT_AREA_SHAPE = 1 << 0, + VCLASS_LIGHT_SPOT_SHAPE = 1 << 1, + VCLASS_LIGHT_SPOT_BLEND = 1 << 2, + VCLASS_LIGHT_SPOT_CONE = 1 << 3, + VCLASS_LIGHT_DIST = 1 << 4, + + VCLASS_CAMERA_FRAME = 1 << 5, + VCLASS_CAMERA_DIST = 1 << 6, + VCLASS_CAMERA_VOLUME = 1 << 7, + + VCLASS_SCREENSPACE = 1 << 8, + VCLASS_SCREENALIGNED = 1 << 9, + + VCLASS_EMPTY_SCALED = 1 << 10, + VCLASS_EMPTY_AXES = 1 << 11, + VCLASS_EMPTY_AXES_NAME = 1 << 12, + VCLASS_EMPTY_AXES_SHADOW = 1 << 13, + VCLASS_EMPTY_SIZE = 1 << 14, + }; + + static constexpr float bone_box_verts[8][3] = { + {1.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, -1.0f}, + {-1.0f, 0.0f, -1.0f}, + {-1.0f, 0.0f, 1.0f}, + {1.0f, 1.0f, 1.0f}, + {1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, 1.0f}, + }; + + static constexpr std::array bone_box_wire = { + 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, + }; + + /* A single ring of vertices. */ + static Vector ring_vertices(const float radius, const int segments) + { + Vector verts; + for (int i : IndexRange(segments)) { + float angle = (2 * M_PI * i) / segments; + verts.append(radius * float2(math::cos(angle), math::sin(angle))); + } + return verts; + } + + /* Returns lines segment geometry forming 3 circles, one on each axis. */ + static Vector sphere_axes_circles(const float radius, + const VertexClass vclass, + const int segments) + { + Vector ring = ring_vertices(radius, segments); + + Vector verts; + for (int axis : IndexRange(3)) { + for (int i : IndexRange(segments)) { + for (int j : IndexRange(2)) { + float2 cv = ring[(i + j) % segments]; + if (axis == 0) { + verts.append({{cv[0], cv[1], 0.0f}, vclass}); + } + else if (axis == 1) { + verts.append({{cv[0], 0.0f, cv[1]}, vclass}); + } + else { + verts.append({{0.0f, cv[0], cv[1]}, vclass}); + } + } + } + } + return verts; + } + + public: + AutoFreeGPUBatch quad_wire = [this]() { + Vector verts; + verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + + verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + + verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + + verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch plain_axes = [this]() { + Vector verts; + verts.append({{0.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{-1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{+1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 0.0f, -1.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 0.0f, +1.0f}, VCLASS_EMPTY_SCALED}); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch single_arrow = [this]() { + Vector verts; + float p[3][3] = {{0}}; + p[0][2] = 1.0f; + p[1][0] = 0.035f; + p[1][1] = 0.035f; + p[2][0] = -0.035f; + p[2][1] = 0.035f; + p[1][2] = p[2][2] = 0.75f; + for (int sides : IndexRange(4)) { + if (sides % 2 == 1) { + p[1][0] = -p[1][0]; + p[2][1] = -p[2][1]; + } + else { + p[1][1] = -p[1][1]; + p[2][0] = -p[2][0]; + } + for (int i = 0, a = 1; i < 2; i++, a++) { + verts.append({{p[i][0], p[i][1], p[i][2]}, VCLASS_EMPTY_SCALED}); + verts.append({{p[a][0], p[a][1], p[a][2]}, VCLASS_EMPTY_SCALED}); + } + } + verts.append({{0.0f, 0.0f, 0.0}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 0.0f, 0.75f}, VCLASS_EMPTY_SCALED}); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch cube = [this]() { + Vector verts; + for (auto index : bone_box_wire) { + float x = bone_box_verts[index][0]; + float y = bone_box_verts[index][1] * 2.0 - 1.0f; + float z = bone_box_verts[index][2]; + verts.append({{x, y, z}, VCLASS_EMPTY_SCALED}); + } + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch circle = [this]() { + constexpr int resolution = 64; + Vector ring = ring_vertices(1.0f, resolution); + + Vector verts; + for (int a : IndexRange(resolution + 1)) { + float2 cv = ring[a % resolution]; + verts.append({{cv.x, 0.0f, cv.y}, VCLASS_EMPTY_SCALED}); + } + return GPU_batch_create_ex( + GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch empty_sphere = [this]() { + Vector verts = sphere_axes_circles(1.0f, VCLASS_EMPTY_SCALED, 32); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch empty_cone = [this]() { + /* A single ring of vertices. */ + constexpr int resolution = 8; + Vector ring = ring_vertices(1.0f, resolution); + + Vector verts; + for (int i : IndexRange(resolution)) { + float2 cv = ring[i % resolution]; + /* Cone sides. */ + verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 2.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + /* Base ring. */ + for (int j : IndexRange(2)) { + float2 cv = ring[(i + j) % resolution]; + verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED}); + } + } + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch arrows = [this]() { + float2 x_axis_name_scale = {0.0215f, 0.025f}; + Vector x_axis_name = { + float2(0.9f, 1.0f) * x_axis_name_scale, + float2(-1.0f, -1.0f) * x_axis_name_scale, + float2(-0.9f, 1.0f) * x_axis_name_scale, + float2(1.0f, -1.0f) * x_axis_name_scale, + }; + + float2 y_axis_name_scale = {0.0175f, 0.025f}; + Vector y_axis_name = { + float2(-1.0f, 1.0f) * y_axis_name_scale, + float2(0.0f, -0.1f) * y_axis_name_scale, + float2(1.0f, 1.0f) * y_axis_name_scale, + float2(0.0f, -0.1f) * y_axis_name_scale, + float2(0.0f, -0.1f) * y_axis_name_scale, + float2(0.0f, -1.0f) * y_axis_name_scale, + }; + + float2 z_axis_name_scale = {0.02f, 0.025f}; + Vector z_axis_name = { + float2(-0.95f, 1.00f) * z_axis_name_scale, + float2(0.95f, 1.00f) * z_axis_name_scale, + float2(0.95f, 1.00f) * z_axis_name_scale, + float2(0.95f, 0.90f) * z_axis_name_scale, + float2(0.95f, 0.90f) * z_axis_name_scale, + float2(-1.00f, -0.90f) * z_axis_name_scale, + float2(-1.00f, -0.90f) * z_axis_name_scale, + float2(-1.00f, -1.00f) * z_axis_name_scale, + float2(-1.00f, -1.00f) * z_axis_name_scale, + float2(1.00f, -1.00f) * z_axis_name_scale, + }; + + float2 axis_marker_scale = {0.007f, 0.007f}; + Vector axis_marker = { +#if 0 /* square */ + float2(-1.0f, 1.0f) * axis_marker_scale, + float2(1.0f, 1.0f) * axis_marker_scale, + float2(1.0f, 1.0f) * axis_marker_scale, + float2(1.0f, -1.0f) * axis_marker_scale, + float2(1.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, 1.0f) * axis_marker_scale, +#else /* diamond */ + float2(-1.0f, 0.0f) * axis_marker_scale, + float2(0.0f, 1.0f) * axis_marker_scale, + float2(0.0f, 1.0f) * axis_marker_scale, + float2(1.0f, 0.0f) * axis_marker_scale, + float2(1.0f, 0.0f) * axis_marker_scale, + float2(0.0f, -1.0f) * axis_marker_scale, + float2(0.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, 0.0f) * axis_marker_scale, +#endif + }; + + Vector verts; + for (int axis : IndexRange(3)) { + /* Vertex layout is XY screen position and axis in Z. + * Fractional part of Z is a positive offset at axis unit position. */ + int flag = VCLASS_EMPTY_AXES | VCLASS_SCREENALIGNED; + /* Center to axis line. */ + verts.append({{0.0f, 0.0f, 0.0f}, 0}); + verts.append({{0.0f, 0.0f, float(axis)}, flag}); + /* Axis end marker. */ + constexpr int marker_fill_layer = 6; + for (int j = 1; j < marker_fill_layer + 1; j++) { + for (float2 axis_marker_vert : axis_marker) { + verts.append({{axis_marker_vert * ((4.0f * j) / marker_fill_layer), float(axis)}, flag}); + } + } + /* Axis name. */ + Vector *axis_names[3] = {&x_axis_name, &y_axis_name, &z_axis_name}; + for (float2 axis_name_vert : *(axis_names[axis])) { + int flag = VCLASS_EMPTY_AXES | VCLASS_EMPTY_AXES_NAME | VCLASS_SCREENALIGNED; + verts.append({{axis_name_vert * 4.0f, axis + 0.25f}, flag}); + } + } + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); +}; + +} // namespace blender::draw::overlay \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh index 9e6b6e5f737..aff132cd414 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh @@ -13,6 +13,7 @@ GPU_SHADER_INTERFACE_INFO(overlay_extra_iface, "") GPU_SHADER_CREATE_INFO(overlay_extra) .do_static_compilation(true) + .typedef_source("overlay_shader_shared.h") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::INT, "vclass") /* Instance attributes. */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 57939bd1f46..5e4e3c2cfaf 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -1270,11 +1270,11 @@ bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d, */ float ED_scene_grid_scale(const struct Scene *scene, const char **r_grid_unit); float ED_view3d_grid_scale(const struct Scene *scene, - struct View3D *v3d, + const struct View3D *v3d, const char **r_grid_unit); void ED_view3d_grid_steps(const struct Scene *scene, - struct View3D *v3d, - struct RegionView3D *rv3d, + const struct View3D *v3d, + const struct RegionView3D *rv3d, float r_grid_steps[8]); /** * Simulates the grid scale that is actually viewed. diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index b0590fba294..7ab3be7f89d 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -850,15 +850,15 @@ float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit) return 1.0f; } -float ED_view3d_grid_scale(const Scene *scene, View3D *v3d, const char **r_grid_unit) +float ED_view3d_grid_scale(const Scene *scene, const View3D *v3d, const char **r_grid_unit) { return v3d->grid * ED_scene_grid_scale(scene, r_grid_unit); } #define STEPS_LEN 8 void ED_view3d_grid_steps(const Scene *scene, - View3D *v3d, - RegionView3D *rv3d, + const View3D *v3d, + const RegionView3D *rv3d, float r_grid_steps[STEPS_LEN]) { const void *usys;