/* ============= RB_CapShadowMap ============= */ const void *RB_CapShadowMap(const void *data) { const capShadowmapCommand_t *cmd = data; // finish any 2D drawing if needed if(tess.numIndexes) RB_EndSurface(); if (cmd->map != -1) { GL_SelectTexture(0); if (cmd->cubeSide != -1) { if (tr.shadowCubemaps[cmd->map]) { GL_Bind(tr.shadowCubemaps[cmd->map]); qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); } } else { if (tr.pshadowMaps[cmd->map]) { GL_Bind(tr.pshadowMaps[cmd->map]); qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); } } } return (const void *)(cmd + 1); }
/* * RB_CapShadowMap * */ const void * RB_CapShadowMap(const void *data) { const capShadowmapCommand_t *cmd = data; if(cmd->map != -1){ GL_SelectTexture(0); if(cmd->cubeSide != -1){ GL_BindCubemap(tr.shadowCubemaps[cmd->map]); qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - (backEnd.refdef.y + 256), 256, 256, 0); }else{ GL_Bind(tr.pshadowMaps[cmd->map]); qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - (backEnd.refdef.y + 256), 256, 256, 0); } } return (const void*)(cmd + 1); }
/** * @brief RB_RenderToTexture * @param[in] data * @return */ const void *RB_RenderToTexture(const void *data) { const renderToTextureCommand_t *cmd = ( const renderToTextureCommand_t * ) data; //ri.Printf( PRINT_ALL, "RB_RenderToTexture\n" ); GL_Bind(cmd->image); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cmd->x, cmd->y, cmd->w, cmd->h, 0); //qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cmd->x, cmd->y, cmd->w, cmd->h ); return ( const void * ) (cmd + 1); }
void R_ScreenGamma(void) { if (gammaProgram.program) { glUseProgramObjectARB(gammaProgram.program); qglActiveTextureARB(GL_TEXTURE0_ARB); qglClientActiveTextureARB(GL_TEXTURE0_ARB); GL_Bind(screenImage); // We will copy the current buffer into the screenImage qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glUniform1f(gammaProgram.gammaUniform, r_gamma->value); // Draw a simple quad, We could have done this in the GLSL code directly but that is version 130 upwards // and we want to be sure that R1 runs even with a toaster. glBegin(GL_QUADS); { glTexCoord2f(0.0, 0.0); glVertex3f(-1.0f, -1.0f, 0.0f); glTexCoord2f(1.0, 0.0); glVertex3f(1.0f, -1.0f, 0.0f); glTexCoord2f(1.0, 1.0); glVertex3f(1.0f, 1.0f, 0.0f); glTexCoord2f(0.0, 1.0); glVertex3f(-1.0f, 1.0f, 0.0f); } glEnd(); glUseProgramObjectARB(0); } }
//update tr.screenImage void RB_CaptureScreenImage(void) { int radX = 2048; int radY = 2048; int x = glConfig.vidWidth/2; int y = glConfig.vidHeight/2; int cX, cY; GL_Bind( tr.screenImage ); //using this method, we could pixel-filter the texture and all sorts of crazy stuff. //but, it is slow as hell. /* static byte *tmp = NULL; if (!tmp) { tmp = (byte *)Z_Malloc((sizeof(byte)*4)*(glConfig.vidWidth*glConfig.vidHeight), TAG_ICARUS, qtrue); } qglReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_UNSIGNED_BYTE, tmp); qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmp); */ if (radX > glConfig.maxTextureSize) { radX = glConfig.maxTextureSize; } if (radY > glConfig.maxTextureSize) { radY = glConfig.maxTextureSize; } while (glConfig.vidWidth < radX) { radX /= 2; } while (glConfig.vidHeight < radY) { radY /= 2; } cX = x-(radX/2); cY = y-(radY/2); if (cX+radX > glConfig.vidWidth) { //would it go off screen? cX = glConfig.vidWidth-radX; } else if (cX < 0) { //cap it off at 0 cX = 0; } if (cY+radY > glConfig.vidHeight) { //would it go off screen? cY = glConfig.vidHeight-radY; } else if (cY < 0) { //cap it off at 0 cY = 0; } #ifndef _XBOX qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, cX, cY, radX, radY, 0); #else qglCopyBackBufferToTexEXT(radX, radY, cX, (480 - cY), (cX + radX), (480 - (cY + radY))); #endif // _XBOX }
GLvoid APIENTRY GLDSA_CopyTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { GL_BindMultiTexture(glDsaState.texunit, target, texture); qglCopyTexImage2D(target, level, internalformat, x, y, width, height, border); }
/* ============= RB_DrawSurfs ============= */ const void *RB_DrawSurfs( const void *data ) { const drawSurfsCommand_t *cmd; // finish any 2D drawing if needed if ( tess.numIndexes ) { RB_EndSurface(); } cmd = (const drawSurfsCommand_t *)data; backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglEnable(GL_DEPTH_CLAMP); } if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW))) { FBO_t *oldFbo = glState.currentFBO; backEnd.depthFill = qtrue; qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); backEnd.depthFill = qfalse; if (tr.msaaResolveFbo) { // If we're using multisampling, resolve the depth first FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); } else if (tr.renderFbo == NULL) { // If we're rendering directly to the screen, copy the depth to a texture GL_BindToTMU(tr.renderDepthImage, 0); qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); } if (r_ssao->integer) { // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); } if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) { vec4_t quadVerts[4]; vec2_t texCoords[4]; vec4_t box; FBO_Bind(tr.screenShadowFbo); box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; qglViewport(box[0], box[1], box[2], box[3]); qglScissor(box[0], box[1], box[2], box[3]); box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; box[0] = -1.0f; box[1] = -1.0f; box[2] = 1.0f; box[3] = 1.0f; VectorSet4(quadVerts[0], box[0], box[3], 0, 1); VectorSet4(quadVerts[1], box[2], box[3], 0, 1); VectorSet4(quadVerts[2], box[2], box[1], 0, 1); VectorSet4(quadVerts[3], box[0], box[1], 0, 1); GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.shadowmaskShader); GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); if (r_shadowCascadeZFar->integer != 0) { GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]); } else { GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]); } GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); { vec4_t viewInfo; vec3_t viewVector; float zmax = backEnd.viewParms.zFar; float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); float zmin = r_znear->value; VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } if (r_ssao->integer) { vec4_t quadVerts[4]; vec2_t texCoords[4]; FBO_Bind(tr.quarterFbo[0]); qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); VectorSet4(quadVerts[0], -1, 1, 0, 1); VectorSet4(quadVerts[1], 1, 1, 0, 1); VectorSet4(quadVerts[2], 1, -1, 0, 1); VectorSet4(quadVerts[3], -1, -1, 0, 1); texCoords[0][0] = 0; texCoords[0][1] = 1; texCoords[1][0] = 1; texCoords[1][1] = 1; texCoords[2][0] = 1; texCoords[2][1] = 0; texCoords[3][0] = 0; texCoords[3][1] = 0; GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.ssaoShader); GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.quarterFbo[1]); qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); GLSL_BindProgram(&tr.depthBlurShader[0]); GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.screenSsaoFbo); qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); GLSL_BindProgram(&tr.depthBlurShader[1]); GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } // reset viewport and scissor FBO_Bind(oldFbo); SetViewportAndScissor(); } if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglDisable(GL_DEPTH_CLAMP); } if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); if (r_drawSun->integer) { RB_DrawSun(0.1, tr.sunShader); } if (r_drawSunRays->integer) { FBO_t *oldFbo = glState.currentFBO; FBO_Bind(tr.sunRaysFbo); qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); qglClear( GL_COLOR_BUFFER_BIT ); if (glRefConfig.occlusionQuery) { tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); } RB_DrawSun(0.3, tr.sunFlareShader); if (glRefConfig.occlusionQuery) { qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(oldFbo); } // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); } if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { FBO_Bind(NULL); GL_SelectTexture(TB_CUBEMAP); GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); GL_SelectTexture(0); } return (const void *)(cmd + 1); }
void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; unsigned int oldSort; float originalTime; trRefEntity_t *curEnt; postRender_t *pRender; bool didShadowPass = false; #ifdef __MACOS__ int macEventTime; Sys_PumpEvents(); // crutch up the mac's limited buffer queue size // we don't want to pump the event loop too often and waste time, so // we are going to check every shader change macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC; #endif if (g_bRenderGlowingObjects) { //only shadow on initial passes didShadowPass = true; } // 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; oldDlighted = qfalse; oldSort = (unsigned int) -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; } R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // If we're rendering glowing objects, but this shader has no stages with glow, skip it! if ( g_bRenderGlowingObjects && !shader->hasGlow ) { shader = oldShader; entityNum = oldEntityNum; fogNum = oldFogNum; dlighted = oldDlighted; continue; } oldSort = drawSurf->sort; // // 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 (entityNum != TR_WORLDENT && g_numPostRenders < MAX_POST_RENDERS) { if ( (backEnd.refdef.entities[entityNum].e.renderfx & RF_DISTORTION)/* || (backEnd.refdef.entities[entityNum].e.renderfx & RF_FORCE_ENT_ALPHA)*/) //not sure if we need this alpha fix for sp or not, leaving it out for now -rww { //must render last curEnt = &backEnd.refdef.entities[entityNum]; pRender = &g_postRenders[g_numPostRenders]; g_numPostRenders++; depthRange = 0; //figure this stuff out now and store it if ( curEnt->e.renderfx & RF_NODEPTH ) { depthRange = 2; } else if ( curEnt->e.renderfx & RF_DEPTHHACK ) { depthRange = 1; } pRender->depthRange = depthRange; //It is not necessary to update the old* values because //we are not updating now with the current values. depthRange = oldDepthRange; //store off the ent num pRender->entNum = entityNum; //remember the other values necessary for rendering this surf pRender->drawSurf = drawSurf; pRender->dlighted = dlighted; pRender->fogNum = fogNum; pRender->shader = shader; //assure the info is back to the last set state shader = oldShader; entityNum = oldEntityNum; fogNum = oldFogNum; dlighted = oldDlighted; oldSort = (unsigned int)-1; //invalidate this thing, cause we may want to postrender more surfs of the same sort //continue without bothering to begin a draw surf continue; } } if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { #ifdef __MACOS__ // crutch up the mac's limited buffer queue size int t; t = ri.Milliseconds(); if ( t > macEventTime ) { macEventTime = t + MAC_EVENT_PUMP_MSEC; Sys_PumpEvents(); } #endif RB_EndSurface(); if (!didShadowPass && shader && shader->sort > SS_BANNER) { RB_ShadowFinish(); didShadowPass = true; } } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = qfalse; if ( entityNum != TR_WORLDENT ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } if ( backEnd.currentEntity->e.renderfx & RF_NODEPTH ) { // No depth at all, very rare but some things for seeing through walls depthRange = 2; } else if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.ori = backEnd.viewParms.world; #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } qglLoadMatrixf( backEnd.ori.modelMatrix ); // // change depthrange if needed // if ( oldDepthRange != depthRange ) { switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } oldDepthRange = depthRange; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } if (tr_stencilled && tr_distortionPrePost) { //ok, cap it now RB_CaptureScreenImage(); RB_DistortionFill(); } //render distortion surfs (or anything else that needs to be post-rendered) if (g_numPostRenders > 0) { int lastPostEnt = -1; while (g_numPostRenders > 0) { g_numPostRenders--; pRender = &g_postRenders[g_numPostRenders]; RB_BeginSurface( pRender->shader, pRender->fogNum ); backEnd.currentEntity = &backEnd.refdef.entities[pRender->entNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } qglLoadMatrixf( backEnd.ori.modelMatrix ); depthRange = pRender->depthRange; switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } if ((backEnd.currentEntity->e.renderfx & RF_DISTORTION) && lastPostEnt != pRender->entNum) { //do the capture now, we only need to do it once per ent int x, y; int rad = backEnd.currentEntity->e.radius; //We are going to just bind this, and then the CopyTexImage is going to //stomp over this texture num in texture memory. GL_Bind( tr.screenImage ); if (R_WorldCoordToScreenCoord( backEnd.currentEntity->e.origin, &x, &y )) { int cX, cY; cX = glConfig.vidWidth-x-(rad/2); cY = glConfig.vidHeight-y-(rad/2); if (cX+rad > glConfig.vidWidth) { //would it go off screen? cX = glConfig.vidWidth-rad; } else if (cX < 0) { //cap it off at 0 cX = 0; } if (cY+rad > glConfig.vidHeight) { //would it go off screen? cY = glConfig.vidHeight-rad; } else if (cY < 0) { //cap it off at 0 cY = 0; } //now copy a portion of the screen to this texture qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, cX, cY, rad, rad, 0); lastPostEnt = pRender->entNum; } } rb_surfaceTable[ *pRender->drawSurf->surface ]( pRender->drawSurf->surface ); RB_EndSurface(); } } // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif if (tr_stencilled && !tr_distortionPrePost) { //draw in the stencil buffer's cutout RB_DistortionFill(); } if (!didShadowPass) { // darken down any stencil shadows RB_ShadowFinish(); didShadowPass = true; } // add light flares on lights that aren't obscured // RB_RenderFlares(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }