/* ================== 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; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; int oldNumVerts, oldNumIndex; //GR - tessellation flag int atiTess = 0, oldAtiTess; #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 // 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 = -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 != oldShader || fogNum != oldFogNum || dlighted != oldDlighted // GR - force draw on tessellation flag change || ( atiTess != oldAtiTess ) || ( 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 // 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 = qfalse; 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 ); } 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.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 if needed // if ( oldDepthRange != depthRange ) { if ( depthRange ) { qglDepthRange( 0, 0.3 ); } else { qglDepthRange( 0, 1 ); } oldDepthRange = depthRange; } 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 ); } // (SA) draw sun RB_DrawSun(); // darken down any stencil shadows RB_ShadowFinish(); // 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 }
/* ================== 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; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; #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 // 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 = -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) { #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(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } #ifdef _NPATCH // See if we can n-patch surface if ( drawSurf->sort & ( 1 << QSORT_NPATCH_SHIFT ) ) { tess.npatched = qtrue; } #endif // _NPATCH // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = qfalse; if ( entityNum != ENTITYNUM_WORLD ) { 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.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; } } else { 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.or.modelMatrix ); // // change depthrange if needed // if ( oldDepthRange != depthRange ) { if ( depthRange ) { qglDepthRange (0, 0.3); } else { qglDepthRange (0, 1); } 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(); } // 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(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }
/* ** SurfIsOffscreen ** ** Determines if a surface is completely offscreen. */ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) { float shortest = 100000000; int entityNum; int numTriangles; shader_t *shader; int fogNum; int dlighted; vec4_t clip, eye; int i; unsigned int pointOr = 0; unsigned int pointAnd = (unsigned int)~0; if ( glConfig.smpActive ) { // FIXME! we can't do RB_BeginSurface/RB_EndSurface stuff with smp! return qfalse; } R_RotateForViewer(); R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); RB_BeginSurface( shader, fogNum ); rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); assert( tess.numVertexes < 128 ); for ( i = 0; i < tess.numVertexes; i++ ) { int j; unsigned int pointFlags = 0; R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); for ( j = 0; j < 3; j++ ) { if ( clip[j] >= clip[3] ) { pointFlags |= (1 << (j*2)); } else if ( clip[j] <= -clip[3] ) { pointFlags |= ( 1 << (j*2+1)); } } pointAnd &= pointFlags; pointOr |= pointFlags; } // trivially reject if ( pointAnd ) { return qtrue; } // determine if this surface is backfaced and also determine the distance // to the nearest vertex so we can cull based on portal range. Culling // based on vertex distance isn't 100% correct (we should be checking for // range to the surface), but it's good enough for the types of portals // we have in the game right now. numTriangles = tess.numIndexes / 3; for ( i = 0; i < tess.numIndexes; i += 3 ) { vec3_t normal; float dot; float len; VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); len = VectorLengthSquared( normal ); // lose the sqrt if ( len < shortest ) { shortest = len; } if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 ) { numTriangles--; } } if ( !numTriangles ) { return qtrue; } // mirrors can early out at this point, since we don't do a fade over distance // with them (although we could) if ( IsMirror( drawSurf, entityNum ) ) { return qfalse; } if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) ) { return qtrue; } return qfalse; }
/* * 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; // 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(); }
void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t /**shader,*/ *oldShader; int /*fogNum,*/ oldFogNum; int entityNum, oldEntityNum; int /*dlighted,*/ oldDlighted; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; int oldSort; // float originalTime; /*MODVIEWREM // 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; //MODVIEWREM backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; //MODVIEWREM backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { /*MODVIEWREM if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; */ GLuint gluiTextureBind = 0; R_DecomposeSort( drawSurf->sort, &entityNum, &gluiTextureBind);//MODVIEWREM , &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 = qfalse; if ( entityNum != ENTITYNUM_WORLD ) { 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.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; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } */ //////////////////////////////////////glLoadMatrixf( backEnd.or.modelMatrix ); /* // // change depthrange if needed // if ( oldDepthRange != depthRange ) { if ( depthRange ) { qglDepthRange (0, 0.3); } else { qglDepthRange (0, 1); } oldDepthRange = depthRange; } oldEntityNum = entityNum; } */ RB_BeginSurface( 0,0, gluiTextureBind);//shader, fogNum ); tess.hModel = tr.refdef.entities[entityNum].e.hModel; tess.pRefEnt=&tr.refdef.entities[entityNum].e; // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); RB_EndSurface(); // stats... // if (!tess.bSurfaceIsG2Tag || AppVars.bShowTagSurfaces) { *tr.refdef.entities[entityNum].e.piRenderedTris += giSurfaceTrisDrawn; *tr.refdef.entities[entityNum].e.piRenderedVerts+= giSurfaceVertsDrawn; *tr.refdef.entities[entityNum].e.piRenderedSurfs+= 1; // NOT ++! *tr.refdef.entities[entityNum].e.piRenderedBoneWeights += giRenderedBoneWeights; *tr.refdef.entities[entityNum].e.piOmittedBoneWeights += giOmittedBoneWeights; } } /*MODVIEWREM // 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); } */ }
/* ================== 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); }
/** * @brief RB_RenderDrawSurfList * @param[in] drawSurfs * @param[in] numDrawSurfs */ void RB_RenderDrawSurfList(drawSurf_t *drawSurfs, int numDrawSurfs) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int frontFace; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; int oldSort; double originalTime = backEnd.refdef.floatTime; // save original time for entity shader offsets // 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 = -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, &frontFace, &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 && (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 = qfalse; if (entityNum != ENTITYNUM_WORLD) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; // FIXME: e.shaderTime must be passed as int to avoid fp-precision loss issues backEnd.refdef.floatTime = originalTime; // - backEnd.currentEntity->e.shaderTime; // JPW NERVE pulled this to match q3ta // 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.orientation); // set up the dynamic lighting if needed if (backEnd.currentEntity->needDlights) { R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation); } 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.orientation = 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.orientation); } qglLoadMatrixf(backEnd.orientation.modelMatrix); // change depthrange if needed if (oldDepthRange != depthRange) { if (depthRange) { qglDepthRange(0, 0.3); } else { qglDepthRange(0, 1); } 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(); } // go back to the world modelview matrix backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.orientation = backEnd.viewParms.world; R_TransformDlights(backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.orientation); qglLoadMatrixf(backEnd.viewParms.world.modelMatrix); if (depthRange) { qglDepthRange(0, 1); } // draw sun RB_DrawSun(); // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }
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 }
/* ================== 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(); }