Refactor: DRW: Make DrawEngine a virtual class
This removes the old `DrawEngineType` and use the new `DrawEngine` virtual class instead. This removes a lot of boilerplate functions that were only there for legacy reason. To this end, some engines that were based on static functions have been refactored into `Instance` classes. This was particularly cumbersome for the Grease pencil engine which needed some more refactoring. The `Engine` class that is in each namespace is a workaround to isolate the internal implementation (i.e. the `Instance`) to the engine modules. Without this, the whole engine is getting included in each compile unit that includes the `Instance` class. Eventually, if we get rid of these intricate dependencies, we could remove the `Engine` class. Pull Request: https://projects.blender.org/blender/blender/pulls/136001
This commit is contained in:
committed by
Clément Foucault
parent
070a4cc9ee
commit
92968c23fe
@@ -140,7 +140,6 @@ set(SRC
|
||||
engines/gpencil/gpencil_draw_data.cc
|
||||
engines/gpencil/gpencil_engine_c.cc
|
||||
engines/gpencil/gpencil_render.cc
|
||||
engines/gpencil/gpencil_shader_c.cc
|
||||
engines/gpencil/gpencil_shader_fx.cc
|
||||
engines/select/select_engine.cc
|
||||
engines/select/select_instance.cc
|
||||
@@ -220,7 +219,9 @@ set(SRC
|
||||
engines/eevee_next/eevee_volume.hh
|
||||
engines/eevee_next/eevee_world.hh
|
||||
engines/external/external_engine.h
|
||||
engines/gpencil/gpencil_engine.h
|
||||
engines/gpencil/gpencil_engine_private.hh
|
||||
engines/gpencil/gpencil_engine.hh
|
||||
engines/gpencil/gpencil_shader.hh
|
||||
engines/image/image_batches.hh
|
||||
engines/image/image_buffer_cache.hh
|
||||
engines/image/image_drawing_mode.hh
|
||||
@@ -281,7 +282,6 @@ set(SRC
|
||||
engines/select/select_defines.hh
|
||||
engines/select/select_engine.hh
|
||||
engines/select/select_instance.hh
|
||||
engines/select/select_private.hh
|
||||
engines/workbench/workbench_defines.hh
|
||||
engines/workbench/workbench_engine.h
|
||||
engines/workbench/workbench_enums.hh
|
||||
|
||||
@@ -13,7 +13,6 @@ struct DRWData;
|
||||
struct DRWInstanceDataList;
|
||||
struct Depsgraph;
|
||||
struct DrawDataList;
|
||||
struct DrawEngineType;
|
||||
struct GPUMaterial;
|
||||
struct GPUOffScreen;
|
||||
struct GPUVertFormat;
|
||||
@@ -109,10 +108,8 @@ bool DRW_draw_in_progress();
|
||||
*/
|
||||
bool DRW_render_check_grease_pencil(Depsgraph *depsgraph);
|
||||
/**
|
||||
* Render grease pencil on top of other render engine output (but only for non-draw-engine).
|
||||
* Render grease pencil on top of other render engine output.
|
||||
* This function creates a DRWContext.
|
||||
* `DRW_render_to_image()` applies grease pencil using `DRW_render_gpencil_to_image` as it
|
||||
* already has a DRWContext setup.
|
||||
*/
|
||||
void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph);
|
||||
|
||||
|
||||
@@ -196,90 +196,63 @@ class Context : public compositor::Context {
|
||||
}
|
||||
};
|
||||
|
||||
class Engine {
|
||||
class Instance : public DrawEngine {
|
||||
private:
|
||||
Context context_;
|
||||
|
||||
public:
|
||||
Engine(char *info_message) : context_(info_message) {}
|
||||
Instance() : context_(this->info) {}
|
||||
|
||||
void draw()
|
||||
StringRefNull name_get() final
|
||||
{
|
||||
compositor::Evaluator evaluator(context_);
|
||||
evaluator.evaluate();
|
||||
return "Compositor";
|
||||
}
|
||||
|
||||
void init() final{};
|
||||
void begin_sync() final{};
|
||||
void object_sync(blender::draw::ObjectRef & /*ob_ref*/,
|
||||
blender::draw::Manager & /*manager*/) final{};
|
||||
void end_sync() final{};
|
||||
|
||||
void draw(Manager & /*manager*/) final
|
||||
{
|
||||
DRW_submission_start();
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (GPU_backend_get_type() == GPU_BACKEND_METAL) {
|
||||
/* NOTE(Metal): Isolate Compositor compute work in individual command buffer to improve
|
||||
* workload scheduling. When expensive compositor nodes are in the graph, these can stall out
|
||||
* the GPU for extended periods of time and sub-optimally schedule work for execution. */
|
||||
GPU_flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Execute Compositor render commands. */
|
||||
{
|
||||
compositor::Evaluator evaluator(context_);
|
||||
evaluator.evaluate();
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* NOTE(Metal): Following previous flush to break command stream, with compositor command
|
||||
* buffers potentially being heavy, we avoid issuing subsequent commands until compositor work
|
||||
* has completed. If subsequent work is prematurely queued up, the subsequent command buffers
|
||||
* will be blocked behind compositor work and may trigger a command buffer time-out error. As a
|
||||
* result, we should wait for compositor work to complete.
|
||||
*
|
||||
* This is not an efficient approach for peak performance, but a catch-all to prevent command
|
||||
* buffer failure, until the offending cases can be resolved. */
|
||||
if (GPU_backend_get_type() == GPU_BACKEND_METAL) {
|
||||
GPU_finish();
|
||||
}
|
||||
#endif
|
||||
DRW_submission_end();
|
||||
}
|
||||
};
|
||||
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
} // namespace blender::draw::compositor_engine
|
||||
|
||||
using namespace blender::draw::compositor_engine;
|
||||
|
||||
struct COMPOSITOR_Data {
|
||||
DrawEngineType *engine_type;
|
||||
Engine *instance_data;
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
|
||||
static void compositor_engine_init(void *data)
|
||||
{
|
||||
COMPOSITOR_Data *compositor_data = static_cast<COMPOSITOR_Data *>(data);
|
||||
|
||||
if (!compositor_data->instance_data) {
|
||||
compositor_data->instance_data = new Engine(compositor_data->info);
|
||||
}
|
||||
}
|
||||
|
||||
static void compositor_engine_free(void *instance_data)
|
||||
{
|
||||
Engine *engine = static_cast<Engine *>(instance_data);
|
||||
delete engine;
|
||||
}
|
||||
|
||||
static void compositor_engine_draw(void *data)
|
||||
{
|
||||
COMPOSITOR_Data *compositor_data = static_cast<COMPOSITOR_Data *>(data);
|
||||
|
||||
DRW_submission_start();
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (GPU_backend_get_type() == GPU_BACKEND_METAL) {
|
||||
/* NOTE(Metal): Isolate Compositor compute work in individual command buffer to improve
|
||||
* workload scheduling. When expensive compositor nodes are in the graph, these can stall out
|
||||
* the GPU for extended periods of time and sub-optimally schedule work for execution. */
|
||||
GPU_flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Execute Compositor render commands. */
|
||||
compositor_data->instance_data->draw();
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* NOTE(Metal): Following previous flush to break command stream, with compositor command
|
||||
* buffers potentially being heavy, we avoid issuing subsequent commands until compositor work
|
||||
* has completed. If subsequent work is prematurely queued up, the subsequent command buffers
|
||||
* will be blocked behind compositor work and may trigger a command buffer time-out error. As a
|
||||
* result, we should wait for compositor work to complete.
|
||||
*
|
||||
* This is not an efficient approach for peak performance, but a catch-all to prevent command
|
||||
* buffer failure, until the offending cases can be resolved. */
|
||||
if (GPU_backend_get_type() == GPU_BACKEND_METAL) {
|
||||
GPU_finish();
|
||||
}
|
||||
#endif
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
DrawEngineType draw_engine_compositor_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("Compositor"),
|
||||
/*engine_init*/ &compositor_engine_init,
|
||||
/*engine_free*/ nullptr,
|
||||
/*instance_free*/ &compositor_engine_free,
|
||||
/*cache_init*/ nullptr,
|
||||
/*cache_populate*/ nullptr,
|
||||
/*cache_finish*/ nullptr,
|
||||
/*draw_scene*/ &compositor_engine_draw,
|
||||
/*render_to_image*/ nullptr,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct DrawEngineType;
|
||||
#include "DRW_render.hh"
|
||||
|
||||
extern DrawEngineType draw_engine_compositor_type;
|
||||
namespace blender::draw::compositor_engine {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
};
|
||||
|
||||
} // namespace blender::draw::compositor_engine
|
||||
|
||||
@@ -19,177 +19,60 @@
|
||||
|
||||
#include "eevee_instance.hh"
|
||||
|
||||
using namespace blender;
|
||||
namespace blender::eevee {
|
||||
|
||||
struct EEVEE_Data {
|
||||
DrawEngineType *engine_type;
|
||||
eevee::Instance *instance;
|
||||
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
|
||||
static void eevee_engine_init(void *vedata)
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
EEVEE_Data *ved = reinterpret_cast<EEVEE_Data *>(vedata);
|
||||
if (ved->instance == nullptr) {
|
||||
ved->instance = new eevee::Instance();
|
||||
}
|
||||
|
||||
const DRWContext *ctx_state = DRW_context_get();
|
||||
Depsgraph *depsgraph = ctx_state->depsgraph;
|
||||
Scene *scene = ctx_state->scene;
|
||||
View3D *v3d = ctx_state->v3d;
|
||||
ARegion *region = ctx_state->region;
|
||||
RegionView3D *rv3d = ctx_state->rv3d;
|
||||
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
int2 size = int2(GPU_texture_width(dtxl->color), GPU_texture_height(dtxl->color));
|
||||
|
||||
draw::View &default_view = draw::View::default_get();
|
||||
|
||||
Object *camera = nullptr;
|
||||
/* Get render borders. */
|
||||
rcti rect;
|
||||
BLI_rcti_init(&rect, 0, size[0], 0, size[1]);
|
||||
rcti visible_rect = rect;
|
||||
if (v3d) {
|
||||
if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
|
||||
camera = v3d->camera;
|
||||
}
|
||||
|
||||
if (camera) {
|
||||
rctf default_border;
|
||||
BLI_rctf_init(&default_border, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
bool is_default_border = BLI_rctf_compare(&scene->r.border, &default_border, 0.0f);
|
||||
bool use_border = scene->r.mode & R_BORDER;
|
||||
if (!is_default_border && use_border) {
|
||||
rctf viewborder;
|
||||
/* TODO(fclem) Might be better to get it from DRW. */
|
||||
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, false, &viewborder);
|
||||
float viewborder_sizex = BLI_rctf_size_x(&viewborder);
|
||||
float viewborder_sizey = BLI_rctf_size_y(&viewborder);
|
||||
rect.xmin = floorf(viewborder.xmin + (scene->r.border.xmin * viewborder_sizex));
|
||||
rect.ymin = floorf(viewborder.ymin + (scene->r.border.ymin * viewborder_sizey));
|
||||
rect.xmax = floorf(viewborder.xmin + (scene->r.border.xmax * viewborder_sizex));
|
||||
rect.ymax = floorf(viewborder.ymin + (scene->r.border.ymax * viewborder_sizey));
|
||||
}
|
||||
}
|
||||
else if (v3d->flag2 & V3D_RENDER_BORDER) {
|
||||
rect.xmin = v3d->render_border.xmin * size[0];
|
||||
rect.ymin = v3d->render_border.ymin * size[1];
|
||||
rect.xmax = v3d->render_border.xmax * size[0];
|
||||
rect.ymax = v3d->render_border.ymax * size[1];
|
||||
}
|
||||
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
const float2 vp_size = DRW_viewport_size_get();
|
||||
visible_rect.xmax = vp_size[0];
|
||||
visible_rect.ymax = vp_size[1];
|
||||
visible_rect.xmin = visible_rect.ymin = 0;
|
||||
}
|
||||
else {
|
||||
visible_rect = *ED_region_visible_rect(region);
|
||||
}
|
||||
}
|
||||
|
||||
ved->instance->init(
|
||||
size, &rect, &visible_rect, nullptr, depsgraph, camera, nullptr, &default_view, v3d, rv3d);
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
static void eevee_draw_scene(void *vedata)
|
||||
void Engine::free_static()
|
||||
{
|
||||
EEVEE_Data *ved = reinterpret_cast<EEVEE_Data *>(vedata);
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
ved->instance->draw_viewport_image_render();
|
||||
}
|
||||
else {
|
||||
ved->instance->draw_viewport();
|
||||
}
|
||||
STRNCPY(ved->info, ved->instance->info_get());
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
GPU_framebuffer_viewport_reset(dfbl->default_fb);
|
||||
ShaderModule::module_free();
|
||||
}
|
||||
|
||||
static void eevee_cache_init(void *vedata)
|
||||
} // namespace blender::eevee
|
||||
|
||||
using namespace blender::eevee;
|
||||
|
||||
void eevee_render(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
{
|
||||
reinterpret_cast<EEVEE_Data *>(vedata)->instance->begin_sync();
|
||||
}
|
||||
Instance *instance = nullptr;
|
||||
|
||||
static void eevee_cache_populate(void *vedata, draw::ObjectRef &ob_ref)
|
||||
{
|
||||
reinterpret_cast<EEVEE_Data *>(vedata)->instance->object_sync(ob_ref);
|
||||
}
|
||||
auto eevee_render_to_image = [&](RenderEngine *engine, RenderLayer *layer, const rcti /*rect*/) {
|
||||
Render *render = engine->re;
|
||||
Depsgraph *depsgraph = DRW_context_get()->depsgraph;
|
||||
Object *camera_original_ob = RE_GetCamera(engine->re);
|
||||
const char *viewname = RE_GetActiveRenderView(engine->re);
|
||||
int size[2] = {engine->resolution_x, engine->resolution_y};
|
||||
|
||||
static void eevee_cache_finish(void *vedata)
|
||||
{
|
||||
reinterpret_cast<EEVEE_Data *>(vedata)->instance->end_sync();
|
||||
}
|
||||
/* WORKAROUND: Fails if created in the parent scope. Must be because of lack of active
|
||||
* `DRWContext`. To be revisited. */
|
||||
instance = new Instance();
|
||||
|
||||
static void eevee_engine_free()
|
||||
{
|
||||
eevee::ShaderModule::module_free();
|
||||
}
|
||||
rctf view_rect;
|
||||
rcti rect;
|
||||
RE_GetViewPlane(render, &view_rect, &rect);
|
||||
rcti visible_rect = rect;
|
||||
|
||||
static void eevee_instance_free(void *instance)
|
||||
{
|
||||
delete reinterpret_cast<eevee::Instance *>(instance);
|
||||
}
|
||||
instance->init(size, &rect, &visible_rect, engine, depsgraph, camera_original_ob, layer);
|
||||
instance->render_frame(engine, layer, viewname);
|
||||
};
|
||||
|
||||
static void eevee_render_to_image(void *vedata,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *layer,
|
||||
const rcti * /*rect*/)
|
||||
{
|
||||
eevee::Instance *instance = new eevee::Instance();
|
||||
auto eevee_store_metadata = [&](RenderResult *render_result) {
|
||||
instance->store_metadata(render_result);
|
||||
};
|
||||
|
||||
Render *render = engine->re;
|
||||
Depsgraph *depsgraph = DRW_context_get()->depsgraph;
|
||||
Object *camera_original_ob = RE_GetCamera(engine->re);
|
||||
const char *viewname = RE_GetActiveRenderView(engine->re);
|
||||
int size[2] = {engine->resolution_x, engine->resolution_y};
|
||||
DRW_render_to_image(engine, depsgraph, eevee_render_to_image, eevee_store_metadata);
|
||||
|
||||
rctf view_rect;
|
||||
rcti rect;
|
||||
RE_GetViewPlane(render, &view_rect, &rect);
|
||||
rcti visible_rect = rect;
|
||||
|
||||
instance->init(size, &rect, &visible_rect, engine, depsgraph, camera_original_ob, layer);
|
||||
instance->render_frame(engine, layer, viewname);
|
||||
|
||||
EEVEE_Data *ved = static_cast<EEVEE_Data *>(vedata);
|
||||
delete ved->instance;
|
||||
ved->instance = instance;
|
||||
}
|
||||
|
||||
static void eevee_store_metadata(void *vedata, RenderResult *render_result)
|
||||
{
|
||||
EEVEE_Data *ved = static_cast<EEVEE_Data *>(vedata);
|
||||
eevee::Instance *instance = ved->instance;
|
||||
instance->store_metadata(render_result);
|
||||
delete instance;
|
||||
ved->instance = nullptr;
|
||||
}
|
||||
|
||||
static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
eevee::Instance::update_passes(engine, scene, view_layer);
|
||||
Instance::update_passes(engine, scene, view_layer);
|
||||
}
|
||||
|
||||
DrawEngineType draw_engine_eevee_next_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("EEVEE"),
|
||||
/*engine_init*/ &eevee_engine_init,
|
||||
/*engine_free*/ &eevee_engine_free,
|
||||
/*instance_free*/ &eevee_instance_free,
|
||||
/*cache_init*/ &eevee_cache_init,
|
||||
/*cache_populate*/ &eevee_cache_populate,
|
||||
/*cache_finish*/ &eevee_cache_finish,
|
||||
/*draw_scene*/ &eevee_draw_scene,
|
||||
/*render_to_image*/ &eevee_render_to_image,
|
||||
/*store_metadata*/ &eevee_store_metadata,
|
||||
};
|
||||
|
||||
RenderEngineType DRW_engine_viewport_eevee_next_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
@@ -197,7 +80,7 @@ RenderEngineType DRW_engine_viewport_eevee_next_type = {
|
||||
/*name*/ N_("EEVEE"),
|
||||
/*flag*/ RE_INTERNAL | RE_USE_PREVIEW | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT,
|
||||
/*update*/ nullptr,
|
||||
/*render*/ &DRW_render_to_image,
|
||||
/*render*/ &eevee_render,
|
||||
/*render_frame_finish*/ nullptr,
|
||||
/*draw*/ nullptr,
|
||||
/*bake*/ nullptr,
|
||||
@@ -205,7 +88,7 @@ RenderEngineType DRW_engine_viewport_eevee_next_type = {
|
||||
/*view_draw*/ nullptr,
|
||||
/*update_script_node*/ nullptr,
|
||||
/*update_render_passes*/ &eevee_render_update_passes,
|
||||
/*draw_engine*/ &draw_engine_eevee_next_type,
|
||||
/*draw_engine*/ nullptr,
|
||||
/*rna_ext*/
|
||||
{
|
||||
/*data*/ nullptr,
|
||||
|
||||
@@ -11,5 +11,14 @@
|
||||
#include "DRW_render.hh"
|
||||
#include "RE_engine.h"
|
||||
|
||||
extern DrawEngineType draw_engine_eevee_next_type;
|
||||
extern RenderEngineType DRW_engine_viewport_eevee_next_type;
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
|
||||
static void free_static();
|
||||
};
|
||||
|
||||
} // namespace blender::eevee
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "DNA_lightprobe_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "ED_screen.hh"
|
||||
#include "ED_view3d.hh"
|
||||
#include "GPU_context.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
@@ -52,6 +54,68 @@ void *Instance::debug_scope_irradiance_sample = nullptr;
|
||||
* Any attempt to do so will likely produce use after free situations.
|
||||
* \{ */
|
||||
|
||||
void Instance::init()
|
||||
{
|
||||
const DRWContext *ctx_state = DRW_context_get();
|
||||
Depsgraph *depsgraph = ctx_state->depsgraph;
|
||||
Scene *scene = ctx_state->scene;
|
||||
View3D *v3d = ctx_state->v3d;
|
||||
ARegion *region = ctx_state->region;
|
||||
RegionView3D *rv3d = ctx_state->rv3d;
|
||||
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
int2 size = int2(GPU_texture_width(dtxl->color), GPU_texture_height(dtxl->color));
|
||||
|
||||
draw::View &default_view = draw::View::default_get();
|
||||
|
||||
Object *camera = nullptr;
|
||||
/* Get render borders. */
|
||||
rcti rect;
|
||||
BLI_rcti_init(&rect, 0, size[0], 0, size[1]);
|
||||
rcti visible_rect = rect;
|
||||
if (v3d) {
|
||||
if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
|
||||
camera = v3d->camera;
|
||||
}
|
||||
|
||||
if (camera) {
|
||||
rctf default_border;
|
||||
BLI_rctf_init(&default_border, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
bool is_default_border = BLI_rctf_compare(&scene->r.border, &default_border, 0.0f);
|
||||
bool use_border = scene->r.mode & R_BORDER;
|
||||
if (!is_default_border && use_border) {
|
||||
rctf viewborder;
|
||||
/* TODO(fclem) Might be better to get it from DRW. */
|
||||
ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, false, &viewborder);
|
||||
float viewborder_sizex = BLI_rctf_size_x(&viewborder);
|
||||
float viewborder_sizey = BLI_rctf_size_y(&viewborder);
|
||||
rect.xmin = floorf(viewborder.xmin + (scene->r.border.xmin * viewborder_sizex));
|
||||
rect.ymin = floorf(viewborder.ymin + (scene->r.border.ymin * viewborder_sizey));
|
||||
rect.xmax = floorf(viewborder.xmin + (scene->r.border.xmax * viewborder_sizex));
|
||||
rect.ymax = floorf(viewborder.ymin + (scene->r.border.ymax * viewborder_sizey));
|
||||
}
|
||||
}
|
||||
else if (v3d->flag2 & V3D_RENDER_BORDER) {
|
||||
rect.xmin = v3d->render_border.xmin * size[0];
|
||||
rect.ymin = v3d->render_border.ymin * size[1];
|
||||
rect.xmax = v3d->render_border.xmax * size[0];
|
||||
rect.ymax = v3d->render_border.ymax * size[1];
|
||||
}
|
||||
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
const float2 vp_size = DRW_viewport_size_get();
|
||||
visible_rect.xmax = vp_size[0];
|
||||
visible_rect.ymax = vp_size[1];
|
||||
visible_rect.xmin = visible_rect.ymin = 0;
|
||||
}
|
||||
else {
|
||||
visible_rect = *ED_region_visible_rect(region);
|
||||
}
|
||||
}
|
||||
|
||||
init(size, &rect, &visible_rect, nullptr, depsgraph, camera, nullptr, &default_view, v3d, rv3d);
|
||||
}
|
||||
|
||||
void Instance::init(const int2 &output_res,
|
||||
const rcti *output_rect,
|
||||
const rcti *visible_rect,
|
||||
@@ -249,7 +313,7 @@ void Instance::begin_sync()
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::object_sync(ObjectRef &ob_ref)
|
||||
void Instance::object_sync(ObjectRef &ob_ref, Manager & /*manager*/)
|
||||
{
|
||||
if (skip_render_) {
|
||||
return;
|
||||
@@ -314,16 +378,6 @@ void Instance::object_sync(ObjectRef &ob_ref)
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::object_sync_render(void *instance_,
|
||||
ObjectRef &ob_ref,
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph)
|
||||
{
|
||||
UNUSED_VARS(engine, depsgraph);
|
||||
Instance &inst = *reinterpret_cast<Instance *>(instance_);
|
||||
inst.object_sync(ob_ref);
|
||||
}
|
||||
|
||||
void Instance::end_sync()
|
||||
{
|
||||
if (skip_render_) {
|
||||
@@ -354,7 +408,10 @@ void Instance::render_sync()
|
||||
|
||||
begin_sync();
|
||||
|
||||
DRW_render_object_iter(this, render, depsgraph, object_sync_render);
|
||||
DRW_render_object_iter(
|
||||
render, depsgraph, [this](blender::draw::ObjectRef &ob_ref, RenderEngine *, Depsgraph *) {
|
||||
this->object_sync(ob_ref, *this->manager);
|
||||
});
|
||||
|
||||
velocity.geometry_steps_fill();
|
||||
|
||||
@@ -621,6 +678,19 @@ void Instance::draw_viewport_image_render()
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::draw(Manager & /*manager*/)
|
||||
{
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
draw_viewport_image_render();
|
||||
}
|
||||
else {
|
||||
draw_viewport();
|
||||
}
|
||||
STRNCPY(info, info_get());
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
GPU_framebuffer_viewport_reset(dfbl->default_fb);
|
||||
}
|
||||
|
||||
void Instance::store_metadata(RenderResult *render_result)
|
||||
{
|
||||
if (skip_render_) {
|
||||
@@ -710,7 +780,7 @@ void Instance::light_bake_irradiance(
|
||||
|
||||
auto custom_pipeline_wrapper = [&](FunctionRef<void()> callback) {
|
||||
context_enable();
|
||||
DRW_custom_pipeline_begin(draw_ctx, &draw_engine_eevee_next_type, depsgraph);
|
||||
DRW_custom_pipeline_begin(draw_ctx, depsgraph);
|
||||
callback();
|
||||
DRW_custom_pipeline_end(draw_ctx);
|
||||
context_disable();
|
||||
|
||||
@@ -72,7 +72,7 @@ struct UniformDataModule {
|
||||
* \class Instance
|
||||
* \brief A running instance of the engine.
|
||||
*/
|
||||
class Instance {
|
||||
class Instance : public DrawEngine {
|
||||
friend VelocityModule;
|
||||
friend MotionBlurModule;
|
||||
|
||||
@@ -180,6 +180,11 @@ class Instance {
|
||||
volume(*this, uniform_data.data.volumes){};
|
||||
~Instance(){};
|
||||
|
||||
blender::StringRefNull name_get() final
|
||||
{
|
||||
return "EEVEE";
|
||||
}
|
||||
|
||||
/* Render & Viewport. */
|
||||
/* TODO(fclem): Split for clarity. */
|
||||
void init(const int2 &output_res,
|
||||
@@ -193,9 +198,11 @@ class Instance {
|
||||
const View3D *v3d = nullptr,
|
||||
const RegionView3D *rv3d = nullptr);
|
||||
|
||||
void begin_sync();
|
||||
void object_sync(ObjectRef &ob_ref);
|
||||
void end_sync();
|
||||
void init() final;
|
||||
|
||||
void begin_sync() final;
|
||||
void object_sync(ObjectRef &ob_ref, Manager &manager) final;
|
||||
void end_sync() final;
|
||||
|
||||
/**
|
||||
* Return true when probe pipeline is used during this sample.
|
||||
@@ -221,6 +228,8 @@ class Instance {
|
||||
void draw_viewport();
|
||||
void draw_viewport_image_render();
|
||||
|
||||
void draw(Manager &manager) final;
|
||||
|
||||
/* Light bake. */
|
||||
|
||||
void init_light_bake(Depsgraph *depsgraph, draw::Manager *manager);
|
||||
@@ -370,11 +379,6 @@ class Instance {
|
||||
}
|
||||
|
||||
private:
|
||||
/** Wrapper to use with #DRW_render_object_iter. */
|
||||
static void object_sync_render(void *instance_,
|
||||
ObjectRef &ob_ref,
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph);
|
||||
/**
|
||||
* Conceptually renders one sample per pixel.
|
||||
* Everything based on random sampling should be done here (i.e: DRWViews jitter)
|
||||
|
||||
@@ -60,13 +60,8 @@ void VelocityModule::init()
|
||||
}
|
||||
|
||||
/* Similar to Instance::object_sync, but only syncs velocity. */
|
||||
static void step_object_sync_render(void *instance,
|
||||
ObjectRef &ob_ref,
|
||||
RenderEngine * /*engine*/,
|
||||
Depsgraph * /*depsgraph*/)
|
||||
static void step_object_sync_render(Instance &inst, ObjectRef &ob_ref)
|
||||
{
|
||||
Instance &inst = *reinterpret_cast<Instance *>(instance);
|
||||
|
||||
Object *ob = ob_ref.object;
|
||||
|
||||
const bool is_velocity_type = ELEM(ob->type, OB_CURVES, OB_MESH, OB_POINTCLOUD);
|
||||
@@ -107,7 +102,11 @@ void VelocityModule::step_sync(eVelocityStep step, float time)
|
||||
object_steps_usage[step_] = 0;
|
||||
step_camera_sync();
|
||||
|
||||
DRW_render_object_iter(&inst_, inst_.render, inst_.depsgraph, step_object_sync_render);
|
||||
DRW_render_object_iter(inst_.render,
|
||||
inst_.depsgraph,
|
||||
[&](blender::draw::ObjectRef &ob_ref, RenderEngine *, Depsgraph *) {
|
||||
step_object_sync_render(inst_, ob_ref);
|
||||
});
|
||||
|
||||
geometry_steps_fill();
|
||||
}
|
||||
|
||||
@@ -38,226 +38,227 @@
|
||||
|
||||
/* Shaders */
|
||||
|
||||
#define EXTERNAL_ENGINE "BLENDER_EXTERNAL"
|
||||
namespace blender::draw::external {
|
||||
class Instance : public DrawEngine {
|
||||
blender::StringRefNull name_get() final
|
||||
{
|
||||
return "External";
|
||||
}
|
||||
|
||||
struct EXTERNAL_Data {
|
||||
void *engine_type;
|
||||
void *instance_data;
|
||||
void init() final {}
|
||||
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
void begin_sync() final {}
|
||||
|
||||
/* Functions */
|
||||
void object_sync(blender::draw::ObjectRef & /*ob_ref*/,
|
||||
blender::draw::Manager & /*manager*/) final
|
||||
{
|
||||
}
|
||||
|
||||
static void external_draw_scene_do_v3d(void *vedata)
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
RegionView3D *rv3d = draw_ctx->rv3d;
|
||||
ARegion *region = draw_ctx->region;
|
||||
void end_sync() final {}
|
||||
|
||||
blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR);
|
||||
void draw_scene_do_v3d()
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
RegionView3D *rv3d = draw_ctx->rv3d;
|
||||
ARegion *region = draw_ctx->region;
|
||||
|
||||
/* The external engine can use the OpenGL rendering API directly, so make sure the state is
|
||||
* already applied. */
|
||||
GPU_apply_state();
|
||||
blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR);
|
||||
|
||||
/* Create render engine. */
|
||||
RenderEngine *render_engine = nullptr;
|
||||
if (!rv3d->view_render) {
|
||||
RenderEngineType *engine_type = ED_view3d_engine_type(draw_ctx->scene,
|
||||
draw_ctx->v3d->shading.type);
|
||||
/* The external engine can use the OpenGL rendering API directly, so make sure the state is
|
||||
* already applied. */
|
||||
GPU_apply_state();
|
||||
|
||||
if (!(engine_type->view_update && engine_type->view_draw)) {
|
||||
/* Create render engine. */
|
||||
RenderEngine *render_engine = nullptr;
|
||||
if (!rv3d->view_render) {
|
||||
RenderEngineType *engine_type = ED_view3d_engine_type(draw_ctx->scene,
|
||||
draw_ctx->v3d->shading.type);
|
||||
|
||||
if (!(engine_type->view_update && engine_type->view_draw)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv3d->view_render = RE_NewViewRender(engine_type);
|
||||
render_engine = RE_view_engine_get(rv3d->view_render);
|
||||
engine_type->view_update(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
|
||||
}
|
||||
else {
|
||||
render_engine = RE_view_engine_get(rv3d->view_render);
|
||||
}
|
||||
|
||||
/* Rendered draw. */
|
||||
GPU_matrix_push_projection();
|
||||
GPU_matrix_push();
|
||||
ED_region_pixelspace(region);
|
||||
|
||||
/* Render result draw. */
|
||||
const RenderEngineType *type = render_engine->type;
|
||||
type->view_draw(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
|
||||
|
||||
GPU_bgl_end();
|
||||
|
||||
GPU_matrix_pop();
|
||||
GPU_matrix_pop_projection();
|
||||
|
||||
/* Set render info. */
|
||||
if (render_engine->text[0] != '\0') {
|
||||
STRNCPY(info, render_engine->text);
|
||||
}
|
||||
else {
|
||||
info[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure current matrix stack so that the external engine can use the same drawing code for
|
||||
* both viewport and image editor drawing.
|
||||
*
|
||||
* The engine draws result in the pixel space, and is applying render offset. For image editor we
|
||||
* need to switch from normalized space to pixel space, and "un-apply" offset. */
|
||||
static void external_image_space_matrix_set(const RenderEngine *engine)
|
||||
{
|
||||
BLI_assert(engine != nullptr);
|
||||
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
SpaceImage *space_image = (SpaceImage *)draw_ctx->space_data;
|
||||
|
||||
/* Apply current view as transformation matrix.
|
||||
* This will configure drawing for normalized space with current zoom and pan applied. */
|
||||
|
||||
float4x4 view_matrix = blender::draw::View::default_get().viewmat();
|
||||
float4x4 projection_matrix = blender::draw::View::default_get().winmat();
|
||||
|
||||
GPU_matrix_projection_set(projection_matrix.ptr());
|
||||
GPU_matrix_set(view_matrix.ptr());
|
||||
|
||||
/* Switch from normalized space to pixel space. */
|
||||
{
|
||||
int width, height;
|
||||
ED_space_image_get_size(space_image, &width, &height);
|
||||
|
||||
const float width_inv = width ? 1.0f / width : 0.0f;
|
||||
const float height_inv = height ? 1.0f / height : 0.0f;
|
||||
GPU_matrix_scale_2f(width_inv, height_inv);
|
||||
}
|
||||
|
||||
/* Un-apply render offset. */
|
||||
{
|
||||
Render *render = engine->re;
|
||||
rctf view_rect;
|
||||
rcti render_rect;
|
||||
RE_GetViewPlane(render, &view_rect, &render_rect);
|
||||
|
||||
GPU_matrix_translate_2f(-render_rect.xmin, -render_rect.ymin);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_scene_do_image()
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
Render *re = RE_GetSceneRender(scene);
|
||||
RenderEngine *engine = RE_engine_get(re);
|
||||
|
||||
/* Is tested before enabling the drawing engine. */
|
||||
BLI_assert(re != nullptr);
|
||||
BLI_assert(engine != nullptr);
|
||||
|
||||
blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR);
|
||||
|
||||
/* The external engine can use the OpenGL rendering API directly, so make sure the state is
|
||||
* already applied. */
|
||||
GPU_apply_state();
|
||||
|
||||
const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
/* Clear the depth buffer to the value used by the background overlay so that the overlay is
|
||||
* not happening outside of the drawn image.
|
||||
*
|
||||
* NOTE: The external engine only draws color. The depth is taken care of using the depth pass
|
||||
* which initialized the depth to the values expected by the background overlay. */
|
||||
GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
|
||||
|
||||
GPU_matrix_push_projection();
|
||||
GPU_matrix_push();
|
||||
|
||||
external_image_space_matrix_set(engine);
|
||||
|
||||
GPU_debug_group_begin("External Engine");
|
||||
|
||||
const RenderEngineType *engine_type = engine->type;
|
||||
BLI_assert(engine_type != nullptr);
|
||||
BLI_assert(engine_type->draw != nullptr);
|
||||
|
||||
engine_type->draw(engine, draw_ctx->evil_C, draw_ctx->depsgraph);
|
||||
|
||||
GPU_debug_group_end();
|
||||
|
||||
GPU_matrix_pop();
|
||||
GPU_matrix_pop_projection();
|
||||
|
||||
blender::draw::command::StateSet::set();
|
||||
GPU_bgl_end();
|
||||
|
||||
RE_engine_draw_release(re);
|
||||
}
|
||||
|
||||
void draw_scene_do()
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
|
||||
if (draw_ctx->v3d != nullptr) {
|
||||
draw_scene_do_v3d();
|
||||
return;
|
||||
}
|
||||
|
||||
rv3d->view_render = RE_NewViewRender(engine_type);
|
||||
render_engine = RE_view_engine_get(rv3d->view_render);
|
||||
engine_type->view_update(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
|
||||
}
|
||||
else {
|
||||
render_engine = RE_view_engine_get(rv3d->view_render);
|
||||
if (draw_ctx->space_data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
|
||||
if (space_type == SPACE_IMAGE) {
|
||||
draw_scene_do_image();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Rendered draw. */
|
||||
GPU_matrix_push_projection();
|
||||
GPU_matrix_push();
|
||||
ED_region_pixelspace(region);
|
||||
|
||||
/* Render result draw. */
|
||||
const RenderEngineType *type = render_engine->type;
|
||||
type->view_draw(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
|
||||
|
||||
GPU_bgl_end();
|
||||
|
||||
GPU_matrix_pop();
|
||||
GPU_matrix_pop_projection();
|
||||
|
||||
/* Set render info. */
|
||||
EXTERNAL_Data *data = static_cast<EXTERNAL_Data *>(vedata);
|
||||
if (render_engine->text[0] != '\0') {
|
||||
STRNCPY(data->info, render_engine->text);
|
||||
}
|
||||
else {
|
||||
data->info[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure current matrix stack so that the external engine can use the same drawing code for
|
||||
* both viewport and image editor drawing.
|
||||
*
|
||||
* The engine draws result in the pixel space, and is applying render offset. For image editor we
|
||||
* need to switch from normalized space to pixel space, and "un-apply" offset. */
|
||||
static void external_image_space_matrix_set(const RenderEngine *engine)
|
||||
{
|
||||
BLI_assert(engine != nullptr);
|
||||
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
SpaceImage *space_image = (SpaceImage *)draw_ctx->space_data;
|
||||
|
||||
/* Apply current view as transformation matrix.
|
||||
* This will configure drawing for normalized space with current zoom and pan applied. */
|
||||
|
||||
float4x4 view_matrix = blender::draw::View::default_get().viewmat();
|
||||
float4x4 projection_matrix = blender::draw::View::default_get().winmat();
|
||||
|
||||
GPU_matrix_projection_set(projection_matrix.ptr());
|
||||
GPU_matrix_set(view_matrix.ptr());
|
||||
|
||||
/* Switch from normalized space to pixel space. */
|
||||
void draw(blender::draw::Manager & /*manager*/) final
|
||||
{
|
||||
int width, height;
|
||||
ED_space_image_get_size(space_image, &width, &height);
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
const float width_inv = width ? 1.0f / width : 0.0f;
|
||||
const float height_inv = height ? 1.0f / height : 0.0f;
|
||||
GPU_matrix_scale_2f(width_inv, height_inv);
|
||||
/* Will be nullptr during OpenGL render.
|
||||
* OpenGL render is used for quick preview (thumbnails or sequencer preview)
|
||||
* where using the rendering engine to preview doesn't make so much sense. */
|
||||
if (draw_ctx->evil_C) {
|
||||
const float clear_col[4] = {0, 0, 0, 0};
|
||||
/* This is to keep compatibility with external engine. */
|
||||
/* TODO(fclem): remove it eventually. */
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
GPU_framebuffer_clear_color(dfbl->default_fb, clear_col);
|
||||
|
||||
DRW_submission_start();
|
||||
draw_scene_do();
|
||||
DRW_submission_end();
|
||||
}
|
||||
}
|
||||
|
||||
/* Un-apply render offset. */
|
||||
{
|
||||
Render *render = engine->re;
|
||||
rctf view_rect;
|
||||
rcti render_rect;
|
||||
RE_GetViewPlane(render, &view_rect, &render_rect);
|
||||
|
||||
GPU_matrix_translate_2f(-render_rect.xmin, -render_rect.ymin);
|
||||
}
|
||||
}
|
||||
|
||||
static void external_draw_scene_do_image(void * /*vedata*/)
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
Scene *scene = draw_ctx->scene;
|
||||
Render *re = RE_GetSceneRender(scene);
|
||||
RenderEngine *engine = RE_engine_get(re);
|
||||
|
||||
/* Is tested before enabling the drawing engine. */
|
||||
BLI_assert(re != nullptr);
|
||||
BLI_assert(engine != nullptr);
|
||||
|
||||
blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR);
|
||||
|
||||
/* The external engine can use the OpenGL rendering API directly, so make sure the state is
|
||||
* already applied. */
|
||||
GPU_apply_state();
|
||||
|
||||
const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
/* Clear the depth buffer to the value used by the background overlay so that the overlay is not
|
||||
* happening outside of the drawn image.
|
||||
*
|
||||
* NOTE: The external engine only draws color. The depth is taken care of using the depth pass
|
||||
* which initialized the depth to the values expected by the background overlay. */
|
||||
GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
|
||||
|
||||
GPU_matrix_push_projection();
|
||||
GPU_matrix_push();
|
||||
|
||||
external_image_space_matrix_set(engine);
|
||||
|
||||
GPU_debug_group_begin("External Engine");
|
||||
|
||||
const RenderEngineType *engine_type = engine->type;
|
||||
BLI_assert(engine_type != nullptr);
|
||||
BLI_assert(engine_type->draw != nullptr);
|
||||
|
||||
engine_type->draw(engine, draw_ctx->evil_C, draw_ctx->depsgraph);
|
||||
|
||||
GPU_debug_group_end();
|
||||
|
||||
GPU_matrix_pop();
|
||||
GPU_matrix_pop_projection();
|
||||
|
||||
blender::draw::command::StateSet::set();
|
||||
GPU_bgl_end();
|
||||
|
||||
RE_engine_draw_release(re);
|
||||
}
|
||||
|
||||
static void external_draw_scene_do(void *vedata)
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
|
||||
if (draw_ctx->v3d != nullptr) {
|
||||
external_draw_scene_do_v3d(vedata);
|
||||
return;
|
||||
}
|
||||
|
||||
if (draw_ctx->space_data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
|
||||
if (space_type == SPACE_IMAGE) {
|
||||
external_draw_scene_do_image(vedata);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void external_draw_scene(void *vedata)
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
/* Will be nullptr during OpenGL render.
|
||||
* OpenGL render is used for quick preview (thumbnails or sequencer preview)
|
||||
* where using the rendering engine to preview doesn't make so much sense. */
|
||||
if (draw_ctx->evil_C) {
|
||||
const float clear_col[4] = {0, 0, 0, 0};
|
||||
/* This is to keep compatibility with external engine. */
|
||||
/* TODO(fclem): remove it eventually. */
|
||||
GPU_framebuffer_bind(dfbl->default_fb);
|
||||
GPU_framebuffer_clear_color(dfbl->default_fb, clear_col);
|
||||
|
||||
DRW_submission_start();
|
||||
external_draw_scene_do(vedata);
|
||||
DRW_submission_end();
|
||||
}
|
||||
}
|
||||
|
||||
DrawEngineType draw_engine_external_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("External"),
|
||||
/*engine_init*/ nullptr,
|
||||
/*engine_free*/ nullptr,
|
||||
/*instance_free*/ nullptr,
|
||||
/*cache_init*/ nullptr,
|
||||
/*cache_populate*/ nullptr,
|
||||
/*cache_finish*/ nullptr,
|
||||
/*draw_scene*/ &external_draw_scene,
|
||||
/*render_to_image*/ nullptr,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
} // namespace blender::draw::external
|
||||
|
||||
/* Functions */
|
||||
|
||||
/* NOTE: currently unused,
|
||||
* we should not register unless we want to see this when debugging the view. */
|
||||
|
||||
RenderEngineType DRW_engine_viewport_external_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ EXTERNAL_ENGINE,
|
||||
/*idname*/ "BLENDER_EXTERNAL",
|
||||
/*name*/ N_("External"),
|
||||
/*flag*/ RE_INTERNAL | RE_USE_STEREO_VIEWPORT,
|
||||
/*update*/ nullptr,
|
||||
@@ -269,7 +270,7 @@ RenderEngineType DRW_engine_viewport_external_type = {
|
||||
/*view_draw*/ nullptr,
|
||||
/*update_script_node*/ nullptr,
|
||||
/*update_render_passes*/ nullptr,
|
||||
/*draw_engine*/ &draw_engine_external_type,
|
||||
/*draw_engine*/ nullptr,
|
||||
/*rna_ext*/
|
||||
{
|
||||
/*data*/ nullptr,
|
||||
@@ -324,5 +325,3 @@ void DRW_engine_external_free(RegionView3D *rv3d)
|
||||
DRW_gpu_context_disable_ex(true);
|
||||
}
|
||||
}
|
||||
|
||||
#undef EXTERNAL_ENGINE
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct DrawEngineType;
|
||||
#include "DRW_render.hh"
|
||||
|
||||
struct RenderEngineType;
|
||||
|
||||
extern DrawEngineType draw_engine_external_type;
|
||||
extern RenderEngineType DRW_engine_viewport_external_type;
|
||||
|
||||
/* Check whether an external engine is to be used to draw content of an image editor.
|
||||
@@ -20,3 +20,11 @@ extern RenderEngineType DRW_engine_viewport_external_type;
|
||||
*
|
||||
* NOTE: Released by the draw engine when it is done drawing. */
|
||||
bool DRW_engine_external_acquire_for_image_editor(void);
|
||||
|
||||
namespace blender::draw::external {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
};
|
||||
|
||||
} // namespace blender::draw::external
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DRW_render.hh"
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
#include "gpencil_engine_private.hh"
|
||||
|
||||
#include "BLI_smaa_textures.h"
|
||||
|
||||
void GPENCIL_antialiasing_init(GPENCIL_Instance *inst)
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
void GPENCIL_antialiasing_init(Instance *inst)
|
||||
{
|
||||
const float2 size_f = DRW_viewport_size_get();
|
||||
const int2 size(size_f[0], size_f[1]);
|
||||
@@ -24,7 +26,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst)
|
||||
blender::draw::PassSimple &pass = inst->smaa_resolve_ps;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
|
||||
pass.shader_set(GPENCIL_shader_antialiasing(2));
|
||||
pass.shader_set(ShaderCache::get().antialiasing[2].get());
|
||||
pass.bind_texture("blendTex", &inst->color_tx);
|
||||
pass.bind_texture("colorTex", &inst->color_tx);
|
||||
pass.bind_texture("revealTex", &inst->reveal_tx);
|
||||
@@ -61,7 +63,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst)
|
||||
blender::draw::PassSimple &pass = inst->smaa_edge_ps;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||
pass.shader_set(GPENCIL_shader_antialiasing(0));
|
||||
pass.shader_set(ShaderCache::get().antialiasing[0].get());
|
||||
pass.bind_texture("colorTex", &inst->color_tx);
|
||||
pass.bind_texture("revealTex", &inst->reveal_tx);
|
||||
pass.push_constant("viewportMetrics", metrics);
|
||||
@@ -74,7 +76,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst)
|
||||
blender::draw::PassSimple &pass = inst->smaa_weight_ps;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||
pass.shader_set(GPENCIL_shader_antialiasing(1));
|
||||
pass.shader_set(ShaderCache::get().antialiasing[1].get());
|
||||
pass.bind_texture("edgesTex", &inst->smaa_edge_tx);
|
||||
pass.bind_texture("areaTex", &inst->smaa_area_tx);
|
||||
pass.bind_texture("searchTex", &inst->smaa_search_tx);
|
||||
@@ -87,7 +89,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst)
|
||||
blender::draw::PassSimple &pass = inst->smaa_resolve_ps;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
|
||||
pass.shader_set(GPENCIL_shader_antialiasing(2));
|
||||
pass.shader_set(ShaderCache::get().antialiasing[2].get());
|
||||
pass.bind_texture("blendTex", &inst->smaa_weight_tx);
|
||||
pass.bind_texture("colorTex", &inst->color_tx);
|
||||
pass.bind_texture("revealTex", &inst->reveal_tx);
|
||||
@@ -98,10 +100,8 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst)
|
||||
}
|
||||
}
|
||||
|
||||
void GPENCIL_antialiasing_draw(GPENCIL_Data *vedata)
|
||||
void GPENCIL_antialiasing_draw(Instance *inst)
|
||||
{
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
|
||||
blender::draw::Manager *manager = DRW_manager_get();
|
||||
|
||||
if (!inst->simplify_antialias) {
|
||||
@@ -115,3 +115,5 @@ void GPENCIL_antialiasing_draw(GPENCIL_Data *vedata)
|
||||
GPU_framebuffer_bind(inst->scene_fb);
|
||||
manager->submit(inst->smaa_resolve_ps);
|
||||
}
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
@@ -27,17 +27,19 @@
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_memblock.h"
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
#include "gpencil_engine_private.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "UI_resources.hh"
|
||||
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Object
|
||||
* \{ */
|
||||
|
||||
GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_Instance *inst,
|
||||
GPENCIL_tObject *gpencil_object_cache_add(Instance *inst,
|
||||
Object *ob,
|
||||
const bool is_stroke_order_3d,
|
||||
const blender::Bounds<float3> bounds)
|
||||
@@ -144,7 +146,7 @@ static int gpencil_tobject_dist_sort(const void *a, const void *b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpencil_object_cache_sort(GPENCIL_Instance *inst)
|
||||
void gpencil_object_cache_sort(Instance *inst)
|
||||
{
|
||||
/* Sort object by distance to the camera. */
|
||||
if (inst->tobjects.first) {
|
||||
@@ -184,7 +186,7 @@ void gpencil_object_cache_sort(GPENCIL_Instance *inst)
|
||||
/** \name Layer
|
||||
* \{ */
|
||||
|
||||
static float grease_pencil_layer_final_opacity_get(const GPENCIL_Instance *inst,
|
||||
static float grease_pencil_layer_final_opacity_get(const Instance *inst,
|
||||
const Object *ob,
|
||||
const GreasePencil &grease_pencil,
|
||||
const blender::bke::greasepencil::Layer &layer)
|
||||
@@ -206,7 +208,7 @@ static float grease_pencil_layer_final_opacity_get(const GPENCIL_Instance *inst,
|
||||
return layer.opacity;
|
||||
}
|
||||
|
||||
static float4 grease_pencil_layer_final_tint_and_alpha_get(const GPENCIL_Instance *inst,
|
||||
static float4 grease_pencil_layer_final_tint_and_alpha_get(const Instance *inst,
|
||||
const GreasePencil &grease_pencil,
|
||||
const int onion_id,
|
||||
float *r_alpha)
|
||||
@@ -286,7 +288,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_get(GPENCIL_tObject *tgp_ob,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst,
|
||||
GPENCIL_tLayer *grease_pencil_layer_cache_add(Instance *inst,
|
||||
const Object *ob,
|
||||
const blender::bke::greasepencil::Layer &layer,
|
||||
const int onion_id,
|
||||
@@ -407,7 +409,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst,
|
||||
PassSimple &pass = *tgp_layer->blend_ps;
|
||||
pass.init();
|
||||
pass.state_set(state);
|
||||
pass.shader_set(GPENCIL_shader_layer_blend_get());
|
||||
pass.shader_set(ShaderCache::get().layer_blend.get());
|
||||
pass.push_constant("blendMode", int(layer.blend_mode));
|
||||
pass.push_constant("blendOpacity", layer_opacity);
|
||||
pass.bind_texture("colorBuf", &inst->color_layer_tx);
|
||||
@@ -445,7 +447,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst,
|
||||
state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
|
||||
|
||||
pass.state_set(state);
|
||||
pass.shader_set(GPENCIL_shader_geometry_get());
|
||||
pass.shader_set(ShaderCache::get().geometry.get());
|
||||
pass.bind_texture("gpSceneDepthTexture", depth_tex);
|
||||
pass.bind_texture("gpMaskTexture", mask_tex);
|
||||
pass.push_constant("gpNormal", tgp_ob->plane_normal);
|
||||
@@ -471,3 +473,5 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst,
|
||||
return tgp_layer;
|
||||
}
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
@@ -22,13 +22,15 @@
|
||||
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
#include "gpencil_engine_private.hh"
|
||||
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Material
|
||||
* \{ */
|
||||
|
||||
static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_Instance *inst)
|
||||
static GPENCIL_MaterialPool *gpencil_material_pool_add(Instance *inst)
|
||||
{
|
||||
GPENCIL_MaterialPool *matpool = static_cast<GPENCIL_MaterialPool *>(
|
||||
BLI_memblock_alloc(inst->gp_material_pool));
|
||||
@@ -41,7 +43,7 @@ static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_Instance *inst)
|
||||
return matpool;
|
||||
}
|
||||
|
||||
static GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_premult)
|
||||
static GPUTexture *gpencil_image_texture_get(::Image *image, bool *r_alpha_premult)
|
||||
{
|
||||
ImageUser iuser = {nullptr};
|
||||
GPUTexture *gpu_tex = nullptr;
|
||||
@@ -88,7 +90,7 @@ static void gpencil_shade_color(float color[3])
|
||||
|
||||
/* Apply all overrides from the solid viewport mode to the GPencil material. */
|
||||
static MaterialGPencilStyle *gpencil_viewport_material_overrides(
|
||||
GPENCIL_Instance *inst,
|
||||
Instance *inst,
|
||||
Object *ob,
|
||||
int color_type,
|
||||
MaterialGPencilStyle *gp_style,
|
||||
@@ -159,7 +161,7 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides(
|
||||
return gp_style;
|
||||
}
|
||||
|
||||
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_Instance *inst,
|
||||
GPENCIL_MaterialPool *gpencil_material_pool_create(Instance *inst,
|
||||
Object *ob,
|
||||
int *ofs,
|
||||
const bool is_vertex_mode)
|
||||
@@ -327,7 +329,7 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
|
||||
/** \name Lights
|
||||
* \{ */
|
||||
|
||||
GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_Instance *inst)
|
||||
GPENCIL_LightPool *gpencil_light_pool_add(Instance *inst)
|
||||
{
|
||||
GPENCIL_LightPool *lightpool = static_cast<GPENCIL_LightPool *>(
|
||||
BLI_memblock_alloc(inst->gp_light_pool));
|
||||
@@ -414,7 +416,7 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob)
|
||||
}
|
||||
}
|
||||
|
||||
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_Instance *inst, Object * /*ob*/)
|
||||
GPENCIL_LightPool *gpencil_light_pool_create(Instance *inst, Object * /*ob*/)
|
||||
{
|
||||
GPENCIL_LightPool *lightpool = inst->last_light_pool;
|
||||
|
||||
@@ -427,57 +429,6 @@ GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_Instance *inst, Object * /*
|
||||
return lightpool;
|
||||
}
|
||||
|
||||
void gpencil_material_pool_free(void *storage)
|
||||
{
|
||||
GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage;
|
||||
GPU_UBO_FREE_SAFE(matpool->ubo);
|
||||
}
|
||||
|
||||
void gpencil_light_pool_free(void *storage)
|
||||
{
|
||||
GPENCIL_LightPool *lightpool = (GPENCIL_LightPool *)storage;
|
||||
GPU_UBO_FREE_SAFE(lightpool->ubo);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name View Layer Data
|
||||
* \{ */
|
||||
|
||||
static void gpencil_view_layer_data_free(void *storage)
|
||||
{
|
||||
GPENCIL_ViewLayerData *vldata = (GPENCIL_ViewLayerData *)storage;
|
||||
|
||||
BLI_memblock_destroy(vldata->gp_light_pool, gpencil_light_pool_free);
|
||||
BLI_memblock_destroy(vldata->gp_material_pool, gpencil_material_pool_free);
|
||||
BLI_memblock_destroy(vldata->gp_maskbit_pool, nullptr);
|
||||
BLI_memblock_destroy(vldata->gp_object_pool, nullptr);
|
||||
delete vldata->gp_layer_pool;
|
||||
delete vldata->gp_vfx_pool;
|
||||
}
|
||||
|
||||
GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure()
|
||||
{
|
||||
GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure(
|
||||
&draw_engine_gpencil_type, gpencil_view_layer_data_free);
|
||||
|
||||
/* NOTE(@fclem): Putting this stuff in view-layer means it is shared by all viewports.
|
||||
* For now it is ok, but in the future, it could become a problem if we implement
|
||||
* the caching system. */
|
||||
if (*vldata == nullptr) {
|
||||
*vldata = static_cast<GPENCIL_ViewLayerData *>(
|
||||
MEM_callocN(sizeof(**vldata), "GPENCIL_ViewLayerData"));
|
||||
|
||||
(*vldata)->gp_light_pool = BLI_memblock_create(sizeof(GPENCIL_LightPool));
|
||||
(*vldata)->gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool));
|
||||
(*vldata)->gp_maskbit_pool = BLI_memblock_create(BLI_BITMAP_SIZE(GP_MAX_MASKBITS));
|
||||
(*vldata)->gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject));
|
||||
(*vldata)->gp_layer_pool = new GPENCIL_tLayer_Pool();
|
||||
(*vldata)->gp_vfx_pool = new GPENCIL_tVfx_Pool();
|
||||
}
|
||||
|
||||
return *vldata;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
22
source/blender/draw/engines/gpencil/gpencil_engine.hh
Normal file
22
source/blender/draw/engines/gpencil/gpencil_engine.hh
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2017 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DRW_render.hh"
|
||||
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
|
||||
static void render_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti rect);
|
||||
static void free_static();
|
||||
};
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
@@ -39,7 +39,8 @@
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_view.hh"
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
#include "gpencil_engine.hh"
|
||||
#include "gpencil_engine_private.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
@@ -49,67 +50,62 @@
|
||||
|
||||
#include "GPU_debug.hh"
|
||||
|
||||
/* *********** FUNCTIONS *********** */
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
void GPENCIL_engine_init(void *ved)
|
||||
using namespace blender::draw;
|
||||
|
||||
void Instance::init()
|
||||
{
|
||||
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
|
||||
const DRWContext *ctx = DRW_context_get();
|
||||
const View3D *v3d = ctx->v3d;
|
||||
|
||||
if (vedata->instance == nullptr) {
|
||||
vedata->instance = new GPENCIL_Instance();
|
||||
}
|
||||
GPENCIL_Instance &inst = *vedata->instance;
|
||||
|
||||
if (!inst.dummy_texture.is_valid()) {
|
||||
if (!dummy_texture.is_valid()) {
|
||||
const float pixels[1][4] = {{1.0f, 0.0f, 1.0f, 1.0f}};
|
||||
inst.dummy_texture.ensure_2d(GPU_RGBA8, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, &pixels[0][0]);
|
||||
dummy_texture.ensure_2d(GPU_RGBA8, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, &pixels[0][0]);
|
||||
}
|
||||
if (!inst.dummy_depth.is_valid()) {
|
||||
if (!dummy_depth.is_valid()) {
|
||||
const float pixels[1] = {1.0f};
|
||||
inst.dummy_depth.ensure_2d(
|
||||
dummy_depth.ensure_2d(
|
||||
GPU_DEPTH_COMPONENT24, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, &pixels[0]);
|
||||
}
|
||||
|
||||
GPENCIL_ViewLayerData *vldata = GPENCIL_view_layer_data_ensure();
|
||||
|
||||
/* Resize and reset memory-blocks. */
|
||||
BLI_memblock_clear(vldata->gp_light_pool, gpencil_light_pool_free);
|
||||
BLI_memblock_clear(vldata->gp_material_pool, gpencil_material_pool_free);
|
||||
BLI_memblock_clear(vldata->gp_object_pool, nullptr);
|
||||
vldata->gp_layer_pool->clear();
|
||||
vldata->gp_vfx_pool->clear();
|
||||
BLI_memblock_clear(vldata->gp_maskbit_pool, nullptr);
|
||||
BLI_memblock_clear(vldata.gp_light_pool, ViewLayerData::light_pool_free);
|
||||
BLI_memblock_clear(vldata.gp_material_pool, ViewLayerData::material_pool_free);
|
||||
BLI_memblock_clear(vldata.gp_object_pool, nullptr);
|
||||
vldata.gp_layer_pool->clear();
|
||||
vldata.gp_vfx_pool->clear();
|
||||
BLI_memblock_clear(vldata.gp_maskbit_pool, nullptr);
|
||||
|
||||
inst.gp_light_pool = vldata->gp_light_pool;
|
||||
inst.gp_material_pool = vldata->gp_material_pool;
|
||||
inst.gp_maskbit_pool = vldata->gp_maskbit_pool;
|
||||
inst.gp_object_pool = vldata->gp_object_pool;
|
||||
inst.gp_layer_pool = vldata->gp_layer_pool;
|
||||
inst.gp_vfx_pool = vldata->gp_vfx_pool;
|
||||
inst.view_layer = ctx->view_layer;
|
||||
inst.scene = ctx->scene;
|
||||
inst.v3d = ctx->v3d;
|
||||
inst.last_light_pool = nullptr;
|
||||
inst.last_material_pool = nullptr;
|
||||
inst.tobjects.first = nullptr;
|
||||
inst.tobjects.last = nullptr;
|
||||
inst.tobjects_infront.first = nullptr;
|
||||
inst.tobjects_infront.last = nullptr;
|
||||
inst.sbuffer_tobjects.first = nullptr;
|
||||
inst.sbuffer_tobjects.last = nullptr;
|
||||
inst.dummy_tx = inst.dummy_texture;
|
||||
inst.draw_wireframe = (v3d && v3d->shading.type == OB_WIRE);
|
||||
inst.scene_depth_tx = nullptr;
|
||||
inst.scene_fb = nullptr;
|
||||
inst.is_render = inst.render_depth_tx.is_valid() || (v3d && v3d->shading.type == OB_RENDER);
|
||||
inst.is_viewport = (v3d != nullptr);
|
||||
inst.global_light_pool = gpencil_light_pool_add(&inst);
|
||||
inst.shadeless_light_pool = gpencil_light_pool_add(&inst);
|
||||
/* TODO remove */
|
||||
this->gp_light_pool = vldata.gp_light_pool;
|
||||
this->gp_material_pool = vldata.gp_material_pool;
|
||||
this->gp_maskbit_pool = vldata.gp_maskbit_pool;
|
||||
this->gp_object_pool = vldata.gp_object_pool;
|
||||
this->gp_layer_pool = vldata.gp_layer_pool;
|
||||
this->gp_vfx_pool = vldata.gp_vfx_pool;
|
||||
this->view_layer = ctx->view_layer;
|
||||
this->scene = ctx->scene;
|
||||
this->v3d = ctx->v3d;
|
||||
this->last_light_pool = nullptr;
|
||||
this->last_material_pool = nullptr;
|
||||
this->tobjects.first = nullptr;
|
||||
this->tobjects.last = nullptr;
|
||||
this->tobjects_infront.first = nullptr;
|
||||
this->tobjects_infront.last = nullptr;
|
||||
this->sbuffer_tobjects.first = nullptr;
|
||||
this->sbuffer_tobjects.last = nullptr;
|
||||
this->dummy_tx = this->dummy_texture;
|
||||
this->draw_wireframe = (v3d && v3d->shading.type == OB_WIRE);
|
||||
this->scene_depth_tx = nullptr;
|
||||
this->scene_fb = nullptr;
|
||||
this->is_render = this->render_depth_tx.is_valid() || (v3d && v3d->shading.type == OB_RENDER);
|
||||
this->is_viewport = (v3d != nullptr);
|
||||
this->global_light_pool = gpencil_light_pool_add(this);
|
||||
this->shadeless_light_pool = gpencil_light_pool_add(this);
|
||||
/* Small HACK: we don't want the global pool to be reused,
|
||||
* so we set the last light pool to nullptr. */
|
||||
inst.last_light_pool = nullptr;
|
||||
this->last_light_pool = nullptr;
|
||||
|
||||
bool use_scene_lights = false;
|
||||
bool use_scene_world = false;
|
||||
@@ -119,76 +115,72 @@ void GPENCIL_engine_init(void *ved)
|
||||
|
||||
use_scene_world = V3D_USES_SCENE_WORLD(v3d);
|
||||
|
||||
inst.v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1;
|
||||
this->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1;
|
||||
/* Special case: If we're in Vertex Paint mode, enforce #V3D_SHADING_VERTEX_COLOR setting. */
|
||||
if (v3d->shading.type == OB_SOLID && ctx->obact &&
|
||||
(ctx->obact->mode & OB_MODE_VERTEX_GREASE_PENCIL) != 0)
|
||||
{
|
||||
inst.v3d_color_type = V3D_SHADING_VERTEX_COLOR;
|
||||
this->v3d_color_type = V3D_SHADING_VERTEX_COLOR;
|
||||
}
|
||||
|
||||
copy_v3_v3(inst.v3d_single_color, v3d->shading.single_color);
|
||||
copy_v3_v3(this->v3d_single_color, v3d->shading.single_color);
|
||||
|
||||
/* For non active frame, use only lines in multiedit mode. */
|
||||
const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
|
||||
inst.use_multiedit_lines_only = overlays_on &&
|
||||
(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
|
||||
this->use_multiedit_lines_only = overlays_on &&
|
||||
(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
|
||||
|
||||
const bool shmode_xray_support = v3d->shading.type <= OB_SOLID;
|
||||
inst.xray_alpha = (shmode_xray_support && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f;
|
||||
inst.force_stroke_order_3d = v3d->gp_flag & V3D_GP_FORCE_STROKE_ORDER_3D;
|
||||
this->xray_alpha = (shmode_xray_support && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f;
|
||||
this->force_stroke_order_3d = v3d->gp_flag & V3D_GP_FORCE_STROKE_ORDER_3D;
|
||||
}
|
||||
else if (inst.is_render) {
|
||||
else if (this->is_render) {
|
||||
use_scene_lights = true;
|
||||
use_scene_world = true;
|
||||
inst.use_multiedit_lines_only = false;
|
||||
inst.xray_alpha = 1.0f;
|
||||
inst.v3d_color_type = -1;
|
||||
inst.force_stroke_order_3d = false;
|
||||
this->use_multiedit_lines_only = false;
|
||||
this->xray_alpha = 1.0f;
|
||||
this->v3d_color_type = -1;
|
||||
this->force_stroke_order_3d = false;
|
||||
}
|
||||
|
||||
inst.use_lighting = (v3d && v3d->shading.type > OB_SOLID) || inst.is_render;
|
||||
inst.use_lights = use_scene_lights;
|
||||
this->use_lighting = (v3d && v3d->shading.type > OB_SOLID) || this->is_render;
|
||||
this->use_lights = use_scene_lights;
|
||||
|
||||
gpencil_light_ambient_add(inst.shadeless_light_pool, blender::float3{1.0f, 1.0f, 1.0f});
|
||||
gpencil_light_ambient_add(this->shadeless_light_pool, blender::float3{1.0f, 1.0f, 1.0f});
|
||||
|
||||
World *world = ctx->scene->world;
|
||||
if (world != nullptr && use_scene_world) {
|
||||
gpencil_light_ambient_add(inst.global_light_pool, &world->horr);
|
||||
gpencil_light_ambient_add(this->global_light_pool, &world->horr);
|
||||
}
|
||||
else if (v3d) {
|
||||
float world_light[3];
|
||||
copy_v3_fl(world_light, v3d->shading.studiolight_intensity);
|
||||
gpencil_light_ambient_add(inst.global_light_pool, world_light);
|
||||
gpencil_light_ambient_add(this->global_light_pool, world_light);
|
||||
}
|
||||
|
||||
float4x4 viewmatinv = blender::draw::View::default_get().viewinv();
|
||||
copy_v3_v3(inst.camera_z_axis, viewmatinv[2]);
|
||||
copy_v3_v3(inst.camera_pos, viewmatinv[3]);
|
||||
inst.camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]);
|
||||
copy_v3_v3(this->camera_z_axis, viewmatinv[2]);
|
||||
copy_v3_v3(this->camera_pos, viewmatinv[3]);
|
||||
this->camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]);
|
||||
|
||||
if (ctx && ctx->rv3d && v3d) {
|
||||
inst.camera = (ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : nullptr;
|
||||
this->camera = (ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : nullptr;
|
||||
}
|
||||
else {
|
||||
inst.camera = nullptr;
|
||||
this->camera = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GPENCIL_cache_init(void *ved)
|
||||
void Instance::begin_sync()
|
||||
{
|
||||
using namespace blender::draw;
|
||||
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
inst->cfra = int(DEG_get_ctime(draw_ctx->depsgraph));
|
||||
inst->simplify_antialias = GPENCIL_SIMPLIFY_AA(draw_ctx->scene);
|
||||
inst->use_layer_fb = false;
|
||||
inst->use_object_fb = false;
|
||||
inst->use_mask_fb = false;
|
||||
this->cfra = int(DEG_get_ctime(draw_ctx->depsgraph));
|
||||
this->simplify_antialias = GPENCIL_SIMPLIFY_AA(draw_ctx->scene);
|
||||
this->use_layer_fb = false;
|
||||
this->use_object_fb = false;
|
||||
this->use_mask_fb = false;
|
||||
/* Always use high precision for render. */
|
||||
inst->use_signed_fb = !inst->is_viewport;
|
||||
this->use_signed_fb = !this->is_viewport;
|
||||
|
||||
if (draw_ctx->v3d) {
|
||||
const bool hide_overlay = ((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) != 0);
|
||||
@@ -197,95 +189,95 @@ void GPENCIL_cache_init(void *ved)
|
||||
ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) !=
|
||||
nullptr :
|
||||
false;
|
||||
inst->do_onion = show_onion && !hide_overlay && !playing;
|
||||
inst->playing = playing;
|
||||
this->do_onion = show_onion && !hide_overlay && !playing;
|
||||
this->playing = playing;
|
||||
/* Save simplify flags (can change while drawing, so it's better to save). */
|
||||
Scene *scene = draw_ctx->scene;
|
||||
inst->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing);
|
||||
inst->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, playing) ||
|
||||
this->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing);
|
||||
this->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, playing) ||
|
||||
(draw_ctx->v3d->shading.type < OB_RENDER);
|
||||
|
||||
/* Fade Layer. */
|
||||
const bool is_fade_layer = ((!hide_overlay) && (!inst->is_render) &&
|
||||
const bool is_fade_layer = ((!hide_overlay) && (!this->is_render) &&
|
||||
(draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS));
|
||||
inst->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f;
|
||||
inst->vertex_paint_opacity = draw_ctx->v3d->overlay.gpencil_vertex_paint_opacity;
|
||||
this->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f;
|
||||
this->vertex_paint_opacity = draw_ctx->v3d->overlay.gpencil_vertex_paint_opacity;
|
||||
/* Fade GPencil Objects. */
|
||||
const bool is_fade_object = ((!hide_overlay) && (!inst->is_render) &&
|
||||
const bool is_fade_object = ((!hide_overlay) && (!this->is_render) &&
|
||||
(draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) &&
|
||||
(draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL));
|
||||
inst->fade_gp_object_opacity = (is_fade_object) ?
|
||||
this->fade_gp_object_opacity = (is_fade_object) ?
|
||||
draw_ctx->v3d->overlay.gpencil_paper_opacity :
|
||||
-1.0f;
|
||||
inst->fade_3d_object_opacity = ((!hide_overlay) && (!inst->is_render) &&
|
||||
this->fade_3d_object_opacity = ((!hide_overlay) && (!this->is_render) &&
|
||||
(draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS)) ?
|
||||
draw_ctx->v3d->overlay.gpencil_paper_opacity :
|
||||
-1.0f;
|
||||
}
|
||||
else {
|
||||
inst->do_onion = true;
|
||||
this->do_onion = true;
|
||||
Scene *scene = draw_ctx->scene;
|
||||
inst->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, false);
|
||||
inst->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, false);
|
||||
inst->fade_layer_opacity = -1.0f;
|
||||
inst->playing = false;
|
||||
this->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, false);
|
||||
this->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, false);
|
||||
this->fade_layer_opacity = -1.0f;
|
||||
this->playing = false;
|
||||
}
|
||||
|
||||
{
|
||||
inst->stroke_batch = nullptr;
|
||||
inst->fill_batch = nullptr;
|
||||
inst->do_fast_drawing = false;
|
||||
this->stroke_batch = nullptr;
|
||||
this->fill_batch = nullptr;
|
||||
this->do_fast_drawing = false;
|
||||
|
||||
inst->obact = draw_ctx->obact;
|
||||
this->obact = draw_ctx->obact;
|
||||
}
|
||||
|
||||
if (inst->do_fast_drawing) {
|
||||
inst->snapshot_buffer_dirty = !inst->snapshot_depth_tx.is_valid();
|
||||
if (this->do_fast_drawing) {
|
||||
this->snapshot_buffer_dirty = !this->snapshot_depth_tx.is_valid();
|
||||
const float2 size = DRW_viewport_size_get();
|
||||
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
inst->snapshot_depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, int2(size), usage);
|
||||
inst->snapshot_color_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage);
|
||||
inst->snapshot_reveal_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage);
|
||||
this->snapshot_depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, int2(size), usage);
|
||||
this->snapshot_color_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage);
|
||||
this->snapshot_reveal_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage);
|
||||
|
||||
inst->snapshot_fb.ensure(GPU_ATTACHMENT_TEXTURE(inst->snapshot_depth_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(inst->snapshot_color_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(inst->snapshot_reveal_tx));
|
||||
this->snapshot_fb.ensure(GPU_ATTACHMENT_TEXTURE(this->snapshot_depth_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(this->snapshot_color_tx),
|
||||
GPU_ATTACHMENT_TEXTURE(this->snapshot_reveal_tx));
|
||||
}
|
||||
else {
|
||||
/* Free unneeded buffers. */
|
||||
inst->snapshot_depth_tx.free();
|
||||
inst->snapshot_color_tx.free();
|
||||
inst->snapshot_reveal_tx.free();
|
||||
this->snapshot_depth_tx.free();
|
||||
this->snapshot_color_tx.free();
|
||||
this->snapshot_reveal_tx.free();
|
||||
}
|
||||
|
||||
{
|
||||
blender::draw::PassSimple &pass = inst->merge_depth_ps;
|
||||
blender::draw::PassSimple &pass = this->merge_depth_ps;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
|
||||
pass.shader_set(GPENCIL_shader_depth_merge_get());
|
||||
pass.bind_texture("depthBuf", &inst->depth_tx);
|
||||
pass.push_constant("strokeOrder3d", &inst->is_stroke_order_3d);
|
||||
pass.push_constant("gpModelMatrix", &inst->object_bound_mat);
|
||||
pass.shader_set(ShaderCache::get().depth_merge.get());
|
||||
pass.bind_texture("depthBuf", &this->depth_tx);
|
||||
pass.push_constant("strokeOrder3d", &this->is_stroke_order_3d);
|
||||
pass.push_constant("gpModelMatrix", &this->object_bound_mat);
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
{
|
||||
blender::draw::PassSimple &pass = inst->mask_invert_ps;
|
||||
blender::draw::PassSimple &pass = this->mask_invert_ps;
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT);
|
||||
pass.shader_set(GPENCIL_shader_mask_invert_get());
|
||||
pass.shader_set(ShaderCache::get().mask_invert.get());
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
|
||||
Camera *cam = static_cast<Camera *>(
|
||||
(inst->camera != nullptr && inst->camera->type == OB_CAMERA) ? inst->camera->data : nullptr);
|
||||
(this->camera != nullptr && this->camera->type == OB_CAMERA) ? this->camera->data : nullptr);
|
||||
|
||||
/* Pseudo DOF setup. */
|
||||
if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) {
|
||||
const float2 vp_size = DRW_viewport_size_get();
|
||||
float fstop = cam->dof.aperture_fstop;
|
||||
float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
|
||||
float focus_dist = BKE_camera_object_dof_distance(inst->camera);
|
||||
float focus_dist = BKE_camera_object_dof_distance(this->camera);
|
||||
float focal_len = cam->lens;
|
||||
|
||||
const float scale_camera = 0.001f;
|
||||
@@ -298,13 +290,13 @@ void GPENCIL_cache_init(void *ved)
|
||||
sensor_scaled *= draw_ctx->rv3d->viewcamtexcofac[0];
|
||||
}
|
||||
|
||||
inst->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
|
||||
inst->dof_params[1] *= vp_size[0] / sensor_scaled;
|
||||
inst->dof_params[0] = -focus_dist * inst->dof_params[1];
|
||||
this->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
|
||||
this->dof_params[1] *= vp_size[0] / sensor_scaled;
|
||||
this->dof_params[0] = -focus_dist * this->dof_params[1];
|
||||
}
|
||||
else {
|
||||
/* Disable DoF blur scaling. */
|
||||
inst->camera = nullptr;
|
||||
this->camera = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +350,7 @@ static bool use_layer_in_render(const GreasePencil &grease_pencil,
|
||||
}
|
||||
|
||||
static GPENCIL_tObject *grease_pencil_object_cache_populate(
|
||||
GPENCIL_Instance *inst, Object *ob, blender::draw::ResourceHandle res_handle)
|
||||
Instance *inst, Object *ob, blender::draw::ResourceHandle res_handle)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::ed::greasepencil;
|
||||
@@ -590,10 +582,8 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(
|
||||
return tgp_ob;
|
||||
}
|
||||
|
||||
void GPENCIL_cache_populate(void *ved, blender::draw::ObjectRef &ob_ref)
|
||||
void Instance::object_sync(ObjectRef &ob_ref, Manager &manager)
|
||||
{
|
||||
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
Object *ob = ob_ref.object;
|
||||
|
||||
/* object must be visible */
|
||||
@@ -602,43 +592,39 @@ void GPENCIL_cache_populate(void *ved, blender::draw::ObjectRef &ob_ref)
|
||||
}
|
||||
|
||||
if (ob->data && (ob->type == OB_GREASE_PENCIL) && (ob->dt >= OB_SOLID)) {
|
||||
blender::draw::Manager *manager = DRW_manager_get();
|
||||
blender::draw::ResourceHandle res_handle = manager->unique_handle(ob_ref);
|
||||
blender::draw::ResourceHandle res_handle = manager.unique_handle(ob_ref);
|
||||
|
||||
GPENCIL_tObject *tgp_ob = grease_pencil_object_cache_populate(inst, ob, res_handle);
|
||||
GPENCIL_tObject *tgp_ob = grease_pencil_object_cache_populate(this, ob, res_handle);
|
||||
gpencil_vfx_cache_populate(
|
||||
vedata,
|
||||
this,
|
||||
ob,
|
||||
tgp_ob,
|
||||
ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_SCULPT_GREASE_PENCIL, OB_MODE_WEIGHT_GREASE_PENCIL));
|
||||
}
|
||||
|
||||
if (ob->type == OB_LAMP && inst->use_lights) {
|
||||
gpencil_light_pool_populate(inst->global_light_pool, ob);
|
||||
if (ob->type == OB_LAMP && this->use_lights) {
|
||||
gpencil_light_pool_populate(this->global_light_pool, ob);
|
||||
}
|
||||
}
|
||||
|
||||
void GPENCIL_cache_finish(void *ved)
|
||||
void Instance::end_sync()
|
||||
{
|
||||
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
|
||||
/* Upload UBO data. */
|
||||
BLI_memblock_iter iter;
|
||||
BLI_memblock_iternew(inst->gp_material_pool, &iter);
|
||||
BLI_memblock_iternew(this->gp_material_pool, &iter);
|
||||
GPENCIL_MaterialPool *pool;
|
||||
while ((pool = (GPENCIL_MaterialPool *)BLI_memblock_iterstep(&iter))) {
|
||||
GPU_uniformbuf_update(pool->ubo, pool->mat_data);
|
||||
}
|
||||
|
||||
BLI_memblock_iternew(inst->gp_light_pool, &iter);
|
||||
BLI_memblock_iternew(this->gp_light_pool, &iter);
|
||||
GPENCIL_LightPool *lpool;
|
||||
while ((lpool = (GPENCIL_LightPool *)BLI_memblock_iterstep(&iter))) {
|
||||
GPU_uniformbuf_update(lpool->ubo, lpool->light_data);
|
||||
}
|
||||
}
|
||||
|
||||
void GPENCIL_Instance::acquire_resources()
|
||||
void Instance::acquire_resources()
|
||||
{
|
||||
/* Create frame-buffers only if needed. */
|
||||
if (this->tobjects.first == nullptr) {
|
||||
@@ -690,7 +676,7 @@ void GPENCIL_Instance::acquire_resources()
|
||||
}
|
||||
}
|
||||
|
||||
void GPENCIL_Instance::release_resources()
|
||||
void Instance::release_resources()
|
||||
{
|
||||
this->depth_tx.release();
|
||||
this->color_tx.release();
|
||||
@@ -706,12 +692,11 @@ void GPENCIL_Instance::release_resources()
|
||||
this->smaa_weight_tx.release();
|
||||
}
|
||||
|
||||
static void gpencil_draw_mask(GPENCIL_Data *vedata,
|
||||
static void gpencil_draw_mask(Instance *inst,
|
||||
blender::draw::View &view,
|
||||
GPENCIL_tObject *ob,
|
||||
GPENCIL_tLayer *layer)
|
||||
{
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
blender::draw::Manager *manager = DRW_manager_get();
|
||||
|
||||
const float clear_col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
@@ -759,11 +744,8 @@ static void gpencil_draw_mask(GPENCIL_Data *vedata,
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
static void GPENCIL_draw_object(GPENCIL_Data *vedata,
|
||||
blender::draw::View &view,
|
||||
GPENCIL_tObject *ob)
|
||||
static void GPENCIL_draw_object(Instance *inst, blender::draw::View &view, GPENCIL_tObject *ob)
|
||||
{
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
blender::draw::Manager *manager = DRW_manager_get();
|
||||
|
||||
const float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
|
||||
@@ -781,7 +763,7 @@ static void GPENCIL_draw_object(GPENCIL_Data *vedata,
|
||||
|
||||
LISTBASE_FOREACH (GPENCIL_tLayer *, layer, &ob->layers) {
|
||||
if (layer->mask_bits) {
|
||||
gpencil_draw_mask(vedata, view, ob, layer);
|
||||
gpencil_draw_mask(inst, view, ob, layer);
|
||||
}
|
||||
|
||||
if (layer->blend_ps) {
|
||||
@@ -816,10 +798,8 @@ static void GPENCIL_draw_object(GPENCIL_Data *vedata,
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
static void GPENCIL_fast_draw_start(GPENCIL_Data *vedata)
|
||||
static void GPENCIL_fast_draw_start(Instance *inst)
|
||||
{
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
if (!inst->snapshot_buffer_dirty) {
|
||||
@@ -832,10 +812,8 @@ static void GPENCIL_fast_draw_start(GPENCIL_Data *vedata)
|
||||
}
|
||||
}
|
||||
|
||||
static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata, blender::draw::View &view)
|
||||
static void GPENCIL_fast_draw_end(Instance *inst, blender::draw::View &view)
|
||||
{
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
if (inst->snapshot_buffer_dirty) {
|
||||
@@ -847,109 +825,92 @@ static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata, blender::draw::View &vie
|
||||
}
|
||||
/* Draw the sbuffer stroke(s). */
|
||||
LISTBASE_FOREACH (GPENCIL_tObject *, ob, &inst->sbuffer_tobjects) {
|
||||
GPENCIL_draw_object(vedata, view, ob);
|
||||
GPENCIL_draw_object(inst, view, ob);
|
||||
}
|
||||
}
|
||||
|
||||
void GPENCIL_draw_scene(void *ved)
|
||||
void Instance::draw(Manager & /*manager*/)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
|
||||
GPENCIL_Instance &inst = *vedata->instance;
|
||||
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
|
||||
if (inst.render_depth_tx.is_valid()) {
|
||||
inst.scene_depth_tx = inst.render_depth_tx;
|
||||
inst.scene_fb = inst.render_fb;
|
||||
if (this->render_depth_tx.is_valid()) {
|
||||
this->scene_depth_tx = this->render_depth_tx;
|
||||
this->scene_fb = this->render_fb;
|
||||
}
|
||||
else {
|
||||
inst.scene_fb = dfbl->default_fb;
|
||||
inst.scene_depth_tx = dtxl->depth;
|
||||
this->scene_fb = dfbl->default_fb;
|
||||
this->scene_depth_tx = dtxl->depth;
|
||||
}
|
||||
BLI_assert(inst.scene_depth_tx);
|
||||
BLI_assert(this->scene_depth_tx);
|
||||
|
||||
float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
|
||||
|
||||
/* Fade 3D objects. */
|
||||
if ((!inst.is_render) && (inst.fade_3d_object_opacity > -1.0f) && (inst.obact != nullptr) &&
|
||||
ELEM(inst.obact->type, OB_GREASE_PENCIL))
|
||||
if ((!this->is_render) && (this->fade_3d_object_opacity > -1.0f) && (this->obact != nullptr) &&
|
||||
ELEM(this->obact->type, OB_GREASE_PENCIL))
|
||||
{
|
||||
float background_color[3];
|
||||
ED_view3d_background_color_get(inst.scene, inst.v3d, background_color);
|
||||
ED_view3d_background_color_get(this->scene, this->v3d, background_color);
|
||||
/* Blend color. */
|
||||
interp_v3_v3v3(clear_cols[0], background_color, clear_cols[0], inst.fade_3d_object_opacity);
|
||||
interp_v3_v3v3(clear_cols[0], background_color, clear_cols[0], this->fade_3d_object_opacity);
|
||||
|
||||
mul_v4_fl(clear_cols[1], inst.fade_3d_object_opacity);
|
||||
mul_v4_fl(clear_cols[1], this->fade_3d_object_opacity);
|
||||
}
|
||||
|
||||
/* Sort object by decreasing Z to avoid most of alpha ordering issues. */
|
||||
gpencil_object_cache_sort(&inst);
|
||||
gpencil_object_cache_sort(this);
|
||||
|
||||
if (inst.tobjects.first == nullptr) {
|
||||
if (this->tobjects.first == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
DRW_submission_start();
|
||||
|
||||
GPENCIL_antialiasing_init(&inst);
|
||||
GPENCIL_antialiasing_init(this);
|
||||
|
||||
inst.acquire_resources();
|
||||
this->acquire_resources();
|
||||
|
||||
if (inst.do_fast_drawing) {
|
||||
GPENCIL_fast_draw_start(vedata);
|
||||
if (this->do_fast_drawing) {
|
||||
GPENCIL_fast_draw_start(this);
|
||||
}
|
||||
|
||||
if (inst.tobjects.first) {
|
||||
GPU_framebuffer_bind(inst.gpencil_fb);
|
||||
GPU_framebuffer_multi_clear(inst.gpencil_fb, clear_cols);
|
||||
if (this->tobjects.first) {
|
||||
GPU_framebuffer_bind(this->gpencil_fb);
|
||||
GPU_framebuffer_multi_clear(this->gpencil_fb, clear_cols);
|
||||
}
|
||||
|
||||
blender::draw::View &view = blender::draw::View::default_get();
|
||||
|
||||
LISTBASE_FOREACH (GPENCIL_tObject *, ob, &inst.tobjects) {
|
||||
GPENCIL_draw_object(vedata, view, ob);
|
||||
LISTBASE_FOREACH (GPENCIL_tObject *, ob, &this->tobjects) {
|
||||
GPENCIL_draw_object(this, view, ob);
|
||||
}
|
||||
|
||||
if (inst.do_fast_drawing) {
|
||||
GPENCIL_fast_draw_end(vedata, view);
|
||||
if (this->do_fast_drawing) {
|
||||
GPENCIL_fast_draw_end(this, view);
|
||||
}
|
||||
|
||||
if (inst.scene_fb) {
|
||||
GPENCIL_antialiasing_draw(vedata);
|
||||
if (this->scene_fb) {
|
||||
GPENCIL_antialiasing_draw(this);
|
||||
}
|
||||
|
||||
inst.gp_object_pool = inst.gp_maskbit_pool = nullptr;
|
||||
inst.gp_vfx_pool = nullptr;
|
||||
inst.gp_layer_pool = nullptr;
|
||||
this->gp_object_pool = this->gp_maskbit_pool = nullptr;
|
||||
this->gp_vfx_pool = nullptr;
|
||||
this->gp_layer_pool = nullptr;
|
||||
|
||||
inst.release_resources();
|
||||
this->release_resources();
|
||||
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
static void GPENCIL_engine_free()
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
GPENCIL_shader_free();
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
static void GPENCIL_instance_free(void *instance)
|
||||
void Engine::free_static()
|
||||
{
|
||||
delete reinterpret_cast<GPENCIL_Instance *>(instance);
|
||||
ShaderCache::release();
|
||||
}
|
||||
|
||||
DrawEngineType draw_engine_gpencil_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("GpencilMode"),
|
||||
/*engine_init*/ &GPENCIL_engine_init,
|
||||
/*engine_free*/ &GPENCIL_engine_free,
|
||||
/*instance_free*/ &GPENCIL_instance_free,
|
||||
/*cache_init*/ &GPENCIL_cache_init,
|
||||
/*cache_populate*/ &GPENCIL_cache_populate,
|
||||
/*cache_finish*/ &GPENCIL_cache_finish,
|
||||
/*draw_scene*/ &GPENCIL_draw_scene,
|
||||
/*render_to_image*/ &GPENCIL_render_to_image,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_memblock.h"
|
||||
#include "DRW_render.hh"
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
@@ -22,10 +23,9 @@
|
||||
#define GP_LIGHT
|
||||
|
||||
#include "gpencil_defines.h"
|
||||
#include "gpencil_shader.hh"
|
||||
#include "gpencil_shader_shared.h"
|
||||
|
||||
extern DrawEngineType draw_engine_gpencil_type;
|
||||
|
||||
struct GPENCIL_Data;
|
||||
struct GPENCIL_StorageList;
|
||||
namespace blender::gpu {
|
||||
@@ -45,13 +45,13 @@ struct View3D;
|
||||
|
||||
#define GP_MAX_MASKBITS 256
|
||||
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
struct GPENCIL_tVfx;
|
||||
struct GPENCIL_tLayer;
|
||||
|
||||
using PassSimple = blender::draw::PassSimple;
|
||||
using Texture = blender::draw::Texture;
|
||||
using TextureFromPool = blender::draw::TextureFromPool;
|
||||
using Framebuffer = blender::draw::Framebuffer;
|
||||
/* NOTE: These do not preserve the PassSimple memory across frames.
|
||||
* If that becomes a bottleneck, these containers can be improved. */
|
||||
using GPENCIL_tVfx_Pool = blender::draw::detail::SubPassVector<GPENCIL_tVfx>;
|
||||
@@ -81,21 +81,6 @@ typedef struct GPENCIL_LightPool {
|
||||
int light_used;
|
||||
} GPENCIL_LightPool;
|
||||
|
||||
struct GPENCIL_ViewLayerData {
|
||||
/* GPENCIL_tObject */
|
||||
struct BLI_memblock *gp_object_pool;
|
||||
/* GPENCIL_tLayer */
|
||||
GPENCIL_tLayer_Pool *gp_layer_pool;
|
||||
/* GPENCIL_tVfx */
|
||||
GPENCIL_tVfx_Pool *gp_vfx_pool;
|
||||
/* GPENCIL_MaterialPool */
|
||||
struct BLI_memblock *gp_material_pool;
|
||||
/* GPENCIL_LightPool */
|
||||
struct BLI_memblock *gp_light_pool;
|
||||
/* BLI_bitmap */
|
||||
struct BLI_memblock *gp_maskbit_pool;
|
||||
};
|
||||
|
||||
/* *********** GPencil *********** */
|
||||
|
||||
struct GPENCIL_tVfx {
|
||||
@@ -148,12 +133,46 @@ typedef struct GPENCIL_tObject {
|
||||
|
||||
} GPENCIL_tObject;
|
||||
|
||||
/* *********** LISTS *********** */
|
||||
typedef struct GPENCIL_StorageList {
|
||||
struct GPENCIL_Instance *inst;
|
||||
} GPENCIL_StorageList;
|
||||
struct ViewLayerData {
|
||||
/* GPENCIL_tObject */
|
||||
struct BLI_memblock *gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject));
|
||||
/* GPENCIL_tLayer */
|
||||
GPENCIL_tLayer_Pool *gp_layer_pool = new GPENCIL_tLayer_Pool();
|
||||
/* GPENCIL_tVfx */
|
||||
GPENCIL_tVfx_Pool *gp_vfx_pool = new GPENCIL_tVfx_Pool();
|
||||
/* GPENCIL_MaterialPool */
|
||||
struct BLI_memblock *gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool));
|
||||
/* GPENCIL_LightPool */
|
||||
struct BLI_memblock *gp_light_pool = BLI_memblock_create(sizeof(GPENCIL_LightPool));
|
||||
/* BLI_bitmap */
|
||||
struct BLI_memblock *gp_maskbit_pool = BLI_memblock_create(BLI_BITMAP_SIZE(GP_MAX_MASKBITS));
|
||||
|
||||
struct GPENCIL_Instance {
|
||||
~ViewLayerData()
|
||||
{
|
||||
BLI_memblock_destroy(gp_light_pool, light_pool_free);
|
||||
BLI_memblock_destroy(gp_material_pool, material_pool_free);
|
||||
BLI_memblock_destroy(gp_maskbit_pool, nullptr);
|
||||
BLI_memblock_destroy(gp_object_pool, nullptr);
|
||||
delete gp_layer_pool;
|
||||
delete gp_vfx_pool;
|
||||
}
|
||||
|
||||
static void material_pool_free(void *storage)
|
||||
{
|
||||
GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage;
|
||||
GPU_UBO_FREE_SAFE(matpool->ubo);
|
||||
}
|
||||
|
||||
static void light_pool_free(void *storage)
|
||||
{
|
||||
GPENCIL_LightPool *lightpool = (GPENCIL_LightPool *)storage;
|
||||
GPU_UBO_FREE_SAFE(lightpool->ubo);
|
||||
}
|
||||
};
|
||||
|
||||
/* *********** LISTS *********** */
|
||||
|
||||
struct Instance : public DrawEngine {
|
||||
PassSimple smaa_edge_ps = {"smaa_edge"};
|
||||
PassSimple smaa_weight_ps = {"smaa_weight"};
|
||||
PassSimple smaa_resolve_ps = {"smaa_resolve"};
|
||||
@@ -204,7 +223,9 @@ struct GPENCIL_Instance {
|
||||
Framebuffer smaa_edge_fb = {"smaa_edge_fb"};
|
||||
Framebuffer smaa_weight_fb = {"smaa_weight_fb"};
|
||||
|
||||
/* Pointers copied from GPENCIL_ViewLayerData. */
|
||||
ViewLayerData vldata;
|
||||
|
||||
/* Pointers copied from blender::draw::gpencil::ViewLayerData. */
|
||||
struct BLI_memblock *gp_object_pool;
|
||||
GPENCIL_tLayer_Pool *gp_layer_pool;
|
||||
GPENCIL_tVfx_Pool *gp_vfx_pool;
|
||||
@@ -310,11 +331,24 @@ struct GPENCIL_Instance {
|
||||
|
||||
void acquire_resources();
|
||||
void release_resources();
|
||||
|
||||
blender::StringRefNull name_get() final
|
||||
{
|
||||
return "Grease Pencil";
|
||||
}
|
||||
|
||||
void init() final;
|
||||
|
||||
void begin_sync() final;
|
||||
void object_sync(blender::draw::ObjectRef &ob_ref, blender::draw::Manager &manager) final;
|
||||
void end_sync() final;
|
||||
|
||||
void draw(blender::draw::Manager &manager) final;
|
||||
};
|
||||
|
||||
struct GPENCIL_Data {
|
||||
void *engine_type; /* Required */
|
||||
struct GPENCIL_Instance *instance;
|
||||
struct Instance *instance;
|
||||
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
@@ -322,17 +356,17 @@ struct GPENCIL_Data {
|
||||
/* geometry batch cache functions */
|
||||
struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra);
|
||||
|
||||
GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_Instance *inst,
|
||||
GPENCIL_tObject *gpencil_object_cache_add(Instance *inst,
|
||||
Object *ob,
|
||||
bool is_stroke_order_3d,
|
||||
blender::Bounds<float3> bounds);
|
||||
void gpencil_object_cache_sort(GPENCIL_Instance *inst);
|
||||
void gpencil_object_cache_sort(Instance *inst);
|
||||
|
||||
GPENCIL_tLayer *grease_pencil_layer_cache_get(GPENCIL_tObject *tgp_ob,
|
||||
int layer_id,
|
||||
bool skip_onion);
|
||||
|
||||
GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst,
|
||||
GPENCIL_tLayer *grease_pencil_layer_cache_add(Instance *inst,
|
||||
const Object *ob,
|
||||
const blender::bke::greasepencil::Layer &layer,
|
||||
int onion_id,
|
||||
@@ -343,7 +377,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst,
|
||||
* We merge the material pools together if object does not contain a huge amount of materials.
|
||||
* Also return an offset to the first material of the object in the UBO.
|
||||
*/
|
||||
GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_Instance *inst,
|
||||
GPENCIL_MaterialPool *gpencil_material_pool_create(Instance *inst,
|
||||
Object *ob,
|
||||
int *ofs,
|
||||
bool is_vertex_mode);
|
||||
@@ -355,62 +389,22 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
|
||||
|
||||
void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]);
|
||||
void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob);
|
||||
GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_Instance *inst);
|
||||
GPENCIL_LightPool *gpencil_light_pool_add(Instance *inst);
|
||||
/**
|
||||
* Creates a single pool containing all lights assigned (light linked) for a given object.
|
||||
*/
|
||||
GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_Instance *inst, Object *ob);
|
||||
GPENCIL_LightPool *gpencil_light_pool_create(Instance *inst, Object *ob);
|
||||
|
||||
/* effects */
|
||||
void gpencil_vfx_cache_populate(GPENCIL_Data *vedata,
|
||||
void gpencil_vfx_cache_populate(Instance *inst,
|
||||
Object *ob,
|
||||
GPENCIL_tObject *tgp_ob,
|
||||
const bool is_edit_mode);
|
||||
|
||||
/* Shaders */
|
||||
struct GPUShader *GPENCIL_shader_antialiasing(int stage);
|
||||
struct GPUShader *GPENCIL_shader_geometry_get(void);
|
||||
struct GPUShader *GPENCIL_shader_layer_blend_get(void);
|
||||
struct GPUShader *GPENCIL_shader_mask_invert_get(void);
|
||||
struct GPUShader *GPENCIL_shader_depth_merge_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_blur_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_colorize_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_composite_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_transform_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_glow_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_pixelize_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_rim_get(void);
|
||||
struct GPUShader *GPENCIL_shader_fx_shadow_get(void);
|
||||
|
||||
void GPENCIL_shader_free(void);
|
||||
|
||||
/* Antialiasing */
|
||||
void GPENCIL_antialiasing_init(GPENCIL_Instance *inst);
|
||||
void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata);
|
||||
|
||||
/* main functions */
|
||||
void GPENCIL_engine_init(void *vedata);
|
||||
void GPENCIL_cache_init(void *vedata);
|
||||
void GPENCIL_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref);
|
||||
void GPENCIL_cache_finish(void *vedata);
|
||||
void GPENCIL_draw_scene(void *vedata);
|
||||
void GPENCIL_antialiasing_init(Instance *inst);
|
||||
void GPENCIL_antialiasing_draw(Instance *inst);
|
||||
|
||||
/* render */
|
||||
|
||||
/**
|
||||
* Initialize render data.
|
||||
*/
|
||||
void GPENCIL_render_init(struct GPENCIL_Data *ved,
|
||||
struct RenderEngine *engine,
|
||||
struct RenderLayer *render_layer,
|
||||
const struct Depsgraph *depsgraph,
|
||||
const rcti *rect);
|
||||
void GPENCIL_render_to_image(void *vedata,
|
||||
struct RenderEngine *engine,
|
||||
struct RenderLayer *render_layer,
|
||||
const rcti *rect);
|
||||
|
||||
/* Draw Data. */
|
||||
void gpencil_light_pool_free(void *storage);
|
||||
void gpencil_material_pool_free(void *storage);
|
||||
GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void);
|
||||
} // namespace blender::draw::gpencil
|
||||
@@ -19,19 +19,16 @@
|
||||
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
#include "gpencil_engine_private.hh"
|
||||
|
||||
void GPENCIL_render_init(GPENCIL_Data *vedata,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const Depsgraph *depsgraph,
|
||||
const rcti *rect)
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
static void render_init(Instance &inst,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const Depsgraph *depsgraph,
|
||||
const rcti *rect)
|
||||
{
|
||||
if (vedata->instance == nullptr) {
|
||||
vedata->instance = new GPENCIL_Instance();
|
||||
}
|
||||
GPENCIL_Instance &inst = *vedata->instance;
|
||||
|
||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
const int2 size = int2(DRW_viewport_size_get());
|
||||
|
||||
@@ -140,25 +137,10 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
|
||||
MEM_SAFE_FREE(pix_z);
|
||||
}
|
||||
|
||||
/* render all objects and select only grease pencil */
|
||||
static void GPENCIL_render_cache(void *vedata,
|
||||
blender::draw::ObjectRef &ob_ref,
|
||||
RenderEngine * /*engine*/,
|
||||
Depsgraph * /*depsgraph*/)
|
||||
{
|
||||
if (!ELEM(ob_ref.object->type, OB_GREASE_PENCIL, OB_LAMP)) {
|
||||
return;
|
||||
}
|
||||
if (!(DRW_object_visibility_in_active_context(ob_ref.object) & OB_VISIBLE_SELF)) {
|
||||
return;
|
||||
}
|
||||
GPENCIL_cache_populate(vedata, ob_ref);
|
||||
}
|
||||
|
||||
static void GPENCIL_render_result_z(RenderLayer *rl,
|
||||
const char *viewname,
|
||||
GPENCIL_Data *vedata,
|
||||
const rcti *rect)
|
||||
static void render_result_z(RenderLayer *rl,
|
||||
const char *viewname,
|
||||
Instance &instance,
|
||||
const rcti *rect)
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
ViewLayer *view_layer = draw_ctx->view_layer;
|
||||
@@ -172,7 +154,7 @@ static void GPENCIL_render_result_z(RenderLayer *rl,
|
||||
|
||||
float *ro_buffer_data = rp->ibuf->float_buffer.data;
|
||||
|
||||
GPU_framebuffer_read_depth(vedata->instance->render_fb,
|
||||
GPU_framebuffer_read_depth(instance.render_fb,
|
||||
rect->xmin,
|
||||
rect->ymin,
|
||||
BLI_rcti_size_x(rect),
|
||||
@@ -213,15 +195,15 @@ static void GPENCIL_render_result_z(RenderLayer *rl,
|
||||
}
|
||||
}
|
||||
|
||||
static void GPENCIL_render_result_combined(RenderLayer *rl,
|
||||
const char *viewname,
|
||||
GPENCIL_Data *vedata,
|
||||
const rcti *rect)
|
||||
static void render_result_combined(RenderLayer *rl,
|
||||
const char *viewname,
|
||||
Instance &instance,
|
||||
const rcti *rect)
|
||||
{
|
||||
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
|
||||
|
||||
GPU_framebuffer_bind(vedata->instance->render_fb);
|
||||
GPU_framebuffer_read_color(vedata->instance->render_fb,
|
||||
GPU_framebuffer_bind(instance.render_fb);
|
||||
GPU_framebuffer_read_color(instance.render_fb,
|
||||
rect->xmin,
|
||||
rect->ymin,
|
||||
BLI_rcti_size_x(rect),
|
||||
@@ -232,33 +214,45 @@ static void GPENCIL_render_result_combined(RenderLayer *rl,
|
||||
rp->ibuf->float_buffer.data);
|
||||
}
|
||||
|
||||
void GPENCIL_render_to_image(void *ved,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const rcti *rect)
|
||||
void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti rect)
|
||||
{
|
||||
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
|
||||
const char *viewname = RE_GetActiveRenderView(engine->re);
|
||||
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
Depsgraph *depsgraph = draw_ctx->depsgraph;
|
||||
|
||||
DRW_manager_get()->begin_sync();
|
||||
blender::draw::gpencil::Instance inst;
|
||||
|
||||
GPENCIL_render_init(vedata, engine, render_layer, depsgraph, rect);
|
||||
GPENCIL_engine_init(vedata);
|
||||
Manager &manager = *DRW_manager_get();
|
||||
|
||||
vedata->instance->camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
render_init(inst, engine, render_layer, depsgraph, &rect);
|
||||
inst.init();
|
||||
|
||||
inst.camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
|
||||
manager.begin_sync();
|
||||
|
||||
/* Loop over all objects and create draw structure. */
|
||||
GPENCIL_cache_init(vedata);
|
||||
DRW_render_object_iter(vedata, engine, depsgraph, GPENCIL_render_cache);
|
||||
GPENCIL_cache_finish(vedata);
|
||||
inst.begin_sync();
|
||||
DRW_render_object_iter(
|
||||
engine, depsgraph, [&](blender::draw::ObjectRef &ob_ref, RenderEngine *, Depsgraph *) {
|
||||
if (!ELEM(ob_ref.object->type, OB_GREASE_PENCIL, OB_LAMP)) {
|
||||
return;
|
||||
}
|
||||
if (!(DRW_object_visibility_in_active_context(ob_ref.object) & OB_VISIBLE_SELF)) {
|
||||
return;
|
||||
}
|
||||
inst.object_sync(ob_ref, manager);
|
||||
});
|
||||
inst.end_sync();
|
||||
|
||||
DRW_manager_get()->end_sync();
|
||||
manager.end_sync();
|
||||
|
||||
/* Render the gpencil object and merge the result to the underlying render. */
|
||||
GPENCIL_draw_scene(vedata);
|
||||
inst.draw(manager);
|
||||
|
||||
GPENCIL_render_result_combined(render_layer, viewname, vedata, rect);
|
||||
GPENCIL_render_result_z(render_layer, viewname, vedata, rect);
|
||||
render_result_combined(render_layer, viewname, inst, &rect);
|
||||
render_result_z(render_layer, viewname, inst, &rect);
|
||||
}
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
/** \file
|
||||
* \ingroup draw
|
||||
*/
|
||||
#include "DRW_render.hh"
|
||||
|
||||
#include "BLI_string.h"
|
||||
#pragma once
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
#include "GPU_shader.hh"
|
||||
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
@@ -57,78 +56,3 @@ class ShaderCache {
|
||||
};
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
using namespace blender::draw::gpencil;
|
||||
|
||||
void GPENCIL_shader_free()
|
||||
{
|
||||
ShaderCache::get().release();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_antialiasing(int stage)
|
||||
{
|
||||
BLI_assert(stage < 3);
|
||||
return ShaderCache::get().antialiasing[stage].get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_geometry_get()
|
||||
{
|
||||
return ShaderCache::get().geometry.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_layer_blend_get()
|
||||
{
|
||||
return ShaderCache::get().layer_blend.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_mask_invert_get()
|
||||
{
|
||||
return ShaderCache::get().mask_invert.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_depth_merge_get()
|
||||
{
|
||||
return ShaderCache::get().depth_merge.get();
|
||||
}
|
||||
|
||||
/* ------- FX Shaders --------- */
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_blur_get()
|
||||
{
|
||||
return ShaderCache::get().fx_blur.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_colorize_get()
|
||||
{
|
||||
return ShaderCache::get().fx_colorize.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_composite_get()
|
||||
{
|
||||
return ShaderCache::get().fx_composite.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_glow_get()
|
||||
{
|
||||
return ShaderCache::get().fx_glow.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_pixelize_get()
|
||||
{
|
||||
return ShaderCache::get().fx_pixelize.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_rim_get()
|
||||
{
|
||||
return ShaderCache::get().fx_rim.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_shadow_get()
|
||||
{
|
||||
return ShaderCache::get().fx_shadow.get();
|
||||
}
|
||||
|
||||
GPUShader *GPENCIL_shader_fx_transform_get()
|
||||
{
|
||||
return ShaderCache::get().fx_transform.get();
|
||||
}
|
||||
@@ -20,7 +20,9 @@
|
||||
|
||||
#include "BKE_camera.h"
|
||||
|
||||
#include "gpencil_engine.h"
|
||||
#include "gpencil_engine_private.hh"
|
||||
|
||||
namespace blender::draw::gpencil {
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
@@ -45,7 +47,7 @@ static bool effect_is_active(ShaderFxData *fx, bool is_edit, bool is_viewport)
|
||||
}
|
||||
|
||||
struct gpIterVfxData {
|
||||
GPENCIL_Instance *inst;
|
||||
Instance *inst;
|
||||
GPENCIL_tObject *tgp_ob;
|
||||
GPUFrameBuffer **target_fb;
|
||||
GPUFrameBuffer **source_fb;
|
||||
@@ -118,7 +120,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
|
||||
mul_v2_fl(blur_size, distance_factor);
|
||||
}
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_blur_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_blur.get();
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
if (blur_size[0] > 0.0f) {
|
||||
@@ -137,7 +139,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
|
||||
|
||||
static void gpencil_vfx_colorize(ColorizeShaderFxData *fx, Object * /*ob*/, gpIterVfxData *iter)
|
||||
{
|
||||
GPUShader *sh = GPENCIL_shader_fx_colorize_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_colorize.get();
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
auto &grp = gpencil_vfx_pass_create("Fx Colorize", state, iter, sh);
|
||||
@@ -154,7 +156,7 @@ static void gpencil_vfx_flip(FlipShaderFxData *fx, Object * /*ob*/, gpIterVfxDat
|
||||
axis_flip[0] = (fx->flag & FX_FLIP_HORIZONTAL) ? -1.0f : 1.0f;
|
||||
axis_flip[1] = (fx->flag & FX_FLIP_VERTICAL) ? -1.0f : 1.0f;
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_transform_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_transform.get();
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
auto &grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh);
|
||||
@@ -184,7 +186,7 @@ static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter
|
||||
mul_v2_v2(offset, vp_size_inv);
|
||||
mul_v2_fl(blur_size, distance_factor);
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_rim_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_rim.get();
|
||||
|
||||
{
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
@@ -267,7 +269,7 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat
|
||||
/* Center to texel */
|
||||
madd_v2_v2fl(ob_center, pixel_size, -0.5f);
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_pixelize_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_pixelize.get();
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
|
||||
@@ -374,7 +376,7 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData
|
||||
wave_phase = 0.0f;
|
||||
}
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_shadow_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_shadow.get();
|
||||
|
||||
copy_v2_fl2(blur_dir, blur_size[0] * vp_size_inv[0], 0.0f);
|
||||
|
||||
@@ -422,7 +424,7 @@ static void gpencil_vfx_glow(GlowShaderFxData *fx, Object * /*ob*/, gpIterVfxDat
|
||||
const float s = sin(fx->rotation);
|
||||
const float c = cos(fx->rotation);
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_glow_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_glow.get();
|
||||
|
||||
float ref_col[4];
|
||||
|
||||
@@ -528,7 +530,7 @@ static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *it
|
||||
/* Phase start at shadow center. */
|
||||
wave_phase = fx->phase - dot_v2v2(wave_center, wave_dir);
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_transform_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_transform.get();
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
auto &grp = gpencil_vfx_pass_create("Fx Wave", state, iter, sh);
|
||||
@@ -572,7 +574,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object * /*ob*/, gpIterVfxD
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_transform_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_transform.get();
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
auto &grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh);
|
||||
@@ -584,13 +586,11 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object * /*ob*/, gpIterVfxD
|
||||
grp.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
|
||||
void gpencil_vfx_cache_populate(GPENCIL_Data *vedata,
|
||||
void gpencil_vfx_cache_populate(Instance *inst,
|
||||
Object *ob,
|
||||
GPENCIL_tObject *tgp_ob,
|
||||
const bool is_edit_mode)
|
||||
{
|
||||
GPENCIL_Instance *inst = vedata->instance;
|
||||
|
||||
/* These may not be allocated yet, use address of future pointer. */
|
||||
gpIterVfxData iter{};
|
||||
iter.inst = inst;
|
||||
@@ -645,7 +645,7 @@ void gpencil_vfx_cache_populate(GPENCIL_Data *vedata,
|
||||
/* We need an extra pass to combine result to main buffer. */
|
||||
iter.target_fb = &inst->gpencil_fb;
|
||||
|
||||
GPUShader *sh = GPENCIL_shader_fx_composite_get();
|
||||
GPUShader *sh = ShaderCache::get().fx_composite.get();
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL;
|
||||
auto &grp = gpencil_vfx_pass_create("GPencil Object Compose", state, &iter, sh);
|
||||
@@ -662,3 +662,5 @@ void gpencil_vfx_cache_populate(GPENCIL_Data *vedata,
|
||||
inst->use_layer_fb = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::draw::gpencil
|
||||
|
||||
@@ -8,96 +8,20 @@
|
||||
* Draw engine to draw the Image/UV editor
|
||||
*/
|
||||
|
||||
#include "DRW_render.hh"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_image.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_object.hh"
|
||||
|
||||
#include "ED_image.hh"
|
||||
|
||||
#include "draw_view_data.hh"
|
||||
|
||||
#include "image_drawing_mode.hh"
|
||||
#include "image_engine.h"
|
||||
#include "image_instance.hh"
|
||||
#include "image_shader.hh"
|
||||
|
||||
namespace blender::image_engine {
|
||||
|
||||
struct IMAGE_Data {
|
||||
void *engine_type;
|
||||
Instance *instance;
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Callbacks
|
||||
* \{ */
|
||||
|
||||
static void IMAGE_engine_init(void *vedata)
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
IMAGE_Data *ved = reinterpret_cast<IMAGE_Data *>(vedata);
|
||||
if (ved->instance == nullptr) {
|
||||
ved->instance = new image_engine::Instance();
|
||||
}
|
||||
|
||||
const DRWContext *ctx_state = DRW_context_get();
|
||||
Main *bmain = CTX_data_main(ctx_state->evil_C);
|
||||
ved->instance->init(bmain, ctx_state->space_data, ctx_state->region);
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
static void IMAGE_cache_init(void *vedata)
|
||||
{
|
||||
IMAGE_Data *ved = reinterpret_cast<IMAGE_Data *>(vedata);
|
||||
ved->instance->begin_sync();
|
||||
ved->instance->image_sync();
|
||||
}
|
||||
|
||||
static void IMAGE_cache_populate(void * /*vedata*/, blender::draw::ObjectRef & /*ob_ref*/)
|
||||
{
|
||||
/* Function intentional left empty. `cache_populate` is required to be implemented. */
|
||||
}
|
||||
|
||||
static void IMAGE_draw_scene(void *vedata)
|
||||
{
|
||||
IMAGE_Data *ved = reinterpret_cast<IMAGE_Data *>(vedata);
|
||||
DRW_submission_start();
|
||||
ved->instance->draw_viewport();
|
||||
ved->instance->draw_finish();
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
static void IMAGE_engine_free()
|
||||
void Engine::free_static()
|
||||
{
|
||||
ShaderModule::module_free();
|
||||
}
|
||||
|
||||
static void IMAGE_instance_free(void *instance)
|
||||
{
|
||||
delete reinterpret_cast<image_engine::Instance *>(instance);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::image_engine
|
||||
|
||||
using namespace blender::image_engine;
|
||||
|
||||
DrawEngineType draw_engine_image_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("UV/Image"),
|
||||
/*engine_init*/ &IMAGE_engine_init,
|
||||
/*engine_free*/ &IMAGE_engine_free,
|
||||
/*instance_free*/ &IMAGE_instance_free,
|
||||
/*cache_init*/ &IMAGE_cache_init,
|
||||
/*cache_populate*/ &IMAGE_cache_populate,
|
||||
/*cache_finish*/ nullptr,
|
||||
/*draw_scene*/ &IMAGE_draw_scene,
|
||||
/*render_to_image*/ nullptr,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct DrawEngineType;
|
||||
#include "DRW_render.hh"
|
||||
|
||||
extern DrawEngineType draw_engine_image_type;
|
||||
namespace blender::image_engine {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
|
||||
static void free_static();
|
||||
};
|
||||
|
||||
} // namespace blender::image_engine
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
#include <DRW_render.hh>
|
||||
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "DRW_engine.hh"
|
||||
|
||||
#include "image_drawing_mode.hh"
|
||||
#include "image_private.hh"
|
||||
#include "image_space.hh"
|
||||
@@ -33,7 +37,7 @@ static inline std::unique_ptr<AbstractSpaceAccessor> space_accessor_from_space(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class Instance {
|
||||
class Instance : public DrawEngine {
|
||||
private:
|
||||
std::unique_ptr<AbstractSpaceAccessor> space_;
|
||||
Main *main_;
|
||||
@@ -48,17 +52,23 @@ class Instance {
|
||||
public:
|
||||
Instance() : drawing_mode_(*this) {}
|
||||
|
||||
void init(Main *main, SpaceLink *space_link, const ARegion *_region)
|
||||
virtual ~Instance() = default;
|
||||
|
||||
StringRefNull name_get() final
|
||||
{
|
||||
main_ = main;
|
||||
region = _region;
|
||||
space_ = space_accessor_from_space(space_link);
|
||||
return "UV/Image";
|
||||
}
|
||||
|
||||
void init() final
|
||||
{
|
||||
const DRWContext *ctx_state = DRW_context_get();
|
||||
main_ = CTX_data_main(ctx_state->evil_C);
|
||||
region = ctx_state->region;
|
||||
space_ = space_accessor_from_space(ctx_state->space_data);
|
||||
manager = DRW_manager_get();
|
||||
}
|
||||
|
||||
virtual ~Instance() = default;
|
||||
|
||||
void begin_sync()
|
||||
void begin_sync() final
|
||||
{
|
||||
drawing_mode_.begin_sync();
|
||||
|
||||
@@ -68,6 +78,8 @@ class Instance {
|
||||
float4x4 winmat = float4x4::identity();
|
||||
state.view.sync(viewmat, winmat);
|
||||
state.flags.do_tile_drawing = false;
|
||||
|
||||
image_sync();
|
||||
}
|
||||
|
||||
void image_sync()
|
||||
@@ -102,15 +114,17 @@ class Instance {
|
||||
drawing_mode_.image_sync(state.image, iuser);
|
||||
}
|
||||
|
||||
void draw_finish()
|
||||
void object_sync(ObjectRef & /*obref*/, Manager & /*manager*/) final {}
|
||||
|
||||
void end_sync() final {}
|
||||
|
||||
void draw(Manager & /*manager */) final
|
||||
{
|
||||
DRW_submission_start();
|
||||
drawing_mode_.draw_viewport();
|
||||
drawing_mode_.draw_finish();
|
||||
state.image = nullptr;
|
||||
}
|
||||
|
||||
void draw_viewport()
|
||||
{
|
||||
drawing_mode_.draw_viewport();
|
||||
DRW_submission_end();
|
||||
}
|
||||
};
|
||||
} // namespace blender::image_engine
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct DrawEngineType;
|
||||
#include "DRW_render.hh"
|
||||
|
||||
extern DrawEngineType draw_engine_overlay_next_type;
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
|
||||
static void free_static();
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
|
||||
@@ -8,89 +8,20 @@
|
||||
* Engine for drawing a selection map where the pixels indicate the selection indices.
|
||||
*/
|
||||
|
||||
#include "DRW_engine.hh"
|
||||
#include "DRW_render.hh"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "overlay_next_instance.hh"
|
||||
|
||||
#include "overlay_engine.h"
|
||||
#include "overlay_next_private.hh"
|
||||
|
||||
using namespace blender::draw;
|
||||
namespace blender::draw::overlay {
|
||||
|
||||
using Instance = blender::draw::overlay::Instance;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Instance
|
||||
* \{ */
|
||||
|
||||
static void OVERLAY_next_engine_init(void *vedata)
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
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();
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
static void OVERLAY_next_cache_init(void *vedata)
|
||||
void Engine::free_static()
|
||||
{
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->begin_sync();
|
||||
ShaderModule::module_free();
|
||||
}
|
||||
|
||||
static void OVERLAY_next_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref)
|
||||
{
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->object_sync(ob_ref, *DRW_manager_get());
|
||||
}
|
||||
|
||||
static void OVERLAY_next_cache_finish(void *vedata)
|
||||
{
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->end_sync();
|
||||
}
|
||||
|
||||
static void OVERLAY_next_draw_scene(void *vedata)
|
||||
{
|
||||
DRW_submission_start();
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->draw(*DRW_manager_get());
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
static void OVERLAY_next_instance_free(void *instance_)
|
||||
{
|
||||
Instance *instance = (Instance *)instance_;
|
||||
delete instance;
|
||||
}
|
||||
|
||||
static void OVERLAY_next_engine_free()
|
||||
{
|
||||
overlay::ShaderModule::module_free();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Type
|
||||
* \{ */
|
||||
|
||||
DrawEngineType draw_engine_overlay_next_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("Overlay"),
|
||||
/*engine_init*/ &OVERLAY_next_engine_init,
|
||||
/*engine_free*/ &OVERLAY_next_engine_free,
|
||||
/*instance_free*/ &OVERLAY_next_instance_free,
|
||||
/*cache_init*/ &OVERLAY_next_cache_init,
|
||||
/*cache_populate*/ &OVERLAY_next_cache_populate,
|
||||
/*cache_finish*/ &OVERLAY_next_cache_finish,
|
||||
/*draw_scene*/ &OVERLAY_next_draw_scene,
|
||||
/*render_to_image*/ nullptr,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
} // namespace blender::draw::overlay
|
||||
|
||||
@@ -54,14 +54,11 @@ 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 {
|
||||
class Instance : public DrawEngine {
|
||||
const SelectionType selection_type_;
|
||||
bool clipping_enabled_;
|
||||
|
||||
public:
|
||||
/* WORKAROUND: Legacy. Move to grid pass. */
|
||||
GPUUniformBuf *grid_ubo = nullptr;
|
||||
|
||||
ShapeCache shapes;
|
||||
|
||||
/** Global types. */
|
||||
@@ -115,18 +112,19 @@ class Instance {
|
||||
AntiAliasing anti_aliasing;
|
||||
XrayFade xray_fade;
|
||||
|
||||
Instance() : selection_type_(select::SelectionType::DISABLED){};
|
||||
Instance(const SelectionType selection_type) : selection_type_(selection_type){};
|
||||
|
||||
~Instance()
|
||||
blender::StringRefNull name_get() final
|
||||
{
|
||||
GPU_UBO_FREE_SAFE(grid_ubo);
|
||||
return "Overlay";
|
||||
}
|
||||
|
||||
void init();
|
||||
void begin_sync();
|
||||
void object_sync(ObjectRef &ob_ref, Manager &manager);
|
||||
void end_sync();
|
||||
void draw(Manager &manager);
|
||||
void init() final;
|
||||
void begin_sync() final;
|
||||
void object_sync(ObjectRef &ob_ref, Manager &manager) final;
|
||||
void end_sync() final;
|
||||
void draw(Manager &manager) final;
|
||||
|
||||
private:
|
||||
bool object_is_selected(const ObjectRef &ob_ref);
|
||||
|
||||
@@ -20,21 +20,15 @@
|
||||
|
||||
#include "select_engine.hh"
|
||||
|
||||
#define SELECT_DEBUG_ENGINE "SELECT_DEBUG_ENGINE"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Structs and static variables
|
||||
* \{ */
|
||||
|
||||
struct SELECTIDDEBUG_Data {
|
||||
void *engine_type;
|
||||
};
|
||||
|
||||
namespace blender::draw::SelectDebug {
|
||||
|
||||
using StaticShader = gpu::StaticShader;
|
||||
namespace blender::draw::edit_select_debug {
|
||||
|
||||
class ShaderCache {
|
||||
using StaticShader = gpu::StaticShader;
|
||||
|
||||
private:
|
||||
static gpu::StaticShaderCache<ShaderCache> &get_static_cache()
|
||||
{
|
||||
@@ -55,63 +49,48 @@ class ShaderCache {
|
||||
StaticShader select_debug = {"select_debug_fullscreen"};
|
||||
};
|
||||
|
||||
} // namespace blender::draw::SelectDebug
|
||||
|
||||
using namespace blender::draw::SelectDebug;
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Functions
|
||||
* \{ */
|
||||
|
||||
static void select_debug_draw_scene(void * /*vedata*/)
|
||||
{
|
||||
GPUTexture *texture_u32 = DRW_engine_select_texture_get();
|
||||
if (texture_u32 == nullptr) {
|
||||
return;
|
||||
class Instance : public DrawEngine {
|
||||
StringRefNull name_get() final
|
||||
{
|
||||
return "Select ID Debug";
|
||||
}
|
||||
using namespace blender::draw;
|
||||
|
||||
PassSimple pass = {"SelectEngineDebug"};
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
|
||||
pass.shader_set(ShaderCache::get().select_debug.get());
|
||||
pass.bind_texture("image", texture_u32);
|
||||
pass.bind_texture("image", texture_u32);
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
void init() final{};
|
||||
void begin_sync() final{};
|
||||
void object_sync(blender::draw::ObjectRef & /*ob_ref*/,
|
||||
blender::draw::Manager & /*manager*/) final{};
|
||||
void end_sync() final{};
|
||||
|
||||
DRW_submission_start();
|
||||
DRW_manager_get()->submit(pass);
|
||||
DRW_submission_end();
|
||||
void draw(blender::draw::Manager &manager) final
|
||||
{
|
||||
GPUTexture *texture_u32 = DRW_engine_select_texture_get();
|
||||
if (texture_u32 == nullptr) {
|
||||
return;
|
||||
}
|
||||
using namespace blender::draw;
|
||||
|
||||
PassSimple pass = {"SelectEngineDebug"};
|
||||
pass.init();
|
||||
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
|
||||
pass.shader_set(ShaderCache::get().select_debug.get());
|
||||
pass.bind_texture("image", texture_u32);
|
||||
pass.bind_texture("image", texture_u32);
|
||||
pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
|
||||
DRW_submission_start();
|
||||
manager.submit(pass);
|
||||
DRW_submission_end();
|
||||
}
|
||||
};
|
||||
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
static void select_debug_engine_free()
|
||||
void Engine::free_static()
|
||||
{
|
||||
ShaderCache::release();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Type
|
||||
* \{ */
|
||||
|
||||
DrawEngineType draw_engine_debug_select_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("Select ID Debug"),
|
||||
/*engine_init*/ nullptr,
|
||||
/*engine_free*/ &select_debug_engine_free,
|
||||
/*instance_free*/ nullptr,
|
||||
/*cache_init*/ nullptr,
|
||||
/*cache_populate*/ nullptr,
|
||||
/*cache_finish*/ nullptr,
|
||||
/*draw_scene*/ &select_debug_draw_scene,
|
||||
/*render_to_image*/ nullptr,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
#undef SELECT_DEBUG_ENGINE
|
||||
} // namespace blender::draw::edit_select_debug
|
||||
|
||||
@@ -25,453 +25,465 @@
|
||||
#include "draw_cache_impl.hh"
|
||||
#include "draw_common_c.hh"
|
||||
#include "draw_context_private.hh"
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
#include "draw_view_data.hh"
|
||||
|
||||
#include "../overlay/overlay_next_private.hh"
|
||||
|
||||
#include "select_engine.hh"
|
||||
#include "select_private.hh"
|
||||
|
||||
#define SELECT_ENGINE "SELECT_ENGINE"
|
||||
namespace blender::draw::edit_select {
|
||||
|
||||
/* *********** STATIC *********** */
|
||||
#define USE_CAGE_OCCLUSION
|
||||
|
||||
struct SelectEngineData {
|
||||
GPUFrameBuffer *framebuffer_select_id;
|
||||
GPUTexture *texture_u32;
|
||||
struct Instance : public DrawEngine {
|
||||
private:
|
||||
PassSimple depth_only_ps = {"depth_only_ps"};
|
||||
PassSimple::Sub *depth_only = nullptr;
|
||||
PassSimple::Sub *depth_occlude = nullptr;
|
||||
|
||||
SELECTID_Shaders sh_data[GPU_SHADER_CFG_LEN];
|
||||
SELECTID_Context context;
|
||||
};
|
||||
PassSimple select_edge_ps = {"select_id_edge_ps"};
|
||||
PassSimple::Sub *select_edge = nullptr;
|
||||
|
||||
static SelectEngineData &get_engine_data()
|
||||
{
|
||||
static SelectEngineData data = {};
|
||||
return data;
|
||||
}
|
||||
PassSimple select_id_vert_ps = {"select_id_vert_ps"};
|
||||
PassSimple::Sub *select_vert = nullptr;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utils
|
||||
* \{ */
|
||||
PassSimple select_face_ps = {"select_id_face_ps"};
|
||||
PassSimple::Sub *select_face_uniform = nullptr;
|
||||
PassSimple::Sub *select_face_flat = nullptr;
|
||||
|
||||
static void select_engine_framebuffer_setup()
|
||||
{
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
int size[2];
|
||||
size[0] = GPU_texture_width(dtxl->depth);
|
||||
size[1] = GPU_texture_height(dtxl->depth);
|
||||
View view_faces = {"view_faces"};
|
||||
View view_edges = {"view_edges"};
|
||||
View view_verts = {"view_verts"};
|
||||
|
||||
if (e_data.framebuffer_select_id == nullptr) {
|
||||
e_data.framebuffer_select_id = GPU_framebuffer_create("framebuffer_select_id");
|
||||
}
|
||||
public:
|
||||
struct StaticData {
|
||||
GPUFrameBuffer *framebuffer_select_id;
|
||||
GPUTexture *texture_u32;
|
||||
|
||||
if ((e_data.texture_u32 != nullptr) && ((GPU_texture_width(e_data.texture_u32) != size[0]) ||
|
||||
(GPU_texture_height(e_data.texture_u32) != size[1])))
|
||||
{
|
||||
GPU_texture_free(e_data.texture_u32);
|
||||
e_data.texture_u32 = nullptr;
|
||||
}
|
||||
struct Shaders {
|
||||
/* Depth Pre Pass */
|
||||
GPUShader *select_id_flat;
|
||||
GPUShader *select_id_uniform;
|
||||
} sh_data[GPU_SHADER_CFG_LEN];
|
||||
|
||||
/* Make sure the depth texture is attached.
|
||||
* It may disappear when loading another Blender session. */
|
||||
GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, dtxl->depth, 0, 0);
|
||||
SELECTID_Context context;
|
||||
|
||||
if (e_data.texture_u32 == nullptr) {
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
e_data.texture_u32 = GPU_texture_create_2d(
|
||||
"select_buf_ids", size[0], size[1], 1, GPU_R32UI, usage, nullptr);
|
||||
GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, e_data.texture_u32, 0, 0);
|
||||
|
||||
GPU_framebuffer_check_valid(e_data.framebuffer_select_id, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Functions
|
||||
* \{ */
|
||||
|
||||
static void select_engine_init(void *vedata)
|
||||
{
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ?
|
||||
GPU_SHADER_CFG_CLIPPED :
|
||||
GPU_SHADER_CFG_DEFAULT;
|
||||
|
||||
SELECTID_Data *ved = reinterpret_cast<SELECTID_Data *>(vedata);
|
||||
SELECTID_Shaders *sh_data = &e_data.sh_data[sh_cfg];
|
||||
|
||||
if (ved->instance == nullptr) {
|
||||
ved->instance = new SELECTID_Instance();
|
||||
}
|
||||
|
||||
/* Prepass */
|
||||
if (!sh_data->select_id_flat) {
|
||||
sh_data->select_id_flat = GPU_shader_create_from_info_name(
|
||||
sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_flat_clipped" : "select_id_flat");
|
||||
}
|
||||
if (!sh_data->select_id_uniform) {
|
||||
sh_data->select_id_uniform = GPU_shader_create_from_info_name(
|
||||
sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_uniform_clipped" : "select_id_uniform");
|
||||
}
|
||||
}
|
||||
|
||||
static short select_id_get_object_select_mode(Scene *scene, Object *ob)
|
||||
{
|
||||
short r_select_mode = 0;
|
||||
if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
|
||||
/* In order to sample flat colors for vertex weights / texture-paint / vertex-paint
|
||||
* we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up
|
||||
* a shgroup with select_id_flat.
|
||||
* Note this is not working correctly for vertex-paint (yet), but has been discussed
|
||||
* in #66645 and there is a solution by @mano-wii in P1032.
|
||||
* So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */
|
||||
Mesh *me_orig = static_cast<Mesh *>(DEG_get_original_object(ob)->data);
|
||||
if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) {
|
||||
r_select_mode = SCE_SELECT_VERTEX;
|
||||
}
|
||||
else {
|
||||
r_select_mode = SCE_SELECT_FACE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
r_select_mode = scene->toolsettings->selectmode;
|
||||
}
|
||||
|
||||
return r_select_mode;
|
||||
}
|
||||
|
||||
static void select_cache_init(void *vedata)
|
||||
{
|
||||
SELECTID_Instance &inst = *reinterpret_cast<SELECTID_Data *>(vedata)->instance;
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ?
|
||||
GPU_SHADER_CFG_CLIPPED :
|
||||
GPU_SHADER_CFG_DEFAULT;
|
||||
|
||||
SELECTID_Shaders *sh = &e_data.sh_data[sh_cfg];
|
||||
|
||||
if (e_data.context.select_mode == -1) {
|
||||
e_data.context.select_mode = select_id_get_object_select_mode(draw_ctx->scene,
|
||||
draw_ctx->obact);
|
||||
BLI_assert(e_data.context.select_mode != 0);
|
||||
}
|
||||
|
||||
DRWState state = DRW_STATE_DEFAULT;
|
||||
if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) {
|
||||
state |= DRW_STATE_CLIP_PLANES;
|
||||
}
|
||||
|
||||
bool retopology_occlusion = RETOPOLOGY_ENABLED(draw_ctx->v3d) && !XRAY_ENABLED(draw_ctx->v3d);
|
||||
float retopology_offset = RETOPOLOGY_OFFSET(draw_ctx->v3d);
|
||||
|
||||
/* Note there might be less than 6 planes, but we always compute the 6 of them for simplicity. */
|
||||
int clipping_plane_count = RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d) ? 6 : 0;
|
||||
|
||||
{
|
||||
inst.depth_only_ps.init();
|
||||
inst.depth_only_ps.state_set(state, clipping_plane_count);
|
||||
inst.depth_only = nullptr;
|
||||
inst.depth_occlude = nullptr;
|
||||
static StaticData &get()
|
||||
{
|
||||
auto &sub = inst.depth_only_ps.sub("DepthOnly");
|
||||
sub.shader_set(sh->select_id_uniform);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
sub.push_constant("select_id", 0);
|
||||
inst.depth_only = ⊂
|
||||
static StaticData data = {};
|
||||
return data;
|
||||
}
|
||||
if (retopology_occlusion) {
|
||||
auto &sub = inst.depth_only_ps.sub("Occlusion");
|
||||
sub.shader_set(sh->select_id_uniform);
|
||||
sub.push_constant("retopologyOffset", 0.0f);
|
||||
sub.push_constant("select_id", 0);
|
||||
inst.depth_occlude = ⊂
|
||||
};
|
||||
|
||||
blender::StringRefNull name_get() final
|
||||
{
|
||||
return "SelectID";
|
||||
}
|
||||
|
||||
void init() final
|
||||
{
|
||||
StaticData &e_data = StaticData::get();
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ?
|
||||
GPU_SHADER_CFG_CLIPPED :
|
||||
GPU_SHADER_CFG_DEFAULT;
|
||||
|
||||
StaticData::Shaders *sh_data = &e_data.sh_data[sh_cfg];
|
||||
|
||||
/* Prepass */
|
||||
if (!sh_data->select_id_flat) {
|
||||
sh_data->select_id_flat = GPU_shader_create_from_info_name(
|
||||
sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_flat_clipped" : "select_id_flat");
|
||||
}
|
||||
if (!sh_data->select_id_uniform) {
|
||||
sh_data->select_id_uniform = GPU_shader_create_from_info_name(
|
||||
sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_uniform_clipped" : "select_id_uniform");
|
||||
}
|
||||
}
|
||||
|
||||
void begin_sync() final
|
||||
{
|
||||
StaticData &e_data = StaticData::get();
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ?
|
||||
GPU_SHADER_CFG_CLIPPED :
|
||||
GPU_SHADER_CFG_DEFAULT;
|
||||
|
||||
StaticData::Shaders *sh = &e_data.sh_data[sh_cfg];
|
||||
|
||||
if (e_data.context.select_mode == -1) {
|
||||
e_data.context.select_mode = get_object_select_mode(draw_ctx->scene, draw_ctx->obact);
|
||||
BLI_assert(e_data.context.select_mode != 0);
|
||||
}
|
||||
|
||||
inst.select_face_ps.init();
|
||||
inst.select_face_ps.state_set(state, clipping_plane_count);
|
||||
inst.select_face_uniform = nullptr;
|
||||
inst.select_face_flat = nullptr;
|
||||
if (e_data.context.select_mode & SCE_SELECT_FACE) {
|
||||
auto &sub = inst.select_face_ps.sub("Face");
|
||||
sub.shader_set(sh->select_id_flat);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
inst.select_face_flat = ⊂
|
||||
DRWState state = DRW_STATE_DEFAULT;
|
||||
if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) {
|
||||
state |= DRW_STATE_CLIP_PLANES;
|
||||
}
|
||||
|
||||
bool retopology_occlusion = RETOPOLOGY_ENABLED(draw_ctx->v3d) && !XRAY_ENABLED(draw_ctx->v3d);
|
||||
float retopology_offset = RETOPOLOGY_OFFSET(draw_ctx->v3d);
|
||||
|
||||
/* Note there might be less than 6 planes, but we always compute the 6 of them for simplicity.
|
||||
*/
|
||||
int clipping_plane_count = RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d) ? 6 : 0;
|
||||
|
||||
{
|
||||
depth_only_ps.init();
|
||||
depth_only_ps.state_set(state, clipping_plane_count);
|
||||
depth_only = nullptr;
|
||||
depth_occlude = nullptr;
|
||||
{
|
||||
auto &sub = depth_only_ps.sub("DepthOnly");
|
||||
sub.shader_set(sh->select_id_uniform);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
sub.push_constant("select_id", 0);
|
||||
depth_only = ⊂
|
||||
}
|
||||
if (retopology_occlusion) {
|
||||
auto &sub = depth_only_ps.sub("Occlusion");
|
||||
sub.shader_set(sh->select_id_uniform);
|
||||
sub.push_constant("retopologyOffset", 0.0f);
|
||||
sub.push_constant("select_id", 0);
|
||||
depth_occlude = ⊂
|
||||
}
|
||||
|
||||
select_face_ps.init();
|
||||
select_face_ps.state_set(state, clipping_plane_count);
|
||||
select_face_uniform = nullptr;
|
||||
select_face_flat = nullptr;
|
||||
if (e_data.context.select_mode & SCE_SELECT_FACE) {
|
||||
auto &sub = select_face_ps.sub("Face");
|
||||
sub.shader_set(sh->select_id_flat);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
select_face_flat = ⊂
|
||||
}
|
||||
else {
|
||||
auto &sub = select_face_ps.sub("FaceNoSelect");
|
||||
sub.shader_set(sh->select_id_uniform);
|
||||
sub.push_constant("select_id", 0);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
select_face_uniform = ⊂
|
||||
}
|
||||
|
||||
select_edge_ps.init();
|
||||
select_edge = nullptr;
|
||||
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
|
||||
auto &sub = select_edge_ps.sub("Sub");
|
||||
sub.state_set(state | DRW_STATE_FIRST_VERTEX_CONVENTION, clipping_plane_count);
|
||||
sub.shader_set(sh->select_id_flat);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
select_edge = ⊂
|
||||
}
|
||||
|
||||
select_id_vert_ps.init();
|
||||
select_vert = nullptr;
|
||||
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
|
||||
const float vertex_size = blender::draw::overlay::Resources::vertex_size_get();
|
||||
auto &sub = select_id_vert_ps.sub("Sub");
|
||||
sub.state_set(state, clipping_plane_count);
|
||||
sub.shader_set(sh->select_id_flat);
|
||||
sub.push_constant("vertex_size", float(2 * vertex_size));
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
select_vert = ⊂
|
||||
}
|
||||
}
|
||||
|
||||
e_data.context.elem_ranges.clear();
|
||||
|
||||
e_data.context.persmat = float4x4(draw_ctx->rv3d->persmat);
|
||||
e_data.context.max_index_drawn_len = 1;
|
||||
framebuffer_setup();
|
||||
GPU_framebuffer_bind(e_data.framebuffer_select_id);
|
||||
GPU_framebuffer_clear_color_depth(e_data.framebuffer_select_id, blender::float4{0.0f}, 1.0f);
|
||||
}
|
||||
|
||||
ElemIndexRanges edit_mesh_sync(Object *ob,
|
||||
ResourceHandle res_handle,
|
||||
short select_mode,
|
||||
bool draw_facedot,
|
||||
const uint initial_index)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
using namespace blender;
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob->data);
|
||||
BMEditMesh *em = mesh.runtime->edit_mesh.get();
|
||||
|
||||
ElemIndexRanges ranges{};
|
||||
ranges.total = IndexRange::from_begin_size(initial_index, 0);
|
||||
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
|
||||
|
||||
if (select_mode & SCE_SELECT_FACE) {
|
||||
ranges.face = alloc_range(ranges.total, em->bm->totface);
|
||||
|
||||
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
|
||||
PassSimple::Sub *face_sub = select_face_flat;
|
||||
face_sub->push_constant("offset", int(ranges.face.start()));
|
||||
face_sub->draw(geom_faces, res_handle);
|
||||
|
||||
if (draw_facedot) {
|
||||
gpu::Batch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(mesh);
|
||||
face_sub->draw(geom_facedots, res_handle);
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto &sub = inst.select_face_ps.sub("FaceNoSelect");
|
||||
sub.shader_set(sh->select_id_uniform);
|
||||
sub.push_constant("select_id", 0);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
inst.select_face_uniform = ⊂
|
||||
if (ob->dt >= OB_SOLID) {
|
||||
#ifdef USE_CAGE_OCCLUSION
|
||||
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
|
||||
#else
|
||||
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(mesh);
|
||||
#endif
|
||||
select_face_uniform->draw(geom_faces, res_handle);
|
||||
}
|
||||
}
|
||||
|
||||
inst.select_edge_ps.init();
|
||||
inst.select_edge = nullptr;
|
||||
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
|
||||
auto &sub = inst.select_edge_ps.sub("Sub");
|
||||
sub.state_set(state | DRW_STATE_FIRST_VERTEX_CONVENTION, clipping_plane_count);
|
||||
sub.shader_set(sh->select_id_flat);
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
inst.select_edge = ⊂
|
||||
/* Unlike faces, only draw edges if edge select mode. */
|
||||
if (select_mode & SCE_SELECT_EDGE) {
|
||||
ranges.edge = alloc_range(ranges.total, em->bm->totedge);
|
||||
|
||||
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
|
||||
select_edge->push_constant("offset", int(ranges.edge.start()));
|
||||
select_edge->draw(geom_edges, res_handle);
|
||||
}
|
||||
|
||||
inst.select_id_vert_ps.init();
|
||||
inst.select_vert = nullptr;
|
||||
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
|
||||
const float vertex_size = blender::draw::overlay::Resources::vertex_size_get();
|
||||
auto &sub = inst.select_id_vert_ps.sub("Sub");
|
||||
sub.state_set(state, clipping_plane_count);
|
||||
sub.shader_set(sh->select_id_flat);
|
||||
sub.push_constant("vertex_size", float(2 * vertex_size));
|
||||
sub.push_constant("retopologyOffset", retopology_offset);
|
||||
inst.select_vert = ⊂
|
||||
/* Unlike faces, only verts if vert select mode. */
|
||||
if (select_mode & SCE_SELECT_VERTEX) {
|
||||
ranges.vert = alloc_range(ranges.total, em->bm->totvert);
|
||||
|
||||
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
|
||||
select_vert->push_constant("offset", int(ranges.vert.start()));
|
||||
select_vert->draw(geom_verts, res_handle);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
e_data.context.elem_ranges.clear();
|
||||
ElemIndexRanges mesh_sync(Object *ob,
|
||||
ResourceHandle res_handle,
|
||||
short select_mode,
|
||||
const uint initial_index)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
using namespace blender;
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob->data);
|
||||
|
||||
e_data.context.persmat = float4x4(draw_ctx->rv3d->persmat);
|
||||
e_data.context.max_index_drawn_len = 1;
|
||||
select_engine_framebuffer_setup();
|
||||
GPU_framebuffer_bind(e_data.framebuffer_select_id);
|
||||
GPU_framebuffer_clear_color_depth(e_data.framebuffer_select_id, blender::float4{0.0f}, 1.0f);
|
||||
}
|
||||
|
||||
static bool check_ob_drawface_dot(short select_mode, const View3D *v3d, eDrawType dt)
|
||||
{
|
||||
if (select_mode & SCE_SELECT_FACE) {
|
||||
if ((dt < OB_SOLID) || XRAY_FLAG_ENABLED(v3d)) {
|
||||
return true;
|
||||
}
|
||||
if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace blender {
|
||||
|
||||
/* Return a new range if size `n` after `total_range` and grow `total_range` by the same amount. */
|
||||
static IndexRange alloc_range(IndexRange &total_range, uint size)
|
||||
{
|
||||
const IndexRange indices = total_range.after(size);
|
||||
total_range = IndexRange::from_begin_size(total_range.start(), total_range.size() + size);
|
||||
return indices;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
static ElemIndexRanges select_id_edit_mesh_sync(SELECTID_Instance &inst,
|
||||
Object *ob,
|
||||
ResourceHandle res_handle,
|
||||
short select_mode,
|
||||
bool draw_facedot,
|
||||
const uint initial_index)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
using namespace blender;
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob->data);
|
||||
BMEditMesh *em = mesh.runtime->edit_mesh.get();
|
||||
|
||||
ElemIndexRanges ranges{};
|
||||
ranges.total = IndexRange::from_begin_size(initial_index, 0);
|
||||
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
|
||||
|
||||
if (select_mode & SCE_SELECT_FACE) {
|
||||
ranges.face = alloc_range(ranges.total, em->bm->totface);
|
||||
ElemIndexRanges ranges{};
|
||||
ranges.total = IndexRange::from_begin_size(initial_index, 0);
|
||||
|
||||
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
|
||||
PassSimple::Sub *face_sub = inst.select_face_flat;
|
||||
face_sub->push_constant("offset", int(ranges.face.start()));
|
||||
face_sub->draw(geom_faces, res_handle);
|
||||
if (select_mode & SCE_SELECT_FACE) {
|
||||
ranges.face = alloc_range(ranges.total, mesh.faces_num);
|
||||
|
||||
if (draw_facedot) {
|
||||
gpu::Batch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(mesh);
|
||||
face_sub->draw(geom_facedots, res_handle);
|
||||
select_face_flat->push_constant("offset", int(ranges.face.start()));
|
||||
select_face_flat->draw(geom_faces, res_handle);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ob->dt >= OB_SOLID) {
|
||||
#ifdef USE_CAGE_OCCLUSION
|
||||
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
|
||||
#else
|
||||
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(mesh);
|
||||
#endif
|
||||
inst.select_face_uniform->draw(geom_faces, res_handle);
|
||||
else {
|
||||
/* Only draw faces to mask out verts, we don't want their selection ID's. */
|
||||
select_face_uniform->draw(geom_faces, res_handle);
|
||||
}
|
||||
|
||||
if (select_mode & SCE_SELECT_EDGE) {
|
||||
ranges.edge = alloc_range(ranges.total, mesh.edges_num);
|
||||
|
||||
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
|
||||
select_edge->push_constant("offset", int(ranges.edge.start()));
|
||||
select_edge->draw(geom_edges, res_handle);
|
||||
}
|
||||
|
||||
if (select_mode & SCE_SELECT_VERTEX) {
|
||||
ranges.vert = alloc_range(ranges.total, mesh.verts_num);
|
||||
|
||||
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
|
||||
select_vert->push_constant("offset", int(ranges.vert.start()));
|
||||
select_vert->draw(geom_verts, res_handle);
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
/* Unlike faces, only draw edges if edge select mode. */
|
||||
if (select_mode & SCE_SELECT_EDGE) {
|
||||
ranges.edge = alloc_range(ranges.total, em->bm->totedge);
|
||||
ElemIndexRanges object_sync(
|
||||
View3D *v3d, Object *ob, ResourceHandle res_handle, short select_mode, uint index_start)
|
||||
{
|
||||
BLI_assert_msg(index_start > 0, "Index 0 is reserved for no selection");
|
||||
|
||||
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
|
||||
inst.select_edge->push_constant("offset", int(ranges.edge.start()));
|
||||
inst.select_edge->draw(geom_edges, res_handle);
|
||||
}
|
||||
|
||||
/* Unlike faces, only verts if vert select mode. */
|
||||
if (select_mode & SCE_SELECT_VERTEX) {
|
||||
ranges.vert = alloc_range(ranges.total, em->bm->totvert);
|
||||
|
||||
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
|
||||
inst.select_vert->push_constant("offset", int(ranges.vert.start()));
|
||||
inst.select_vert->draw(geom_verts, res_handle);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
static ElemIndexRanges select_id_mesh_sync(SELECTID_Instance &inst,
|
||||
Object *ob,
|
||||
ResourceHandle res_handle,
|
||||
short select_mode,
|
||||
const uint initial_index)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
using namespace blender;
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob->data);
|
||||
|
||||
ElemIndexRanges ranges{};
|
||||
ranges.total = IndexRange::from_begin_size(initial_index, 0);
|
||||
|
||||
gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh);
|
||||
if (select_mode & SCE_SELECT_FACE) {
|
||||
ranges.face = alloc_range(ranges.total, mesh.faces_num);
|
||||
|
||||
inst.select_face_flat->push_constant("offset", int(ranges.face.start()));
|
||||
inst.select_face_flat->draw(geom_faces, res_handle);
|
||||
}
|
||||
else {
|
||||
/* Only draw faces to mask out verts, we don't want their selection ID's. */
|
||||
inst.select_face_uniform->draw(geom_faces, res_handle);
|
||||
}
|
||||
|
||||
if (select_mode & SCE_SELECT_EDGE) {
|
||||
ranges.edge = alloc_range(ranges.total, mesh.edges_num);
|
||||
|
||||
gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh);
|
||||
inst.select_edge->push_constant("offset", int(ranges.edge.start()));
|
||||
inst.select_edge->draw(geom_edges, res_handle);
|
||||
}
|
||||
|
||||
if (select_mode & SCE_SELECT_VERTEX) {
|
||||
ranges.vert = alloc_range(ranges.total, mesh.verts_num);
|
||||
|
||||
gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh);
|
||||
inst.select_vert->push_constant("offset", int(ranges.vert.start()));
|
||||
inst.select_vert->draw(geom_verts, res_handle);
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
static ElemIndexRanges select_id_object_sync(SELECTID_Instance &inst,
|
||||
View3D *v3d,
|
||||
Object *ob,
|
||||
ResourceHandle res_handle,
|
||||
short select_mode,
|
||||
uint index_start)
|
||||
{
|
||||
BLI_assert_msg(index_start > 0, "Index 0 is reserved for no selection");
|
||||
|
||||
switch (ob->type) {
|
||||
case OB_MESH: {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
|
||||
if (mesh.runtime->edit_mesh) {
|
||||
bool draw_facedot = check_ob_drawface_dot(select_mode, v3d, eDrawType(ob->dt));
|
||||
return select_id_edit_mesh_sync(
|
||||
inst, ob, res_handle, select_mode, draw_facedot, index_start);
|
||||
switch (ob->type) {
|
||||
case OB_MESH: {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
|
||||
if (mesh.runtime->edit_mesh) {
|
||||
bool draw_facedot = check_ob_drawface_dot(select_mode, v3d, eDrawType(ob->dt));
|
||||
return edit_mesh_sync(ob, res_handle, select_mode, draw_facedot, index_start);
|
||||
}
|
||||
return mesh_sync(ob, res_handle, select_mode, index_start);
|
||||
}
|
||||
return select_id_mesh_sync(inst, ob, res_handle, select_mode, index_start);
|
||||
case OB_CURVES_LEGACY:
|
||||
case OB_SURF:
|
||||
break;
|
||||
}
|
||||
case OB_CURVES_LEGACY:
|
||||
case OB_SURF:
|
||||
break;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return ElemIndexRanges{};
|
||||
}
|
||||
|
||||
static void select_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref)
|
||||
{
|
||||
Manager &manager = *DRW_manager_get();
|
||||
Object *ob = ob_ref.object;
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
SELECTID_Context &sel_ctx = e_data.context;
|
||||
SELECTID_Instance &inst = *reinterpret_cast<SELECTID_Data *>(vedata)->instance;
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
|
||||
if (!sel_ctx.objects.contains(ob) && ob->dt >= OB_SOLID) {
|
||||
/* This object is not selectable. It is here to participate in occlusion.
|
||||
* This is the case in retopology mode. */
|
||||
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(
|
||||
*static_cast<Mesh *>(ob->data));
|
||||
|
||||
inst.depth_occlude->draw(geom_faces, manager.resource_handle(ob_ref));
|
||||
return;
|
||||
BLI_assert_unreachable();
|
||||
return ElemIndexRanges{};
|
||||
}
|
||||
|
||||
/* Only sync selectable object once.
|
||||
* This can happen in retopology mode where there is two sync loop. */
|
||||
sel_ctx.elem_ranges.lookup_or_add_cb(ob, [&]() {
|
||||
ResourceHandle res_handle = manager.resource_handle(ob_ref);
|
||||
ElemIndexRanges elem_ranges = select_id_object_sync(
|
||||
inst, draw_ctx->v3d, ob, res_handle, sel_ctx.select_mode, sel_ctx.max_index_drawn_len);
|
||||
sel_ctx.max_index_drawn_len = elem_ranges.total.one_after_last();
|
||||
return elem_ranges;
|
||||
});
|
||||
}
|
||||
|
||||
static void select_draw_scene(void *vedata)
|
||||
{
|
||||
Manager &manager = *DRW_manager_get();
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
SELECTID_Instance &inst = *reinterpret_cast<SELECTID_Data *>(vedata)->instance;
|
||||
|
||||
DRW_submission_start();
|
||||
void object_sync(ObjectRef &ob_ref, Manager &manager) final
|
||||
{
|
||||
Object *ob = ob_ref.object;
|
||||
StaticData &e_data = StaticData::get();
|
||||
SELECTID_Context &sel_ctx = e_data.context;
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
View::OffsetData offset_data(*draw_ctx->rv3d);
|
||||
/* Create view with depth offset */
|
||||
const View &view = View::default_get();
|
||||
inst.view_faces.sync(view.viewmat(), view.winmat());
|
||||
inst.view_edges.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.0f));
|
||||
inst.view_verts.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.1f));
|
||||
|
||||
if (!sel_ctx.objects.contains(ob) && ob->dt >= OB_SOLID) {
|
||||
/* This object is not selectable. It is here to participate in occlusion.
|
||||
* This is the case in retopology mode. */
|
||||
blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(
|
||||
*static_cast<Mesh *>(ob->data));
|
||||
|
||||
depth_occlude->draw(geom_faces, manager.resource_handle(ob_ref));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only sync selectable object once.
|
||||
* This can happen in retopology mode where there is two sync loop. */
|
||||
sel_ctx.elem_ranges.lookup_or_add_cb(ob, [&]() {
|
||||
ResourceHandle res_handle = manager.resource_handle(ob_ref);
|
||||
ElemIndexRanges elem_ranges = object_sync(
|
||||
draw_ctx->v3d, ob, res_handle, sel_ctx.select_mode, sel_ctx.max_index_drawn_len);
|
||||
sel_ctx.max_index_drawn_len = elem_ranges.total.one_after_last();
|
||||
return elem_ranges;
|
||||
});
|
||||
}
|
||||
|
||||
void end_sync() final {}
|
||||
|
||||
void draw(Manager &manager) final
|
||||
{
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
GPU_framebuffer_bind(dfbl->depth_only_fb);
|
||||
GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0f);
|
||||
manager.submit(inst.depth_only_ps, inst.view_faces);
|
||||
StaticData &e_data = StaticData::get();
|
||||
|
||||
DRW_submission_start();
|
||||
{
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
View::OffsetData offset_data(*draw_ctx->rv3d);
|
||||
/* Create view with depth offset */
|
||||
const View &view = View::default_get();
|
||||
view_faces.sync(view.viewmat(), view.winmat());
|
||||
view_edges.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.0f));
|
||||
view_verts.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.1f));
|
||||
}
|
||||
|
||||
{
|
||||
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
|
||||
GPU_framebuffer_bind(dfbl->depth_only_fb);
|
||||
GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0f);
|
||||
manager.submit(depth_only_ps, view_faces);
|
||||
}
|
||||
|
||||
/* Setup framebuffer */
|
||||
GPU_framebuffer_bind(e_data.framebuffer_select_id);
|
||||
|
||||
manager.submit(select_face_ps, view_faces);
|
||||
|
||||
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
|
||||
manager.submit(select_edge_ps, view_edges);
|
||||
}
|
||||
|
||||
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
|
||||
manager.submit(select_id_vert_ps, view_verts);
|
||||
}
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
/* Setup framebuffer */
|
||||
GPU_framebuffer_bind(e_data.framebuffer_select_id);
|
||||
private:
|
||||
void framebuffer_setup()
|
||||
{
|
||||
StaticData &e_data = StaticData::get();
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
int size[2];
|
||||
size[0] = GPU_texture_width(dtxl->depth);
|
||||
size[1] = GPU_texture_height(dtxl->depth);
|
||||
|
||||
manager.submit(inst.select_face_ps, inst.view_faces);
|
||||
if (e_data.framebuffer_select_id == nullptr) {
|
||||
e_data.framebuffer_select_id = GPU_framebuffer_create("framebuffer_select_id");
|
||||
}
|
||||
|
||||
if (e_data.context.select_mode & SCE_SELECT_EDGE) {
|
||||
manager.submit(inst.select_edge_ps, inst.view_edges);
|
||||
if ((e_data.texture_u32 != nullptr) && ((GPU_texture_width(e_data.texture_u32) != size[0]) ||
|
||||
(GPU_texture_height(e_data.texture_u32) != size[1])))
|
||||
{
|
||||
GPU_texture_free(e_data.texture_u32);
|
||||
e_data.texture_u32 = nullptr;
|
||||
}
|
||||
|
||||
/* Make sure the depth texture is attached.
|
||||
* It may disappear when loading another Blender session. */
|
||||
GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, dtxl->depth, 0, 0);
|
||||
|
||||
if (e_data.texture_u32 == nullptr) {
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
e_data.texture_u32 = GPU_texture_create_2d(
|
||||
"select_buf_ids", size[0], size[1], 1, GPU_R32UI, usage, nullptr);
|
||||
GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, e_data.texture_u32, 0, 0);
|
||||
|
||||
GPU_framebuffer_check_valid(e_data.framebuffer_select_id, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (e_data.context.select_mode & SCE_SELECT_VERTEX) {
|
||||
manager.submit(inst.select_id_vert_ps, inst.view_verts);
|
||||
short get_object_select_mode(Scene *scene, Object *ob)
|
||||
{
|
||||
short r_select_mode = 0;
|
||||
if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) {
|
||||
/* In order to sample flat colors for vertex weights / texture-paint / vertex-paint
|
||||
* we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up
|
||||
* a shgroup with select_id_flat.
|
||||
* Note this is not working correctly for vertex-paint (yet), but has been discussed
|
||||
* in #66645 and there is a solution by @mano-wii in P1032.
|
||||
* So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */
|
||||
Mesh *me_orig = static_cast<Mesh *>(DEG_get_original_object(ob)->data);
|
||||
if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) {
|
||||
r_select_mode = SCE_SELECT_VERTEX;
|
||||
}
|
||||
else {
|
||||
r_select_mode = SCE_SELECT_FACE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
r_select_mode = scene->toolsettings->selectmode;
|
||||
}
|
||||
|
||||
return r_select_mode;
|
||||
}
|
||||
DRW_submission_end();
|
||||
|
||||
bool check_ob_drawface_dot(short select_mode, const View3D *v3d, eDrawType dt)
|
||||
{
|
||||
if (select_mode & SCE_SELECT_FACE) {
|
||||
if ((dt < OB_SOLID) || XRAY_FLAG_ENABLED(v3d)) {
|
||||
return true;
|
||||
}
|
||||
if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return a new range if size `n` after `total_range` and grow `total_range` by the same amount.
|
||||
*/
|
||||
IndexRange alloc_range(IndexRange &total_range, uint size)
|
||||
{
|
||||
const IndexRange indices = total_range.after(size);
|
||||
total_range = IndexRange::from_begin_size(total_range.start(), total_range.size() + size);
|
||||
return indices;
|
||||
}
|
||||
};
|
||||
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
static void select_engine_free()
|
||||
void Engine::free_static()
|
||||
{
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
Instance::StaticData &e_data = Instance::StaticData::get();
|
||||
for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) {
|
||||
SELECTID_Shaders *sh_data = &e_data.sh_data[sh_data_index];
|
||||
Instance::StaticData::Shaders *sh_data = &e_data.sh_data[sh_data_index];
|
||||
GPU_SHADER_FREE_SAFE(sh_data->select_id_flat);
|
||||
GPU_SHADER_FREE_SAFE(sh_data->select_id_uniform);
|
||||
}
|
||||
@@ -480,57 +492,7 @@ static void select_engine_free()
|
||||
GPU_FRAMEBUFFER_FREE_SAFE(e_data.framebuffer_select_id);
|
||||
}
|
||||
|
||||
static void select_instance_free(void *instance)
|
||||
{
|
||||
delete reinterpret_cast<SELECTID_Instance *>(instance);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Engine Type
|
||||
* \{ */
|
||||
|
||||
DrawEngineType draw_engine_select_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("Select ID"),
|
||||
/*engine_init*/ &select_engine_init,
|
||||
/*engine_free*/ &select_engine_free,
|
||||
/*instance_free*/ select_instance_free,
|
||||
/*cache_init*/ &select_cache_init,
|
||||
/*cache_populate*/ &select_cache_populate,
|
||||
/*cache_finish*/ nullptr,
|
||||
/*draw_scene*/ &select_draw_scene,
|
||||
/*render_to_image*/ nullptr,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
|
||||
/* NOTE: currently unused, we may want to register so we can see this when debugging the view. */
|
||||
|
||||
RenderEngineType DRW_engine_viewport_select_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ SELECT_ENGINE,
|
||||
/*name*/ N_("Select ID"),
|
||||
/*flag*/ RE_INTERNAL | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT,
|
||||
/*update*/ nullptr,
|
||||
/*render*/ nullptr,
|
||||
/*render_frame_finish*/ nullptr,
|
||||
/*draw*/ nullptr,
|
||||
/*bake*/ nullptr,
|
||||
/*view_update*/ nullptr,
|
||||
/*view_draw*/ nullptr,
|
||||
/*update_script_node*/ nullptr,
|
||||
/*update_render_passes*/ nullptr,
|
||||
/*draw_engine*/ &draw_engine_select_type,
|
||||
/*rna_ext*/
|
||||
{
|
||||
/*data*/ nullptr,
|
||||
/*srna*/ nullptr,
|
||||
/*call*/ nullptr,
|
||||
},
|
||||
};
|
||||
} // namespace blender::draw::edit_select
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -538,24 +500,24 @@ RenderEngineType DRW_engine_viewport_select_type = {
|
||||
/** \name Exposed `select_private.h` functions
|
||||
* \{ */
|
||||
|
||||
using namespace blender::draw::edit_select;
|
||||
|
||||
SELECTID_Context *DRW_select_engine_context_get()
|
||||
{
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
Instance::StaticData &e_data = Instance::StaticData::get();
|
||||
return &e_data.context;
|
||||
}
|
||||
|
||||
GPUFrameBuffer *DRW_engine_select_framebuffer_get()
|
||||
{
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
Instance::StaticData &e_data = Instance::StaticData::get();
|
||||
return e_data.framebuffer_select_id;
|
||||
}
|
||||
|
||||
GPUTexture *DRW_engine_select_texture_get()
|
||||
{
|
||||
SelectEngineData &e_data = get_engine_data();
|
||||
Instance::StaticData &e_data = Instance::StaticData::get();
|
||||
return e_data.texture_u32;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
#undef SELECT_ENGINE
|
||||
|
||||
@@ -8,15 +8,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/* `select_engine.cc` */
|
||||
#include "DRW_render.hh"
|
||||
|
||||
extern DrawEngineType draw_engine_select_type;
|
||||
extern RenderEngineType DRW_engine_viewport_select_type;
|
||||
/* `select_engine.cc` */
|
||||
|
||||
#ifdef WITH_DRAW_DEBUG
|
||||
/* `select_debug_engine.cc` */
|
||||
|
||||
extern DrawEngineType draw_engine_debug_select_type;
|
||||
namespace blender::draw::edit_select_debug {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
|
||||
static void free_static();
|
||||
};
|
||||
|
||||
} // namespace blender::draw::edit_select_debug
|
||||
|
||||
#endif
|
||||
|
||||
struct SELECTID_Context *DRW_select_engine_context_get();
|
||||
@@ -25,4 +33,20 @@ struct GPUTexture *DRW_engine_select_texture_get();
|
||||
|
||||
/* select_instance.cc */
|
||||
|
||||
extern DrawEngineType draw_engine_select_next_type;
|
||||
namespace blender::draw::select {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
};
|
||||
|
||||
} // namespace blender::draw::select
|
||||
|
||||
namespace blender::draw::edit_select {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
|
||||
static void free_static();
|
||||
};
|
||||
|
||||
} // namespace blender::draw::edit_select
|
||||
|
||||
@@ -8,79 +8,21 @@
|
||||
|
||||
#include "DRW_render.hh"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "select_engine.hh"
|
||||
|
||||
#include "../overlay/overlay_next_instance.hh"
|
||||
#include "select_instance.hh"
|
||||
|
||||
using namespace blender::draw;
|
||||
namespace blender::draw::select {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Select-Next Engine
|
||||
* \{ */
|
||||
|
||||
using Instance = overlay::Instance;
|
||||
|
||||
struct SELECT_NextData {
|
||||
void *engine_type;
|
||||
Instance *instance;
|
||||
class Instance : public overlay::Instance {
|
||||
public:
|
||||
Instance() : overlay::Instance(SelectionType::ENABLED){};
|
||||
};
|
||||
|
||||
static void SELECT_next_engine_init(void *vedata)
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
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();
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
static void SELECT_next_cache_init(void *vedata)
|
||||
{
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->begin_sync();
|
||||
}
|
||||
|
||||
static void SELECT_next_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref)
|
||||
{
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->object_sync(ob_ref, *DRW_manager_get());
|
||||
}
|
||||
|
||||
static void SELECT_next_cache_finish(void *vedata)
|
||||
{
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->end_sync();
|
||||
}
|
||||
|
||||
static void SELECT_next_draw_scene(void *vedata)
|
||||
{
|
||||
DRW_submission_start();
|
||||
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||
->draw(*DRW_manager_get());
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
static void SELECT_next_instance_free(void *instance_)
|
||||
{
|
||||
Instance *instance = (Instance *)instance_;
|
||||
delete instance;
|
||||
}
|
||||
|
||||
DrawEngineType draw_engine_select_next_type = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("Select-Next"),
|
||||
/*engine_init*/ &SELECT_next_engine_init,
|
||||
/*engine_free*/ nullptr,
|
||||
/*instance_free*/ &SELECT_next_instance_free,
|
||||
/*cache_init*/ &SELECT_next_cache_init,
|
||||
/*cache_populate*/ &SELECT_next_cache_populate,
|
||||
/*cache_finish*/ &SELECT_next_cache_finish,
|
||||
/*draw_scene*/ &SELECT_next_draw_scene,
|
||||
/*render_to_image*/ nullptr,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
} // namespace blender::draw::select
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2019 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup draw_engine
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define USE_CAGE_OCCLUSION
|
||||
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_pass.hh"
|
||||
#include "draw_view_data.hh"
|
||||
|
||||
#include "DRW_render.hh"
|
||||
#include "DRW_select_buffer.hh"
|
||||
|
||||
using namespace blender::draw;
|
||||
|
||||
/* GPUViewport.storage
|
||||
* Is freed every time the viewport engine changes. */
|
||||
struct SELECTID_StorageList {
|
||||
struct SELECTID_PrivateData *g_data;
|
||||
};
|
||||
|
||||
struct SELECTID_Instance {
|
||||
PassSimple depth_only_ps = {"depth_only_ps"};
|
||||
PassSimple::Sub *depth_only = nullptr;
|
||||
PassSimple::Sub *depth_occlude = nullptr;
|
||||
|
||||
PassSimple select_edge_ps = {"select_id_edge_ps"};
|
||||
PassSimple::Sub *select_edge = nullptr;
|
||||
|
||||
PassSimple select_id_vert_ps = {"select_id_vert_ps"};
|
||||
PassSimple::Sub *select_vert = nullptr;
|
||||
|
||||
PassSimple select_face_ps = {"select_id_face_ps"};
|
||||
PassSimple::Sub *select_face_uniform = nullptr;
|
||||
PassSimple::Sub *select_face_flat = nullptr;
|
||||
|
||||
View view_faces = {"view_faces"};
|
||||
View view_edges = {"view_edges"};
|
||||
View view_verts = {"view_verts"};
|
||||
};
|
||||
|
||||
struct SELECTID_Data {
|
||||
void *engine_type;
|
||||
SELECTID_Instance *instance;
|
||||
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
|
||||
struct SELECTID_Shaders {
|
||||
/* Depth Pre Pass */
|
||||
GPUShader *select_id_flat;
|
||||
GPUShader *select_id_uniform;
|
||||
};
|
||||
@@ -41,7 +41,7 @@ namespace blender::workbench {
|
||||
|
||||
using namespace draw;
|
||||
|
||||
class Instance {
|
||||
class Instance : public DrawEngine {
|
||||
private:
|
||||
View view_ = {"DefaultView"};
|
||||
|
||||
@@ -67,6 +67,11 @@ class Instance {
|
||||
uint64_t depsgraph_last_update_ = 0;
|
||||
|
||||
public:
|
||||
blender::StringRefNull name_get() final
|
||||
{
|
||||
return "Workbench";
|
||||
}
|
||||
|
||||
Span<const GPUMaterial *> get_dummy_gpu_materials(int material_count)
|
||||
{
|
||||
if (material_count > dummy_gpu_materials_.size()) {
|
||||
@@ -75,6 +80,11 @@ class Instance {
|
||||
return dummy_gpu_materials_.as_span().slice(IndexRange(material_count));
|
||||
};
|
||||
|
||||
void init() final
|
||||
{
|
||||
init(DRW_context_get()->depsgraph);
|
||||
}
|
||||
|
||||
void init(Depsgraph *depsgraph, Object *camera_ob = nullptr)
|
||||
{
|
||||
bool scene_updated = assign_if_different(depsgraph_last_update_,
|
||||
@@ -89,7 +99,7 @@ class Instance {
|
||||
anti_aliasing_ps_.init(scene_state_);
|
||||
}
|
||||
|
||||
void begin_sync()
|
||||
void begin_sync() final
|
||||
{
|
||||
resources_.material_buf.clear_and_trim();
|
||||
|
||||
@@ -104,7 +114,7 @@ class Instance {
|
||||
anti_aliasing_ps_.sync(scene_state_, resources_);
|
||||
}
|
||||
|
||||
void end_sync()
|
||||
void end_sync() final
|
||||
{
|
||||
resources_.material_buf.push_update();
|
||||
}
|
||||
@@ -132,7 +142,7 @@ class Instance {
|
||||
}
|
||||
}
|
||||
|
||||
void object_sync(Manager &manager, ObjectRef &ob_ref)
|
||||
void object_sync(ObjectRef &ob_ref, Manager &manager) final
|
||||
{
|
||||
if (scene_state_.render_finished) {
|
||||
return;
|
||||
@@ -494,6 +504,20 @@ class Instance {
|
||||
}
|
||||
}
|
||||
|
||||
void draw(Manager &manager) final
|
||||
{
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
|
||||
DRW_submission_start();
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
draw_image_render(manager, dtxl->depth, dtxl->depth_in_front, dtxl->color);
|
||||
}
|
||||
else {
|
||||
draw_viewport(manager, dtxl->depth, dtxl->depth_in_front, dtxl->color);
|
||||
}
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
void draw_image_render(Manager &manager,
|
||||
GPUTexture *depth_tx,
|
||||
GPUTexture *depth_in_front_tx,
|
||||
@@ -523,6 +547,16 @@ class Instance {
|
||||
}
|
||||
};
|
||||
|
||||
DrawEngine *Engine::create_instance()
|
||||
{
|
||||
return new Instance();
|
||||
}
|
||||
|
||||
void Engine::free_static()
|
||||
{
|
||||
ShaderCache::release();
|
||||
}
|
||||
|
||||
} // namespace blender::workbench
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -531,66 +565,6 @@ class Instance {
|
||||
|
||||
using namespace blender;
|
||||
|
||||
struct WORKBENCH_Data {
|
||||
DrawEngineType *engine_type;
|
||||
workbench::Instance *instance;
|
||||
|
||||
char info[GPU_INFO_SIZE];
|
||||
};
|
||||
|
||||
static void workbench_engine_init(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *ved = reinterpret_cast<WORKBENCH_Data *>(vedata);
|
||||
if (ved->instance == nullptr) {
|
||||
ved->instance = new workbench::Instance();
|
||||
}
|
||||
|
||||
ved->instance->init(DRW_context_get()->depsgraph);
|
||||
}
|
||||
|
||||
static void workbench_cache_init(void *vedata)
|
||||
{
|
||||
reinterpret_cast<WORKBENCH_Data *>(vedata)->instance->begin_sync();
|
||||
}
|
||||
|
||||
static void workbench_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref)
|
||||
{
|
||||
draw::Manager *manager = DRW_manager_get();
|
||||
|
||||
reinterpret_cast<WORKBENCH_Data *>(vedata)->instance->object_sync(*manager, ob_ref);
|
||||
}
|
||||
|
||||
static void workbench_cache_finish(void *vedata)
|
||||
{
|
||||
reinterpret_cast<WORKBENCH_Data *>(vedata)->instance->end_sync();
|
||||
}
|
||||
|
||||
static void workbench_draw_scene(void *vedata)
|
||||
{
|
||||
WORKBENCH_Data *ved = reinterpret_cast<WORKBENCH_Data *>(vedata);
|
||||
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
|
||||
draw::Manager *manager = DRW_manager_get();
|
||||
|
||||
DRW_submission_start();
|
||||
if (DRW_state_is_viewport_image_render()) {
|
||||
ved->instance->draw_image_render(*manager, dtxl->depth, dtxl->depth_in_front, dtxl->color);
|
||||
}
|
||||
else {
|
||||
ved->instance->draw_viewport(*manager, dtxl->depth, dtxl->depth_in_front, dtxl->color);
|
||||
}
|
||||
DRW_submission_end();
|
||||
}
|
||||
|
||||
static void workbench_instance_free(void *instance)
|
||||
{
|
||||
delete reinterpret_cast<workbench::Instance *>(instance);
|
||||
}
|
||||
|
||||
static void workbench_engine_free()
|
||||
{
|
||||
workbench::ShaderCache::release();
|
||||
}
|
||||
|
||||
/* RENDER */
|
||||
|
||||
static bool workbench_render_framebuffers_init()
|
||||
@@ -704,10 +678,7 @@ static void write_render_z_output(RenderLayer *layer,
|
||||
}
|
||||
}
|
||||
|
||||
static void workbench_render_to_image(void *vedata,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *layer,
|
||||
const rcti *rect)
|
||||
static void workbench_render_to_image(RenderEngine *engine, RenderLayer *layer, const rcti rect)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
if (!workbench_render_framebuffers_init()) {
|
||||
@@ -720,10 +691,7 @@ static void workbench_render_to_image(void *vedata,
|
||||
const DRWContext *draw_ctx = DRW_context_get();
|
||||
Depsgraph *depsgraph = draw_ctx->depsgraph;
|
||||
|
||||
WORKBENCH_Data *ved = reinterpret_cast<WORKBENCH_Data *>(vedata);
|
||||
if (ved->instance == nullptr) {
|
||||
ved->instance = new workbench::Instance();
|
||||
}
|
||||
workbench::Instance instance;
|
||||
|
||||
/* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */
|
||||
Object *camera_ob = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
|
||||
@@ -739,34 +707,33 @@ static void workbench_render_to_image(void *vedata,
|
||||
DRW_cache_restart();
|
||||
blender::draw::View::default_set(float4x4(viewmat), float4x4(winmat));
|
||||
|
||||
ved->instance->init(depsgraph, camera_ob);
|
||||
instance.init(depsgraph, camera_ob);
|
||||
|
||||
draw::Manager &manager = *DRW_manager_get();
|
||||
manager.begin_sync();
|
||||
|
||||
workbench_cache_init(vedata);
|
||||
auto workbench_render_cache = [](void *vedata,
|
||||
blender::draw::ObjectRef &ob_ref,
|
||||
RenderEngine * /*engine*/,
|
||||
Depsgraph * /*depsgraph*/) {
|
||||
workbench_cache_populate(vedata, ob_ref);
|
||||
};
|
||||
DRW_render_object_iter(vedata, engine, depsgraph, workbench_render_cache);
|
||||
workbench_cache_finish(vedata);
|
||||
instance.begin_sync();
|
||||
DRW_render_object_iter(
|
||||
engine,
|
||||
depsgraph,
|
||||
[&](blender::draw::ObjectRef &ob_ref, RenderEngine * /*engine*/, Depsgraph * /*depsgraph*/) {
|
||||
instance.object_sync(ob_ref, manager);
|
||||
});
|
||||
instance.end_sync();
|
||||
|
||||
manager.end_sync();
|
||||
|
||||
DRW_submission_start();
|
||||
|
||||
DefaultTextureList &dtxl = *DRW_viewport_texture_list_get();
|
||||
ved->instance->draw_image_render(manager, dtxl.depth, dtxl.depth_in_front, dtxl.color, engine);
|
||||
instance.draw_image_render(manager, dtxl.depth, dtxl.depth_in_front, dtxl.color, engine);
|
||||
|
||||
DRW_submission_end();
|
||||
|
||||
/* Write image */
|
||||
const char *viewname = RE_GetActiveRenderView(engine->re);
|
||||
write_render_color_output(layer, viewname, dfbl->default_fb, rect);
|
||||
write_render_z_output(layer, viewname, dfbl->default_fb, rect, winmat);
|
||||
write_render_color_output(layer, viewname, dfbl->default_fb, &rect);
|
||||
write_render_z_output(layer, viewname, dfbl->default_fb, &rect, winmat);
|
||||
}
|
||||
|
||||
static void workbench_render_update_passes(RenderEngine *engine,
|
||||
@@ -781,20 +748,10 @@ static void workbench_render_update_passes(RenderEngine *engine,
|
||||
}
|
||||
}
|
||||
|
||||
DrawEngineType draw_engine_workbench = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*idname*/ N_("Workbench"),
|
||||
/*engine_init*/ &workbench_engine_init,
|
||||
/*engine_free*/ &workbench_engine_free,
|
||||
/*instance_free*/ &workbench_instance_free,
|
||||
/*cache_init*/ &workbench_cache_init,
|
||||
/*cache_populate*/ &workbench_cache_populate,
|
||||
/*cache_finish*/ &workbench_cache_finish,
|
||||
/*draw_scene*/ &workbench_draw_scene,
|
||||
/*render_to_image*/ &workbench_render_to_image,
|
||||
/*store_metadata*/ nullptr,
|
||||
};
|
||||
void workbench_render(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
{
|
||||
DRW_render_to_image(engine, depsgraph, workbench_render_to_image, [](RenderResult *) {});
|
||||
}
|
||||
|
||||
RenderEngineType DRW_engine_viewport_workbench_type = {
|
||||
/*next*/ nullptr,
|
||||
@@ -803,7 +760,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = {
|
||||
/*name*/ N_("Workbench"),
|
||||
/*flag*/ RE_INTERNAL | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT,
|
||||
/*update*/ nullptr,
|
||||
/*render*/ &DRW_render_to_image,
|
||||
/*render*/ &workbench_render,
|
||||
/*render_frame_finish*/ nullptr,
|
||||
/*draw*/ nullptr,
|
||||
/*bake*/ nullptr,
|
||||
@@ -811,7 +768,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = {
|
||||
/*view_draw*/ nullptr,
|
||||
/*update_script_node*/ nullptr,
|
||||
/*update_render_passes*/ &workbench_render_update_passes,
|
||||
/*draw_engine*/ &draw_engine_workbench,
|
||||
/*draw_engine*/ nullptr,
|
||||
/*rna_ext*/
|
||||
{
|
||||
/*data*/ nullptr,
|
||||
|
||||
@@ -8,6 +8,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DRW_render.hh"
|
||||
|
||||
struct RenderEngineType;
|
||||
|
||||
extern RenderEngineType DRW_engine_viewport_workbench_type;
|
||||
|
||||
namespace blender::workbench {
|
||||
|
||||
struct Engine : public DrawEngine::Pointer {
|
||||
DrawEngine *create_instance() final;
|
||||
|
||||
static void free_static();
|
||||
};
|
||||
|
||||
} // namespace blender::workbench
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include "GPU_capabilities.hh"
|
||||
|
||||
extern "C" DrawEngineType draw_engine_workbench;
|
||||
|
||||
namespace blender::workbench {
|
||||
|
||||
using namespace draw;
|
||||
|
||||
@@ -54,6 +54,7 @@ struct GPUViewport;
|
||||
namespace blender::draw {
|
||||
class TextureFromPool;
|
||||
struct ObjectRef;
|
||||
class Manager;
|
||||
} // namespace blender::draw
|
||||
|
||||
typedef struct DRWPass DRWPass;
|
||||
@@ -65,27 +66,63 @@ struct BoundSphere {
|
||||
float center[3], radius;
|
||||
};
|
||||
|
||||
struct DrawEngineType {
|
||||
DrawEngineType *next, *prev;
|
||||
struct DrawEngine {
|
||||
static constexpr int GPU_INFO_SIZE = 512; /* IMA_MAX_RENDER_TEXT_SIZE */
|
||||
|
||||
char idname[32];
|
||||
char info[GPU_INFO_SIZE] = {'\0'};
|
||||
DRWTextStore *text_draw_cache = nullptr;
|
||||
|
||||
void (*engine_init)(void *vedata);
|
||||
void (*engine_free)();
|
||||
bool used = false;
|
||||
|
||||
void (*instance_free)(void *instance_data);
|
||||
virtual ~DrawEngine() = default;
|
||||
|
||||
void (*cache_init)(void *vedata);
|
||||
void (*cache_populate)(void *vedata, blender::draw::ObjectRef &ob_ref);
|
||||
void (*cache_finish)(void *vedata);
|
||||
virtual blender::StringRefNull name_get() = 0;
|
||||
|
||||
void (*draw_scene)(void *vedata);
|
||||
/* Functions called for viewport. */
|
||||
|
||||
void (*render_to_image)(void *vedata,
|
||||
RenderEngine *engine,
|
||||
RenderLayer *layer,
|
||||
const rcti *rect);
|
||||
void (*store_metadata)(void *vedata, RenderResult *render_result);
|
||||
/* Init engine. Run first and for every redraw. */
|
||||
virtual void init() = 0;
|
||||
/* Scene synchronization. Command buffers building. */
|
||||
virtual void begin_sync() = 0;
|
||||
virtual void object_sync(blender::draw::ObjectRef &ob_ref, blender::draw::Manager &manager) = 0;
|
||||
virtual void end_sync() = 0;
|
||||
/* Command Submission. */
|
||||
virtual void draw(blender::draw::Manager &manager) = 0;
|
||||
|
||||
/* Called when closing blender.
|
||||
* Cleanup all lazily initialized static members that have GPU resources.
|
||||
* Implemented on a case by case basis and called directly. */
|
||||
// static void exit(){};
|
||||
|
||||
struct Pointer {
|
||||
DrawEngine *instance = nullptr;
|
||||
|
||||
~Pointer()
|
||||
{
|
||||
free_instance();
|
||||
}
|
||||
|
||||
void free_instance()
|
||||
{
|
||||
delete instance;
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
void set_used(bool used)
|
||||
{
|
||||
if (used) {
|
||||
if (instance == nullptr) {
|
||||
instance = create_instance();
|
||||
}
|
||||
instance->used = true;
|
||||
}
|
||||
else if (instance) {
|
||||
instance->used = false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual DrawEngine *create_instance() = 0;
|
||||
};
|
||||
};
|
||||
|
||||
/* Shaders */
|
||||
@@ -120,19 +157,24 @@ blender::float2 DRW_viewport_size_get();
|
||||
DefaultFramebufferList *DRW_viewport_framebuffer_list_get();
|
||||
DefaultTextureList *DRW_viewport_texture_list_get();
|
||||
|
||||
/* See DRW_viewport_pass_texture_get. */
|
||||
/* Returns a TextureFromPool stored in the given view data for the pass identified by the given
|
||||
* pass name. Engines should call this function for each of the passes needed by the viewport
|
||||
* compositor in every redraw, then it should allocate the texture and write the pass data to it.
|
||||
* The texture should cover the entire viewport. */
|
||||
blender::draw::TextureFromPool &DRW_viewport_pass_texture_get(const char *pass_name);
|
||||
|
||||
void DRW_viewport_request_redraw();
|
||||
|
||||
void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph);
|
||||
void DRW_render_object_iter(void *vedata,
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph,
|
||||
void (*callback)(void *vedata,
|
||||
blender::draw::ObjectRef &ob_ref,
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph));
|
||||
void DRW_render_to_image(
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph,
|
||||
std::function<void(RenderEngine *, RenderLayer *, const rcti)> render_view_cb,
|
||||
std::function<void(RenderResult *)> store_metadata_cb);
|
||||
|
||||
void DRW_render_object_iter(
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph,
|
||||
std::function<void(blender::draw::ObjectRef &, RenderEngine *, Depsgraph *)>);
|
||||
|
||||
/**
|
||||
* \warning Changing frame might free the #ViewLayerEngineData.
|
||||
@@ -144,9 +186,7 @@ void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame,
|
||||
* This function only setup DST and execute the given function.
|
||||
* \warning similar to DRW_render_to_image you cannot use default lists (`dfbl` & `dtxl`).
|
||||
*/
|
||||
void DRW_custom_pipeline_begin(DRWContext &draw_ctx,
|
||||
DrawEngineType *draw_engine_type,
|
||||
Depsgraph *depsgraph);
|
||||
void DRW_custom_pipeline_begin(DRWContext &draw_ctx, Depsgraph *depsgraph);
|
||||
void DRW_custom_pipeline_end(DRWContext &draw_ctx);
|
||||
|
||||
/**
|
||||
@@ -155,24 +195,6 @@ void DRW_custom_pipeline_end(DRWContext &draw_ctx);
|
||||
*/
|
||||
void DRW_cache_restart();
|
||||
|
||||
/* ViewLayers */
|
||||
|
||||
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
|
||||
void **DRW_view_layer_engine_data_ensure_ex(ViewLayer *view_layer,
|
||||
DrawEngineType *engine_type,
|
||||
void (*callback)(void *storage));
|
||||
void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type,
|
||||
void (*callback)(void *storage));
|
||||
|
||||
/* DrawData */
|
||||
|
||||
DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type);
|
||||
DrawData *DRW_drawdata_ensure(ID *id,
|
||||
DrawEngineType *engine_type,
|
||||
size_t size,
|
||||
DrawDataInitCb init_cb,
|
||||
DrawDataFreeCb free_cb);
|
||||
|
||||
/* Settings. */
|
||||
|
||||
bool DRW_object_is_renderable(const Object *ob);
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
#include "engines/compositor/compositor_engine.h"
|
||||
#include "engines/eevee_next/eevee_engine.h"
|
||||
#include "engines/external/external_engine.h"
|
||||
#include "engines/gpencil/gpencil_engine.h"
|
||||
#include "engines/gpencil/gpencil_engine.hh"
|
||||
#include "engines/image/image_engine.h"
|
||||
#include "engines/overlay/overlay_engine.h"
|
||||
#include "engines/select/select_engine.hh"
|
||||
@@ -197,8 +197,7 @@ DRWContext::~DRWContext()
|
||||
|
||||
GPUFrameBuffer *DRWContext::default_framebuffer()
|
||||
{
|
||||
DefaultFramebufferList *dfbl = DRW_view_data_default_framebuffer_list_get(view_data_active);
|
||||
return dfbl->default_fb;
|
||||
return view_data_active->dfbl.default_fb;
|
||||
}
|
||||
|
||||
static bool draw_show_annotation()
|
||||
@@ -496,17 +495,18 @@ void DRWContext::release_data()
|
||||
|
||||
DefaultFramebufferList *DRW_viewport_framebuffer_list_get()
|
||||
{
|
||||
return DRW_view_data_default_framebuffer_list_get(drw_get().view_data_active);
|
||||
return &drw_get().view_data_active->dfbl;
|
||||
}
|
||||
|
||||
DefaultTextureList *DRW_viewport_texture_list_get()
|
||||
{
|
||||
return DRW_view_data_default_texture_list_get(drw_get().view_data_active);
|
||||
return &drw_get().view_data_active->dtxl;
|
||||
}
|
||||
|
||||
blender::draw::TextureFromPool &DRW_viewport_pass_texture_get(const char *pass_name)
|
||||
{
|
||||
return DRW_view_data_pass_texture_get(drw_get().view_data_active, pass_name);
|
||||
return *drw_get().view_data_active->viewport_compositor_passes.lookup_or_add_cb(
|
||||
pass_name, [&]() { return std::make_unique<blender::draw::TextureFromPool>(pass_name); });
|
||||
}
|
||||
|
||||
void DRW_viewport_request_redraw()
|
||||
@@ -634,49 +634,6 @@ void DupliCacheManager::extract_all(ExtractionGraph &extraction)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name ViewLayers (DRW_scenelayer)
|
||||
* \{ */
|
||||
|
||||
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type)
|
||||
{
|
||||
LISTBASE_FOREACH (ViewLayerEngineData *, sled, &drw_get().view_layer->drawdata) {
|
||||
if (sled->engine_type == engine_type) {
|
||||
return sled->storage;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void **DRW_view_layer_engine_data_ensure_ex(ViewLayer *view_layer,
|
||||
DrawEngineType *engine_type,
|
||||
void (*callback)(void *storage))
|
||||
{
|
||||
ViewLayerEngineData *sled;
|
||||
|
||||
LISTBASE_FOREACH (ViewLayerEngineData *, sled, &view_layer->drawdata) {
|
||||
if (sled->engine_type == engine_type) {
|
||||
return &sled->storage;
|
||||
}
|
||||
}
|
||||
|
||||
sled = static_cast<ViewLayerEngineData *>(
|
||||
MEM_callocN(sizeof(ViewLayerEngineData), "ViewLayerEngineData"));
|
||||
sled->engine_type = engine_type;
|
||||
sled->free = callback;
|
||||
BLI_addtail(&view_layer->drawdata, sled);
|
||||
|
||||
return &sled->storage;
|
||||
}
|
||||
|
||||
void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type,
|
||||
void (*callback)(void *storage))
|
||||
{
|
||||
return DRW_view_layer_engine_data_ensure_ex(drw_get().view_layer, engine_type, callback);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Draw Data (DRW_drawdata)
|
||||
* \{ */
|
||||
@@ -737,56 +694,6 @@ DrawDataList *DRW_drawdatalist_from_id(ID *id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type)
|
||||
{
|
||||
DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
|
||||
|
||||
if (drawdata == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (DrawData *, dd, drawdata) {
|
||||
if (dd->engine_type == engine_type) {
|
||||
return dd;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DrawData *DRW_drawdata_ensure(ID *id,
|
||||
DrawEngineType *engine_type,
|
||||
size_t size,
|
||||
DrawDataInitCb init_cb,
|
||||
DrawDataFreeCb free_cb)
|
||||
{
|
||||
BLI_assert(size >= sizeof(DrawData));
|
||||
BLI_assert(id_can_have_drawdata(id));
|
||||
BLI_assert_msg(
|
||||
GS(id->name) != ID_OB,
|
||||
"Objects should not use DrawData anymore. Use last_update instead for update detection");
|
||||
/* Try to re-use existing data. */
|
||||
DrawData *dd = DRW_drawdata_get(id, engine_type);
|
||||
if (dd != nullptr) {
|
||||
return dd;
|
||||
}
|
||||
|
||||
DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
|
||||
|
||||
/* Allocate new data. */
|
||||
{
|
||||
dd = static_cast<DrawData *>(MEM_callocN(size, "DrawData"));
|
||||
}
|
||||
dd->engine_type = engine_type;
|
||||
dd->free = free_cb;
|
||||
/* Perform user-side initialization, if needed. */
|
||||
if (init_cb != nullptr) {
|
||||
init_cb(dd);
|
||||
}
|
||||
/* Register in the list. */
|
||||
BLI_addtail((ListBase *)drawdata, dd);
|
||||
return dd;
|
||||
}
|
||||
|
||||
void DRW_drawdata_free(ID *id)
|
||||
{
|
||||
DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
|
||||
@@ -908,11 +815,7 @@ static void drw_engines_cache_populate(blender::draw::ObjectRef &ref, Extraction
|
||||
|
||||
DRWContext &ctx = drw_get();
|
||||
ctx.view_data_active->foreach_enabled_engine(
|
||||
[&](ViewportEngineData *data, DrawEngineType *engine) {
|
||||
if (engine->cache_populate) {
|
||||
engine->cache_populate(data, ref);
|
||||
}
|
||||
});
|
||||
[&](DrawEngine &instance) { instance.object_sync(ref, *DRW_manager_get()); });
|
||||
|
||||
/* TODO: in the future it would be nice to generate once for all viewports.
|
||||
* But we need threaded DRW manager first. */
|
||||
@@ -947,34 +850,24 @@ void DRWContext::sync(iter_callback_t iter_callback)
|
||||
|
||||
void DRWContext::engines_init_and_sync(iter_callback_t iter_callback)
|
||||
{
|
||||
view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) {
|
||||
if (engine->engine_init) {
|
||||
engine->engine_init(data);
|
||||
}
|
||||
});
|
||||
view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { instance.init(); });
|
||||
|
||||
view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) {
|
||||
view_data_active->foreach_enabled_engine([&](DrawEngine &instance) {
|
||||
/* TODO(fclem): Remove. Only there for overlay engine. */
|
||||
if (data->text_draw_cache) {
|
||||
DRW_text_cache_destroy(data->text_draw_cache);
|
||||
data->text_draw_cache = nullptr;
|
||||
if (instance.text_draw_cache) {
|
||||
DRW_text_cache_destroy(instance.text_draw_cache);
|
||||
instance.text_draw_cache = nullptr;
|
||||
}
|
||||
if (drw_get().text_store_p == nullptr) {
|
||||
drw_get().text_store_p = &data->text_draw_cache;
|
||||
drw_get().text_store_p = &instance.text_draw_cache;
|
||||
}
|
||||
|
||||
if (engine->cache_init) {
|
||||
engine->cache_init(data);
|
||||
}
|
||||
instance.begin_sync();
|
||||
});
|
||||
|
||||
sync(iter_callback);
|
||||
|
||||
view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) {
|
||||
if (engine->cache_finish) {
|
||||
engine->cache_finish(data);
|
||||
}
|
||||
});
|
||||
view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { instance.end_sync(); });
|
||||
}
|
||||
|
||||
void DRWContext::engines_draw_scene()
|
||||
@@ -982,12 +875,10 @@ void DRWContext::engines_draw_scene()
|
||||
/* Start Drawing */
|
||||
blender::draw::command::StateSet::set();
|
||||
|
||||
view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) {
|
||||
if (engine->draw_scene) {
|
||||
GPU_debug_group_begin(engine->idname);
|
||||
engine->draw_scene(data);
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
view_data_active->foreach_enabled_engine([&](DrawEngine &instance) {
|
||||
GPU_debug_group_begin(instance.name_get().c_str());
|
||||
instance.draw(*DRW_manager_get());
|
||||
GPU_debug_group_end();
|
||||
});
|
||||
|
||||
/* Reset state after drawing */
|
||||
@@ -1002,30 +893,28 @@ void DRWContext::engines_draw_scene()
|
||||
static void drw_engines_draw_text()
|
||||
{
|
||||
DRWContext &ctx = drw_get();
|
||||
ctx.view_data_active->foreach_enabled_engine(
|
||||
[&](ViewportEngineData *data, DrawEngineType * /*engine*/) {
|
||||
if (data->text_draw_cache) {
|
||||
DRW_text_cache_draw(data->text_draw_cache, ctx.region, ctx.v3d);
|
||||
}
|
||||
});
|
||||
ctx.view_data_active->foreach_enabled_engine([&](DrawEngine &instance) {
|
||||
if (instance.text_draw_cache) {
|
||||
DRW_text_cache_draw(instance.text_draw_cache, ctx.region, ctx.v3d);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height)
|
||||
{
|
||||
DRWContext &ctx = drw_get();
|
||||
ctx.view_data_active->foreach_enabled_engine(
|
||||
[&](ViewportEngineData *data, DrawEngineType * /*engine*/) {
|
||||
if (data->info[0] != '\0') {
|
||||
const char *buf_step = IFACE_(data->info);
|
||||
do {
|
||||
const char *buf = buf_step;
|
||||
buf_step = BLI_strchr_or_end(buf, '\n');
|
||||
const int buf_len = buf_step - buf;
|
||||
*yoffset -= line_height;
|
||||
BLF_draw_default(xoffset, *yoffset, 0.0f, buf, buf_len);
|
||||
} while (*buf_step ? ((void)buf_step++, true) : false);
|
||||
}
|
||||
});
|
||||
ctx.view_data_active->foreach_enabled_engine([&](DrawEngine &instance) {
|
||||
if (instance.info[0] != '\0') {
|
||||
const char *buf_step = IFACE_(instance.info);
|
||||
do {
|
||||
const char *buf = buf_step;
|
||||
buf_step = BLI_strchr_or_end(buf, '\n');
|
||||
const int buf_len = buf_step - buf;
|
||||
*yoffset -= line_height;
|
||||
BLF_draw_default(xoffset, *yoffset, 0.0f, buf, buf_len);
|
||||
} while (*buf_step ? ((void)buf_step++, true) : false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *render_engine_type)
|
||||
@@ -1035,12 +924,12 @@ void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *re
|
||||
SpaceLink *space_data = this->space_data;
|
||||
if (space_data && space_data->spacetype == SPACE_IMAGE) {
|
||||
if (DRW_engine_external_acquire_for_image_editor()) {
|
||||
view_data.external.used = true;
|
||||
view_data.external.set_used(true);
|
||||
}
|
||||
else {
|
||||
view_data.image.used = true;
|
||||
view_data.image.set_used(true);
|
||||
}
|
||||
view_data.overlay.used = true;
|
||||
view_data.overlay.set_used(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1048,26 +937,26 @@ void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *re
|
||||
/* Only enable when drawing the space image backdrop. */
|
||||
SpaceNode *snode = (SpaceNode *)space_data;
|
||||
if ((snode->flag & SNODE_BACKDRAW) != 0) {
|
||||
view_data.image.used = true;
|
||||
view_data.overlay.used = true;
|
||||
view_data.image.set_used(true);
|
||||
view_data.overlay.set_used(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ELEM(this->mode, DRWContext::SELECT_OBJECT, DRWContext::SELECT_OBJECT_MATERIAL)) {
|
||||
this->view_data_active->grease_pencil.used = gpencil_engine_needed;
|
||||
this->view_data_active->object_select.used = true;
|
||||
view_data.grease_pencil.set_used(gpencil_engine_needed);
|
||||
view_data.object_select.set_used(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ELEM(this->mode, DRWContext::SELECT_EDIT_MESH)) {
|
||||
this->view_data_active->edit_select.used = true;
|
||||
view_data.edit_select.set_used(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ELEM(this->mode, DRWContext::DEPTH)) {
|
||||
this->view_data_active->grease_pencil.used = gpencil_engine_needed;
|
||||
this->view_data_active->overlay.used = true;
|
||||
view_data.grease_pencil.set_used(gpencil_engine_needed);
|
||||
view_data.overlay.set_used(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1080,41 +969,39 @@ void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *re
|
||||
switch (drawtype) {
|
||||
case OB_WIRE:
|
||||
case OB_SOLID:
|
||||
view_data.workbench.used = true;
|
||||
view_data.workbench.set_used(true);
|
||||
break;
|
||||
case OB_MATERIAL:
|
||||
case OB_RENDER:
|
||||
default:
|
||||
if (render_engine_type->draw_engine != nullptr) {
|
||||
if (render_engine_type == &DRW_engine_viewport_eevee_next_type) {
|
||||
view_data.eevee.used = true;
|
||||
}
|
||||
else if (render_engine_type == &DRW_engine_viewport_workbench_type) {
|
||||
view_data.workbench.used = true;
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
if (render_engine_type == &DRW_engine_viewport_eevee_next_type) {
|
||||
view_data.eevee.set_used(true);
|
||||
}
|
||||
else if (render_engine_type == &DRW_engine_viewport_workbench_type) {
|
||||
view_data.workbench.set_used(true);
|
||||
}
|
||||
else if ((render_engine_type->flag & RE_INTERNAL) == 0) {
|
||||
view_data.external.used = true;
|
||||
view_data.external.set_used(true);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) {
|
||||
view_data.grease_pencil.used = true;
|
||||
if ((drawtype >= OB_SOLID) || !use_xray) {
|
||||
view_data.grease_pencil.set_used(gpencil_engine_needed);
|
||||
}
|
||||
|
||||
if (DRW_state_viewport_compositor_enabled()) {
|
||||
view_data.compositor.used = true;
|
||||
view_data.compositor.set_used(true);
|
||||
}
|
||||
|
||||
view_data.overlay.used = true;
|
||||
view_data.overlay.set_used(true);
|
||||
|
||||
#ifdef WITH_DRAW_DEBUG
|
||||
if (G.debug_value == 31) {
|
||||
view_data_active.edit_select_debug.used = true;
|
||||
view_data.edit_select_debug.set_used(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1605,21 +1492,9 @@ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void drw_render_gpencil_to_image(RenderEngine *engine,
|
||||
RenderLayer *render_layer,
|
||||
const rcti *rect)
|
||||
{
|
||||
DrawEngineType *draw_engine = &draw_engine_gpencil_type;
|
||||
|
||||
if (draw_engine->render_to_image) {
|
||||
ViewportEngineData *gpdata = DRW_view_data_engine_data_get_ensure(drw_get().view_data_active,
|
||||
draw_engine);
|
||||
draw_engine->render_to_image(gpdata, engine, render_layer, rect);
|
||||
}
|
||||
}
|
||||
|
||||
void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
/* This function should only be called if there are grease pencil objects,
|
||||
* especially important to avoid failing in background renders without GPU context. */
|
||||
BLI_assert(DRW_render_check_grease_pencil(depsgraph));
|
||||
@@ -1655,10 +1530,10 @@ void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
render_view = render_view->next)
|
||||
{
|
||||
RE_SetActiveRenderView(render, render_view->name);
|
||||
drw_render_gpencil_to_image(engine, render_layer, &render_rect);
|
||||
gpencil::Engine::render_to_image(engine, render_layer, render_rect);
|
||||
}
|
||||
|
||||
blender::draw::command::StateSet::set();
|
||||
command::StateSet::set();
|
||||
|
||||
GPU_depth_test(GPU_DEPTH_NONE);
|
||||
|
||||
@@ -1672,13 +1547,15 @@ void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
DRW_render_context_disable(render);
|
||||
}
|
||||
|
||||
void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
void DRW_render_to_image(
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph,
|
||||
std::function<void(RenderEngine *, RenderLayer *, const rcti)> render_view_cb,
|
||||
std::function<void(RenderResult *)> store_metadata_cb)
|
||||
{
|
||||
using namespace blender::draw;
|
||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
|
||||
RenderEngineType *engine_type = engine->type;
|
||||
DrawEngineType *draw_engine_type = engine_type->draw_engine;
|
||||
Render *render = engine->re;
|
||||
|
||||
/* IMPORTANT: We don't support immediate mode in render mode!
|
||||
@@ -1694,9 +1571,6 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
/* Init modules ahead of time because the begin_sync happens before DRW_render_object_iter. */
|
||||
draw_ctx.data->modules_init();
|
||||
|
||||
ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(drw_get().view_data_active,
|
||||
draw_engine_type);
|
||||
|
||||
/* Main rendering. */
|
||||
rctf view_rect;
|
||||
rcti render_rect;
|
||||
@@ -1706,7 +1580,7 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
}
|
||||
|
||||
/* Reset state before drawing */
|
||||
blender::draw::command::StateSet::set();
|
||||
command::StateSet::set();
|
||||
|
||||
/* set default viewport */
|
||||
GPU_viewport(0, 0, draw_ctx.size[0], draw_ctx.size[1]);
|
||||
@@ -1725,15 +1599,12 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
render_view = render_view->next)
|
||||
{
|
||||
RE_SetActiveRenderView(render, render_view->name);
|
||||
engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
|
||||
render_view_cb(engine, render_layer, render_rect);
|
||||
}
|
||||
|
||||
RE_engine_end_result(engine, render_result, false, false, false);
|
||||
|
||||
if (engine_type->draw_engine->store_metadata) {
|
||||
RenderResult *final_render_result = RE_engine_get_result(engine);
|
||||
engine_type->draw_engine->store_metadata(data, final_render_result);
|
||||
}
|
||||
store_metadata_cb(RE_engine_get_result(engine));
|
||||
|
||||
GPU_framebuffer_restore();
|
||||
|
||||
@@ -1746,13 +1617,10 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph)
|
||||
GPU_render_end();
|
||||
}
|
||||
|
||||
void DRW_render_object_iter(void *vedata,
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph,
|
||||
void (*callback)(void *vedata,
|
||||
blender::draw::ObjectRef &ob_ref,
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph))
|
||||
void DRW_render_object_iter(
|
||||
RenderEngine *engine,
|
||||
Depsgraph *depsgraph,
|
||||
std::function<void(blender::draw::ObjectRef &, RenderEngine *, Depsgraph *)> callback)
|
||||
{
|
||||
DRWContext &draw_ctx = drw_get();
|
||||
|
||||
@@ -1772,7 +1640,7 @@ void DRW_render_object_iter(void *vedata,
|
||||
if (ob_ref.is_dupli() == false) {
|
||||
drw_batch_cache_validate(ob);
|
||||
}
|
||||
callback(vedata, ob_ref, engine, depsgraph);
|
||||
callback(ob_ref, engine, depsgraph);
|
||||
if (ob_ref.is_dupli() == false) {
|
||||
drw_batch_cache_generate_requested(ob, *extraction.graph);
|
||||
}
|
||||
@@ -1782,9 +1650,7 @@ void DRW_render_object_iter(void *vedata,
|
||||
});
|
||||
}
|
||||
|
||||
void DRW_custom_pipeline_begin(DRWContext &draw_ctx,
|
||||
DrawEngineType * /*draw_engine_type*/,
|
||||
Depsgraph * /*depsgraph*/)
|
||||
void DRW_custom_pipeline_begin(DRWContext &draw_ctx, Depsgraph * /*depsgraph*/)
|
||||
{
|
||||
draw_ctx.acquire_data();
|
||||
draw_ctx.data->modules_init();
|
||||
@@ -2245,15 +2111,15 @@ void DRW_engines_register()
|
||||
|
||||
void DRW_engines_free()
|
||||
{
|
||||
DRW_engine_viewport_eevee_next_type.draw_engine->engine_free();
|
||||
DRW_engine_viewport_workbench_type.draw_engine->engine_free();
|
||||
draw_engine_gpencil_type.engine_free();
|
||||
draw_engine_image_type.engine_free();
|
||||
draw_engine_overlay_next_type.engine_free();
|
||||
blender::eevee::Engine::free_static();
|
||||
blender::workbench::Engine::free_static();
|
||||
blender::draw::gpencil::Engine::free_static();
|
||||
blender::image_engine::Engine::free_static();
|
||||
blender::draw::overlay::Engine::free_static();
|
||||
blender::draw::edit_select::Engine::free_static();
|
||||
#ifdef WITH_DRAW_DEBUG
|
||||
draw_engine_debug_select_type.engine_free();
|
||||
blender::draw::edit_select_debug::Engine::free_static();
|
||||
#endif
|
||||
draw_engine_select_type.engine_free();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -81,6 +81,9 @@ DRWTextStore *DRW_text_cache_create()
|
||||
|
||||
void DRW_text_cache_destroy(DRWTextStore *dt)
|
||||
{
|
||||
if (dt == nullptr) {
|
||||
return;
|
||||
}
|
||||
BLI_memiter_destroy(dt->cache_strings);
|
||||
MEM_freeN(dt);
|
||||
}
|
||||
|
||||
@@ -23,30 +23,9 @@
|
||||
#include "draw_manager.hh"
|
||||
#include "draw_view_data.hh"
|
||||
|
||||
#include "engines/compositor/compositor_engine.h"
|
||||
#include "engines/eevee_next/eevee_engine.h"
|
||||
#include "engines/external/external_engine.h"
|
||||
#include "engines/gpencil/gpencil_engine.h"
|
||||
#include "engines/image/image_engine.h"
|
||||
#include "engines/overlay/overlay_engine.h"
|
||||
#include "engines/select/select_engine.hh"
|
||||
#include "engines/workbench/workbench_engine.h"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
DRWViewData::DRWViewData()
|
||||
: eevee(DRW_engine_viewport_eevee_next_type.draw_engine),
|
||||
workbench(DRW_engine_viewport_workbench_type.draw_engine),
|
||||
external(&draw_engine_external_type),
|
||||
image(&draw_engine_image_type),
|
||||
grease_pencil(&draw_engine_gpencil_type),
|
||||
overlay(&draw_engine_overlay_next_type),
|
||||
object_select(&draw_engine_select_next_type),
|
||||
edit_select(&draw_engine_select_type),
|
||||
#ifdef WITH_DRAW_DEBUG
|
||||
edit_select_debug(DRW_engine_viewport_select_type.draw_engine),
|
||||
#endif
|
||||
compositor(&draw_engine_compositor_type)
|
||||
{
|
||||
manager = new draw::Manager();
|
||||
};
|
||||
@@ -57,13 +36,6 @@ DRWViewData::~DRWViewData()
|
||||
delete manager;
|
||||
};
|
||||
|
||||
draw::TextureFromPool &DRW_view_data_pass_texture_get(DRWViewData *view_data,
|
||||
const char *pass_name)
|
||||
{
|
||||
return *view_data->viewport_compositor_passes.lookup_or_add_cb(
|
||||
pass_name, [&]() { return std::make_unique<draw::TextureFromPool>(pass_name); });
|
||||
}
|
||||
|
||||
void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewport *viewport)
|
||||
{
|
||||
int active_view = GPU_viewport_active_view_get(viewport);
|
||||
@@ -103,22 +75,6 @@ void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewpo
|
||||
});
|
||||
}
|
||||
|
||||
static void draw_viewport_engines_data_clear(ViewportEngineData *data, bool clear_instance_data)
|
||||
{
|
||||
DrawEngineType *engine_type = data->draw_engine;
|
||||
|
||||
if (clear_instance_data && data->instance_data) {
|
||||
BLI_assert(engine_type->instance_free != nullptr);
|
||||
engine_type->instance_free(data->instance_data);
|
||||
data->instance_data = nullptr;
|
||||
}
|
||||
|
||||
if (data->text_draw_cache) {
|
||||
DRW_text_cache_destroy(data->text_draw_cache);
|
||||
data->text_draw_cache = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DRWViewData::clear(bool free_instance_data)
|
||||
{
|
||||
GPU_FRAMEBUFFER_FREE_SAFE(this->dfbl.default_fb);
|
||||
@@ -135,9 +91,15 @@ void DRWViewData::clear(bool free_instance_data)
|
||||
}
|
||||
GPU_TEXTURE_FREE_SAFE(this->dtxl.depth_in_front);
|
||||
|
||||
foreach_engine([&](ViewportEngineData *data, DrawEngineType * /*engine*/) {
|
||||
draw_viewport_engines_data_clear(data, free_instance_data);
|
||||
});
|
||||
if (free_instance_data) {
|
||||
foreach_engine([&](DrawEngine::Pointer &ptr) {
|
||||
if (ptr.instance) {
|
||||
/* TODO Move where it belongs. */
|
||||
DRW_text_cache_destroy(ptr.instance->text_draw_cache);
|
||||
ptr.free_instance();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DRWViewData::texture_list_size_validate(const blender::int2 &size)
|
||||
@@ -148,28 +110,9 @@ void DRWViewData::texture_list_size_validate(const blender::int2 &size)
|
||||
}
|
||||
}
|
||||
|
||||
ViewportEngineData *DRW_view_data_engine_data_get_ensure(DRWViewData *view_data,
|
||||
DrawEngineType *engine_type)
|
||||
{
|
||||
ViewportEngineData *result = nullptr;
|
||||
view_data->foreach_engine([&](ViewportEngineData *data, DrawEngineType *engine) {
|
||||
if (engine_type == engine) {
|
||||
result = data;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void DRW_view_data_use_engine(DRWViewData *view_data, DrawEngineType *engine_type)
|
||||
{
|
||||
ViewportEngineData *engine = DRW_view_data_engine_data_get_ensure(view_data, engine_type);
|
||||
engine->used = true;
|
||||
}
|
||||
|
||||
void DRW_view_data_reset(DRWViewData *view_data)
|
||||
{
|
||||
view_data->foreach_enabled_engine(
|
||||
[&](ViewportEngineData *data, DrawEngineType * /*engine*/) { data->used = false; });
|
||||
view_data->foreach_enabled_engine([&](DrawEngine &instance) { instance.used = false; });
|
||||
|
||||
for (std::unique_ptr<draw::TextureFromPool> &texture :
|
||||
view_data->viewport_compositor_passes.values())
|
||||
@@ -181,23 +124,15 @@ void DRW_view_data_reset(DRWViewData *view_data)
|
||||
|
||||
void DRW_view_data_free_unused(DRWViewData *view_data)
|
||||
{
|
||||
view_data->foreach_engine([&](ViewportEngineData *data, DrawEngineType * /*engine*/) {
|
||||
if (data->used == false) {
|
||||
draw_viewport_engines_data_clear(data, false);
|
||||
view_data->foreach_engine([&](DrawEngine::Pointer &ptr) {
|
||||
if (ptr.instance && ptr.instance->used == false) {
|
||||
/* TODO Move where it belongs. */
|
||||
DRW_text_cache_destroy(ptr.instance->text_draw_cache);
|
||||
ptr.free_instance();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DefaultFramebufferList *DRW_view_data_default_framebuffer_list_get(DRWViewData *view_data)
|
||||
{
|
||||
return &view_data->dfbl;
|
||||
}
|
||||
|
||||
DefaultTextureList *DRW_view_data_default_texture_list_get(DRWViewData *view_data)
|
||||
{
|
||||
return &view_data->dtxl;
|
||||
}
|
||||
|
||||
draw::Manager *DRW_manager_get()
|
||||
{
|
||||
BLI_assert(drw_get().view_data_active->manager);
|
||||
|
||||
@@ -17,6 +17,15 @@
|
||||
#include "DRW_render.hh"
|
||||
#include "draw_context_private.hh"
|
||||
|
||||
#include "engines/compositor/compositor_engine.h"
|
||||
#include "engines/eevee_next/eevee_engine.h"
|
||||
#include "engines/external/external_engine.h"
|
||||
#include "engines/gpencil/gpencil_engine.hh"
|
||||
#include "engines/image/image_engine.h"
|
||||
#include "engines/overlay/overlay_engine.h"
|
||||
#include "engines/select/select_engine.hh"
|
||||
#include "engines/workbench/workbench_engine.h"
|
||||
|
||||
#define GPU_INFO_SIZE 512 /* IMA_MAX_RENDER_TEXT_SIZE */
|
||||
|
||||
namespace blender::draw {
|
||||
@@ -24,40 +33,12 @@ class TextureFromPool;
|
||||
class Manager;
|
||||
} // namespace blender::draw
|
||||
|
||||
struct DrawEngineType;
|
||||
struct DRWTextStore;
|
||||
struct GPUFrameBuffer;
|
||||
struct GPUTexture;
|
||||
struct GPUViewport;
|
||||
struct ListBase;
|
||||
|
||||
struct ViewportEngineData {
|
||||
/* Not owning pointer to the draw engine. */
|
||||
DrawEngineType *draw_engine;
|
||||
|
||||
/**
|
||||
* \brief Memory block that can be freely used by the draw engine.
|
||||
* When used the draw engine must implement #DrawEngineType.instance_free callback.
|
||||
*/
|
||||
void *instance_data = nullptr;
|
||||
|
||||
char info[GPU_INFO_SIZE] = {'\0'};
|
||||
|
||||
/* we may want to put this elsewhere */
|
||||
DRWTextStore *text_draw_cache = nullptr;
|
||||
|
||||
bool used = false;
|
||||
|
||||
ViewportEngineData(DrawEngineType *engine_type) : draw_engine(engine_type) {}
|
||||
};
|
||||
|
||||
struct ViewportEngineData_Info {
|
||||
int fbl_len;
|
||||
int txl_len;
|
||||
int psl_len;
|
||||
int stl_len;
|
||||
};
|
||||
|
||||
/* Buffer and textures used by the viewport by default */
|
||||
struct DefaultFramebufferList {
|
||||
GPUFrameBuffer *default_fb;
|
||||
@@ -86,19 +67,18 @@ struct DRWViewData {
|
||||
blender::int2 texture_list_size = {0, 0};
|
||||
|
||||
/* Engines running for this viewport. nullptr if not enabled. */
|
||||
/* TODO(fclem): Directly use each engine class. */
|
||||
ViewportEngineData eevee;
|
||||
ViewportEngineData workbench;
|
||||
ViewportEngineData external;
|
||||
ViewportEngineData image;
|
||||
ViewportEngineData grease_pencil;
|
||||
ViewportEngineData overlay;
|
||||
ViewportEngineData object_select;
|
||||
ViewportEngineData edit_select;
|
||||
blender::eevee::Engine eevee;
|
||||
blender::workbench::Engine workbench;
|
||||
blender::draw::external::Engine external;
|
||||
blender::image_engine::Engine image;
|
||||
blender::draw::gpencil::Engine grease_pencil;
|
||||
blender::draw::overlay::Engine overlay;
|
||||
blender::draw::select::Engine object_select;
|
||||
blender::draw::edit_select::Engine edit_select;
|
||||
#ifdef WITH_DRAW_DEBUG
|
||||
ViewportEngineData edit_select_debug;
|
||||
blender::draw::edit_select_debug::Engine edit_select_debug;
|
||||
#endif
|
||||
ViewportEngineData compositor;
|
||||
blender::draw::compositor_engine::Engine compositor;
|
||||
|
||||
/* Stores passes needed by the viewport compositor. Engines are expected to populate those in
|
||||
* every redraw using calls to the DRW_viewport_pass_texture_get function. The compositor can
|
||||
@@ -121,32 +101,32 @@ struct DRWViewData {
|
||||
/* IMPORTANT: Order here defines the draw order. */
|
||||
|
||||
/* Render engines. Output to the render result framebuffer. Mutually exclusive. */
|
||||
callback(&eevee, eevee.draw_engine);
|
||||
callback(&workbench, workbench.draw_engine);
|
||||
callback(&external, external.draw_engine);
|
||||
callback(&image, image.draw_engine);
|
||||
callback(eevee);
|
||||
callback(workbench);
|
||||
callback(external);
|
||||
callback(image);
|
||||
#ifdef WITH_DRAW_DEBUG
|
||||
callback(&edit_select_debug, edit_select_debug.draw_engine);
|
||||
callback(edit_select_debug);
|
||||
#endif
|
||||
/* Grease pencil. Merge its output to the render result framebuffer. */
|
||||
callback(&grease_pencil, grease_pencil.draw_engine);
|
||||
callback(grease_pencil);
|
||||
/* GPU compositor. Processes render result and output to the render result framebuffer. */
|
||||
callback(&compositor, compositor.draw_engine);
|
||||
callback(compositor);
|
||||
/* Overlays. Draw on a separate overlay framebuffer. Can read render result. */
|
||||
callback(&overlay, overlay.draw_engine);
|
||||
callback(overlay);
|
||||
|
||||
/* Selection. Are always enabled alone and have no interaction with other engines. */
|
||||
callback(&object_select, object_select.draw_engine);
|
||||
callback(&edit_select, edit_select.draw_engine);
|
||||
callback(object_select);
|
||||
callback(edit_select);
|
||||
}
|
||||
|
||||
template<typename CallbackT> void foreach_enabled_engine(CallbackT callback)
|
||||
{
|
||||
foreach_engine([&](ViewportEngineData *data, DrawEngineType *engine) {
|
||||
if (!data->used) {
|
||||
foreach_engine([&](DrawEngine::Pointer &ptr) {
|
||||
if (ptr.instance == nullptr || ptr.instance->used == false) {
|
||||
return;
|
||||
}
|
||||
callback(data, engine);
|
||||
callback(*ptr.instance);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -154,18 +134,6 @@ struct DRWViewData {
|
||||
void clear(bool free_instance_data);
|
||||
};
|
||||
|
||||
/* Returns a TextureFromPool stored in the given view data for the pass identified by the given
|
||||
* pass name. Engines should call this function for each of the passes needed by the viewport
|
||||
* compositor in every redraw, then it should allocate the texture and write the pass data to it.
|
||||
* The texture should cover the entire viewport. */
|
||||
blender::draw::TextureFromPool &DRW_view_data_pass_texture_get(DRWViewData *view_data,
|
||||
const char *pass_name);
|
||||
|
||||
void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewport *viewport);
|
||||
ViewportEngineData *DRW_view_data_engine_data_get_ensure(DRWViewData *view_data,
|
||||
DrawEngineType *engine_type);
|
||||
void DRW_view_data_use_engine(DRWViewData *view_data, DrawEngineType *engine_type);
|
||||
void DRW_view_data_reset(DRWViewData *view_data);
|
||||
void DRW_view_data_free_unused(DRWViewData *view_data);
|
||||
DefaultFramebufferList *DRW_view_data_default_framebuffer_list_get(DRWViewData *view_data);
|
||||
DefaultTextureList *DRW_view_data_default_texture_list_get(DRWViewData *view_data);
|
||||
|
||||
Reference in New Issue
Block a user