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 .
2013-04-10 00:13:27 +00:00
Copyright ( C ) 2013 Robert Beckebans
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"
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 )
{
2013-04-10 00:13:27 +00:00
if ( ! verify ( renderProgManager . ShaderUsesJoints ( ) ) )
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-11-26 18:58:24 +00:00
qglBindBufferRange ( GL_UNIFORM_BUFFER , 0 , ubo , jointBuffer . GetOffset ( ) , jointBuffer . GetNumJoints ( ) * sizeof ( idJointMat ) ) ;
}
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-07 16:06:44 +00:00
qglBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) ) ;
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-07 16:06:44 +00:00
qglBindBufferARB ( GL_ARRAY_BUFFER_ARB , ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) ;
backEnd . glState . currentVertexBuffer = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_VERTEX ) ;
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_NORMAL ) ;
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR ) ;
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR2 ) ;
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_ST ) ;
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_TANGENT ) ;
2012-11-28 15:47:07 +00:00
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_VERTEX , 3 , GL_FLOAT , GL_FALSE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_XYZ_OFFSET ) ) ;
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_NORMAL , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_NORMAL_OFFSET ) ) ;
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_COLOR_OFFSET ) ) ;
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR2 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_COLOR2_OFFSET ) ) ;
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_ST , 2 , GL_HALF_FLOAT , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_ST_OFFSET ) ) ;
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_TANGENT , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_TANGENT_OFFSET ) ) ;
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-11-28 15:47:07 +00:00
qglDrawElementsBaseVertex ( GL_TRIANGLES ,
r_singleTriangle . GetBool ( ) ? 3 : surf - > numIndexes ,
GL_INDEX_TYPE ,
( triIndex_t * ) indexOffset ,
vertOffset / sizeof ( idDrawVert ) ) ;
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 ( ) ;
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 ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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
float color [ 4 ] ;
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 ;
/*
= = = = = = = = = = = = = = = = = =
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 ;
static const int MAX_COMPLEX_INTERACTIONS_PER_LIGHT = 128 ;
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
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
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
{
if ( surf - > jointCache )
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_InteractionSkinned ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Interaction ( ) ;
}
}
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
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 ( ) ) ;
}
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
qglStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_KEEP , GL_INCR ) ;
qglStencilOpSeparate ( 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
qglStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_DECR , GL_DECR ) ;
qglStencilOpSeparate ( 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-07 16:06:44 +00:00
qglBindBufferARB ( GL_ELEMENT_ARRAY_BUFFER_ARB , ( GLintptrARB ) indexBuffer - > GetAPIObject ( ) ) ;
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-11-26 18:58:24 +00:00
qglBindBufferRange ( 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-07 16:06:44 +00:00
qglBindBufferARB ( GL_ARRAY_BUFFER_ARB , ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) ;
backEnd . glState . currentVertexBuffer = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_VERTEX ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_NORMAL ) ;
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR ) ;
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR2 ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_ST ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_TANGENT ) ;
2012-11-28 15:47:07 +00:00
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_XYZW_OFFSET ) ) ;
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_COLOR_OFFSET ) ) ;
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_COLOR2 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_COLOR2_OFFSET ) ) ;
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-07 16:06:44 +00:00
qglBindBufferARB ( GL_ARRAY_BUFFER_ARB , ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ) ;
backEnd . glState . currentVertexBuffer = ( GLintptrARB ) vertexBuffer - > GetAPIObject ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
qglEnableVertexAttribArrayARB ( PC_ATTRIB_INDEX_VERTEX ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_NORMAL ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_COLOR2 ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_ST ) ;
qglDisableVertexAttribArrayARB ( PC_ATTRIB_INDEX_TANGENT ) ;
2012-11-28 15:47:07 +00:00
qglVertexAttribPointerARB ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVert ) , ( void * ) ( SHADOWVERT_XYZW_OFFSET ) ) ;
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 )
{
qglDrawElementsBaseVertex ( 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
{
qglDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVert ) ) ;
}
if ( ! renderZPass & & r_useStencilShadowPreload . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// render again with Z-pass
qglStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_KEEP , GL_INCR ) ;
qglStencilOpSeparate ( GL_BACK , GL_KEEP , GL_KEEP , GL_DECR ) ;
2012-11-28 15:47:07 +00:00
if ( drawSurf - > jointCache )
{
qglDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVertSkinned ) ) ;
}
else
{
qglDrawElementsBaseVertex ( 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
}
}
}
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
qglStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_REPLACE , GL_ZERO ) ;
qglStencilOpSeparate ( 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 ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DRAW INTERACTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
RB_DrawInteractions
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void RB_DrawInteractions ( )
{
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
2012-11-26 18:58:24 +00:00
const bool useLightDepthBounds = r_useLightDepthBounds . 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
2012-11-26 18:58:24 +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 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// 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 ) ;
2012-11-28 15:47:07 +00:00
if ( performStencilTest )
{
if ( useLightStencilSelect )
{
2012-11-26 18:58:24 +00:00
// write a stencil mask for the visible light bounds to hi-stencil
RB_StencilSelectLight ( vLight ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// 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 ;
2012-11-28 15:47:07 +00:00
if ( ! backEnd . currentScissor . Equals ( rect ) & & r_useScissor . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
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 ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( vLight - > globalShadows ! = NULL )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " Global Light Shadows " ) ;
RB_StencilShadowPass ( vLight - > globalShadows , vLight ) ;
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( vLight - > localInteractions ! = NULL )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " Local Light Interactions " ) ;
RB_RenderInteractions ( vLight - > localInteractions , vLight , GLS_DEPTHFUNC_EQUAL , performStencilTest , useLightDepthBounds ) ;
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( vLight - > localShadows ! = NULL )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " Local Light Shadows " ) ;
RB_StencilShadowPass ( vLight - > localShadows , vLight ) ;
renderLog . CloseBlock ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( vLight - > globalInteractions ! = NULL )
{
2012-11-26 18:58:24 +00:00
renderLog . OpenBlock ( " Global Light Interactions " ) ;
RB_RenderInteractions ( vLight - > globalInteractions , vLight , GLS_DEPTHFUNC_EQUAL , performStencilTest , useLightDepthBounds ) ;
renderLog . CloseBlock ( ) ;
}
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
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
renderProgManager . BindShader ( newStage - > vertexProgram , newStage - > fragmentProgram ) ;
// 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
float color [ 4 ] ;
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
float lightColor [ 4 ] ;
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 ) ;
2012-11-26 18:58:24 +00:00
float lightColor [ 4 ] ;
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
//-------------------------------------------------
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the window clipping
GL_Viewport ( viewDef - > viewport . x1 ,
2012-11-28 15:47:07 +00:00
viewDef - > viewport . y1 ,
viewDef - > viewport . x2 + 1 - viewDef - > viewport . x1 ,
viewDef - > viewport . y2 + 1 - viewDef - > viewport . y1 ) ;
2012-11-26 18:58:24 +00:00
// 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 ;
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)
qglBindVertexArray ( glConfig . global_vao ) ;
# 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
//-------------------------------------------------
RB_DrawInteractions ( ) ;
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
qglClearColor ( 0 , 0 , 0 , 1 ) ;
GL_State ( GLS_COLORMASK | GLS_DEPTHMASK ) ;
qglClear ( GL_COLOR_BUFFER_BIT ) ;
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 ( ) ;
}