2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2014-05-10 12:40:01 +00:00
Copyright ( C ) 2013 - 2014 Robert Beckebans
2014-04-05 13:41:19 +00:00
Copyright ( C ) 2014 Carl Kenner
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 .
Doom 3 BFG Edition Source Code 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 .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "tr_local.h"
2014-05-10 12:40:01 +00:00
# include "Framebuffer.h"
2012-11-26 18:58:24 +00:00
idCVar r_drawEyeColor ( " r_drawEyeColor " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " Draw a colored box, red = left eye, blue = right eye, grey = non-stereo " ) ;
idCVar r_motionBlur ( " r_motionBlur " , " 0 " , CVAR_RENDERER | CVAR_INTEGER | CVAR_ARCHIVE , " 1 - 5, log2 of the number of motion blur samples " ) ;
idCVar r_forceZPassStencilShadows ( " r_forceZPassStencilShadows " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " force Z-pass rendering for performance testing " ) ;
idCVar r_useStencilShadowPreload ( " r_useStencilShadowPreload " , " 1 " , CVAR_RENDERER | CVAR_BOOL , " use stencil shadow preload algorithm instead of Z-fail " ) ;
idCVar r_skipShaderPasses ( " r_skipShaderPasses " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " " ) ;
idCVar r_skipInteractionFastPath ( " r_skipInteractionFastPath " , " 1 " , CVAR_RENDERER | CVAR_BOOL , " " ) ;
idCVar r_useLightStencilSelect ( " r_useLightStencilSelect " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " use stencil select pass " ) ;
extern idCVar stereoRender_swapEyes ;
backEndState_t backEnd ;
/*
= = = = = = = = = = = = = = = =
SetVertexParm
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static ID_INLINE void SetVertexParm ( renderParm_t rp , const float * value )
{
2012-11-26 18:58:24 +00:00
renderProgManager . SetUniformValue ( rp , value ) ;
}
/*
= = = = = = = = = = = = = = = =
SetVertexParms
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static ID_INLINE void SetVertexParms ( renderParm_t rp , const float * value , int num )
{
for ( int i = 0 ; i < num ; i + + )
{
renderProgManager . SetUniformValue ( ( renderParm_t ) ( rp + i ) , value + ( i * 4 ) ) ;
2012-11-26 18:58:24 +00:00
}
}
/*
= = = = = = = = = = = = = = = =
SetFragmentParm
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static ID_INLINE void SetFragmentParm ( renderParm_t rp , const float * value )
{
2012-11-26 18:58:24 +00:00
renderProgManager . SetUniformValue ( rp , value ) ;
}
/*
= = = = = = = = = = = = = = = =
RB_SetMVP
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_SetMVP ( const idRenderMatrix & mvp )
{
2012-11-26 18:58:24 +00:00
SetVertexParms ( RENDERPARM_MVPMATRIX_X , mvp [ 0 ] , 4 ) ;
}
/*
= = = = = = = = = = = = = = = =
RB_SetMVPWithStereoOffset
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_SetMVPWithStereoOffset ( const idRenderMatrix & mvp , const float stereoOffset )
{
2012-11-26 18:58:24 +00:00
idRenderMatrix offset = mvp ;
offset [ 0 ] [ 3 ] + = stereoOffset ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetVertexParms ( RENDERPARM_MVPMATRIX_X , offset [ 0 ] , 4 ) ;
}
static const float zero [ 4 ] = { 0 , 0 , 0 , 0 } ;
static const float one [ 4 ] = { 1 , 1 , 1 , 1 } ;
static const float negOne [ 4 ] = { - 1 , - 1 , - 1 , - 1 } ;
/*
= = = = = = = = = = = = = = = =
RB_SetVertexColorParms
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_SetVertexColorParms ( stageVertexColor_t svc )
{
switch ( svc )
{
2012-11-26 18:58:24 +00:00
case SVC_IGNORE :
SetVertexParm ( RENDERPARM_VERTEXCOLOR_MODULATE , zero ) ;
SetVertexParm ( RENDERPARM_VERTEXCOLOR_ADD , one ) ;
break ;
case SVC_MODULATE :
SetVertexParm ( RENDERPARM_VERTEXCOLOR_MODULATE , one ) ;
SetVertexParm ( RENDERPARM_VERTEXCOLOR_ADD , zero ) ;
break ;
case SVC_INVERSE_MODULATE :
SetVertexParm ( RENDERPARM_VERTEXCOLOR_MODULATE , negOne ) ;
SetVertexParm ( RENDERPARM_VERTEXCOLOR_ADD , one ) ;
break ;
}
}
/*
= = = = = = = = = = = = = = = =
RB_DrawElementsWithCounters
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_DrawElementsWithCounters ( const drawSurf_t * surf )
{
2012-11-26 18:58:24 +00:00
// get vertex buffer
const vertCacheHandle_t vbHandle = surf - > ambientCache ;
2012-11-28 15:47:07 +00:00
idVertexBuffer * vertexBuffer ;
if ( vertexCache . CacheIsStatic ( vbHandle ) )
{
2012-11-26 18:58:24 +00:00
vertexBuffer = & vertexCache . staticData . vertexBuffer ;
2012-11-28 15:47:07 +00:00
}
else
{
const uint64 frameNum = ( int ) ( vbHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " RB_DrawElementsWithCounters, vertexBuffer == NULL " ) ;
return ;
}
vertexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . vertexBuffer ;
}
2012-11-28 15:47:07 +00:00
const int vertOffset = ( int ) ( vbHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
2012-11-26 18:58:24 +00:00
// get index buffer
const vertCacheHandle_t ibHandle = surf - > indexCache ;
2012-11-28 15:47:07 +00:00
idIndexBuffer * indexBuffer ;
if ( vertexCache . CacheIsStatic ( ibHandle ) )
{
2012-11-26 18:58:24 +00:00
indexBuffer = & vertexCache . staticData . indexBuffer ;
2012-11-28 15:47:07 +00:00
}
else
{
const uint64 frameNum = ( int ) ( ibHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " RB_DrawElementsWithCounters, indexBuffer == NULL " ) ;
return ;
}
indexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . indexBuffer ;
}
2012-12-07 16:06:44 +00:00
// RB: 64 bit fixes, changed int to GLintptrARB
const GLintptrARB indexOffset = ( GLintptrARB ) ( ibHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
// RB end
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " Binding Buffers: %p:%i %p:%i \n " , vertexBuffer , vertOffset , indexBuffer , indexOffset ) ;
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache )
{
2012-12-30 15:24:12 +00:00
// DG: this happens all the time in the erebus1 map with blendlight.vfp,
// so don't call assert (through verify) here until it's fixed (if fixable)
// else the game crashes on linux when using debug builds
2013-04-10 00:40:09 +00:00
2012-12-30 15:24:12 +00:00
// FIXME: fix this properly if possible?
2013-04-10 00:40:09 +00:00
// RB: yes but it would require an additional blend light skinned shader
2012-12-30 15:24:12 +00:00
//if( !verify( renderProgManager.ShaderUsesJoints() ) )
2013-04-10 00:40:09 +00:00
if ( ! renderProgManager . ShaderUsesJoints ( ) )
2012-12-30 15:24:12 +00:00
// DG end
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
}
else
{
if ( ! verify ( ! renderProgManager . ShaderUsesJoints ( ) | | renderProgManager . ShaderHasOptionalSkinning ( ) ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
}
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
idJointBuffer jointBuffer ;
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . GetJointBuffer ( surf - > jointCache , & jointBuffer ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " RB_DrawElementsWithCounters, jointBuffer == NULL " ) ;
return ;
}
assert ( ( jointBuffer . GetOffset ( ) & ( glConfig . uniformBufferOffsetAlignment - 1 ) ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
2012-12-07 16:06:44 +00:00
// RB: 64 bit fixes, changed GLuint to GLintptrARB
const GLintptrARB ubo = reinterpret_cast < GLintptrARB > ( jointBuffer . GetAPIObject ( ) ) ;
// RB end
2012-12-08 17:20:13 +00:00
2012-12-17 16:30:59 +00:00
glBindBufferRange ( GL_UNIFORM_BUFFER , 0 , ubo , jointBuffer . GetOffset ( ) , jointBuffer . GetNumJoints ( ) * sizeof ( idJointMat ) ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . CommitUniforms ( ) ;
2012-11-28 15:47:07 +00:00
2012-12-07 16:06:44 +00:00
// RB: 64 bit fixes, changed GLuint to GLintptrARB
if ( backEnd . glState . currentIndexBuffer ! = ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) | | ! r_useStateCaching . GetBool ( ) )
2012-11-28 15:47:07 +00:00
{
2012-12-17 16:30:59 +00:00
glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) ) ;
2012-12-07 16:06:44 +00:00
backEnd . glState . currentIndexBuffer = ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-12-07 16:06:44 +00:00
if ( ( backEnd . glState . vertexLayout ! = LAYOUT_DRAW_VERT ) | | ( backEnd . glState . currentVertexBuffer ! = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) | | ! r_useStateCaching . GetBool ( ) )
2012-11-28 15:47:07 +00:00
{
2012-12-17 16:30:59 +00:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) ;
2012-12-07 16:06:44 +00:00
backEnd . glState . currentVertexBuffer = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ;
2012-11-28 15:47:07 +00:00
2012-12-17 16:30:59 +00:00
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_VERTEX ) ;
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_NORMAL ) ;
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR ) ;
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR2 ) ;
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_ST ) ;
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_TANGENT ) ;
2012-11-28 15:47:07 +00:00
2012-12-17 16:30:59 +00:00
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_VERTEX , 3 , GL_FLOAT , GL_FALSE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_XYZ_OFFSET ) ) ;
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_NORMAL , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_NORMAL_OFFSET ) ) ;
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_COLOR_OFFSET ) ) ;
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR2 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_COLOR2_OFFSET ) ) ;
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_ST , 2 , GL_HALF_FLOAT , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_ST_OFFSET ) ) ;
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_TANGENT , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_TANGENT_OFFSET ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . glState . vertexLayout = LAYOUT_DRAW_VERT ;
}
2012-12-07 16:06:44 +00:00
// RB end
2012-11-26 18:58:24 +00:00
2012-12-17 16:30:59 +00:00
glDrawElementsBaseVertex ( GL_TRIANGLES ,
r_singleTriangle . GetBool ( ) ? 3 : surf - > numIndexes ,
GL_INDEX_TYPE ,
( triIndex_t * ) indexOffset ,
vertOffset / sizeof ( idDrawVert ) ) ;
2014-04-20 14:29:58 +00:00
// RB: added stats
backEnd . pc . c_drawElements + + ;
backEnd . pc . c_drawIndexes + = surf - > numIndexes ;
// RB end
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = =
RB_GetShaderTextureMatrix
= = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_GetShaderTextureMatrix ( const float * shaderRegisters , const textureStage_t * texture , float matrix [ 16 ] )
{
matrix [ 0 * 4 + 0 ] = shaderRegisters [ texture - > matrix [ 0 ] [ 0 ] ] ;
matrix [ 1 * 4 + 0 ] = shaderRegisters [ texture - > matrix [ 0 ] [ 1 ] ] ;
matrix [ 2 * 4 + 0 ] = 0.0f ;
matrix [ 3 * 4 + 0 ] = shaderRegisters [ texture - > matrix [ 0 ] [ 2 ] ] ;
matrix [ 0 * 4 + 1 ] = shaderRegisters [ texture - > matrix [ 1 ] [ 0 ] ] ;
matrix [ 1 * 4 + 1 ] = shaderRegisters [ texture - > matrix [ 1 ] [ 1 ] ] ;
matrix [ 2 * 4 + 1 ] = 0.0f ;
matrix [ 3 * 4 + 1 ] = shaderRegisters [ texture - > matrix [ 1 ] [ 2 ] ] ;
2012-11-26 18:58:24 +00:00
// we attempt to keep scrolls from generating incredibly large texture values, but
// center rotations and center scales can still generate offsets that need to be > 1
2012-11-28 15:47:07 +00:00
if ( matrix [ 3 * 4 + 0 ] < - 40.0f | | matrix [ 12 ] > 40.0f )
{
matrix [ 3 * 4 + 0 ] - = ( int ) matrix [ 3 * 4 + 0 ] ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( matrix [ 13 ] < - 40.0f | | matrix [ 13 ] > 40.0f )
{
matrix [ 13 ] - = ( int ) matrix [ 13 ] ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
matrix [ 0 * 4 + 2 ] = 0.0f ;
matrix [ 1 * 4 + 2 ] = 0.0f ;
matrix [ 2 * 4 + 2 ] = 1.0f ;
matrix [ 3 * 4 + 2 ] = 0.0f ;
matrix [ 0 * 4 + 3 ] = 0.0f ;
matrix [ 1 * 4 + 3 ] = 0.0f ;
matrix [ 2 * 4 + 3 ] = 0.0f ;
matrix [ 3 * 4 + 3 ] = 1.0f ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = =
RB_LoadShaderTextureMatrix
= = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_LoadShaderTextureMatrix ( const float * shaderRegisters , const textureStage_t * texture )
{
2012-11-26 18:58:24 +00:00
float texS [ 4 ] = { 1.0f , 0.0f , 0.0f , 0.0f } ;
float texT [ 4 ] = { 0.0f , 1.0f , 0.0f , 0.0f } ;
2012-11-28 15:47:07 +00:00
if ( texture - > hasMatrix )
{
2012-11-26 18:58:24 +00:00
float matrix [ 16 ] ;
RB_GetShaderTextureMatrix ( shaderRegisters , texture , matrix ) ;
2012-11-28 15:47:07 +00:00
texS [ 0 ] = matrix [ 0 * 4 + 0 ] ;
texS [ 1 ] = matrix [ 1 * 4 + 0 ] ;
texS [ 2 ] = matrix [ 2 * 4 + 0 ] ;
texS [ 3 ] = matrix [ 3 * 4 + 0 ] ;
texT [ 0 ] = matrix [ 0 * 4 + 1 ] ;
texT [ 1 ] = matrix [ 1 * 4 + 1 ] ;
texT [ 2 ] = matrix [ 2 * 4 + 1 ] ;
texT [ 3 ] = matrix [ 3 * 4 + 1 ] ;
RENDERLOG_PRINTF ( " Setting Texture Matrix \n " ) ;
2012-11-26 18:58:24 +00:00
renderLog . Indent ( ) ;
RENDERLOG_PRINTF ( " Texture Matrix S : %4.3f, %4.3f, %4.3f, %4.3f \n " , texS [ 0 ] , texS [ 1 ] , texS [ 2 ] , texS [ 3 ] ) ;
RENDERLOG_PRINTF ( " Texture Matrix T : %4.3f, %4.3f, %4.3f, %4.3f \n " , texT [ 0 ] , texT [ 1 ] , texT [ 2 ] , texT [ 3 ] ) ;
renderLog . Outdent ( ) ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
SetVertexParm ( RENDERPARM_TEXTUREMATRIX_S , texS ) ;
SetVertexParm ( RENDERPARM_TEXTUREMATRIX_T , texT ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = =
RB_BakeTextureMatrixIntoTexgen
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_BakeTextureMatrixIntoTexgen ( idPlane lightProject [ 3 ] , const float * textureMatrix )
{
2012-11-26 18:58:24 +00:00
float genMatrix [ 16 ] ;
float final [ 16 ] ;
2012-11-28 15:47:07 +00:00
genMatrix [ 0 * 4 + 0 ] = lightProject [ 0 ] [ 0 ] ;
genMatrix [ 1 * 4 + 0 ] = lightProject [ 0 ] [ 1 ] ;
genMatrix [ 2 * 4 + 0 ] = lightProject [ 0 ] [ 2 ] ;
genMatrix [ 3 * 4 + 0 ] = lightProject [ 0 ] [ 3 ] ;
genMatrix [ 0 * 4 + 1 ] = lightProject [ 1 ] [ 0 ] ;
genMatrix [ 1 * 4 + 1 ] = lightProject [ 1 ] [ 1 ] ;
genMatrix [ 2 * 4 + 1 ] = lightProject [ 1 ] [ 2 ] ;
genMatrix [ 3 * 4 + 1 ] = lightProject [ 1 ] [ 3 ] ;
genMatrix [ 0 * 4 + 2 ] = 0.0f ;
genMatrix [ 1 * 4 + 2 ] = 0.0f ;
genMatrix [ 2 * 4 + 2 ] = 0.0f ;
genMatrix [ 3 * 4 + 2 ] = 0.0f ;
genMatrix [ 0 * 4 + 3 ] = lightProject [ 2 ] [ 0 ] ;
genMatrix [ 1 * 4 + 3 ] = lightProject [ 2 ] [ 1 ] ;
genMatrix [ 2 * 4 + 3 ] = lightProject [ 2 ] [ 2 ] ;
genMatrix [ 3 * 4 + 3 ] = lightProject [ 2 ] [ 3 ] ;
2012-11-26 18:58:24 +00:00
R_MatrixMultiply ( genMatrix , textureMatrix , final ) ;
2012-11-28 15:47:07 +00:00
lightProject [ 0 ] [ 0 ] = final [ 0 * 4 + 0 ] ;
lightProject [ 0 ] [ 1 ] = final [ 1 * 4 + 0 ] ;
lightProject [ 0 ] [ 2 ] = final [ 2 * 4 + 0 ] ;
lightProject [ 0 ] [ 3 ] = final [ 3 * 4 + 0 ] ;
lightProject [ 1 ] [ 0 ] = final [ 0 * 4 + 1 ] ;
lightProject [ 1 ] [ 1 ] = final [ 1 * 4 + 1 ] ;
lightProject [ 1 ] [ 2 ] = final [ 2 * 4 + 1 ] ;
lightProject [ 1 ] [ 3 ] = final [ 3 * 4 + 1 ] ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = =
RB_BindVariableStageImage
Handles generating a cinematic frame if needed
= = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_BindVariableStageImage ( const textureStage_t * texture , const float * shaderRegisters )
{
if ( texture - > cinematic )
{
2012-11-26 18:58:24 +00:00
cinData_t cin ;
2012-11-28 15:47:07 +00:00
if ( r_skipDynamicTextures . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
globalImages - > defaultImage - > Bind ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?)
// We make no attempt to optimize for multiple identical cinematics being in view, or
// for cinematics going at a lower framerate than the renderer.
cin = texture - > cinematic - > ImageForTime ( backEnd . viewDef - > renderView . time [ 0 ] + idMath : : Ftoi ( 1000.0f * backEnd . viewDef - > renderView . shaderParms [ 11 ] ) ) ;
2012-11-28 15:47:07 +00:00
if ( cin . imageY ! = NULL )
{
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
cin . imageY - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
cin . imageCr - > Bind ( ) ;
GL_SelectTexture ( 2 ) ;
cin . imageCb - > Bind ( ) ;
2014-04-05 13:41:19 +00:00
}
else if ( cin . image ! = NULL )
{
//Carl: A single RGB image works better with the FFMPEG BINK codec.
GL_SelectTexture ( 0 ) ;
cin . image - > Bind ( ) ;
renderProgManager . BindShader_TextureVertexColor ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
globalImages - > blackImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
// because the shaders may have already been set - we need to make sure we are not using a bink shader which would
2012-11-26 18:58:24 +00:00
// display incorrectly. We may want to get rid of RB_BindVariableStageImage and inline the code so that the
// SWF GUI case is handled better, too
renderProgManager . BindShader_TextureVertexColor ( ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// FIXME: see why image is invalid
2012-11-28 15:47:07 +00:00
if ( texture - > image ! = NULL )
{
2012-11-26 18:58:24 +00:00
texture - > image - > Bind ( ) ;
}
}
}
/*
= = = = = = = = = = = = = = = =
RB_PrepareStageTexturing
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_PrepareStageTexturing ( const shaderStage_t * pStage , const drawSurf_t * surf )
{
2012-11-26 18:58:24 +00:00
float useTexGenParm [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the texture matrix if needed
RB_LoadShaderTextureMatrix ( surf - > shaderRegisters , & pStage - > texture ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texgens
2012-11-28 15:47:07 +00:00
if ( pStage - > texture . texgen = = TG_REFLECT_CUBE )
{
2012-11-26 18:58:24 +00:00
// see if there is also a bump map specified
2012-11-28 15:47:07 +00:00
const shaderStage_t * bumpStage = surf - > material - > GetBumpStage ( ) ;
if ( bumpStage ! = NULL )
{
2012-11-26 18:58:24 +00:00
// per-pixel reflection mapping with bump mapping
GL_SelectTexture ( 1 ) ;
bumpStage - > texture . image - > Bind ( ) ;
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " TexGen: TG_REFLECT_CUBE: Bumpy Environment \n " ) ;
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_BumpyEnvironmentSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_BumpyEnvironment ( ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " TexGen: TG_REFLECT_CUBE: Environment \n " ) ;
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_EnvironmentSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Environment ( ) ;
}
}
2012-11-28 15:47:07 +00:00
}
else if ( pStage - > texture . texgen = = TG_SKYBOX_CUBE )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_SkyBox ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( pStage - > texture . texgen = = TG_WOBBLESKY_CUBE )
{
const int * parms = surf - > material - > GetTexGenRegisters ( ) ;
2012-11-26 18:58:24 +00:00
float wobbleDegrees = surf - > shaderRegisters [ parms [ 0 ] ] * ( idMath : : PI / 180.0f ) ;
float wobbleSpeed = surf - > shaderRegisters [ parms [ 1 ] ] * ( 2.0f * idMath : : PI / 60.0f ) ;
float rotateSpeed = surf - > shaderRegisters [ parms [ 2 ] ] * ( 2.0f * idMath : : PI / 60.0f ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec3 axis [ 3 ] ;
{
// very ad-hoc "wobble" transform
float s , c ;
idMath : : SinCos ( wobbleSpeed * backEnd . viewDef - > renderView . time [ 0 ] * 0.001f , s , c ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float ws , wc ;
idMath : : SinCos ( wobbleDegrees , ws , wc ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
axis [ 2 ] [ 0 ] = ws * c ;
axis [ 2 ] [ 1 ] = ws * s ;
axis [ 2 ] [ 2 ] = wc ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
axis [ 1 ] [ 0 ] = - s * s * ws ;
axis [ 1 ] [ 2 ] = - s * ws * ws ;
axis [ 1 ] [ 1 ] = idMath : : Sqrt ( idMath : : Fabs ( 1.0f - ( axis [ 1 ] [ 0 ] * axis [ 1 ] [ 0 ] + axis [ 1 ] [ 2 ] * axis [ 1 ] [ 2 ] ) ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// make the second vector exactly perpendicular to the first
axis [ 1 ] - = ( axis [ 2 ] * axis [ 1 ] ) * axis [ 2 ] ;
axis [ 1 ] . Normalize ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// construct the third with a cross
axis [ 0 ] . Cross ( axis [ 1 ] , axis [ 2 ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// add the rotate
float rs , rc ;
idMath : : SinCos ( rotateSpeed * backEnd . viewDef - > renderView . time [ 0 ] * 0.001f , rs , rc ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float transform [ 12 ] ;
2012-11-28 15:47:07 +00:00
transform [ 0 * 4 + 0 ] = axis [ 0 ] [ 0 ] * rc + axis [ 1 ] [ 0 ] * rs ;
transform [ 0 * 4 + 1 ] = axis [ 0 ] [ 1 ] * rc + axis [ 1 ] [ 1 ] * rs ;
transform [ 0 * 4 + 2 ] = axis [ 0 ] [ 2 ] * rc + axis [ 1 ] [ 2 ] * rs ;
transform [ 0 * 4 + 3 ] = 0.0f ;
transform [ 1 * 4 + 0 ] = axis [ 1 ] [ 0 ] * rc - axis [ 0 ] [ 0 ] * rs ;
transform [ 1 * 4 + 1 ] = axis [ 1 ] [ 1 ] * rc - axis [ 0 ] [ 1 ] * rs ;
transform [ 1 * 4 + 2 ] = axis [ 1 ] [ 2 ] * rc - axis [ 0 ] [ 2 ] * rs ;
transform [ 1 * 4 + 3 ] = 0.0f ;
transform [ 2 * 4 + 0 ] = axis [ 2 ] [ 0 ] ;
transform [ 2 * 4 + 1 ] = axis [ 2 ] [ 1 ] ;
transform [ 2 * 4 + 2 ] = axis [ 2 ] [ 2 ] ;
transform [ 2 * 4 + 3 ] = 0.0f ;
2012-11-26 18:58:24 +00:00
SetVertexParms ( RENDERPARM_WOBBLESKY_X , transform , 3 ) ;
renderProgManager . BindShader_WobbleSky ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ( pStage - > texture . texgen = = TG_SCREEN ) | | ( pStage - > texture . texgen = = TG_SCREEN2 ) )
{
2012-11-26 18:58:24 +00:00
useTexGenParm [ 0 ] = 1.0f ;
useTexGenParm [ 1 ] = 1.0f ;
useTexGenParm [ 2 ] = 1.0f ;
useTexGenParm [ 3 ] = 1.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float mat [ 16 ] ;
R_MatrixMultiply ( surf - > space - > modelViewMatrix , backEnd . viewDef - > projectionMatrix , mat ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " TexGen : %s \n " , ( pStage - > texture . texgen = = TG_SCREEN ) ? " TG_SCREEN " : " TG_SCREEN2 " ) ;
renderLog . Indent ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float plane [ 4 ] ;
2012-11-28 15:47:07 +00:00
plane [ 0 ] = mat [ 0 * 4 + 0 ] ;
plane [ 1 ] = mat [ 1 * 4 + 0 ] ;
plane [ 2 ] = mat [ 2 * 4 + 0 ] ;
plane [ 3 ] = mat [ 3 * 4 + 0 ] ;
2012-11-26 18:58:24 +00:00
SetVertexParm ( RENDERPARM_TEXGEN_0_S , plane ) ;
RENDERLOG_PRINTF ( " TEXGEN_S = %4.3f, %4.3f, %4.3f, %4.3f \n " , plane [ 0 ] , plane [ 1 ] , plane [ 2 ] , plane [ 3 ] ) ;
2012-11-28 15:47:07 +00:00
plane [ 0 ] = mat [ 0 * 4 + 1 ] ;
plane [ 1 ] = mat [ 1 * 4 + 1 ] ;
plane [ 2 ] = mat [ 2 * 4 + 1 ] ;
plane [ 3 ] = mat [ 3 * 4 + 1 ] ;
2012-11-26 18:58:24 +00:00
SetVertexParm ( RENDERPARM_TEXGEN_0_T , plane ) ;
RENDERLOG_PRINTF ( " TEXGEN_T = %4.3f, %4.3f, %4.3f, %4.3f \n " , plane [ 0 ] , plane [ 1 ] , plane [ 2 ] , plane [ 3 ] ) ;
2012-11-28 15:47:07 +00:00
plane [ 0 ] = mat [ 0 * 4 + 3 ] ;
plane [ 1 ] = mat [ 1 * 4 + 3 ] ;
plane [ 2 ] = mat [ 2 * 4 + 3 ] ;
plane [ 3 ] = mat [ 3 * 4 + 3 ] ;
SetVertexParm ( RENDERPARM_TEXGEN_0_Q , plane ) ;
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " TEXGEN_Q = %4.3f, %4.3f, %4.3f, %4.3f \n " , plane [ 0 ] , plane [ 1 ] , plane [ 2 ] , plane [ 3 ] ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . Outdent ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( pStage - > texture . texgen = = TG_DIFFUSE_CUBE )
{
2012-11-26 18:58:24 +00:00
// As far as I can tell, this is never used
idLib : : Warning ( " Using Diffuse Cube! Please contact Brian! " ) ;
2012-11-28 15:47:07 +00:00
}
else if ( pStage - > texture . texgen = = TG_GLASSWARP )
{
2012-11-26 18:58:24 +00:00
// As far as I can tell, this is never used
idLib : : Warning ( " Using GlassWarp! Please contact Brian! " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetVertexParm ( RENDERPARM_TEXGEN_0_ENABLED , useTexGenParm ) ;
}
/*
= = = = = = = = = = = = = = = =
RB_FinishStageTexturing
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_FinishStageTexturing ( const shaderStage_t * pStage , const drawSurf_t * surf )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( pStage - > texture . cinematic )
{
2012-11-26 18:58:24 +00:00
// unbind the extra bink textures
GL_SelectTexture ( 1 ) ;
globalImages - > BindNull ( ) ;
GL_SelectTexture ( 2 ) ;
globalImages - > BindNull ( ) ;
GL_SelectTexture ( 0 ) ;
}
2012-11-28 15:47:07 +00:00
if ( pStage - > texture . texgen = = TG_REFLECT_CUBE )
{
2012-11-26 18:58:24 +00:00
// see if there is also a bump map specified
2012-11-28 15:47:07 +00:00
const shaderStage_t * bumpStage = surf - > material - > GetBumpStage ( ) ;
if ( bumpStage ! = NULL )
{
2012-11-26 18:58:24 +00:00
// per-pixel reflection mapping with bump mapping
GL_SelectTexture ( 1 ) ;
globalImages - > BindNull ( ) ;
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// per-pixel reflection mapping without bump mapping
}
renderProgManager . Unbind ( ) ;
}
}
2014-05-10 12:40:01 +00:00
// RB: moved this up because we need to call this several times for shadow mapping
static void RB_ResetViewportAndScissorToDefaultCamera ( const viewDef_t * viewDef )
{
// set the window clipping
GL_Viewport ( viewDef - > viewport . x1 ,
viewDef - > viewport . y1 ,
viewDef - > viewport . x2 + 1 - viewDef - > viewport . x1 ,
viewDef - > viewport . y2 + 1 - viewDef - > viewport . y1 ) ;
// the scissor may be smaller than the viewport for subviews
GL_Scissor ( backEnd . viewDef - > viewport . x1 + viewDef - > scissor . x1 ,
backEnd . viewDef - > viewport . y1 + viewDef - > scissor . y1 ,
viewDef - > scissor . x2 + 1 - viewDef - > scissor . x1 ,
viewDef - > scissor . y2 + 1 - viewDef - > scissor . y1 ) ;
backEnd . currentScissor = viewDef - > scissor ;
}
// RB end
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DEPTH BUFFER RENDERING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
RB_FillDepthBufferGeneric
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_FillDepthBufferGeneric ( const drawSurf_t * const * drawSurfs , int numDrawSurfs )
{
for ( int i = 0 ; i < numDrawSurfs ; i + + )
{
const drawSurf_t * drawSurf = drawSurfs [ i ] ;
const idMaterial * shader = drawSurf - > material ;
2012-11-26 18:58:24 +00:00
// translucent surfaces don't put anything in the depth buffer and don't
// test against it, which makes them fail the mirror clip plane operation
2012-11-28 15:47:07 +00:00
if ( shader - > Coverage ( ) = = MC_TRANSLUCENT )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get the expressions for conditionals / color / texcoords
2012-11-28 15:47:07 +00:00
const float * regs = drawSurf - > shaderRegisters ;
2012-11-26 18:58:24 +00:00
// if all stages of a material have been conditioned off, don't do anything
int stage = 0 ;
2012-11-28 15:47:07 +00:00
for ( ; stage < shader - > GetNumStages ( ) ; stage + + )
{
const shaderStage_t * pStage = shader - > GetStage ( stage ) ;
2012-11-26 18:58:24 +00:00
// check the stage enable condition
2012-11-28 15:47:07 +00:00
if ( regs [ pStage - > conditionRegister ] ! = 0 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( stage = = shader - > GetNumStages ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// change the matrix if needed
2012-11-28 15:47:07 +00:00
if ( drawSurf - > space ! = backEnd . currentSpace )
{
2012-11-26 18:58:24 +00:00
RB_SetMVP ( drawSurf - > space - > mvp ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = drawSurf - > space ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 surfGLState = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set polygon offset if necessary
2012-11-28 15:47:07 +00:00
if ( shader - > TestMaterialFlag ( MF_POLYGONOFFSET ) )
{
2012-11-26 18:58:24 +00:00
surfGLState | = GLS_POLYGON_OFFSET ;
GL_PolygonOffset ( r_offsetFactor . GetFloat ( ) , r_offsetUnits . GetFloat ( ) * shader - > GetPolygonOffset ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// subviews will just down-modulate the color buffer
2014-05-10 12:40:01 +00:00
idVec4 color ;
2012-11-28 15:47:07 +00:00
if ( shader - > GetSort ( ) = = SS_SUBVIEW )
{
2012-11-26 18:58:24 +00:00
surfGLState | = GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS ;
color [ 0 ] = 1.0f ;
color [ 1 ] = 1.0f ;
color [ 2 ] = 1.0f ;
color [ 3 ] = 1.0f ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// others just draw black
color [ 0 ] = 0.0f ;
color [ 1 ] = 0.0f ;
color [ 2 ] = 0.0f ;
color [ 3 ] = 1.0f ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( shader - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool drawSolid = false ;
2012-11-28 15:47:07 +00:00
if ( shader - > Coverage ( ) = = MC_OPAQUE )
{
2012-11-26 18:58:24 +00:00
drawSolid = true ;
2012-11-28 15:47:07 +00:00
}
else if ( shader - > Coverage ( ) = = MC_PERFORATED )
{
2012-11-26 18:58:24 +00:00
// we may have multiple alpha tested stages
// if the only alpha tested stages are condition register omitted,
// draw a normal opaque surface
bool didDraw = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// perforated surfaces may have multiple alpha tested stages
2012-11-28 15:47:07 +00:00
for ( stage = 0 ; stage < shader - > GetNumStages ( ) ; stage + + )
{
const shaderStage_t * pStage = shader - > GetStage ( stage ) ;
if ( ! pStage - > hasAlphaTest )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check the stage enable condition
2012-11-28 15:47:07 +00:00
if ( regs [ pStage - > conditionRegister ] = = 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if we at least tried to draw an alpha tested stage,
// we won't draw the opaque surface
didDraw = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the alpha modulate
color [ 3 ] = regs [ pStage - > color . registers [ 3 ] ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// skip the entire stage if alpha would be black
2012-11-28 15:47:07 +00:00
if ( color [ 3 ] < = 0.0f )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 stageGLState = surfGLState ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set privatePolygonOffset if necessary
2012-11-28 15:47:07 +00:00
if ( pStage - > privatePolygonOffset )
{
2012-11-26 18:58:24 +00:00
GL_PolygonOffset ( r_offsetFactor . GetFloat ( ) , r_offsetUnits . GetFloat ( ) * pStage - > privatePolygonOffset ) ;
stageGLState | = GLS_POLYGON_OFFSET ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_Color ( color ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
# ifdef USE_CORE_PROFILE
GL_State ( stageGLState ) ;
idVec4 alphaTestValue ( regs [ pStage - > alphaTestRegister ] ) ;
SetFragmentParm ( RENDERPARM_ALPHA_TEST , alphaTestValue . ToFloatPtr ( ) ) ;
# else
GL_State ( stageGLState | GLS_ALPHATEST_FUNC_GREATER | GLS_ALPHATEST_MAKE_REF ( idMath : : Ftob ( 255.0f * regs [ pStage - > alphaTestRegister ] ) ) ) ;
# endif
2012-11-28 15:47:07 +00:00
if ( drawSurf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColorSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColor ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_SetVertexColorParms ( SVC_IGNORE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bind the texture
GL_SelectTexture ( 0 ) ;
pStage - > texture . image - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set texture matrix and texGens
RB_PrepareStageTexturing ( pStage , drawSurf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// must render with less-equal for Z-Cull to work properly
assert ( ( GL_GetCurrentState ( ) & GLS_DEPTHFUNC_BITS ) = = GLS_DEPTHFUNC_LESS ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw it
RB_DrawElementsWithCounters ( drawSurf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clean up
RB_FinishStageTexturing ( pStage , drawSurf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// unset privatePolygonOffset if necessary
2012-11-28 15:47:07 +00:00
if ( pStage - > privatePolygonOffset )
{
2012-11-26 18:58:24 +00:00
GL_PolygonOffset ( r_offsetFactor . GetFloat ( ) , r_offsetUnits . GetFloat ( ) * shader - > GetPolygonOffset ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! didDraw )
{
2012-11-26 18:58:24 +00:00
drawSolid = true ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw the entire surface solid
2012-11-28 15:47:07 +00:00
if ( drawSolid )
{
if ( shader - > GetSort ( ) = = SS_SUBVIEW )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Color ( ) ;
GL_Color ( color ) ;
GL_State ( surfGLState ) ;
2012-11-28 15:47:07 +00:00
}
else
{
if ( drawSurf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_DepthSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Depth ( ) ;
}
GL_State ( surfGLState | GLS_ALPHAMASK ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// must render with less-equal for Z-Cull to work properly
assert ( ( GL_GetCurrentState ( ) & GLS_DEPTHFUNC_BITS ) = = GLS_DEPTHFUNC_LESS ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw it
RB_DrawElementsWithCounters ( drawSurf ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
# ifdef USE_CORE_PROFILE
SetFragmentParm ( RENDERPARM_ALPHA_TEST , vec4_zero . ToFloatPtr ( ) ) ;
# endif
}
/*
= = = = = = = = = = = = = = = = = = = = =
RB_FillDepthBufferFast
Optimized fast path code .
If there are subview surfaces , they must be guarded in the depth buffer to allow
the mirror / subview to show through underneath the current view rendering .
Surfaces with perforated shaders need the full shader setup done , but should be
drawn after the opaque surfaces .
The bulk of the surfaces should be simple opaque geometry that can be drawn very rapidly .
If there are no subview surfaces , we could clear to black and use fast - Z rendering
on the 360.
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_FillDepthBufferFast ( drawSurf_t * * drawSurfs , int numDrawSurfs )
{
if ( numDrawSurfs = = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if we are just doing 2D rendering, no need to fill the depth buffer
2012-11-28 15:47:07 +00:00
if ( backEnd . viewDef - > viewEntitys = = NULL )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . OpenMainBlock ( MRB_FILL_DEPTH_BUFFER ) ;
renderLog . OpenBlock ( " RB_FillDepthBufferFast " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_StartDepthPass ( backEnd . viewDef - > scissor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// force MVP change on first surface
backEnd . currentSpace = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw all the subview surfaces, which will already be at the start of the sorted list,
// with the general purpose path
GL_State ( GLS_DEFAULT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int surfNum ;
2012-11-28 15:47:07 +00:00
for ( surfNum = 0 ; surfNum < numDrawSurfs ; surfNum + + )
{
if ( drawSurfs [ surfNum ] - > material - > GetSort ( ) ! = SS_SUBVIEW )
{
2012-11-26 18:58:24 +00:00
break ;
}
RB_FillDepthBufferGeneric ( & drawSurfs [ surfNum ] , 1 ) ;
}
2012-11-28 15:47:07 +00:00
const drawSurf_t * * perforatedSurfaces = ( const drawSurf_t * * ) _alloca ( numDrawSurfs * sizeof ( drawSurf_t * ) ) ;
2012-11-26 18:58:24 +00:00
int numPerforatedSurfaces = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw all the opaque surfaces and build up a list of perforated surfaces that
// we will defer drawing until all opaque surfaces are done
GL_State ( GLS_DEFAULT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// continue checking past the subview surfaces
2012-11-28 15:47:07 +00:00
for ( ; surfNum < numDrawSurfs ; surfNum + + )
{
const drawSurf_t * surf = drawSurfs [ surfNum ] ;
const idMaterial * shader = surf - > material ;
2012-11-26 18:58:24 +00:00
// translucent surfaces don't put anything in the depth buffer
2012-11-28 15:47:07 +00:00
if ( shader - > Coverage ( ) = = MC_TRANSLUCENT )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( shader - > Coverage ( ) = = MC_PERFORATED )
{
2012-11-26 18:58:24 +00:00
// save for later drawing
perforatedSurfaces [ numPerforatedSurfaces ] = surf ;
numPerforatedSurfaces + + ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set polygon offset?
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set mvp matrix
2012-11-28 15:47:07 +00:00
if ( surf - > space ! = backEnd . currentSpace )
{
2012-11-26 18:58:24 +00:00
RB_SetMVP ( surf - > space - > mvp ) ;
backEnd . currentSpace = surf - > space ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( shader - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_DepthSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Depth ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// must render with less-equal for Z-Cull to work properly
assert ( ( GL_GetCurrentState ( ) & GLS_DEPTHFUNC_BITS ) = = GLS_DEPTHFUNC_LESS ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw it solid
RB_DrawElementsWithCounters ( surf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw all perforated surfaces with the general code path
2012-11-28 15:47:07 +00:00
if ( numPerforatedSurfaces > 0 )
{
2012-11-26 18:58:24 +00:00
RB_FillDepthBufferGeneric ( perforatedSurfaces , numPerforatedSurfaces ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Allow platform specific data to be collected after the depth pass.
GL_FinishDepthPass ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
renderLog . CloseMainBlock ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
GENERAL INTERACTION RENDERING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
const int INTERACTION_TEXUNIT_BUMP = 0 ;
const int INTERACTION_TEXUNIT_FALLOFF = 1 ;
const int INTERACTION_TEXUNIT_PROJECTION = 2 ;
const int INTERACTION_TEXUNIT_DIFFUSE = 3 ;
const int INTERACTION_TEXUNIT_SPECULAR = 4 ;
2014-05-10 12:40:01 +00:00
const int INTERACTION_TEXUNIT_SHADOWMAPS = 5 ;
const int INTERACTION_TEXUNIT_JITTER = 6 ;
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = =
RB_SetupInteractionStage
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_SetupInteractionStage ( const shaderStage_t * surfaceStage , const float * surfaceRegs , const float lightColor [ 4 ] ,
idVec4 matrix [ 2 ] , float color [ 4 ] )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( surfaceStage - > texture . hasMatrix )
{
2012-11-26 18:58:24 +00:00
matrix [ 0 ] [ 0 ] = surfaceRegs [ surfaceStage - > texture . matrix [ 0 ] [ 0 ] ] ;
matrix [ 0 ] [ 1 ] = surfaceRegs [ surfaceStage - > texture . matrix [ 0 ] [ 1 ] ] ;
matrix [ 0 ] [ 2 ] = 0.0f ;
matrix [ 0 ] [ 3 ] = surfaceRegs [ surfaceStage - > texture . matrix [ 0 ] [ 2 ] ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
matrix [ 1 ] [ 0 ] = surfaceRegs [ surfaceStage - > texture . matrix [ 1 ] [ 0 ] ] ;
matrix [ 1 ] [ 1 ] = surfaceRegs [ surfaceStage - > texture . matrix [ 1 ] [ 1 ] ] ;
matrix [ 1 ] [ 2 ] = 0.0f ;
matrix [ 1 ] [ 3 ] = surfaceRegs [ surfaceStage - > texture . matrix [ 1 ] [ 2 ] ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we attempt to keep scrolls from generating incredibly large texture values, but
// center rotations and center scales can still generate offsets that need to be > 1
2012-11-28 15:47:07 +00:00
if ( matrix [ 0 ] [ 3 ] < - 40.0f | | matrix [ 0 ] [ 3 ] > 40.0f )
{
2012-11-26 18:58:24 +00:00
matrix [ 0 ] [ 3 ] - = idMath : : Ftoi ( matrix [ 0 ] [ 3 ] ) ;
}
2012-11-28 15:47:07 +00:00
if ( matrix [ 1 ] [ 3 ] < - 40.0f | | matrix [ 1 ] [ 3 ] > 40.0f )
{
2012-11-26 18:58:24 +00:00
matrix [ 1 ] [ 3 ] - = idMath : : Ftoi ( matrix [ 1 ] [ 3 ] ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
matrix [ 0 ] [ 0 ] = 1.0f ;
matrix [ 0 ] [ 1 ] = 0.0f ;
matrix [ 0 ] [ 2 ] = 0.0f ;
matrix [ 0 ] [ 3 ] = 0.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
matrix [ 1 ] [ 0 ] = 0.0f ;
matrix [ 1 ] [ 1 ] = 1.0f ;
matrix [ 1 ] [ 2 ] = 0.0f ;
matrix [ 1 ] [ 3 ] = 0.0f ;
}
2012-11-28 15:47:07 +00:00
if ( color ! = NULL )
{
for ( int i = 0 ; i < 4 ; i + + )
{
2012-11-26 18:58:24 +00:00
// clamp here, so cards with a greater range don't look different.
// we could perform overbrighting like we do for lights, but
// it doesn't currently look worth it.
color [ i ] = idMath : : ClampFloat ( 0.0f , 1.0f , surfaceRegs [ surfaceStage - > color . registers [ i ] ] ) * lightColor [ i ] ;
}
}
}
/*
= = = = = = = = = = = = = = = = =
RB_DrawSingleInteraction
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_DrawSingleInteraction ( drawInteraction_t * din )
{
if ( din - > bumpImage = = NULL )
{
2012-11-26 18:58:24 +00:00
// stage wasn't actually an interaction
return ;
}
2012-11-28 15:47:07 +00:00
if ( din - > diffuseImage = = NULL | | r_skipDiffuse . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// this isn't a YCoCg black, but it doesn't matter, because
// the diffuseColor will also be 0
din - > diffuseImage = globalImages - > blackImage ;
}
2012-11-28 15:47:07 +00:00
if ( din - > specularImage = = NULL | | r_skipSpecular . GetBool ( ) | | din - > ambientLight )
{
2012-11-26 18:58:24 +00:00
din - > specularImage = globalImages - > blackImage ;
}
2012-11-28 15:47:07 +00:00
if ( r_skipBump . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
din - > bumpImage = globalImages - > flatNormalMap ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if we wouldn't draw anything, don't call the Draw function
const bool diffuseIsBlack = ( din - > diffuseImage = = globalImages - > blackImage )
2012-11-28 15:47:07 +00:00
| | ( ( din - > diffuseColor [ 0 ] < = 0 ) & & ( din - > diffuseColor [ 1 ] < = 0 ) & & ( din - > diffuseColor [ 2 ] < = 0 ) ) ;
2012-11-26 18:58:24 +00:00
const bool specularIsBlack = ( din - > specularImage = = globalImages - > blackImage )
2012-11-28 15:47:07 +00:00
| | ( ( din - > specularColor [ 0 ] < = 0 ) & & ( din - > specularColor [ 1 ] < = 0 ) & & ( din - > specularColor [ 2 ] < = 0 ) ) ;
if ( diffuseIsBlack & & specularIsBlack )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bump matrix
SetVertexParm ( RENDERPARM_BUMPMATRIX_S , din - > bumpMatrix [ 0 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_BUMPMATRIX_T , din - > bumpMatrix [ 1 ] . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// diffuse matrix
SetVertexParm ( RENDERPARM_DIFFUSEMATRIX_S , din - > diffuseMatrix [ 0 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_DIFFUSEMATRIX_T , din - > diffuseMatrix [ 1 ] . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// specular matrix
SetVertexParm ( RENDERPARM_SPECULARMATRIX_S , din - > specularMatrix [ 0 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_SPECULARMATRIX_T , din - > specularMatrix [ 1 ] . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_SetVertexColorParms ( din - > vertexColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetFragmentParm ( RENDERPARM_DIFFUSEMODIFIER , din - > diffuseColor . ToFloatPtr ( ) ) ;
SetFragmentParm ( RENDERPARM_SPECULARMODIFIER , din - > specularColor . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 0 will be the per-surface bump map
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( INTERACTION_TEXUNIT_BUMP ) ;
2012-11-26 18:58:24 +00:00
din - > bumpImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 3 is the per-surface diffuse map
GL_SelectTexture ( INTERACTION_TEXUNIT_DIFFUSE ) ;
din - > diffuseImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 4 is the per-surface specular map
GL_SelectTexture ( INTERACTION_TEXUNIT_SPECULAR ) ;
din - > specularImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( din - > surf ) ;
}
/*
= = = = = = = = = = = = = = = = =
RB_SetupForFastPathInteractions
These are common for all fast path surfaces
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_SetupForFastPathInteractions ( const idVec4 & diffuseColor , const idVec4 & specularColor )
{
2012-11-26 18:58:24 +00:00
const idVec4 sMatrix ( 1 , 0 , 0 , 0 ) ;
const idVec4 tMatrix ( 0 , 1 , 0 , 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bump matrix
SetVertexParm ( RENDERPARM_BUMPMATRIX_S , sMatrix . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_BUMPMATRIX_T , tMatrix . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// diffuse matrix
SetVertexParm ( RENDERPARM_DIFFUSEMATRIX_S , sMatrix . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_DIFFUSEMATRIX_T , tMatrix . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// specular matrix
SetVertexParm ( RENDERPARM_SPECULARMATRIX_S , sMatrix . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_SPECULARMATRIX_T , tMatrix . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_SetVertexColorParms ( SVC_IGNORE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetFragmentParm ( RENDERPARM_DIFFUSEMODIFIER , diffuseColor . ToFloatPtr ( ) ) ;
SetFragmentParm ( RENDERPARM_SPECULARMODIFIER , specularColor . ToFloatPtr ( ) ) ;
}
/*
= = = = = = = = = = = = =
RB_RenderInteractions
With added sorting and trivial path work .
= = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_RenderInteractions ( const drawSurf_t * surfList , const viewLight_t * vLight , int depthFunc , bool performStencilTest , bool useLightDepthBounds )
{
if ( surfList = = NULL )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// change the scissor if needed, it will be constant across all the surfaces lit by the light
2012-11-28 15:47:07 +00:00
if ( ! backEnd . currentScissor . Equals ( vLight - > scissorRect ) & & r_useScissor . GetBool ( ) )
{
GL_Scissor ( backEnd . viewDef - > viewport . x1 + vLight - > scissorRect . x1 ,
2012-11-26 18:58:24 +00:00
backEnd . viewDef - > viewport . y1 + vLight - > scissorRect . y1 ,
vLight - > scissorRect . x2 + 1 - vLight - > scissorRect . x1 ,
vLight - > scissorRect . y2 + 1 - vLight - > scissorRect . y1 ) ;
backEnd . currentScissor = vLight - > scissorRect ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// perform setup here that will be constant for all interactions
2012-11-28 15:47:07 +00:00
if ( performStencilTest )
{
2012-11-26 18:58:24 +00:00
GL_State ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | depthFunc | GLS_STENCIL_FUNC_EQUAL | GLS_STENCIL_MAKE_REF ( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK ( STENCIL_SHADOW_MASK_VALUE ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
GL_State ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | depthFunc | GLS_STENCIL_FUNC_ALWAYS ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// some rare lights have multiple animating stages, loop over them outside the surface list
2012-11-28 15:47:07 +00:00
const idMaterial * lightShader = vLight - > lightShader ;
const float * lightRegs = vLight - > shaderRegisters ;
2012-11-26 18:58:24 +00:00
drawInteraction_t inter = { } ;
inter . ambientLight = lightShader - > IsAmbientLight ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//---------------------------------
// Split out the complex surfaces from the fast-path surfaces
// so we can do the fast path ones all in a row.
// The surfaces should already be sorted by space because they
// are added single-threaded, and there is only a negligable amount
// of benefit to trying to sort by materials.
//---------------------------------
static const int MAX_INTERACTIONS_PER_LIGHT = 1024 ;
2014-04-20 14:29:58 +00:00
static const int MAX_COMPLEX_INTERACTIONS_PER_LIGHT = 256 ;
2012-11-28 15:47:07 +00:00
idStaticList < const drawSurf_t * , MAX_INTERACTIONS_PER_LIGHT > allSurfaces ;
idStaticList < const drawSurf_t * , MAX_COMPLEX_INTERACTIONS_PER_LIGHT > complexSurfaces ;
for ( const drawSurf_t * walk = surfList ; walk ! = NULL ; walk = walk - > nextOnLight )
{
2012-11-26 18:58:24 +00:00
// make sure the triangle culling is done
2012-11-28 15:47:07 +00:00
if ( walk - > shadowVolumeState ! = SHADOWVOLUME_DONE )
{
2012-11-26 18:58:24 +00:00
assert ( walk - > shadowVolumeState = = SHADOWVOLUME_UNFINISHED | | walk - > shadowVolumeState = = SHADOWVOLUME_DONE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 start = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
while ( walk - > shadowVolumeState = = SHADOWVOLUME_UNFINISHED )
{
2012-11-26 18:58:24 +00:00
Sys_Yield ( ) ;
}
uint64 end = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . pc . shadowMicroSec + = end - start ;
}
2012-11-28 15:47:07 +00:00
const idMaterial * surfaceShader = walk - > material ;
if ( surfaceShader - > GetFastPathBumpImage ( ) )
{
2012-11-26 18:58:24 +00:00
allSurfaces . Append ( walk ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
complexSurfaces . Append ( walk ) ;
}
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < complexSurfaces . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
allSurfaces . Append ( complexSurfaces [ i ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool lightDepthBoundsDisabled = false ;
2012-11-28 15:47:07 +00:00
2014-05-10 12:40:01 +00:00
// RB begin
if ( r_useShadowMapping . GetBool ( ) )
{
const static int JITTER_SIZE = 128 ;
// screen power of two correction factor
float screenCorrectionParm [ 4 ] ;
screenCorrectionParm [ 0 ] = 1.0f / ( JITTER_SIZE * r_shadowMapSamples . GetInteger ( ) ) ;
screenCorrectionParm [ 1 ] = 1.0f / JITTER_SIZE ;
screenCorrectionParm [ 2 ] = 0.0f ;
screenCorrectionParm [ 3 ] = 1.0f ;
SetFragmentParm ( RENDERPARM_SCREENCORRECTIONFACTOR , screenCorrectionParm ) ; // rpScreenCorrectionFactor
float jitterTexScale [ 4 ] ;
jitterTexScale [ 0 ] = r_shadowMapJitterScale . GetFloat ( ) * 1.0f ; // TODO shadow buffer size fraction shadowMapSize / maxShadowMapSize
jitterTexScale [ 1 ] = r_shadowMapJitterScale . GetFloat ( ) * 1.0f ;
jitterTexScale [ 2 ] = - r_shadowMapBiasScale . GetFloat ( ) ;
jitterTexScale [ 3 ] = 0.0f ;
SetFragmentParm ( RENDERPARM_JITTERTEXSCALE , jitterTexScale ) ; // rpJitterTexScale
float jitterTexOffset [ 4 ] ;
jitterTexOffset [ 0 ] = ( rand ( ) & 255 ) / 255.0 ;
jitterTexOffset [ 1 ] = ( rand ( ) & 255 ) / 255.0 ;
jitterTexOffset [ 2 ] = 0.0f ;
jitterTexOffset [ 3 ] = 0.0f ;
SetFragmentParm ( RENDERPARM_JITTERTEXOFFSET , jitterTexOffset ) ; // rpJitterTexOffset
if ( vLight - > parallel )
{
float cascadeDistances [ 4 ] ;
cascadeDistances [ 0 ] = backEnd . viewDef - > frustumSplitDistances [ 0 ] ;
cascadeDistances [ 1 ] = backEnd . viewDef - > frustumSplitDistances [ 1 ] ;
cascadeDistances [ 2 ] = backEnd . viewDef - > frustumSplitDistances [ 2 ] ;
cascadeDistances [ 3 ] = backEnd . viewDef - > frustumSplitDistances [ 3 ] ;
SetFragmentParm ( RENDERPARM_CASCADEDISTANCES , cascadeDistances ) ; // rpCascadeDistances
}
}
// RB end
2012-11-28 15:47:07 +00:00
for ( int lightStageNum = 0 ; lightStageNum < lightShader - > GetNumStages ( ) ; lightStageNum + + )
{
const shaderStage_t * lightStage = lightShader - > GetStage ( lightStageNum ) ;
2012-11-26 18:58:24 +00:00
// ignore stages that fail the condition
2012-11-28 15:47:07 +00:00
if ( ! lightRegs [ lightStage - > conditionRegister ] )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float lightScale = r_lightScale . GetFloat ( ) ;
const idVec4 lightColor (
lightScale * lightRegs [ lightStage - > color . registers [ 0 ] ] ,
lightScale * lightRegs [ lightStage - > color . registers [ 1 ] ] ,
lightScale * lightRegs [ lightStage - > color . registers [ 2 ] ] ,
lightRegs [ lightStage - > color . registers [ 3 ] ] ) ;
// apply the world-global overbright and the 2x factor for specular
const idVec4 diffuseColor = lightColor ;
const idVec4 specularColor = lightColor * 2.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float lightTextureMatrix [ 16 ] ;
2012-11-28 15:47:07 +00:00
if ( lightStage - > texture . hasMatrix )
{
2012-11-26 18:58:24 +00:00
RB_GetShaderTextureMatrix ( lightRegs , & lightStage - > texture , lightTextureMatrix ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 1 will be the light falloff texture
GL_SelectTexture ( INTERACTION_TEXUNIT_FALLOFF ) ;
vLight - > falloffImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 2 will be the light projection texture
GL_SelectTexture ( INTERACTION_TEXUNIT_PROJECTION ) ;
lightStage - > texture . image - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2014-05-10 12:40:01 +00:00
if ( r_useShadowMapping . GetBool ( ) )
{
// texture 5 will be the shadow maps array
GL_SelectTexture ( INTERACTION_TEXUNIT_SHADOWMAPS ) ;
globalImages - > shadowImage - > Bind ( ) ;
// texture 6 will be the jitter texture for soft shadowing
GL_SelectTexture ( INTERACTION_TEXUNIT_JITTER ) ;
if ( r_shadowMapSamples . GetInteger ( ) = = 16 )
{
globalImages - > jitterImage16 - > Bind ( ) ;
}
else if ( r_shadowMapSamples . GetInteger ( ) = = 4 )
{
globalImages - > jitterImage4 - > Bind ( ) ;
}
else
{
globalImages - > jitterImage1 - > Bind ( ) ;
}
}
2012-11-26 18:58:24 +00:00
// force the light textures to not use anisotropic filtering, which is wasted on them
// all of the texture sampler parms should be constant for all interactions, only
// the actual texture image bindings will change
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//----------------------------------
// For all surfaces on this light list, generate an interaction for this light stage
//----------------------------------
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// setup renderparms assuming we will be drawing trivial surfaces first
RB_SetupForFastPathInteractions ( diffuseColor , specularColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// even if the space does not change between light stages, each light stage may need a different lightTextureMatrix baked in
backEnd . currentSpace = NULL ;
2012-11-28 15:47:07 +00:00
for ( int sortedSurfNum = 0 ; sortedSurfNum < allSurfaces . Num ( ) ; sortedSurfNum + + )
{
const drawSurf_t * const surf = allSurfaces [ sortedSurfNum ] ;
2012-11-26 18:58:24 +00:00
// select the render prog
2012-11-28 15:47:07 +00:00
if ( lightShader - > IsAmbientLight ( ) )
{
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_InteractionAmbientSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_InteractionAmbient ( ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2014-05-10 12:40:01 +00:00
if ( r_useShadowMapping . GetBool ( ) & & vLight - > globalShadows )
2012-11-28 15:47:07 +00:00
{
2014-05-10 12:40:01 +00:00
// RB: we have shadow mapping enabled and shadow maps so do a shadow compare
if ( vLight - > parallel )
{
if ( surf - > jointCache )
{
renderProgManager . BindShader_Interaction_ShadowMapping_Parallel_Skinned ( ) ;
}
else
{
renderProgManager . BindShader_Interaction_ShadowMapping_Parallel ( ) ;
}
}
else if ( vLight - > pointLight )
{
if ( surf - > jointCache )
{
renderProgManager . BindShader_Interaction_ShadowMapping_Point_Skinned ( ) ;
}
else
{
renderProgManager . BindShader_Interaction_ShadowMapping_Point ( ) ;
}
}
else
{
if ( surf - > jointCache )
{
renderProgManager . BindShader_Interaction_ShadowMapping_Spot_Skinned ( ) ;
}
else
{
renderProgManager . BindShader_Interaction_ShadowMapping_Spot ( ) ;
}
}
2012-11-28 15:47:07 +00:00
}
else
{
2014-05-10 12:40:01 +00:00
if ( surf - > jointCache )
{
renderProgManager . BindShader_InteractionSkinned ( ) ;
}
else
{
renderProgManager . BindShader_Interaction ( ) ;
}
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
const idMaterial * surfaceShader = surf - > material ;
const float * surfaceRegs = surf - > shaderRegisters ;
2012-11-26 18:58:24 +00:00
inter . surf = surf ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// change the MVP matrix, view/light origin and light projection vectors if needed
2012-11-28 15:47:07 +00:00
if ( surf - > space ! = backEnd . currentSpace )
{
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = surf - > space ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// turn off the light depth bounds test if this model is rendered with a depth hack
2012-11-28 15:47:07 +00:00
if ( useLightDepthBounds )
{
if ( ! surf - > space - > weaponDepthHack & & surf - > space - > modelDepthHack = = 0.0f )
{
if ( lightDepthBoundsDisabled )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( vLight - > scissorRect . zmin , vLight - > scissorRect . zmax ) ;
lightDepthBoundsDisabled = false ;
}
2012-11-28 15:47:07 +00:00
}
else
{
if ( ! lightDepthBoundsDisabled )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( 0.0f , 0.0f ) ;
lightDepthBoundsDisabled = true ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// model-view-projection
RB_SetMVP ( surf - > space - > mvp ) ;
2012-11-28 15:47:07 +00:00
2014-05-10 12:40:01 +00:00
// RB begin
idRenderMatrix modelMatrix ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) surf - > space - > modelMatrix , modelMatrix ) ;
SetVertexParms ( RENDERPARM_MODELMATRIX_X , modelMatrix [ 0 ] , 4 ) ;
// for determining the shadow mapping cascades
idRenderMatrix modelViewMatrix , tmp ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) surf - > space - > modelViewMatrix , modelViewMatrix ) ;
SetVertexParms ( RENDERPARM_MODELVIEWMATRIX_X , modelViewMatrix [ 0 ] , 4 ) ;
idVec4 globalLightOrigin ( vLight - > globalLightOrigin . x , vLight - > globalLightOrigin . y , vLight - > globalLightOrigin . z , 1.0f ) ;
SetVertexParm ( RENDERPARM_GLOBALLIGHTORIGIN , globalLightOrigin . ToFloatPtr ( ) ) ;
// RB end
2012-11-26 18:58:24 +00:00
// tranform the light/view origin into model local space
idVec4 localLightOrigin ( 0.0f ) ;
idVec4 localViewOrigin ( 1.0f ) ;
R_GlobalPointToLocal ( surf - > space - > modelMatrix , vLight - > globalLightOrigin , localLightOrigin . ToVec3 ( ) ) ;
R_GlobalPointToLocal ( surf - > space - > modelMatrix , backEnd . viewDef - > renderView . vieworg , localViewOrigin . ToVec3 ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the local light/view origin
SetVertexParm ( RENDERPARM_LOCALLIGHTORIGIN , localLightOrigin . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_LOCALVIEWORIGIN , localViewOrigin . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// transform the light project into model local space
idPlane lightProjection [ 4 ] ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
2012-11-26 18:58:24 +00:00
R_GlobalPlaneToLocal ( surf - > space - > modelMatrix , vLight - > lightProject [ i ] , lightProjection [ i ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// optionally multiply the local light projection by the light texture matrix
2012-11-28 15:47:07 +00:00
if ( lightStage - > texture . hasMatrix )
{
2012-11-26 18:58:24 +00:00
RB_BakeTextureMatrixIntoTexgen ( lightProjection , lightTextureMatrix ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the light projection
SetVertexParm ( RENDERPARM_LIGHTPROJECTION_S , lightProjection [ 0 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_LIGHTPROJECTION_T , lightProjection [ 1 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_LIGHTPROJECTION_Q , lightProjection [ 2 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_LIGHTFALLOFF_S , lightProjection [ 3 ] . ToFloatPtr ( ) ) ;
2014-05-10 12:40:01 +00:00
// RB begin
if ( r_useShadowMapping . GetBool ( ) )
{
if ( vLight - > parallel )
{
for ( int i = 0 ; i < ( r_shadowMapSplits . GetInteger ( ) + 1 ) ; i + + )
{
idRenderMatrix modelToShadowMatrix ;
idRenderMatrix : : Multiply ( backEnd . shadowV [ i ] , modelMatrix , modelToShadowMatrix ) ;
idRenderMatrix shadowClipMVP ;
idRenderMatrix : : Multiply ( backEnd . shadowP [ i ] , modelToShadowMatrix , shadowClipMVP ) ;
idRenderMatrix shadowWindowMVP ;
idRenderMatrix : : Multiply ( renderMatrix_clipSpaceToWindowSpace , shadowClipMVP , shadowWindowMVP ) ;
SetVertexParms ( ( renderParm_t ) ( RENDERPARM_SHADOW_MATRIX_0_X + i * 4 ) , shadowWindowMVP [ 0 ] , 4 ) ;
}
}
else if ( vLight - > pointLight )
{
for ( int i = 0 ; i < 6 ; i + + )
{
idRenderMatrix modelToShadowMatrix ;
idRenderMatrix : : Multiply ( backEnd . shadowV [ i ] , modelMatrix , modelToShadowMatrix ) ;
idRenderMatrix shadowClipMVP ;
idRenderMatrix : : Multiply ( backEnd . shadowP [ i ] , modelToShadowMatrix , shadowClipMVP ) ;
idRenderMatrix shadowWindowMVP ;
idRenderMatrix : : Multiply ( renderMatrix_clipSpaceToWindowSpace , shadowClipMVP , shadowWindowMVP ) ;
SetVertexParms ( ( renderParm_t ) ( RENDERPARM_SHADOW_MATRIX_0_X + i * 4 ) , shadowWindowMVP [ 0 ] , 4 ) ;
}
}
else
{
// spot light
idRenderMatrix modelToShadowMatrix ;
idRenderMatrix : : Multiply ( backEnd . shadowV [ 0 ] , modelMatrix , modelToShadowMatrix ) ;
idRenderMatrix shadowClipMVP ;
idRenderMatrix : : Multiply ( backEnd . shadowP [ 0 ] , modelToShadowMatrix , shadowClipMVP ) ;
SetVertexParms ( ( renderParm_t ) ( RENDERPARM_SHADOW_MATRIX_0_X ) , shadowClipMVP [ 0 ] , 4 ) ;
}
}
// RB end
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for the fast path
2012-11-28 15:47:07 +00:00
if ( surfaceShader - > GetFastPathBumpImage ( ) & & ! r_skipInteractionFastPath . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( surf - > material - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 0 will be the per-surface bump map
GL_SelectTexture ( INTERACTION_TEXUNIT_BUMP ) ;
surfaceShader - > GetFastPathBumpImage ( ) - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 3 is the per-surface diffuse map
GL_SelectTexture ( INTERACTION_TEXUNIT_DIFFUSE ) ;
surfaceShader - > GetFastPathDiffuseImage ( ) - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 4 is the per-surface specular map
GL_SelectTexture ( INTERACTION_TEXUNIT_SPECULAR ) ;
surfaceShader - > GetFastPathSpecularImage ( ) - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( surf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
continue ;
}
renderLog . OpenBlock ( surf - > material - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
inter . bumpImage = NULL ;
inter . specularImage = NULL ;
inter . diffuseImage = NULL ;
inter . diffuseColor [ 0 ] = inter . diffuseColor [ 1 ] = inter . diffuseColor [ 2 ] = inter . diffuseColor [ 3 ] = 0 ;
inter . specularColor [ 0 ] = inter . specularColor [ 1 ] = inter . specularColor [ 2 ] = inter . specularColor [ 3 ] = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// go through the individual surface stages
//
// This is somewhat arcane because of the old support for video cards that had to render
// interactions in multiple passes.
//
// We also have the very rare case of some materials that have conditional interactions
// for the "hell writing" that can be shined on them.
2012-11-28 15:47:07 +00:00
for ( int surfaceStageNum = 0 ; surfaceStageNum < surfaceShader - > GetNumStages ( ) ; surfaceStageNum + + )
{
const shaderStage_t * surfaceStage = surfaceShader - > GetStage ( surfaceStageNum ) ;
switch ( surfaceStage - > lighting )
{
case SL_COVERAGE :
{
2012-11-26 18:58:24 +00:00
// ignore any coverage stages since they should only be used for the depth fill pass
// for diffuse stages that use alpha test.
break ;
}
2012-11-28 15:47:07 +00:00
case SL_AMBIENT :
{
2012-11-26 18:58:24 +00:00
// ignore ambient stages while drawing interactions
break ;
}
2012-11-28 15:47:07 +00:00
case SL_BUMP :
{
2012-11-26 18:58:24 +00:00
// ignore stage that fails the condition
2012-11-28 15:47:07 +00:00
if ( ! surfaceRegs [ surfaceStage - > conditionRegister ] )
{
2012-11-26 18:58:24 +00:00
break ;
}
// draw any previous interaction
2012-11-28 15:47:07 +00:00
if ( inter . bumpImage ! = NULL )
{
2012-11-26 18:58:24 +00:00
RB_DrawSingleInteraction ( & inter ) ;
}
inter . bumpImage = surfaceStage - > texture . image ;
inter . diffuseImage = NULL ;
inter . specularImage = NULL ;
RB_SetupInteractionStage ( surfaceStage , surfaceRegs , NULL ,
2012-11-28 15:47:07 +00:00
inter . bumpMatrix , NULL ) ;
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
case SL_DIFFUSE :
{
2012-11-26 18:58:24 +00:00
// ignore stage that fails the condition
2012-11-28 15:47:07 +00:00
if ( ! surfaceRegs [ surfaceStage - > conditionRegister ] )
{
2012-11-26 18:58:24 +00:00
break ;
}
// draw any previous interaction
2012-11-28 15:47:07 +00:00
if ( inter . diffuseImage ! = NULL )
{
2012-11-26 18:58:24 +00:00
RB_DrawSingleInteraction ( & inter ) ;
}
inter . diffuseImage = surfaceStage - > texture . image ;
inter . vertexColor = surfaceStage - > vertexColor ;
RB_SetupInteractionStage ( surfaceStage , surfaceRegs , diffuseColor . ToFloatPtr ( ) ,
2012-11-28 15:47:07 +00:00
inter . diffuseMatrix , inter . diffuseColor . ToFloatPtr ( ) ) ;
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
case SL_SPECULAR :
{
2012-11-26 18:58:24 +00:00
// ignore stage that fails the condition
2012-11-28 15:47:07 +00:00
if ( ! surfaceRegs [ surfaceStage - > conditionRegister ] )
{
2012-11-26 18:58:24 +00:00
break ;
}
// draw any previous interaction
2012-11-28 15:47:07 +00:00
if ( inter . specularImage ! = NULL )
{
2012-11-26 18:58:24 +00:00
RB_DrawSingleInteraction ( & inter ) ;
}
inter . specularImage = surfaceStage - > texture . image ;
inter . vertexColor = surfaceStage - > vertexColor ;
RB_SetupInteractionStage ( surfaceStage , surfaceRegs , specularColor . ToFloatPtr ( ) ,
2012-11-28 15:47:07 +00:00
inter . specularMatrix , inter . specularColor . ToFloatPtr ( ) ) ;
2012-11-26 18:58:24 +00:00
break ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw the final interaction
RB_DrawSingleInteraction ( & inter ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( useLightDepthBounds & & lightDepthBoundsDisabled )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( vLight - > scissorRect . zmin , vLight - > scissorRect . zmax ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . Unbind ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
STENCIL SHADOW RENDERING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = =
RB_StencilShadowPass
The stencil buffer should have been set to 128 on any surfaces that might receive shadows .
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_StencilShadowPass ( const drawSurf_t * drawSurfs , const viewLight_t * vLight )
{
if ( r_skipShadows . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( drawSurfs = = NULL )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " ---------- RB_StencilShadowPass ---------- \n " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Shadow ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
globalImages - > BindNull ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 glState = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// for visualizing the shadows
2012-11-28 15:47:07 +00:00
if ( r_showShadows . GetInteger ( ) )
{
2012-11-26 18:58:24 +00:00
// set the debug shadow color
SetFragmentParm ( RENDERPARM_COLOR , colorMagenta . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( r_showShadows . GetInteger ( ) = = 2 )
{
2012-11-26 18:58:24 +00:00
// draw filled in
glState = GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// draw as lines, filling the depth buffer
glState = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// don't write to the color or depth buffer, just the stencil buffer
glState = GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_PolygonOffset ( r_shadowPolygonFactor . GetFloat ( ) , - r_shadowPolygonOffset . GetFloat ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// the actual stencil func will be set in the draw code, but we need to make sure it isn't
// disabled here, and that the value will get reset for the interactions without looking
// like a no-change-required
2012-11-28 15:47:07 +00:00
GL_State ( glState | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_KEEP | GLS_STENCIL_OP_PASS_INCR |
GLS_STENCIL_MAKE_REF ( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK ( STENCIL_SHADOW_MASK_VALUE ) | GLS_POLYGON_OFFSET ) ;
2012-11-26 18:58:24 +00:00
// Two Sided Stencil reduces two draw calls to one for slightly faster shadows
GL_Cull ( CT_TWO_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// process the chain of shadows with the current rendering state
backEnd . currentSpace = NULL ;
2012-11-28 15:47:07 +00:00
for ( const drawSurf_t * drawSurf = drawSurfs ; drawSurf ! = NULL ; drawSurf = drawSurf - > nextOnLight )
{
if ( drawSurf - > scissorRect . IsEmpty ( ) )
{
2012-11-26 18:58:24 +00:00
continue ; // !@# FIXME: find out why this is sometimes being hit!
2012-11-28 15:47:07 +00:00
// temporarily jump over the scissor and draw so the gl error callback doesn't get hit
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// make sure the shadow volume is done
2012-11-28 15:47:07 +00:00
if ( drawSurf - > shadowVolumeState ! = SHADOWVOLUME_DONE )
{
2012-11-26 18:58:24 +00:00
assert ( drawSurf - > shadowVolumeState = = SHADOWVOLUME_UNFINISHED | | drawSurf - > shadowVolumeState = = SHADOWVOLUME_DONE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 start = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
while ( drawSurf - > shadowVolumeState = = SHADOWVOLUME_UNFINISHED )
{
2012-11-26 18:58:24 +00:00
Sys_Yield ( ) ;
}
uint64 end = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . pc . shadowMicroSec + = end - start ;
}
2012-11-28 15:47:07 +00:00
if ( drawSurf - > numIndexes = = 0 )
{
2012-11-26 18:58:24 +00:00
continue ; // a job may have created an empty shadow volume
}
2012-11-28 15:47:07 +00:00
if ( ! backEnd . currentScissor . Equals ( drawSurf - > scissorRect ) & & r_useScissor . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// change the scissor
GL_Scissor ( backEnd . viewDef - > viewport . x1 + drawSurf - > scissorRect . x1 ,
backEnd . viewDef - > viewport . y1 + drawSurf - > scissorRect . y1 ,
drawSurf - > scissorRect . x2 + 1 - drawSurf - > scissorRect . x1 ,
drawSurf - > scissorRect . y2 + 1 - drawSurf - > scissorRect . y1 ) ;
backEnd . currentScissor = drawSurf - > scissorRect ;
}
2012-11-28 15:47:07 +00:00
if ( drawSurf - > space ! = backEnd . currentSpace )
{
2012-11-26 18:58:24 +00:00
// change the matrix
RB_SetMVP ( drawSurf - > space - > mvp ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the local light position to allow the vertex program to project the shadow volume end cap to infinity
idVec4 localLight ( 0.0f ) ;
R_GlobalPointToLocal ( drawSurf - > space - > modelMatrix , vLight - > globalLightOrigin , localLight . ToVec3 ( ) ) ;
SetVertexParm ( RENDERPARM_LOCALLIGHTORIGIN , localLight . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = drawSurf - > space ;
}
2012-11-28 15:47:07 +00:00
if ( r_showShadows . GetInteger ( ) = = 0 )
{
if ( drawSurf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_ShadowSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Shadow ( ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
if ( drawSurf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_ShadowDebugSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_ShadowDebug ( ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set depth bounds per shadow
2012-11-28 15:47:07 +00:00
if ( r_useShadowDepthBounds . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( drawSurf - > scissorRect . zmin , drawSurf - > scissorRect . zmax ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Determine whether or not the shadow volume needs to be rendered with Z-pass or
// Z-fail. It is worthwhile to spend significant resources to reduce the number of
// cases where shadow volumes need to be rendered with Z-fail because Z-fail
// rendering can be significantly slower even on today's hardware. For instance,
// on NVIDIA hardware Z-fail rendering causes the Z-Cull to be used in reverse:
// Z-near becomes Z-far (trivial accept becomes trivial reject). Using the Z-Cull
// in reverse is far less efficient because the Z-Cull only stores Z-near per 16x16
// pixels while the Z-far is stored per 4x2 pixels. (The Z-near coallesce buffer
// which has 4x4 granularity is only used when updating the depth which is not the
// case for shadow volumes.) Note that it is also important to NOT use a Z-Cull
// reconstruct because that would clear the Z-near of the Z-Cull which results in
// no trivial rejection for Z-fail stencil shadow rendering.
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const bool renderZPass = ( drawSurf - > renderZFail = = 0 ) | | r_forceZPassStencilShadows . GetBool ( ) ;
2012-11-28 15:47:07 +00:00
if ( renderZPass )
{
2012-11-26 18:58:24 +00:00
// Z-pass
2012-12-17 16:30:59 +00:00
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_KEEP , GL_INCR ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_KEEP , GL_DECR ) ;
2012-11-28 15:47:07 +00:00
}
else if ( r_useStencilShadowPreload . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// preload + Z-pass
2012-12-17 16:30:59 +00:00
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_DECR , GL_DECR ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_INCR , GL_INCR ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// Z-fail
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get vertex buffer
const vertCacheHandle_t vbHandle = drawSurf - > shadowCache ;
2012-11-28 15:47:07 +00:00
idVertexBuffer * vertexBuffer ;
if ( vertexCache . CacheIsStatic ( vbHandle ) )
{
2012-11-26 18:58:24 +00:00
vertexBuffer = & vertexCache . staticData . vertexBuffer ;
2012-11-28 15:47:07 +00:00
}
else
{
const uint64 frameNum = ( int ) ( vbHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " RB_DrawElementsWithCounters, vertexBuffer == NULL " ) ;
continue ;
}
vertexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . vertexBuffer ;
}
2012-11-28 15:47:07 +00:00
const int vertOffset = ( int ) ( vbHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
2012-11-26 18:58:24 +00:00
// get index buffer
const vertCacheHandle_t ibHandle = drawSurf - > indexCache ;
2012-11-28 15:47:07 +00:00
idIndexBuffer * indexBuffer ;
if ( vertexCache . CacheIsStatic ( ibHandle ) )
{
2012-11-26 18:58:24 +00:00
indexBuffer = & vertexCache . staticData . indexBuffer ;
2012-11-28 15:47:07 +00:00
}
else
{
const uint64 frameNum = ( int ) ( ibHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " RB_DrawElementsWithCounters, indexBuffer == NULL " ) ;
continue ;
}
indexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . indexBuffer ;
}
2012-11-28 15:47:07 +00:00
const uint64 indexOffset = ( int ) ( ibHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " Binding Buffers: %p %p \n " , vertexBuffer , indexBuffer ) ;
2012-11-28 15:47:07 +00:00
2012-12-07 16:06:44 +00:00
// RB: 64 bit fixes, changed GLuint to GLintptrARB
if ( backEnd . glState . currentIndexBuffer ! = ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) | | ! r_useStateCaching . GetBool ( ) )
2012-11-28 15:47:07 +00:00
{
2012-12-17 16:30:59 +00:00
glBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) ) ;
2012-12-07 16:06:44 +00:00
backEnd . glState . currentIndexBuffer = ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( drawSurf - > jointCache )
{
2012-11-26 18:58:24 +00:00
assert ( renderProgManager . ShaderUsesJoints ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idJointBuffer jointBuffer ;
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . GetJointBuffer ( drawSurf - > jointCache , & jointBuffer ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " RB_DrawElementsWithCounters, jointBuffer == NULL " ) ;
continue ;
}
assert ( ( jointBuffer . GetOffset ( ) & ( glConfig . uniformBufferOffsetAlignment - 1 ) ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
2012-12-07 16:06:44 +00:00
const GLintptrARB ubo = reinterpret_cast < GLintptrARB > ( jointBuffer . GetAPIObject ( ) ) ;
2012-12-17 16:30:59 +00:00
glBindBufferRange ( GL_UNIFORM_BUFFER , 0 , ubo , jointBuffer . GetOffset ( ) , jointBuffer . GetNumJoints ( ) * sizeof ( idJointMat ) ) ;
2012-11-28 15:47:07 +00:00
2012-12-07 16:06:44 +00:00
if ( ( backEnd . glState . vertexLayout ! = LAYOUT_DRAW_SHADOW_VERT_SKINNED ) | | ( backEnd . glState . currentVertexBuffer ! = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) | | ! r_useStateCaching . GetBool ( ) )
2012-11-28 15:47:07 +00:00
{
2012-12-17 16:30:59 +00:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) ;
2012-12-07 16:06:44 +00:00
backEnd . glState . currentVertexBuffer = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ;
2012-11-28 15:47:07 +00:00
2012-12-17 16:30:59 +00:00
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_VERTEX ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_NORMAL ) ;
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR ) ;
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR2 ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_ST ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_TANGENT ) ;
2012-11-28 15:47:07 +00:00
2012-12-17 16:30:59 +00:00
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_XYZW_OFFSET ) ) ;
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_COLOR_OFFSET ) ) ;
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR2 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_COLOR2_OFFSET ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . glState . vertexLayout = LAYOUT_DRAW_SHADOW_VERT_SKINNED ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-12-07 16:06:44 +00:00
if ( ( backEnd . glState . vertexLayout ! = LAYOUT_DRAW_SHADOW_VERT ) | | ( backEnd . glState . currentVertexBuffer ! = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) | | ! r_useStateCaching . GetBool ( ) )
2012-11-28 15:47:07 +00:00
{
2012-12-17 16:30:59 +00:00
glBindBufferARB ( GL_ARRAY_BUFFER_ARB , ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) ;
2012-12-07 16:06:44 +00:00
backEnd . glState . currentVertexBuffer = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ;
2012-11-28 15:47:07 +00:00
2012-12-17 16:30:59 +00:00
glEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_VERTEX ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_NORMAL ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR2 ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_ST ) ;
glDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_TANGENT ) ;
2012-11-28 15:47:07 +00:00
2012-12-17 16:30:59 +00:00
glVertexAttribPointerARB ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVert ) , ( void * ) ( SHADOWVERT_XYZW_OFFSET ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . glState . vertexLayout = LAYOUT_DRAW_SHADOW_VERT ;
}
}
2012-12-07 16:06:44 +00:00
// RB end
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . CommitUniforms ( ) ;
2012-11-28 15:47:07 +00:00
if ( drawSurf - > jointCache )
{
2012-12-17 16:30:59 +00:00
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVertSkinned ) ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
else
{
2012-12-17 16:30:59 +00:00
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVert ) ) ;
2012-11-28 15:47:07 +00:00
}
2014-04-20 14:29:58 +00:00
// RB: added stats
backEnd . pc . c_shadowElements + + ;
backEnd . pc . c_shadowIndexes + = drawSurf - > numIndexes ;
// RB end
2012-11-28 15:47:07 +00:00
if ( ! renderZPass & & r_useStencilShadowPreload . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// render again with Z-pass
2012-12-17 16:30:59 +00:00
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_KEEP , GL_INCR ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_KEEP , GL_DECR ) ;
2012-11-28 15:47:07 +00:00
if ( drawSurf - > jointCache )
{
2012-12-17 16:30:59 +00:00
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVertSkinned ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-12-17 16:30:59 +00:00
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVert ) ) ;
2012-11-26 18:58:24 +00:00
}
2014-04-20 14:29:58 +00:00
// RB: added stats
backEnd . pc . c_shadowElements + + ;
backEnd . pc . c_shadowIndexes + = drawSurf - > numIndexes ;
// RB end
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// cleanup the shadow specific rendering state
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_Cull ( CT_FRONT_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// reset depth bounds
2012-11-28 15:47:07 +00:00
if ( r_useShadowDepthBounds . GetBool ( ) )
{
if ( r_useLightDepthBounds . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( vLight - > scissorRect . zmin , vLight - > scissorRect . zmax ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( 0.0f , 0.0f ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
RB_StencilSelectLight
Deform the zeroOneCubeModel to exactly cover the light volume . Render the deformed cube model to the stencil buffer in
2012-11-28 15:47:07 +00:00
such a way that only fragments that are directly visible and contained within the volume will be written creating a
2012-11-26 18:58:24 +00:00
mask to be used by the following stencil shadow and draw interaction passes .
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_StencilSelectLight ( const viewLight_t * vLight )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " Stencil Select " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// enable the light scissor
2012-11-28 15:47:07 +00:00
if ( ! backEnd . currentScissor . Equals ( vLight - > scissorRect ) & & r_useScissor . GetBool ( ) )
{
GL_Scissor ( backEnd . viewDef - > viewport . x1 + vLight - > scissorRect . x1 ,
2012-11-26 18:58:24 +00:00
backEnd . viewDef - > viewport . y1 + vLight - > scissorRect . y1 ,
vLight - > scissorRect . x2 + 1 - vLight - > scissorRect . x1 ,
vLight - > scissorRect . y2 + 1 - vLight - > scissorRect . y1 ) ;
backEnd . currentScissor = vLight - > scissorRect ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear stencil buffer to 0 (not drawable)
uint64 glStateMinusStencil = GL_GetCurrentStateMinusStencil ( ) ;
GL_State ( glStateMinusStencil | GLS_STENCIL_FUNC_ALWAYS | GLS_STENCIL_MAKE_REF ( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK ( STENCIL_SHADOW_MASK_VALUE ) ) ; // make sure stencil mask passes for the clear
GL_Clear ( false , false , true , 0 , 0.0f , 0.0f , 0.0f , 0.0f ) ; // clear to 0 for stencil select
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the depthbounds
GL_DepthBoundsTest ( vLight - > scissorRect . zmin , vLight - > scissorRect . zmax ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_State ( GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS | GLS_STENCIL_FUNC_ALWAYS | GLS_STENCIL_MAKE_REF ( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK ( STENCIL_SHADOW_MASK_VALUE ) ) ;
GL_Cull ( CT_TWO_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Depth ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the matrix for deforming the 'zeroOneCubeModel' into the frustum to exactly cover the light volume
idRenderMatrix invProjectMVPMatrix ;
idRenderMatrix : : Multiply ( backEnd . viewDef - > worldSpace . mvp , vLight - > inverseBaseLightProject , invProjectMVPMatrix ) ;
RB_SetMVP ( invProjectMVPMatrix ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// two-sided stencil test
2012-12-17 16:30:59 +00:00
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_REPLACE , GL_ZERO ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_ZERO , GL_REPLACE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( & backEnd . zeroOneCubeSurface ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// reset stencil state
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_Cull ( CT_FRONT_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . Unbind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// unset the depthbounds
GL_DepthBoundsTest ( 0.0f , 0.0f ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2014-05-10 12:40:01 +00:00
SHADOW MAPS RENDERING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
same as D3DXMatrixOrthoOffCenterRH
http : //msdn.microsoft.com/en-us/library/bb205348(VS.85).aspx
*/
static void MatrixOrthogonalProjectionRH ( float m [ 16 ] , float left , float right , float bottom , float top , float zNear , float zFar )
{
m [ 0 ] = 2 / ( right - left ) ;
m [ 4 ] = 0 ;
m [ 8 ] = 0 ;
m [ 12 ] = ( left + right ) / ( left - right ) ;
m [ 1 ] = 0 ;
m [ 5 ] = 2 / ( top - bottom ) ;
m [ 9 ] = 0 ;
m [ 13 ] = ( top + bottom ) / ( bottom - top ) ;
m [ 2 ] = 0 ;
m [ 6 ] = 0 ;
m [ 10 ] = 1 / ( zNear - zFar ) ;
m [ 14 ] = zNear / ( zNear - zFar ) ;
m [ 3 ] = 0 ;
m [ 7 ] = 0 ;
m [ 11 ] = 0 ;
m [ 15 ] = 1 ;
}
void MatrixCrop ( float m [ 16 ] , const idVec3 mins , const idVec3 maxs )
{
float scaleX , scaleY , scaleZ ;
float offsetX , offsetY , offsetZ ;
scaleX = 2.0f / ( maxs [ 0 ] - mins [ 0 ] ) ;
scaleY = 2.0f / ( maxs [ 1 ] - mins [ 1 ] ) ;
offsetX = - 0.5f * ( maxs [ 0 ] + mins [ 0 ] ) * scaleX ;
offsetY = - 0.5f * ( maxs [ 1 ] + mins [ 1 ] ) * scaleY ;
scaleZ = 1.0f / ( maxs [ 2 ] - mins [ 2 ] ) ;
offsetZ = - mins [ 2 ] * scaleZ ;
m [ 0 ] = scaleX ;
m [ 4 ] = 0 ;
m [ 8 ] = 0 ;
m [ 12 ] = offsetX ;
m [ 1 ] = 0 ;
m [ 5 ] = scaleY ;
m [ 9 ] = 0 ;
m [ 13 ] = offsetY ;
m [ 2 ] = 0 ;
m [ 6 ] = 0 ;
m [ 10 ] = scaleZ ;
m [ 14 ] = offsetZ ;
m [ 3 ] = 0 ;
m [ 7 ] = 0 ;
m [ 11 ] = 0 ;
m [ 15 ] = 1 ;
}
void MatrixLookAtRH ( float m [ 16 ] , const idVec3 & eye , const idVec3 & dir , const idVec3 & up )
{
idVec3 dirN ;
idVec3 upN ;
idVec3 sideN ;
sideN = dir . Cross ( up ) ;
sideN . Normalize ( ) ;
upN = sideN . Cross ( dir ) ;
upN . Normalize ( ) ;
dirN = dir ;
dirN . Normalize ( ) ;
m [ 0 ] = sideN [ 0 ] ;
m [ 4 ] = sideN [ 1 ] ;
m [ 8 ] = sideN [ 2 ] ;
m [ 12 ] = - ( sideN * eye ) ;
m [ 1 ] = upN [ 0 ] ;
m [ 5 ] = upN [ 1 ] ;
m [ 9 ] = upN [ 2 ] ;
m [ 13 ] = - ( upN * eye ) ;
m [ 2 ] = - dirN [ 0 ] ;
m [ 6 ] = - dirN [ 1 ] ;
m [ 10 ] = - dirN [ 2 ] ;
m [ 14 ] = ( dirN * eye ) ;
m [ 3 ] = 0 ;
m [ 7 ] = 0 ;
m [ 11 ] = 0 ;
m [ 15 ] = 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = =
RB_ShadowMapPass
= = = = = = = = = = = = = = = = = = = = =
*/
static void RB_ShadowMapPass ( const drawSurf_t * drawSurfs , const viewLight_t * vLight , int side )
{
if ( r_skipShadows . GetBool ( ) )
{
return ;
}
if ( drawSurfs = = NULL )
{
return ;
}
RENDERLOG_PRINTF ( " ---------- RB_ShadowMapPass( side = %i ) ---------- \n " , side ) ;
renderProgManager . BindShader_Depth ( ) ;
GL_SelectTexture ( 0 ) ;
globalImages - > BindNull ( ) ;
uint64 glState = 0 ;
GL_PolygonOffset ( r_shadowPolygonFactor . GetFloat ( ) , - r_shadowPolygonOffset . GetFloat ( ) ) ;
// the actual stencil func will be set in the draw code, but we need to make sure it isn't
// disabled here, and that the value will get reset for the interactions without looking
// like a no-change-required
GL_State ( glState | GLS_POLYGON_OFFSET ) ;
// Two Sided Stencil reduces two draw calls to one for slightly faster shadows
GL_Cull ( CT_TWO_SIDED ) ;
idRenderMatrix lightProjectionRenderMatrix ;
idRenderMatrix lightViewRenderMatrix ;
if ( vLight - > parallel & & side > = 0 )
{
assert ( side > = 0 & & side < 6 ) ;
// original light direction is from surface to light origin
idVec3 lightDir = - vLight - > lightCenter ;
if ( lightDir . Normalize ( ) = = 0.0f )
{
lightDir [ 2 ] = - 1.0f ;
}
idMat3 rotation = lightDir . ToMat3 ( ) ;
//idAngles angles = lightDir.ToAngles();
//idMat3 rotation = angles.ToMat3();
const idVec3 viewDir = backEnd . viewDef - > renderView . viewaxis [ 0 ] ;
const idVec3 viewPos = backEnd . viewDef - > renderView . vieworg ;
# if 1
idRenderMatrix : : CreateViewMatrix ( backEnd . viewDef - > renderView . vieworg , rotation , lightViewRenderMatrix ) ;
# else
float lightViewMatrix [ 16 ] ;
MatrixLookAtRH ( lightViewMatrix , viewPos , lightDir , viewDir ) ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) lightViewMatrix , lightViewRenderMatrix ) ;
# endif
idBounds lightBounds ;
lightBounds . Clear ( ) ;
ALIGNTYPE16 frustumCorners_t corners ;
idRenderMatrix : : GetFrustumCorners ( corners , vLight - > inverseBaseLightProject , bounds_zeroOneCube ) ;
idVec4 point , transf ;
for ( int j = 0 ; j < 8 ; j + + )
{
point [ 0 ] = corners . x [ j ] ;
point [ 1 ] = corners . y [ j ] ;
point [ 2 ] = corners . z [ j ] ;
point [ 3 ] = 1 ;
lightViewRenderMatrix . TransformPoint ( point , transf ) ;
transf [ 0 ] / = transf [ 3 ] ;
transf [ 1 ] / = transf [ 3 ] ;
transf [ 2 ] / = transf [ 3 ] ;
lightBounds . AddPoint ( transf . ToVec3 ( ) ) ;
}
float lightProjectionMatrix [ 16 ] ;
MatrixOrthogonalProjectionRH ( lightProjectionMatrix , lightBounds [ 0 ] [ 0 ] , lightBounds [ 1 ] [ 0 ] , lightBounds [ 0 ] [ 1 ] , lightBounds [ 1 ] [ 1 ] , - lightBounds [ 1 ] [ 2 ] , - lightBounds [ 0 ] [ 2 ] ) ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) lightProjectionMatrix , lightProjectionRenderMatrix ) ;
// 'frustumMVP' goes from global space -> camera local space -> camera projective space
// invert the MVP projection so we can deform zero-to-one cubes into the frustum pyramid shape and calculate global bounds
idRenderMatrix splitFrustumInverse ;
if ( ! idRenderMatrix : : Inverse ( backEnd . viewDef - > frustumMVPs [ FRUSTUM_CASCADE1 + side ] , splitFrustumInverse ) )
{
idLib : : Warning ( " splitFrustumMVP invert failed " ) ;
}
// splitFrustumCorners in global space
ALIGNTYPE16 frustumCorners_t splitFrustumCorners ;
idRenderMatrix : : GetFrustumCorners ( splitFrustumCorners , splitFrustumInverse , bounds_unitCube ) ;
#if 0
idBounds splitFrustumBounds ;
splitFrustumBounds . Clear ( ) ;
for ( int j = 0 ; j < 8 ; j + + )
{
point [ 0 ] = splitFrustumCorners . x [ j ] ;
point [ 1 ] = splitFrustumCorners . y [ j ] ;
point [ 2 ] = splitFrustumCorners . z [ j ] ;
splitFrustumBounds . AddPoint ( point . ToVec3 ( ) ) ;
}
idVec3 center = splitFrustumBounds . GetCenter ( ) ;
float radius = splitFrustumBounds . GetRadius ( center ) ;
//ALIGNTYPE16 frustumCorners_t splitFrustumCorners;
splitFrustumBounds [ 0 ] = idVec3 ( - radius , - radius , - radius ) ;
splitFrustumBounds [ 1 ] = idVec3 ( radius , radius , radius ) ;
splitFrustumBounds . TranslateSelf ( viewPos ) ;
idVec3 splitFrustumCorners2 [ 8 ] ;
splitFrustumBounds . ToPoints ( splitFrustumCorners2 ) ;
for ( int j = 0 ; j < 8 ; j + + )
{
splitFrustumCorners . x [ j ] = splitFrustumCorners2 [ j ] . x ;
splitFrustumCorners . y [ j ] = splitFrustumCorners2 [ j ] . y ;
splitFrustumCorners . z [ j ] = splitFrustumCorners2 [ j ] . z ;
}
# endif
idRenderMatrix lightViewProjectionRenderMatrix ;
idRenderMatrix : : Multiply ( lightProjectionRenderMatrix , lightViewRenderMatrix , lightViewProjectionRenderMatrix ) ;
// find the bounding box of the current split in the light's clip space
idBounds cropBounds ;
cropBounds . Clear ( ) ;
for ( int j = 0 ; j < 8 ; j + + )
{
point [ 0 ] = splitFrustumCorners . x [ j ] ;
point [ 1 ] = splitFrustumCorners . y [ j ] ;
point [ 2 ] = splitFrustumCorners . z [ j ] ;
point [ 3 ] = 1 ;
lightViewRenderMatrix . TransformPoint ( point , transf ) ;
transf [ 0 ] / = transf [ 3 ] ;
transf [ 1 ] / = transf [ 3 ] ;
transf [ 2 ] / = transf [ 3 ] ;
cropBounds . AddPoint ( transf . ToVec3 ( ) ) ;
}
// don't let the frustum AABB be bigger than the light AABB
if ( cropBounds [ 0 ] [ 0 ] < lightBounds [ 0 ] [ 0 ] )
{
cropBounds [ 0 ] [ 0 ] = lightBounds [ 0 ] [ 0 ] ;
}
if ( cropBounds [ 0 ] [ 1 ] < lightBounds [ 0 ] [ 1 ] )
{
cropBounds [ 0 ] [ 1 ] = lightBounds [ 0 ] [ 1 ] ;
}
if ( cropBounds [ 1 ] [ 0 ] > lightBounds [ 1 ] [ 0 ] )
{
cropBounds [ 1 ] [ 0 ] = lightBounds [ 1 ] [ 0 ] ;
}
if ( cropBounds [ 1 ] [ 1 ] > lightBounds [ 1 ] [ 1 ] )
{
cropBounds [ 1 ] [ 1 ] = lightBounds [ 1 ] [ 1 ] ;
}
cropBounds [ 0 ] [ 2 ] = lightBounds [ 0 ] [ 2 ] ;
cropBounds [ 1 ] [ 2 ] = lightBounds [ 1 ] [ 2 ] ;
//float cropMatrix[16];
//MatrixCrop(cropMatrix, cropBounds[0], cropBounds[1]);
//idRenderMatrix cropRenderMatrix;
//idRenderMatrix::Transpose( *( idRenderMatrix* )cropMatrix, cropRenderMatrix );
//idRenderMatrix tmp = lightProjectionRenderMatrix;
//idRenderMatrix::Multiply( cropRenderMatrix, tmp, lightProjectionRenderMatrix );
MatrixOrthogonalProjectionRH ( lightProjectionMatrix , cropBounds [ 0 ] [ 0 ] , cropBounds [ 1 ] [ 0 ] , cropBounds [ 0 ] [ 1 ] , cropBounds [ 1 ] [ 1 ] , - cropBounds [ 1 ] [ 2 ] , - cropBounds [ 0 ] [ 2 ] ) ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) lightProjectionMatrix , lightProjectionRenderMatrix ) ;
backEnd . shadowV [ side ] = lightViewRenderMatrix ;
backEnd . shadowP [ side ] = lightProjectionRenderMatrix ;
}
else if ( vLight - > pointLight & & side > = 0 )
{
assert ( side > = 0 & & side < 6 ) ;
// FIXME OPTIMIZE no memset
float viewMatrix [ 16 ] ;
idVec3 vec ;
idVec3 origin = vLight - > globalLightOrigin ;
// side of a point light
memset ( viewMatrix , 0 , sizeof ( viewMatrix ) ) ;
switch ( side )
{
case 0 :
viewMatrix [ 0 ] = 1 ;
viewMatrix [ 9 ] = 1 ;
viewMatrix [ 6 ] = - 1 ;
break ;
case 1 :
viewMatrix [ 0 ] = - 1 ;
viewMatrix [ 9 ] = - 1 ;
viewMatrix [ 6 ] = - 1 ;
break ;
case 2 :
viewMatrix [ 4 ] = 1 ;
viewMatrix [ 1 ] = - 1 ;
viewMatrix [ 10 ] = 1 ;
break ;
case 3 :
viewMatrix [ 4 ] = - 1 ;
viewMatrix [ 1 ] = - 1 ;
viewMatrix [ 10 ] = - 1 ;
break ;
case 4 :
viewMatrix [ 8 ] = 1 ;
viewMatrix [ 1 ] = - 1 ;
viewMatrix [ 6 ] = - 1 ;
break ;
case 5 :
viewMatrix [ 8 ] = - 1 ;
viewMatrix [ 1 ] = 1 ;
viewMatrix [ 6 ] = - 1 ;
break ;
}
viewMatrix [ 12 ] = - origin [ 0 ] * viewMatrix [ 0 ] + - origin [ 1 ] * viewMatrix [ 4 ] + - origin [ 2 ] * viewMatrix [ 8 ] ;
viewMatrix [ 13 ] = - origin [ 0 ] * viewMatrix [ 1 ] + - origin [ 1 ] * viewMatrix [ 5 ] + - origin [ 2 ] * viewMatrix [ 9 ] ;
viewMatrix [ 14 ] = - origin [ 0 ] * viewMatrix [ 2 ] + - origin [ 1 ] * viewMatrix [ 6 ] + - origin [ 2 ] * viewMatrix [ 10 ] ;
viewMatrix [ 3 ] = 0 ;
viewMatrix [ 7 ] = 0 ;
viewMatrix [ 11 ] = 0 ;
viewMatrix [ 15 ] = 1 ;
// from world space to light origin, looking down the X axis
float unflippedLightViewMatrix [ 16 ] ;
// from world space to OpenGL view space, looking down the negative Z axis
float lightViewMatrix [ 16 ] ;
static float s_flipMatrix [ 16 ] =
{
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
0 , 0 , - 1 , 0 ,
- 1 , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 0 , 1
} ;
memcpy ( unflippedLightViewMatrix , viewMatrix , sizeof ( unflippedLightViewMatrix ) ) ;
R_MatrixMultiply ( viewMatrix , s_flipMatrix , lightViewMatrix ) ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) lightViewMatrix , lightViewRenderMatrix ) ;
// set up 90 degree projection matrix
const float zNear = 4 ;
const float fov = r_shadowMapFrustumFOV . GetFloat ( ) ;
float ymax = zNear * tan ( fov * idMath : : PI / 360.0f ) ;
float ymin = - ymax ;
float xmax = zNear * tan ( fov * idMath : : PI / 360.0f ) ;
float xmin = - xmax ;
const float width = xmax - xmin ;
const float height = ymax - ymin ;
// from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ )
float lightProjectionMatrix [ 16 ] ;
lightProjectionMatrix [ 0 * 4 + 0 ] = 2.0f * zNear / width ;
lightProjectionMatrix [ 1 * 4 + 0 ] = 0.0f ;
lightProjectionMatrix [ 2 * 4 + 0 ] = ( xmax + xmin ) / width ; // normally 0
lightProjectionMatrix [ 3 * 4 + 0 ] = 0.0f ;
lightProjectionMatrix [ 0 * 4 + 1 ] = 0.0f ;
lightProjectionMatrix [ 1 * 4 + 1 ] = 2.0f * zNear / height ;
lightProjectionMatrix [ 2 * 4 + 1 ] = ( ymax + ymin ) / height ; // normally 0
lightProjectionMatrix [ 3 * 4 + 1 ] = 0.0f ;
// this is the far-plane-at-infinity formulation, and
// crunches the Z range slightly so w=0 vertexes do not
// rasterize right at the wraparound point
lightProjectionMatrix [ 0 * 4 + 2 ] = 0.0f ;
lightProjectionMatrix [ 1 * 4 + 2 ] = 0.0f ;
lightProjectionMatrix [ 2 * 4 + 2 ] = - 0.999f ; // adjust value to prevent imprecision issues
lightProjectionMatrix [ 3 * 4 + 2 ] = - 2.0f * zNear ;
lightProjectionMatrix [ 0 * 4 + 3 ] = 0.0f ;
lightProjectionMatrix [ 1 * 4 + 3 ] = 0.0f ;
lightProjectionMatrix [ 2 * 4 + 3 ] = - 1.0f ;
lightProjectionMatrix [ 3 * 4 + 3 ] = 0.0f ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) lightProjectionMatrix , lightProjectionRenderMatrix ) ;
backEnd . shadowV [ side ] = lightViewRenderMatrix ;
backEnd . shadowP [ side ] = lightProjectionRenderMatrix ;
}
else
{
lightViewRenderMatrix . Identity ( ) ;
lightProjectionRenderMatrix = vLight - > baseLightProject ;
backEnd . shadowV [ 0 ] = lightViewRenderMatrix ;
backEnd . shadowP [ 0 ] = lightProjectionRenderMatrix ;
}
globalFramebuffers . shadowFBO - > Bind ( ) ;
if ( side < 0 )
{
globalFramebuffers . shadowFBO - > AttachImageDepthLayer ( globalImages - > shadowImage , 0 ) ;
}
else
{
globalFramebuffers . shadowFBO - > AttachImageDepthLayer ( globalImages - > shadowImage , side ) ;
}
globalFramebuffers . shadowFBO - > Check ( ) ;
GL_ViewportAndScissor ( 0 , 0 , r_shadowMapImageSize . GetInteger ( ) , r_shadowMapImageSize . GetInteger ( ) ) ;
glClear ( GL_DEPTH_BUFFER_BIT ) ;
// process the chain of shadows with the current rendering state
backEnd . currentSpace = NULL ;
for ( const drawSurf_t * drawSurf = drawSurfs ; drawSurf ! = NULL ; drawSurf = drawSurf - > nextOnLight )
{
# if 1
// make sure the shadow occluder geometry is done
if ( drawSurf - > shadowVolumeState ! = SHADOWVOLUME_DONE )
{
assert ( drawSurf - > shadowVolumeState = = SHADOWVOLUME_UNFINISHED | | drawSurf - > shadowVolumeState = = SHADOWVOLUME_DONE ) ;
uint64 start = Sys_Microseconds ( ) ;
while ( drawSurf - > shadowVolumeState = = SHADOWVOLUME_UNFINISHED )
{
Sys_Yield ( ) ;
}
uint64 end = Sys_Microseconds ( ) ;
backEnd . pc . shadowMicroSec + = end - start ;
}
# endif
if ( drawSurf - > numIndexes = = 0 )
{
continue ; // a job may have created an empty shadow geometry
}
if ( drawSurf - > space ! = backEnd . currentSpace )
{
idRenderMatrix modelRenderMatrix ;
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) drawSurf - > space - > modelMatrix , modelRenderMatrix ) ;
idRenderMatrix modelToLightRenderMatrix ;
idRenderMatrix : : Multiply ( lightViewRenderMatrix , modelRenderMatrix , modelToLightRenderMatrix ) ;
idRenderMatrix clipMVP ;
idRenderMatrix : : Multiply ( lightProjectionRenderMatrix , modelToLightRenderMatrix , clipMVP ) ;
if ( vLight - > parallel )
{
idRenderMatrix MVP ;
idRenderMatrix : : Multiply ( renderMatrix_clipSpaceToWindowSpace , clipMVP , MVP ) ;
RB_SetMVP ( clipMVP ) ;
}
else if ( side < 0 )
{
// from OpenGL view space to OpenGL NDC ( -1 : 1 in XYZ )
idRenderMatrix MVP ;
idRenderMatrix : : Multiply ( renderMatrix_windowSpaceToClipSpace , clipMVP , MVP ) ;
RB_SetMVP ( MVP ) ;
}
else
{
RB_SetMVP ( clipMVP ) ;
}
// set the local light position to allow the vertex program to project the shadow volume end cap to infinity
/*
idVec4 localLight ( 0.0f ) ;
R_GlobalPointToLocal ( drawSurf - > space - > modelMatrix , vLight - > globalLightOrigin , localLight . ToVec3 ( ) ) ;
SetVertexParm ( RENDERPARM_LOCALLIGHTORIGIN , localLight . ToFloatPtr ( ) ) ;
*/
backEnd . currentSpace = drawSurf - > space ;
}
if ( drawSurf - > jointCache )
{
renderProgManager . BindShader_DepthSkinned ( ) ;
}
else
{
renderProgManager . BindShader_Depth ( ) ;
}
RB_DrawElementsWithCounters ( drawSurf ) ;
}
// cleanup the shadow specific rendering state
Framebuffer : : BindNull ( ) ;
GL_Cull ( CT_FRONT_SIDED ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2012-11-26 18:58:24 +00:00
DRAW INTERACTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
RB_DrawInteractions
= = = = = = = = = = = = = = = = = =
*/
2014-05-10 12:40:01 +00:00
static void RB_DrawInteractions ( const viewDef_t * viewDef )
2012-11-28 15:47:07 +00:00
{
if ( r_skipInteractions . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . OpenMainBlock ( MRB_DRAW_INTERACTIONS ) ;
renderLog . OpenBlock ( " RB_DrawInteractions " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
2014-05-10 12:40:01 +00:00
const bool useLightDepthBounds = r_useLightDepthBounds . GetBool ( ) & & ! r_useShadowMapping . GetBool ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//
// for each light, perform shadowing and adding
//
2012-11-28 15:47:07 +00:00
for ( const viewLight_t * vLight = backEnd . viewDef - > viewLights ; vLight ! = NULL ; vLight = vLight - > next )
{
2012-11-26 18:58:24 +00:00
// do fogging later
2012-11-28 15:47:07 +00:00
if ( vLight - > lightShader - > IsFogLight ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( vLight - > lightShader - > IsBlendLight ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( vLight - > localInteractions = = NULL & & vLight - > globalInteractions = = NULL & & vLight - > translucentInteractions = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
const idMaterial * lightShader = vLight - > lightShader ;
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( lightShader - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the depth bounds for the whole light
2012-11-28 15:47:07 +00:00
if ( useLightDepthBounds )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( vLight - > scissorRect . zmin , vLight - > scissorRect . zmax ) ;
}
2012-11-28 15:47:07 +00:00
2014-05-10 12:40:01 +00:00
// RB: shadow mapping
if ( r_useShadowMapping . GetBool ( ) )
2012-11-28 15:47:07 +00:00
{
2014-05-10 12:40:01 +00:00
int side , sideStop ;
if ( vLight - > parallel )
2012-11-28 15:47:07 +00:00
{
2014-05-10 12:40:01 +00:00
side = 0 ;
sideStop = r_shadowMapSplits . GetInteger ( ) + 1 ;
2012-11-28 15:47:07 +00:00
}
2014-05-10 12:40:01 +00:00
else if ( vLight - > pointLight )
2012-11-28 15:47:07 +00:00
{
2014-05-10 12:40:01 +00:00
if ( r_shadowMapSingleSide . GetInteger ( ) ! = - 1 )
2012-11-28 15:47:07 +00:00
{
2014-05-10 12:40:01 +00:00
side = r_shadowMapSingleSide . GetInteger ( ) ;
sideStop = side + 1 ;
}
else
{
side = 0 ;
sideStop = 6 ;
2012-11-26 18:58:24 +00:00
}
2014-05-10 12:40:01 +00:00
}
else
{
side = - 1 ;
sideStop = 0 ;
}
for ( ; side < sideStop ; side + + )
{
RB_ShadowMapPass ( vLight - > globalShadows , vLight , side ) ;
}
// go back from light view to default camera view
RB_ResetViewportAndScissorToDefaultCamera ( viewDef ) ;
if ( vLight - > localInteractions ! = NULL )
{
renderLog . OpenBlock ( " Local Light Interactions " ) ;
RB_RenderInteractions ( vLight - > localInteractions , vLight , GLS_DEPTHFUNC_EQUAL , false , useLightDepthBounds ) ;
renderLog . CloseBlock ( ) ;
}
if ( vLight - > globalInteractions ! = NULL )
{
renderLog . OpenBlock ( " Global Light Interactions " ) ;
RB_RenderInteractions ( vLight - > globalInteractions , vLight , GLS_DEPTHFUNC_EQUAL , false , useLightDepthBounds ) ;
renderLog . CloseBlock ( ) ;
2012-11-26 18:58:24 +00:00
}
}
2014-05-10 12:40:01 +00:00
else
2012-11-28 15:47:07 +00:00
{
2014-05-10 12:40:01 +00:00
// only need to clear the stencil buffer and perform stencil testing if there are shadows
const bool performStencilTest = ( vLight - > globalShadows ! = NULL | | vLight - > localShadows ! = NULL ) & & ! r_useShadowMapping . GetBool ( ) ;
// mirror flips the sense of the stencil select, and I don't want to risk accidentally breaking it
// in the normal case, so simply disable the stencil select in the mirror case
const bool useLightStencilSelect = ( r_useLightStencilSelect . GetBool ( ) & & backEnd . viewDef - > isMirror = = false ) ;
if ( performStencilTest )
{
if ( useLightStencilSelect )
{
// write a stencil mask for the visible light bounds to hi-stencil
RB_StencilSelectLight ( vLight ) ;
}
else
{
// always clear whole S-Cull tiles
idScreenRect rect ;
rect . x1 = ( vLight - > scissorRect . x1 + 0 ) & ~ 15 ;
rect . y1 = ( vLight - > scissorRect . y1 + 0 ) & ~ 15 ;
rect . x2 = ( vLight - > scissorRect . x2 + 15 ) & ~ 15 ;
rect . y2 = ( vLight - > scissorRect . y2 + 15 ) & ~ 15 ;
if ( ! backEnd . currentScissor . Equals ( rect ) & & r_useScissor . GetBool ( ) )
{
GL_Scissor ( backEnd . viewDef - > viewport . x1 + rect . x1 ,
backEnd . viewDef - > viewport . y1 + rect . y1 ,
rect . x2 + 1 - rect . x1 ,
rect . y2 + 1 - rect . y1 ) ;
backEnd . currentScissor = rect ;
}
GL_State ( GLS_DEFAULT ) ; // make sure stencil mask passes for the clear
GL_Clear ( false , false , true , STENCIL_SHADOW_TEST_VALUE , 0.0f , 0.0f , 0.0f , 0.0f ) ;
}
}
if ( vLight - > globalShadows ! = NULL )
{
renderLog . OpenBlock ( " Global Light Shadows " ) ;
RB_StencilShadowPass ( vLight - > globalShadows , vLight ) ;
renderLog . CloseBlock ( ) ;
}
if ( vLight - > localInteractions ! = NULL )
{
renderLog . OpenBlock ( " Local Light Interactions " ) ;
RB_RenderInteractions ( vLight - > localInteractions , vLight , GLS_DEPTHFUNC_EQUAL , performStencilTest , useLightDepthBounds ) ;
renderLog . CloseBlock ( ) ;
}
if ( vLight - > localShadows ! = NULL )
{
renderLog . OpenBlock ( " Local Light Shadows " ) ;
RB_StencilShadowPass ( vLight - > localShadows , vLight ) ;
renderLog . CloseBlock ( ) ;
}
if ( vLight - > globalInteractions ! = NULL )
{
renderLog . OpenBlock ( " Global Light Interactions " ) ;
RB_RenderInteractions ( vLight - > globalInteractions , vLight , GLS_DEPTHFUNC_EQUAL , performStencilTest , useLightDepthBounds ) ;
renderLog . CloseBlock ( ) ;
}
2012-11-26 18:58:24 +00:00
}
2014-05-10 12:40:01 +00:00
// RB end
2012-11-28 15:47:07 +00:00
if ( vLight - > translucentInteractions ! = NULL & & ! r_skipTranslucent . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " Translucent Interactions " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Disable the depth bounds test because translucent surfaces don't work with
// the depth bounds tests since they did not write depth during the depth pass.
2012-11-28 15:47:07 +00:00
if ( useLightDepthBounds )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( 0.0f , 0.0f ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// The depth buffer wasn't filled in for translucent surfaces, so they
// can never be constrained to perforated surfaces with the depthfunc equal.
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Translucent surfaces do not receive shadows. This is a case where a
// shadow buffer solution would work but stencil shadows do not because
// stencil shadows only affect surfaces that contribute to the view depth
// buffer and translucent surfaces do not contribute to the view depth buffer.
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_RenderInteractions ( vLight - > translucentInteractions , vLight , GLS_DEPTHFUNC_LESS , false , false ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// disable stencil shadow test
GL_State ( GLS_DEFAULT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// unbind texture units
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 5 ; i + + )
{
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( i ) ;
globalImages - > BindNull ( ) ;
}
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// reset depth bounds
2012-11-28 15:47:07 +00:00
if ( useLightDepthBounds )
{
2012-11-26 18:58:24 +00:00
GL_DepthBoundsTest ( 0.0f , 0.0f ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
renderLog . CloseMainBlock ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
NON - INTERACTION SHADER PASSES
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = =
RB_DrawShaderPasses
Draw non - light dependent passes
If we are rendering Guis , the drawSurf_t : : sort value is a depth offset that can
be multiplied by guiEye for polarity and screenSeparation for scale .
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static int RB_DrawShaderPasses ( const drawSurf_t * const * const drawSurfs , const int numDrawSurfs ,
const float guiStereoScreenOffset , const int stereoEye )
{
2012-11-26 18:58:24 +00:00
// only obey skipAmbient if we are rendering a view
2012-11-28 15:47:07 +00:00
if ( backEnd . viewDef - > viewEntitys & & r_skipAmbient . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return numDrawSurfs ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " RB_DrawShaderPasses " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 1 ) ;
globalImages - > BindNull ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
backEnd . currentSpace = ( const viewEntity_t * ) 1 ; // using NULL makes /analyze think surf->space needs to be checked...
2012-11-26 18:58:24 +00:00
float currentGuiStereoOffset = 0.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int i = 0 ;
2012-11-28 15:47:07 +00:00
for ( ; i < numDrawSurfs ; i + + )
{
const drawSurf_t * surf = drawSurfs [ i ] ;
const idMaterial * shader = surf - > material ;
if ( ! shader - > HasAmbient ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( shader - > IsPortalSky ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// some deforms may disable themselves by setting numIndexes = 0
2012-11-28 15:47:07 +00:00
if ( surf - > numIndexes = = 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( shader - > SuppressInSubview ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( backEnd . viewDef - > isXraySubview & & surf - > space - > entityDef )
{
if ( surf - > space - > entityDef - > parms . xrayIndex ! = 2 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we need to draw the post process shaders after we have drawn the fog lights
2012-11-28 15:47:07 +00:00
if ( shader - > GetSort ( ) > = SS_POST_PROCESS & & ! backEnd . currentRenderCopied )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
// if we are rendering a 3D view and the surface's eye index doesn't match
2012-11-26 18:58:24 +00:00
// the current view's eye index then we skip the surface
// if the stereoEye value of a surface is 0 then we need to draw it for both eyes.
const int shaderStereoEye = shader - > GetStereoEye ( ) ;
const bool isEyeValid = stereoRender_swapEyes . GetBool ( ) ? ( shaderStereoEye = = stereoEye ) : ( shaderStereoEye ! = stereoEye ) ;
2012-11-28 15:47:07 +00:00
if ( ( stereoEye ! = 0 ) & & ( shaderStereoEye ! = 0 ) & & ( isEyeValid ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( shader - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
// determine the stereoDepth offset
2012-11-26 18:58:24 +00:00
// guiStereoScreenOffset will always be zero for 3D views, so the !=
// check will never force an update due to the current sort value.
const float thisGuiStereoOffset = guiStereoScreenOffset * surf - > sort ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// change the matrix and other space related vars if needed
2012-11-28 15:47:07 +00:00
if ( surf - > space ! = backEnd . currentSpace | | thisGuiStereoOffset ! = currentGuiStereoOffset )
{
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = surf - > space ;
currentGuiStereoOffset = thisGuiStereoOffset ;
2012-11-28 15:47:07 +00:00
const viewEntity_t * space = backEnd . currentSpace ;
if ( guiStereoScreenOffset ! = 0.0f )
{
2012-11-26 18:58:24 +00:00
RB_SetMVPWithStereoOffset ( space - > mvp , currentGuiStereoOffset ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
RB_SetMVP ( space - > mvp ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set eye position in local space
idVec4 localViewOrigin ( 1.0f ) ;
R_GlobalPointToLocal ( space - > modelMatrix , backEnd . viewDef - > renderView . vieworg , localViewOrigin . ToVec3 ( ) ) ;
SetVertexParm ( RENDERPARM_LOCALVIEWORIGIN , localViewOrigin . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set model Matrix
float modelMatrixTranspose [ 16 ] ;
R_MatrixTranspose ( space - > modelMatrix , modelMatrixTranspose ) ;
SetVertexParms ( RENDERPARM_MODELMATRIX_X , modelMatrixTranspose , 4 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Set ModelView Matrix
float modelViewMatrixTranspose [ 16 ] ;
R_MatrixTranspose ( space - > modelViewMatrix , modelViewMatrixTranspose ) ;
SetVertexParms ( RENDERPARM_MODELVIEWMATRIX_X , modelViewMatrixTranspose , 4 ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// change the scissor if needed
2012-11-28 15:47:07 +00:00
if ( ! backEnd . currentScissor . Equals ( surf - > scissorRect ) & & r_useScissor . GetBool ( ) )
{
GL_Scissor ( backEnd . viewDef - > viewport . x1 + surf - > scissorRect . x1 ,
2012-11-26 18:58:24 +00:00
backEnd . viewDef - > viewport . y1 + surf - > scissorRect . y1 ,
surf - > scissorRect . x2 + 1 - surf - > scissorRect . x1 ,
surf - > scissorRect . y2 + 1 - surf - > scissorRect . y1 ) ;
backEnd . currentScissor = surf - > scissorRect ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get the expressions for conditionals / color / texcoords
2012-11-28 15:47:07 +00:00
const float * regs = surf - > shaderRegisters ;
2012-11-26 18:58:24 +00:00
// set face culling appropriately
2012-11-28 15:47:07 +00:00
if ( surf - > space - > isGuiSurface )
{
2012-11-26 18:58:24 +00:00
GL_Cull ( CT_TWO_SIDED ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
GL_Cull ( shader - > GetCullType ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 surfGLState = surf - > extraGLState ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set polygon offset if necessary
2012-11-28 15:47:07 +00:00
if ( shader - > TestMaterialFlag ( MF_POLYGONOFFSET ) )
{
2012-11-26 18:58:24 +00:00
GL_PolygonOffset ( r_offsetFactor . GetFloat ( ) , r_offsetUnits . GetFloat ( ) * shader - > GetPolygonOffset ( ) ) ;
surfGLState = GLS_POLYGON_OFFSET ;
}
2012-11-28 15:47:07 +00:00
for ( int stage = 0 ; stage < shader - > GetNumStages ( ) ; stage + + )
{
const shaderStage_t * pStage = shader - > GetStage ( stage ) ;
2012-11-26 18:58:24 +00:00
// check the enable condition
2012-11-28 15:47:07 +00:00
if ( regs [ pStage - > conditionRegister ] = = 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// skip the stages involved in lighting
2012-11-28 15:47:07 +00:00
if ( pStage - > lighting ! = SL_AMBIENT )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint64 stageGLState = surfGLState ;
2012-11-28 15:47:07 +00:00
if ( ( surfGLState & GLS_OVERRIDE ) = = 0 )
{
2012-11-26 18:58:24 +00:00
stageGLState | = pStage - > drawStateBits ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// skip if the stage is ( GL_ZERO, GL_ONE ), which is used for some alpha masks
2012-11-28 15:47:07 +00:00
if ( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) = = ( GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2014-04-20 14:29:58 +00:00
2012-11-26 18:58:24 +00:00
// see if we are a new-style stage
2012-11-28 15:47:07 +00:00
newShaderStage_t * newStage = pStage - > newStage ;
if ( newStage ! = NULL )
{
2012-11-26 18:58:24 +00:00
//--------------------------
//
// new style stages
//
//--------------------------
2012-11-28 15:47:07 +00:00
if ( r_skipNewAmbient . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
renderLog . OpenBlock ( " New Shader Stage " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_State ( stageGLState ) ;
2012-11-28 15:47:07 +00:00
2013-04-10 00:13:27 +00:00
// RB: CRITICAL BUGFIX: changed newStage->glslProgram to vertexProgram and fragmentProgram
// otherwise it will result in an out of bounds crash in RB_DrawElementsWithCounters
2014-04-20 14:29:58 +00:00
renderProgManager . BindShader ( newStage - > glslProgram , newStage - > vertexProgram , newStage - > fragmentProgram , false ) ;
2013-04-10 00:13:27 +00:00
// RB end
2012-11-28 15:47:07 +00:00
for ( int j = 0 ; j < newStage - > numVertexParms ; j + + )
{
2012-11-26 18:58:24 +00:00
float parm [ 4 ] ;
parm [ 0 ] = regs [ newStage - > vertexParms [ j ] [ 0 ] ] ;
parm [ 1 ] = regs [ newStage - > vertexParms [ j ] [ 1 ] ] ;
parm [ 2 ] = regs [ newStage - > vertexParms [ j ] [ 2 ] ] ;
parm [ 3 ] = regs [ newStage - > vertexParms [ j ] [ 3 ] ] ;
2012-11-28 15:47:07 +00:00
SetVertexParm ( ( renderParm_t ) ( RENDERPARM_USER + j ) , parm ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set rpEnableSkinning if the shader has optional support for skinning
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache & & renderProgManager . ShaderHasOptionalSkinning ( ) )
{
2012-11-26 18:58:24 +00:00
const idVec4 skinningParm ( 1.0f ) ;
SetVertexParm ( RENDERPARM_ENABLE_SKINNING , skinningParm . ToFloatPtr ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bind texture units
2012-11-28 15:47:07 +00:00
for ( int j = 0 ; j < newStage - > numFragmentProgramImages ; j + + )
{
idImage * image = newStage - > fragmentProgramImages [ j ] ;
if ( image ! = NULL )
{
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( j ) ;
image - > Bind ( ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw it
RB_DrawElementsWithCounters ( surf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// unbind texture units
2012-11-28 15:47:07 +00:00
for ( int j = 0 ; j < newStage - > numFragmentProgramImages ; j + + )
{
idImage * image = newStage - > fragmentProgramImages [ j ] ;
if ( image ! = NULL )
{
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( j ) ;
globalImages - > BindNull ( ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear rpEnableSkinning if it was set
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache & & renderProgManager . ShaderHasOptionalSkinning ( ) )
{
2012-11-26 18:58:24 +00:00
const idVec4 skinningParm ( 0.0f ) ;
SetVertexParm ( RENDERPARM_ENABLE_SKINNING , skinningParm . ToFloatPtr ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
renderProgManager . Unbind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//--------------------------
//
// old style stages
//
//--------------------------
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the color
2014-05-10 12:40:01 +00:00
idVec4 color ;
2012-11-26 18:58:24 +00:00
color [ 0 ] = regs [ pStage - > color . registers [ 0 ] ] ;
color [ 1 ] = regs [ pStage - > color . registers [ 1 ] ] ;
color [ 2 ] = regs [ pStage - > color . registers [ 2 ] ] ;
color [ 3 ] = regs [ pStage - > color . registers [ 3 ] ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// skip the entire stage if an add would be black
2012-11-28 15:47:07 +00:00
if ( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) = = ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE )
& & color [ 0 ] < = 0 & & color [ 1 ] < = 0 & & color [ 2 ] < = 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// skip the entire stage if a blend would be completely transparent
2012-11-28 15:47:07 +00:00
if ( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) = = ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA )
& & color [ 3 ] < = 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
stageVertexColor_t svc = pStage - > vertexColor ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " Old Shader Stage " ) ;
GL_Color ( color ) ;
2012-11-28 15:47:07 +00:00
if ( surf - > space - > isGuiSurface )
{
2012-11-26 18:58:24 +00:00
// Force gui surfaces to always be SVC_MODULATE
svc = SVC_MODULATE ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// use special shaders for bink cinematics
2012-11-28 15:47:07 +00:00
if ( pStage - > texture . cinematic )
{
if ( ( stageGLState & GLS_OVERRIDE ) ! = 0 )
{
2012-11-26 18:58:24 +00:00
// This is a hack... Only SWF Guis set GLS_OVERRIDE
// Old style guis do not, and we don't want them to use the new GUI renederProg
renderProgManager . BindShader_BinkGUI ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Bink ( ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
if ( ( stageGLState & GLS_OVERRIDE ) ! = 0 )
{
2012-11-26 18:58:24 +00:00
// This is a hack... Only SWF Guis set GLS_OVERRIDE
// Old style guis do not, and we don't want them to use the new GUI renderProg
renderProgManager . BindShader_GUI ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColorSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColor ( ) ;
}
}
}
2012-11-28 15:47:07 +00:00
}
else if ( ( pStage - > texture . texgen = = TG_SCREEN ) | | ( pStage - > texture . texgen = = TG_SCREEN2 ) )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureTexGenVertexColor ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( pStage - > texture . cinematic )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Bink ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColorSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColor ( ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_SetVertexColorParms ( svc ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bind the texture
RB_BindVariableStageImage ( & pStage - > texture , regs ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set privatePolygonOffset if necessary
2012-11-28 15:47:07 +00:00
if ( pStage - > privatePolygonOffset )
{
2012-11-26 18:58:24 +00:00
GL_PolygonOffset ( r_offsetFactor . GetFloat ( ) , r_offsetUnits . GetFloat ( ) * pStage - > privatePolygonOffset ) ;
stageGLState | = GLS_POLYGON_OFFSET ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the state
GL_State ( stageGLState ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_PrepareStageTexturing ( pStage , surf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw it
RB_DrawElementsWithCounters ( surf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_FinishStageTexturing ( pStage , surf ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// unset privatePolygonOffset if necessary
2012-11-28 15:47:07 +00:00
if ( pStage - > privatePolygonOffset )
{
2012-11-26 18:58:24 +00:00
GL_PolygonOffset ( r_offsetFactor . GetFloat ( ) , r_offsetUnits . GetFloat ( ) * shader - > GetPolygonOffset ( ) ) ;
}
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_Cull ( CT_FRONT_SIDED ) ;
GL_Color ( 1.0f , 1.0f , 1.0f ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
return i ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BLEND LIGHT PROJECTION
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = =
RB_T_BlendLight
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_T_BlendLight ( const drawSurf_t * drawSurfs , const viewLight_t * vLight )
{
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = NULL ;
2012-11-28 15:47:07 +00:00
for ( const drawSurf_t * drawSurf = drawSurfs ; drawSurf ! = NULL ; drawSurf = drawSurf - > nextOnLight )
{
if ( drawSurf - > scissorRect . IsEmpty ( ) )
{
2012-11-26 18:58:24 +00:00
continue ; // !@# FIXME: find out why this is sometimes being hit!
2012-11-28 15:47:07 +00:00
// temporarily jump over the scissor and draw so the gl error callback doesn't get hit
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( ! backEnd . currentScissor . Equals ( drawSurf - > scissorRect ) & & r_useScissor . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// change the scissor
GL_Scissor ( backEnd . viewDef - > viewport . x1 + drawSurf - > scissorRect . x1 ,
backEnd . viewDef - > viewport . y1 + drawSurf - > scissorRect . y1 ,
drawSurf - > scissorRect . x2 + 1 - drawSurf - > scissorRect . x1 ,
drawSurf - > scissorRect . y2 + 1 - drawSurf - > scissorRect . y1 ) ;
backEnd . currentScissor = drawSurf - > scissorRect ;
}
2012-11-28 15:47:07 +00:00
if ( drawSurf - > space ! = backEnd . currentSpace )
{
2012-11-26 18:58:24 +00:00
// change the matrix
RB_SetMVP ( drawSurf - > space - > mvp ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// change the light projection matrix
idPlane lightProjectInCurrentSpace [ 4 ] ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
2012-11-26 18:58:24 +00:00
R_GlobalPlaneToLocal ( drawSurf - > space - > modelMatrix , vLight - > lightProject [ i ] , lightProjectInCurrentSpace [ i ] ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetVertexParm ( RENDERPARM_TEXGEN_0_S , lightProjectInCurrentSpace [ 0 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_TEXGEN_0_T , lightProjectInCurrentSpace [ 1 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_TEXGEN_0_Q , lightProjectInCurrentSpace [ 2 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_TEXGEN_1_S , lightProjectInCurrentSpace [ 3 ] . ToFloatPtr ( ) ) ; // falloff
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = drawSurf - > space ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( drawSurf ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = =
RB_BlendLight
Dual texture together the falloff and projection texture with a blend
mode to the framebuffer , instead of interacting with the surface texture
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_BlendLight ( const drawSurf_t * drawSurfs , const drawSurf_t * drawSurfs2 , const viewLight_t * vLight )
{
if ( drawSurfs = = NULL )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( r_skipBlendLights . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
renderLog . OpenBlock ( vLight - > lightShader - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
const idMaterial * lightShader = vLight - > lightShader ;
const float * regs = vLight - > shaderRegisters ;
2012-11-26 18:58:24 +00:00
// texture 1 will get the falloff texture
GL_SelectTexture ( 1 ) ;
vLight - > falloffImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 0 will get the projected texture
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_BlendLight ( ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < lightShader - > GetNumStages ( ) ; i + + )
{
const shaderStage_t * stage = lightShader - > GetStage ( i ) ;
if ( ! regs [ stage - > conditionRegister ] )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_State ( GLS_DEPTHMASK | stage - > drawStateBits | GLS_DEPTHFUNC_EQUAL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
stage - > texture . image - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
if ( stage - > texture . hasMatrix )
{
2012-11-26 18:58:24 +00:00
RB_LoadShaderTextureMatrix ( regs , & stage - > texture ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get the modulate values from the light, including alpha, unlike normal lights
2014-05-10 12:40:01 +00:00
idVec4 lightColor ;
2012-11-26 18:58:24 +00:00
lightColor [ 0 ] = regs [ stage - > color . registers [ 0 ] ] ;
lightColor [ 1 ] = regs [ stage - > color . registers [ 1 ] ] ;
lightColor [ 2 ] = regs [ stage - > color . registers [ 2 ] ] ;
lightColor [ 3 ] = regs [ stage - > color . registers [ 3 ] ] ;
GL_Color ( lightColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_T_BlendLight ( drawSurfs , vLight ) ;
RB_T_BlendLight ( drawSurfs2 , vLight ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 1 ) ;
globalImages - > BindNull ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . Unbind ( ) ;
renderLog . CloseBlock ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
FOG LIGHTS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = =
RB_T_BasicFog
= = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_T_BasicFog ( const drawSurf_t * drawSurfs , const idPlane fogPlanes [ 4 ] , const idRenderMatrix * inverseBaseLightProject )
{
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = NULL ;
2012-11-28 15:47:07 +00:00
for ( const drawSurf_t * drawSurf = drawSurfs ; drawSurf ! = NULL ; drawSurf = drawSurf - > nextOnLight )
{
if ( drawSurf - > scissorRect . IsEmpty ( ) )
{
2012-11-26 18:58:24 +00:00
continue ; // !@# FIXME: find out why this is sometimes being hit!
2012-11-28 15:47:07 +00:00
// temporarily jump over the scissor and draw so the gl error callback doesn't get hit
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( ! backEnd . currentScissor . Equals ( drawSurf - > scissorRect ) & & r_useScissor . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// change the scissor
GL_Scissor ( backEnd . viewDef - > viewport . x1 + drawSurf - > scissorRect . x1 ,
backEnd . viewDef - > viewport . y1 + drawSurf - > scissorRect . y1 ,
drawSurf - > scissorRect . x2 + 1 - drawSurf - > scissorRect . x1 ,
drawSurf - > scissorRect . y2 + 1 - drawSurf - > scissorRect . y1 ) ;
backEnd . currentScissor = drawSurf - > scissorRect ;
}
2012-11-28 15:47:07 +00:00
if ( drawSurf - > space ! = backEnd . currentSpace )
{
2012-11-26 18:58:24 +00:00
idPlane localFogPlanes [ 4 ] ;
2012-11-28 15:47:07 +00:00
if ( inverseBaseLightProject = = NULL )
{
2012-11-26 18:58:24 +00:00
RB_SetMVP ( drawSurf - > space - > mvp ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
2012-11-26 18:58:24 +00:00
R_GlobalPlaneToLocal ( drawSurf - > space - > modelMatrix , fogPlanes [ i ] , localFogPlanes [ i ] ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
idRenderMatrix invProjectMVPMatrix ;
idRenderMatrix : : Multiply ( backEnd . viewDef - > worldSpace . mvp , * inverseBaseLightProject , invProjectMVPMatrix ) ;
RB_SetMVP ( invProjectMVPMatrix ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
2012-11-26 18:58:24 +00:00
inverseBaseLightProject - > InverseTransformPlane ( fogPlanes [ i ] , localFogPlanes [ i ] , false ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetVertexParm ( RENDERPARM_TEXGEN_0_S , localFogPlanes [ 0 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_TEXGEN_0_T , localFogPlanes [ 1 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_TEXGEN_1_T , localFogPlanes [ 2 ] . ToFloatPtr ( ) ) ;
SetVertexParm ( RENDERPARM_TEXGEN_1_S , localFogPlanes [ 3 ] . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . currentSpace = ( inverseBaseLightProject = = NULL ) ? drawSurf - > space : NULL ;
}
2012-11-28 15:47:07 +00:00
if ( drawSurf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_FogSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Fog ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( drawSurf ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
RB_FogPass
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_FogPass ( const drawSurf_t * drawSurfs , const drawSurf_t * drawSurfs2 , const viewLight_t * vLight )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( vLight - > lightShader - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// find the current color and density of the fog
2012-11-28 15:47:07 +00:00
const idMaterial * lightShader = vLight - > lightShader ;
const float * regs = vLight - > shaderRegisters ;
2012-11-26 18:58:24 +00:00
// assume fog shaders have only a single stage
2012-11-28 15:47:07 +00:00
const shaderStage_t * stage = lightShader - > GetStage ( 0 ) ;
2014-05-10 12:40:01 +00:00
idVec4 lightColor ;
2012-11-26 18:58:24 +00:00
lightColor [ 0 ] = regs [ stage - > color . registers [ 0 ] ] ;
lightColor [ 1 ] = regs [ stage - > color . registers [ 1 ] ] ;
lightColor [ 2 ] = regs [ stage - > color . registers [ 2 ] ] ;
lightColor [ 3 ] = regs [ stage - > color . registers [ 3 ] ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_Color ( lightColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// calculate the falloff planes
float a ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if they left the default value on, set a fog distance of 500
2012-11-28 15:47:07 +00:00
if ( lightColor [ 3 ] < = 1.0f )
{
2012-11-26 18:58:24 +00:00
a = - 0.5f / DEFAULT_FOG_DISTANCE ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// otherwise, distance = alpha color
a = - 0.5f / lightColor [ 3 ] ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 0 is the falloff image
GL_SelectTexture ( 0 ) ;
globalImages - > fogImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// texture 1 is the entering plane fade correction
GL_SelectTexture ( 1 ) ;
globalImages - > fogEnterImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// S is based on the view origin
const float s = vLight - > fogPlane . Distance ( backEnd . viewDef - > renderView . vieworg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float FOG_SCALE = 0.001f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idPlane fogPlanes [ 4 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// S-0
2012-11-28 15:47:07 +00:00
fogPlanes [ 0 ] [ 0 ] = a * backEnd . viewDef - > worldSpace . modelViewMatrix [ 0 * 4 + 2 ] ;
fogPlanes [ 0 ] [ 1 ] = a * backEnd . viewDef - > worldSpace . modelViewMatrix [ 1 * 4 + 2 ] ;
fogPlanes [ 0 ] [ 2 ] = a * backEnd . viewDef - > worldSpace . modelViewMatrix [ 2 * 4 + 2 ] ;
fogPlanes [ 0 ] [ 3 ] = a * backEnd . viewDef - > worldSpace . modelViewMatrix [ 3 * 4 + 2 ] + 0.5f ;
2012-11-26 18:58:24 +00:00
// T-0
fogPlanes [ 1 ] [ 0 ] = 0.0f ; //a * backEnd.viewDef->worldSpace.modelViewMatrix[0*4+0];
fogPlanes [ 1 ] [ 1 ] = 0.0f ; //a * backEnd.viewDef->worldSpace.modelViewMatrix[1*4+0];
fogPlanes [ 1 ] [ 2 ] = 0.0f ; //a * backEnd.viewDef->worldSpace.modelViewMatrix[2*4+0];
fogPlanes [ 1 ] [ 3 ] = 0.5f ; //a * backEnd.viewDef->worldSpace.modelViewMatrix[3*4+0] + 0.5f;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// T-1 will get a texgen for the fade plane, which is always the "top" plane on unrotated lights
fogPlanes [ 2 ] [ 0 ] = FOG_SCALE * vLight - > fogPlane [ 0 ] ;
fogPlanes [ 2 ] [ 1 ] = FOG_SCALE * vLight - > fogPlane [ 1 ] ;
fogPlanes [ 2 ] [ 2 ] = FOG_SCALE * vLight - > fogPlane [ 2 ] ;
fogPlanes [ 2 ] [ 3 ] = FOG_SCALE * vLight - > fogPlane [ 3 ] + FOG_ENTER ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// S-1
fogPlanes [ 3 ] [ 0 ] = 0.0f ;
fogPlanes [ 3 ] [ 1 ] = 0.0f ;
fogPlanes [ 3 ] [ 2 ] = 0.0f ;
fogPlanes [ 3 ] [ 3 ] = FOG_SCALE * s + FOG_ENTER ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw it
GL_State ( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ) ;
RB_T_BasicFog ( drawSurfs , fogPlanes , NULL ) ;
RB_T_BasicFog ( drawSurfs2 , fogPlanes , NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead
// of depthfunc_equal
GL_State ( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS ) ;
GL_Cull ( CT_BACK_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . zeroOneCubeSurface . space = & backEnd . viewDef - > worldSpace ;
backEnd . zeroOneCubeSurface . scissorRect = backEnd . viewDef - > scissor ;
RB_T_BasicFog ( & backEnd . zeroOneCubeSurface , fogPlanes , & vLight - > inverseBaseLightProject ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_Cull ( CT_FRONT_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 1 ) ;
globalImages - > BindNull ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . Unbind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
RB_FogAllLights
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_FogAllLights ( )
{
if ( r_skipFogLights . GetBool ( ) | | r_showOverDraw . GetInteger ( ) ! = 0
| | backEnd . viewDef - > isXraySubview /* don't fog in xray mode*/ )
{
2012-11-26 18:58:24 +00:00
return ;
}
renderLog . OpenMainBlock ( MRB_FOG_ALL_LIGHTS ) ;
renderLog . OpenBlock ( " RB_FogAllLights " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// force fog plane to recalculate
backEnd . currentSpace = NULL ;
2012-11-28 15:47:07 +00:00
for ( viewLight_t * vLight = backEnd . viewDef - > viewLights ; vLight ! = NULL ; vLight = vLight - > next )
{
if ( vLight - > lightShader - > IsFogLight ( ) )
{
2012-11-26 18:58:24 +00:00
RB_FogPass ( vLight - > globalInteractions , vLight - > localInteractions , vLight ) ;
2012-11-28 15:47:07 +00:00
}
else if ( vLight - > lightShader - > IsBlendLight ( ) )
{
2012-11-26 18:58:24 +00:00
RB_BlendLight ( vLight - > globalInteractions , vLight - > localInteractions , vLight ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
renderLog . CloseMainBlock ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BACKEND COMMANDS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
RB_DrawViewInternal
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_DrawViewInternal ( const viewDef_t * viewDef , const int stereoEye )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " RB_DrawViewInternal " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// guis can wind up referencing purged images that need to be loaded.
// this used to be in the gui emit code, but now that it can be running
// in a separate thread, it must not try to load images, so do it here.
//-------------------------------------------------
2012-11-28 15:47:07 +00:00
drawSurf_t * * drawSurfs = ( drawSurf_t * * ) & viewDef - > drawSurfs [ 0 ] ;
2012-11-26 18:58:24 +00:00
const int numDrawSurfs = viewDef - > numDrawSurfs ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numDrawSurfs ; i + + )
{
const drawSurf_t * ds = viewDef - > drawSurfs [ i ] ;
if ( ds - > material ! = NULL )
{
const_cast < idMaterial * > ( ds - > material ) - > EnsureNotPurged ( ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// RB_BeginDrawingView
//
// Any mirrored or portaled views have already been drawn, so prepare
// to actually render the visible surfaces for this view
//
// clear the z buffer, set the projection matrix, etc
//-------------------------------------------------
2014-05-10 12:40:01 +00:00
RB_ResetViewportAndScissorToDefaultCamera ( viewDef ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . glState . faceCulling = - 1 ; // force face culling to set next time
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// ensures that depth writes are enabled for the depth clear
GL_State ( GLS_DEFAULT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Clear the depth buffer and clear the stencil to 128 for stencil shadows as well as gui masking
GL_Clear ( false , true , true , STENCIL_SHADOW_TEST_VALUE , 0.0f , 0.0f , 0.0f , 0.0f ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// normal face culling
GL_Cull ( CT_FRONT_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
# ifdef USE_CORE_PROFILE
// bind one global Vertex Array Object (VAO)
2012-12-17 16:30:59 +00:00
glBindVertexArray ( glConfig . global_vao ) ;
2012-11-26 18:58:24 +00:00
# endif
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//------------------------------------
// sets variables that can be used by all programs
//------------------------------------
{
//
// set eye position in global space
//
float parm [ 4 ] ;
parm [ 0 ] = backEnd . viewDef - > renderView . vieworg [ 0 ] ;
parm [ 1 ] = backEnd . viewDef - > renderView . vieworg [ 1 ] ;
parm [ 2 ] = backEnd . viewDef - > renderView . vieworg [ 2 ] ;
parm [ 3 ] = 1.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetVertexParm ( RENDERPARM_GLOBALEYEPOS , parm ) ; // rpGlobalEyePos
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// sets overbright to make world brighter
// This value is baked into the specularScale and diffuseScale values so
// the interaction programs don't need to perform the extra multiply,
// but any other renderprogs that want to obey the brightness value
// can reference this.
float overbright = r_lightScale . GetFloat ( ) * 0.5f ;
parm [ 0 ] = overbright ;
parm [ 1 ] = overbright ;
parm [ 2 ] = overbright ;
parm [ 3 ] = overbright ;
SetFragmentParm ( RENDERPARM_OVERBRIGHT , parm ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Set Projection Matrix
float projMatrixTranspose [ 16 ] ;
R_MatrixTranspose ( backEnd . viewDef - > projectionMatrix , projMatrixTranspose ) ;
SetVertexParms ( RENDERPARM_PROJMATRIX_X , projMatrixTranspose , 4 ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// fill the depth buffer and clear color buffer to black except on subviews
//-------------------------------------------------
RB_FillDepthBufferFast ( drawSurfs , numDrawSurfs ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// main light renderer
//-------------------------------------------------
2014-05-10 12:40:01 +00:00
RB_DrawInteractions ( viewDef ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// now draw any non-light dependent shading passes
//-------------------------------------------------
int processed = 0 ;
2012-11-28 15:47:07 +00:00
if ( ! r_skipShaderPasses . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenMainBlock ( MRB_DRAW_SHADER_PASSES ) ;
float guiScreenOffset ;
2012-11-28 15:47:07 +00:00
if ( viewDef - > viewEntitys ! = NULL )
{
2012-11-26 18:58:24 +00:00
// guiScreenOffset will be 0 in non-gui views
guiScreenOffset = 0.0f ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
guiScreenOffset = stereoEye * viewDef - > renderView . stereoScreenSeparation ;
}
processed = RB_DrawShaderPasses ( drawSurfs , numDrawSurfs , guiScreenOffset , stereoEye ) ;
renderLog . CloseMainBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// fog and blend lights, drawn after emissive surfaces
// so they are properly dimmed down
//-------------------------------------------------
RB_FogAllLights ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// capture the depth for the motion blur before rendering any post process surfaces that may contribute to the depth
//-------------------------------------------------
2012-11-28 15:47:07 +00:00
if ( r_motionBlur . GetInteger ( ) > 0 )
{
const idScreenRect & viewport = backEnd . viewDef - > viewport ;
2012-11-26 18:58:24 +00:00
globalImages - > currentDepthImage - > CopyDepthbuffer ( viewport . x1 , viewport . y1 , viewport . GetWidth ( ) , viewport . GetHeight ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// now draw any screen warping post-process effects using _currentRender
//-------------------------------------------------
2012-11-28 15:47:07 +00:00
if ( processed < numDrawSurfs & & ! r_skipPostProcess . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
int x = backEnd . viewDef - > viewport . x1 ;
int y = backEnd . viewDef - > viewport . y1 ;
int w = backEnd . viewDef - > viewport . x2 - backEnd . viewDef - > viewport . x1 + 1 ;
int h = backEnd . viewDef - > viewport . y2 - backEnd . viewDef - > viewport . y1 + 1 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " Resolve to %i x %i buffer \n " , w , h ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// resolve the screen
globalImages - > currentRenderImage - > CopyFramebuffer ( x , y , w , h ) ;
backEnd . currentRenderCopied = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// RENDERPARM_SCREENCORRECTIONFACTOR amd RENDERPARM_WINDOWCOORD overlap
// diffuseScale and specularScale
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// screen power of two correction factor (no longer relevant now)
float screenCorrectionParm [ 4 ] ;
screenCorrectionParm [ 0 ] = 1.0f ;
screenCorrectionParm [ 1 ] = 1.0f ;
screenCorrectionParm [ 2 ] = 0.0f ;
screenCorrectionParm [ 3 ] = 1.0f ;
SetFragmentParm ( RENDERPARM_SCREENCORRECTIONFACTOR , screenCorrectionParm ) ; // rpScreenCorrectionFactor
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// window coord to 0.0 to 1.0 conversion
float windowCoordParm [ 4 ] ;
windowCoordParm [ 0 ] = 1.0f / w ;
windowCoordParm [ 1 ] = 1.0f / h ;
windowCoordParm [ 2 ] = 0.0f ;
windowCoordParm [ 3 ] = 1.0f ;
SetFragmentParm ( RENDERPARM_WINDOWCOORD , windowCoordParm ) ; // rpWindowCoord
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// render the remaining surfaces
renderLog . OpenMainBlock ( MRB_DRAW_SHADER_PASSES_POST ) ;
RB_DrawShaderPasses ( drawSurfs + processed , numDrawSurfs - processed , 0.0f /* definitely not a gui */ , stereoEye ) ;
renderLog . CloseMainBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// render debug tools
//-------------------------------------------------
RB_RenderDebugTools ( drawSurfs , numDrawSurfs ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
RB_MotionBlur
Experimental feature
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_MotionBlur ( )
{
if ( ! backEnd . viewDef - > viewEntitys )
{
2012-11-26 18:58:24 +00:00
// 3D views only
return ;
}
2012-11-28 15:47:07 +00:00
if ( r_motionBlur . GetInteger ( ) < = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( backEnd . viewDef - > isSubview )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_CheckErrors ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear the alpha buffer and draw only the hands + weapon into it so
// we can avoid blurring them
2012-12-17 16:30:59 +00:00
glClearColor ( 0 , 0 , 0 , 1 ) ;
2012-11-26 18:58:24 +00:00
GL_State ( GLS_COLORMASK | GLS_DEPTHMASK ) ;
2012-12-17 16:30:59 +00:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2012-11-26 18:58:24 +00:00
GL_Color ( 0 , 0 , 0 , 0 ) ;
GL_SelectTexture ( 0 ) ;
globalImages - > blackImage - > Bind ( ) ;
backEnd . currentSpace = NULL ;
2012-11-28 15:47:07 +00:00
drawSurf_t * * drawSurfs = ( drawSurf_t * * ) & backEnd . viewDef - > drawSurfs [ 0 ] ;
for ( int surfNum = 0 ; surfNum < backEnd . viewDef - > numDrawSurfs ; surfNum + + )
{
const drawSurf_t * surf = drawSurfs [ surfNum ] ;
if ( ! surf - > space - > weaponDepthHack & & ! surf - > space - > skipMotionBlur & & ! surf - > material - > HasSubview ( ) )
{
2012-11-26 18:58:24 +00:00
// Apply motion blur to this object
continue ;
}
2012-11-28 15:47:07 +00:00
const idMaterial * shader = surf - > material ;
if ( shader - > Coverage ( ) = = MC_TRANSLUCENT )
{
2012-11-26 18:58:24 +00:00
// muzzle flash, etc
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set mvp matrix
2012-11-28 15:47:07 +00:00
if ( surf - > space ! = backEnd . currentSpace )
{
2012-11-26 18:58:24 +00:00
RB_SetMVP ( surf - > space - > mvp ) ;
backEnd . currentSpace = surf - > space ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// this could just be a color, but we don't have a skinned color-only prog
2012-11-28 15:47:07 +00:00
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColorSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_TextureVertexColor ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// draw it solid
RB_DrawElementsWithCounters ( surf ) ;
}
GL_State ( GLS_DEPTHFUNC_ALWAYS ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// copy off the color buffer and the depth buffer for the motion blur prog
// we use the viewport dimensions for copying the buffers in case resolution scaling is enabled.
2012-11-28 15:47:07 +00:00
const idScreenRect & viewport = backEnd . viewDef - > viewport ;
2012-11-26 18:58:24 +00:00
globalImages - > currentRenderImage - > CopyFramebuffer ( viewport . x1 , viewport . y1 , viewport . GetWidth ( ) , viewport . GetHeight ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// in stereo rendering, each eye needs to get a separate previous frame mvp
int mvpIndex = ( backEnd . viewDef - > renderView . viewEyeBuffer = = 1 ) ? 1 : 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// derive the matrix to go from current pixels to previous frame pixels
idRenderMatrix inverseMVP ;
idRenderMatrix : : Inverse ( backEnd . viewDef - > worldSpace . mvp , inverseMVP ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idRenderMatrix motionMatrix ;
idRenderMatrix : : Multiply ( backEnd . prevMVP [ mvpIndex ] , inverseMVP , motionMatrix ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . prevMVP [ mvpIndex ] = backEnd . viewDef - > worldSpace . mvp ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_SetMVP ( motionMatrix ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_State ( GLS_DEPTHFUNC_ALWAYS ) ;
GL_Cull ( CT_TWO_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_MotionBlur ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// let the fragment program know how many samples we are going to use
2012-11-28 15:47:07 +00:00
idVec4 samples ( ( float ) ( 1 < < r_motionBlur . GetInteger ( ) ) ) ;
2012-11-26 18:58:24 +00:00
SetFragmentParm ( RENDERPARM_OVERBRIGHT , samples . ToFloatPtr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
globalImages - > currentRenderImage - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
globalImages - > currentDepthImage - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
GL_CheckErrors ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
RB_DrawView
StereoEye will always be 0 in mono modes , or - 1 / 1 in stereo modes .
If the view is a GUI view that is repeated for both eyes , the viewDef . stereoEye value
is 0 , so the stereoEye parameter is not always the same as that .
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_DrawView ( const void * data , const int stereoEye )
{
const drawSurfsCommand_t * cmd = ( const drawSurfsCommand_t * ) data ;
2012-11-26 18:58:24 +00:00
backEnd . viewDef = cmd - > viewDef ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we will need to do a new copyTexSubImage of the screen
// when a SS_POST_PROCESS material is used
backEnd . currentRenderCopied = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if there aren't any drawsurfs, do nothing
2012-11-28 15:47:07 +00:00
if ( ! backEnd . viewDef - > numDrawSurfs )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// skip render bypasses everything that has models, assuming
// them to be 3D views, but leaves 2D rendering visible
2012-11-28 15:47:07 +00:00
if ( r_skipRender . GetBool ( ) & & backEnd . viewDef - > viewEntitys )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// skip render context sets the wgl context to NULL,
// which should factor out the API cost, under the assumption
// that all gl calls just return if the context isn't valid
2012-12-11 22:17:23 +00:00
// RB: not really needed
//if( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys )
//{
// GLimp_DeactivateContext();
//}
// RB end
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
backEnd . pc . c_surfaces + = backEnd . viewDef - > numDrawSurfs ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_ShowOverdraw ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// render the scene
RB_DrawViewInternal ( cmd - > viewDef , stereoEye ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RB_MotionBlur ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// restore the context for 2D drawing if we were stubbing it out
2012-12-11 22:17:23 +00:00
// RB: not really needed
//if( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys )
//{
// GLimp_ActivateContext();
// GL_SetDefaultState();
//}
// RB end
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// optionally draw a box colored based on the eye number
2012-11-28 15:47:07 +00:00
if ( r_drawEyeColor . GetBool ( ) )
{
const idScreenRect & r = backEnd . viewDef - > viewport ;
2012-11-26 18:58:24 +00:00
GL_Scissor ( ( r . x1 + r . x2 ) / 2 , ( r . y1 + r . y2 ) / 2 , 32 , 32 ) ;
2012-11-28 15:47:07 +00:00
switch ( stereoEye )
{
2012-11-26 18:58:24 +00:00
case - 1 :
GL_Clear ( true , false , false , 0 , 1.0f , 0.0f , 0.0f , 1.0f ) ;
break ;
case 1 :
GL_Clear ( true , false , false , 0 , 0.0f , 1.0f , 0.0f , 1.0f ) ;
break ;
default :
GL_Clear ( true , false , false , 0 , 0.5f , 0.5f , 0.5f , 1.0f ) ;
break ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
RB_CopyRender
Copy part of the current framebuffer to an image
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void RB_CopyRender ( const void * data )
{
const copyRenderCommand_t * cmd = ( const copyRenderCommand_t * ) data ;
if ( r_skipCopyTexture . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RENDERLOG_PRINTF ( " ***************** RB_CopyRender ***************** \n " ) ;
2012-11-28 15:47:07 +00:00
if ( cmd - > image )
{
2012-11-26 18:58:24 +00:00
cmd - > image - > CopyFramebuffer ( cmd - > x , cmd - > y , cmd - > imageWidth , cmd - > imageHeight ) ;
}
2012-11-28 15:47:07 +00:00
if ( cmd - > clearColorAfterCopy )
{
2012-11-26 18:58:24 +00:00
GL_Clear ( true , false , false , STENCIL_SHADOW_TEST_VALUE , 0 , 0 , 0 , 0 ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
RB_PostProcess
= = = = = = = = = = = = = = = = = =
*/
extern idCVar rs_enable ;
2012-11-28 15:47:07 +00:00
void RB_PostProcess ( const void * data )
{
2012-11-26 18:58:24 +00:00
// only do the post process step if resolution scaling is enabled. Prevents the unnecessary copying of the framebuffer and
// corresponding full screen quad pass.
2012-11-28 15:47:07 +00:00
if ( rs_enable . GetInteger ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// resolve the scaled rendering to a temporary texture
2012-11-28 15:47:07 +00:00
postProcessCommand_t * cmd = ( postProcessCommand_t * ) data ;
const idScreenRect & viewport = cmd - > viewDef - > viewport ;
2012-11-26 18:58:24 +00:00
globalImages - > currentRenderImage - > CopyFramebuffer ( viewport . x1 , viewport . y1 , viewport . GetWidth ( ) , viewport . GetHeight ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_State ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS ) ;
GL_Cull ( CT_TWO_SIDED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int screenWidth = renderSystem - > GetWidth ( ) ;
int screenHeight = renderSystem - > GetHeight ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the window clipping
GL_Viewport ( 0 , 0 , screenWidth , screenHeight ) ;
GL_Scissor ( 0 , 0 , screenWidth , screenHeight ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
globalImages - > currentRenderImage - > Bind ( ) ;
renderProgManager . BindShader_PostProcess ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Draw
RB_DrawElementsWithCounters ( & backEnd . unitSquareSurface ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderLog . CloseBlock ( ) ;
}