DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

tr_backend_draw.cpp (98979B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "tr_local.h"
     33 
     34 idCVar r_drawEyeColor( "r_drawEyeColor", "0", CVAR_RENDERER | CVAR_BOOL, "Draw a colored box, red = left eye, blue = right eye, grey = non-stereo" );
     35 idCVar r_motionBlur( "r_motionBlur", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_ARCHIVE, "1 - 5, log2 of the number of motion blur samples" );
     36 idCVar r_forceZPassStencilShadows( "r_forceZPassStencilShadows", "0", CVAR_RENDERER | CVAR_BOOL, "force Z-pass rendering for performance testing" );
     37 idCVar r_useStencilShadowPreload( "r_useStencilShadowPreload", "1", CVAR_RENDERER | CVAR_BOOL, "use stencil shadow preload algorithm instead of Z-fail" );
     38 idCVar r_skipShaderPasses( "r_skipShaderPasses", "0", CVAR_RENDERER | CVAR_BOOL, "" );
     39 idCVar r_skipInteractionFastPath( "r_skipInteractionFastPath", "1", CVAR_RENDERER | CVAR_BOOL, "" );
     40 idCVar r_useLightStencilSelect( "r_useLightStencilSelect", "0", CVAR_RENDERER | CVAR_BOOL, "use stencil select pass" );
     41 
     42 extern idCVar stereoRender_swapEyes;
     43 
     44 backEndState_t	backEnd;
     45 
     46 /*
     47 ================
     48 SetVertexParm
     49 ================
     50 */
     51 static ID_INLINE void SetVertexParm( renderParm_t rp, const float * value ) {
     52 	renderProgManager.SetUniformValue( rp, value );
     53 }
     54 
     55 /*
     56 ================
     57 SetVertexParms
     58 ================
     59 */
     60 static ID_INLINE void SetVertexParms( renderParm_t rp, const float * value, int num ) {
     61 	for ( int i = 0; i < num; i++ ) {
     62 		renderProgManager.SetUniformValue( (renderParm_t)( rp + i ), value + ( i * 4 ) );
     63 	}
     64 }
     65 
     66 /*
     67 ================
     68 SetFragmentParm
     69 ================
     70 */
     71 static ID_INLINE void SetFragmentParm( renderParm_t rp, const float * value ) {
     72 	renderProgManager.SetUniformValue( rp, value );
     73 }
     74 
     75 /*
     76 ================
     77 RB_SetMVP
     78 ================
     79 */
     80 void RB_SetMVP( const idRenderMatrix & mvp ) { 
     81 	SetVertexParms( RENDERPARM_MVPMATRIX_X, mvp[0], 4 );
     82 }
     83 
     84 /*
     85 ================
     86 RB_SetMVPWithStereoOffset
     87 ================
     88 */
     89 static void RB_SetMVPWithStereoOffset( const idRenderMatrix & mvp, const float stereoOffset ) { 
     90 	idRenderMatrix offset = mvp;
     91 	offset[0][3] += stereoOffset;
     92 
     93 	SetVertexParms( RENDERPARM_MVPMATRIX_X, offset[0], 4 );
     94 }
     95 
     96 static const float zero[4] = { 0, 0, 0, 0 };
     97 static const float one[4] = { 1, 1, 1, 1 };
     98 static const float negOne[4] = { -1, -1, -1, -1 };
     99 
    100 /*
    101 ================
    102 RB_SetVertexColorParms
    103 ================
    104 */
    105 static void RB_SetVertexColorParms( stageVertexColor_t svc ) {
    106 	switch ( svc ) {
    107 		case SVC_IGNORE:
    108 			SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, zero );
    109 			SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, one );
    110 			break;
    111 		case SVC_MODULATE:
    112 			SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, one );
    113 			SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, zero );
    114 			break;
    115 		case SVC_INVERSE_MODULATE:
    116 			SetVertexParm( RENDERPARM_VERTEXCOLOR_MODULATE, negOne );
    117 			SetVertexParm( RENDERPARM_VERTEXCOLOR_ADD, one );
    118 			break;
    119 	}
    120 }
    121 
    122 /*
    123 ================
    124 RB_DrawElementsWithCounters
    125 ================
    126 */
    127 void RB_DrawElementsWithCounters( const drawSurf_t *surf ) {
    128 	// get vertex buffer
    129 	const vertCacheHandle_t vbHandle = surf->ambientCache;
    130 	idVertexBuffer * vertexBuffer;
    131 	if ( vertexCache.CacheIsStatic( vbHandle ) ) {
    132 		vertexBuffer = &vertexCache.staticData.vertexBuffer;
    133 	} else {
    134 		const uint64 frameNum = (int)( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
    135 		if ( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) {
    136 			idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" );
    137 			return;
    138 		}
    139 		vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer;
    140 	}
    141 	const int vertOffset = (int)( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
    142 
    143 	// get index buffer
    144 	const vertCacheHandle_t ibHandle = surf->indexCache;
    145 	idIndexBuffer * indexBuffer;
    146 	if ( vertexCache.CacheIsStatic( ibHandle ) ) {
    147 		indexBuffer = &vertexCache.staticData.indexBuffer;
    148 	} else {
    149 		const uint64 frameNum = (int)( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
    150 		if ( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) {
    151 			idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" );
    152 			return;
    153 		}
    154 		indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer;
    155 	}
    156 	const int indexOffset = (int)( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
    157 
    158 	RENDERLOG_PRINTF( "Binding Buffers: %p:%i %p:%i\n", vertexBuffer, vertOffset, indexBuffer, indexOffset );
    159 
    160 	if ( surf->jointCache ) {
    161 		if ( !verify( renderProgManager.ShaderUsesJoints() ) ) {
    162 			return;
    163 		}
    164 	} else {
    165 		if ( !verify( !renderProgManager.ShaderUsesJoints() || renderProgManager.ShaderHasOptionalSkinning() ) ) {
    166 			return;
    167 		}
    168 	}
    169 
    170 
    171 	if ( surf->jointCache ) {
    172 		idJointBuffer jointBuffer;
    173 		if ( !vertexCache.GetJointBuffer( surf->jointCache, &jointBuffer ) ) {
    174 			idLib::Warning( "RB_DrawElementsWithCounters, jointBuffer == NULL" );
    175 			return;
    176 		}
    177 		assert( ( jointBuffer.GetOffset() & ( glConfig.uniformBufferOffsetAlignment - 1 ) ) == 0 );
    178 
    179 		const GLuint ubo = reinterpret_cast< GLuint >( jointBuffer.GetAPIObject() );
    180 		qglBindBufferRange( GL_UNIFORM_BUFFER, 0, ubo, jointBuffer.GetOffset(), jointBuffer.GetNumJoints() * sizeof( idJointMat ) );
    181 	}
    182 
    183 	renderProgManager.CommitUniforms();
    184 
    185 	if ( backEnd.glState.currentIndexBuffer != (GLuint)indexBuffer->GetAPIObject() || !r_useStateCaching.GetBool() ) {
    186 		qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, (GLuint)indexBuffer->GetAPIObject() );
    187 		backEnd.glState.currentIndexBuffer = (GLuint)indexBuffer->GetAPIObject();
    188 	}
    189 
    190 	if ( ( backEnd.glState.vertexLayout != LAYOUT_DRAW_VERT ) || ( backEnd.glState.currentVertexBuffer != (GLuint)vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) {
    191 		qglBindBufferARB( GL_ARRAY_BUFFER_ARB, (GLuint)vertexBuffer->GetAPIObject() );
    192 		backEnd.glState.currentVertexBuffer = (GLuint)vertexBuffer->GetAPIObject();
    193 
    194 		qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_VERTEX );
    195 		qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_NORMAL );
    196 		qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_COLOR );
    197 		qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_COLOR2 );
    198 		qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_ST );
    199 		qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_TANGENT );
    200 
    201 		qglVertexAttribPointerARB( PC_ATTRIB_INDEX_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof( idDrawVert ), (void *)( DRAWVERT_XYZ_OFFSET ) );
    202 		qglVertexAttribPointerARB( PC_ATTRIB_INDEX_NORMAL, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), (void *)( DRAWVERT_NORMAL_OFFSET ) );
    203 		qglVertexAttribPointerARB( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), (void *)( DRAWVERT_COLOR_OFFSET ) );
    204 		qglVertexAttribPointerARB( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), (void *)( DRAWVERT_COLOR2_OFFSET ) );
    205 		qglVertexAttribPointerARB( PC_ATTRIB_INDEX_ST, 2, GL_HALF_FLOAT, GL_TRUE, sizeof( idDrawVert ), (void *)( DRAWVERT_ST_OFFSET ) );
    206 		qglVertexAttribPointerARB( PC_ATTRIB_INDEX_TANGENT, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idDrawVert ), (void *)( DRAWVERT_TANGENT_OFFSET ) );
    207 
    208 		backEnd.glState.vertexLayout = LAYOUT_DRAW_VERT;
    209 	}
    210 	
    211 	qglDrawElementsBaseVertex( GL_TRIANGLES, 
    212 							  r_singleTriangle.GetBool() ? 3 : surf->numIndexes,
    213 							  GL_INDEX_TYPE,
    214 							  (triIndex_t *)indexOffset,
    215 							  vertOffset / sizeof ( idDrawVert ) );
    216 							  
    217 
    218 }
    219 
    220 /*
    221 ======================
    222 RB_GetShaderTextureMatrix
    223 ======================
    224 */
    225 static void RB_GetShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture, float matrix[16] ) {
    226 	matrix[0*4+0] = shaderRegisters[ texture->matrix[0][0] ];
    227 	matrix[1*4+0] = shaderRegisters[ texture->matrix[0][1] ];
    228 	matrix[2*4+0] = 0.0f;
    229 	matrix[3*4+0] = shaderRegisters[ texture->matrix[0][2] ];
    230 
    231 	matrix[0*4+1] = shaderRegisters[ texture->matrix[1][0] ];
    232 	matrix[1*4+1] = shaderRegisters[ texture->matrix[1][1] ];
    233 	matrix[2*4+1] = 0.0f;
    234 	matrix[3*4+1] = shaderRegisters[ texture->matrix[1][2] ];
    235 
    236 	// we attempt to keep scrolls from generating incredibly large texture values, but
    237 	// center rotations and center scales can still generate offsets that need to be > 1
    238 	if ( matrix[3*4+0] < -40.0f || matrix[12] > 40.0f ) {
    239 		matrix[3*4+0] -= (int)matrix[3*4+0];
    240 	}
    241 	if ( matrix[13] < -40.0f || matrix[13] > 40.0f ) {
    242 		matrix[13] -= (int)matrix[13];
    243 	}
    244 
    245 	matrix[0*4+2] = 0.0f;
    246 	matrix[1*4+2] = 0.0f;
    247 	matrix[2*4+2] = 1.0f;
    248 	matrix[3*4+2] = 0.0f;
    249 
    250 	matrix[0*4+3] = 0.0f;
    251 	matrix[1*4+3] = 0.0f;
    252 	matrix[2*4+3] = 0.0f;
    253 	matrix[3*4+3] = 1.0f;
    254 }
    255 
    256 /*
    257 ======================
    258 RB_LoadShaderTextureMatrix
    259 ======================
    260 */
    261 static void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ) {	
    262 	float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
    263 	float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
    264 
    265 	if ( texture->hasMatrix ) {
    266 		float matrix[16];
    267 		RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix );
    268 		texS[0] = matrix[0*4+0];
    269 		texS[1] = matrix[1*4+0];
    270 		texS[2] = matrix[2*4+0];
    271 		texS[3] = matrix[3*4+0];
    272 	
    273 		texT[0] = matrix[0*4+1];
    274 		texT[1] = matrix[1*4+1];
    275 		texT[2] = matrix[2*4+1];
    276 		texT[3] = matrix[3*4+1];
    277 
    278 		RENDERLOG_PRINTF( "Setting Texture Matrix\n");
    279 		renderLog.Indent();
    280 		RENDERLOG_PRINTF( "Texture Matrix S : %4.3f, %4.3f, %4.3f, %4.3f\n", texS[0], texS[1], texS[2], texS[3] );
    281 		RENDERLOG_PRINTF( "Texture Matrix T : %4.3f, %4.3f, %4.3f, %4.3f\n", texT[0], texT[1], texT[2], texT[3] );
    282 		renderLog.Outdent();
    283 	} 
    284 
    285 	SetVertexParm( RENDERPARM_TEXTUREMATRIX_S, texS );
    286 	SetVertexParm( RENDERPARM_TEXTUREMATRIX_T, texT );
    287 }
    288 
    289 /*
    290 =====================
    291 RB_BakeTextureMatrixIntoTexgen
    292 =====================
    293 */
    294 static void RB_BakeTextureMatrixIntoTexgen( idPlane lightProject[3], const float *textureMatrix ) {
    295 	float genMatrix[16];
    296 	float final[16];
    297 
    298 	genMatrix[0*4+0] = lightProject[0][0];
    299 	genMatrix[1*4+0] = lightProject[0][1];
    300 	genMatrix[2*4+0] = lightProject[0][2];
    301 	genMatrix[3*4+0] = lightProject[0][3];
    302 
    303 	genMatrix[0*4+1] = lightProject[1][0];
    304 	genMatrix[1*4+1] = lightProject[1][1];
    305 	genMatrix[2*4+1] = lightProject[1][2];
    306 	genMatrix[3*4+1] = lightProject[1][3];
    307 
    308 	genMatrix[0*4+2] = 0.0f;
    309 	genMatrix[1*4+2] = 0.0f;
    310 	genMatrix[2*4+2] = 0.0f;
    311 	genMatrix[3*4+2] = 0.0f;
    312 
    313 	genMatrix[0*4+3] = lightProject[2][0];
    314 	genMatrix[1*4+3] = lightProject[2][1];
    315 	genMatrix[2*4+3] = lightProject[2][2];
    316 	genMatrix[3*4+3] = lightProject[2][3];
    317 
    318 	R_MatrixMultiply( genMatrix, textureMatrix, final );
    319 
    320 	lightProject[0][0] = final[0*4+0];
    321 	lightProject[0][1] = final[1*4+0];
    322 	lightProject[0][2] = final[2*4+0];
    323 	lightProject[0][3] = final[3*4+0];
    324 
    325 	lightProject[1][0] = final[0*4+1];
    326 	lightProject[1][1] = final[1*4+1];
    327 	lightProject[1][2] = final[2*4+1];
    328 	lightProject[1][3] = final[3*4+1];
    329 }
    330 
    331 /*
    332 ======================
    333 RB_BindVariableStageImage
    334 
    335 Handles generating a cinematic frame if needed
    336 ======================
    337 */
    338 static void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters ) {
    339 	if ( texture->cinematic ) {
    340 		cinData_t cin;
    341 
    342 		if ( r_skipDynamicTextures.GetBool() ) {
    343 			globalImages->defaultImage->Bind();
    344 			return;
    345 		}
    346 
    347 		// offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?)
    348 		// We make no attempt to optimize for multiple identical cinematics being in view, or
    349 		// for cinematics going at a lower framerate than the renderer.
    350 		cin = texture->cinematic->ImageForTime( backEnd.viewDef->renderView.time[0] + idMath::Ftoi( 1000.0f * backEnd.viewDef->renderView.shaderParms[11] ) );
    351 		if ( cin.imageY != NULL ) {
    352 			GL_SelectTexture( 0 );
    353 			cin.imageY->Bind();
    354 			GL_SelectTexture( 1 );
    355 			cin.imageCr->Bind();
    356 			GL_SelectTexture( 2 );
    357 			cin.imageCb->Bind();
    358 		} else {
    359 			globalImages->blackImage->Bind();
    360 			// because the shaders may have already been set - we need to make sure we are not using a bink shader which would 
    361 			// display incorrectly.  We may want to get rid of RB_BindVariableStageImage and inline the code so that the
    362 			// SWF GUI case is handled better, too
    363 			renderProgManager.BindShader_TextureVertexColor();
    364 		}
    365 	} else {
    366 		// FIXME: see why image is invalid
    367 		if ( texture->image != NULL ) {
    368 			texture->image->Bind();
    369 		}
    370 	}
    371 }
    372 
    373 /*
    374 ================
    375 RB_PrepareStageTexturing
    376 ================
    377 */
    378 static void RB_PrepareStageTexturing( const shaderStage_t * pStage,  const drawSurf_t * surf ) {
    379 	float useTexGenParm[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    380 
    381 	// set the texture matrix if needed
    382 	RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture );
    383 
    384 	// texgens
    385 	if ( pStage->texture.texgen == TG_REFLECT_CUBE ) {
    386 
    387 		// see if there is also a bump map specified
    388 		const shaderStage_t *bumpStage = surf->material->GetBumpStage();
    389 		if ( bumpStage != NULL ) {
    390 			// per-pixel reflection mapping with bump mapping
    391 			GL_SelectTexture( 1 );
    392 			bumpStage->texture.image->Bind();
    393 			GL_SelectTexture( 0 );
    394 
    395 			RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Bumpy Environment\n" );
    396 			if ( surf->jointCache ) {
    397 				renderProgManager.BindShader_BumpyEnvironmentSkinned();
    398 			} else {
    399 				renderProgManager.BindShader_BumpyEnvironment();
    400 			}
    401 		} else {
    402 			RENDERLOG_PRINTF( "TexGen: TG_REFLECT_CUBE: Environment\n" );
    403 			if ( surf->jointCache ) {
    404 				renderProgManager.BindShader_EnvironmentSkinned();
    405 			} else {
    406 				renderProgManager.BindShader_Environment();
    407 			}
    408 		}
    409 
    410 	} else if ( pStage->texture.texgen == TG_SKYBOX_CUBE ) {
    411 
    412 		renderProgManager.BindShader_SkyBox();
    413 
    414 	} else if ( pStage->texture.texgen == TG_WOBBLESKY_CUBE ) {
    415 
    416 		const int * parms = surf->material->GetTexGenRegisters();
    417 
    418 		float wobbleDegrees = surf->shaderRegisters[ parms[0] ] * ( idMath::PI / 180.0f );
    419 		float wobbleSpeed = surf->shaderRegisters[ parms[1] ] * ( 2.0f * idMath::PI / 60.0f );
    420 		float rotateSpeed = surf->shaderRegisters[ parms[2] ] * ( 2.0f * idMath::PI / 60.0f );
    421 
    422 		idVec3 axis[3];
    423 		{
    424 			// very ad-hoc "wobble" transform
    425 			float s, c;
    426 			idMath::SinCos( wobbleSpeed * backEnd.viewDef->renderView.time[0] * 0.001f, s, c );
    427 
    428 			float ws, wc;
    429 			idMath::SinCos( wobbleDegrees, ws, wc );
    430 
    431 			axis[2][0] = ws * c;
    432 			axis[2][1] = ws * s;
    433 			axis[2][2] = wc;
    434 
    435 			axis[1][0] = -s * s * ws;
    436 			axis[1][2] = -s * ws * ws;
    437 			axis[1][1] = idMath::Sqrt( idMath::Fabs( 1.0f - ( axis[1][0] * axis[1][0] + axis[1][2] * axis[1][2] ) ) );
    438 
    439 			// make the second vector exactly perpendicular to the first
    440 			axis[1] -= ( axis[2] * axis[1] ) * axis[2];
    441 			axis[1].Normalize();
    442 
    443 			// construct the third with a cross
    444 			axis[0].Cross( axis[1], axis[2] );
    445 		}
    446 
    447 		// add the rotate
    448 		float rs, rc;
    449 		idMath::SinCos( rotateSpeed * backEnd.viewDef->renderView.time[0] * 0.001f, rs, rc );
    450 
    451 		float transform[12];
    452 		transform[0*4+0] = axis[0][0] * rc + axis[1][0] * rs;
    453 		transform[0*4+1] = axis[0][1] * rc + axis[1][1] * rs;
    454 		transform[0*4+2] = axis[0][2] * rc + axis[1][2] * rs;
    455 		transform[0*4+3] = 0.0f;
    456 
    457 		transform[1*4+0] = axis[1][0] * rc - axis[0][0] * rs;
    458 		transform[1*4+1] = axis[1][1] * rc - axis[0][1] * rs;
    459 		transform[1*4+2] = axis[1][2] * rc - axis[0][2] * rs;
    460 		transform[1*4+3] = 0.0f;
    461 
    462 		transform[2*4+0] = axis[2][0];
    463 		transform[2*4+1] = axis[2][1];
    464 		transform[2*4+2] = axis[2][2];
    465 		transform[2*4+3] = 0.0f;
    466 
    467 		SetVertexParms( RENDERPARM_WOBBLESKY_X, transform, 3 );
    468 		renderProgManager.BindShader_WobbleSky();
    469 
    470 	} else if ( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) ) {
    471 
    472 		useTexGenParm[0] = 1.0f;
    473 		useTexGenParm[1] = 1.0f;
    474 		useTexGenParm[2] = 1.0f;
    475 		useTexGenParm[3] = 1.0f;
    476 
    477 		float mat[16];
    478 		R_MatrixMultiply( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat );
    479 
    480 		RENDERLOG_PRINTF( "TexGen : %s\n", ( pStage->texture.texgen == TG_SCREEN ) ? "TG_SCREEN" : "TG_SCREEN2" );
    481 		renderLog.Indent();
    482 
    483 		float plane[4];
    484 		plane[0] = mat[0*4+0];
    485 		plane[1] = mat[1*4+0];
    486 		plane[2] = mat[2*4+0];
    487 		plane[3] = mat[3*4+0];
    488 		SetVertexParm( RENDERPARM_TEXGEN_0_S, plane );
    489 		RENDERLOG_PRINTF( "TEXGEN_S = %4.3f, %4.3f, %4.3f, %4.3f\n",  plane[0], plane[1], plane[2], plane[3] );
    490 
    491 		plane[0] = mat[0*4+1];
    492 		plane[1] = mat[1*4+1];
    493 		plane[2] = mat[2*4+1];
    494 		plane[3] = mat[3*4+1];
    495 		SetVertexParm( RENDERPARM_TEXGEN_0_T, plane );
    496 		RENDERLOG_PRINTF( "TEXGEN_T = %4.3f, %4.3f, %4.3f, %4.3f\n",  plane[0], plane[1], plane[2], plane[3] );
    497 
    498 		plane[0] = mat[0*4+3];
    499 		plane[1] = mat[1*4+3];
    500 		plane[2] = mat[2*4+3];
    501 		plane[3] = mat[3*4+3];
    502 		SetVertexParm( RENDERPARM_TEXGEN_0_Q, plane );	
    503 		RENDERLOG_PRINTF( "TEXGEN_Q = %4.3f, %4.3f, %4.3f, %4.3f\n",  plane[0], plane[1], plane[2], plane[3] );
    504 
    505 		renderLog.Outdent();
    506 
    507 	} else if ( pStage->texture.texgen == TG_DIFFUSE_CUBE ) {
    508 
    509 		// As far as I can tell, this is never used
    510 		idLib::Warning( "Using Diffuse Cube! Please contact Brian!" );
    511 
    512 	} else if ( pStage->texture.texgen == TG_GLASSWARP ) {
    513 
    514 		// As far as I can tell, this is never used
    515 		idLib::Warning( "Using GlassWarp! Please contact Brian!" );
    516 	}
    517 
    518 	SetVertexParm( RENDERPARM_TEXGEN_0_ENABLED, useTexGenParm );
    519 }
    520 
    521 /*
    522 ================
    523 RB_FinishStageTexturing
    524 ================
    525 */
    526 static void RB_FinishStageTexturing( const shaderStage_t *pStage, const drawSurf_t *surf ) {
    527 
    528 	if ( pStage->texture.cinematic ) {
    529 		// unbind the extra bink textures
    530 		GL_SelectTexture( 1 );
    531 		globalImages->BindNull();
    532 		GL_SelectTexture( 2 );
    533 		globalImages->BindNull();
    534 		GL_SelectTexture( 0 );
    535 	}
    536 
    537 	if ( pStage->texture.texgen == TG_REFLECT_CUBE ) {
    538 		// see if there is also a bump map specified
    539 		const shaderStage_t *bumpStage = surf->material->GetBumpStage();
    540 		if ( bumpStage != NULL ) {
    541 			// per-pixel reflection mapping with bump mapping
    542 			GL_SelectTexture( 1 );
    543 			globalImages->BindNull();
    544 			GL_SelectTexture( 0 );
    545 		} else {
    546 			// per-pixel reflection mapping without bump mapping
    547 		}
    548 		renderProgManager.Unbind();
    549 	}
    550 }
    551 
    552 /*
    553 =========================================================================================
    554 
    555 DEPTH BUFFER RENDERING
    556 
    557 =========================================================================================
    558 */
    559 
    560 /*
    561 ==================
    562 RB_FillDepthBufferGeneric
    563 ==================
    564 */
    565 static void RB_FillDepthBufferGeneric( const drawSurf_t * const * drawSurfs, int numDrawSurfs ) {
    566 	for ( int i = 0; i < numDrawSurfs; i++ ) {
    567 		const drawSurf_t * drawSurf = drawSurfs[i];
    568 		const idMaterial * shader = drawSurf->material;
    569 
    570 		// translucent surfaces don't put anything in the depth buffer and don't
    571 		// test against it, which makes them fail the mirror clip plane operation
    572 		if ( shader->Coverage() == MC_TRANSLUCENT ) {
    573 			continue;
    574 		}
    575 
    576 		// get the expressions for conditionals / color / texcoords
    577 		const float * regs = drawSurf->shaderRegisters;
    578 
    579 		// if all stages of a material have been conditioned off, don't do anything
    580 		int stage = 0;
    581 		for ( ; stage < shader->GetNumStages(); stage++ ) {		
    582 			const shaderStage_t * pStage = shader->GetStage( stage );
    583 			// check the stage enable condition
    584 			if ( regs[ pStage->conditionRegister ] != 0 ) {
    585 				break;
    586 			}
    587 		}
    588 		if ( stage == shader->GetNumStages() ) {
    589 			continue;
    590 		}
    591 
    592 		// change the matrix if needed
    593 		if ( drawSurf->space != backEnd.currentSpace ) {
    594 			RB_SetMVP( drawSurf->space->mvp );
    595 
    596 			backEnd.currentSpace = drawSurf->space;
    597 		}
    598 
    599 		uint64 surfGLState = 0;
    600 
    601 		// set polygon offset if necessary
    602 		if ( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) {
    603 			surfGLState |= GLS_POLYGON_OFFSET;
    604 			GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() );
    605 		}
    606 
    607 		// subviews will just down-modulate the color buffer
    608 		float color[4];
    609 		if ( shader->GetSort() == SS_SUBVIEW ) {
    610 			surfGLState |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS;
    611 			color[0] = 1.0f;
    612 			color[1] = 1.0f;
    613 			color[2] = 1.0f;
    614 			color[3] = 1.0f;
    615 		} else {
    616 			// others just draw black
    617 			color[0] = 0.0f;
    618 			color[1] = 0.0f;
    619 			color[2] = 0.0f;
    620 			color[3] = 1.0f;
    621 		}
    622 
    623 		renderLog.OpenBlock( shader->GetName() );
    624 
    625 		bool drawSolid = false;
    626 		if ( shader->Coverage() == MC_OPAQUE ) {
    627 			drawSolid = true;
    628 		} else if ( shader->Coverage() == MC_PERFORATED ) {
    629 			// we may have multiple alpha tested stages
    630 			// if the only alpha tested stages are condition register omitted,
    631 			// draw a normal opaque surface
    632 			bool didDraw = false;
    633 
    634 			// perforated surfaces may have multiple alpha tested stages
    635 			for ( stage = 0; stage < shader->GetNumStages(); stage++ ) {		
    636 				const shaderStage_t *pStage = shader->GetStage(stage);
    637 
    638 				if ( !pStage->hasAlphaTest ) {
    639 					continue;
    640 				}
    641 
    642 				// check the stage enable condition
    643 				if ( regs[ pStage->conditionRegister ] == 0 ) {
    644 					continue;
    645 				}
    646 
    647 				// if we at least tried to draw an alpha tested stage,
    648 				// we won't draw the opaque surface
    649 				didDraw = true;
    650 
    651 				// set the alpha modulate
    652 				color[3] = regs[ pStage->color.registers[3] ];
    653 
    654 				// skip the entire stage if alpha would be black
    655 				if ( color[3] <= 0.0f ) {
    656 					continue;
    657 				}
    658 
    659 				uint64 stageGLState = surfGLState;
    660 
    661 				// set privatePolygonOffset if necessary
    662 				if ( pStage->privatePolygonOffset ) {
    663 					GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset );
    664 					stageGLState |= GLS_POLYGON_OFFSET;
    665 				}
    666 
    667 				GL_Color( color );
    668 
    669 #ifdef USE_CORE_PROFILE
    670 				GL_State( stageGLState );
    671 				idVec4 alphaTestValue( regs[ pStage->alphaTestRegister ] );
    672 				SetFragmentParm( RENDERPARM_ALPHA_TEST, alphaTestValue.ToFloatPtr() );
    673 #else
    674 				GL_State( stageGLState | GLS_ALPHATEST_FUNC_GREATER | GLS_ALPHATEST_MAKE_REF( idMath::Ftob( 255.0f * regs[ pStage->alphaTestRegister ] ) ) );
    675 #endif
    676 
    677 				if ( drawSurf->jointCache ) {
    678 					renderProgManager.BindShader_TextureVertexColorSkinned();
    679 				} else {
    680 					renderProgManager.BindShader_TextureVertexColor();
    681 				}
    682 
    683 				RB_SetVertexColorParms( SVC_IGNORE );
    684 
    685 				// bind the texture
    686 				GL_SelectTexture( 0 );
    687 				pStage->texture.image->Bind();
    688 
    689 				// set texture matrix and texGens
    690 				RB_PrepareStageTexturing( pStage, drawSurf );
    691 
    692 				// must render with less-equal for Z-Cull to work properly
    693 				assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS );
    694 
    695 				// draw it
    696 				RB_DrawElementsWithCounters( drawSurf );
    697 
    698 				// clean up
    699 				RB_FinishStageTexturing( pStage, drawSurf );
    700 
    701 				// unset privatePolygonOffset if necessary
    702 				if ( pStage->privatePolygonOffset ) {
    703 					GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() );
    704 				}
    705 			}
    706 
    707 			if ( !didDraw ) {
    708 				drawSolid = true;
    709 			}
    710 		}
    711 
    712 		// draw the entire surface solid
    713 		if ( drawSolid ) {
    714 			if ( shader->GetSort() == SS_SUBVIEW ) {
    715 				renderProgManager.BindShader_Color();
    716 				GL_Color( color );
    717 				GL_State( surfGLState );
    718 			} else {
    719 				if ( drawSurf->jointCache ) {
    720 					renderProgManager.BindShader_DepthSkinned();
    721 				} else {
    722 					renderProgManager.BindShader_Depth();
    723 				}
    724 				GL_State( surfGLState | GLS_ALPHAMASK );
    725 			}
    726 
    727 			// must render with less-equal for Z-Cull to work properly
    728 			assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS );
    729 
    730 			// draw it
    731 			RB_DrawElementsWithCounters( drawSurf );
    732 		}
    733 
    734 		renderLog.CloseBlock();
    735 	}
    736 
    737 #ifdef USE_CORE_PROFILE
    738 	SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() );
    739 #endif
    740 }
    741 
    742 /*
    743 =====================
    744 RB_FillDepthBufferFast
    745 
    746 Optimized fast path code.
    747 
    748 If there are subview surfaces, they must be guarded in the depth buffer to allow
    749 the mirror / subview to show through underneath the current view rendering.
    750 
    751 Surfaces with perforated shaders need the full shader setup done, but should be
    752 drawn after the opaque surfaces.
    753 
    754 The bulk of the surfaces should be simple opaque geometry that can be drawn very rapidly.
    755 
    756 If there are no subview surfaces, we could clear to black and use fast-Z rendering
    757 on the 360.
    758 =====================
    759 */
    760 static void RB_FillDepthBufferFast( drawSurf_t **drawSurfs, int numDrawSurfs ) {
    761 	if ( numDrawSurfs == 0 ) {
    762 		return;
    763 	}
    764 
    765 	// if we are just doing 2D rendering, no need to fill the depth buffer
    766 	if ( backEnd.viewDef->viewEntitys == NULL ) {
    767 		return;
    768 	}
    769 
    770 	renderLog.OpenMainBlock( MRB_FILL_DEPTH_BUFFER );
    771 	renderLog.OpenBlock( "RB_FillDepthBufferFast" );
    772 
    773 	GL_StartDepthPass( backEnd.viewDef->scissor );
    774 
    775 	// force MVP change on first surface
    776 	backEnd.currentSpace = NULL;
    777 
    778 	// draw all the subview surfaces, which will already be at the start of the sorted list,
    779 	// with the general purpose path
    780 	GL_State( GLS_DEFAULT );
    781 
    782 	int	surfNum;
    783 	for ( surfNum = 0; surfNum < numDrawSurfs; surfNum++ ) {
    784 		if ( drawSurfs[surfNum]->material->GetSort() != SS_SUBVIEW ) {
    785 			break;
    786 		}
    787 		RB_FillDepthBufferGeneric( &drawSurfs[surfNum], 1 );
    788 	}
    789 
    790 	const drawSurf_t ** perforatedSurfaces = (const drawSurf_t ** )_alloca( numDrawSurfs * sizeof( drawSurf_t * ) );
    791 	int numPerforatedSurfaces = 0;
    792 
    793 	// draw all the opaque surfaces and build up a list of perforated surfaces that
    794 	// we will defer drawing until all opaque surfaces are done
    795 	GL_State( GLS_DEFAULT );
    796 
    797 	// continue checking past the subview surfaces
    798 	for ( ; surfNum < numDrawSurfs; surfNum++ ) {
    799 		const drawSurf_t * surf = drawSurfs[ surfNum ];
    800 		const idMaterial * shader = surf->material;
    801 
    802 		// translucent surfaces don't put anything in the depth buffer
    803 		if ( shader->Coverage() == MC_TRANSLUCENT ) {
    804 			continue;
    805 		}
    806 		if ( shader->Coverage() == MC_PERFORATED ) {
    807 			// save for later drawing
    808 			perforatedSurfaces[ numPerforatedSurfaces ] = surf;
    809 			numPerforatedSurfaces++;
    810 			continue;
    811 		}
    812 
    813 		// set polygon offset?
    814 
    815 		// set mvp matrix
    816 		if ( surf->space != backEnd.currentSpace ) {
    817 			RB_SetMVP( surf->space->mvp );
    818 			backEnd.currentSpace = surf->space;
    819 		}
    820 
    821 		renderLog.OpenBlock( shader->GetName() );
    822 
    823 		if ( surf->jointCache ) {
    824 			renderProgManager.BindShader_DepthSkinned();
    825 		} else {
    826 			renderProgManager.BindShader_Depth();
    827 		}
    828 
    829 		// must render with less-equal for Z-Cull to work properly
    830 		assert( ( GL_GetCurrentState() & GLS_DEPTHFUNC_BITS ) == GLS_DEPTHFUNC_LESS );
    831 
    832 		// draw it solid
    833 		RB_DrawElementsWithCounters( surf );
    834 
    835 		renderLog.CloseBlock();
    836 	}
    837 
    838 	// draw all perforated surfaces with the general code path
    839 	if ( numPerforatedSurfaces > 0 ) {
    840 		RB_FillDepthBufferGeneric( perforatedSurfaces, numPerforatedSurfaces );
    841 	}
    842 
    843 	// Allow platform specific data to be collected after the depth pass.
    844 	GL_FinishDepthPass();
    845 
    846 	renderLog.CloseBlock();
    847 	renderLog.CloseMainBlock();
    848 }
    849 
    850 /*
    851 =========================================================================================
    852 
    853 GENERAL INTERACTION RENDERING
    854 
    855 =========================================================================================
    856 */
    857 
    858 const int INTERACTION_TEXUNIT_BUMP			= 0;
    859 const int INTERACTION_TEXUNIT_FALLOFF		= 1;
    860 const int INTERACTION_TEXUNIT_PROJECTION	= 2;
    861 const int INTERACTION_TEXUNIT_DIFFUSE		= 3;
    862 const int INTERACTION_TEXUNIT_SPECULAR		= 4;
    863 
    864 /*
    865 ==================
    866 RB_SetupInteractionStage
    867 ==================
    868 */
    869 static void RB_SetupInteractionStage( const shaderStage_t *surfaceStage, const float *surfaceRegs, const float lightColor[4],
    870 									idVec4 matrix[2], float color[4] ) {
    871 
    872 	if ( surfaceStage->texture.hasMatrix ) {
    873 		matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]];
    874 		matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]];
    875 		matrix[0][2] = 0.0f;
    876 		matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]];
    877 
    878 		matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]];
    879 		matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]];
    880 		matrix[1][2] = 0.0f;
    881 		matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]];
    882 
    883 		// we attempt to keep scrolls from generating incredibly large texture values, but
    884 		// center rotations and center scales can still generate offsets that need to be > 1
    885 		if ( matrix[0][3] < -40.0f || matrix[0][3] > 40.0f ) {
    886 			matrix[0][3] -= idMath::Ftoi( matrix[0][3] );
    887 		}
    888 		if ( matrix[1][3] < -40.0f || matrix[1][3] > 40.0f ) {
    889 			matrix[1][3] -= idMath::Ftoi( matrix[1][3] );
    890 		}
    891 	} else {
    892 		matrix[0][0] = 1.0f;
    893 		matrix[0][1] = 0.0f;
    894 		matrix[0][2] = 0.0f;
    895 		matrix[0][3] = 0.0f;
    896 
    897 		matrix[1][0] = 0.0f;
    898 		matrix[1][1] = 1.0f;
    899 		matrix[1][2] = 0.0f;
    900 		matrix[1][3] = 0.0f;
    901 	}
    902 
    903 	if ( color != NULL ) {
    904 		for ( int i = 0; i < 4; i++ ) {
    905 			// clamp here, so cards with a greater range don't look different.
    906 			// we could perform overbrighting like we do for lights, but
    907 			// it doesn't currently look worth it.
    908 			color[i] = idMath::ClampFloat( 0.0f, 1.0f, surfaceRegs[surfaceStage->color.registers[i]] ) * lightColor[i];
    909 		}
    910 	}
    911 }
    912 
    913 /*
    914 =================
    915 RB_DrawSingleInteraction
    916 =================
    917 */
    918 static void RB_DrawSingleInteraction( drawInteraction_t * din ) {
    919 	if ( din->bumpImage == NULL ) {
    920 		// stage wasn't actually an interaction
    921 		return;
    922 	}
    923 
    924 	if ( din->diffuseImage == NULL || r_skipDiffuse.GetBool() ) {
    925 		// this isn't a YCoCg black, but it doesn't matter, because
    926 		// the diffuseColor will also be 0
    927 		din->diffuseImage = globalImages->blackImage;
    928 	}
    929 	if ( din->specularImage == NULL || r_skipSpecular.GetBool() || din->ambientLight ) {
    930 		din->specularImage = globalImages->blackImage;
    931 	}
    932 	if ( r_skipBump.GetBool() ) {
    933 		din->bumpImage = globalImages->flatNormalMap;
    934 	}
    935 
    936 	// if we wouldn't draw anything, don't call the Draw function
    937 	const bool diffuseIsBlack = ( din->diffuseImage == globalImages->blackImage )
    938 									|| ( ( din->diffuseColor[0] <= 0 ) && ( din->diffuseColor[1] <= 0 ) && ( din->diffuseColor[2] <= 0 ) );
    939 	const bool specularIsBlack = ( din->specularImage == globalImages->blackImage )
    940 									|| ( ( din->specularColor[0] <= 0 ) && ( din->specularColor[1] <= 0 ) && ( din->specularColor[2] <= 0 ) );
    941 	if ( diffuseIsBlack && specularIsBlack ) {
    942 		return;
    943 	}
    944 
    945 	// bump matrix
    946 	SetVertexParm( RENDERPARM_BUMPMATRIX_S, din->bumpMatrix[0].ToFloatPtr() );
    947 	SetVertexParm( RENDERPARM_BUMPMATRIX_T, din->bumpMatrix[1].ToFloatPtr() );
    948 
    949 	// diffuse matrix
    950 	SetVertexParm( RENDERPARM_DIFFUSEMATRIX_S, din->diffuseMatrix[0].ToFloatPtr() );
    951 	SetVertexParm( RENDERPARM_DIFFUSEMATRIX_T, din->diffuseMatrix[1].ToFloatPtr() );
    952 
    953 	// specular matrix
    954 	SetVertexParm( RENDERPARM_SPECULARMATRIX_S, din->specularMatrix[0].ToFloatPtr() );
    955 	SetVertexParm( RENDERPARM_SPECULARMATRIX_T, din->specularMatrix[1].ToFloatPtr() );
    956 
    957 	RB_SetVertexColorParms( din->vertexColor );
    958 
    959 	SetFragmentParm( RENDERPARM_DIFFUSEMODIFIER, din->diffuseColor.ToFloatPtr() );
    960 	SetFragmentParm( RENDERPARM_SPECULARMODIFIER, din->specularColor.ToFloatPtr() );
    961 
    962 	// texture 0 will be the per-surface bump map
    963  	GL_SelectTexture( INTERACTION_TEXUNIT_BUMP );
    964 	din->bumpImage->Bind();
    965 
    966 	// texture 3 is the per-surface diffuse map
    967 	GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE );
    968 	din->diffuseImage->Bind();
    969 
    970 	// texture 4 is the per-surface specular map
    971 	GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR );
    972 	din->specularImage->Bind();
    973 
    974 	RB_DrawElementsWithCounters( din->surf );
    975 }
    976 
    977 /*
    978 =================
    979 RB_SetupForFastPathInteractions
    980 
    981 These are common for all fast path surfaces
    982 =================
    983 */
    984 static void RB_SetupForFastPathInteractions( const idVec4 & diffuseColor, const idVec4 & specularColor ) {
    985 	const idVec4 sMatrix( 1, 0, 0, 0 );
    986 	const idVec4 tMatrix( 0, 1, 0, 0 );
    987 
    988 	// bump matrix
    989 	SetVertexParm( RENDERPARM_BUMPMATRIX_S, sMatrix.ToFloatPtr() );
    990 	SetVertexParm( RENDERPARM_BUMPMATRIX_T, tMatrix.ToFloatPtr() );
    991 
    992 	// diffuse matrix
    993 	SetVertexParm( RENDERPARM_DIFFUSEMATRIX_S, sMatrix.ToFloatPtr() );
    994 	SetVertexParm( RENDERPARM_DIFFUSEMATRIX_T, tMatrix.ToFloatPtr() );
    995 
    996 	// specular matrix
    997 	SetVertexParm( RENDERPARM_SPECULARMATRIX_S, sMatrix.ToFloatPtr() );
    998 	SetVertexParm( RENDERPARM_SPECULARMATRIX_T, tMatrix.ToFloatPtr() );
    999 
   1000 	RB_SetVertexColorParms( SVC_IGNORE );
   1001 
   1002 	SetFragmentParm( RENDERPARM_DIFFUSEMODIFIER, diffuseColor.ToFloatPtr() );
   1003 	SetFragmentParm( RENDERPARM_SPECULARMODIFIER, specularColor.ToFloatPtr() );
   1004 }
   1005 
   1006 /*
   1007 =============
   1008 RB_RenderInteractions
   1009 
   1010 With added sorting and trivial path work.
   1011 =============
   1012 */
   1013 static void RB_RenderInteractions( const drawSurf_t *surfList, const viewLight_t * vLight, int depthFunc, bool performStencilTest, bool useLightDepthBounds ) {
   1014 	if ( surfList == NULL ) {
   1015 		return;
   1016 	}
   1017 
   1018 	// change the scissor if needed, it will be constant across all the surfaces lit by the light
   1019 	if ( !backEnd.currentScissor.Equals( vLight->scissorRect ) && r_useScissor.GetBool() ) {
   1020 		GL_Scissor( backEnd.viewDef->viewport.x1 + vLight->scissorRect.x1, 
   1021 					backEnd.viewDef->viewport.y1 + vLight->scissorRect.y1,
   1022 					vLight->scissorRect.x2 + 1 - vLight->scissorRect.x1,
   1023 					vLight->scissorRect.y2 + 1 - vLight->scissorRect.y1 );
   1024 		backEnd.currentScissor = vLight->scissorRect;
   1025 	}
   1026 
   1027 	// perform setup here that will be constant for all interactions
   1028 	if ( performStencilTest ) {
   1029 		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 ) );
   1030 
   1031 	} else {
   1032 		GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | depthFunc | GLS_STENCIL_FUNC_ALWAYS );
   1033 	}
   1034 
   1035 	// some rare lights have multiple animating stages, loop over them outside the surface list
   1036 	const idMaterial * lightShader = vLight->lightShader;
   1037 	const float * lightRegs = vLight->shaderRegisters;
   1038 
   1039 	drawInteraction_t inter = {};
   1040 	inter.ambientLight = lightShader->IsAmbientLight();
   1041 
   1042 	//---------------------------------
   1043 	// Split out the complex surfaces from the fast-path surfaces
   1044 	// so we can do the fast path ones all in a row.
   1045 	// The surfaces should already be sorted by space because they
   1046 	// are added single-threaded, and there is only a negligable amount
   1047 	// of benefit to trying to sort by materials.
   1048 	//---------------------------------
   1049 	static const int MAX_INTERACTIONS_PER_LIGHT = 1024;
   1050 	static const int MAX_COMPLEX_INTERACTIONS_PER_LIGHT = 128;
   1051 	idStaticList< const drawSurf_t *, MAX_INTERACTIONS_PER_LIGHT > allSurfaces;
   1052 	idStaticList< const drawSurf_t *, MAX_COMPLEX_INTERACTIONS_PER_LIGHT > complexSurfaces;
   1053 	for ( const drawSurf_t * walk = surfList; walk != NULL; walk = walk->nextOnLight ) {
   1054 
   1055 		// make sure the triangle culling is done
   1056 		if ( walk->shadowVolumeState != SHADOWVOLUME_DONE ) {
   1057 			assert( walk->shadowVolumeState == SHADOWVOLUME_UNFINISHED || walk->shadowVolumeState == SHADOWVOLUME_DONE );
   1058 
   1059 			uint64 start = Sys_Microseconds();
   1060 			while ( walk->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) {
   1061 				Sys_Yield();
   1062 			}
   1063 			uint64 end = Sys_Microseconds();
   1064 
   1065 			backEnd.pc.shadowMicroSec += end - start;
   1066 		}
   1067 
   1068 		const idMaterial * surfaceShader = walk->material;
   1069 		if ( surfaceShader->GetFastPathBumpImage() ) {
   1070 			allSurfaces.Append( walk );
   1071 		} else {
   1072 			complexSurfaces.Append( walk );
   1073 		}
   1074 	}
   1075 	for ( int i = 0; i < complexSurfaces.Num(); i++ ) {
   1076 		allSurfaces.Append( complexSurfaces[i] );
   1077 	}
   1078 
   1079 	bool lightDepthBoundsDisabled = false;
   1080 
   1081 	for ( int lightStageNum = 0; lightStageNum < lightShader->GetNumStages(); lightStageNum++ ) {
   1082 		const shaderStage_t	*lightStage = lightShader->GetStage( lightStageNum );
   1083 
   1084 		// ignore stages that fail the condition
   1085 		if ( !lightRegs[ lightStage->conditionRegister ] ) {
   1086 			continue;
   1087 		}
   1088 
   1089 		const float lightScale = r_lightScale.GetFloat();
   1090 		const idVec4 lightColor(
   1091 			lightScale * lightRegs[ lightStage->color.registers[0] ],
   1092 			lightScale * lightRegs[ lightStage->color.registers[1] ],
   1093 			lightScale * lightRegs[ lightStage->color.registers[2] ],
   1094 			lightRegs[ lightStage->color.registers[3] ] );
   1095 		// apply the world-global overbright and the 2x factor for specular
   1096 		const idVec4 diffuseColor = lightColor;
   1097 		const idVec4 specularColor = lightColor * 2.0f;
   1098 
   1099 		float lightTextureMatrix[16];
   1100 		if ( lightStage->texture.hasMatrix ) {
   1101 			RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, lightTextureMatrix );
   1102 		}
   1103 
   1104 		// texture 1 will be the light falloff texture
   1105 		GL_SelectTexture( INTERACTION_TEXUNIT_FALLOFF );
   1106 		vLight->falloffImage->Bind();
   1107 
   1108 		// texture 2 will be the light projection texture
   1109 		GL_SelectTexture( INTERACTION_TEXUNIT_PROJECTION );
   1110 		lightStage->texture.image->Bind();
   1111 
   1112 		// force the light textures to not use anisotropic filtering, which is wasted on them
   1113 		// all of the texture sampler parms should be constant for all interactions, only
   1114 		// the actual texture image bindings will change
   1115 
   1116 		//----------------------------------
   1117 		// For all surfaces on this light list, generate an interaction for this light stage
   1118 		//----------------------------------
   1119 
   1120 		// setup renderparms assuming we will be drawing trivial surfaces first
   1121 		RB_SetupForFastPathInteractions( diffuseColor, specularColor );
   1122 
   1123 		// even if the space does not change between light stages, each light stage may need a different lightTextureMatrix baked in
   1124 		backEnd.currentSpace = NULL;
   1125 
   1126 		for ( int sortedSurfNum = 0; sortedSurfNum < allSurfaces.Num(); sortedSurfNum++ ) {
   1127 			const drawSurf_t * const surf = allSurfaces[ sortedSurfNum ];
   1128 
   1129 			// select the render prog
   1130 			if ( lightShader->IsAmbientLight() ) {
   1131 				if ( surf->jointCache ) {
   1132 					renderProgManager.BindShader_InteractionAmbientSkinned();
   1133 				} else {
   1134 					renderProgManager.BindShader_InteractionAmbient();
   1135 				}
   1136 			} else {
   1137 				if ( surf->jointCache ) {
   1138 					renderProgManager.BindShader_InteractionSkinned();
   1139 				} else {
   1140 					renderProgManager.BindShader_Interaction();
   1141 				}
   1142 			}
   1143 
   1144 			const idMaterial * surfaceShader = surf->material;
   1145 			const float * surfaceRegs = surf->shaderRegisters;
   1146 
   1147 			inter.surf = surf;
   1148 
   1149 			// change the MVP matrix, view/light origin and light projection vectors if needed
   1150 			if ( surf->space != backEnd.currentSpace ) {
   1151 				backEnd.currentSpace = surf->space;
   1152 
   1153 				// turn off the light depth bounds test if this model is rendered with a depth hack
   1154 				if ( useLightDepthBounds ) {
   1155 					if ( !surf->space->weaponDepthHack && surf->space->modelDepthHack == 0.0f ) {
   1156 						if ( lightDepthBoundsDisabled ) {
   1157 							GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax );
   1158 							lightDepthBoundsDisabled = false;
   1159 						}
   1160 					} else {
   1161 						if ( !lightDepthBoundsDisabled ) {
   1162 							GL_DepthBoundsTest( 0.0f, 0.0f );
   1163 							lightDepthBoundsDisabled = true;
   1164 						}
   1165 					}
   1166 				}
   1167 
   1168 				// model-view-projection
   1169 				RB_SetMVP( surf->space->mvp );
   1170 
   1171 				// tranform the light/view origin into model local space
   1172 				idVec4 localLightOrigin( 0.0f );
   1173 				idVec4 localViewOrigin( 1.0f );
   1174 				R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, localLightOrigin.ToVec3() );
   1175 				R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewOrigin.ToVec3() );
   1176 
   1177 				// set the local light/view origin
   1178 				SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLightOrigin.ToFloatPtr() );
   1179 				SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() );
   1180 
   1181 				// transform the light project into model local space
   1182 				idPlane lightProjection[4];
   1183 				for ( int i = 0; i < 4; i++ ) {
   1184 					R_GlobalPlaneToLocal( surf->space->modelMatrix, vLight->lightProject[i], lightProjection[i] );
   1185 				}
   1186 
   1187 				// optionally multiply the local light projection by the light texture matrix
   1188 				if ( lightStage->texture.hasMatrix ) {
   1189 					RB_BakeTextureMatrixIntoTexgen( lightProjection, lightTextureMatrix );
   1190 				}
   1191 
   1192 				// set the light projection
   1193 				SetVertexParm( RENDERPARM_LIGHTPROJECTION_S, lightProjection[0].ToFloatPtr() );
   1194 				SetVertexParm( RENDERPARM_LIGHTPROJECTION_T, lightProjection[1].ToFloatPtr() );
   1195 				SetVertexParm( RENDERPARM_LIGHTPROJECTION_Q, lightProjection[2].ToFloatPtr() );
   1196 				SetVertexParm( RENDERPARM_LIGHTFALLOFF_S, lightProjection[3].ToFloatPtr() );
   1197 			}
   1198 
   1199 			// check for the fast path
   1200 			if ( surfaceShader->GetFastPathBumpImage() && !r_skipInteractionFastPath.GetBool() ) {
   1201 				renderLog.OpenBlock( surf->material->GetName() );
   1202 
   1203 				// texture 0 will be the per-surface bump map
   1204 				GL_SelectTexture( INTERACTION_TEXUNIT_BUMP );
   1205 				surfaceShader->GetFastPathBumpImage()->Bind();
   1206 
   1207 				// texture 3 is the per-surface diffuse map
   1208 				GL_SelectTexture( INTERACTION_TEXUNIT_DIFFUSE );
   1209 				surfaceShader->GetFastPathDiffuseImage()->Bind();
   1210 
   1211 				// texture 4 is the per-surface specular map
   1212 				GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR );
   1213 				surfaceShader->GetFastPathSpecularImage()->Bind();
   1214 
   1215 				RB_DrawElementsWithCounters( surf );
   1216 
   1217 				renderLog.CloseBlock();
   1218 				continue;
   1219 			}
   1220 			
   1221 			renderLog.OpenBlock( surf->material->GetName() );
   1222 
   1223 			inter.bumpImage = NULL;
   1224 			inter.specularImage = NULL;
   1225 			inter.diffuseImage = NULL;
   1226 			inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0;
   1227 			inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0;
   1228 
   1229 			// go through the individual surface stages
   1230 			//
   1231 			// This is somewhat arcane because of the old support for video cards that had to render
   1232 			// interactions in multiple passes.
   1233 			//
   1234 			// We also have the very rare case of some materials that have conditional interactions
   1235 			// for the "hell writing" that can be shined on them.
   1236 			for ( int surfaceStageNum = 0; surfaceStageNum < surfaceShader->GetNumStages(); surfaceStageNum++ ) {
   1237 				const shaderStage_t	*surfaceStage = surfaceShader->GetStage( surfaceStageNum );
   1238 
   1239 				switch( surfaceStage->lighting ) {
   1240 					case SL_COVERAGE: {
   1241 						// ignore any coverage stages since they should only be used for the depth fill pass
   1242 						// for diffuse stages that use alpha test.
   1243 						break;
   1244 					}
   1245 					case SL_AMBIENT: {
   1246 						// ignore ambient stages while drawing interactions
   1247 						break;
   1248 					}
   1249 					case SL_BUMP: {
   1250 						// ignore stage that fails the condition
   1251 						if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
   1252 							break;
   1253 						}
   1254 						// draw any previous interaction
   1255 						if ( inter.bumpImage != NULL ) {
   1256 							RB_DrawSingleInteraction( &inter );
   1257 						}
   1258 						inter.bumpImage = surfaceStage->texture.image;
   1259 						inter.diffuseImage = NULL;
   1260 						inter.specularImage = NULL;
   1261 						RB_SetupInteractionStage( surfaceStage, surfaceRegs, NULL,
   1262 												inter.bumpMatrix, NULL );
   1263 						break;
   1264 					}
   1265 					case SL_DIFFUSE: {
   1266 						// ignore stage that fails the condition
   1267 						if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
   1268 							break;
   1269 						}
   1270 						// draw any previous interaction
   1271 						if ( inter.diffuseImage != NULL ) {
   1272 							RB_DrawSingleInteraction( &inter );
   1273 						}
   1274 						inter.diffuseImage = surfaceStage->texture.image;
   1275 						inter.vertexColor = surfaceStage->vertexColor;
   1276 						RB_SetupInteractionStage( surfaceStage, surfaceRegs, diffuseColor.ToFloatPtr(),
   1277 												inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() );
   1278 						break;
   1279 					}
   1280 					case SL_SPECULAR: {
   1281 						// ignore stage that fails the condition
   1282 						if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
   1283 							break;
   1284 						}
   1285 						// draw any previous interaction
   1286 						if ( inter.specularImage != NULL ) {
   1287 							RB_DrawSingleInteraction( &inter );
   1288 						}
   1289 						inter.specularImage = surfaceStage->texture.image;
   1290 						inter.vertexColor = surfaceStage->vertexColor;
   1291 						RB_SetupInteractionStage( surfaceStage, surfaceRegs, specularColor.ToFloatPtr(),
   1292 												inter.specularMatrix, inter.specularColor.ToFloatPtr() );
   1293 						break;
   1294 					}
   1295 				}
   1296 			}
   1297 
   1298 			// draw the final interaction
   1299 			RB_DrawSingleInteraction( &inter );
   1300 
   1301 			renderLog.CloseBlock();
   1302 		}
   1303 	}
   1304 
   1305 	if ( useLightDepthBounds && lightDepthBoundsDisabled ) {
   1306 		GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax );
   1307 	}
   1308 
   1309 	renderProgManager.Unbind();
   1310 }
   1311 
   1312 /*
   1313 ==============================================================================================
   1314 
   1315 STENCIL SHADOW RENDERING
   1316 
   1317 ==============================================================================================
   1318 */
   1319 
   1320 /*
   1321 =====================
   1322 RB_StencilShadowPass
   1323 
   1324 The stencil buffer should have been set to 128 on any surfaces that might receive shadows.
   1325 =====================
   1326 */
   1327 static void RB_StencilShadowPass( const drawSurf_t *drawSurfs, const viewLight_t * vLight ) {
   1328 	if ( r_skipShadows.GetBool() ) {
   1329 		return;
   1330 	}
   1331 
   1332 	if ( drawSurfs == NULL ) {
   1333 		return;
   1334 	}
   1335 
   1336 	RENDERLOG_PRINTF( "---------- RB_StencilShadowPass ----------\n" );
   1337 
   1338 	renderProgManager.BindShader_Shadow();
   1339 
   1340 	GL_SelectTexture( 0 );
   1341 	globalImages->BindNull();
   1342 
   1343 	uint64 glState = 0;
   1344 
   1345 	// for visualizing the shadows
   1346 	if ( r_showShadows.GetInteger() ) {
   1347 		// set the debug shadow color
   1348 		SetFragmentParm( RENDERPARM_COLOR, colorMagenta.ToFloatPtr() );
   1349 		if ( r_showShadows.GetInteger() == 2 ) {
   1350 			// draw filled in
   1351 			glState = GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS;
   1352 		} else {
   1353 			// draw as lines, filling the depth buffer
   1354 			glState = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS;
   1355 		}
   1356 	} else {
   1357 		// don't write to the color or depth buffer, just the stencil buffer
   1358 		glState = GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS;
   1359 	}
   1360 
   1361 	GL_PolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() );
   1362 
   1363 	// the actual stencil func will be set in the draw code, but we need to make sure it isn't
   1364 	// disabled here, and that the value will get reset for the interactions without looking
   1365 	// like a no-change-required
   1366 	GL_State( glState | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_KEEP | GLS_STENCIL_OP_PASS_INCR | 
   1367 		GLS_STENCIL_MAKE_REF( STENCIL_SHADOW_TEST_VALUE ) | GLS_STENCIL_MAKE_MASK( STENCIL_SHADOW_MASK_VALUE ) | GLS_POLYGON_OFFSET );
   1368 
   1369 	// Two Sided Stencil reduces two draw calls to one for slightly faster shadows
   1370 	GL_Cull( CT_TWO_SIDED );
   1371 
   1372 
   1373 	// process the chain of shadows with the current rendering state
   1374 	backEnd.currentSpace = NULL;
   1375 
   1376 	for ( const drawSurf_t * drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) {
   1377 		if ( drawSurf->scissorRect.IsEmpty() ) {
   1378 			continue;	// !@# FIXME: find out why this is sometimes being hit!
   1379 						// temporarily jump over the scissor and draw so the gl error callback doesn't get hit
   1380 		}
   1381 
   1382 		// make sure the shadow volume is done
   1383 		if ( drawSurf->shadowVolumeState != SHADOWVOLUME_DONE ) {
   1384 			assert( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED || drawSurf->shadowVolumeState == SHADOWVOLUME_DONE );
   1385 
   1386 			uint64 start = Sys_Microseconds();
   1387 			while ( drawSurf->shadowVolumeState == SHADOWVOLUME_UNFINISHED ) {
   1388 				Sys_Yield();
   1389 			}
   1390 			uint64 end = Sys_Microseconds();
   1391 
   1392 			backEnd.pc.shadowMicroSec += end - start;
   1393 		}
   1394 
   1395 		if ( drawSurf->numIndexes == 0 ) {
   1396 			continue;	// a job may have created an empty shadow volume
   1397 		}
   1398 
   1399 		if ( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) {
   1400 			// change the scissor
   1401 			GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1,
   1402 						backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1,
   1403 						drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1,
   1404 						drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 );
   1405 			backEnd.currentScissor = drawSurf->scissorRect;
   1406 		}
   1407 
   1408 		if ( drawSurf->space != backEnd.currentSpace ) {
   1409 			// change the matrix
   1410 			RB_SetMVP( drawSurf->space->mvp );
   1411 
   1412 			// set the local light position to allow the vertex program to project the shadow volume end cap to infinity
   1413 			idVec4 localLight( 0.0f );
   1414 			R_GlobalPointToLocal( drawSurf->space->modelMatrix, vLight->globalLightOrigin, localLight.ToVec3() );
   1415 			SetVertexParm( RENDERPARM_LOCALLIGHTORIGIN, localLight.ToFloatPtr() );
   1416 
   1417 			backEnd.currentSpace = drawSurf->space;
   1418 		}
   1419 
   1420 		if ( r_showShadows.GetInteger() == 0 ) {
   1421 			if ( drawSurf->jointCache ) {
   1422 				renderProgManager.BindShader_ShadowSkinned();
   1423 			} else {
   1424 				renderProgManager.BindShader_Shadow();
   1425 			}
   1426 		} else {
   1427 			if ( drawSurf->jointCache ) {
   1428 				renderProgManager.BindShader_ShadowDebugSkinned();
   1429 			} else {
   1430 				renderProgManager.BindShader_ShadowDebug();
   1431 			}
   1432 		}
   1433 
   1434 		// set depth bounds per shadow
   1435 		if ( r_useShadowDepthBounds.GetBool() ) {
   1436 			GL_DepthBoundsTest( drawSurf->scissorRect.zmin, drawSurf->scissorRect.zmax );
   1437 		}
   1438 
   1439 		// Determine whether or not the shadow volume needs to be rendered with Z-pass or
   1440 		// Z-fail. It is worthwhile to spend significant resources to reduce the number of
   1441 		// cases where shadow volumes need to be rendered with Z-fail because Z-fail
   1442 		// rendering can be significantly slower even on today's hardware. For instance,
   1443 		// on NVIDIA hardware Z-fail rendering causes the Z-Cull to be used in reverse:
   1444 		// Z-near becomes Z-far (trivial accept becomes trivial reject). Using the Z-Cull
   1445 		// in reverse is far less efficient because the Z-Cull only stores Z-near per 16x16
   1446 		// pixels while the Z-far is stored per 4x2 pixels. (The Z-near coallesce buffer
   1447 		// which has 4x4 granularity is only used when updating the depth which is not the
   1448 		// case for shadow volumes.) Note that it is also important to NOT use a Z-Cull
   1449 		// reconstruct because that would clear the Z-near of the Z-Cull which results in
   1450 		// no trivial rejection for Z-fail stencil shadow rendering.
   1451 
   1452 		const bool renderZPass = ( drawSurf->renderZFail == 0 ) || r_forceZPassStencilShadows.GetBool();
   1453 
   1454 
   1455 		if ( renderZPass ) {
   1456 			// Z-pass
   1457 			qglStencilOpSeparate( GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR );
   1458 			qglStencilOpSeparate( GL_BACK, GL_KEEP, GL_KEEP, GL_DECR );
   1459 		} else if ( r_useStencilShadowPreload.GetBool() ) {
   1460 			// preload + Z-pass
   1461 			qglStencilOpSeparate( GL_FRONT, GL_KEEP, GL_DECR, GL_DECR );
   1462 			qglStencilOpSeparate( GL_BACK, GL_KEEP, GL_INCR, GL_INCR );
   1463 		} else {
   1464 			// Z-fail
   1465 		}
   1466 
   1467 
   1468 		// get vertex buffer
   1469 		const vertCacheHandle_t vbHandle = drawSurf->shadowCache;
   1470 		idVertexBuffer * vertexBuffer;
   1471 		if ( vertexCache.CacheIsStatic( vbHandle ) ) {
   1472 			vertexBuffer = &vertexCache.staticData.vertexBuffer;
   1473 		} else {
   1474 			const uint64 frameNum = (int)( vbHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
   1475 			if ( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) {
   1476 				idLib::Warning( "RB_DrawElementsWithCounters, vertexBuffer == NULL" );
   1477 				continue;
   1478 			}
   1479 			vertexBuffer = &vertexCache.frameData[vertexCache.drawListNum].vertexBuffer;
   1480 		}
   1481 		const int vertOffset = (int)( vbHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
   1482 
   1483 		// get index buffer
   1484 		const vertCacheHandle_t ibHandle = drawSurf->indexCache;
   1485 		idIndexBuffer * indexBuffer;
   1486 		if ( vertexCache.CacheIsStatic( ibHandle ) ) {
   1487 			indexBuffer = &vertexCache.staticData.indexBuffer;
   1488 		} else {
   1489 			const uint64 frameNum = (int)( ibHandle >> VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK;
   1490 			if ( frameNum != ( ( vertexCache.currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) ) {
   1491 				idLib::Warning( "RB_DrawElementsWithCounters, indexBuffer == NULL" );
   1492 				continue;
   1493 			}
   1494 			indexBuffer = &vertexCache.frameData[vertexCache.drawListNum].indexBuffer;
   1495 		}
   1496 		const uint64 indexOffset = (int)( ibHandle >> VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK;
   1497 
   1498 		RENDERLOG_PRINTF( "Binding Buffers: %p %p\n", vertexBuffer, indexBuffer );
   1499 
   1500 
   1501 		if ( backEnd.glState.currentIndexBuffer != (GLuint)indexBuffer->GetAPIObject() || !r_useStateCaching.GetBool() ) {
   1502 			qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, (GLuint)indexBuffer->GetAPIObject() );
   1503 			backEnd.glState.currentIndexBuffer = (GLuint)indexBuffer->GetAPIObject();
   1504 		}
   1505 
   1506 		if ( drawSurf->jointCache ) {
   1507 			assert( renderProgManager.ShaderUsesJoints() );
   1508 
   1509 			idJointBuffer jointBuffer;
   1510 			if ( !vertexCache.GetJointBuffer( drawSurf->jointCache, &jointBuffer ) ) {
   1511 				idLib::Warning( "RB_DrawElementsWithCounters, jointBuffer == NULL" );
   1512 				continue;
   1513 			}
   1514 			assert( ( jointBuffer.GetOffset() & ( glConfig.uniformBufferOffsetAlignment - 1 ) ) == 0 );
   1515 
   1516 			const GLuint ubo = reinterpret_cast< GLuint >( jointBuffer.GetAPIObject() );
   1517 			qglBindBufferRange( GL_UNIFORM_BUFFER, 0, ubo, jointBuffer.GetOffset(), jointBuffer.GetNumJoints() * sizeof( idJointMat ) );
   1518 
   1519 			if ( ( backEnd.glState.vertexLayout != LAYOUT_DRAW_SHADOW_VERT_SKINNED) || ( backEnd.glState.currentVertexBuffer != (GLuint)vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) {
   1520 				qglBindBufferARB( GL_ARRAY_BUFFER_ARB, (GLuint)vertexBuffer->GetAPIObject() );
   1521 				backEnd.glState.currentVertexBuffer = (GLuint)vertexBuffer->GetAPIObject();
   1522 
   1523 				qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_VERTEX );
   1524 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_NORMAL );
   1525 				qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_COLOR );
   1526 				qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_COLOR2 );
   1527 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_ST );
   1528 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_TANGENT );
   1529 
   1530 				qglVertexAttribPointerARB( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVertSkinned ), (void *)( SHADOWVERTSKINNED_XYZW_OFFSET ) );
   1531 				qglVertexAttribPointerARB( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), (void *)( SHADOWVERTSKINNED_COLOR_OFFSET ) );
   1532 				qglVertexAttribPointerARB( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), (void *)( SHADOWVERTSKINNED_COLOR2_OFFSET ) );
   1533 
   1534 				backEnd.glState.vertexLayout = LAYOUT_DRAW_SHADOW_VERT_SKINNED;
   1535 			}
   1536 
   1537 		} else {
   1538 
   1539 			if ( ( backEnd.glState.vertexLayout != LAYOUT_DRAW_SHADOW_VERT ) || ( backEnd.glState.currentVertexBuffer != (GLuint)vertexBuffer->GetAPIObject() ) || !r_useStateCaching.GetBool() ) {
   1540 				qglBindBufferARB( GL_ARRAY_BUFFER_ARB, (GLuint)vertexBuffer->GetAPIObject() );
   1541 				backEnd.glState.currentVertexBuffer = (GLuint)vertexBuffer->GetAPIObject();
   1542 
   1543 				qglEnableVertexAttribArrayARB( PC_ATTRIB_INDEX_VERTEX );
   1544 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_NORMAL );
   1545 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_COLOR );
   1546 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_COLOR2 );
   1547 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_ST );
   1548 				qglDisableVertexAttribArrayARB( PC_ATTRIB_INDEX_TANGENT );
   1549 
   1550 				qglVertexAttribPointerARB( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVert ), (void *)( SHADOWVERT_XYZW_OFFSET ) );
   1551 
   1552 				backEnd.glState.vertexLayout = LAYOUT_DRAW_SHADOW_VERT;
   1553 			}
   1554 		}
   1555 
   1556 		renderProgManager.CommitUniforms();
   1557 
   1558 		if ( drawSurf->jointCache ) {
   1559 			qglDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, (triIndex_t *)indexOffset, vertOffset / sizeof( idShadowVertSkinned ) );
   1560 		} else {
   1561 			qglDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, (triIndex_t *)indexOffset, vertOffset / sizeof( idShadowVert ) );
   1562 		}
   1563 
   1564 		if ( !renderZPass && r_useStencilShadowPreload.GetBool() ) {
   1565 			// render again with Z-pass
   1566 			qglStencilOpSeparate( GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR );
   1567 			qglStencilOpSeparate( GL_BACK, GL_KEEP, GL_KEEP, GL_DECR );
   1568 
   1569 			if ( drawSurf->jointCache ) {
   1570 				qglDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, (triIndex_t *)indexOffset, vertOffset / sizeof ( idShadowVertSkinned ) );
   1571 			} else {
   1572 				qglDrawElementsBaseVertex( GL_TRIANGLES, r_singleTriangle.GetBool() ? 3 : drawSurf->numIndexes, GL_INDEX_TYPE, (triIndex_t *)indexOffset, vertOffset / sizeof ( idShadowVert ) );
   1573 			}
   1574 		}
   1575 	}
   1576 
   1577 	// cleanup the shadow specific rendering state
   1578 
   1579 	GL_Cull( CT_FRONT_SIDED );
   1580 
   1581 	// reset depth bounds
   1582 	if ( r_useShadowDepthBounds.GetBool() ) {
   1583 		if ( r_useLightDepthBounds.GetBool() ) {
   1584 			GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax );
   1585 		} else {
   1586 			GL_DepthBoundsTest( 0.0f, 0.0f );
   1587 		}
   1588 	}
   1589 }
   1590 
   1591 /*
   1592 ==================
   1593 RB_StencilSelectLight
   1594 
   1595 Deform the zeroOneCubeModel to exactly cover the light volume. Render the deformed cube model to the stencil buffer in
   1596 such a way that only fragments that are directly visible and contained within the volume will be written creating a 
   1597 mask to be used by the following stencil shadow and draw interaction passes.
   1598 ==================
   1599 */
   1600 static void RB_StencilSelectLight( const viewLight_t * vLight ) {
   1601 	renderLog.OpenBlock( "Stencil Select" );
   1602 
   1603 	// enable the light scissor
   1604 	if ( !backEnd.currentScissor.Equals( vLight->scissorRect ) && r_useScissor.GetBool() ) {
   1605 		GL_Scissor( backEnd.viewDef->viewport.x1 + vLight->scissorRect.x1, 
   1606 					backEnd.viewDef->viewport.y1 + vLight->scissorRect.y1,
   1607 					vLight->scissorRect.x2 + 1 - vLight->scissorRect.x1,
   1608 					vLight->scissorRect.y2 + 1 - vLight->scissorRect.y1 );
   1609 		backEnd.currentScissor = vLight->scissorRect;
   1610 	}
   1611 
   1612 	// clear stencil buffer to 0 (not drawable)
   1613 	uint64 glStateMinusStencil = GL_GetCurrentStateMinusStencil();
   1614 	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
   1615 	GL_Clear( false, false, true, 0, 0.0f, 0.0f, 0.0f, 0.0f );	// clear to 0 for stencil select
   1616 
   1617 	// set the depthbounds
   1618 	GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax );
   1619 
   1620 
   1621 	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 ) );
   1622 	GL_Cull( CT_TWO_SIDED );
   1623 
   1624 	renderProgManager.BindShader_Depth();
   1625 
   1626 	// set the matrix for deforming the 'zeroOneCubeModel' into the frustum to exactly cover the light volume
   1627 	idRenderMatrix invProjectMVPMatrix;
   1628 	idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix );
   1629 	RB_SetMVP( invProjectMVPMatrix );
   1630 
   1631 	// two-sided stencil test
   1632 	qglStencilOpSeparate( GL_FRONT, GL_KEEP, GL_REPLACE, GL_ZERO );
   1633 	qglStencilOpSeparate( GL_BACK, GL_KEEP, GL_ZERO, GL_REPLACE );
   1634 
   1635 	RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface );
   1636 
   1637 	// reset stencil state
   1638 
   1639 	GL_Cull( CT_FRONT_SIDED );
   1640 
   1641 	renderProgManager.Unbind();
   1642 
   1643 
   1644 	// unset the depthbounds
   1645 	GL_DepthBoundsTest( 0.0f, 0.0f );
   1646 
   1647 	renderLog.CloseBlock();
   1648 }
   1649 
   1650 /*
   1651 ==============================================================================================
   1652 
   1653 DRAW INTERACTIONS
   1654 
   1655 ==============================================================================================
   1656 */
   1657 /*
   1658 ==================
   1659 RB_DrawInteractions
   1660 ==================
   1661 */
   1662 static void RB_DrawInteractions() {
   1663 	if ( r_skipInteractions.GetBool() ) {
   1664 		return;
   1665 	}
   1666 
   1667 	renderLog.OpenMainBlock( MRB_DRAW_INTERACTIONS );
   1668 	renderLog.OpenBlock( "RB_DrawInteractions" );
   1669 
   1670 	GL_SelectTexture( 0 );
   1671 
   1672 
   1673 	const bool useLightDepthBounds = r_useLightDepthBounds.GetBool();
   1674 
   1675 	//
   1676 	// for each light, perform shadowing and adding
   1677 	//
   1678 	for ( const viewLight_t * vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next ) {
   1679 		// do fogging later
   1680 		if ( vLight->lightShader->IsFogLight() ) {
   1681 			continue;
   1682 		}
   1683 		if ( vLight->lightShader->IsBlendLight() ) {
   1684 			continue;
   1685 		}
   1686 
   1687 		if ( vLight->localInteractions == NULL && vLight->globalInteractions == NULL && vLight->translucentInteractions == NULL ) {
   1688 			continue;
   1689 		}
   1690 
   1691 		const idMaterial * lightShader = vLight->lightShader;
   1692 		renderLog.OpenBlock( lightShader->GetName() );
   1693 
   1694 		// set the depth bounds for the whole light
   1695 		if ( useLightDepthBounds ) {
   1696 			GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax );
   1697 		}
   1698 
   1699 		// only need to clear the stencil buffer and perform stencil testing if there are shadows
   1700 		const bool performStencilTest = ( vLight->globalShadows != NULL || vLight->localShadows != NULL );
   1701 
   1702 		// mirror flips the sense of the stencil select, and I don't want to risk accidentally breaking it
   1703 		// in the normal case, so simply disable the stencil select in the mirror case
   1704 		const bool useLightStencilSelect = ( r_useLightStencilSelect.GetBool() && backEnd.viewDef->isMirror == false );
   1705 
   1706 		if ( performStencilTest ) {
   1707 			if ( useLightStencilSelect ) {
   1708 				// write a stencil mask for the visible light bounds to hi-stencil
   1709 				RB_StencilSelectLight( vLight );
   1710 			} else {
   1711 				// always clear whole S-Cull tiles
   1712 				idScreenRect rect;
   1713 				rect.x1 = ( vLight->scissorRect.x1 +  0 ) & ~15;
   1714 				rect.y1 = ( vLight->scissorRect.y1 +  0 ) & ~15;
   1715 				rect.x2 = ( vLight->scissorRect.x2 + 15 ) & ~15;
   1716 				rect.y2 = ( vLight->scissorRect.y2 + 15 ) & ~15;
   1717 
   1718 				if ( !backEnd.currentScissor.Equals( rect ) && r_useScissor.GetBool() ) {
   1719 					GL_Scissor( backEnd.viewDef->viewport.x1 + rect.x1,
   1720 								backEnd.viewDef->viewport.y1 + rect.y1,
   1721 								rect.x2 + 1 - rect.x1,
   1722 								rect.y2 + 1 - rect.y1 );
   1723 					backEnd.currentScissor = rect;
   1724 				}
   1725 				GL_State( GLS_DEFAULT );	// make sure stencil mask passes for the clear
   1726 				GL_Clear( false, false, true, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 0.0f );
   1727 			}
   1728 		}
   1729 
   1730 		if ( vLight->globalShadows != NULL ) {
   1731 			renderLog.OpenBlock( "Global Light Shadows" );
   1732 			RB_StencilShadowPass( vLight->globalShadows, vLight );
   1733 			renderLog.CloseBlock();
   1734 		}
   1735 
   1736 		if ( vLight->localInteractions != NULL ) {
   1737 			renderLog.OpenBlock( "Local Light Interactions" );
   1738 			RB_RenderInteractions( vLight->localInteractions, vLight, GLS_DEPTHFUNC_EQUAL, performStencilTest, useLightDepthBounds );
   1739 			renderLog.CloseBlock();
   1740 		}
   1741 
   1742 		if ( vLight->localShadows != NULL ) {
   1743 			renderLog.OpenBlock( "Local Light Shadows" );
   1744 			RB_StencilShadowPass( vLight->localShadows, vLight );
   1745 			renderLog.CloseBlock();
   1746 		}
   1747 
   1748 		if ( vLight->globalInteractions != NULL ) {
   1749 			renderLog.OpenBlock( "Global Light Interactions" );
   1750 			RB_RenderInteractions( vLight->globalInteractions, vLight, GLS_DEPTHFUNC_EQUAL, performStencilTest, useLightDepthBounds );
   1751 			renderLog.CloseBlock();
   1752 		}
   1753 
   1754 
   1755 		if ( vLight->translucentInteractions != NULL && !r_skipTranslucent.GetBool() ) {
   1756 			renderLog.OpenBlock( "Translucent Interactions" );
   1757 
   1758 			// Disable the depth bounds test because translucent surfaces don't work with
   1759 			// the depth bounds tests since they did not write depth during the depth pass.
   1760 			if ( useLightDepthBounds ) {
   1761 				GL_DepthBoundsTest( 0.0f, 0.0f );
   1762 			}
   1763 
   1764 			// The depth buffer wasn't filled in for translucent surfaces, so they
   1765 			// can never be constrained to perforated surfaces with the depthfunc equal.
   1766 
   1767 			// Translucent surfaces do not receive shadows. This is a case where a
   1768 			// shadow buffer solution would work but stencil shadows do not because
   1769 			// stencil shadows only affect surfaces that contribute to the view depth
   1770 			// buffer and translucent surfaces do not contribute to the view depth buffer.
   1771 
   1772 			RB_RenderInteractions( vLight->translucentInteractions, vLight, GLS_DEPTHFUNC_LESS, false, false );
   1773 
   1774 			renderLog.CloseBlock();
   1775 		}
   1776 
   1777 		renderLog.CloseBlock();
   1778 	}
   1779 
   1780 	// disable stencil shadow test
   1781 	GL_State( GLS_DEFAULT );
   1782 
   1783 	// unbind texture units
   1784 	for ( int i = 0; i < 5; i++ ) {
   1785 		GL_SelectTexture( i );
   1786 		globalImages->BindNull();
   1787 	}
   1788 	GL_SelectTexture( 0 );
   1789 
   1790 	// reset depth bounds
   1791 	if ( useLightDepthBounds ) {
   1792 		GL_DepthBoundsTest( 0.0f, 0.0f );
   1793 	}
   1794 
   1795 	renderLog.CloseBlock();
   1796 	renderLog.CloseMainBlock();
   1797 }
   1798 
   1799 /*
   1800 =============================================================================================
   1801 
   1802 NON-INTERACTION SHADER PASSES
   1803 
   1804 =============================================================================================
   1805 */
   1806 
   1807 /*
   1808 =====================
   1809 RB_DrawShaderPasses
   1810 
   1811 Draw non-light dependent passes
   1812 
   1813 If we are rendering Guis, the drawSurf_t::sort value is a depth offset that can
   1814 be multiplied by guiEye for polarity and screenSeparation for scale.
   1815 =====================
   1816 */
   1817 static int RB_DrawShaderPasses( const drawSurf_t * const * const drawSurfs, const int numDrawSurfs, 
   1818 									const float guiStereoScreenOffset, const int stereoEye ) {
   1819 	// only obey skipAmbient if we are rendering a view
   1820 	if ( backEnd.viewDef->viewEntitys && r_skipAmbient.GetBool() ) {
   1821 		return numDrawSurfs;
   1822 	}
   1823 
   1824 	renderLog.OpenBlock( "RB_DrawShaderPasses" );
   1825 
   1826 	GL_SelectTexture( 1 );
   1827 	globalImages->BindNull();
   1828 
   1829 	GL_SelectTexture( 0 );
   1830 
   1831 	backEnd.currentSpace = (const viewEntity_t *)1;	// using NULL makes /analyze think surf->space needs to be checked...
   1832 	float currentGuiStereoOffset = 0.0f;
   1833 
   1834 	int i = 0;
   1835 	for ( ; i < numDrawSurfs; i++ ) {
   1836 		const drawSurf_t * surf = drawSurfs[i];
   1837 		const idMaterial * shader = surf->material;
   1838 
   1839 		if ( !shader->HasAmbient() ) {
   1840 			continue;
   1841 		}
   1842 
   1843 		if ( shader->IsPortalSky() ) {
   1844 			continue;
   1845 		}
   1846 
   1847 		// some deforms may disable themselves by setting numIndexes = 0
   1848 		if ( surf->numIndexes == 0 ) {
   1849 			continue;
   1850 		}
   1851 
   1852 		if ( shader->SuppressInSubview() ) {
   1853 			continue;
   1854 		}
   1855 
   1856 		if ( backEnd.viewDef->isXraySubview && surf->space->entityDef ) {
   1857 			if ( surf->space->entityDef->parms.xrayIndex != 2 ) {
   1858 				continue;
   1859 			}
   1860 		}
   1861 
   1862 		// we need to draw the post process shaders after we have drawn the fog lights
   1863 		if ( shader->GetSort() >= SS_POST_PROCESS && !backEnd.currentRenderCopied ) {
   1864 			break;
   1865 		}
   1866 
   1867 		// if we are rendering a 3D view and the surface's eye index doesn't match 
   1868 		// the current view's eye index then we skip the surface
   1869 		// if the stereoEye value of a surface is 0 then we need to draw it for both eyes.
   1870 		const int shaderStereoEye = shader->GetStereoEye();
   1871 		const bool isEyeValid = stereoRender_swapEyes.GetBool() ? ( shaderStereoEye == stereoEye ) : ( shaderStereoEye != stereoEye );
   1872 		if ( ( stereoEye != 0 ) && ( shaderStereoEye != 0 ) && ( isEyeValid ) ) {
   1873 			continue;
   1874 		}
   1875 
   1876 		renderLog.OpenBlock( shader->GetName() );
   1877 
   1878 		// determine the stereoDepth offset 
   1879 		// guiStereoScreenOffset will always be zero for 3D views, so the !=
   1880 		// check will never force an update due to the current sort value.
   1881 		const float thisGuiStereoOffset = guiStereoScreenOffset * surf->sort;
   1882 
   1883 		// change the matrix and other space related vars if needed
   1884 		if ( surf->space != backEnd.currentSpace || thisGuiStereoOffset != currentGuiStereoOffset ) {
   1885 			backEnd.currentSpace = surf->space;
   1886 			currentGuiStereoOffset = thisGuiStereoOffset;
   1887 
   1888 			const viewEntity_t *space = backEnd.currentSpace;
   1889 
   1890 			if ( guiStereoScreenOffset != 0.0f ) {
   1891 				RB_SetMVPWithStereoOffset( space->mvp, currentGuiStereoOffset );
   1892 			} else {
   1893 				RB_SetMVP( space->mvp );
   1894 			}
   1895 
   1896 			// set eye position in local space
   1897 			idVec4 localViewOrigin( 1.0f );
   1898 			R_GlobalPointToLocal( space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewOrigin.ToVec3() );
   1899 			SetVertexParm( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() );
   1900 
   1901 			// set model Matrix
   1902 			float modelMatrixTranspose[16];
   1903 			R_MatrixTranspose( space->modelMatrix, modelMatrixTranspose );
   1904 			SetVertexParms( RENDERPARM_MODELMATRIX_X, modelMatrixTranspose, 4 );
   1905 
   1906 			// Set ModelView Matrix
   1907 			float modelViewMatrixTranspose[16];
   1908 			R_MatrixTranspose( space->modelViewMatrix, modelViewMatrixTranspose );
   1909 			SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, modelViewMatrixTranspose, 4 );
   1910 		}
   1911 
   1912 		// change the scissor if needed
   1913 		if ( !backEnd.currentScissor.Equals( surf->scissorRect ) && r_useScissor.GetBool() ) {
   1914 			GL_Scissor( backEnd.viewDef->viewport.x1 + surf->scissorRect.x1, 
   1915 						backEnd.viewDef->viewport.y1 + surf->scissorRect.y1,
   1916 						surf->scissorRect.x2 + 1 - surf->scissorRect.x1,
   1917 						surf->scissorRect.y2 + 1 - surf->scissorRect.y1 );
   1918 			backEnd.currentScissor = surf->scissorRect;
   1919 		}
   1920 
   1921 		// get the expressions for conditionals / color / texcoords
   1922 		const float	*regs = surf->shaderRegisters;
   1923 
   1924 		// set face culling appropriately
   1925 		if ( surf->space->isGuiSurface ) {
   1926 			GL_Cull( CT_TWO_SIDED );
   1927 		} else {
   1928 			GL_Cull( shader->GetCullType() );
   1929 		}
   1930 
   1931 		uint64 surfGLState = surf->extraGLState;
   1932 
   1933 		// set polygon offset if necessary
   1934 		if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) {
   1935 			GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() );
   1936 			surfGLState = GLS_POLYGON_OFFSET;
   1937 		}
   1938 
   1939 		for ( int stage = 0; stage < shader->GetNumStages(); stage++ ) {		
   1940 			const shaderStage_t *pStage = shader->GetStage(stage);
   1941 
   1942 			// check the enable condition
   1943 			if ( regs[ pStage->conditionRegister ] == 0 ) {
   1944 				continue;
   1945 			}
   1946 
   1947 			// skip the stages involved in lighting
   1948 			if ( pStage->lighting != SL_AMBIENT ) {
   1949 				continue;
   1950 			}
   1951 
   1952 			uint64 stageGLState = surfGLState;
   1953 			if ( ( surfGLState & GLS_OVERRIDE ) == 0 ) {
   1954 				stageGLState |= pStage->drawStateBits;
   1955 			}
   1956 
   1957 			// skip if the stage is ( GL_ZERO, GL_ONE ), which is used for some alpha masks
   1958 			if ( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE ) ) {
   1959 				continue;
   1960 			}
   1961 
   1962 			// see if we are a new-style stage
   1963 			newShaderStage_t *newStage = pStage->newStage;
   1964 			if ( newStage != NULL ) {
   1965 				//--------------------------
   1966 				//
   1967 				// new style stages
   1968 				//
   1969 				//--------------------------
   1970 				if ( r_skipNewAmbient.GetBool() ) {
   1971 					continue;
   1972 				}
   1973 				renderLog.OpenBlock( "New Shader Stage" );
   1974 
   1975 				GL_State( stageGLState );
   1976 			
   1977 				renderProgManager.BindShader( newStage->glslProgram, newStage->glslProgram );
   1978 
   1979 				for ( int j = 0; j < newStage->numVertexParms; j++ ) {
   1980 					float parm[4];
   1981 					parm[0] = regs[ newStage->vertexParms[j][0] ];
   1982 					parm[1] = regs[ newStage->vertexParms[j][1] ];
   1983 					parm[2] = regs[ newStage->vertexParms[j][2] ];
   1984 					parm[3] = regs[ newStage->vertexParms[j][3] ];
   1985 					SetVertexParm( (renderParm_t)( RENDERPARM_USER + j ), parm );
   1986 				}
   1987 
   1988 				// set rpEnableSkinning if the shader has optional support for skinning
   1989 				if ( surf->jointCache && renderProgManager.ShaderHasOptionalSkinning() ) {
   1990 					const idVec4 skinningParm( 1.0f );
   1991 					SetVertexParm( RENDERPARM_ENABLE_SKINNING, skinningParm.ToFloatPtr() );
   1992 				}
   1993 
   1994 				// bind texture units
   1995 				for ( int j = 0; j < newStage->numFragmentProgramImages; j++ ) {
   1996 					idImage * image = newStage->fragmentProgramImages[j];
   1997 					if ( image != NULL ) {
   1998 						GL_SelectTexture( j );
   1999 						image->Bind();
   2000 					}
   2001 				}
   2002 
   2003 				// draw it
   2004 				RB_DrawElementsWithCounters( surf );
   2005 
   2006 				// unbind texture units
   2007 				for ( int j = 0; j < newStage->numFragmentProgramImages; j++ ) {
   2008 					idImage * image = newStage->fragmentProgramImages[j];
   2009 					if ( image != NULL ) {
   2010 						GL_SelectTexture( j );
   2011 						globalImages->BindNull();
   2012 					}
   2013 				}
   2014 
   2015 				// clear rpEnableSkinning if it was set
   2016 				if ( surf->jointCache && renderProgManager.ShaderHasOptionalSkinning() ) {
   2017 					const idVec4 skinningParm( 0.0f );
   2018 					SetVertexParm( RENDERPARM_ENABLE_SKINNING, skinningParm.ToFloatPtr() );
   2019 				}
   2020 
   2021 				GL_SelectTexture( 0 );
   2022 				renderProgManager.Unbind();
   2023 
   2024 				renderLog.CloseBlock();
   2025 				continue;
   2026 			}
   2027 
   2028 			//--------------------------
   2029 			//
   2030 			// old style stages
   2031 			//
   2032 			//--------------------------
   2033 
   2034 			// set the color
   2035 			float color[4];
   2036 			color[0] = regs[ pStage->color.registers[0] ];
   2037 			color[1] = regs[ pStage->color.registers[1] ];
   2038 			color[2] = regs[ pStage->color.registers[2] ];
   2039 			color[3] = regs[ pStage->color.registers[3] ];
   2040 
   2041 			// skip the entire stage if an add would be black
   2042 			if ( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) 
   2043 				&& color[0] <= 0 && color[1] <= 0 && color[2] <= 0 ) {
   2044 				continue;
   2045 			}
   2046 
   2047 			// skip the entire stage if a blend would be completely transparent
   2048 			if ( ( stageGLState & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA )
   2049 				&& color[3] <= 0 ) {
   2050 				continue;
   2051 			}
   2052 
   2053 			stageVertexColor_t svc = pStage->vertexColor;
   2054 
   2055 			renderLog.OpenBlock( "Old Shader Stage" );
   2056 			GL_Color( color );
   2057 
   2058 			if ( surf->space->isGuiSurface ) {
   2059 				// Force gui surfaces to always be SVC_MODULATE
   2060 				svc = SVC_MODULATE;
   2061 
   2062 				// use special shaders for bink cinematics
   2063 				if ( pStage->texture.cinematic ) {
   2064 					if ( ( stageGLState & GLS_OVERRIDE ) != 0 ) {
   2065 						// This is a hack... Only SWF Guis set GLS_OVERRIDE
   2066 						// Old style guis do not, and we don't want them to use the new GUI renederProg
   2067 						renderProgManager.BindShader_BinkGUI();
   2068 					} else {
   2069 						renderProgManager.BindShader_Bink();
   2070 					}
   2071 				} else {
   2072 					if ( ( stageGLState & GLS_OVERRIDE ) != 0 ) {
   2073 						// This is a hack... Only SWF Guis set GLS_OVERRIDE
   2074 						// Old style guis do not, and we don't want them to use the new GUI renderProg
   2075 						renderProgManager.BindShader_GUI();
   2076 					} else {
   2077 						if ( surf->jointCache ) {
   2078 							renderProgManager.BindShader_TextureVertexColorSkinned();
   2079 						} else {
   2080 							renderProgManager.BindShader_TextureVertexColor();
   2081 						}
   2082 					}
   2083 				}
   2084 			} else if ( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) ) {
   2085 				renderProgManager.BindShader_TextureTexGenVertexColor();
   2086 			} else if ( pStage->texture.cinematic ) {
   2087 				renderProgManager.BindShader_Bink();
   2088 			} else {
   2089 				if ( surf->jointCache ) {
   2090 					renderProgManager.BindShader_TextureVertexColorSkinned();
   2091 				} else {
   2092 					renderProgManager.BindShader_TextureVertexColor();
   2093 				}
   2094 			}
   2095 		
   2096 			RB_SetVertexColorParms( svc );
   2097 
   2098 			// bind the texture
   2099 			RB_BindVariableStageImage( &pStage->texture, regs );
   2100 
   2101 			// set privatePolygonOffset if necessary
   2102 			if ( pStage->privatePolygonOffset ) {
   2103 				GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset );
   2104 				stageGLState |= GLS_POLYGON_OFFSET;
   2105 			}
   2106 
   2107 			// set the state
   2108 			GL_State( stageGLState );
   2109 		
   2110 			RB_PrepareStageTexturing( pStage, surf );
   2111 
   2112 			// draw it
   2113 			RB_DrawElementsWithCounters( surf );
   2114 
   2115 			RB_FinishStageTexturing( pStage, surf );
   2116 
   2117 			// unset privatePolygonOffset if necessary
   2118 			if ( pStage->privatePolygonOffset ) {
   2119 				GL_PolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() );
   2120 			}
   2121 			renderLog.CloseBlock();
   2122 		}
   2123 
   2124 		renderLog.CloseBlock();
   2125 	}
   2126 
   2127 	GL_Cull( CT_FRONT_SIDED );
   2128 	GL_Color( 1.0f, 1.0f, 1.0f );
   2129 
   2130 	renderLog.CloseBlock();
   2131 	return i;
   2132 }
   2133 
   2134 /*
   2135 =============================================================================================
   2136 
   2137 BLEND LIGHT PROJECTION
   2138 
   2139 =============================================================================================
   2140 */
   2141 
   2142 /*
   2143 =====================
   2144 RB_T_BlendLight
   2145 =====================
   2146 */
   2147 static void RB_T_BlendLight( const drawSurf_t *drawSurfs, const viewLight_t * vLight ) {
   2148 	backEnd.currentSpace = NULL;
   2149 
   2150 	for ( const drawSurf_t * drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) {
   2151 		if ( drawSurf->scissorRect.IsEmpty() ) {
   2152 			continue;	// !@# FIXME: find out why this is sometimes being hit!
   2153 						// temporarily jump over the scissor and draw so the gl error callback doesn't get hit
   2154 		}
   2155 
   2156 		if ( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) {
   2157 			// change the scissor
   2158 			GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1,
   2159 						backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1,
   2160 						drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1,
   2161 						drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 );
   2162 			backEnd.currentScissor = drawSurf->scissorRect;
   2163 		}
   2164 
   2165 		if ( drawSurf->space != backEnd.currentSpace ) {
   2166 			// change the matrix
   2167 			RB_SetMVP( drawSurf->space->mvp );
   2168 
   2169 			// change the light projection matrix
   2170 			idPlane	lightProjectInCurrentSpace[4];
   2171 			for ( int i = 0; i < 4; i++ ) {
   2172 				R_GlobalPlaneToLocal( drawSurf->space->modelMatrix, vLight->lightProject[i], lightProjectInCurrentSpace[i] );
   2173 			}
   2174 
   2175 			SetVertexParm( RENDERPARM_TEXGEN_0_S, lightProjectInCurrentSpace[0].ToFloatPtr() );
   2176 			SetVertexParm( RENDERPARM_TEXGEN_0_T, lightProjectInCurrentSpace[1].ToFloatPtr() );
   2177 			SetVertexParm( RENDERPARM_TEXGEN_0_Q, lightProjectInCurrentSpace[2].ToFloatPtr() );
   2178 			SetVertexParm( RENDERPARM_TEXGEN_1_S, lightProjectInCurrentSpace[3].ToFloatPtr() );	// falloff
   2179 
   2180 			backEnd.currentSpace = drawSurf->space;
   2181 		}
   2182 
   2183 		RB_DrawElementsWithCounters( drawSurf );
   2184 	}
   2185 }
   2186 
   2187 /*
   2188 =====================
   2189 RB_BlendLight
   2190 
   2191 Dual texture together the falloff and projection texture with a blend
   2192 mode to the framebuffer, instead of interacting with the surface texture
   2193 =====================
   2194 */
   2195 static void RB_BlendLight( const drawSurf_t *drawSurfs, const drawSurf_t *drawSurfs2, const viewLight_t * vLight ) {
   2196 	if ( drawSurfs == NULL ) {
   2197 		return;
   2198 	}
   2199 	if ( r_skipBlendLights.GetBool() ) {
   2200 		return;
   2201 	}
   2202 	renderLog.OpenBlock( vLight->lightShader->GetName() );
   2203 
   2204 	const idMaterial * lightShader = vLight->lightShader;
   2205 	const float	* regs = vLight->shaderRegisters;
   2206 
   2207 	// texture 1 will get the falloff texture
   2208 	GL_SelectTexture( 1 );
   2209 	vLight->falloffImage->Bind();
   2210 
   2211 	// texture 0 will get the projected texture
   2212 	GL_SelectTexture( 0 );
   2213 
   2214 	renderProgManager.BindShader_BlendLight();
   2215 
   2216 	for ( int i = 0; i < lightShader->GetNumStages(); i++ ) {
   2217 		const shaderStage_t	*stage = lightShader->GetStage(i);
   2218 
   2219 		if ( !regs[ stage->conditionRegister ] ) {
   2220 			continue;
   2221 		}
   2222 
   2223 		GL_State( GLS_DEPTHMASK | stage->drawStateBits | GLS_DEPTHFUNC_EQUAL );
   2224 
   2225 		GL_SelectTexture( 0 );
   2226 		stage->texture.image->Bind();
   2227 
   2228 		if ( stage->texture.hasMatrix ) {
   2229 			RB_LoadShaderTextureMatrix( regs, &stage->texture );
   2230 		}
   2231 
   2232 		// get the modulate values from the light, including alpha, unlike normal lights
   2233 		float lightColor[4];
   2234 		lightColor[0] = regs[ stage->color.registers[0] ];
   2235 		lightColor[1] = regs[ stage->color.registers[1] ];
   2236 		lightColor[2] = regs[ stage->color.registers[2] ];
   2237 		lightColor[3] = regs[ stage->color.registers[3] ];
   2238 		GL_Color( lightColor );
   2239 
   2240 		RB_T_BlendLight( drawSurfs, vLight );
   2241 		RB_T_BlendLight( drawSurfs2, vLight );
   2242 	}
   2243 
   2244 	GL_SelectTexture( 1 );
   2245 	globalImages->BindNull();
   2246 
   2247 	GL_SelectTexture( 0 );
   2248 
   2249 	renderProgManager.Unbind();
   2250 	renderLog.CloseBlock();
   2251 }
   2252 
   2253 /*
   2254 =========================================================================================================
   2255 
   2256 FOG LIGHTS
   2257 
   2258 =========================================================================================================
   2259 */
   2260 
   2261 /*
   2262 =====================
   2263 RB_T_BasicFog
   2264 =====================
   2265 */
   2266 static void RB_T_BasicFog( const drawSurf_t *drawSurfs, const idPlane fogPlanes[4], const idRenderMatrix * inverseBaseLightProject ) {
   2267 	backEnd.currentSpace = NULL;
   2268 
   2269 	for ( const drawSurf_t * drawSurf = drawSurfs; drawSurf != NULL; drawSurf = drawSurf->nextOnLight ) {
   2270 		if ( drawSurf->scissorRect.IsEmpty() ) {
   2271 			continue;	// !@# FIXME: find out why this is sometimes being hit!
   2272 						// temporarily jump over the scissor and draw so the gl error callback doesn't get hit
   2273 		}
   2274 
   2275 		if ( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) {
   2276 			// change the scissor
   2277 			GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1,
   2278 						backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1,
   2279 						drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1,
   2280 						drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 );
   2281 			backEnd.currentScissor = drawSurf->scissorRect;
   2282 		}
   2283 
   2284 		if ( drawSurf->space != backEnd.currentSpace ) {
   2285 			idPlane localFogPlanes[4];
   2286 			if ( inverseBaseLightProject == NULL ) {
   2287 				RB_SetMVP( drawSurf->space->mvp );
   2288 				for ( int i = 0; i < 4; i++ ) {
   2289 					R_GlobalPlaneToLocal( drawSurf->space->modelMatrix, fogPlanes[i], localFogPlanes[i] );
   2290 				}
   2291 			} else {
   2292 				idRenderMatrix invProjectMVPMatrix;
   2293 				idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, *inverseBaseLightProject, invProjectMVPMatrix );
   2294 				RB_SetMVP( invProjectMVPMatrix );
   2295 				for ( int i = 0; i < 4; i++ ) {
   2296 					inverseBaseLightProject->InverseTransformPlane( fogPlanes[i], localFogPlanes[i], false );
   2297 				}
   2298 			}
   2299 
   2300 			SetVertexParm( RENDERPARM_TEXGEN_0_S, localFogPlanes[0].ToFloatPtr() );
   2301 			SetVertexParm( RENDERPARM_TEXGEN_0_T, localFogPlanes[1].ToFloatPtr() );
   2302 			SetVertexParm( RENDERPARM_TEXGEN_1_T, localFogPlanes[2].ToFloatPtr() );
   2303 			SetVertexParm( RENDERPARM_TEXGEN_1_S, localFogPlanes[3].ToFloatPtr() );
   2304 
   2305 			backEnd.currentSpace = ( inverseBaseLightProject == NULL ) ? drawSurf->space : NULL;
   2306 		}
   2307 
   2308 		if ( drawSurf->jointCache ) {
   2309 			renderProgManager.BindShader_FogSkinned();
   2310 		} else {
   2311 			renderProgManager.BindShader_Fog();
   2312 		}
   2313 
   2314 		RB_DrawElementsWithCounters( drawSurf );
   2315 	}
   2316 }
   2317 
   2318 /*
   2319 ==================
   2320 RB_FogPass
   2321 ==================
   2322 */
   2323 static void RB_FogPass( const drawSurf_t * drawSurfs,  const drawSurf_t * drawSurfs2, const viewLight_t * vLight ) {
   2324 	renderLog.OpenBlock( vLight->lightShader->GetName() );
   2325 
   2326 	// find the current color and density of the fog
   2327 	const idMaterial * lightShader = vLight->lightShader;
   2328 	const float * regs = vLight->shaderRegisters;
   2329 	// assume fog shaders have only a single stage
   2330 	const shaderStage_t * stage = lightShader->GetStage( 0 );
   2331 
   2332 	float lightColor[4];
   2333 	lightColor[0] = regs[ stage->color.registers[0] ];
   2334 	lightColor[1] = regs[ stage->color.registers[1] ];
   2335 	lightColor[2] = regs[ stage->color.registers[2] ];
   2336 	lightColor[3] = regs[ stage->color.registers[3] ];
   2337 
   2338 	GL_Color( lightColor );
   2339 
   2340 	// calculate the falloff planes
   2341 	float a;
   2342 
   2343 	// if they left the default value on, set a fog distance of 500
   2344 	if ( lightColor[3] <= 1.0f ) {
   2345 		a = -0.5f / DEFAULT_FOG_DISTANCE;
   2346 	} else {
   2347 		// otherwise, distance = alpha color
   2348 		a = -0.5f / lightColor[3];
   2349 	}
   2350 
   2351 	// texture 0 is the falloff image
   2352 	GL_SelectTexture( 0 );
   2353 	globalImages->fogImage->Bind();
   2354 
   2355 	// texture 1 is the entering plane fade correction
   2356 	GL_SelectTexture( 1 );
   2357 	globalImages->fogEnterImage->Bind();
   2358 
   2359 	// S is based on the view origin
   2360 	const float s = vLight->fogPlane.Distance( backEnd.viewDef->renderView.vieworg );
   2361 
   2362 	const float FOG_SCALE = 0.001f;
   2363 
   2364 	idPlane fogPlanes[4];
   2365 
   2366 	// S-0
   2367 	fogPlanes[0][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[0*4+2];
   2368 	fogPlanes[0][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[1*4+2];
   2369 	fogPlanes[0][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[2*4+2];
   2370 	fogPlanes[0][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[3*4+2] + 0.5f;
   2371 
   2372 	// T-0
   2373 	fogPlanes[1][0] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[0*4+0];
   2374 	fogPlanes[1][1] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[1*4+0];
   2375 	fogPlanes[1][2] = 0.0f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[2*4+0];
   2376 	fogPlanes[1][3] = 0.5f;//a * backEnd.viewDef->worldSpace.modelViewMatrix[3*4+0] + 0.5f;
   2377 
   2378 	// T-1 will get a texgen for the fade plane, which is always the "top" plane on unrotated lights
   2379 	fogPlanes[2][0] = FOG_SCALE * vLight->fogPlane[0];
   2380 	fogPlanes[2][1] = FOG_SCALE * vLight->fogPlane[1];
   2381 	fogPlanes[2][2] = FOG_SCALE * vLight->fogPlane[2];
   2382 	fogPlanes[2][3] = FOG_SCALE * vLight->fogPlane[3] + FOG_ENTER;
   2383 
   2384 	// S-1
   2385 	fogPlanes[3][0] = 0.0f;
   2386 	fogPlanes[3][1] = 0.0f;
   2387 	fogPlanes[3][2] = 0.0f;
   2388 	fogPlanes[3][3] = FOG_SCALE * s + FOG_ENTER;
   2389 
   2390 	// draw it
   2391 	GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
   2392 	RB_T_BasicFog( drawSurfs, fogPlanes, NULL );
   2393 	RB_T_BasicFog( drawSurfs2, fogPlanes, NULL );
   2394 
   2395 	// the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead
   2396 	// of depthfunc_equal
   2397 	GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS );
   2398 	GL_Cull( CT_BACK_SIDED );
   2399 
   2400 	backEnd.zeroOneCubeSurface.space = &backEnd.viewDef->worldSpace;
   2401 	backEnd.zeroOneCubeSurface.scissorRect = backEnd.viewDef->scissor;
   2402 	RB_T_BasicFog( &backEnd.zeroOneCubeSurface, fogPlanes, &vLight->inverseBaseLightProject );
   2403 
   2404 	GL_Cull( CT_FRONT_SIDED );
   2405 
   2406 	GL_SelectTexture( 1 );
   2407 	globalImages->BindNull();
   2408 
   2409 	GL_SelectTexture( 0 );
   2410 
   2411 	renderProgManager.Unbind();
   2412 
   2413 	renderLog.CloseBlock();
   2414 }
   2415 
   2416 /*
   2417 ==================
   2418 RB_FogAllLights
   2419 ==================
   2420 */
   2421 static void RB_FogAllLights() {
   2422 	if ( r_skipFogLights.GetBool() || r_showOverDraw.GetInteger() != 0 
   2423 		 || backEnd.viewDef->isXraySubview /* don't fog in xray mode*/ ) {
   2424 		return;
   2425 	}
   2426 	renderLog.OpenMainBlock( MRB_FOG_ALL_LIGHTS );
   2427 	renderLog.OpenBlock( "RB_FogAllLights" );
   2428 
   2429 	// force fog plane to recalculate
   2430 	backEnd.currentSpace = NULL;
   2431 
   2432 	for ( viewLight_t * vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next ) {
   2433 		if ( vLight->lightShader->IsFogLight() ) {
   2434 			RB_FogPass( vLight->globalInteractions, vLight->localInteractions, vLight );
   2435 		} else if ( vLight->lightShader->IsBlendLight() ) {
   2436 			RB_BlendLight( vLight->globalInteractions, vLight->localInteractions, vLight );
   2437 		}
   2438 	}
   2439 
   2440 	renderLog.CloseBlock();
   2441 	renderLog.CloseMainBlock();
   2442 }
   2443 
   2444 /*
   2445 =========================================================================================================
   2446 
   2447 BACKEND COMMANDS
   2448 
   2449 =========================================================================================================
   2450 */
   2451 
   2452 /*
   2453 ==================
   2454 RB_DrawViewInternal
   2455 ==================
   2456 */
   2457 void RB_DrawViewInternal( const viewDef_t * viewDef, const int stereoEye ) {
   2458 	renderLog.OpenBlock( "RB_DrawViewInternal" );
   2459 
   2460 	//-------------------------------------------------
   2461 	// guis can wind up referencing purged images that need to be loaded.
   2462 	// this used to be in the gui emit code, but now that it can be running
   2463 	// in a separate thread, it must not try to load images, so do it here.
   2464 	//-------------------------------------------------
   2465 	drawSurf_t **drawSurfs = (drawSurf_t **)&viewDef->drawSurfs[0];
   2466 	const int numDrawSurfs = viewDef->numDrawSurfs;
   2467 
   2468 	for ( int i = 0; i < numDrawSurfs; i++ ) {
   2469 		const drawSurf_t * ds = viewDef->drawSurfs[ i ];
   2470 		if ( ds->material != NULL ) {
   2471 			const_cast<idMaterial *>( ds->material )->EnsureNotPurged();
   2472 		}
   2473 	}
   2474 
   2475 	//-------------------------------------------------
   2476 	// RB_BeginDrawingView
   2477 	//
   2478 	// Any mirrored or portaled views have already been drawn, so prepare
   2479 	// to actually render the visible surfaces for this view
   2480 	//
   2481 	// clear the z buffer, set the projection matrix, etc
   2482 	//-------------------------------------------------
   2483 
   2484 	// set the window clipping
   2485 	GL_Viewport( viewDef->viewport.x1,
   2486 		viewDef->viewport.y1,
   2487 		viewDef->viewport.x2 + 1 - viewDef->viewport.x1,
   2488 		viewDef->viewport.y2 + 1 - viewDef->viewport.y1 );
   2489 
   2490 	// the scissor may be smaller than the viewport for subviews
   2491 	GL_Scissor( backEnd.viewDef->viewport.x1 + viewDef->scissor.x1,
   2492 				backEnd.viewDef->viewport.y1 + viewDef->scissor.y1,
   2493 				viewDef->scissor.x2 + 1 - viewDef->scissor.x1,
   2494 				viewDef->scissor.y2 + 1 - viewDef->scissor.y1 );
   2495 	backEnd.currentScissor = viewDef->scissor;
   2496 
   2497 	backEnd.glState.faceCulling = -1;		// force face culling to set next time
   2498 
   2499 	// ensures that depth writes are enabled for the depth clear
   2500 	GL_State( GLS_DEFAULT );
   2501 
   2502 
   2503 	// Clear the depth buffer and clear the stencil to 128 for stencil shadows as well as gui masking
   2504 	GL_Clear( false, true, true, STENCIL_SHADOW_TEST_VALUE, 0.0f, 0.0f, 0.0f, 0.0f );
   2505 
   2506 	// normal face culling
   2507 	GL_Cull( CT_FRONT_SIDED );
   2508 
   2509 #ifdef USE_CORE_PROFILE
   2510 	// bind one global Vertex Array Object (VAO)
   2511 	qglBindVertexArray( glConfig.global_vao );
   2512 #endif
   2513 
   2514 	//------------------------------------
   2515 	// sets variables that can be used by all programs
   2516 	//------------------------------------
   2517 	{
   2518 		//
   2519 		// set eye position in global space
   2520 		//
   2521 		float parm[4];
   2522 		parm[0] = backEnd.viewDef->renderView.vieworg[0];
   2523 		parm[1] = backEnd.viewDef->renderView.vieworg[1];
   2524 		parm[2] = backEnd.viewDef->renderView.vieworg[2];
   2525 		parm[3] = 1.0f;
   2526 
   2527 		SetVertexParm( RENDERPARM_GLOBALEYEPOS, parm ); // rpGlobalEyePos
   2528 
   2529 		// sets overbright to make world brighter
   2530 		// This value is baked into the specularScale and diffuseScale values so
   2531 		// the interaction programs don't need to perform the extra multiply,
   2532 		// but any other renderprogs that want to obey the brightness value
   2533 		// can reference this.
   2534 		float overbright = r_lightScale.GetFloat() * 0.5f;
   2535 		parm[0] = overbright;
   2536 		parm[1] = overbright;
   2537 		parm[2] = overbright;
   2538 		parm[3] = overbright;
   2539 		SetFragmentParm( RENDERPARM_OVERBRIGHT, parm );
   2540 
   2541 		// Set Projection Matrix
   2542 		float projMatrixTranspose[16];
   2543 		R_MatrixTranspose( backEnd.viewDef->projectionMatrix, projMatrixTranspose );
   2544 		SetVertexParms( RENDERPARM_PROJMATRIX_X, projMatrixTranspose, 4 );
   2545 	}
   2546 
   2547 	//-------------------------------------------------
   2548 	// fill the depth buffer and clear color buffer to black except on subviews
   2549 	//-------------------------------------------------
   2550 	RB_FillDepthBufferFast( drawSurfs, numDrawSurfs );
   2551 
   2552 	//-------------------------------------------------
   2553 	// main light renderer
   2554 	//-------------------------------------------------
   2555 	RB_DrawInteractions();
   2556 
   2557 	//-------------------------------------------------
   2558 	// now draw any non-light dependent shading passes
   2559 	//-------------------------------------------------
   2560 	int processed = 0;
   2561 	if ( !r_skipShaderPasses.GetBool() ) {
   2562 		renderLog.OpenMainBlock( MRB_DRAW_SHADER_PASSES );
   2563 		float guiScreenOffset;
   2564 		if ( viewDef->viewEntitys != NULL ) {
   2565 			// guiScreenOffset will be 0 in non-gui views
   2566 			guiScreenOffset = 0.0f;
   2567 		} else {
   2568 			guiScreenOffset = stereoEye * viewDef->renderView.stereoScreenSeparation;
   2569 		}
   2570 		processed = RB_DrawShaderPasses( drawSurfs, numDrawSurfs, guiScreenOffset, stereoEye );
   2571 		renderLog.CloseMainBlock();
   2572 	}
   2573 
   2574 	//-------------------------------------------------
   2575 	// fog and blend lights, drawn after emissive surfaces
   2576 	// so they are properly dimmed down
   2577 	//-------------------------------------------------
   2578 	RB_FogAllLights();
   2579 
   2580 	//-------------------------------------------------
   2581 	// capture the depth for the motion blur before rendering any post process surfaces that may contribute to the depth
   2582 	//-------------------------------------------------
   2583 	if ( r_motionBlur.GetInteger() > 0 ) {
   2584 		const idScreenRect & viewport = backEnd.viewDef->viewport;
   2585 		globalImages->currentDepthImage->CopyDepthbuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() );
   2586 	}
   2587 
   2588 	//-------------------------------------------------
   2589 	// now draw any screen warping post-process effects using _currentRender
   2590 	//-------------------------------------------------
   2591 	if ( processed < numDrawSurfs && !r_skipPostProcess.GetBool() ) {
   2592 		int x = backEnd.viewDef->viewport.x1;
   2593 		int y = backEnd.viewDef->viewport.y1;
   2594 		int	w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1;
   2595 		int	h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1;
   2596 
   2597 		RENDERLOG_PRINTF( "Resolve to %i x %i buffer\n", w, h );
   2598 
   2599 		GL_SelectTexture( 0 );
   2600 
   2601 		// resolve the screen
   2602 		globalImages->currentRenderImage->CopyFramebuffer( x, y, w, h );
   2603 		backEnd.currentRenderCopied = true;
   2604 
   2605 		// RENDERPARM_SCREENCORRECTIONFACTOR amd RENDERPARM_WINDOWCOORD overlap
   2606 		// diffuseScale and specularScale
   2607 
   2608 		// screen power of two correction factor (no longer relevant now)
   2609 		float screenCorrectionParm[4];
   2610 		screenCorrectionParm[0] = 1.0f;
   2611 		screenCorrectionParm[1] = 1.0f;
   2612 		screenCorrectionParm[2] = 0.0f;
   2613 		screenCorrectionParm[3] = 1.0f;
   2614 		SetFragmentParm( RENDERPARM_SCREENCORRECTIONFACTOR, screenCorrectionParm ); // rpScreenCorrectionFactor
   2615 
   2616 		// window coord to 0.0 to 1.0 conversion
   2617 		float windowCoordParm[4];
   2618 		windowCoordParm[0] = 1.0f / w;
   2619 		windowCoordParm[1] = 1.0f / h;
   2620 		windowCoordParm[2] = 0.0f;
   2621 		windowCoordParm[3] = 1.0f;
   2622 		SetFragmentParm( RENDERPARM_WINDOWCOORD, windowCoordParm ); // rpWindowCoord
   2623 
   2624 		// render the remaining surfaces
   2625 		renderLog.OpenMainBlock( MRB_DRAW_SHADER_PASSES_POST );
   2626 		RB_DrawShaderPasses( drawSurfs + processed, numDrawSurfs - processed, 0.0f /* definitely not a gui */, stereoEye );
   2627 		renderLog.CloseMainBlock();
   2628 	}
   2629 
   2630 	//-------------------------------------------------
   2631 	// render debug tools
   2632 	//-------------------------------------------------
   2633 	RB_RenderDebugTools( drawSurfs, numDrawSurfs );
   2634 
   2635 	renderLog.CloseBlock();
   2636 }
   2637 
   2638 /*
   2639 ==================
   2640 RB_MotionBlur
   2641 
   2642 Experimental feature
   2643 ==================
   2644 */
   2645 void RB_MotionBlur() {
   2646 	if ( !backEnd.viewDef->viewEntitys ) {
   2647 		// 3D views only
   2648 		return;
   2649 	}
   2650 	if ( r_motionBlur.GetInteger() <= 0 ) {
   2651 		return;
   2652 	}
   2653 	if ( backEnd.viewDef->isSubview ) {
   2654 		return;
   2655 	}
   2656 
   2657 	GL_CheckErrors();
   2658 
   2659 	// clear the alpha buffer and draw only the hands + weapon into it so
   2660 	// we can avoid blurring them
   2661 	qglClearColor( 0, 0, 0, 1 );
   2662 	GL_State( GLS_COLORMASK | GLS_DEPTHMASK );
   2663 	qglClear( GL_COLOR_BUFFER_BIT );
   2664 	GL_Color( 0, 0, 0, 0 );
   2665 	GL_SelectTexture( 0 );
   2666 	globalImages->blackImage->Bind();
   2667 	backEnd.currentSpace = NULL;
   2668 
   2669 	drawSurf_t **drawSurfs = (drawSurf_t **)&backEnd.viewDef->drawSurfs[0];
   2670 	for ( int surfNum = 0; surfNum < backEnd.viewDef->numDrawSurfs; surfNum++ ) {
   2671 		const drawSurf_t * surf = drawSurfs[ surfNum ];
   2672 
   2673 		if ( !surf->space->weaponDepthHack && !surf->space->skipMotionBlur && !surf->material->HasSubview() ) {
   2674 			// Apply motion blur to this object
   2675 			continue;
   2676 		}
   2677 
   2678 		const idMaterial * shader = surf->material;
   2679 		if ( shader->Coverage() == MC_TRANSLUCENT ) {
   2680 			// muzzle flash, etc
   2681 			continue;
   2682 		}
   2683 
   2684 		// set mvp matrix
   2685 		if ( surf->space != backEnd.currentSpace ) {
   2686 			RB_SetMVP( surf->space->mvp );
   2687 			backEnd.currentSpace = surf->space;
   2688 		}
   2689 
   2690 		// this could just be a color, but we don't have a skinned color-only prog
   2691 		if ( surf->jointCache ) {
   2692 			renderProgManager.BindShader_TextureVertexColorSkinned();
   2693 		} else {
   2694 			renderProgManager.BindShader_TextureVertexColor();
   2695 		}
   2696 
   2697 		// draw it solid
   2698 		RB_DrawElementsWithCounters( surf );
   2699 	}
   2700 	GL_State( GLS_DEPTHFUNC_ALWAYS );
   2701 
   2702 	// copy off the color buffer and the depth buffer for the motion blur prog
   2703 	// we use the viewport dimensions for copying the buffers in case resolution scaling is enabled.
   2704 	const idScreenRect & viewport = backEnd.viewDef->viewport;
   2705 	globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() );
   2706 
   2707 	// in stereo rendering, each eye needs to get a separate previous frame mvp
   2708 	int mvpIndex = ( backEnd.viewDef->renderView.viewEyeBuffer == 1 ) ? 1 : 0;
   2709 
   2710 	// derive the matrix to go from current pixels to previous frame pixels
   2711 	idRenderMatrix	inverseMVP;
   2712 	idRenderMatrix::Inverse( backEnd.viewDef->worldSpace.mvp, inverseMVP );
   2713 
   2714 	idRenderMatrix	motionMatrix;
   2715 	idRenderMatrix::Multiply( backEnd.prevMVP[mvpIndex], inverseMVP, motionMatrix );
   2716 
   2717 	backEnd.prevMVP[mvpIndex] = backEnd.viewDef->worldSpace.mvp;
   2718 
   2719 	RB_SetMVP( motionMatrix );
   2720 
   2721 	GL_State( GLS_DEPTHFUNC_ALWAYS );
   2722 	GL_Cull( CT_TWO_SIDED );
   2723 
   2724 	renderProgManager.BindShader_MotionBlur();
   2725 
   2726 	// let the fragment program know how many samples we are going to use
   2727 	idVec4 samples( (float)( 1 << r_motionBlur.GetInteger() ) );
   2728 	SetFragmentParm( RENDERPARM_OVERBRIGHT, samples.ToFloatPtr() );
   2729 
   2730 	GL_SelectTexture( 0 );
   2731 	globalImages->currentRenderImage->Bind();
   2732 	GL_SelectTexture( 1 );
   2733 	globalImages->currentDepthImage->Bind();
   2734 
   2735 	RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
   2736 	GL_CheckErrors();
   2737 }
   2738 
   2739 /*
   2740 ==================
   2741 RB_DrawView
   2742 
   2743 StereoEye will always be 0 in mono modes, or -1 / 1 in stereo modes.
   2744 If the view is a GUI view that is repeated for both eyes, the viewDef.stereoEye value
   2745 is 0, so the stereoEye parameter is not always the same as that.
   2746 ==================
   2747 */
   2748 void RB_DrawView( const void *data, const int stereoEye ) {
   2749 	const drawSurfsCommand_t * cmd = (const drawSurfsCommand_t *)data;
   2750 
   2751 	backEnd.viewDef = cmd->viewDef;
   2752 
   2753 	// we will need to do a new copyTexSubImage of the screen
   2754 	// when a SS_POST_PROCESS material is used
   2755 	backEnd.currentRenderCopied = false;
   2756 
   2757 	// if there aren't any drawsurfs, do nothing
   2758 	if ( !backEnd.viewDef->numDrawSurfs ) {
   2759 		return;
   2760 	}
   2761 
   2762 	// skip render bypasses everything that has models, assuming
   2763 	// them to be 3D views, but leaves 2D rendering visible
   2764 	if ( r_skipRender.GetBool() && backEnd.viewDef->viewEntitys ) {
   2765 		return;
   2766 	}
   2767 
   2768 	// skip render context sets the wgl context to NULL,
   2769 	// which should factor out the API cost, under the assumption
   2770 	// that all gl calls just return if the context isn't valid
   2771 	if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
   2772 		GLimp_DeactivateContext();
   2773 	}
   2774 
   2775 	backEnd.pc.c_surfaces += backEnd.viewDef->numDrawSurfs;
   2776 
   2777 	RB_ShowOverdraw();
   2778 
   2779 	// render the scene
   2780 	RB_DrawViewInternal( cmd->viewDef, stereoEye );
   2781 
   2782 	RB_MotionBlur();
   2783 
   2784 	// restore the context for 2D drawing if we were stubbing it out
   2785 	if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
   2786 		GLimp_ActivateContext();
   2787 		GL_SetDefaultState();
   2788 	}
   2789 
   2790 	// optionally draw a box colored based on the eye number
   2791 	if ( r_drawEyeColor.GetBool() ) {
   2792 		const idScreenRect & r = backEnd.viewDef->viewport;
   2793 		GL_Scissor( ( r.x1 + r.x2 ) / 2, ( r.y1 + r.y2 ) / 2, 32, 32 );
   2794 		switch ( stereoEye ) {
   2795 			case -1:
   2796 				GL_Clear( true, false, false, 0, 1.0f, 0.0f, 0.0f, 1.0f );
   2797 				break;
   2798 			case 1:
   2799 				GL_Clear( true, false, false, 0, 0.0f, 1.0f, 0.0f, 1.0f );
   2800 				break;
   2801 			default:
   2802 				GL_Clear( true, false, false, 0, 0.5f, 0.5f, 0.5f, 1.0f );
   2803 				break;
   2804 		}
   2805 	}
   2806 }
   2807 
   2808 /*
   2809 ==================
   2810 RB_CopyRender
   2811 
   2812 Copy part of the current framebuffer to an image
   2813 ==================
   2814 */
   2815 void RB_CopyRender( const void *data ) {
   2816 	const copyRenderCommand_t * cmd = (const copyRenderCommand_t *)data;
   2817 
   2818 	if ( r_skipCopyTexture.GetBool() ) {
   2819 		return;
   2820 	}
   2821 
   2822 	RENDERLOG_PRINTF( "***************** RB_CopyRender *****************\n" );
   2823 
   2824 	if ( cmd->image ) {
   2825 		cmd->image->CopyFramebuffer( cmd->x, cmd->y, cmd->imageWidth, cmd->imageHeight );
   2826 	}
   2827 
   2828 	if ( cmd->clearColorAfterCopy ) {
   2829 		GL_Clear( true, false, false, STENCIL_SHADOW_TEST_VALUE, 0, 0, 0, 0 );
   2830 	}
   2831 }
   2832 
   2833 /*
   2834 ==================
   2835 RB_PostProcess
   2836 
   2837 ==================
   2838 */
   2839 extern idCVar rs_enable;
   2840 void RB_PostProcess( const void * data ) {
   2841 
   2842 	// only do the post process step if resolution scaling is enabled. Prevents the unnecessary copying of the framebuffer and
   2843 	// corresponding full screen quad pass.
   2844 	if ( rs_enable.GetInteger() == 0 ) { 
   2845 		return;
   2846 	}
   2847 
   2848 	// resolve the scaled rendering to a temporary texture
   2849 	postProcessCommand_t * cmd = (postProcessCommand_t *)data;
   2850 	const idScreenRect & viewport = cmd->viewDef->viewport;
   2851 	globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() );
   2852 
   2853 	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS );
   2854 	GL_Cull( CT_TWO_SIDED );
   2855 
   2856 	int screenWidth = renderSystem->GetWidth();
   2857 	int screenHeight = renderSystem->GetHeight();
   2858 
   2859 	// set the window clipping
   2860 	GL_Viewport( 0, 0, screenWidth, screenHeight );
   2861 	GL_Scissor( 0, 0, screenWidth, screenHeight );
   2862 
   2863 	GL_SelectTexture( 0 );
   2864 	globalImages->currentRenderImage->Bind();
   2865 	renderProgManager.BindShader_PostProcess();
   2866 
   2867 	// Draw
   2868 	RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
   2869 
   2870 	renderLog.CloseBlock();
   2871 }