/* ================ R_RenderView A view may be either the actual camera view, a mirror / remote location, or a 3D view on a gui surface. Parms will typically be allocated with R_FrameAlloc ================ */ void R_RenderView( viewDef_t *parms ) { viewDef_t *oldView; if ( parms->renderView.width <= 0 || parms->renderView.height <= 0 ) { return; } tr.viewCount++; // save view in case we are a subview oldView = tr.viewDef; tr.viewDef = parms; tr.sortOffset = 0; // set the matrix for world space to eye space R_SetViewMatrix( tr.viewDef ); // the four sides of the view frustum are needed // for culling and portal visibility R_SetupViewFrustum(); // we need to set the projection matrix before doing // portal-to-screen scissor box calculations R_SetupProjection(); // identify all the visible portalAreas, and the entityDefs and // lightDefs that are in them and pass culling. static_cast<idRenderWorldLocal *>(parms->renderWorld)->FindViewLightsAndEntities(); // constrain the view frustum to the view lights and entities R_ConstrainViewFrustum(); // make sure that interactions exist for all light / entity combinations // that are visible // add any pre-generated light shadows, and calculate the light shader values R_AddLightSurfaces(); // adds ambient surfaces and create any necessary interaction surfaces to add to the light // lists R_AddModelSurfaces(); // any viewLight that didn't have visible surfaces can have it's shadows removed R_RemoveUnecessaryViewLights(); // sort all the ambient surfaces for translucency ordering R_SortDrawSurfs(); // generate any subviews (mirrors, cameras, etc) before adding this view if ( R_GenerateSubViews() ) { // if we are debugging subviews, allow the skipping of the // main view draw if ( r_subviewOnly.GetBool() ) { return; } } // write everything needed to the demo file if ( session->writeDemo ) { static_cast<idRenderWorldLocal *>(parms->renderWorld)->WriteVisibleDefs( tr.viewDef ); } // add the rendering commands for this viewDef R_AddDrawViewCmd( parms ); // restore view in case we are a subview tr.viewDef = oldView; }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { RB_EndSurface(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } qglLoadMatrixf( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, qfalse); qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(temp.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } if(!oldDepthRange) qglDepthRange (0, 0.3); } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } qglDepthRange (0, 1); } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int pshadowed, oldPshadowed; int cubemapIndex, oldCubemapIndex; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; FBO_t* fbo = NULL; qboolean inQuery = qfalse; float depth[2]; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; fbo = glState.currentFBO; // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldPshadowed = qfalse; oldCubemapIndex = -1; oldSort = -1; depth[0] = 0.f; depth[1] = 1.f; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) { if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) continue; // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); cubemapIndex = drawSurf->cubemapIndex; // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { if (oldShader != NULL) { RB_EndSurface(); } RB_BeginSurface( shader, fogNum, cubemapIndex ); backEnd.pc.c_surfBatches++; oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; oldPshadowed = pshadowed; oldCubemapIndex = cubemapIndex; } if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) continue; // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { qboolean sunflare = qfalse; depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } GL_SetModelviewMatrix( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, 0, qfalse); GL_SetProjectionMatrix( temp.projectionMatrix ); } } if(!oldDepthRange) { depth[0] = 0; depth[1] = 0.3f; qglDepthRange (depth[0], depth[1]); } } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); } if (!sunflare) qglDepthRange (0, 1); depth[0] = 0; depth[1] = 1; } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } if (inQuery) { qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } if (glRefConfig.framebufferObject) FBO_Bind(fbo); // go back to the world modelview matrix GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix ); qglDepthRange (0, 1); }
/* * RB_RenderDrawSurfList */ void RB_RenderDrawSurfList(drawSurf_t *drawSurfs, int numDrawSurfs) { material_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int pshadowed, oldPshadowed; qbool depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; float depth[2]; FBO_t * fbo = NULL; qbool inQuery = qfalse; /* save original time for entity shader offsets */ originalTime = backEnd.refdef.floatTime; /* clear the z buffer, set the modelview, etc */ RB_BeginDrawingView (); fbo = glState.currentFBO; /* draw everything */ oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldPshadowed = qfalse; oldSort = -1; depthRange = qfalse; depth[0] = 0.f; depth[1] = 1.f; backEnd.pc.c_surfaces += numDrawSurfs; for(i = 0, drawSurf = drawSurfs; i < numDrawSurfs; i++, drawSurf++){ if(drawSurf->sort == oldSort){ /* fast path, same as previous sort */ rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface); continue; } oldSort = drawSurf->sort; R_DecomposeSort(drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed); /* * change the tess parameters if needed * a "entityMergable" shader is a shader that can have surfaces from seperate * entities merged into a single batch, like smoke and blood puff sprites */ if(shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || (entityNum != oldEntityNum && !shader->entityMergable)){ if(oldShader != NULL){ RB_EndSurface(); } RB_BeginSurface(shader, fogNum); backEnd.pc.c_surfBatches++; oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; oldPshadowed = pshadowed; } /* * change the modelview matrix if needed * */ if(entityNum != oldEntityNum){ qbool sunflare = qfalse; depthRange = isCrosshair = qfalse; #ifdef REACTION /* if we were rendering to a FBO and the previous entity was a sunflare * and the current one isn't, switch back to the main fbo */ if(oldEntityNum != -1 && fbo && RF_SUNFLARE == (backEnd.refdef.entities[oldEntityNum].e.renderfx & RF_SUNFLARE) && 0 == (backEnd.refdef.entities[entityNum].e.renderfx & RF_SUNFLARE)){ if(inQuery){ inQuery = qfalse; qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(fbo); qglDepthRange(depth[0], depth[1]); } #endif if(entityNum != ENTITYNUM_WORLD){ backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; /* we have to reset the shaderTime as well otherwise image animations start * from the wrong frame */ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; /* set up the transformation matrix */ R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.or); /* set up the dynamic lighting if needed */ if(backEnd.currentEntity->needDlights){ R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or); } #ifdef REACTION /* if the current entity is a sunflare */ if(backEnd.currentEntity->e.renderfx & RF_SUNFLARE){ /* if we're rendering to a fbo */ if(fbo){ copyv3(backEnd.currentEntity->e.origin, backEnd.sunFlarePos); /* switch FBO */ FBO_Bind(tr.godRaysFbo); qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglClear(GL_COLOR_BUFFER_BIT); qglDepthRange(1.f, 1.f); if(glRefConfig.occlusionQuery && !inQuery && !backEnd.hasSunFlare){ inQuery = qtrue; tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; qglBeginQueryARB( GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); } /* backEnd.hasSunFlare = qtrue; */ sunflare = qtrue; }else{ depthRange = qtrue; } } #endif if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK){ /* hack the depth range to prevent view model from poking into walls */ depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } }else{ backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; /* we have to reset the shaderTime as well otherwise image animations on * the world (like water) continue with the wrong frame */ tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or); } GL_SetModelviewMatrix(backEnd.or.modelMatrix); /* * change depthrange. Also change projection matrix so first person weapon does not look like coming * out of the screen. * */ if(oldDepthRange != depthRange || wasCrosshair != isCrosshair){ if(depthRange){ if(backEnd.viewParms.stereoFrame != STEREO_CENTER){ if(isCrosshair){ if(oldDepthRange){ /* was not a crosshair but now is, change back proj matrix */ GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix); } }else{ viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, 0, qfalse); GL_SetProjectionMatrix(temp.projectionMatrix); } } #ifdef REACTION if(!oldDepthRange){ depth[0] = 0; depth[1] = 0.3f; qglDepthRange (0, 0.3); } #endif }else{ if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER){ GL_SetProjectionMatrix(backEnd.viewParms.projectionMatrix); } if(!sunflare) qglDepthRange (0, 1); depth[0] = 0; depth[1] = 1; } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } /* add the triangles for this surface */ rb_surfaceTable[ *drawSurf->surface ](drawSurf->surface); } backEnd.refdef.floatTime = originalTime; /* draw the contents of the last shader batch */ if(oldShader != NULL){ RB_EndSurface(); } if(inQuery){ inQuery = qfalse; qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(fbo); /* go back to the world modelview matrix */ GL_SetModelviewMatrix(backEnd.viewParms.world.modelMatrix); /* if ( depthRange ) { */ qglDepthRange (0, 1); /* } */ #if 0 RB_DrawSun(); #endif /* darken down any stencil shadows */ RB_ShadowFinish(); /* add light flares on lights that aren't obscured */ RB_RenderFlares(); if(glRefConfig.framebufferObject) FBO_Bind(NULL); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; int oldNumVerts, oldNumIndex; //GR - tessellation flag int atiTess = 0, oldAtiTess; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView(); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; // GR - tessellation also forces to draw everything oldAtiTess = -1; backEnd.pc.c_surfaces += numDrawSurfs; for ( i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++ ) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort oldNumVerts = tess.numVertexes; oldNumIndex = tess.numIndexes; rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); // RF, convert the newly created vertexes into dust particles, and overwrite if (backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX) { RB_ZombieFX( 0, drawSurf, oldNumVerts, oldNumIndex ); } else if (backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX2) { RB_ZombieFX( 1, drawSurf, oldNumVerts, oldNumIndex ); } continue; } oldSort = drawSurf->sort; // GR - also extract tesselation flag R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &atiTess ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted // GR - force draw on tessellation flag change || ( atiTess != oldAtiTess ) || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ){ if ( oldShader != NULL ) { // GR - pass tessellation flag to the shader command // make sure to use oldAtiTess!!! tess.ATI_tess = ( oldAtiTess == ATI_TESS_TRUFORM ); RB_EndSurface(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; // GR - update old tessellation flag oldAtiTess = atiTess; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame // tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } qglLoadMatrixf( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, qfalse); qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(temp.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } if(!oldDepthRange) qglDepthRange (0, 0.3); } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } qglDepthRange( 0, 1 ); } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // RF, ZOMBIEFX, store the tess indexes, so we can grab the calculated // vertex positions and normals, and convert them into dust particles oldNumVerts = tess.numVertexes; oldNumIndex = tess.numIndexes; // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); // RF, convert the newly created vertexes into dust particles, and overwrite if ( backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX ) { RB_ZombieFX( 0, drawSurf, oldNumVerts, oldNumIndex ); } else if ( backEnd.currentEntity->e.reFlags & REFLAG_ZOMBIEFX2 ) { RB_ZombieFX( 1, drawSurf, oldNumVerts, oldNumIndex ); } } // draw the contents of the last shader batch if ( oldShader != NULL ) { // GR - pass tessellation flag to the shader command // make sure to use oldAtiTess!!! tess.ATI_tess = ( oldAtiTess == ATI_TESS_TRUFORM ); RB_EndSurface(); } // go back to the world modelview matrix backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange( 0, 1 ); } if (r_drawSun->integer) { RB_DrawSun(0.2, tr.sunShader); } // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }