Compare commits

...

14 Commits

Author SHA1 Message Date
cdb9b6a041 Overlay-Next: Add support for empties
Also added a shape cache and move the color selection to `Resources`.
2023-02-10 20:22:38 +01:00
aff61bf5b4 Merge branch 'main' into overlay-next 2023-02-10 00:20:29 +01:00
968f5748c6 Merge branch 'main' into overlay-next
# Conflicts:
#	release/scripts/startup/bl_ui/space_userpref.py
#	source/blender/makesdna/DNA_userdef_types.h
#	source/blender/makesrna/intern/rna_userdef.c
2023-02-09 14:18:10 +01:00
2abc4d0538 Overlay-Next: Port Metaball overlay 2022-10-12 23:40:37 +02:00
c4ecfce6bb Overlay-Next: Port Background overlay 2022-10-12 19:53:51 +02:00
c3157ddc44 Merge branch 'master' into overlay-next 2022-10-12 17:46:23 +02:00
e116c67c3a DRW: Fix gl error related to incorrect uniform size 2022-10-12 17:36:11 +02:00
64d9660fc4 Overlay-Next: Make Grid parameters work 2022-10-12 17:35:52 +02:00
f0514484f5 DRW: Wrappers: Add TextureRef to wrap around GPUTexture pointers
This adds the possibility to use the C++ API for other GPUTexture.
2022-10-12 17:35:29 +02:00
cd93f790c7 Overlay: Add experimental option to enable overlay-next 2022-10-12 17:34:28 +02:00
482fee9bbe DRW: View: Expose matrices through interface 2022-10-12 17:33:33 +02:00
82e298227f Cleanup: EEVEE-Next: Add precision to comment 2022-10-12 17:32:20 +02:00
279774ad0b Overlay-Next: First commit 2022-10-11 17:22:17 +02:00
2538c3b1a2 Cleanup: DRW: Improve state_stencil documentation 2022-10-11 10:06:38 +02:00
21 changed files with 1616 additions and 20 deletions

View File

@@ -2345,6 +2345,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
({"property": "use_full_frame_compositor"}, ("blender/blender/issues/88150", "#88150")),
({"property": "enable_eevee_next"}, ("blender/blender/issues/93220", "#93220")),
({"property": "enable_workbench_next"}, ("blender/blender/issues/101619", "#101619")),
({"property": "enable_overlay_next"}, ("blender/blender/issues/102179", "#102179")),
),
)

View File

@@ -206,6 +206,7 @@ set(SRC
engines/overlay/overlay_gpencil.cc
engines/overlay/overlay_grid.cc
engines/overlay/overlay_image.cc
engines/overlay/overlay_instance.cc
engines/overlay/overlay_lattice.cc
engines/overlay/overlay_metaball.cc
engines/overlay/overlay_mode_transfer.cc
@@ -311,6 +312,7 @@ set(SRC
engines/select/select_engine.h
engines/select/select_private.h
engines/overlay/overlay_engine.h
engines/overlay/overlay_instance.hh
engines/overlay/overlay_private.hh
)

View File

@@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
#include "DNA_space_types.h"
#include "ED_view3d.h"
#include "UI_resources.h"
#include "draw_cache.h"
#include "draw_pass.hh"
#include "overlay_private.hh"
#include "overlay_shader_shared.h"
namespace blender::draw::overlay {
class Background {
private:
PassSimple bg_ps_ = {"Background"};
public:
void begin_sync(Resources &res, const State &state)
{
DRWState pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_BACKGROUND;
float4 color_override(0.0f, 0.0f, 0.0f, 0.0f);
int background_type;
if (DRW_state_is_opengl_render() && !DRW_state_draw_background()) {
background_type = BG_SOLID;
color_override[3] = 1.0f;
}
/*
else if (pd->space_type == SPACE_IMAGE) {
background_type = BG_SOLID_CHECKER;
}
else if (pd->space_type == SPACE_NODE) {
background_type = BG_MASK;
pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL;
}
*/
else if (!DRW_state_draw_background()) {
background_type = BG_CHECKER;
}
else if (state.v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD &&
state.scene->world) {
background_type = BG_SOLID;
/* TODO(fclem): this is a scene referred linear color. we should convert
* it to display linear here. */
color_override = float4(UNPACK3(&state.scene->world->horr), 1.0f);
}
else if (state.v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT &&
state.v3d->shading.type <= OB_SOLID) {
background_type = BG_SOLID;
color_override = float4(UNPACK3(state.v3d->shading.background_color), 1.0f);
}
else {
switch (UI_GetThemeValue(TH_BACKGROUND_TYPE)) {
case TH_BACKGROUND_GRADIENT_LINEAR:
background_type = BG_GRADIENT;
break;
case TH_BACKGROUND_GRADIENT_RADIAL:
background_type = BG_RADIAL;
break;
default:
case TH_BACKGROUND_SINGLE_COLOR:
background_type = BG_SOLID;
break;
}
}
bg_ps_.init();
bg_ps_.state_set(pass_state);
bg_ps_.shader_set(OVERLAY_shader_background());
bg_ps_.bind_ubo("globalsBlock", &res.globals_buf);
bg_ps_.bind_texture("colorBuffer", &res.color_render_tx);
bg_ps_.bind_texture("depthBuffer", &res.depth_tx);
bg_ps_.push_constant("colorOverride", color_override);
bg_ps_.push_constant("bgType", background_type);
bg_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
if (state.clipping_state != 0 && state.rv3d != nullptr && state.rv3d->clipbb != nullptr) {
bg_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK);
bg_ps_.shader_set(OVERLAY_shader_clipbound());
bg_ps_.push_constant("ucolor", res.theme_settings.color_clipping_border);
bg_ps_.push_constant("boundbox", &state.rv3d->clipbb->vec[0][0], 8);
bg_ps_.draw(DRW_cache_cube_get());
}
}
void draw(Resources &res, Manager &manager)
{
GPU_framebuffer_bind(res.overlay_color_only_fb);
manager.submit(bg_ps_);
}
};
} // namespace blender::draw::overlay

View File

@@ -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

View File

@@ -20,8 +20,13 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "GPU_capabilities.h"
#include "DNA_space_types.h"
#include "draw_manager.hh"
#include "overlay_instance.hh"
#include "overlay_engine.h"
#include "overlay_private.hh"
@@ -46,8 +51,7 @@ static void OVERLAY_engine_init(void *vedata)
/* Allocate instance. */
if (data->instance == nullptr) {
data->instance = static_cast<OVERLAY_Instance *>(
MEM_callocN(sizeof(*data->instance), __func__));
data->instance = new blender::draw::overlay::Instance();
}
OVERLAY_PrivateData *pd = stl->pd;
@@ -729,9 +733,70 @@ static void OVERLAY_engine_free()
static void OVERLAY_instance_free(void *instance_)
{
OVERLAY_Instance *instance = (OVERLAY_Instance *)instance_;
DRW_UBO_FREE_SAFE(instance->grid_ubo);
MEM_freeN(instance);
blender::draw::overlay::Instance *instance = (blender::draw::overlay::Instance *)instance_;
if (instance != nullptr) {
delete instance;
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Engine Instance
* \{ */
using namespace blender::draw;
static void OVERLAY_next_engine_init(void *vedata)
{
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
OVERLAY_Data *ved = reinterpret_cast<OVERLAY_Data *>(vedata);
if (ved->instance == nullptr) {
ved->instance = new overlay::Instance();
}
ved->instance->init();
}
static void OVERLAY_next_cache_init(void *vedata)
{
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->begin_sync();
}
static void OVERLAY_next_cache_populate(void *vedata, Object *object)
{
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
ObjectRef ref;
ref.object = object;
ref.dupli_object = DRW_object_get_dupli(object);
ref.dupli_parent = DRW_object_get_dupli_parent(object);
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->object_sync(ref);
}
static void OVERLAY_next_cache_finish(void *vedata)
{
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->end_sync();
}
static void OVERLAY_next_draw_scene(void *vedata)
{
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->draw(*DRW_manager_get());
}
/** \} */
@@ -760,6 +825,24 @@ DrawEngineType draw_engine_overlay_type = {
nullptr,
};
DrawEngineType draw_engine_overlay_next_type = {
nullptr,
nullptr,
N_("Overlay"),
&overlay_data_size,
&OVERLAY_next_engine_init,
nullptr,
&OVERLAY_instance_free,
&OVERLAY_next_cache_init,
&OVERLAY_next_cache_populate,
&OVERLAY_next_cache_finish,
&OVERLAY_next_draw_scene,
nullptr,
nullptr,
nullptr,
nullptr,
};
/** \} */
#undef SELECT_ENGINE

View File

@@ -12,6 +12,7 @@ extern "C" {
#endif
extern DrawEngineType draw_engine_overlay_type;
extern DrawEngineType draw_engine_overlay_next_type;
#ifdef __cplusplus
}

View File

@@ -17,6 +17,7 @@
#include "UI_resources.h"
#include "overlay_instance.hh"
#include "overlay_private.hh"
BLI_STATIC_ASSERT(SI_GRID_STEPS_LEN == OVERLAY_GRID_STEPS_LEN, "")

View File

@@ -0,0 +1,209 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
#include "DNA_space_types.h"
#include "ED_view3d.h"
#include "draw_cache.h"
#include "draw_pass.hh"
#include "overlay_private.hh"
#include "overlay_shader_shared.h"
namespace blender::draw::overlay {
class Grid {
private:
UniformBuffer<OVERLAY_GridData> data_;
PassSimple grid_ps_ = {"grid_ps_"};
float3 grid_axes_ = float3(0.0f);
float3 zplane_axes_ = float3(0.0f);
OVERLAY_GridBits grid_flag_ = OVERLAY_GridBits(0);
OVERLAY_GridBits zneg_flag_ = OVERLAY_GridBits(0);
OVERLAY_GridBits zpos_flag_ = OVERLAY_GridBits(0);
bool enabled_ = false;
public:
void update_ubo(const State &state, const View &view)
{
float grid_steps[SI_GRID_STEPS_LEN] = {
0.001f, 0.01f, 0.1f, 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f};
float grid_steps_y[SI_GRID_STEPS_LEN] = {0.0f}; /* When zero, use value from grid_steps. */
data_.line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f;
/* Default, nothing is drawn. */
grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0);
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;
const bool show_axis_z = (state.v3d_gridflag & V3D_SHOW_Z) != 0;
const bool show_floor = (state.v3d_gridflag & V3D_SHOW_FLOOR) != 0;
const bool show_ortho_grid = (state.v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0;
const bool show_any = show_axis_x || show_axis_y || show_axis_z || show_floor ||
show_ortho_grid;
enabled_ = !state.hide_overlays && show_any;
if (!enabled_) {
return;
}
/* If perspective view or non-axis aligned view. */
if (view.is_persp() || rv3d->view == RV3D_VIEW_USER) {
if (show_axis_x) {
grid_flag_ |= PLANE_XY | SHOW_AXIS_X;
}
if (show_axis_y) {
grid_flag_ |= PLANE_XY | SHOW_AXIS_Y;
}
if (show_floor) {
grid_flag_ |= PLANE_XY | SHOW_GRID;
}
}
else {
if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
grid_flag_ = PLANE_YZ | SHOW_AXIS_Y | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
}
else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
grid_flag_ = PLANE_XY | SHOW_AXIS_X | SHOW_AXIS_Y | SHOW_GRID | GRID_BACK;
}
else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
grid_flag_ = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
}
}
grid_axes_[0] = float((grid_flag_ & (PLANE_XZ | PLANE_XY)) != 0);
grid_axes_[1] = float((grid_flag_ & (PLANE_YZ | PLANE_XY)) != 0);
grid_axes_[2] = float((grid_flag_ & (PLANE_YZ | PLANE_XZ)) != 0);
/* Z axis if needed */
if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
zpos_flag_ = SHOW_AXIS_Z;
float3 zvec = -float3(view.viewinv()[2]);
float3 campos = float3(view.viewinv()[3]);
/* z axis : chose the most facing plane */
if (fabsf(zvec[0]) < fabsf(zvec[1])) {
zpos_flag_ |= PLANE_XZ;
}
else {
zpos_flag_ |= PLANE_YZ;
}
zneg_flag_ = zpos_flag_;
/* Perspective: If camera is below floor plane, we switch clipping.
* Orthographic: If eye vector is looking up, we switch clipping. */
if ((view.is_persp() && (campos[2] > 0.0f)) || (!view.is_persp() && (zvec[2] < 0.0f))) {
zpos_flag_ |= CLIP_ZPOS;
zneg_flag_ |= CLIP_ZNEG;
}
else {
zpos_flag_ |= CLIP_ZNEG;
zneg_flag_ |= CLIP_ZPOS;
}
zplane_axes_[0] = float((zpos_flag_ & (PLANE_XZ | PLANE_XY)) != 0);
zplane_axes_[1] = float((zpos_flag_ & (PLANE_YZ | PLANE_XY)) != 0);
zplane_axes_[2] = float((zpos_flag_ & (PLANE_YZ | PLANE_XZ)) != 0);
}
else {
zneg_flag_ = zpos_flag_ = CLIP_ZNEG | CLIP_ZPOS;
}
float dist;
if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) {
Object *camera_object = DEG_get_evaluated_object(state.depsgraph, v3d->camera);
dist = ((Camera *)(camera_object->data))->clip_end;
grid_flag_ |= GRID_CAMERA;
zneg_flag_ |= GRID_CAMERA;
zpos_flag_ |= GRID_CAMERA;
}
else {
dist = v3d->clip_end;
}
if (view.is_persp()) {
data_.size = float4(dist);
}
else {
float viewdist = 1.0f / min_ff(fabsf(view.winmat()[0][0]), fabsf(view.winmat()[1][1]));
data_.size = float4(viewdist * dist);
}
data_.distance = dist / 2.0f;
ED_view3d_grid_steps(state.scene, v3d, rv3d, grid_steps);
if ((v3d->flag & (V3D_XR_SESSION_SURFACE | V3D_XR_SESSION_MIRROR)) != 0) {
/* The calculations for the grid parameters assume that the view matrix has no scale
* component, which may not be correct if the user is "shrunk" or "enlarged" by zooming in or
* out. Therefore, we need to compensate the values here. */
/* Assumption is uniform scaling (all column vectors are of same length). */
float viewinvscale = len_v3(view.viewinv()[0]);
data_.distance *= viewinvscale;
}
/* Convert to UBO alignment. */
for (int i = 0; i < SI_GRID_STEPS_LEN; i++) {
data_.steps[i][0] = grid_steps[i];
data_.steps[i][1] = (grid_steps_y[i] != 0.0f) ? grid_steps_y[i] : grid_steps[i];
}
data_.push_update();
}
void begin_sync(Resources &res, const State &state, const View &view)
{
this->update_ubo(state, view);
if (!enabled_) {
return;
}
grid_ps_.init();
grid_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
grid_ps_.shader_set(OVERLAY_shader_grid());
grid_ps_.bind_ubo("grid_buf", &data_);
grid_ps_.bind_ubo("globalsBlock", &res.globals_buf);
grid_ps_.bind_texture("depth_tx", &res.depth_tx);
if (zneg_flag_ & SHOW_AXIS_Z) {
grid_ps_.push_constant("grid_flag", zneg_flag_);
grid_ps_.push_constant("plane_axes", zplane_axes_);
grid_ps_.draw(DRW_cache_grid_get());
}
if (grid_flag_) {
grid_ps_.push_constant("grid_flag", grid_flag_);
grid_ps_.push_constant("plane_axes", grid_axes_);
grid_ps_.draw(DRW_cache_grid_get());
}
if (zpos_flag_ & SHOW_AXIS_Z) {
grid_ps_.push_constant("grid_flag", zpos_flag_);
grid_ps_.push_constant("plane_axes", zplane_axes_);
grid_ps_.draw(DRW_cache_grid_get());
}
}
void draw(Resources &res, Manager &manager, View &view)
{
if (!enabled_) {
return;
}
GPU_framebuffer_bind(res.overlay_color_only_fb);
manager.submit(grid_ps_, view);
}
};
} // namespace blender::draw::overlay

View File

@@ -0,0 +1,185 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#include "draw_debug.hh"
#include "overlay_instance.hh"
namespace blender::draw::overlay {
void Instance::init()
{
resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth);
resources.depth_in_front_tx.wrap(DRW_viewport_texture_list_get()->depth_in_front);
resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay);
resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color);
/* 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);
state.clear_in_front = (state.v3d->shading.type != OB_SOLID);
state.use_in_front = (state.v3d->shading.type <= OB_SOLID) ||
BKE_scene_uses_blender_workbench(state.scene);
state.is_wireframe_mode = (state.v3d->shading.type == OB_WIRE);
state.hide_overlays = (state.v3d->flag2 & V3D_HIDE_OVERLAYS) != 0;
state.xray_enabled = XRAY_ACTIVE(state.v3d);
state.xray_enabled_and_not_wire = state.xray_enabled && (state.v3d->shading.type > OB_WIRE);
state.xray_opacity = XRAY_ALPHA(state.v3d);
state.cfra = DEG_get_ctime(state.depsgraph);
state.clipping_state = RV3D_CLIPPING_ENABLED(state.v3d, state.rv3d) ? DRW_STATE_CLIP_PLANES :
DRWState(0);
if (!state.hide_overlays) {
state.overlay = state.v3d->overlay;
state.v3d_flag = state.v3d->flag;
state.v3d_gridflag = state.v3d->gridflag;
}
else {
memset(&state.overlay, 0, sizeof(state.overlay));
state.v3d_flag = 0;
state.v3d_gridflag = 0;
state.overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS |
V3D_OVERLAY_HIDE_BONES | V3D_OVERLAY_HIDE_OBJECT_XTRAS |
V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
state.overlay.wireframe_threshold = state.v3d->overlay.wireframe_threshold;
state.overlay.wireframe_opacity = state.v3d->overlay.wireframe_opacity;
}
/* TODO(fclem): Remove DRW global usage. */
resources.globals_buf = G_draw.block_ubo;
resources.theme_settings = G_draw.block;
}
void Instance::begin_sync()
{
const DRWView *view_legacy = DRW_view_default_get();
View view("OverlayView", view_legacy);
background.begin_sync(resources, state);
empties.begin_sync();
metaballs.begin_sync();
grid.begin_sync(resources, state, view);
}
void Instance::object_sync(ObjectRef &ob_ref)
{
const bool in_edit_mode = object_is_edit_mode(ob_ref.object);
if (in_edit_mode && !state.hide_overlays) {
switch (ob_ref.object->type) {
case OB_MESH:
break;
case OB_ARMATURE:
break;
case OB_CURVES_LEGACY:
break;
case OB_SURF:
break;
case OB_LATTICE:
break;
case OB_MBALL:
metaballs.edit_object_sync(ob_ref, resources);
break;
case OB_FONT:
break;
case OB_CURVES:
break;
}
}
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:
if (!in_edit_mode) {
metaballs.object_sync(ob_ref, resources, state);
}
break;
case OB_GPENCIL:
break;
}
}
}
void Instance::end_sync()
{
metaballs.end_sync(resources, state);
empties.end_sync(resources, shapes, state);
}
void Instance::draw(Manager &manager)
{
/* WORKAROUND: This is to prevent crashes when using depth picking or selection.
* The selection engine should handle theses cases instead. */
if (!DRW_state_is_fbo()) {
return;
}
int2 render_size = int2(resources.depth_tx.size());
const DRWView *view_legacy = DRW_view_default_get();
View view("OverlayView", view_legacy);
resources.line_tx.acquire(render_size, GPU_RGBA8);
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx),
GPU_ATTACHMENT_TEXTURE(resources.line_tx));
resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
/* TODO(fclem): Remove mandatory allocation. */
if (!resources.depth_in_front_tx.is_valid()) {
resources.depth_in_front_alloc_tx.acquire(render_size, GPU_DEPTH_COMPONENT24);
resources.depth_in_front_tx.wrap(resources.depth_in_front_alloc_tx);
}
resources.overlay_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_in_front_tx),
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
resources.overlay_line_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_in_front_tx),
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx),
GPU_ATTACHMENT_TEXTURE(resources.line_tx));
GPU_framebuffer_bind(resources.overlay_color_only_fb);
float4 clear_color(0.0f);
GPU_framebuffer_clear_color(resources.overlay_color_only_fb, clear_color);
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);
resources.line_tx.release();
resources.depth_in_front_alloc_tx.release();
}
} // namespace blender::draw::overlay

View File

@@ -0,0 +1,112 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#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 {
class ShaderCache {
Map<StringRefNull, std::array<GPUShader *, 2>> cache;
int clipping_enabled = 0;
};
class SceneResources {
ShaderCache shaders;
// UniformBuffer<ThemeColorData> theme_colors;
// Texture color_ramp = {"color_ramp"};
void weight_ramp_init()
{
/* Weight Painting color ramp texture */
// bool user_weight_ramp = (U.flag & USER_CUSTOM_RANGE) != 0;
// if (weight_ramp_custom != user_weight_ramp ||
// (user_weight_ramp && memcmp(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)) != 0))
// {
// DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp);
// }
// if (G_draw.weight_ramp == NULL) {
// weight_ramp_custom = user_weight_ramp;
// memcpy(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand));
// G_draw.weight_ramp = DRW_create_weight_colorramp_texture();
// }
}
};
class Instance {
public:
ShaderCache shaders;
ShapeCache shapes;
/* WORKAROUND: Legacy. Move to grid pass. */
GPUUniformBuf *grid_ubo = nullptr;
/** Global types. */
Resources resources;
State state;
/** Overlay types. */
Background background;
Metaballs metaballs;
Empties empties;
Grid grid;
~Instance()
{
DRW_UBO_FREE_SAFE(grid_ubo);
}
void init();
void begin_sync();
void object_sync(ObjectRef &ob_ref);
void end_sync();
void draw(Manager &manager);
private:
bool object_is_edit_mode(const Object *ob)
{
if (DRW_object_is_in_edit_mode(ob)) {
/* Also check for context mode as the object mode is not 100% reliable. (see T72490) */
switch (ob->type) {
case OB_MESH:
return state.ctx_mode == CTX_MODE_EDIT_MESH;
case OB_ARMATURE:
return state.ctx_mode == CTX_MODE_EDIT_ARMATURE;
case OB_CURVES_LEGACY:
return state.ctx_mode == CTX_MODE_EDIT_CURVE;
case OB_SURF:
return state.ctx_mode == CTX_MODE_EDIT_SURFACE;
case OB_LATTICE:
return state.ctx_mode == CTX_MODE_EDIT_LATTICE;
case OB_MBALL:
return state.ctx_mode == CTX_MODE_EDIT_METABALL;
case OB_FONT:
return state.ctx_mode == CTX_MODE_EDIT_TEXT;
case OB_CURVES:
return state.ctx_mode == CTX_MODE_EDIT_CURVES;
case OB_POINTCLOUD:
case OB_VOLUME:
/* No edit mode yet. */
return false;
}
}
return false;
}
};
} // namespace blender::draw::overlay

View File

@@ -0,0 +1,129 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
#include "DNA_space_types.h"
#include "ED_view3d.h"
#include "UI_resources.h"
#include "draw_cache.h"
#include "draw_pass.hh"
#include "overlay_private.hh"
#include "overlay_shader_shared.h"
namespace blender::draw::overlay {
class Metaballs {
private:
PassSimple metaball_ps_ = {"MetaBalls"};
PassSimple metaball_in_front_ps_ = {"MetaBalls_In_front"};
ArmatureSphereBuf data_buf_ = {"metaball_data_buf"};
ArmatureSphereBuf data_in_front_buf_ = {"metaball_data_buf"};
public:
void begin_sync()
{
data_buf_.clear();
data_in_front_buf_.clear();
}
void metaball_instance_data_set(BoneInstanceData *data,
Object *ob,
const float *pos,
const float radius,
const float color[4])
{
/* Bone point radius is 0.05. Compensate for that. */
mul_v3_v3fl(data->mat[0], ob->object_to_world[0], radius / 0.05f);
mul_v3_v3fl(data->mat[1], ob->object_to_world[1], radius / 0.05f);
mul_v3_v3fl(data->mat[2], ob->object_to_world[2], radius / 0.05f);
mul_v3_m4v3(data->mat[3], ob->object_to_world, pos);
/* WATCH: Reminder, alpha is wire-size. */
OVERLAY_bone_instance_data_set_color(data, color);
}
void edit_object_sync(const ObjectRef &ob_ref, const Resources &res)
{
ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
data_in_front_buf_ :
data_buf_;
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
const float *color;
const float *col_radius = res.theme_settings.color_mball_radius;
const float *col_radius_select = res.theme_settings.color_mball_radius_select;
const float *col_stiffness = res.theme_settings.color_mball_stiffness;
const float *col_stiffness_select = res.theme_settings.color_mball_stiffness_select;
LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
const bool is_selected = (ml->flag & SELECT) != 0;
const bool is_scale_radius = (ml->flag & MB_SCALE_RAD) != 0;
float stiffness_radius = ml->rad * atanf(ml->s) / float(M_PI_2);
BoneInstanceData instdata;
color = (is_selected && is_scale_radius) ? col_radius_select : col_radius;
metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, ml->rad, color);
data_buf.append(*reinterpret_cast<float4x4 *>(&instdata));
color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness;
metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, stiffness_radius, color);
data_buf.append(*reinterpret_cast<float4x4 *>(&instdata));
}
}
void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state)
{
ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
data_in_front_buf_ :
data_buf_;
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
const float4 &color = res.object_wire_color(ob_ref, state);
LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
/* Draw radius only. */
BoneInstanceData instdata;
metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, ml->rad, color);
data_buf.append(*reinterpret_cast<float4x4 *>(&instdata));
}
}
void end_sync(Resources &res, const State &state)
{
auto init_pass = [&](PassSimple &pass, ArmatureSphereBuf &data_buf) {
data_buf.push_update();
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_armature_sphere(true));
pass.bind_ubo("globalsBlock", &res.globals_buf);
pass.bind_ssbo("data_buf", &data_buf);
pass.draw(DRW_cache_bone_point_wire_outline_get(), data_buf.size());
};
init_pass(metaball_ps_, data_buf_);
init_pass(metaball_in_front_ps_, data_in_front_buf_);
}
void draw(Resources &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_fb);
manager.submit(metaball_ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(metaball_in_front_ps_, view);
}
};
} // namespace blender::draw::overlay

View File

@@ -7,8 +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
@@ -27,6 +34,137 @@ extern "C" {
/* Forward declarations */
struct ImBuf;
namespace blender::draw::overlay {
class Instance;
struct State {
Depsgraph *depsgraph;
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;
bool hide_overlays;
bool xray_enabled;
bool xray_enabled_and_not_wire;
float xray_opacity;
short v3d_flag; /* TODO: move to #View3DOverlay. */
short v3d_gridflag; /* TODO: move to #View3DOverlay. */
int cfra;
DRWState clipping_state;
};
using blender::draw::Framebuffer;
using blender::draw::StorageVectorBuffer;
using blender::draw::Texture;
using blender::draw::TextureFromPool;
using blender::draw::TextureRef;
using ArmatureSphereBuf = StorageVectorBuffer<float4x4>;
struct Resources {
Framebuffer overlay_fb = {"overlay_fb"};
Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"};
Framebuffer overlay_color_only_fb = {"overlay_color_only_fb"};
Framebuffer overlay_line_fb = {"overlay_line_fb"};
Framebuffer overlay_line_in_front_fb = {"overlay_line_in_front_fb"};
TextureFromPool line_tx = {"line_tx"};
TextureFromPool depth_in_front_alloc_tx = {"overlay_depth_in_front_tx"};
/** TODO(fclem): Copy of G_data.block that should become theme colors only and managed by the
* engine. */
GlobalsUboStorage theme_settings;
/* References, not owned. */
GPUUniformBuf *globals_buf;
TextureRef depth_tx;
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
typedef struct OVERLAY_FramebufferList {
struct GPUFrameBuffer *overlay_default_fb;
struct GPUFrameBuffer *overlay_line_fb;
@@ -430,10 +568,6 @@ typedef struct OVERLAY_StorageList {
struct OVERLAY_PrivateData *pd;
} OVERLAY_StorageList;
typedef struct OVERLAY_Instance {
GPUUniformBuf *grid_ubo;
} OVERLAY_Instance;
typedef struct OVERLAY_Data {
void *engine_type;
OVERLAY_FramebufferList *fbl;
@@ -441,7 +575,7 @@ typedef struct OVERLAY_Data {
OVERLAY_PassList *psl;
OVERLAY_StorageList *stl;
OVERLAY_Instance *instance;
blender::draw::overlay::Instance *instance;
} OVERLAY_Data;
typedef struct OVERLAY_DupliData {

View File

@@ -11,6 +11,8 @@
#include "UI_resources.h"
#include "gpu_shader_create_info.hh"
#include "overlay_private.hh"
struct OVERLAY_Shaders {
@@ -184,6 +186,17 @@ GPUShader *OVERLAY_shader_armature_sphere(bool use_outline)
const DRWContextState *draw_ctx = DRW_context_state_get();
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
if (use_outline && !sh_data->armature_sphere_outline) {
using namespace blender::gpu::shader;
ShaderCreateInfo &info = const_cast<ShaderCreateInfo &>(
*reinterpret_cast<const ShaderCreateInfo *>(
GPU_shader_create_info_get("overlay_armature_sphere_outline")));
if (U.experimental.enable_overlay_next) {
info.storage_buf(0, Qualifier::READ, "mat4", "data_buf[]");
info.define("inst_obmat", "data_buf[gl_InstanceID]");
info.vertex_inputs_.pop_last();
}
sh_data->armature_sphere_outline = GPU_shader_create_from_info_name(
(draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "overlay_armature_sphere_outline_clipped" :
"overlay_armature_sphere_outline");
@@ -477,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<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(
(draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ?
(is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") :

View File

@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef GPU_SHADER
# pragma once
# include "GPU_shader_shared_utils.h"
# include "DNA_action_types.h"
@@ -12,6 +14,8 @@ extern "C" {
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.
@@ -84,6 +88,126 @@ BLI_STATIC_ASSERT(MOTIONPATH_VERT_SEL == (1u << 0), "Ensure value is sync");
BLI_STATIC_ASSERT(MOTIONPATH_VERT_KEY == (1u << 1), "Ensure value is sync");
#endif
struct ThemeColorData {
float4 color_wire;
float4 color_wire_edit;
float4 color_active;
float4 color_select;
float4 color_library_select;
float4 color_library;
float4 color_transform;
float4 color_light;
float4 color_speaker;
float4 color_camera;
float4 color_camera_path;
float4 color_empty;
float4 color_vertex;
float4 color_vertex_select;
float4 color_vertex_unreferenced;
float4 color_vertex_missing_data;
float4 color_edit_mesh_active;
float4 color_edge_select;
float4 color_edge_seam;
float4 color_edge_sharp;
float4 color_edge_crease;
float4 color_edge_bweight;
float4 color_edge_face_select;
float4 color_edge_freestyle;
float4 color_face;
float4 color_face_select;
float4 color_face_freestyle;
float4 color_gpencil_vertex;
float4 color_gpencil_vertex_select;
float4 color_normal;
float4 color_vnormal;
float4 color_lnormal;
float4 color_facedot;
float4 color_skinroot;
float4 color_deselect;
float4 color_outline;
float4 color_light_no_alpha;
float4 color_background;
float4 color_background_gradient;
float4 color_checker_primary;
float4 color_checker_secondary;
float4 color_clipping_border;
float4 color_edit_mesh_middle;
float4 color_handle_free;
float4 color_handle_auto;
float4 color_handle_vect;
float4 color_handle_align;
float4 color_handle_autoclamp;
float4 color_handle_sel_free;
float4 color_handle_sel_auto;
float4 color_handle_sel_vect;
float4 color_handle_sel_align;
float4 color_handle_sel_autoclamp;
float4 color_nurb_uline;
float4 color_nurb_vline;
float4 color_nurb_sel_uline;
float4 color_nurb_sel_vline;
float4 color_active_spline;
float4 color_bone_pose;
float4 color_bone_pose_active;
float4 color_bone_pose_active_unsel;
float4 color_bone_pose_constraint;
float4 color_bone_pose_ik;
float4 color_bone_pose_spline_ik;
float4 color_bone_pose_target;
float4 color_bone_solid;
float4 color_bone_locked;
float4 color_bone_active;
float4 color_bone_active_unsel;
float4 color_bone_select;
float4 color_bone_ik_line;
float4 color_bone_ik_line_no_target;
float4 color_bone_ik_line_spline;
float4 color_text;
float4 color_text_hi;
float4 color_bundle_solid;
float4 color_mball_radius;
float4 color_mball_radius_select;
float4 color_mball_stiffness;
float4 color_mball_stiffness_select;
float4 color_current_frame;
float4 color_grid;
float4 color_grid_emphasis;
float4 color_grid_axis_x;
float4 color_grid_axis_y;
float4 color_grid_axis_z;
float4 color_face_back;
float4 color_face_front;
float4 color_uv_shadow;
};
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
}

View File

@@ -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

View File

@@ -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. */

View File

@@ -1205,7 +1205,8 @@ static void drw_engines_enable_from_engine(const RenderEngineType *engine_type,
static void drw_engines_enable_overlays(void)
{
use_drw_engine(&draw_engine_overlay_type);
use_drw_engine((U.experimental.enable_overlay_next) ? &draw_engine_overlay_next_type :
&draw_engine_overlay_type);
}
/**
* Use for select and depth-drawing.
@@ -1224,7 +1225,8 @@ static void drw_engine_enable_image_editor(void)
use_drw_engine(&draw_engine_image_type);
}
use_drw_engine(&draw_engine_overlay_type);
use_drw_engine((U.experimental.enable_overlay_next) ? &draw_engine_overlay_next_type :
&draw_engine_overlay_type);
}
static void drw_engines_enable_editors(void)
@@ -1242,7 +1244,8 @@ static void drw_engines_enable_editors(void)
SpaceNode *snode = (SpaceNode *)space_data;
if ((snode->flag & SNODE_BACKDRAW) != 0) {
use_drw_engine(&draw_engine_image_type);
use_drw_engine(&draw_engine_overlay_type);
use_drw_engine((U.experimental.enable_overlay_next) ? &draw_engine_overlay_next_type :
&draw_engine_overlay_type);
}
}
}
@@ -3008,6 +3011,7 @@ void DRW_engines_register(void)
DRW_engine_register(&draw_engine_gpencil_type);
DRW_engine_register(&draw_engine_overlay_type);
DRW_engine_register(&draw_engine_overlay_next_type);
DRW_engine_register(&draw_engine_select_type);
DRW_engine_register(&draw_engine_basic_type);
DRW_engine_register(&draw_engine_compositor_type);

View File

@@ -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.

View File

@@ -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;

View File

@@ -652,8 +652,9 @@ typedef struct UserDef_Experimental {
char use_override_templates;
char enable_eevee_next;
char use_sculpt_texture_paint;
char enable_overlay_next;
char enable_workbench_next;
char _pad[7];
char _pad[6];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;

View File

@@ -6441,6 +6441,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"pop-over");
RNA_def_property_update(prop, 0, "rna_userdef_ui_update");
prop = RNA_def_property(srna, "enable_overlay_next", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "enable_overlay_next", 1);
RNA_def_property_ui_text(
prop, "Overlay Next", "Enable the new Overlay codebase, requires restart");
prop = RNA_def_property(srna, "use_all_linked_data_direct", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop,