Overlay-Next: Initial implementation
This contains the basis of the new overlay engine. Only a few overlays are ported for proof of concept of the new design. This new design unifies the selection drawing with the overlay-next engine. It now becomes responsible of selection in object mode. For this we create a dedicated shader module that patches the shaders for selection. Note that the gizmo selection still uses the occlusion queries and edit-mode the current selection engine (select_engine.c). Related task #102179 Related task #102177 Co-authored-by: Clément Foucault <foucault.clem@gmail.com> Pull Request: https://projects.blender.org/blender/blender/pulls/107734
This commit is contained in:
parent
3d895f6e7a
commit
9ae2dd577a
@ -2393,6 +2393,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")),
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -192,6 +192,7 @@ set(SRC
|
||||
engines/gpencil/gpencil_shader_fx.c
|
||||
engines/select/select_draw_utils.c
|
||||
engines/select/select_engine.c
|
||||
engines/select/select_instance.cc
|
||||
engines/overlay/overlay_antialiasing.cc
|
||||
engines/overlay/overlay_armature.cc
|
||||
engines/overlay/overlay_background.cc
|
||||
@ -211,6 +212,10 @@ set(SRC
|
||||
engines/overlay/overlay_metaball.cc
|
||||
engines/overlay/overlay_mode_transfer.cc
|
||||
engines/overlay/overlay_motion_path.cc
|
||||
engines/overlay/overlay_next_engine.cc
|
||||
engines/overlay/overlay_next_instance.cc
|
||||
engines/overlay/overlay_next_shader.cc
|
||||
engines/overlay/overlay_next_shape.cc
|
||||
engines/overlay/overlay_outline.cc
|
||||
engines/overlay/overlay_paint.cc
|
||||
engines/overlay/overlay_particle.cc
|
||||
@ -313,6 +318,8 @@ set(SRC
|
||||
engines/select/select_engine.h
|
||||
engines/select/select_private.h
|
||||
engines/overlay/overlay_engine.h
|
||||
engines/overlay/overlay_next_instance.hh
|
||||
engines/overlay/overlay_next_private.hh
|
||||
engines/overlay/overlay_private.hh
|
||||
)
|
||||
|
||||
@ -601,6 +608,9 @@ set(GLSL_SRC
|
||||
|
||||
engines/select/shaders/select_id_vert.glsl
|
||||
engines/select/shaders/select_id_frag.glsl
|
||||
engines/select/shaders/select_lib.glsl
|
||||
|
||||
engines/select/select_shader_shared.hh
|
||||
|
||||
engines/basic/shaders/basic_conservative_depth_geom.glsl
|
||||
engines/basic/shaders/basic_depth_vert.glsl
|
||||
|
@ -619,9 +619,6 @@ static void drw_shgroup_bone_envelope(ArmatureDrawContext *ctx,
|
||||
|
||||
/* Custom (geometry) */
|
||||
|
||||
extern "C" void drw_batch_cache_validate(Object *custom);
|
||||
extern "C" void drw_batch_cache_generate_requested_delayed(Object *custom);
|
||||
|
||||
BLI_INLINE DRWCallBuffer *custom_bone_instance_shgroup(ArmatureDrawContext *ctx,
|
||||
DRWShadingGroup *grp,
|
||||
GPUBatch *custom_geom)
|
||||
|
@ -20,11 +20,20 @@
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_paint.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "overlay_next_instance.hh"
|
||||
|
||||
#include "overlay_engine.h"
|
||||
#include "overlay_private.hh"
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
using Instance = blender::draw::overlay::Instance;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Callbacks
|
||||
* \{ */
|
||||
@ -46,8 +55,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 Instance(select::SelectionType::DISABLED);
|
||||
}
|
||||
|
||||
OVERLAY_PrivateData *pd = stl->pd;
|
||||
@ -729,17 +737,17 @@ static void OVERLAY_draw_scene(void *vedata)
|
||||
static void OVERLAY_engine_free()
|
||||
{
|
||||
OVERLAY_shader_free();
|
||||
overlay::ShaderModule::module_free();
|
||||
}
|
||||
|
||||
static void OVERLAY_instance_free(void *instance_)
|
||||
{
|
||||
OVERLAY_Instance *instance = (OVERLAY_Instance *)instance_;
|
||||
DRW_UBO_FREE_SAFE(instance->grid_ubo);
|
||||
MEM_freeN(instance);
|
||||
auto *instance = (Instance *)instance_;
|
||||
if (instance != nullptr) {
|
||||
delete instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Type
|
||||
* \{ */
|
||||
|
@ -12,6 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
extern DrawEngineType draw_engine_overlay_type;
|
||||
extern DrawEngineType draw_engine_overlay_next_type;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -17,8 +17,13 @@
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "overlay_next_instance.hh"
|
||||
#include "overlay_private.hh"
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
using Instance = blender::draw::overlay::Instance;
|
||||
|
||||
BLI_STATIC_ASSERT(SI_GRID_STEPS_LEN == OVERLAY_GRID_STEPS_LEN, "")
|
||||
|
||||
void OVERLAY_grid_init(OVERLAY_Data *vedata)
|
||||
@ -226,10 +231,11 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *ved)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ved->instance->grid_ubo == nullptr) {
|
||||
ved->instance->grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData));
|
||||
GPUUniformBuf *&grid_ubo = reinterpret_cast<Instance *>(ved->instance)->grid_ubo;
|
||||
if (grid_ubo == nullptr) {
|
||||
grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData));
|
||||
}
|
||||
GPU_uniformbuf_update(ved->instance->grid_ubo, &pd->grid_data);
|
||||
GPU_uniformbuf_update(grid_ubo, &pd->grid_data);
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
|
||||
DRW_PASS_CREATE(psl->grid_ps, state);
|
||||
@ -259,7 +265,7 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *ved)
|
||||
|
||||
/* Create 3 quads to render ordered transparency Z axis */
|
||||
grp = DRW_shgroup_create(sh, psl->grid_ps);
|
||||
DRW_shgroup_uniform_block(grp, "grid_buf", ved->instance->grid_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "grid_buf", grid_ubo);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &dtxl->depth);
|
||||
|
||||
|
@ -0,0 +1,96 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class Background {
|
||||
private:
|
||||
const SelectionType selection_type_;
|
||||
|
||||
PassSimple bg_ps_ = {"Background"};
|
||||
|
||||
public:
|
||||
Background(const SelectionType selection_type) : selection_type_(selection_type){};
|
||||
|
||||
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 (state.space_type == SPACE_IMAGE) {
|
||||
background_type = BG_SOLID_CHECKER;
|
||||
}
|
||||
else if (state.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(res.shaders.background_fill.get());
|
||||
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(res.shaders.background_clip_bound.get());
|
||||
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
|
127
source/blender/draw/engines/overlay/overlay_next_empty.hh
Normal file
127
source/blender/draw/engines/overlay/overlay_next_empty.hh
Normal file
@ -0,0 +1,127 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class Empties {
|
||||
using EmptyInstanceBuf = ShapeInstanceBuf<ExtraInstanceData>;
|
||||
|
||||
private:
|
||||
const SelectionType selection_type_;
|
||||
|
||||
PassSimple empty_ps_ = {"Empties"};
|
||||
PassSimple empty_in_front_ps_ = {"Empties_In_front"};
|
||||
|
||||
struct CallBuffers {
|
||||
const SelectionType selection_type_;
|
||||
EmptyInstanceBuf plain_axes_buf = {selection_type_, "plain_axes_buf"};
|
||||
EmptyInstanceBuf single_arrow_buf = {selection_type_, "single_arrow_buf"};
|
||||
EmptyInstanceBuf cube_buf = {selection_type_, "cube_buf"};
|
||||
EmptyInstanceBuf circle_buf = {selection_type_, "circle_buf"};
|
||||
EmptyInstanceBuf sphere_buf = {selection_type_, "sphere_buf"};
|
||||
EmptyInstanceBuf cone_buf = {selection_type_, "cone_buf"};
|
||||
EmptyInstanceBuf arrows_buf = {selection_type_, "arrows_buf"};
|
||||
EmptyInstanceBuf image_buf = {selection_type_, "image_buf"};
|
||||
} call_buffers_[2] = {{selection_type_}, {selection_type_}};
|
||||
|
||||
public:
|
||||
Empties(const SelectionType selection_type) : selection_type_(selection_type){};
|
||||
|
||||
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, 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);
|
||||
|
||||
const select::ID select_id = res.select_id(ob_ref);
|
||||
|
||||
switch (ob_ref.object->empty_drawtype) {
|
||||
case OB_PLAINAXES:
|
||||
call_bufs.plain_axes_buf.append(data, select_id);
|
||||
break;
|
||||
case OB_SINGLE_ARROW:
|
||||
call_bufs.single_arrow_buf.append(data, select_id);
|
||||
break;
|
||||
case OB_CUBE:
|
||||
call_bufs.cube_buf.append(data, select_id);
|
||||
break;
|
||||
case OB_CIRCLE:
|
||||
call_bufs.circle_buf.append(data, select_id);
|
||||
break;
|
||||
case OB_EMPTY_SPHERE:
|
||||
call_bufs.sphere_buf.append(data, select_id);
|
||||
break;
|
||||
case OB_EMPTY_CONE:
|
||||
call_bufs.cone_buf.append(data, select_id);
|
||||
break;
|
||||
case OB_ARROWS:
|
||||
call_bufs.arrows_buf.append(data, select_id);
|
||||
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, select_id);
|
||||
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(res.shaders.extra_shape.get());
|
||||
pass.bind_ubo("globalsBlock", &res.globals_buf);
|
||||
res.select_bind(pass);
|
||||
|
||||
call_bufs.plain_axes_buf.end_sync(pass, shapes.plain_axes.get());
|
||||
call_bufs.single_arrow_buf.end_sync(pass, shapes.single_arrow.get());
|
||||
call_bufs.cube_buf.end_sync(pass, shapes.cube.get());
|
||||
call_bufs.circle_buf.end_sync(pass, shapes.circle.get());
|
||||
call_bufs.sphere_buf.end_sync(pass, shapes.empty_sphere.get());
|
||||
call_bufs.cone_buf.end_sync(pass, shapes.empty_cone.get());
|
||||
call_bufs.arrows_buf.end_sync(pass, shapes.arrows.get());
|
||||
call_bufs.image_buf.end_sync(pass, shapes.quad_wire.get());
|
||||
};
|
||||
|
||||
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
|
130
source/blender/draw/engines/overlay/overlay_next_engine.cc
Normal file
130
source/blender/draw/engines/overlay/overlay_next_engine.cc
Normal file
@ -0,0 +1,130 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2019 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
* Engine for drawing a selection map where the pixels indicate the selection indices.
|
||||
*/
|
||||
|
||||
#include "DRW_engine.h"
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "BKE_duplilist.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_paint.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "overlay_next_instance.hh"
|
||||
|
||||
#include "overlay_engine.h"
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
using Instance = blender::draw::overlay::Instance;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Instance
|
||||
* \{ */
|
||||
|
||||
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 Instance(select::SelectionType::DISABLED);
|
||||
}
|
||||
|
||||
reinterpret_cast<Instance *>(ved->instance)->init();
|
||||
}
|
||||
|
||||
static void OVERLAY_next_cache_init(void *vedata)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<Instance *>(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<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->object_sync(ref, *DRW_manager_get());
|
||||
}
|
||||
|
||||
static void OVERLAY_next_cache_finish(void *vedata)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<Instance *>(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<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->draw(*DRW_manager_get());
|
||||
}
|
||||
|
||||
static void OVERLAY_next_instance_free(void *instance_)
|
||||
{
|
||||
auto *instance = (Instance *)instance_;
|
||||
if (instance != nullptr) {
|
||||
delete instance;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Type
|
||||
* \{ */
|
||||
|
||||
static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
|
||||
|
||||
DrawEngineType draw_engine_overlay_next_type = {
|
||||
nullptr,
|
||||
nullptr,
|
||||
N_("Overlay"),
|
||||
&overlay_data_size,
|
||||
&OVERLAY_next_engine_init,
|
||||
nullptr,
|
||||
&OVERLAY_next_instance_free,
|
||||
&OVERLAY_next_cache_init,
|
||||
&OVERLAY_next_cache_populate,
|
||||
&OVERLAY_next_cache_finish,
|
||||
&OVERLAY_next_draw_scene,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
/** \} */
|
217
source/blender/draw/engines/overlay/overlay_next_grid.hh
Normal file
217
source/blender/draw/engines/overlay/overlay_next_grid.hh
Normal file
@ -0,0 +1,217 @@
|
||||
/* 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 "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class Grid {
|
||||
private:
|
||||
const SelectionType selection_type_;
|
||||
|
||||
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:
|
||||
Grid(const SelectionType selection_type) : selection_type_(selection_type){};
|
||||
|
||||
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(res.shaders.grid.get());
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
void update_ubo(const State &state, const View &view)
|
||||
{
|
||||
if (state.space_type == SPACE_IMAGE) {
|
||||
/* TODO */
|
||||
enabled_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
273
source/blender/draw/engines/overlay/overlay_next_instance.cc
Normal file
273
source/blender/draw/engines/overlay/overlay_next_instance.cc
Normal file
@ -0,0 +1,273 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
#include "ED_view3d.h"
|
||||
#include "draw_debug.hh"
|
||||
|
||||
#include "overlay_next_instance.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
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);
|
||||
state.space_type = state.v3d != nullptr ? SPACE_VIEW3D : eSpace_Type(ctx->space_data->spacetype);
|
||||
if (state.v3d != nullptr) {
|
||||
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);
|
||||
|
||||
resources.begin_sync();
|
||||
|
||||
background.begin_sync(resources, state);
|
||||
prepass.begin_sync(resources, state);
|
||||
empties.begin_sync();
|
||||
metaballs.begin_sync();
|
||||
grid.begin_sync(resources, state, view);
|
||||
}
|
||||
|
||||
void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
{
|
||||
const bool in_edit_mode = object_is_edit_mode(ob_ref.object);
|
||||
const bool needs_prepass = true; /* TODO */
|
||||
|
||||
if (needs_prepass) {
|
||||
switch (ob_ref.object->type) {
|
||||
case OB_MESH:
|
||||
case OB_SURF:
|
||||
case OB_CURVES:
|
||||
case OB_FONT:
|
||||
case OB_CURVES_LEGACY:
|
||||
prepass.object_sync(manager, ob_ref, resources);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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_LEGACY:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::end_sync()
|
||||
{
|
||||
resources.end_sync();
|
||||
|
||||
metaballs.end_sync(resources, shapes, state);
|
||||
empties.end_sync(resources, shapes, state);
|
||||
}
|
||||
|
||||
void Instance::draw(Manager &manager)
|
||||
{
|
||||
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);
|
||||
|
||||
int2 render_size = int2(resources.depth_tx.size());
|
||||
|
||||
const DRWView *view_legacy = DRW_view_default_get();
|
||||
View view("OverlayView", view_legacy);
|
||||
|
||||
/* TODO: Better semantical switch? */
|
||||
if (!resources.color_overlay_tx.is_valid()) {
|
||||
/* Likely to be the selection case. Allocate dummy texture and bind only depth buffer. */
|
||||
resources.line_tx.acquire(int2(1, 1), GPU_RGBA8);
|
||||
resources.color_overlay_alloc_tx.acquire(int2(1, 1), GPU_SRGB8_A8);
|
||||
resources.color_render_alloc_tx.acquire(int2(1, 1), GPU_SRGB8_A8);
|
||||
|
||||
resources.color_overlay_tx.wrap(resources.color_overlay_alloc_tx);
|
||||
resources.color_render_tx.wrap(resources.color_render_alloc_tx);
|
||||
|
||||
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||
/* Create it but shouldn't even be used. */
|
||||
resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
|
||||
}
|
||||
else {
|
||||
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);
|
||||
|
||||
prepass.draw(resources, manager, view);
|
||||
prepass.draw_in_front(resources, manager, view);
|
||||
|
||||
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();
|
||||
resources.color_overlay_alloc_tx.release();
|
||||
resources.color_render_alloc_tx.release();
|
||||
|
||||
resources.read_result();
|
||||
}
|
||||
|
||||
bool Instance::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
|
||||
|
||||
#include "overlay_private.hh"
|
||||
|
||||
/* TODO(fclem): Move elsewhere. */
|
||||
BoneInstanceData::BoneInstanceData(Object *ob,
|
||||
const float *pos,
|
||||
const float radius,
|
||||
const float color[4])
|
||||
{
|
||||
/* TODO(fclem): Use C++ math API. */
|
||||
mul_v3_v3fl(this->mat[0], ob->object_to_world[0], radius);
|
||||
mul_v3_v3fl(this->mat[1], ob->object_to_world[1], radius);
|
||||
mul_v3_v3fl(this->mat[2], ob->object_to_world[2], radius);
|
||||
mul_v3_m4v3(this->mat[3], ob->object_to_world, pos);
|
||||
/* WATCH: Reminder, alpha is wire-size. */
|
||||
OVERLAY_bone_instance_data_set_color(this, color);
|
||||
}
|
59
source/blender/draw/engines/overlay/overlay_next_instance.hh
Normal file
59
source/blender/draw/engines/overlay/overlay_next_instance.hh
Normal file
@ -0,0 +1,59 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
#include "overlay_next_background.hh"
|
||||
#include "overlay_next_empty.hh"
|
||||
#include "overlay_next_grid.hh"
|
||||
#include "overlay_next_metaball.hh"
|
||||
#include "overlay_next_prepass.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
/* Selection engine reuse most of the Overlay engine by creating selection IDs for each
|
||||
* selectable component and using a special shaders for drawing.*/
|
||||
class Instance {
|
||||
const SelectionType selection_type_;
|
||||
|
||||
public:
|
||||
/* WORKAROUND: Legacy. Move to grid pass. */
|
||||
GPUUniformBuf *grid_ubo = nullptr;
|
||||
|
||||
ShapeCache shapes;
|
||||
|
||||
/** Global types. */
|
||||
Resources resources = {selection_type_,
|
||||
overlay::ShaderModule::module_get(selection_type_, false /*TODO*/)};
|
||||
State state;
|
||||
|
||||
/** Overlay types. */
|
||||
Background background = {selection_type_};
|
||||
Prepass prepass = {selection_type_};
|
||||
Metaballs metaballs = {selection_type_};
|
||||
Empties empties = {selection_type_};
|
||||
Grid grid = {selection_type_};
|
||||
|
||||
Instance(const SelectionType selection_type) : selection_type_(selection_type){};
|
||||
|
||||
~Instance()
|
||||
{
|
||||
DRW_UBO_FREE_SAFE(grid_ubo);
|
||||
}
|
||||
|
||||
void init();
|
||||
void begin_sync();
|
||||
void object_sync(ObjectRef &ob_ref, Manager &manager);
|
||||
void end_sync();
|
||||
void draw(Manager &manager);
|
||||
|
||||
private:
|
||||
bool object_is_edit_mode(const Object *ob);
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
112
source/blender/draw/engines/overlay/overlay_next_metaball.hh
Normal file
112
source/blender/draw/engines/overlay/overlay_next_metaball.hh
Normal file
@ -0,0 +1,112 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
#include "overlay_shader_shared.h"
|
||||
|
||||
#include "ED_mball.h"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class Metaballs {
|
||||
using SphereOutlineInstanceBuf = ShapeInstanceBuf<BoneInstanceData>;
|
||||
|
||||
private:
|
||||
const SelectionType selection_type_;
|
||||
|
||||
PassSimple metaball_ps_ = {"MetaBalls"};
|
||||
PassSimple metaball_in_front_ps_ = {"MetaBalls_In_front"};
|
||||
|
||||
SphereOutlineInstanceBuf circle_buf_ = {selection_type_, "metaball_data_buf"};
|
||||
SphereOutlineInstanceBuf circle_in_front_buf_ = {selection_type_, "metaball_data_buf"};
|
||||
|
||||
public:
|
||||
Metaballs(const SelectionType selection_type) : selection_type_(selection_type){};
|
||||
|
||||
void begin_sync()
|
||||
{
|
||||
circle_buf_.clear();
|
||||
circle_in_front_buf_.clear();
|
||||
}
|
||||
|
||||
void edit_object_sync(const ObjectRef &ob_ref, Resources &res)
|
||||
{
|
||||
SphereOutlineInstanceBuf &circle_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
|
||||
circle_in_front_buf_ :
|
||||
circle_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);
|
||||
|
||||
const select::ID radius_id = res.select_id(ob_ref, MBALLSEL_RADIUS);
|
||||
color = (is_selected && is_scale_radius) ? col_radius_select : col_radius;
|
||||
circle_buf.append({ob_ref.object, &ml->x, ml->rad, color}, radius_id);
|
||||
|
||||
const select::ID stiff_id = res.select_id(ob_ref, MBALLSEL_STIFF);
|
||||
color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness;
|
||||
circle_buf.append({ob_ref.object, &ml->x, stiffness_radius, color}, stiff_id);
|
||||
}
|
||||
}
|
||||
|
||||
void object_sync(const ObjectRef &ob_ref, Resources &res, const State &state)
|
||||
{
|
||||
SphereOutlineInstanceBuf &circle_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
|
||||
circle_in_front_buf_ :
|
||||
circle_buf_;
|
||||
MetaBall *mb = static_cast<MetaBall *>(ob_ref.object->data);
|
||||
|
||||
const float4 &color = res.object_wire_color(ob_ref, state);
|
||||
const select::ID select_id = res.select_id(ob_ref);
|
||||
|
||||
LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
|
||||
/* Draw radius only. */
|
||||
circle_buf.append({ob_ref.object, &ml->x, ml->rad, color}, select_id);
|
||||
}
|
||||
}
|
||||
|
||||
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
|
||||
{
|
||||
auto init_pass = [&](PassSimple &pass, SphereOutlineInstanceBuf &call_buf) {
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
|
||||
state.clipping_state);
|
||||
/* NOTE: Use armature sphere outline shader to have perspective correct outline instead of
|
||||
* just a circle facing the camera. */
|
||||
pass.shader_set(res.shaders.armature_sphere_outline.get());
|
||||
pass.bind_ubo("globalsBlock", &res.globals_buf);
|
||||
res.select_bind(pass);
|
||||
|
||||
call_buf.end_sync(pass, shapes.metaball_wire_circle.get());
|
||||
};
|
||||
init_pass(metaball_ps_, circle_buf_);
|
||||
init_pass(metaball_in_front_ps_, circle_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
|
67
source/blender/draw/engines/overlay/overlay_next_prepass.hh
Normal file
67
source/blender/draw/engines/overlay/overlay_next_prepass.hh
Normal file
@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*
|
||||
* A depth pass that write surface depth when it is needed.
|
||||
* It is also used for selecting non overlay-only objects.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
class Prepass {
|
||||
private:
|
||||
const SelectionType selection_type_;
|
||||
|
||||
PassMain prepass_ps_ = {"prepass"};
|
||||
PassMain prepass_in_front_ps_ = {"prepass_in_front"};
|
||||
|
||||
public:
|
||||
Prepass(const SelectionType selection_type) : selection_type_(selection_type){};
|
||||
|
||||
void begin_sync(Resources &res, const State &state)
|
||||
{
|
||||
auto init_pass = [&](PassMain &pass) {
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state);
|
||||
pass.shader_set(res.shaders.depth_mesh.get());
|
||||
res.select_bind(pass);
|
||||
};
|
||||
init_pass(prepass_ps_);
|
||||
init_pass(prepass_in_front_ps_);
|
||||
}
|
||||
|
||||
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res)
|
||||
{
|
||||
PassMain &pass = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? prepass_in_front_ps_ :
|
||||
prepass_ps_;
|
||||
|
||||
/* TODO(fclem) This function should contain what `basic_cache_populate` contained. */
|
||||
|
||||
GPUBatch *geom = DRW_cache_object_surface_get(ob_ref.object);
|
||||
if (geom) {
|
||||
ResourceHandle res_handle = manager.resource_handle(ob_ref);
|
||||
pass.draw(geom, res_handle, res.select_id(ob_ref).get());
|
||||
}
|
||||
}
|
||||
|
||||
void draw(Resources &res, Manager &manager, View &view)
|
||||
{
|
||||
/* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */
|
||||
GPU_framebuffer_bind(res.overlay_line_fb);
|
||||
manager.submit(prepass_ps_, view);
|
||||
}
|
||||
|
||||
void draw_in_front(Resources &res, Manager &manager, View &view)
|
||||
{
|
||||
/* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */
|
||||
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
|
||||
manager.submit(prepass_in_front_ps_, view);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
268
source/blender/draw/engines/overlay/overlay_next_private.hh
Normal file
268
source/blender/draw/engines/overlay/overlay_next_private.hh
Normal file
@ -0,0 +1,268 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2019 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
#include "DRW_render.h"
|
||||
#include "UI_resources.h"
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "../select/select_instance.hh"
|
||||
#include "overlay_shader_shared.h"
|
||||
|
||||
/* Needed for BoneInstanceData. */
|
||||
#include "overlay_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
using SelectionType = select::SelectionType;
|
||||
|
||||
using blender::draw::Framebuffer;
|
||||
using blender::draw::StorageVectorBuffer;
|
||||
using blender::draw::Texture;
|
||||
using blender::draw::TextureFromPool;
|
||||
using blender::draw::TextureRef;
|
||||
|
||||
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 eSpace_Type space_type;
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains all overlay generic geometry batches.
|
||||
*/
|
||||
class ShapeCache {
|
||||
private:
|
||||
struct BatchDeleter {
|
||||
void operator()(GPUBatch *shader)
|
||||
{
|
||||
GPU_BATCH_DISCARD_SAFE(shader);
|
||||
}
|
||||
};
|
||||
using BatchPtr = std::unique_ptr<GPUBatch, BatchDeleter>;
|
||||
|
||||
public:
|
||||
BatchPtr quad_wire;
|
||||
BatchPtr plain_axes;
|
||||
BatchPtr single_arrow;
|
||||
BatchPtr cube;
|
||||
BatchPtr circle;
|
||||
BatchPtr empty_sphere;
|
||||
BatchPtr empty_cone;
|
||||
BatchPtr arrows;
|
||||
BatchPtr metaball_wire_circle;
|
||||
|
||||
ShapeCache();
|
||||
};
|
||||
|
||||
/**
|
||||
* Shader module. Shared between instances.
|
||||
*/
|
||||
class ShaderModule {
|
||||
private:
|
||||
struct ShaderDeleter {
|
||||
void operator()(GPUShader *shader)
|
||||
{
|
||||
DRW_SHADER_FREE_SAFE(shader);
|
||||
}
|
||||
};
|
||||
using ShaderPtr = std::unique_ptr<GPUShader, ShaderDeleter>;
|
||||
|
||||
/** Shared shader module across all engine instances. */
|
||||
static ShaderModule *g_shader_modules[2 /*Selection Instance*/][2 /*Clipping Enabled*/];
|
||||
|
||||
const SelectionType selection_type_;
|
||||
/** TODO: Support clipping. This global state should be set by the overlay::Instance and switch
|
||||
* to the shader variations that use clipping. */
|
||||
const bool clipping_enabled_;
|
||||
|
||||
public:
|
||||
/** Shaders */
|
||||
ShaderPtr grid = shader("overlay_grid");
|
||||
ShaderPtr background_fill = shader("overlay_background");
|
||||
ShaderPtr background_clip_bound = shader("overlay_clipbound");
|
||||
|
||||
/** Selectable Shaders */
|
||||
ShaderPtr armature_sphere_outline;
|
||||
ShaderPtr depth_mesh;
|
||||
ShaderPtr extra_shape;
|
||||
|
||||
ShaderModule(const SelectionType selection_type, const bool clipping_enabled);
|
||||
|
||||
/** Module */
|
||||
/** Only to be used by Instance constructor. */
|
||||
static ShaderModule &module_get(SelectionType selection_type, bool clipping_enabled);
|
||||
static void module_free();
|
||||
|
||||
private:
|
||||
ShaderPtr shader(const char *create_info_name)
|
||||
{
|
||||
return ShaderPtr(GPU_shader_create_from_info_name(create_info_name));
|
||||
}
|
||||
ShaderPtr selectable_shader(const char *create_info_name);
|
||||
ShaderPtr selectable_shader(const char *create_info_name,
|
||||
std::function<void(gpu::shader::ShaderCreateInfo &info)> patch);
|
||||
};
|
||||
|
||||
struct Resources : public select::SelectMap {
|
||||
ShaderModule &shaders;
|
||||
|
||||
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"};
|
||||
TextureFromPool color_overlay_alloc_tx = {"overlay_color_overlay_alloc_tx"};
|
||||
TextureFromPool color_render_alloc_tx = {"overlay_color_render_alloc_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;
|
||||
|
||||
Resources(const SelectionType selection_type_, ShaderModule &shader_module)
|
||||
: select::SelectMap(selection_type_), shaders(shader_module){};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer containing instances of a certain shape.
|
||||
*/
|
||||
template<typename InstanceDataT> struct ShapeInstanceBuf : private select::SelectBuf {
|
||||
|
||||
StorageVectorBuffer<InstanceDataT> data_buf;
|
||||
|
||||
ShapeInstanceBuf(const SelectionType selection_type, const char *name = nullptr)
|
||||
: select::SelectBuf(selection_type), data_buf(name){};
|
||||
|
||||
void clear()
|
||||
{
|
||||
this->select_clear();
|
||||
data_buf.clear();
|
||||
}
|
||||
|
||||
void append(const InstanceDataT &data, select::ID select_id)
|
||||
{
|
||||
this->select_append(select_id);
|
||||
data_buf.append(data);
|
||||
}
|
||||
|
||||
void end_sync(PassSimple &pass, GPUBatch *shape)
|
||||
{
|
||||
if (data_buf.size() == 0) {
|
||||
return;
|
||||
}
|
||||
this->select_bind(pass);
|
||||
data_buf.push_update();
|
||||
pass.bind_ssbo("data_buf", &data_buf);
|
||||
pass.draw(shape, data_buf.size());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
108
source/blender/draw/engines/overlay/overlay_next_shader.cc
Normal file
108
source/blender/draw/engines/overlay/overlay_next_shader.cc
Normal file
@ -0,0 +1,108 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
ShaderModule *ShaderModule::g_shader_modules[2][2] = {{nullptr}};
|
||||
|
||||
ShaderModule::ShaderPtr ShaderModule::selectable_shader(const char *create_info_name)
|
||||
{
|
||||
/* TODO: This is what it should be like with all variations defined with create infos. */
|
||||
// std::string create_info_name = base_create_info;
|
||||
// create_info_name += SelectEngineT::shader_suffix;
|
||||
// create_info_name += ClippingEnabled ? "_clipped" : "";
|
||||
// this->shader_ = GPU_shader_create_from_info_name(create_info_name.c_str());
|
||||
|
||||
/* WORKAROUND: ... but for now, we have to patch the create info used by the old engine. */
|
||||
gpu::shader::ShaderCreateInfo info = *reinterpret_cast<const gpu::shader::ShaderCreateInfo *>(
|
||||
GPU_shader_create_info_get(create_info_name));
|
||||
|
||||
if (selection_type_ != SelectionType::DISABLED) {
|
||||
info.define("SELECT_ENABLE");
|
||||
}
|
||||
|
||||
return ShaderPtr(
|
||||
GPU_shader_create_from_info(reinterpret_cast<const GPUShaderCreateInfo *>(&info)));
|
||||
}
|
||||
|
||||
ShaderModule::ShaderPtr ShaderModule::selectable_shader(
|
||||
const char *create_info_name, std::function<void(gpu::shader::ShaderCreateInfo &info)> patch)
|
||||
{
|
||||
gpu::shader::ShaderCreateInfo info = *reinterpret_cast<const gpu::shader::ShaderCreateInfo *>(
|
||||
GPU_shader_create_info_get(create_info_name));
|
||||
|
||||
patch(info);
|
||||
|
||||
if (selection_type_ != SelectionType::DISABLED) {
|
||||
info.define("SELECT_ENABLE");
|
||||
/* Replace additional info. */
|
||||
for (StringRefNull &str : info.additional_infos_) {
|
||||
if (str == "draw_modelmat_new") {
|
||||
str = "draw_modelmat_new_with_custom_id";
|
||||
}
|
||||
}
|
||||
info.additional_info("select_id_patch");
|
||||
}
|
||||
|
||||
return ShaderPtr(
|
||||
GPU_shader_create_from_info(reinterpret_cast<const GPUShaderCreateInfo *>(&info)));
|
||||
}
|
||||
|
||||
using namespace blender::gpu::shader;
|
||||
|
||||
ShaderModule::ShaderModule(const SelectionType selection_type, const bool clipping_enabled)
|
||||
: selection_type_(selection_type), clipping_enabled_(clipping_enabled)
|
||||
{
|
||||
armature_sphere_outline = selectable_shader(
|
||||
"overlay_armature_sphere_outline", [](gpu::shader::ShaderCreateInfo &info) {
|
||||
info.storage_buf(0, Qualifier::READ, "mat4", "data_buf[]");
|
||||
info.define("inst_obmat", "data_buf[gl_InstanceID]");
|
||||
info.vertex_inputs_.pop_last();
|
||||
});
|
||||
|
||||
depth_mesh = selectable_shader("overlay_depth_only", [](gpu::shader::ShaderCreateInfo &info) {
|
||||
info.additional_infos_.clear();
|
||||
info.additional_info("draw_view", "draw_modelmat_new", "draw_resource_handle_new");
|
||||
});
|
||||
|
||||
extra_shape = selectable_shader("overlay_extra", [](gpu::shader::ShaderCreateInfo &info) {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
ShaderModule &ShaderModule::module_get(SelectionType selection_type, bool clipping_enabled)
|
||||
{
|
||||
int selection_index = selection_type == SelectionType::DISABLED ? 0 : 1;
|
||||
ShaderModule *&g_shader_module = g_shader_modules[selection_index][clipping_enabled];
|
||||
if (g_shader_module == nullptr) {
|
||||
/* TODO(@fclem) thread-safety. */
|
||||
g_shader_module = new ShaderModule(selection_type, clipping_enabled);
|
||||
}
|
||||
return *g_shader_module;
|
||||
}
|
||||
|
||||
void ShaderModule::module_free()
|
||||
{
|
||||
for (int i : IndexRange(2)) {
|
||||
for (int j : IndexRange(2)) {
|
||||
if (g_shader_modules[i][j] != nullptr) {
|
||||
/* TODO(@fclem) thread-safety. */
|
||||
delete g_shader_modules[i][j];
|
||||
g_shader_modules[i][j] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::draw::overlay
|
325
source/blender/draw/engines/overlay/overlay_next_shape.cc
Normal file
325
source/blender/draw/engines/overlay/overlay_next_shape.cc
Normal file
@ -0,0 +1,325 @@
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup overlay
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
/* Matches Vertex Format. */
|
||||
struct Vertex {
|
||||
float3 pos;
|
||||
int vclass;
|
||||
};
|
||||
|
||||
/* Caller gets ownership of the #GPUVertBuf. */
|
||||
static GPUVertBuf *vbo_from_vector(Vector<Vertex> &vector)
|
||||
{
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
GPU_vertformat_attr_add(&format, "vclass", GPU_COMP_I32, 1, GPU_FETCH_INT);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ShapeCache::ShapeCache()
|
||||
{
|
||||
/* quad_wire */
|
||||
{
|
||||
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});
|
||||
|
||||
quad_wire = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* plain_axes */
|
||||
{
|
||||
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});
|
||||
|
||||
plain_axes = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* single_arrow */
|
||||
{
|
||||
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});
|
||||
|
||||
single_arrow = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* cube */
|
||||
{
|
||||
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});
|
||||
}
|
||||
|
||||
cube = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* circle */
|
||||
{
|
||||
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});
|
||||
}
|
||||
|
||||
circle = BatchPtr(GPU_batch_create_ex(
|
||||
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* empty_spehere */
|
||||
{
|
||||
Vector<Vertex> verts = sphere_axes_circles(1.0f, VCLASS_EMPTY_SCALED, 32);
|
||||
|
||||
empty_sphere = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* empty_cone */
|
||||
{
|
||||
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});
|
||||
}
|
||||
}
|
||||
|
||||
empty_cone = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* arrows */
|
||||
{
|
||||
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});
|
||||
}
|
||||
}
|
||||
arrows = BatchPtr(
|
||||
GPU_batch_create_ex(GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
}
|
||||
/* metaball_wire_circle */
|
||||
{
|
||||
constexpr int resolution = 64;
|
||||
constexpr float radius = 1.0f;
|
||||
Vector<float2> ring = ring_vertices(radius, resolution);
|
||||
|
||||
Vector<Vertex> verts;
|
||||
for (int i : IndexRange(resolution + 1)) {
|
||||
float2 cv = ring[i % resolution];
|
||||
verts.append({{cv[0], cv[1], 0.0f}, VCLASS_SCREENALIGNED});
|
||||
}
|
||||
metaball_wire_circle = BatchPtr(GPU_batch_create_ex(
|
||||
GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO));
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace blender::draw::overlay
|
@ -7,13 +7,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "overlay_shader_shared.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "draw_handle.hh"
|
||||
|
||||
#include "overlay_shader_shared.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
# define USE_GEOM_SHADER_WORKAROUND 1
|
||||
@ -436,10 +439,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;
|
||||
@ -447,7 +446,7 @@ typedef struct OVERLAY_Data {
|
||||
OVERLAY_PassList *psl;
|
||||
OVERLAY_StorageList *stl;
|
||||
|
||||
OVERLAY_Instance *instance;
|
||||
void *instance;
|
||||
} OVERLAY_Data;
|
||||
|
||||
typedef struct OVERLAY_DupliData {
|
||||
@ -460,7 +459,7 @@ typedef struct OVERLAY_DupliData {
|
||||
short base_flag;
|
||||
} OVERLAY_DupliData;
|
||||
|
||||
typedef struct BoneInstanceData {
|
||||
struct BoneInstanceData {
|
||||
/* Keep sync with bone instance vertex format (OVERLAY_InstanceFormats) */
|
||||
union {
|
||||
float mat[4][4];
|
||||
@ -477,7 +476,12 @@ typedef struct BoneInstanceData {
|
||||
float _pad03[3], amax_b;
|
||||
};
|
||||
};
|
||||
} BoneInstanceData;
|
||||
|
||||
BoneInstanceData() = default;
|
||||
/* Constructor used by metaball overlays and expected to be used for drawing
|
||||
* metaball_wire_sphere with armature wire shader that produces wide-lines. */
|
||||
BoneInstanceData(Object *ob, const float *pos, const float radius, const float color[4]);
|
||||
};
|
||||
|
||||
typedef struct OVERLAY_InstanceFormats {
|
||||
struct GPUVertFormat *instance_pos;
|
||||
@ -797,7 +801,3 @@ GPUShader *OVERLAY_shader_xray_fade(void);
|
||||
OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void);
|
||||
|
||||
void OVERLAY_shader_free(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "overlay_private.hh"
|
||||
|
||||
struct OVERLAY_Shaders {
|
||||
|
@ -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,125 @@ 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)
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -1,12 +1,15 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
/* Sphere radius */
|
||||
const float rad = 0.05;
|
||||
|
||||
void main()
|
||||
{
|
||||
select_id_set(in_select_buf[gl_InstanceID]);
|
||||
|
||||
vec4 bone_color, state_color;
|
||||
mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
|
||||
fragColor = vec4(finalColor.rgb, finalColor.a * alpha);
|
||||
select_id_output(select_id);
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
/* No color output, only depth (line below is implicit). */
|
||||
// gl_FragDepth = gl_FragCoord.z;
|
||||
|
||||
/* This is optimized to noop in the non select case. */
|
||||
select_id_output(select_id);
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
GPU_INTEL_VERTEX_SHADER_WORKAROUND
|
||||
|
||||
select_id_set(drw_CustomID);
|
||||
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = finalColor;
|
||||
lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
|
||||
|
||||
select_id_output(select_id);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(select_lib.glsl)
|
||||
|
||||
#define lamp_area_size inst_data.xy
|
||||
#define lamp_clip_sta inst_data.z
|
||||
@ -41,6 +42,8 @@
|
||||
|
||||
void main()
|
||||
{
|
||||
select_id_set(in_select_buf[gl_InstanceID]);
|
||||
|
||||
/* Extract data packed inside the unused mat4 members. */
|
||||
vec4 inst_data = vec4(inst_obmat[0][3], inst_obmat[1][3], inst_obmat[2][3], inst_obmat[3][3]);
|
||||
float inst_color_data = color.a;
|
||||
|
11
source/blender/draw/engines/select/select_defines.h
Normal file
11
source/blender/draw/engines/select/select_defines.h
Normal file
@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SELECT_DATA 4
|
||||
#define SELECT_ID_IN 5
|
||||
#define SELECT_ID_OUT 6
|
@ -163,7 +163,7 @@ static void select_cache_init(void *vedata)
|
||||
}
|
||||
else {
|
||||
pd->shgrp_face_unif = DRW_shgroup_create(sh->select_id_uniform, psl->select_id_face_pass);
|
||||
DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "id", 0);
|
||||
DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "select_id", 0);
|
||||
DRW_shgroup_uniform_float_copy(pd->shgrp_face_unif, "retopologyOffset", retopology_offset);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* select_engine.c */
|
||||
|
||||
extern DrawEngineType draw_engine_select_type;
|
||||
@ -22,3 +26,11 @@ struct SELECTID_Context *DRW_select_engine_context_get(void);
|
||||
|
||||
struct GPUFrameBuffer *DRW_engine_select_framebuffer_get(void);
|
||||
struct GPUTexture *DRW_engine_select_texture_get(void);
|
||||
|
||||
/* select_instance.cc */
|
||||
|
||||
extern DrawEngineType draw_engine_select_next_type;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
117
source/blender/draw/engines/select/select_instance.cc
Normal file
117
source/blender/draw/engines/select/select_instance.cc
Normal file
@ -0,0 +1,117 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup select
|
||||
*/
|
||||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
|
||||
#include "select_engine.h"
|
||||
|
||||
#include "../overlay/overlay_next_instance.hh"
|
||||
#include "select_instance.hh"
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Select-Next Engine
|
||||
* \{ */
|
||||
|
||||
using Instance = overlay::Instance;
|
||||
|
||||
typedef struct SELECT_NextData {
|
||||
void *engine_type;
|
||||
DRWViewportEmptyList *fbl;
|
||||
DRWViewportEmptyList *txl;
|
||||
DRWViewportEmptyList *psl;
|
||||
DRWViewportEmptyList *stl;
|
||||
|
||||
Instance *instance;
|
||||
} SELECT_NextData;
|
||||
|
||||
static void SELECT_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 Instance(select::SelectionType::ENABLED);
|
||||
}
|
||||
|
||||
reinterpret_cast<Instance *>(ved->instance)->init();
|
||||
}
|
||||
|
||||
static void SELECT_next_cache_init(void *vedata)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->begin_sync();
|
||||
}
|
||||
|
||||
static void SELECT_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<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->object_sync(ref, *DRW_manager_get());
|
||||
}
|
||||
|
||||
static void SELECT_next_cache_finish(void *vedata)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->end_sync();
|
||||
}
|
||||
|
||||
static void SELECT_next_draw_scene(void *vedata)
|
||||
{
|
||||
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||
return;
|
||||
}
|
||||
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->draw(*DRW_manager_get());
|
||||
}
|
||||
|
||||
static void SELECT_next_instance_free(void *instance_)
|
||||
{
|
||||
auto *instance = (Instance *)instance_;
|
||||
if (instance != nullptr) {
|
||||
delete instance;
|
||||
}
|
||||
}
|
||||
|
||||
static const DrawEngineDataSize SELECT_next_data_size = DRW_VIEWPORT_DATA_SIZE(SELECT_NextData);
|
||||
|
||||
DrawEngineType draw_engine_select_next_type = {
|
||||
NULL,
|
||||
NULL,
|
||||
N_("Select-Next"),
|
||||
&SELECT_next_data_size,
|
||||
&SELECT_next_engine_init,
|
||||
NULL,
|
||||
&SELECT_next_instance_free,
|
||||
&SELECT_next_cache_init,
|
||||
&SELECT_next_cache_populate,
|
||||
&SELECT_next_cache_finish,
|
||||
&SELECT_next_draw_scene,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/** \} */
|
247
source/blender/draw/engines/select/select_instance.hh
Normal file
247
source/blender/draw/engines/select/select_instance.hh
Normal file
@ -0,0 +1,247 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DRW_gpu_wrapper.hh"
|
||||
|
||||
#include "GPU_select.h"
|
||||
|
||||
#include "../intern/gpu_select_private.h"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "select_defines.h"
|
||||
#include "select_shader_shared.hh"
|
||||
|
||||
namespace blender::draw::select {
|
||||
|
||||
enum class SelectionType { DISABLED = 0, ENABLED = 1 };
|
||||
|
||||
class ID {
|
||||
private:
|
||||
uint32_t value;
|
||||
|
||||
/* Add type safety to selection ID. Only the select types should provide them. */
|
||||
ID(uint32_t value) : value(value){};
|
||||
|
||||
friend struct SelectBuf;
|
||||
friend struct SelectMap;
|
||||
|
||||
public:
|
||||
uint32_t get() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a dedicated selection id buffer to a pass.
|
||||
* To be used when not using a #PassMain which can pass the select ID via CustomID.
|
||||
*/
|
||||
struct SelectBuf {
|
||||
const SelectionType selection_type;
|
||||
|
||||
StorageVectorBuffer<uint32_t> select_buf = {"select_buf"};
|
||||
|
||||
SelectBuf(const SelectionType selection_type) : selection_type(selection_type){};
|
||||
|
||||
void select_clear()
|
||||
{
|
||||
if (selection_type != SelectionType::DISABLED) {
|
||||
select_buf.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void select_append(ID select_id)
|
||||
{
|
||||
if (selection_type != SelectionType::DISABLED) {
|
||||
select_buf.append(select_id.get());
|
||||
}
|
||||
}
|
||||
|
||||
void select_bind(PassSimple &pass)
|
||||
{
|
||||
if (selection_type != SelectionType::DISABLED) {
|
||||
select_buf.push_update();
|
||||
pass.bind_ssbo(SELECT_ID_IN, &select_buf);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate selection IDs from objects and keep record of the mapping between them.
|
||||
* The id's are contiguous so that we can create a destination buffer.
|
||||
*/
|
||||
struct SelectMap {
|
||||
const SelectionType selection_type;
|
||||
|
||||
/** Mapping between internal IDs and `object->runtime.select_id`. */
|
||||
Vector<uint> select_id_map;
|
||||
#ifdef DEBUG
|
||||
/** Debug map containing a copy of the object name. */
|
||||
Vector<std::string> map_names;
|
||||
#endif
|
||||
/** Stores the result of the whole selection drawing. Content depends on selection mode. */
|
||||
StorageArrayBuffer<uint> select_output_buf = {"select_output_buf"};
|
||||
/** Dummy buffer. Might be better to remove, but simplify the shader create info patching. */
|
||||
StorageArrayBuffer<uint, 4, true> dummy_select_buf = {"dummy_select_buf"};
|
||||
/** Uniform buffer to bind to all passes to pass information about the selection state. */
|
||||
UniformBuffer<SelectInfoData> info_buf;
|
||||
/** Will remove the depth test state from any pass drawing objects with select id. */
|
||||
bool disable_depth_test;
|
||||
|
||||
SelectMap(const SelectionType selection_type) : selection_type(selection_type){};
|
||||
|
||||
/* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object
|
||||
* reference directly. This would isolate the selection logic to this class. */
|
||||
[[nodiscard]] const ID select_id(const ObjectRef &ob_ref, uint sub_object_id = 0)
|
||||
{
|
||||
if (selection_type == SelectionType::DISABLED) {
|
||||
return {0};
|
||||
}
|
||||
|
||||
uint object_id = ob_ref.object->runtime.select_id;
|
||||
uint id = select_id_map.append_and_get_index(object_id | sub_object_id);
|
||||
#ifdef DEBUG
|
||||
map_names.append(ob_ref.object->id.name);
|
||||
#endif
|
||||
return {id};
|
||||
}
|
||||
|
||||
/* Load an invalid index that will not write to the output (not selectable). */
|
||||
[[nodiscard]] const ID select_invalid_id()
|
||||
{
|
||||
return {uint32_t(-1)};
|
||||
}
|
||||
|
||||
void begin_sync()
|
||||
{
|
||||
if (selection_type == SelectionType::DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (gpu_select_next_get_mode()) {
|
||||
case GPU_SELECT_ALL:
|
||||
info_buf.mode = SelectType::SELECT_ALL;
|
||||
disable_depth_test = true;
|
||||
break;
|
||||
/* Not sure if these 2 NEAREST are mapped to the right algorithm. */
|
||||
case GPU_SELECT_NEAREST_FIRST_PASS:
|
||||
case GPU_SELECT_NEAREST_SECOND_PASS:
|
||||
case GPU_SELECT_PICK_ALL:
|
||||
info_buf.mode = SelectType::SELECT_PICK_ALL;
|
||||
info_buf.cursor = int2(gpu_select_next_get_pick_area_center());
|
||||
disable_depth_test = true;
|
||||
break;
|
||||
case GPU_SELECT_PICK_NEAREST:
|
||||
info_buf.mode = SelectType::SELECT_PICK_NEAREST;
|
||||
info_buf.cursor = int2(gpu_select_next_get_pick_area_center());
|
||||
disable_depth_test = true;
|
||||
break;
|
||||
}
|
||||
info_buf.push_update();
|
||||
|
||||
select_id_map.clear();
|
||||
#ifdef DEBUG
|
||||
map_names.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state_set. */
|
||||
void select_bind(PassSimple &pass)
|
||||
{
|
||||
if (selection_type == SelectionType::DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (disable_depth_test) {
|
||||
/* TODO: clipping state. */
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||
}
|
||||
pass.bind_ubo(SELECT_DATA, &info_buf);
|
||||
pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
|
||||
}
|
||||
|
||||
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state_set. */
|
||||
void select_bind(PassMain &pass)
|
||||
{
|
||||
if (selection_type == SelectionType::DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
pass.use_custom_ids = true;
|
||||
if (disable_depth_test) {
|
||||
/* TODO: clipping state. */
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||
}
|
||||
pass.bind_ubo(SELECT_DATA, &info_buf);
|
||||
/* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */
|
||||
pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf);
|
||||
pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
|
||||
}
|
||||
|
||||
void end_sync()
|
||||
{
|
||||
if (selection_type == SelectionType::DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4));
|
||||
select_output_buf.push_update();
|
||||
if (info_buf.mode == SelectType::SELECT_ALL) {
|
||||
/* This mode uses atomicOr and store result as a bitmap. Clear to 0 (no selection). */
|
||||
GPU_storagebuf_clear(select_output_buf, 0);
|
||||
}
|
||||
else {
|
||||
/* Other modes use atomicMin. Clear to UINT_MAX. */
|
||||
GPU_storagebuf_clear(select_output_buf, 0xFFFFFFFFu);
|
||||
}
|
||||
}
|
||||
|
||||
void read_result()
|
||||
{
|
||||
if (selection_type == SelectionType::DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||
select_output_buf.read();
|
||||
|
||||
Vector<GPUSelectResult> result;
|
||||
|
||||
/* Convert raw data from GPU to #GPUSelectResult. */
|
||||
switch (info_buf.mode) {
|
||||
case SelectType::SELECT_ALL:
|
||||
for (auto i : IndexRange(select_id_map.size())) {
|
||||
if (((select_output_buf[i / 32] >> (i % 32)) & 1) != 0) {
|
||||
result.append({select_id_map[i], 0xFFFFu});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SelectType::SELECT_PICK_ALL:
|
||||
case SelectType::SELECT_PICK_NEAREST:
|
||||
for (auto i : IndexRange(select_id_map.size())) {
|
||||
if (select_output_buf[i] != 0xFFFFFFFFu) {
|
||||
/* NOTE: For `SELECT_PICK_NEAREST`, `select_output_buf` also contains the screen
|
||||
* distance to cursor in the lowest bits. */
|
||||
result.append({select_id_map[i], select_output_buf[i]});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
gpu_select_next_set_result(result.data(), result.size());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::select
|
28
source/blender/draw/engines/select/select_shader_shared.hh
Normal file
28
source/blender/draw/engines/select/select_shader_shared.hh
Normal file
@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef GPU_SHADER
|
||||
# pragma once
|
||||
|
||||
# include "GPU_shader_shared_utils.h"
|
||||
|
||||
namespace blender::draw::select {
|
||||
|
||||
#endif
|
||||
|
||||
/* Matches eV3DSelectMode */
|
||||
enum SelectType : uint32_t {
|
||||
SELECT_ALL = 0u,
|
||||
SELECT_PICK_ALL = 1u,
|
||||
SELECT_PICK_NEAREST = 2u,
|
||||
};
|
||||
|
||||
struct SelectInfoData {
|
||||
int2 cursor;
|
||||
SelectType mode;
|
||||
uint _pad0;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(SelectInfoData, 16)
|
||||
|
||||
#ifndef GPU_SHADER
|
||||
} // namespace blender::draw::select
|
||||
#endif
|
@ -1,12 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
#include "select_defines.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Select ID for Edit Mesh Selection
|
||||
* \{ */
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "id");
|
||||
GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "select_id");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(select_id_flat)
|
||||
.push_constant(Type::FLOAT, "sizeVertex")
|
||||
@ -24,7 +25,7 @@ GPU_SHADER_CREATE_INFO(select_id_flat)
|
||||
GPU_SHADER_CREATE_INFO(select_id_uniform)
|
||||
.define("UNIFORM_ID")
|
||||
.push_constant(Type::FLOAT, "sizeVertex")
|
||||
.push_constant(Type::INT, "id")
|
||||
.push_constant(Type::INT, "select_id")
|
||||
.push_constant(Type::FLOAT, "retopologyOffset")
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.fragment_out(0, Type::UINT, "fragColor")
|
||||
@ -42,4 +43,17 @@ GPU_SHADER_CREATE_INFO(select_id_uniform_clipped)
|
||||
.additional_info("select_id_uniform")
|
||||
.additional_info("drw_clipped")
|
||||
.do_static_compilation(true);
|
||||
|
||||
/* Used to patch overlay shaders. */
|
||||
GPU_SHADER_CREATE_INFO(select_id_patch)
|
||||
.typedef_source("select_shader_shared.hh")
|
||||
.vertex_out(select_id_iface)
|
||||
/* Need to make sure the depth & stencil comparison runs before the fragment shader. */
|
||||
.early_fragment_test(true)
|
||||
.uniform_buf(SELECT_DATA, "SelectInfoData", "select_info_buf")
|
||||
/* Select IDs for instanced draw-calls not using #PassMain. */
|
||||
.storage_buf(SELECT_ID_IN, Qualifier::READ, "int", "in_select_buf[]")
|
||||
/* Stores the result of the whole selection drawing. Content depends on selection mode. */
|
||||
.storage_buf(SELECT_ID_OUT, Qualifier::READ_WRITE, "uint", "out_select_buf[]");
|
||||
|
||||
/** \} */
|
||||
|
@ -1,4 +1,4 @@
|
||||
void main()
|
||||
{
|
||||
fragColor = floatBitsToUint(intBitsToFloat(id));
|
||||
fragColor = floatBitsToUint(intBitsToFloat(select_id));
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
void main()
|
||||
{
|
||||
#ifndef UNIFORM_ID
|
||||
id = offset + index;
|
||||
select_id = offset + index;
|
||||
#endif
|
||||
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
|
49
source/blender/draw/engines/select/shaders/select_lib.glsl
Normal file
49
source/blender/draw/engines/select/shaders/select_lib.glsl
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
#ifndef SELECT_ENABLE
|
||||
/* Avoid requesting the select_id when not in selection mode. */
|
||||
# define select_id_set(select_id)
|
||||
# define select_id_output(select_id)
|
||||
|
||||
#elif defined(GPU_VERTEX_SHADER)
|
||||
|
||||
void select_id_set(int id)
|
||||
{
|
||||
/* Declared in the create info. */
|
||||
select_id = id;
|
||||
}
|
||||
|
||||
#elif defined(GPU_FRAGMENT_SHADER)
|
||||
|
||||
void select_id_output(int id)
|
||||
{
|
||||
if (id == -1) {
|
||||
/* Invalid index */
|
||||
return;
|
||||
}
|
||||
|
||||
if (select_info_buf.mode == SELECT_ALL) {
|
||||
/* Set the bit of the select id in the bitmap. */
|
||||
atomicOr(out_select_buf[id / 32u], 1u << (uint(id) % 32u));
|
||||
}
|
||||
else if (select_info_buf.mode == SELECT_PICK_ALL) {
|
||||
/* Stores the nearest depth for this select id. */
|
||||
atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z));
|
||||
}
|
||||
else if (select_info_buf.mode == SELECT_PICK_NEAREST) {
|
||||
/* Stores the nearest depth with the distance to the cursor. */
|
||||
|
||||
/* Distance function to the cursor. Currently a simple pixel ring distance. */
|
||||
ivec2 coord = abs(ivec2(gl_FragCoord.xy) - select_info_buf.cursor);
|
||||
uint dist = uint(max(coord.x, coord.y));
|
||||
|
||||
uint depth = uint(gl_FragCoord.z * float(0x00FFFFFFu));
|
||||
|
||||
/* Reject hits outside of valid range. */
|
||||
if (dist < 0xFFu) {
|
||||
/* Packed values to ensure the atomicMin is performed on the whole result. */
|
||||
atomicMin(out_select_buf[id], (depth << 8u) | dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1204,7 +1204,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.
|
||||
@ -1223,7 +1224,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)
|
||||
@ -1241,7 +1243,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2458,7 +2461,10 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||
DST.options.is_material_select = do_material_sub_selection;
|
||||
drw_task_graph_init();
|
||||
/* Get list of enabled engines */
|
||||
if (use_obedit) {
|
||||
if (U.experimental.enable_overlay_next) {
|
||||
use_drw_engine(&draw_engine_select_next_type);
|
||||
}
|
||||
else if (use_obedit) {
|
||||
drw_engines_enable_overlays();
|
||||
}
|
||||
else if (!draw_surface) {
|
||||
@ -2567,6 +2573,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||
draw_select_framebuffer_depth_only_setup(viewport_size);
|
||||
GPU_framebuffer_bind(g_select_buffer.framebuffer_depth_only);
|
||||
GPU_framebuffer_clear_depth(g_select_buffer.framebuffer_depth_only, 1.0f);
|
||||
/* WORKAROUND: Needed for Select-Next for keeping the same codeflow as Overlay-Next. */
|
||||
BLI_assert(DRW_viewport_texture_list_get()->depth == NULL);
|
||||
DRW_viewport_texture_list_get()->depth = g_select_buffer.texture_depth;
|
||||
|
||||
/* Start Drawing */
|
||||
DRW_state_reset();
|
||||
@ -2579,11 +2588,15 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||
if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) {
|
||||
break;
|
||||
}
|
||||
DRW_state_lock(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_TEST_ENABLED);
|
||||
if (!U.experimental.enable_overlay_next) {
|
||||
DRW_state_lock(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_TEST_ENABLED);
|
||||
}
|
||||
|
||||
drw_engines_draw_scene();
|
||||
|
||||
DRW_state_lock(0);
|
||||
if (!U.experimental.enable_overlay_next) {
|
||||
DRW_state_lock(0);
|
||||
}
|
||||
|
||||
if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) {
|
||||
break;
|
||||
@ -2592,6 +2605,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||
|
||||
DRW_smoke_exit(DST.vmempool);
|
||||
|
||||
/* WORKAROUND: Do not leave ownership to the viewport list. */
|
||||
DRW_viewport_texture_list_get()->depth = NULL;
|
||||
|
||||
DRW_state_reset();
|
||||
drw_engines_disable();
|
||||
|
||||
@ -3031,6 +3047,8 @@ 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_next_type);
|
||||
DRW_engine_register(&draw_engine_select_type);
|
||||
DRW_engine_register(&draw_engine_basic_type);
|
||||
DRW_engine_register(&draw_engine_compositor_type);
|
||||
|
@ -1285,11 +1285,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.
|
||||
|
@ -852,15 +852,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
|
||||
static void view3d_grid_steps_ex(const Scene *scene,
|
||||
View3D *v3d,
|
||||
RegionView3D *rv3d,
|
||||
const View3D *v3d,
|
||||
const RegionView3D *rv3d,
|
||||
float r_grid_steps[STEPS_LEN],
|
||||
void const **r_usys_pt,
|
||||
int *r_len)
|
||||
@ -912,8 +912,8 @@ static void view3d_grid_steps_ex(const Scene *scene,
|
||||
}
|
||||
|
||||
void ED_view3d_grid_steps(const Scene *scene,
|
||||
View3D *v3d,
|
||||
RegionView3D *rv3d,
|
||||
const View3D *v3d,
|
||||
const RegionView3D *rv3d,
|
||||
float r_grid_steps[STEPS_LEN])
|
||||
{
|
||||
view3d_grid_steps_ex(scene, v3d, rv3d, r_grid_steps, nullptr, nullptr);
|
||||
|
@ -487,7 +487,7 @@ static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
|
||||
bool continue_pass = false;
|
||||
struct DrawSelectLoopUserData *data = user_data;
|
||||
if (stage == DRW_SELECT_PASS_PRE) {
|
||||
GPU_select_begin(
|
||||
GPU_select_begin_next(
|
||||
data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
|
||||
/* always run POST after PRE. */
|
||||
continue_pass = true;
|
||||
@ -599,7 +599,7 @@ int view3d_opengl_select_ex(ViewContext *vc,
|
||||
/* Re-use cache (rect must be smaller than the cached)
|
||||
* other context is assumed to be unchanged */
|
||||
if (GPU_select_is_cached()) {
|
||||
GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0);
|
||||
GPU_select_begin_next(buffer, buffer_len, &rect, gpu_select_mode, 0);
|
||||
GPU_select_cache_load_id();
|
||||
hits = GPU_select_end();
|
||||
goto finally;
|
||||
|
@ -29,6 +29,7 @@ set(INC
|
||||
# For *_info.hh includes.
|
||||
../compositor/realtime_compositor
|
||||
../draw/engines/eevee_next
|
||||
../draw/engines/select
|
||||
../draw/engines/workbench
|
||||
../draw/intern
|
||||
|
||||
@ -76,6 +77,7 @@ set(SRC
|
||||
intern/gpu_platform.cc
|
||||
intern/gpu_query.cc
|
||||
intern/gpu_select.c
|
||||
intern/gpu_select_next.cc
|
||||
intern/gpu_select_pick.c
|
||||
intern/gpu_select_sample_query.cc
|
||||
intern/gpu_shader.cc
|
||||
|
@ -50,6 +50,15 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||
const struct rcti *input,
|
||||
eGPUSelectMode mode,
|
||||
int oldhits);
|
||||
/**
|
||||
* Initialize and provide buffer for results.
|
||||
* Uses the new Select-Next engine if enabled.
|
||||
*/
|
||||
void GPU_select_begin_next(GPUSelectResult *buffer,
|
||||
const uint buffer_len,
|
||||
const struct rcti *input,
|
||||
eGPUSelectMode mode,
|
||||
int oldhits);
|
||||
/**
|
||||
* Loads a new selection id and ends previous query, if any.
|
||||
* In second pass of selection it also returns
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "GPU_select.h"
|
||||
|
||||
#include "BLI_rect.h"
|
||||
@ -30,6 +32,8 @@ typedef enum eGPUSelectAlgo {
|
||||
/** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c`
|
||||
* Only sets 4th component (ID) correctly. */
|
||||
ALGO_GL_PICK = 2,
|
||||
/** Use Select-Next draw engine. */
|
||||
ALGO_SELECT_NEXT = 3,
|
||||
} eGPUSelectAlgo;
|
||||
|
||||
typedef struct GPUSelectState {
|
||||
@ -60,11 +64,12 @@ static GPUSelectState g_select_state = {0};
|
||||
/** \name Public API
|
||||
* \{ */
|
||||
|
||||
void GPU_select_begin(GPUSelectResult *buffer,
|
||||
const uint buffer_len,
|
||||
const rcti *input,
|
||||
eGPUSelectMode mode,
|
||||
int oldhits)
|
||||
static void gpu_select_begin_ex(GPUSelectResult *buffer,
|
||||
const uint buffer_len,
|
||||
const rcti *input,
|
||||
eGPUSelectMode mode,
|
||||
int oldhits,
|
||||
bool use_select_next)
|
||||
{
|
||||
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
|
||||
/* In the case hits was '-1',
|
||||
@ -76,7 +81,10 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||
g_select_state.select_is_active = true;
|
||||
g_select_state.mode = mode;
|
||||
|
||||
if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) {
|
||||
if (use_select_next) {
|
||||
g_select_state.algorithm = ALGO_SELECT_NEXT;
|
||||
}
|
||||
else if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) {
|
||||
g_select_state.algorithm = ALGO_GL_PICK;
|
||||
}
|
||||
else {
|
||||
@ -89,6 +97,7 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||
g_select_state.use_cache_needs_init = false;
|
||||
|
||||
switch (g_select_state.algorithm) {
|
||||
case ALGO_SELECT_NEXT:
|
||||
case ALGO_GL_QUERY: {
|
||||
g_select_state.use_cache = false;
|
||||
break;
|
||||
@ -102,6 +111,10 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||
}
|
||||
|
||||
switch (g_select_state.algorithm) {
|
||||
case ALGO_SELECT_NEXT: {
|
||||
gpu_select_next_begin(buffer, buffer_len, input, mode);
|
||||
break;
|
||||
}
|
||||
case ALGO_GL_QUERY: {
|
||||
gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits);
|
||||
break;
|
||||
@ -114,6 +127,25 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_select_begin_next(GPUSelectResult *buffer,
|
||||
const uint buffer_len,
|
||||
const rcti *input,
|
||||
eGPUSelectMode mode,
|
||||
int oldhits)
|
||||
{
|
||||
gpu_select_begin_ex(
|
||||
buffer, buffer_len, input, mode, oldhits, U.experimental.enable_overlay_next);
|
||||
}
|
||||
|
||||
void GPU_select_begin(GPUSelectResult *buffer,
|
||||
const uint buffer_len,
|
||||
const rcti *input,
|
||||
eGPUSelectMode mode,
|
||||
int oldhits)
|
||||
{
|
||||
gpu_select_begin_ex(buffer, buffer_len, input, mode, oldhits, false);
|
||||
}
|
||||
|
||||
bool GPU_select_load_id(uint id)
|
||||
{
|
||||
/* if no selection mode active, ignore */
|
||||
@ -122,6 +154,11 @@ bool GPU_select_load_id(uint id)
|
||||
}
|
||||
|
||||
switch (g_select_state.algorithm) {
|
||||
case ALGO_SELECT_NEXT:
|
||||
/* This shouldn't use this pipeline. */
|
||||
BLI_assert_unreachable();
|
||||
return 0;
|
||||
|
||||
case ALGO_GL_QUERY: {
|
||||
return gpu_select_query_load_id(id);
|
||||
}
|
||||
@ -137,6 +174,10 @@ uint GPU_select_end(void)
|
||||
uint hits = 0;
|
||||
|
||||
switch (g_select_state.algorithm) {
|
||||
case ALGO_SELECT_NEXT: {
|
||||
hits = gpu_select_next_end();
|
||||
break;
|
||||
}
|
||||
case ALGO_GL_QUERY: {
|
||||
hits = gpu_select_query_end();
|
||||
break;
|
||||
|
91
source/blender/gpu/intern/gpu_select_next.cc
Normal file
91
source/blender/gpu/intern/gpu_select_next.cc
Normal file
@ -0,0 +1,91 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2017 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*
|
||||
* Glue to make the new Select-Next engine work with the old GPU select API.
|
||||
*/
|
||||
#include <float.h>
|
||||
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "GPU_select.h"
|
||||
|
||||
#include "gpu_select_private.h"
|
||||
|
||||
struct GPUSelectNextState {
|
||||
/** Result buffer set on initialization. */
|
||||
GPUSelectResult *buffer;
|
||||
uint buffer_len;
|
||||
/** Area of the viewport to render / select from. */
|
||||
rcti rect;
|
||||
/** Number of hits. Set to -1 if it overflows buffer_len. */
|
||||
uint hits;
|
||||
/** Mode of operation. */
|
||||
eGPUSelectMode mode;
|
||||
};
|
||||
|
||||
static GPUSelectNextState g_state = {};
|
||||
|
||||
void gpu_select_next_begin(GPUSelectResult *buffer,
|
||||
uint buffer_len,
|
||||
const rcti *input,
|
||||
eGPUSelectMode mode)
|
||||
|
||||
{
|
||||
g_state.buffer = buffer;
|
||||
g_state.rect = *input;
|
||||
g_state.buffer_len = buffer_len;
|
||||
g_state.mode = mode;
|
||||
}
|
||||
|
||||
int gpu_select_next_get_pick_area_center()
|
||||
{
|
||||
BLI_assert(BLI_rcti_size_x(&g_state.rect) == BLI_rcti_size_y(&g_state.rect));
|
||||
return BLI_rcti_size_x(&g_state.rect) / 2;
|
||||
}
|
||||
|
||||
eGPUSelectMode gpu_select_next_get_mode()
|
||||
{
|
||||
return g_state.mode;
|
||||
}
|
||||
|
||||
void gpu_select_next_set_result(GPUSelectResult *hit_buf, uint hit_len)
|
||||
|
||||
{
|
||||
if (hit_len > g_state.buffer_len) {
|
||||
g_state.hits = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
blender::MutableSpan<GPUSelectResult> result(g_state.buffer, g_state.buffer_len);
|
||||
blender::Span<GPUSelectResult> hits(hit_buf, hit_len);
|
||||
|
||||
/* TODO(fclem): There might be some conversion to do to align to the other APIs output. */
|
||||
switch (g_state.mode) {
|
||||
case eGPUSelectMode::GPU_SELECT_ALL:
|
||||
result.take_front(hit_len).copy_from(hits);
|
||||
break;
|
||||
case eGPUSelectMode::GPU_SELECT_NEAREST_FIRST_PASS:
|
||||
result.take_front(hit_len).copy_from(hits);
|
||||
break;
|
||||
case eGPUSelectMode::GPU_SELECT_NEAREST_SECOND_PASS:
|
||||
result.take_front(hit_len).copy_from(hits);
|
||||
break;
|
||||
case eGPUSelectMode::GPU_SELECT_PICK_ALL:
|
||||
result.take_front(hit_len).copy_from(hits);
|
||||
break;
|
||||
case eGPUSelectMode::GPU_SELECT_PICK_NEAREST:
|
||||
result.take_front(hit_len).copy_from(hits);
|
||||
break;
|
||||
}
|
||||
|
||||
g_state.hits = hit_len;
|
||||
}
|
||||
|
||||
uint gpu_select_next_end()
|
||||
{
|
||||
return g_state.hits;
|
||||
}
|
@ -37,6 +37,19 @@ void gpu_select_query_begin(
|
||||
bool gpu_select_query_load_id(uint id);
|
||||
uint gpu_select_query_end(void);
|
||||
|
||||
/* gpu_select_next */
|
||||
|
||||
void gpu_select_next_begin(GPUSelectResult *buffer,
|
||||
uint buffer_len,
|
||||
const rcti *input,
|
||||
eGPUSelectMode mode);
|
||||
uint gpu_select_next_end(void);
|
||||
|
||||
/* Return a single offset since picking uses squared viewport. */
|
||||
int gpu_select_next_get_pick_area_center(void);
|
||||
eGPUSelectMode gpu_select_next_get_mode(void);
|
||||
void gpu_select_next_set_result(GPUSelectResult *buffer, uint buffer_len);
|
||||
|
||||
#define SELECT_ID_NONE ((uint)0xffffffff)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -675,9 +675,10 @@ 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 use_new_volume_nodes;
|
||||
char _pad[6];
|
||||
char _pad[5];
|
||||
/** `makesdna` does not allow empty structs. */
|
||||
} UserDef_Experimental;
|
||||
|
||||
|
@ -6652,6 +6652,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,
|
||||
|
Loading…
Reference in New Issue
Block a user