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 }