Cleanup: move off-screen drawing to view3d_draw.c
Since offscreen drawing now uses draw engine, this doesn't need to be considered legacy. Note that there are some calls into view3d_draw_legacy.c from view3d_draw.c this is generally not accepted, so its only dont where there are checks for new/old engine. Functions exposed to do this use a VP_deprecated prefix.
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_object.h"
|
||||
@@ -48,6 +49,7 @@
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_jitter.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
@@ -72,11 +74,13 @@
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_matrix.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_immediate_util.h"
|
||||
#include "GPU_material.h"
|
||||
#include "GPU_viewport.h"
|
||||
#include "GPU_compositing.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
@@ -88,6 +92,9 @@
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
#include "view3d_intern.h" /* own include */
|
||||
|
||||
/* prototypes */
|
||||
@@ -2444,11 +2451,416 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar)
|
||||
v3d->flag |= V3D_INVALID_BACKBUF;
|
||||
}
|
||||
|
||||
/* ******************** legacy interface ***************** */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Offscreen Drawing
|
||||
* \{ */
|
||||
|
||||
static void view3d_stereo3d_setup_offscreen(
|
||||
Scene *scene, View3D *v3d, ARegion *ar,
|
||||
float winmat[4][4], const char *viewname)
|
||||
{
|
||||
/* update the viewport matrices with the new camera */
|
||||
if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
|
||||
float viewmat[4][4];
|
||||
const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
|
||||
|
||||
BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
|
||||
VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
|
||||
}
|
||||
else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
|
||||
float viewmat[4][4];
|
||||
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
|
||||
|
||||
BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
|
||||
VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
|
||||
}
|
||||
}
|
||||
|
||||
void ED_view3d_draw_offscreen_init(Scene *scene, SceneLayer *sl, View3D *v3d)
|
||||
{
|
||||
RenderEngineType *type = RE_engines_find(scene->r.engine);
|
||||
if (IS_VIEWPORT_LEGACY(v3d) && ((type->flag & RE_USE_LEGACY_PIPELINE) != 0)) {
|
||||
/* shadow buffers, before we setup matrices */
|
||||
if (draw_glsl_material(scene, sl, NULL, v3d, v3d->drawtype)) {
|
||||
VP_deprecated_gpu_update_lamps_shadows_world(scene, v3d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to clear the view
|
||||
*/
|
||||
static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
|
||||
{
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
|
||||
VP_view3d_draw_background_world(scene, v3d, ar->regiondata);
|
||||
}
|
||||
else {
|
||||
VP_view3d_draw_background_none();
|
||||
}
|
||||
}
|
||||
|
||||
/* ED_view3d_draw_offscreen_init should be called before this to initialize
|
||||
* stuff like shadow buffers
|
||||
*/
|
||||
void ED_view3d_draw_offscreen(
|
||||
Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
|
||||
float viewmat[4][4], float winmat[4][4],
|
||||
bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
|
||||
GPUFX *fx, GPUFXSettings *fx_settings,
|
||||
GPUOffScreen *ofs)
|
||||
{
|
||||
bool do_compositing = false;
|
||||
RegionView3D *rv3d = ar->regiondata;
|
||||
|
||||
/* set temporary new size */
|
||||
int bwinx = ar->winx;
|
||||
int bwiny = ar->winy;
|
||||
rcti brect = ar->winrct;
|
||||
|
||||
ar->winx = winx;
|
||||
ar->winy = winy;
|
||||
ar->winrct.xmin = 0;
|
||||
ar->winrct.ymin = 0;
|
||||
ar->winrct.xmax = winx;
|
||||
ar->winrct.ymax = winy;
|
||||
|
||||
struct bThemeState theme_state;
|
||||
UI_Theme_Store(&theme_state);
|
||||
UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
|
||||
|
||||
/* set flags */
|
||||
G.f |= G_RENDER_OGL;
|
||||
|
||||
if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
|
||||
/* free images which can have changed on frame-change
|
||||
* warning! can be slow so only free animated images - campbell */
|
||||
GPU_free_images_anim();
|
||||
}
|
||||
|
||||
gpuPushProjectionMatrix();
|
||||
gpuLoadIdentity();
|
||||
gpuPushMatrix();
|
||||
gpuLoadIdentity();
|
||||
|
||||
/* clear opengl buffers */
|
||||
if (do_sky) {
|
||||
view3d_main_region_clear(scene, v3d, ar);
|
||||
}
|
||||
else {
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
|
||||
view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
|
||||
else
|
||||
VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
|
||||
|
||||
/* framebuffer fx needed, we need to draw offscreen first */
|
||||
if (v3d->fx_settings.fx_flag && fx) {
|
||||
GPUSSAOSettings *ssao = NULL;
|
||||
|
||||
if (v3d->drawtype < OB_SOLID) {
|
||||
ssao = v3d->fx_settings.ssao;
|
||||
v3d->fx_settings.ssao = NULL;
|
||||
}
|
||||
|
||||
do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings);
|
||||
|
||||
if (ssao)
|
||||
v3d->fx_settings.ssao = ssao;
|
||||
}
|
||||
|
||||
/* main drawing call */
|
||||
RenderEngineType *type = RE_engines_find(scene->r.engine);
|
||||
if (IS_VIEWPORT_LEGACY(v3d) && ((type->flag & RE_USE_LEGACY_PIPELINE) != 0)) {
|
||||
VP_deprecated_view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL);
|
||||
}
|
||||
else {
|
||||
/* XXX, should take depsgraph as arg */
|
||||
DRW_draw_render_loop_offscreen(scene->depsgraph, ar, v3d, ofs);
|
||||
}
|
||||
|
||||
/* post process */
|
||||
if (do_compositing) {
|
||||
if (!winmat)
|
||||
is_persp = rv3d->is_persp;
|
||||
GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs);
|
||||
}
|
||||
|
||||
if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
|
||||
/* draw grease-pencil stuff */
|
||||
ED_region_pixelspace(ar);
|
||||
|
||||
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
|
||||
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
|
||||
ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false);
|
||||
}
|
||||
|
||||
/* freeing the images again here could be done after the operator runs, leaving for now */
|
||||
GPU_free_images_anim();
|
||||
}
|
||||
|
||||
/* restore size */
|
||||
ar->winx = bwinx;
|
||||
ar->winy = bwiny;
|
||||
ar->winrct = brect;
|
||||
|
||||
gpuPopProjectionMatrix();
|
||||
gpuPopMatrix();
|
||||
|
||||
UI_Theme_Restore(&theme_state);
|
||||
|
||||
G.f &= ~G_RENDER_OGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility func for ED_view3d_draw_offscreen
|
||||
*
|
||||
* \param ofs: Optional off-screen buffer, can be NULL.
|
||||
* (avoids re-creating when doing multiple GL renders).
|
||||
*/
|
||||
ImBuf *ED_view3d_draw_offscreen_imbuf(
|
||||
Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, int sizex, int sizey,
|
||||
unsigned int flag, bool draw_background,
|
||||
int alpha_mode, int samples, bool full_samples, const char *viewname,
|
||||
/* output vars */
|
||||
GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
|
||||
{
|
||||
RegionView3D *rv3d = ar->regiondata;
|
||||
const bool draw_sky = (alpha_mode == R_ADDSKY);
|
||||
|
||||
/* view state */
|
||||
GPUFXSettings fx_settings = v3d->fx_settings;
|
||||
bool is_ortho = false;
|
||||
float winmat[4][4];
|
||||
|
||||
if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) {
|
||||
/* sizes differ, can't reuse */
|
||||
ofs = NULL;
|
||||
}
|
||||
|
||||
const bool own_ofs = (ofs == NULL);
|
||||
|
||||
if (own_ofs) {
|
||||
/* bind */
|
||||
ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out);
|
||||
if (ofs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ED_view3d_draw_offscreen_init(scene, sl, v3d);
|
||||
|
||||
GPU_offscreen_bind(ofs, true);
|
||||
|
||||
/* read in pixels & stamp */
|
||||
ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
|
||||
|
||||
/* render 3d view */
|
||||
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
|
||||
CameraParams params;
|
||||
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
|
||||
|
||||
BKE_camera_params_init(¶ms);
|
||||
/* fallback for non camera objects */
|
||||
params.clipsta = v3d->near;
|
||||
params.clipend = v3d->far;
|
||||
BKE_camera_params_from_object(¶ms, camera);
|
||||
BKE_camera_multiview_params(&scene->r, ¶ms, camera, viewname);
|
||||
BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp);
|
||||
BKE_camera_params_compute_matrix(¶ms);
|
||||
|
||||
BKE_camera_to_gpu_dof(camera, &fx_settings);
|
||||
|
||||
is_ortho = params.is_ortho;
|
||||
copy_m4_m4(winmat, params.winmat);
|
||||
}
|
||||
else {
|
||||
rctf viewplane;
|
||||
float clipsta, clipend;
|
||||
|
||||
is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
|
||||
if (is_ortho) {
|
||||
orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
|
||||
}
|
||||
else {
|
||||
perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
|
||||
}
|
||||
}
|
||||
|
||||
if ((samples && full_samples) == 0) {
|
||||
/* Single-pass render, common case */
|
||||
ED_view3d_draw_offscreen(
|
||||
scene, v3d, ar, sizex, sizey, NULL, winmat,
|
||||
draw_background, draw_sky, !is_ortho, viewname,
|
||||
fx, &fx_settings, ofs);
|
||||
|
||||
if (ibuf->rect_float) {
|
||||
GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
|
||||
}
|
||||
else if (ibuf->rect) {
|
||||
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling.
|
||||
* Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */
|
||||
static float jit_ofs[32][2];
|
||||
float winmat_jitter[4][4];
|
||||
/* use imbuf as temp storage, before writing into it from accumulation buffer */
|
||||
unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float;
|
||||
unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1");
|
||||
|
||||
BLI_jitter_init(jit_ofs, samples);
|
||||
|
||||
/* first sample buffer, also initializes 'rv3d->persmat' */
|
||||
ED_view3d_draw_offscreen(
|
||||
scene, v3d, ar, sizex, sizey, NULL, winmat,
|
||||
draw_background, draw_sky, !is_ortho, viewname,
|
||||
fx, &fx_settings, ofs);
|
||||
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
|
||||
|
||||
unsigned i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
accum_buffer[i] = rect_temp[i];
|
||||
}
|
||||
|
||||
/* skip the first sample */
|
||||
for (int j = 1; j < samples; j++) {
|
||||
copy_m4_m4(winmat_jitter, winmat);
|
||||
window_translate_m4(
|
||||
winmat_jitter, rv3d->persmat,
|
||||
(jit_ofs[j][0] * 2.0f) / sizex,
|
||||
(jit_ofs[j][1] * 2.0f) / sizey);
|
||||
|
||||
ED_view3d_draw_offscreen(
|
||||
scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
|
||||
draw_background, draw_sky, !is_ortho, viewname,
|
||||
fx, &fx_settings, ofs);
|
||||
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
|
||||
|
||||
i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
accum_buffer[i] += rect_temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (ibuf->rect_float) {
|
||||
float *rect_float = ibuf->rect_float;
|
||||
i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned char *rect_ub = (unsigned char *)ibuf->rect;
|
||||
i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
rect_ub[i] = accum_buffer[i] / samples;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(accum_buffer);
|
||||
}
|
||||
|
||||
/* unbind */
|
||||
GPU_offscreen_unbind(ofs, true);
|
||||
|
||||
if (own_ofs) {
|
||||
GPU_offscreen_free(ofs);
|
||||
}
|
||||
|
||||
if (ibuf->rect_float && ibuf->rect)
|
||||
IMB_rect_from_float(ibuf);
|
||||
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
|
||||
*
|
||||
* \param ofs: Optional off-screen buffer can be NULL.
|
||||
* (avoids re-creating when doing multiple GL renders).
|
||||
*
|
||||
* \note used by the sequencer
|
||||
*/
|
||||
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
|
||||
Scene *scene, SceneLayer *sl, Object *camera, int width, int height,
|
||||
unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background,
|
||||
int alpha_mode, int samples, bool full_samples, const char *viewname,
|
||||
GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
|
||||
{
|
||||
View3D v3d = {NULL};
|
||||
ARegion ar = {NULL};
|
||||
RegionView3D rv3d = {{{0}}};
|
||||
|
||||
/* connect data */
|
||||
v3d.regionbase.first = v3d.regionbase.last = &ar;
|
||||
ar.regiondata = &rv3d;
|
||||
ar.regiontype = RGN_TYPE_WINDOW;
|
||||
|
||||
v3d.camera = camera;
|
||||
v3d.lay = scene->lay;
|
||||
v3d.drawtype = drawtype;
|
||||
v3d.flag2 = V3D_RENDER_OVERRIDE;
|
||||
|
||||
if (use_gpencil)
|
||||
v3d.flag2 |= V3D_SHOW_GPENCIL;
|
||||
|
||||
if (use_solid_tex)
|
||||
v3d.flag2 |= V3D_SOLID_TEX;
|
||||
|
||||
if (draw_background)
|
||||
v3d.flag3 |= V3D_SHOW_WORLD;
|
||||
|
||||
rv3d.persp = RV3D_CAMOB;
|
||||
|
||||
copy_m4_m4(rv3d.viewinv, v3d.camera->obmat);
|
||||
normalize_m4(rv3d.viewinv);
|
||||
invert_m4_m4(rv3d.viewmat, rv3d.viewinv);
|
||||
|
||||
{
|
||||
CameraParams params;
|
||||
Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
|
||||
|
||||
BKE_camera_params_init(¶ms);
|
||||
BKE_camera_params_from_object(¶ms, view_camera);
|
||||
BKE_camera_multiview_params(&scene->r, ¶ms, view_camera, viewname);
|
||||
BKE_camera_params_compute_viewplane(¶ms, width, height, scene->r.xasp, scene->r.yasp);
|
||||
BKE_camera_params_compute_matrix(¶ms);
|
||||
|
||||
copy_m4_m4(rv3d.winmat, params.winmat);
|
||||
v3d.near = params.clipsta;
|
||||
v3d.far = params.clipend;
|
||||
v3d.lens = params.lens;
|
||||
}
|
||||
|
||||
mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
|
||||
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
|
||||
|
||||
return ED_view3d_draw_offscreen_imbuf(
|
||||
scene, sl, &v3d, &ar, width, height, flag,
|
||||
draw_background, alpha_mode, samples, full_samples, viewname,
|
||||
fx, ofs, err_out);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Legacy Interface
|
||||
*
|
||||
* This will be removed once the viewport gets replaced
|
||||
* meanwhile it should keep the old viewport working.
|
||||
*/
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void VP_legacy_drawcursor(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d)
|
||||
{
|
||||
@@ -2526,3 +2938,10 @@ void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv
|
||||
{
|
||||
view3d_draw_background_world(scene, v3d, rv3d);
|
||||
}
|
||||
|
||||
void VP_view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
|
||||
{
|
||||
view3d_main_region_clear(scene, v3d, ar);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -113,10 +113,6 @@
|
||||
|
||||
#include "view3d_intern.h" /* own include */
|
||||
|
||||
/* prototypes */
|
||||
static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
|
||||
float winmat[4][4], const char *viewname);
|
||||
|
||||
/* ********* custom clipping *********** */
|
||||
|
||||
static void view3d_draw_clipping(RegionView3D *rv3d)
|
||||
@@ -1720,375 +1716,6 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto
|
||||
rv3d->pixsize = rv3dmat->pixsize;
|
||||
}
|
||||
|
||||
void ED_view3d_draw_offscreen_init(Scene *scene, SceneLayer *sl, View3D *v3d)
|
||||
{
|
||||
/* shadow buffers, before we setup matrices */
|
||||
if (draw_glsl_material(scene, sl, NULL, v3d, v3d->drawtype))
|
||||
gpu_update_lamps_shadows_world(scene, v3d);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to clear the view
|
||||
*/
|
||||
static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
|
||||
{
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
|
||||
VP_view3d_draw_background_world(scene, v3d, ar->regiondata);
|
||||
}
|
||||
else {
|
||||
VP_view3d_draw_background_none();
|
||||
}
|
||||
}
|
||||
|
||||
/* ED_view3d_draw_offscreen_init should be called before this to initialize
|
||||
* stuff like shadow buffers
|
||||
*/
|
||||
void ED_view3d_draw_offscreen(
|
||||
Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
|
||||
float viewmat[4][4], float winmat[4][4],
|
||||
bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
|
||||
GPUFX *fx, GPUFXSettings *fx_settings,
|
||||
GPUOffScreen *ofs)
|
||||
{
|
||||
bool do_compositing = false;
|
||||
RegionView3D *rv3d = ar->regiondata;
|
||||
|
||||
/* set temporary new size */
|
||||
int bwinx = ar->winx;
|
||||
int bwiny = ar->winy;
|
||||
rcti brect = ar->winrct;
|
||||
|
||||
ar->winx = winx;
|
||||
ar->winy = winy;
|
||||
ar->winrct.xmin = 0;
|
||||
ar->winrct.ymin = 0;
|
||||
ar->winrct.xmax = winx;
|
||||
ar->winrct.ymax = winy;
|
||||
|
||||
struct bThemeState theme_state;
|
||||
UI_Theme_Store(&theme_state);
|
||||
UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
|
||||
|
||||
/* set flags */
|
||||
G.f |= G_RENDER_OGL;
|
||||
|
||||
if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
|
||||
/* free images which can have changed on frame-change
|
||||
* warning! can be slow so only free animated images - campbell */
|
||||
GPU_free_images_anim();
|
||||
}
|
||||
|
||||
gpuPushProjectionMatrix();
|
||||
gpuLoadIdentity();
|
||||
gpuPushMatrix();
|
||||
gpuLoadIdentity();
|
||||
|
||||
/* clear opengl buffers */
|
||||
if (do_sky) {
|
||||
view3d_main_region_clear(scene, v3d, ar);
|
||||
}
|
||||
else {
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
|
||||
view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
|
||||
else
|
||||
VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
|
||||
|
||||
/* framebuffer fx needed, we need to draw offscreen first */
|
||||
if (v3d->fx_settings.fx_flag && fx) {
|
||||
GPUSSAOSettings *ssao = NULL;
|
||||
|
||||
if (v3d->drawtype < OB_SOLID) {
|
||||
ssao = v3d->fx_settings.ssao;
|
||||
v3d->fx_settings.ssao = NULL;
|
||||
}
|
||||
|
||||
do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings);
|
||||
|
||||
if (ssao)
|
||||
v3d->fx_settings.ssao = ssao;
|
||||
}
|
||||
|
||||
/* main drawing call */
|
||||
RenderEngineType *type = RE_engines_find(scene->r.engine);
|
||||
if (IS_VIEWPORT_LEGACY(v3d) && ((type->flag & RE_USE_LEGACY_PIPELINE) != 0)) {
|
||||
view3d_draw_objects(NULL, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL);
|
||||
}
|
||||
else {
|
||||
/* XXX, should take depsgraph as arg */
|
||||
DRW_draw_render_loop_offscreen(scene->depsgraph, ar, v3d, ofs);
|
||||
}
|
||||
|
||||
/* post process */
|
||||
if (do_compositing) {
|
||||
if (!winmat)
|
||||
is_persp = rv3d->is_persp;
|
||||
GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs);
|
||||
}
|
||||
|
||||
if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
|
||||
/* draw grease-pencil stuff */
|
||||
ED_region_pixelspace(ar);
|
||||
|
||||
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
|
||||
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
|
||||
ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false);
|
||||
}
|
||||
|
||||
/* freeing the images again here could be done after the operator runs, leaving for now */
|
||||
GPU_free_images_anim();
|
||||
}
|
||||
|
||||
/* restore size */
|
||||
ar->winx = bwinx;
|
||||
ar->winy = bwiny;
|
||||
ar->winrct = brect;
|
||||
|
||||
gpuPopProjectionMatrix();
|
||||
gpuPopMatrix();
|
||||
|
||||
UI_Theme_Restore(&theme_state);
|
||||
|
||||
G.f &= ~G_RENDER_OGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility func for ED_view3d_draw_offscreen
|
||||
*
|
||||
* \param ofs: Optional off-screen buffer, can be NULL.
|
||||
* (avoids re-creating when doing multiple GL renders).
|
||||
*/
|
||||
ImBuf *ED_view3d_draw_offscreen_imbuf(
|
||||
Scene *scene, SceneLayer *sl, View3D *v3d, ARegion *ar, int sizex, int sizey,
|
||||
unsigned int flag, bool draw_background,
|
||||
int alpha_mode, int samples, bool full_samples, const char *viewname,
|
||||
/* output vars */
|
||||
GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
|
||||
{
|
||||
RegionView3D *rv3d = ar->regiondata;
|
||||
const bool draw_sky = (alpha_mode == R_ADDSKY);
|
||||
|
||||
/* view state */
|
||||
GPUFXSettings fx_settings = v3d->fx_settings;
|
||||
bool is_ortho = false;
|
||||
float winmat[4][4];
|
||||
|
||||
if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) {
|
||||
/* sizes differ, can't reuse */
|
||||
ofs = NULL;
|
||||
}
|
||||
|
||||
const bool own_ofs = (ofs == NULL);
|
||||
|
||||
if (own_ofs) {
|
||||
/* bind */
|
||||
ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out);
|
||||
if (ofs == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ED_view3d_draw_offscreen_init(scene, sl, v3d);
|
||||
|
||||
GPU_offscreen_bind(ofs, true);
|
||||
|
||||
/* read in pixels & stamp */
|
||||
ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
|
||||
|
||||
/* render 3d view */
|
||||
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
|
||||
CameraParams params;
|
||||
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
|
||||
|
||||
BKE_camera_params_init(¶ms);
|
||||
/* fallback for non camera objects */
|
||||
params.clipsta = v3d->near;
|
||||
params.clipend = v3d->far;
|
||||
BKE_camera_params_from_object(¶ms, camera);
|
||||
BKE_camera_multiview_params(&scene->r, ¶ms, camera, viewname);
|
||||
BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp);
|
||||
BKE_camera_params_compute_matrix(¶ms);
|
||||
|
||||
BKE_camera_to_gpu_dof(camera, &fx_settings);
|
||||
|
||||
is_ortho = params.is_ortho;
|
||||
copy_m4_m4(winmat, params.winmat);
|
||||
}
|
||||
else {
|
||||
rctf viewplane;
|
||||
float clipsta, clipend;
|
||||
|
||||
is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
|
||||
if (is_ortho) {
|
||||
orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
|
||||
}
|
||||
else {
|
||||
perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
|
||||
}
|
||||
}
|
||||
|
||||
if ((samples && full_samples) == 0) {
|
||||
/* Single-pass render, common case */
|
||||
ED_view3d_draw_offscreen(
|
||||
scene, v3d, ar, sizex, sizey, NULL, winmat,
|
||||
draw_background, draw_sky, !is_ortho, viewname,
|
||||
fx, &fx_settings, ofs);
|
||||
|
||||
if (ibuf->rect_float) {
|
||||
GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
|
||||
}
|
||||
else if (ibuf->rect) {
|
||||
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling.
|
||||
* Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */
|
||||
static float jit_ofs[32][2];
|
||||
float winmat_jitter[4][4];
|
||||
/* use imbuf as temp storage, before writing into it from accumulation buffer */
|
||||
unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float;
|
||||
unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1");
|
||||
|
||||
BLI_jitter_init(jit_ofs, samples);
|
||||
|
||||
/* first sample buffer, also initializes 'rv3d->persmat' */
|
||||
ED_view3d_draw_offscreen(
|
||||
scene, v3d, ar, sizex, sizey, NULL, winmat,
|
||||
draw_background, draw_sky, !is_ortho, viewname,
|
||||
fx, &fx_settings, ofs);
|
||||
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
|
||||
|
||||
unsigned i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
accum_buffer[i] = rect_temp[i];
|
||||
}
|
||||
|
||||
/* skip the first sample */
|
||||
for (int j = 1; j < samples; j++) {
|
||||
copy_m4_m4(winmat_jitter, winmat);
|
||||
window_translate_m4(
|
||||
winmat_jitter, rv3d->persmat,
|
||||
(jit_ofs[j][0] * 2.0f) / sizex,
|
||||
(jit_ofs[j][1] * 2.0f) / sizey);
|
||||
|
||||
ED_view3d_draw_offscreen(
|
||||
scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
|
||||
draw_background, draw_sky, !is_ortho, viewname,
|
||||
fx, &fx_settings, ofs);
|
||||
GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
|
||||
|
||||
i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
accum_buffer[i] += rect_temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (ibuf->rect_float) {
|
||||
float *rect_float = ibuf->rect_float;
|
||||
i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned char *rect_ub = (unsigned char *)ibuf->rect;
|
||||
i = sizex * sizey * 4;
|
||||
while (i--) {
|
||||
rect_ub[i] = accum_buffer[i] / samples;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(accum_buffer);
|
||||
}
|
||||
|
||||
/* unbind */
|
||||
GPU_offscreen_unbind(ofs, true);
|
||||
|
||||
if (own_ofs) {
|
||||
GPU_offscreen_free(ofs);
|
||||
}
|
||||
|
||||
if (ibuf->rect_float && ibuf->rect)
|
||||
IMB_rect_from_float(ibuf);
|
||||
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
|
||||
*
|
||||
* \param ofs: Optional off-screen buffer can be NULL.
|
||||
* (avoids re-creating when doing multiple GL renders).
|
||||
*
|
||||
* \note used by the sequencer
|
||||
*/
|
||||
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
|
||||
Scene *scene, SceneLayer *sl, Object *camera, int width, int height,
|
||||
unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background,
|
||||
int alpha_mode, int samples, bool full_samples, const char *viewname,
|
||||
GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
|
||||
{
|
||||
View3D v3d = {NULL};
|
||||
ARegion ar = {NULL};
|
||||
RegionView3D rv3d = {{{0}}};
|
||||
|
||||
/* connect data */
|
||||
v3d.regionbase.first = v3d.regionbase.last = &ar;
|
||||
ar.regiondata = &rv3d;
|
||||
ar.regiontype = RGN_TYPE_WINDOW;
|
||||
|
||||
v3d.camera = camera;
|
||||
v3d.lay = scene->lay;
|
||||
v3d.drawtype = drawtype;
|
||||
v3d.flag2 = V3D_RENDER_OVERRIDE;
|
||||
|
||||
if (use_gpencil)
|
||||
v3d.flag2 |= V3D_SHOW_GPENCIL;
|
||||
|
||||
if (use_solid_tex)
|
||||
v3d.flag2 |= V3D_SOLID_TEX;
|
||||
|
||||
if (draw_background)
|
||||
v3d.flag3 |= V3D_SHOW_WORLD;
|
||||
|
||||
rv3d.persp = RV3D_CAMOB;
|
||||
|
||||
copy_m4_m4(rv3d.viewinv, v3d.camera->obmat);
|
||||
normalize_m4(rv3d.viewinv);
|
||||
invert_m4_m4(rv3d.viewmat, rv3d.viewinv);
|
||||
|
||||
{
|
||||
CameraParams params;
|
||||
Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
|
||||
|
||||
BKE_camera_params_init(¶ms);
|
||||
BKE_camera_params_from_object(¶ms, view_camera);
|
||||
BKE_camera_multiview_params(&scene->r, ¶ms, view_camera, viewname);
|
||||
BKE_camera_params_compute_viewplane(¶ms, width, height, scene->r.xasp, scene->r.yasp);
|
||||
BKE_camera_params_compute_matrix(¶ms);
|
||||
|
||||
copy_m4_m4(rv3d.winmat, params.winmat);
|
||||
v3d.near = params.clipsta;
|
||||
v3d.far = params.clipend;
|
||||
v3d.lens = params.lens;
|
||||
}
|
||||
|
||||
mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
|
||||
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
|
||||
|
||||
return ED_view3d_draw_offscreen_imbuf(
|
||||
scene, sl, &v3d, &ar, width, height, flag,
|
||||
draw_background, alpha_mode, samples, full_samples, viewname,
|
||||
fx, ofs, err_out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \note The info that this uses is updated in #ED_refresh_viewport_fps,
|
||||
* which currently gets called during #SCREEN_OT_animation_step.
|
||||
@@ -2294,26 +1921,6 @@ static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d,
|
||||
ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true);
|
||||
}
|
||||
|
||||
static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
|
||||
float winmat[4][4], const char *viewname)
|
||||
{
|
||||
/* update the viewport matrices with the new camera */
|
||||
if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
|
||||
float viewmat[4][4];
|
||||
const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
|
||||
|
||||
BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
|
||||
VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
|
||||
}
|
||||
else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
|
||||
float viewmat[4][4];
|
||||
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
|
||||
|
||||
BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
|
||||
VP_legacy_view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_GAMEENGINE
|
||||
static void update_lods(Scene *scene, float camera_pos[3])
|
||||
{
|
||||
@@ -2500,7 +2107,7 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar)
|
||||
|
||||
/* draw viewport using opengl */
|
||||
if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) {
|
||||
view3d_main_region_clear(scene, v3d, ar); /* background */
|
||||
VP_view3d_main_region_clear(scene, v3d, ar); /* background */
|
||||
view3d_main_region_draw_objects(C, scene, sl, v3d, ar, &grid_unit);
|
||||
|
||||
if (G.debug & G_DEBUG_SIMDATA)
|
||||
@@ -2532,3 +2139,30 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar)
|
||||
BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray));
|
||||
BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp));
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Deprecated Interface
|
||||
*
|
||||
* New viewport sometimes has a check for new/old viewport code.
|
||||
* Use these functions so new viewport can *optionally* call.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
|
||||
void VP_deprecated_view3d_draw_objects(
|
||||
const bContext *C,
|
||||
Scene *scene, View3D *v3d, ARegion *ar,
|
||||
const char **grid_unit,
|
||||
const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
|
||||
{
|
||||
view3d_draw_objects(C, scene, v3d, ar, grid_unit, do_bgpic, draw_offscreen, fx);
|
||||
}
|
||||
|
||||
void VP_deprecated_gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
|
||||
{
|
||||
gpu_update_lamps_shadows_world(scene, v3d);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -361,5 +361,14 @@ void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d);
|
||||
void VP_drawrenderborder(ARegion *ar, View3D *v3d);
|
||||
void VP_view3d_draw_background_none(void);
|
||||
void VP_view3d_draw_background_world(Scene *scene, View3D *v3d, RegionView3D *rv3d);
|
||||
void VP_view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar);
|
||||
|
||||
/* temporary legacy calls, only when there is a switch between new/old draw calls */
|
||||
void VP_deprecated_gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d);
|
||||
void VP_deprecated_view3d_draw_objects(
|
||||
const struct bContext *C,
|
||||
Scene *scene, View3D *v3d, ARegion *ar,
|
||||
const char **grid_unit,
|
||||
const bool do_bgpic, const bool draw_offscreen, struct GPUFX *fx);
|
||||
|
||||
#endif /* __VIEW3D_INTERN_H__ */
|
||||
|
||||
Reference in New Issue
Block a user