Overlay-Next: Initial implementation #107045
|
@ -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<ExtraInstanceData>;
|
||||||
|
|
||||||
|
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
|
|
@ -42,8 +42,8 @@ class Grid {
|
||||||
/* Default, nothing is drawn. */
|
/* Default, nothing is drawn. */
|
||||||
grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0);
|
grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0);
|
||||||
|
|
||||||
View3D *v3d = state.v3d;
|
const View3D *v3d = state.v3d;
|
||||||
RegionView3D *rv3d = state.rv3d;
|
const RegionView3D *rv3d = state.rv3d;
|
||||||
|
|
||||||
const bool show_axis_x = (state.v3d_gridflag & V3D_SHOW_X) != 0;
|
const bool show_axis_x = (state.v3d_gridflag & V3D_SHOW_X) != 0;
|
||||||
const bool show_axis_y = (state.v3d_gridflag & V3D_SHOW_Y) != 0;
|
const bool show_axis_y = (state.v3d_gridflag & V3D_SHOW_Y) != 0;
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
* \ingroup overlay
|
* \ingroup overlay
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "overlay_instance.hh"
|
|
||||||
#include "draw_debug.hh"
|
#include "draw_debug.hh"
|
||||||
|
|
||||||
|
#include "overlay_instance.hh"
|
||||||
|
|
||||||
namespace blender::draw::overlay {
|
namespace blender::draw::overlay {
|
||||||
|
|
||||||
void Instance::init()
|
void Instance::init()
|
||||||
|
@ -18,12 +19,16 @@ void Instance::init()
|
||||||
|
|
||||||
/* TODO(fclem): Remove DRW global usage. */
|
/* TODO(fclem): Remove DRW global usage. */
|
||||||
const DRWContextState *ctx = DRW_context_state_get();
|
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.depsgraph = ctx->depsgraph;
|
||||||
state.view_layer = ctx->view_layer;
|
state.view_layer = ctx->view_layer;
|
||||||
state.scene = ctx->scene;
|
state.scene = ctx->scene;
|
||||||
state.v3d = ctx->v3d;
|
state.v3d = ctx->v3d;
|
||||||
state.rv3d = ctx->rv3d;
|
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.pixelsize = U.pixelsize;
|
||||||
state.ctx_mode = CTX_data_mode_enum_ex(ctx->object_edit, ctx->obact, ctx->object_mode);
|
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);
|
View view("OverlayView", view_legacy);
|
||||||
|
|
||||||
background.begin_sync(resources, state);
|
background.begin_sync(resources, state);
|
||||||
|
empties.begin_sync();
|
||||||
metaballs.begin_sync();
|
metaballs.begin_sync();
|
||||||
grid.begin_sync(resources, state, view);
|
grid.begin_sync(resources, state, view);
|
||||||
}
|
}
|
||||||
|
@ -98,6 +104,9 @@ void Instance::object_sync(ObjectRef &ob_ref)
|
||||||
|
|
||||||
if (!state.hide_overlays) {
|
if (!state.hide_overlays) {
|
||||||
switch (ob_ref.object->type) {
|
switch (ob_ref.object->type) {
|
||||||
|
case OB_EMPTY:
|
||||||
|
empties.object_sync(ob_ref, resources, state);
|
||||||
|
break;
|
||||||
case OB_ARMATURE:
|
case OB_ARMATURE:
|
||||||
break;
|
break;
|
||||||
case OB_MBALL:
|
case OB_MBALL:
|
||||||
|
@ -114,6 +123,7 @@ void Instance::object_sync(ObjectRef &ob_ref)
|
||||||
void Instance::end_sync()
|
void Instance::end_sync()
|
||||||
{
|
{
|
||||||
metaballs.end_sync(resources, state);
|
metaballs.end_sync(resources, state);
|
||||||
|
empties.end_sync(resources, shapes, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::draw(Manager &manager)
|
void Instance::draw(Manager &manager)
|
||||||
|
@ -158,10 +168,12 @@ void Instance::draw(Manager &manager)
|
||||||
|
|
||||||
background.draw(resources, manager);
|
background.draw(resources, manager);
|
||||||
|
|
||||||
|
empties.draw(resources, manager, view);
|
||||||
metaballs.draw(resources, manager, view);
|
metaballs.draw(resources, manager, view);
|
||||||
|
|
||||||
grid.draw(resources, manager, view);
|
grid.draw(resources, manager, view);
|
||||||
|
|
||||||
|
empties.draw_in_front(resources, manager, view);
|
||||||
metaballs.draw_in_front(resources, manager, view);
|
metaballs.draw_in_front(resources, manager, view);
|
||||||
|
|
||||||
// anti_aliasing.draw(resources, manager, view);
|
// anti_aliasing.draw(resources, manager, view);
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
#include "draw_manager.hh"
|
#include "draw_manager.hh"
|
||||||
|
|
||||||
#include "overlay_background.hh"
|
#include "overlay_background.hh"
|
||||||
|
#include "overlay_empty.hh"
|
||||||
#include "overlay_grid.hh"
|
#include "overlay_grid.hh"
|
||||||
#include "overlay_metaball.hh"
|
#include "overlay_metaball.hh"
|
||||||
|
#include "overlay_shape.hh"
|
||||||
|
|
||||||
namespace blender::draw::overlay {
|
namespace blender::draw::overlay {
|
||||||
|
|
||||||
|
@ -49,6 +51,7 @@ class SceneResources {
|
||||||
class Instance {
|
class Instance {
|
||||||
public:
|
public:
|
||||||
ShaderCache shaders;
|
ShaderCache shaders;
|
||||||
|
ShapeCache shapes;
|
||||||
|
|
||||||
/* WORKAROUND: Legacy. Move to grid pass. */
|
/* WORKAROUND: Legacy. Move to grid pass. */
|
||||||
GPUUniformBuf *grid_ubo = nullptr;
|
GPUUniformBuf *grid_ubo = nullptr;
|
||||||
|
@ -60,6 +63,7 @@ class Instance {
|
||||||
/** Overlay types. */
|
/** Overlay types. */
|
||||||
Background background;
|
Background background;
|
||||||
Metaballs metaballs;
|
Metaballs metaballs;
|
||||||
|
Empties empties;
|
||||||
Grid grid;
|
Grid grid;
|
||||||
|
|
||||||
~Instance()
|
~Instance()
|
||||||
|
|
|
@ -86,10 +86,7 @@ class Metaballs {
|
||||||
data_buf_;
|
data_buf_;
|
||||||
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
|
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
|
||||||
|
|
||||||
float *color;
|
const float4 &color = res.object_wire_color(ob_ref, state);
|
||||||
/* TODO(fclem): Remove DRW global usage. */
|
|
||||||
UNUSED_VARS(res);
|
|
||||||
DRW_object_wire_theme_get(ob_ref.object, state.view_layer, &color);
|
|
||||||
|
|
||||||
LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
|
LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
|
||||||
/* Draw radius only. */
|
/* Draw radius only. */
|
||||||
|
|
|
@ -7,9 +7,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "BKE_global.h"
|
||||||
|
|
||||||
#include "DRW_gpu_wrapper.hh"
|
#include "DRW_gpu_wrapper.hh"
|
||||||
#include "DRW_render.h"
|
#include "DRW_render.h"
|
||||||
|
|
||||||
|
#include "UI_resources.h"
|
||||||
|
|
||||||
|
#include "draw_handle.hh"
|
||||||
|
|
||||||
#include "overlay_shader_shared.h"
|
#include "overlay_shader_shared.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -33,13 +39,15 @@ class Instance;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
Depsgraph *depsgraph;
|
Depsgraph *depsgraph;
|
||||||
ViewLayer *view_layer;
|
const ViewLayer *view_layer;
|
||||||
Scene *scene;
|
const Scene *scene;
|
||||||
View3D *v3d;
|
const View3D *v3d;
|
||||||
RegionView3D *rv3d;
|
const RegionView3D *rv3d;
|
||||||
|
const Base *active_base;
|
||||||
View3DOverlay overlay;
|
View3DOverlay overlay;
|
||||||
float pixelsize;
|
float pixelsize;
|
||||||
enum eContextObjectMode ctx_mode;
|
enum eContextObjectMode ctx_mode;
|
||||||
|
enum eObjectMode object_mode;
|
||||||
bool clear_in_front;
|
bool clear_in_front;
|
||||||
bool use_in_front;
|
bool use_in_front;
|
||||||
bool is_wireframe_mode;
|
bool is_wireframe_mode;
|
||||||
|
@ -79,6 +87,80 @@ struct Resources {
|
||||||
TextureRef depth_in_front_tx;
|
TextureRef depth_in_front_tx;
|
||||||
TextureRef color_overlay_tx;
|
TextureRef color_overlay_tx;
|
||||||
TextureRef color_render_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
|
} // namespace blender::draw::overlay
|
||||||
|
|
|
@ -490,6 +490,18 @@ GPUShader *OVERLAY_shader_extra(bool is_select)
|
||||||
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
|
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
|
||||||
GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra;
|
GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra;
|
||||||
if (!*sh) {
|
if (!*sh) {
|
||||||
|
using namespace blender::gpu::shader;
|
||||||
|
ShaderCreateInfo &info = const_cast<ShaderCreateInfo &>(
|
||||||
|
*reinterpret_cast<const ShaderCreateInfo *>(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(
|
*sh = GPU_shader_create_from_info_name(
|
||||||
(draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ?
|
(draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ?
|
||||||
(is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") :
|
(is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") :
|
||||||
|
|
|
@ -15,6 +15,7 @@ typedef enum OVERLAY_GridBits OVERLAY_GridBits;
|
||||||
# endif
|
# endif
|
||||||
typedef struct OVERLAY_GridData OVERLAY_GridData;
|
typedef struct OVERLAY_GridData OVERLAY_GridData;
|
||||||
typedef struct ThemeColorData ThemeColorData;
|
typedef struct ThemeColorData ThemeColorData;
|
||||||
|
typedef struct ExtraInstanceData ExtraInstanceData;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* TODO(fclem): Should eventually become OVERLAY_BackgroundType.
|
/* TODO(fclem): Should eventually become OVERLAY_BackgroundType.
|
||||||
|
@ -191,6 +192,22 @@ struct ThemeColorData {
|
||||||
};
|
};
|
||||||
BLI_STATIC_ASSERT_ALIGN(ThemeColorData, 16)
|
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
|
#ifndef GPU_SHADER
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<Vertex> &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<Vertex> 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<uint, 24> 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<float2> ring_vertices(const float radius, const int segments)
|
||||||
|
{
|
||||||
|
Vector<float2> 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<Vertex> sphere_axes_circles(const float radius,
|
||||||
|
const VertexClass vclass,
|
||||||
|
const int segments)
|
||||||
|
{
|
||||||
|
Vector<float2> ring = ring_vertices(radius, segments);
|
||||||
|
|
||||||
|
Vector<Vertex> 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<Vertex> 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<Vertex> 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<Vertex> 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<Vertex> 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<float2> ring = ring_vertices(1.0f, resolution);
|
||||||
|
|
||||||
|
Vector<Vertex> 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<Vertex> 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<float2> ring = ring_vertices(1.0f, resolution);
|
||||||
|
|
||||||
|
Vector<Vertex> 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<float2> 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<float2> 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<float2> 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<float2> 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<Vertex> 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<float2> *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
|
|
@ -13,6 +13,7 @@ GPU_SHADER_INTERFACE_INFO(overlay_extra_iface, "")
|
||||||
|
|
||||||
GPU_SHADER_CREATE_INFO(overlay_extra)
|
GPU_SHADER_CREATE_INFO(overlay_extra)
|
||||||
.do_static_compilation(true)
|
.do_static_compilation(true)
|
||||||
|
.typedef_source("overlay_shader_shared.h")
|
||||||
.vertex_in(0, Type::VEC3, "pos")
|
.vertex_in(0, Type::VEC3, "pos")
|
||||||
.vertex_in(1, Type::INT, "vclass")
|
.vertex_in(1, Type::INT, "vclass")
|
||||||
/* Instance attributes. */
|
/* Instance attributes. */
|
||||||
|
|
|
@ -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_scene_grid_scale(const struct Scene *scene, const char **r_grid_unit);
|
||||||
float ED_view3d_grid_scale(const struct Scene *scene,
|
float ED_view3d_grid_scale(const struct Scene *scene,
|
||||||
struct View3D *v3d,
|
const struct View3D *v3d,
|
||||||
const char **r_grid_unit);
|
const char **r_grid_unit);
|
||||||
void ED_view3d_grid_steps(const struct Scene *scene,
|
void ED_view3d_grid_steps(const struct Scene *scene,
|
||||||
struct View3D *v3d,
|
const struct View3D *v3d,
|
||||||
struct RegionView3D *rv3d,
|
const struct RegionView3D *rv3d,
|
||||||
float r_grid_steps[8]);
|
float r_grid_steps[8]);
|
||||||
/**
|
/**
|
||||||
* Simulates the grid scale that is actually viewed.
|
* Simulates the grid scale that is actually viewed.
|
||||||
|
|
|
@ -850,15 +850,15 @@ float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
|
||||||
return 1.0f;
|
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);
|
return v3d->grid * ED_scene_grid_scale(scene, r_grid_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STEPS_LEN 8
|
#define STEPS_LEN 8
|
||||||
void ED_view3d_grid_steps(const Scene *scene,
|
void ED_view3d_grid_steps(const Scene *scene,
|
||||||
View3D *v3d,
|
const View3D *v3d,
|
||||||
RegionView3D *rv3d,
|
const RegionView3D *rv3d,
|
||||||
float r_grid_steps[STEPS_LEN])
|
float r_grid_steps[STEPS_LEN])
|
||||||
{
|
{
|
||||||
const void *usys;
|
const void *usys;
|
||||||
|
|
Loading…
Reference in New Issue