2020-08-31 18:50:41 +02:00
|
|
|
/*
|
|
|
|
gl_deferred.cpp - deferred rendering
|
|
|
|
Copyright (C) 2018 Uncle Mike
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "hud.h"
|
|
|
|
#include "cl_util.h"
|
|
|
|
#include "gl_local.h"
|
|
|
|
#include "gl_shader.h"
|
|
|
|
#include "gl_world.h"
|
|
|
|
#include "gl_grass.h"
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
SCENE_PASS = 0,
|
|
|
|
LIGHT_PASS,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
BILATERAL_PASS0 = 0,
|
|
|
|
BILATERAL_PASS1,
|
|
|
|
};
|
|
|
|
|
|
|
|
void GL_InitDefSceneFBO( void )
|
|
|
|
{
|
|
|
|
GLenum MRTBuffers[5] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_COLOR_ATTACHMENT4_EXT };
|
|
|
|
int albedo_buffer;
|
|
|
|
int normal_buffer;
|
|
|
|
int smooth_buffer;
|
|
|
|
int light0_buffer;
|
|
|
|
int light1_buffer;
|
|
|
|
int depth_buffer;
|
|
|
|
|
|
|
|
if( !GL_Support( R_FRAMEBUFFER_OBJECT ) || !GL_Support( R_DRAW_BUFFERS_EXT ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create and set up the framebuffer
|
|
|
|
tr.defscene_fbo = GL_AllocDrawbuffer( "*defscene", glState.width, glState.height, 1 );
|
|
|
|
|
|
|
|
// create textures
|
|
|
|
albedo_buffer = CREATE_TEXTURE( "*albedo_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
|
|
|
|
normal_buffer = CREATE_TEXTURE( "*normal_rt", glState.width, glState.height, NULL, TF_RT_NORMAL|TF_HAS_ALPHA );
|
|
|
|
smooth_buffer = CREATE_TEXTURE( "*smooth_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
|
|
|
|
light0_buffer = CREATE_TEXTURE( "*light0_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
|
|
|
|
light1_buffer = CREATE_TEXTURE( "*light1_rt", glState.width, glState.height, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
|
|
|
|
depth_buffer = CREATE_TEXTURE( "*depth_rt", glState.width, glState.height, NULL, TF_RT_DEPTH );
|
|
|
|
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, albedo_buffer, 0 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, normal_buffer, 1 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, smooth_buffer, 2 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, light0_buffer, 3 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, light1_buffer, 4 );
|
|
|
|
GL_AttachDepthTextureToFBO( tr.defscene_fbo, depth_buffer );
|
|
|
|
|
|
|
|
pglDrawBuffersARB( ARRAYSIZE( MRTBuffers ), MRTBuffers );
|
|
|
|
pglReadBuffer( GL_NONE );
|
|
|
|
|
|
|
|
// check the framebuffer status
|
|
|
|
GL_CheckFBOStatus( tr.defscene_fbo );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_VidInitDefSceneFBO( void )
|
|
|
|
{
|
|
|
|
// resize attached textures
|
|
|
|
GL_ResizeDrawbuffer( tr.defscene_fbo, glState.width, glState.height, 1 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[0], 0 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[1], 1 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[2], 2 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[3], 3 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->colortarget[4], 4 );
|
|
|
|
GL_AttachDepthTextureToFBO( tr.defscene_fbo, tr.defscene_fbo->depthtarget );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_InitDefLightFBO( void )
|
|
|
|
{
|
|
|
|
GLenum MRTBuffers[3] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT };
|
|
|
|
int normal_buffer;
|
|
|
|
int light0_buffer;
|
|
|
|
int light1_buffer;
|
|
|
|
int depth_buffer;
|
|
|
|
|
|
|
|
if( !GL_Support( R_FRAMEBUFFER_OBJECT ) || !GL_Support( R_DRAW_BUFFERS_EXT ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create and set up the framebuffer
|
|
|
|
tr.deflight_fbo = GL_AllocDrawbuffer( "*deflight", glState.defWidth, glState.defHeight, 1 );
|
|
|
|
|
|
|
|
// create textures
|
|
|
|
normal_buffer = CREATE_TEXTURE( "*normal_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_NORMAL|TF_HAS_ALPHA );
|
|
|
|
light0_buffer = CREATE_TEXTURE( "*light0_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
|
|
|
|
light1_buffer = CREATE_TEXTURE( "*light1_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_COLOR|TF_HAS_ALPHA );
|
|
|
|
depth_buffer = CREATE_TEXTURE( "*depth_rs", glState.defWidth, glState.defHeight, NULL, TF_RT_DEPTH );
|
|
|
|
|
|
|
|
GL_AttachColorTextureToFBO( tr.deflight_fbo, normal_buffer, 0 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.deflight_fbo, light0_buffer, 1 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.deflight_fbo, light1_buffer, 2 );
|
|
|
|
GL_AttachDepthTextureToFBO( tr.deflight_fbo, depth_buffer );
|
|
|
|
|
|
|
|
pglDrawBuffersARB( ARRAYSIZE( MRTBuffers ), MRTBuffers );
|
|
|
|
pglReadBuffer( GL_NONE );
|
|
|
|
|
|
|
|
// check the framebuffer status
|
|
|
|
GL_CheckFBOStatus( tr.deflight_fbo );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_VidInitDefLightFBO( void )
|
|
|
|
{
|
|
|
|
// resize attached textures
|
|
|
|
GL_ResizeDrawbuffer( tr.deflight_fbo, glState.defWidth, glState.defHeight, 1 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->colortarget[0], 0 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->colortarget[1], 1 );
|
|
|
|
GL_AttachColorTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->colortarget[2], 2 );
|
|
|
|
GL_AttachDepthTextureToFBO( tr.deflight_fbo, tr.deflight_fbo->depthtarget );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_VidInitDrawBuffers( void )
|
|
|
|
{
|
|
|
|
if( tr.defscene_fbo == NULL )
|
|
|
|
GL_InitDefSceneFBO();
|
|
|
|
else GL_VidInitDefSceneFBO();
|
|
|
|
|
|
|
|
if( tr.deflight_fbo == NULL )
|
|
|
|
GL_InitDefLightFBO();
|
|
|
|
else GL_VidInitDefLightFBO();
|
|
|
|
|
|
|
|
// unbind the framebuffer
|
|
|
|
GL_BindDrawbuffer( NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_SetupGBuffer( void )
|
|
|
|
{
|
|
|
|
// bind geometry fullscreen buffer
|
|
|
|
if( FBitSet( RI->params, RP_DEFERREDSCENE ))
|
|
|
|
GL_BindDrawbuffer( tr.defscene_fbo );
|
|
|
|
|
|
|
|
// bind light-pass downscaled buffer
|
|
|
|
if( FBitSet( RI->params, RP_DEFERREDLIGHT ))
|
|
|
|
GL_BindDrawbuffer( tr.deflight_fbo );
|
|
|
|
|
|
|
|
R_Clear( ~0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_ResetGBuffer( void )
|
|
|
|
{
|
|
|
|
GL_BindDrawbuffer( NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_DrawScreenSpaceQuad( const vec3_t normals[4] )
|
|
|
|
{
|
|
|
|
pglBegin( GL_QUADS );
|
|
|
|
pglTexCoord2f( 0.0f, 1.0f );
|
|
|
|
pglNormal3fv( normals[0] );
|
|
|
|
pglVertex2f( 0.0f, 0.0f );
|
|
|
|
pglTexCoord2f( 1.0f, 1.0f );
|
|
|
|
pglNormal3fv( normals[3] );
|
|
|
|
pglVertex2f( RI->view.port[2], 0.0f );
|
|
|
|
pglTexCoord2f( 1.0f, 0.0f );
|
|
|
|
pglNormal3fv( normals[2] );
|
|
|
|
pglVertex2f( RI->view.port[2], RI->view.port[3] );
|
|
|
|
pglTexCoord2f( 0.0f, 0.0f );
|
|
|
|
pglNormal3fv( normals[1] );
|
|
|
|
pglVertex2f( 0.0f, RI->view.port[3] );
|
|
|
|
pglEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
GL_Setup2D
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void GL_SetupDeferred( void )
|
|
|
|
{
|
|
|
|
// set up full screen workspace
|
|
|
|
pglMatrixMode( GL_PROJECTION );
|
|
|
|
pglLoadIdentity();
|
|
|
|
|
|
|
|
pglOrtho( 0, RI->view.port[2], RI->view.port[3], 0, -99999, 99999 );
|
|
|
|
|
|
|
|
pglMatrixMode( GL_MODELVIEW );
|
|
|
|
pglLoadIdentity();
|
|
|
|
|
|
|
|
GL_AlphaTest( GL_FALSE );
|
|
|
|
GL_DepthMask( GL_FALSE );
|
|
|
|
pglDisable( GL_DEPTH_TEST ); // older dirvers has issues with this
|
|
|
|
|
|
|
|
if( RI->currentlight != NULL )
|
|
|
|
{
|
|
|
|
GL_Blend( GL_TRUE );
|
|
|
|
pglBlendFunc( GL_ONE, GL_ONE );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GL_Blend( GL_FALSE );
|
|
|
|
}
|
|
|
|
|
|
|
|
GL_Cull( GL_FRONT );
|
|
|
|
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
pglViewport( 0, 0, RI->view.port[2], RI->view.port[3] );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GL_DrawDeferred( word hProgram, int pass )
|
|
|
|
{
|
|
|
|
if( hProgram <= 0 )
|
|
|
|
{
|
|
|
|
GL_BindShader( NULL );
|
|
|
|
return; // bad shader?
|
|
|
|
}
|
|
|
|
|
|
|
|
// prepare deferred pass
|
|
|
|
GL_SetupDeferred();
|
|
|
|
|
|
|
|
if( RI->currentshader != &glsl_programs[hProgram] )
|
|
|
|
{
|
|
|
|
// force to bind new shader
|
|
|
|
GL_BindShader( &glsl_programs[hProgram] );
|
|
|
|
}
|
|
|
|
|
|
|
|
glsl_program_t *shader = RI->currentshader;
|
|
|
|
CDynLight *pl = RI->currentlight; // may be NULL
|
|
|
|
Vector4D lightdir;
|
|
|
|
float *v;
|
|
|
|
|
|
|
|
// setup specified uniforms (and texture bindings)
|
|
|
|
for( int i = 0; i < shader->numUniforms; i++ )
|
|
|
|
{
|
|
|
|
uniform_t *u = &shader->uniforms[i];
|
|
|
|
|
|
|
|
switch( u->type )
|
|
|
|
{
|
|
|
|
case UT_COLORMAP:
|
|
|
|
u->SetValue( tr.defscene_fbo->colortarget[0] );
|
|
|
|
break;
|
|
|
|
case UT_NORMALMAP:
|
|
|
|
if( pass == LIGHT_PASS )
|
|
|
|
u->SetValue( tr.deflight_fbo->colortarget[0] );
|
|
|
|
else u->SetValue( tr.defscene_fbo->colortarget[1] );
|
|
|
|
break;
|
|
|
|
case UT_GLOSSMAP:
|
|
|
|
u->SetValue( tr.defscene_fbo->colortarget[2] );
|
|
|
|
break;
|
|
|
|
case UT_VISLIGHTMAP0:
|
|
|
|
if( pass == LIGHT_PASS )
|
|
|
|
u->SetValue( tr.deflight_fbo->colortarget[1] );
|
|
|
|
else u->SetValue( tr.defscene_fbo->colortarget[3] );
|
|
|
|
break;
|
|
|
|
case UT_VISLIGHTMAP1:
|
|
|
|
if( pass == LIGHT_PASS )
|
|
|
|
u->SetValue( tr.deflight_fbo->colortarget[2] );
|
|
|
|
else u->SetValue( tr.defscene_fbo->colortarget[4] );
|
|
|
|
break;
|
|
|
|
case UT_DEPTHMAP:
|
|
|
|
if( pass == LIGHT_PASS )
|
|
|
|
u->SetValue( tr.deflight_fbo->depthtarget );
|
|
|
|
else u->SetValue( tr.defscene_fbo->depthtarget );
|
|
|
|
break;
|
|
|
|
case UT_BSPPLANESMAP:
|
|
|
|
u->SetValue( tr.packed_planes_texture );
|
|
|
|
break;
|
|
|
|
case UT_BSPNODESMAP:
|
|
|
|
u->SetValue( tr.packed_nodes_texture );
|
|
|
|
break;
|
|
|
|
case UT_BSPLIGHTSMAP:
|
|
|
|
u->SetValue( tr.packed_lights_texture );
|
|
|
|
break;
|
|
|
|
case UT_BSPMODELSMAP:
|
|
|
|
u->SetValue( tr.packed_models_texture );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWMAP:
|
|
|
|
if( pl ) u->SetValue( pl->shadowTexture[0] );
|
|
|
|
else u->SetValue( tr.fbo_light.GetTexture() );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWMAP0:
|
|
|
|
if( pl ) u->SetValue( pl->shadowTexture[0] );
|
|
|
|
else u->SetValue( tr.depthTexture );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWMAP1:
|
|
|
|
if( pl ) u->SetValue( pl->shadowTexture[1] );
|
|
|
|
else u->SetValue( tr.depthTexture );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWMAP2:
|
|
|
|
if( pl ) u->SetValue( pl->shadowTexture[2] );
|
|
|
|
else u->SetValue( tr.depthTexture );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWMAP3:
|
|
|
|
if( pl ) u->SetValue( pl->shadowTexture[3] );
|
|
|
|
else u->SetValue( tr.depthTexture );
|
|
|
|
break;
|
|
|
|
case UT_PROJECTMAP:
|
|
|
|
if( pl && pl->type == LIGHT_SPOT )
|
|
|
|
u->SetValue( pl->spotlightTexture );
|
|
|
|
else u->SetValue( tr.whiteTexture );
|
|
|
|
break;
|
|
|
|
case UT_VIEWORIGIN:
|
|
|
|
u->SetValue( RI->view.matrix[3][0], RI->view.matrix[3][1], RI->view.matrix[3][2] );
|
|
|
|
break;
|
|
|
|
case UT_LIGHTSTYLEVALUES:
|
|
|
|
u->SetValue( &tr.lightstyle[0], MAX_LIGHTSTYLES );
|
|
|
|
break;
|
|
|
|
case UT_GAMMATABLE:
|
|
|
|
u->SetValue( &tr.gamma_table[0][0], 64 );
|
|
|
|
break;
|
|
|
|
case UT_LIGHTTHRESHOLD:
|
|
|
|
u->SetValue( tr.light_threshold );
|
|
|
|
break;
|
|
|
|
case UT_LIGHTSCALE:
|
|
|
|
u->SetValue( tr.direct_scale );
|
|
|
|
break;
|
|
|
|
case UT_LIGHTGAMMA:
|
|
|
|
u->SetValue( tr.light_gamma );
|
|
|
|
break;
|
|
|
|
case UT_ZFAR:
|
|
|
|
u->SetValue( RI->view.farClip );
|
|
|
|
break;
|
|
|
|
case UT_SCREENSIZEINV:
|
|
|
|
u->SetValue( 1.0f / (float)glState.width, 1.0f / (float)glState.height );
|
|
|
|
break;
|
|
|
|
case UT_DIFFUSEFACTOR:
|
|
|
|
u->SetValue( tr.diffuseFactor );
|
|
|
|
break;
|
|
|
|
case UT_AMBIENTFACTOR:
|
|
|
|
if( pl && pl->type == LIGHT_DIRECTIONAL )
|
|
|
|
u->SetValue( tr.sun_ambient );
|
|
|
|
else u->SetValue( tr.ambientFactor );
|
|
|
|
break;
|
|
|
|
case UT_SUNREFRACT:
|
|
|
|
u->SetValue( tr.sun_refract );
|
|
|
|
break;
|
|
|
|
case UT_REALTIME:
|
|
|
|
u->SetValue( (float)tr.time );
|
|
|
|
break;
|
|
|
|
case UT_FOGPARAMS:
|
|
|
|
u->SetValue( tr.fogColor[0], tr.fogColor[1], tr.fogColor[2], tr.fogDensity );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWPARMS:
|
|
|
|
if( pl != NULL )
|
|
|
|
{
|
|
|
|
float shadowWidth = 1.0f / (float)RENDER_GET_PARM( PARM_TEX_WIDTH, pl->shadowTexture[0] );
|
|
|
|
float shadowHeight = 1.0f / (float)RENDER_GET_PARM( PARM_TEX_HEIGHT, pl->shadowTexture[0] );
|
|
|
|
// depth scale and bias and shadowmap resolution
|
|
|
|
u->SetValue( shadowWidth, shadowHeight, -pl->projectionMatrix[2][2], pl->projectionMatrix[3][2] );
|
|
|
|
}
|
|
|
|
else u->SetValue( 0.0f, 0.0f, 0.0f, 0.0f );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWMATRIX:
|
|
|
|
if( pl ) u->SetValue( &pl->gl_shadowMatrix[0][0], MAX_SHADOWMAPS );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWSPLITDIST:
|
|
|
|
v = RI->view.parallelSplitDistances;
|
|
|
|
u->SetValue( v[0], v[1], v[2], v[3] );
|
|
|
|
break;
|
|
|
|
case UT_TEXELSIZE:
|
|
|
|
u->SetValue( 1.0f / (float)sunSize[0], 1.0f / (float)sunSize[1], 1.0f / (float)sunSize[2], 1.0f / (float)sunSize[3] );
|
|
|
|
break;
|
|
|
|
case UT_LIGHTDIR:
|
|
|
|
if( pl )
|
|
|
|
{
|
|
|
|
if( pl->type == LIGHT_DIRECTIONAL ) lightdir = -tr.sky_normal;
|
|
|
|
else lightdir = pl->frustum.GetPlane( FRUSTUM_FAR )->normal;
|
|
|
|
u->SetValue( lightdir.x, lightdir.y, lightdir.z, pl->fov );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UT_LIGHTDIFFUSE:
|
|
|
|
if( pl ) u->SetValue( pl->color.x, pl->color.y, pl->color.z );
|
|
|
|
break;
|
|
|
|
case UT_LIGHTORIGIN:
|
|
|
|
if( pl ) u->SetValue( pl->origin.x, pl->origin.y, pl->origin.z, ( 1.0f / pl->radius ));
|
|
|
|
break;
|
|
|
|
case UT_LIGHTVIEWPROJMATRIX:
|
|
|
|
if( pl )
|
|
|
|
{
|
|
|
|
GLfloat gl_lightViewProjMatrix[16];
|
|
|
|
pl->lightviewProjMatrix.CopyToArray( gl_lightViewProjMatrix );
|
|
|
|
u->SetValue( &gl_lightViewProjMatrix[0] );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UT_NUMVISIBLEMODELS:
|
|
|
|
u->SetValue( world->num_visible_models );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ALERT( at_error, "%s: unhandled uniform %s\n", RI->currentshader->name, u->name );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GL_DrawScreenSpaceQuad( tr.screen_normals );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GL_DrawBilateralFilter( word hProgram, int pass )
|
|
|
|
{
|
|
|
|
if( hProgram <= 0 )
|
|
|
|
{
|
|
|
|
GL_BindShader( NULL );
|
|
|
|
return; // bad shader?
|
|
|
|
}
|
|
|
|
|
|
|
|
if( RI->currentshader != &glsl_programs[hProgram] )
|
|
|
|
{
|
|
|
|
// force to bind new shader
|
|
|
|
GL_BindShader( &glsl_programs[hProgram] );
|
|
|
|
}
|
|
|
|
|
|
|
|
glsl_program_t *shader = RI->currentshader;
|
|
|
|
|
|
|
|
// setup specified uniforms (and texture bindings)
|
|
|
|
for( int i = 0; i < shader->numUniforms; i++ )
|
|
|
|
{
|
|
|
|
uniform_t *u = &shader->uniforms[i];
|
|
|
|
|
|
|
|
switch( u->type )
|
|
|
|
{
|
|
|
|
case UT_COLORMAP:
|
|
|
|
if( pass == BILATERAL_PASS0 )
|
|
|
|
u->SetValue( tr.fbo_light.GetTexture() );
|
2020-09-01 17:07:37 +02:00
|
|
|
else if( pass == BILATERAL_PASS1 )
|
2020-08-31 18:50:41 +02:00
|
|
|
u->SetValue( tr.fbo_filter.GetTexture() );
|
|
|
|
else u->SetValue( tr.defscene_fbo->colortarget[0] );
|
|
|
|
break;
|
|
|
|
case UT_DEPTHMAP:
|
|
|
|
u->SetValue( tr.defscene_fbo->depthtarget );
|
|
|
|
break;
|
|
|
|
case UT_ZFAR:
|
|
|
|
u->SetValue( RI->view.farClip );
|
|
|
|
break;
|
|
|
|
case UT_SCREENSIZEINV:
|
|
|
|
if( pass == BILATERAL_PASS0 )
|
|
|
|
u->SetValue( 1.0f / (float)glState.width, 0.0f );
|
2020-09-01 17:07:37 +02:00
|
|
|
else if( pass == BILATERAL_PASS1 )
|
2020-08-31 18:50:41 +02:00
|
|
|
u->SetValue( 0.0f, 1.0f / (float)glState.height );
|
|
|
|
else u->SetValue( 1.0f / (float)glState.width, 1.0f / (float)glState.height );
|
|
|
|
break;
|
|
|
|
case UT_SHADOWPARMS:
|
|
|
|
u->SetValue( RI->view.projectionMatrix[3][2], RI->view.projectionMatrix[2][2] );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ALERT( at_error, "%s: unhandled uniform %s\n", RI->currentshader->name, u->name );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RenderFSQ( glState.width, glState.height );
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_SetupWorldLightPass( void )
|
|
|
|
{
|
|
|
|
tr.fbo_shadow.Bind(); // <- render to shadow texture
|
|
|
|
|
|
|
|
// FIXME! modelview isn't be changed anyway until current pass!!!
|
|
|
|
// pglMatrixMode( GL_MODELVIEW );
|
|
|
|
// pglLoadMatrixf( RI->glstate.modelviewMatrix );
|
|
|
|
|
|
|
|
GL_DrawDeferred( tr.defLightShader, LIGHT_PASS );
|
|
|
|
GL_CleanupAllTextureUnits();
|
|
|
|
|
|
|
|
GL_Setup2D();
|
|
|
|
tr.fbo_light.Bind(); // <- copy to fbo_light result of works complex light shader
|
|
|
|
GL_BindShader( NULL );
|
|
|
|
GL_BindTexture( GL_TEXTURE0, tr.fbo_shadow.GetTexture() );
|
|
|
|
RenderFSQ( glState.width, glState.height );
|
|
|
|
|
|
|
|
if( tr.bilateralShader )
|
|
|
|
{
|
|
|
|
// apply bilateral filter
|
|
|
|
tr.fbo_filter.Bind(); // <- bilateral pass0, filtering by width, store to fbo_filter
|
|
|
|
GL_DrawBilateralFilter( tr.bilateralShader, BILATERAL_PASS0 );
|
|
|
|
|
|
|
|
tr.fbo_light.Bind(); // <- bilateral pass1, filtering by height, store back to fbo_light
|
|
|
|
GL_DrawBilateralFilter( tr.bilateralShader, BILATERAL_PASS1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_SetupDynamicPass( void )
|
|
|
|
{
|
|
|
|
if( !FBitSet( RI->view.flags, RF_HASDYNLIGHTS ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
pglEnable( GL_SCISSOR_TEST );
|
|
|
|
CDynLight *pl = tr.dlights;
|
|
|
|
|
|
|
|
for( int i = 0; i < MAX_DLIGHTS; i++, pl++ )
|
|
|
|
{
|
|
|
|
// deferred path are ignored sunlights
|
|
|
|
if( pl->Expired( ) || pl->type == LIGHT_DIRECTIONAL )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( !pl->Active( )) continue;
|
|
|
|
|
|
|
|
if( !Mod_CheckBoxVisible( pl->absmin, pl->absmax ))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( R_CullFrustum( &pl->frustum ))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
float y2 = (float)RI->view.port[3] - pl->h - pl->y;
|
|
|
|
pglScissor( pl->x, y2, pl->w, pl->h );
|
|
|
|
RI->currentlight = pl;
|
|
|
|
|
|
|
|
GL_DrawDeferred( tr.defDynLightShader[pl->type], SCENE_PASS );
|
|
|
|
}
|
|
|
|
|
|
|
|
pglDisable( GL_SCISSOR_TEST );
|
|
|
|
RI->currentlight = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_SetupWorldScenePass( void )
|
|
|
|
{
|
|
|
|
mworldlight_t *wl;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// debug
|
|
|
|
for( i = 0, wl = world->worldlights; i < world->numworldlights; i++, wl++ )
|
|
|
|
{
|
|
|
|
if( wl->emittype == emit_ignored )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( !CHECKVISBIT( RI->view.vislight, i ))
|
|
|
|
continue;
|
|
|
|
r_stats.c_worldlights++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int type = CVAR_TO_BOOL( cv_deferred_full ) ? 1 : 0;
|
|
|
|
GL_DrawDeferred( tr.defSceneShader[type], SCENE_PASS );
|
|
|
|
|
|
|
|
// also render a standard dynamic lights
|
|
|
|
GL_SetupDynamicPass();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GL_DrawDeferredPass( void )
|
|
|
|
{
|
|
|
|
if( !tr.defSceneShader || !tr.defLightShader )
|
|
|
|
return; // oops!
|
|
|
|
|
|
|
|
GL_ComputeScreenRays();
|
|
|
|
|
|
|
|
if( FBitSet( RI->params, RP_DEFERREDSCENE ))
|
|
|
|
GL_SetupWorldScenePass();
|
|
|
|
|
|
|
|
if( FBitSet( RI->params, RP_DEFERREDLIGHT ))
|
|
|
|
GL_SetupWorldLightPass();
|
|
|
|
|
|
|
|
GL_CleanupDrawState();
|
|
|
|
GL_BindFBO( FBO_MAIN );
|
|
|
|
GL_Setup3D();
|
2020-09-01 17:07:37 +02:00
|
|
|
}
|