/* ** RB_DrawSun */ void RB_DrawSun( float scale, shader_t *shader ) { float size; float dist; vec3_t origin, vec1, vec2; byte sunColor[4] = { 255, 255, 255, 255 }; if ( !backEnd.skyRenderedThisView ) { return; } qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * scale; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range qglDepthRange( 1.0, 1.0 ); RB_BeginSurface( shader, 0 ); RB_AddQuadStamp(origin, vec1, vec2, sunColor); RB_EndSurface(); // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
/* ============= RB_StretchPic ============= */ static void RB_StretchPic ( const void *data ) { const stretchPicCommand_t *cmd; shader_t *shader; int *indexes; vec2_t *texCoords; vecSimd_t *xyz; color4ub_t *colors; cmd = (const stretchPicCommand_t *)data; if ( !backEnd.projection2D ) { RB_SetGL2D(); } shader = cmd->shader; if ( shader != tess.shader ) { RB_EndSurface(); RB_BeginSurface( shader, 0 ); } RB_CheckOverflow( 4, 6 ); indexes = tess.indexes + tess.numIndexes; indexes[0] = tess.numVertexes + 3; indexes[1] = tess.numVertexes + 0; indexes[2] = tess.numVertexes + 2; indexes[3] = tess.numVertexes + 2; indexes[4] = tess.numVertexes + 0; indexes[5] = tess.numVertexes + 1; colors = tess.colors + tess.numVertexes; Byte4Copy( backEnd.color2D, colors[0] ); Byte4Copy( backEnd.color2D, colors[1] ); Byte4Copy( backEnd.color2D, colors[2] ); Byte4Copy( backEnd.color2D, colors[3] ); xyz = tess.xyz + tess.numVertexes; VectorSet( xyz[0], cmd->x, cmd->y, 0 ); VectorSet( xyz[1], cmd->x + cmd->w, cmd->y, 0 ); VectorSet( xyz[2], cmd->x + cmd->w, cmd->y + cmd->h, 0 ); VectorSet( xyz[3], cmd->x, cmd->y + cmd->h, 0 ); texCoords = tess.texCoords + tess.numVertexes; texCoords[0][0] = cmd->s1; texCoords[0][1] = cmd->t1; texCoords[1][0] = cmd->s2; texCoords[1][1] = cmd->t1; texCoords[2][0] = cmd->s2; texCoords[2][1] = cmd->t2; texCoords[3][0] = cmd->s1; texCoords[3][1] = cmd->t2; tess.numVertexes += 4; tess.numIndexes += 6; }
const void *RB_Draw2dPolys( const void *data ) { const poly2dCommand_t *cmd; shader_t *shader; int i; cmd = ( const poly2dCommand_t * ) data; if ( !backEnd.projection2D ) { RB_SetGL2D(); } shader = cmd->shader; if ( shader != tess.shader ) { if ( tess.numIndexes ) { RB_EndSurface(); } backEnd.currentEntity = &backEnd.entity2D; RB_BeginSurface( shader, 0 ); } RB_CHECKOVERFLOW( cmd->numverts, ( cmd->numverts - 2 ) * 3 ); for ( i = 0; i < cmd->numverts - 2; i++ ) { tess.indexes[ tess.numIndexes + 0 ] = tess.numVertexes; tess.indexes[ tess.numIndexes + 1 ] = tess.numVertexes + i + 1; tess.indexes[ tess.numIndexes + 2 ] = tess.numVertexes + i + 2; tess.numIndexes += 3; } for ( i = 0; i < cmd->numverts; i++ ) { tess.xyz[ tess.numVertexes ].v[ 0 ] = cmd->verts[ i ].xyz[ 0 ]; tess.xyz[ tess.numVertexes ].v[ 1 ] = cmd->verts[ i ].xyz[ 1 ]; tess.xyz[ tess.numVertexes ].v[ 2 ] = 0; tess.texCoords0[ tess.numVertexes ].v[ 0 ] = cmd->verts[ i ].st[ 0 ]; tess.texCoords0[ tess.numVertexes ].v[ 1 ] = cmd->verts[ i ].st[ 1 ]; tess.vertexColors[ tess.numVertexes ].v[ 0 ] = cmd->verts[ i ].modulate[ 0 ]; tess.vertexColors[ tess.numVertexes ].v[ 1 ] = cmd->verts[ i ].modulate[ 1 ]; tess.vertexColors[ tess.numVertexes ].v[ 2 ] = cmd->verts[ i ].modulate[ 2 ]; tess.vertexColors[ tess.numVertexes ].v[ 3 ] = cmd->verts[ i ].modulate[ 3 ]; tess.numVertexes++; } return ( const void * )( cmd + 1 ); }
void RB_CheckVao(vao_t *vao) { if (vao != glState.currentVao) { RB_EndSurface(); RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); R_BindVao(vao); } if (vao != tess.vao) tess.useInternalVao = qfalse; }
void RB_CheckVao(vao_t *vao) { if (vao != glState.currentVao || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES) { RB_EndSurface(); RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); R_BindVao(vao); } if (vao != tess.vao) tess.useInternalVao = qfalse; }
/* ============== RB_CheckOverflow ============== */ void RB_CheckOverflow( int verts, int indexes ) { if (tess.numVertexes + verts < SHADER_MAX_VERTEXES && tess.numIndexes + indexes < SHADER_MAX_INDEXES) { return; } RB_EndSurface(); if ( verts >= SHADER_MAX_VERTEXES ) { ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, SHADER_MAX_VERTEXES ); } if ( indexes >= SHADER_MAX_INDEXES ) { ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES ); } RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex ); }
void RB_CheckOverflow( int verts, int indexes ) { if (tess.numVertexes + verts < ACTUAL_SHADER_MAX_VERTEXES && tess.numIndexes + indexes < ACTUAL_SHADER_MAX_INDEXES) { return; } RB_EndSurface(); if ( verts >= ACTUAL_SHADER_MAX_VERTEXES ) { ri.Error(ERR_DROP, "RB_CheckOverflow: verts > MAX (%d > %d)", verts, ACTUAL_SHADER_MAX_VERTEXES ); } if ( indexes >= ACTUAL_SHADER_MAX_INDEXES ) { ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, ACTUAL_SHADER_MAX_INDEXES ); } RB_BeginSurface(NULL/*MODVIEWREM tess.shader*/, 0/*MODVIEWREM tess.fogNum*/, tess.gluiTextureBind ); }
static qboolean RB_SurfaceVaoCached(int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits) { qboolean recycleVertexBuffer = qfalse; qboolean recycleIndexBuffer = qfalse; qboolean endSurface = qfalse; if (!(!ShaderRequiresCPUDeforms(tess.shader) && !tess.shader->isSky && !tess.shader->isPortal)) return qfalse; if (!numIndexes || !numVerts) return qfalse; VaoCache_BindVao(); tess.dlightBits |= dlightBits; tess.pshadowBits |= pshadowBits; VaoCache_CheckAdd(&endSurface, &recycleVertexBuffer, &recycleIndexBuffer, numVerts, numIndexes); if (endSurface) { RB_EndSurface(); RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); } if (recycleVertexBuffer) VaoCache_RecycleVertexBuffer(); if (recycleIndexBuffer) VaoCache_RecycleIndexBuffer(); if (!tess.numVertexes) VaoCache_InitQueue(); VaoCache_AddSurface(verts, numVerts, indexes, numIndexes); tess.numIndexes += numIndexes; tess.numVertexes += numVerts; tess.useInternalVao = qfalse; tess.useCacheVao = qtrue; return qtrue; }
/* ** RB_DrawSun */ void RB_DrawSun( float scale, shader_t *shader ) { float size; float dist; vec3_t origin, vec1, vec2; if ( !backEnd.skyRenderedThisView ) { return; } //qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); { // FIXME: this could be a lot cleaner mat4_t translation, modelview; Mat4Translation( backEnd.viewParms.or.origin, translation ); Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview ); GL_SetModelviewMatrix( modelview ); } dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * scale; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range qglDepthRange( 1.0, 1.0 ); RB_BeginSurface( shader, 0, 0 ); RB_AddQuadStamp(origin, vec1, vec2, colorWhite); RB_EndSurface(); // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
const void *RB_WorldEffects( const void *data ) { const setModeCommand_t *cmd; cmd = (const setModeCommand_t *)data; // Always flush the tess buffer if ( tess.shader && tess.numIndexes ) { RB_EndSurface(); } RB_RenderWorldEffects(); if(tess.shader) { RB_BeginSurface( tess.shader, tess.fogNum ); } return (const void *)(cmd + 1); }
/* ================== RB_RenderFlare ================== */ void RB_RenderFlare( flare_t *f ) { float size; vec3_t color; int iColor[3]; backEnd.pc.c_flareRenders++; VectorScale( f->color, f->drawIntensity*tr.identityLight, color ); iColor[0] = color[0] * 255; iColor[1] = color[1] * 255; iColor[2] = color[2] * 255; size = f->lightScale * backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0 + 8 / -f->eyeZ ); RB_BeginSurface( tr.flareShader, f->fogNum ); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); }
/* ================== 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, 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; 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_RotatedPic ============= */ const void *RB_RotatedPic( const void *data ) { const stretchPicCommand_t *cmd; shader_t *shader; int numVerts, numIndexes; float mx, my, cosA, sinA, cw, ch, sw, sh; cmd = ( const stretchPicCommand_t * ) data; if ( !backEnd.projection2D ) { RB_SetGL2D(); } shader = cmd->shader; if ( shader != tess.shader ) { if ( tess.numIndexes ) { RB_EndSurface(); } backEnd.currentEntity = &backEnd.entity2D; RB_BeginSurface( shader, 0 ); } RB_CHECKOVERFLOW( 4, 6 ); numVerts = tess.numVertexes; numIndexes = tess.numIndexes; tess.numVertexes += 4; tess.numIndexes += 6; tess.indexes[ numIndexes ] = numVerts + 3; tess.indexes[ numIndexes + 1 ] = numVerts + 0; tess.indexes[ numIndexes + 2 ] = numVerts + 2; tess.indexes[ numIndexes + 3 ] = numVerts + 2; tess.indexes[ numIndexes + 4 ] = numVerts + 0; tess.indexes[ numIndexes + 5 ] = numVerts + 1; * ( int * ) tess.vertexColors[ numVerts ].v = * ( int * ) tess.vertexColors[ numVerts + 1 ].v = * ( int * ) tess.vertexColors[ numVerts + 2 ].v = * ( int * ) tess.vertexColors[ numVerts + 3 ].v = * ( int * ) backEnd.color2D; mx = cmd->x + ( cmd->w / 2 ); my = cmd->y + ( cmd->h / 2 ); cosA = cos( DEG2RAD( cmd->angle ) ); sinA = sin( DEG2RAD( cmd->angle ) ); cw = cosA * ( cmd->w / 2 ); ch = cosA * ( cmd->h / 2 ); sw = sinA * ( cmd->w / 2 ); sh = sinA * ( cmd->h / 2 ); tess.xyz[ numVerts ].v[ 0 ] = mx - cw - sh; tess.xyz[ numVerts ].v[ 1 ] = my + sw - ch; tess.xyz[ numVerts ].v[ 2 ] = 0; tess.texCoords0[ numVerts ].v[ 0 ] = cmd->s1; tess.texCoords0[ numVerts ].v[ 1 ] = cmd->t1; tess.xyz[ numVerts + 1 ].v[ 0 ] = mx + cw - sh; tess.xyz[ numVerts + 1 ].v[ 1 ] = my - sw - ch; tess.xyz[ numVerts + 1 ].v[ 2 ] = 0; tess.texCoords0[ numVerts + 1 ].v[ 0 ] = cmd->s2; tess.texCoords0[ numVerts + 1 ].v[ 1 ] = cmd->t1; tess.xyz[ numVerts + 2 ].v[ 0 ] = mx + cw + sh; tess.xyz[ numVerts + 2 ].v[ 1 ] = my - sw + ch; tess.xyz[ numVerts + 2 ].v[ 2 ] = 0; tess.texCoords0[ numVerts + 2 ].v[ 0 ] = cmd->s2; tess.texCoords0[ numVerts + 2 ].v[ 1 ] = cmd->t2; tess.xyz[ numVerts + 3 ].v[ 0 ] = mx - cw + sh; tess.xyz[ numVerts + 3 ].v[ 1 ] = my + sw + ch; tess.xyz[ numVerts + 3 ].v[ 2 ] = 0; tess.texCoords0[ numVerts + 3 ].v[ 0 ] = cmd->s1; tess.texCoords0[ numVerts + 3 ].v[ 1 ] = cmd->t2; return ( const void * )( cmd + 1 ); }
/* ================== RB_RenderFlare ================== */ void RB_RenderFlare( flare_t *f ) { float size; vec3_t color; int iColor[3]; float distance, intensity, factor; byte fogFactors[3] = {255, 255, 255}; backEnd.pc.c_flareRenders++; // We don't want too big values anyways when dividing by distance. if(f->eyeZ > -1.0f) distance = 1.0f; else distance = -f->eyeZ; // calculate the flare size.. size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance ); /* * This is an alternative to intensity scaling. It changes the size of the flare on screen instead * with growing distance. See in the description at the top why this is not the way to go. // size will change ~ 1/r. size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f)); */ /* * As flare sizes stay nearly constant with increasing distance we must decrease the intensity * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be * got by considering the ratio of * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) * An important requirement is: * intensity <= 1 for all distances. * * The formula used here to compute the intensity is as follows: * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 * As you can see, the intensity will have a max. of 1 when the distance is 0. * The coefficient flareCoeff will determine the falloff speed with increasing distance. */ factor = distance + size * sqrt(flareCoeff); intensity = flareCoeff * size * size / (factor * factor); VectorScale(f->color, f->drawIntensity * intensity, color); // Calculations for fogging if(tr.world && f->fogNum < tr.world->numfogs) { tess.numVertexes = 1; VectorCopy(f->origin, tess.xyz[0]); tess.fogNum = f->fogNum; RB_CalcModulateColorsByFog(fogFactors); // We don't need to render the flare if colors are 0 anyways. if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) return; } iColor[0] = color[0] * fogFactors[0]; iColor[1] = color[1] * fogFactors[1]; iColor[2] = color[2] * fogFactors[2]; RB_BeginSurface( tr.flareShader, f->fogNum ); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); }
/** * @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(); }
/* ** RB_DrawSun */ void RB_DrawSun( void ) { float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { return; } qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * 0.4; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range qglDepthRange( 1.0, 1.0 ); // FIXME: use quad stamp RB_BeginSurface( tr.sunShader, tess.fogNum ); VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
/* ============= RB_StretchPic ============= */ const void *RB_StretchPic ( const void *data ) { const stretchPicCommand_t *cmd; shader_t *shader; int numVerts, numIndexes; cmd = (const stretchPicCommand_t *)data; if ( !backEnd.projection2D ) { RB_SetGL2D(); } shader = cmd->shader; if ( shader != tess.shader ) { if ( tess.numIndexes ) { RB_EndSurface(); } backEnd.currentEntity = &backEnd.entity2D; RB_BeginSurface( shader, 0 ); } RB_CHECKOVERFLOW( 4, 6 ); numVerts = tess.numVertexes; numIndexes = tess.numIndexes; tess.numVertexes += 4; tess.numIndexes += 6; tess.indexes[ numIndexes ] = numVerts + 3; tess.indexes[ numIndexes + 1 ] = numVerts + 0; tess.indexes[ numIndexes + 2 ] = numVerts + 2; tess.indexes[ numIndexes + 3 ] = numVerts + 2; tess.indexes[ numIndexes + 4 ] = numVerts + 0; tess.indexes[ numIndexes + 5 ] = numVerts + 1; *(int *)tess.vertexColors[ numVerts ] = *(int *)tess.vertexColors[ numVerts + 1 ] = *(int *)tess.vertexColors[ numVerts + 2 ] = *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D; tess.xyz[ numVerts ][0] = cmd->x; tess.xyz[ numVerts ][1] = cmd->y; tess.xyz[ numVerts ][2] = 0; tess.texCoords[ numVerts ][0][0] = cmd->s1; tess.texCoords[ numVerts ][0][1] = cmd->t1; tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; tess.xyz[ numVerts + 1 ][1] = cmd->y; tess.xyz[ numVerts + 1 ][2] = 0; tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; tess.xyz[ numVerts + 2 ][2] = 0; tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; tess.xyz[ numVerts + 3 ][0] = cmd->x; tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; tess.xyz[ numVerts + 3 ][2] = 0; tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; return (const void *)(cmd + 1); }
/* ** 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; 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.ori.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.ori.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 ) { 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); }
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; 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; } // // 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; } // 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(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }
/* ** RB_DrawSun */ void RB_DrawSun( void ) { float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; float cachedModelView[16]; float newModelView[16]; if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { return; } GFX_GetModelViewMatrix( cachedModelView ); memcpy( newModelView, backEnd.viewParms.world.modelMatrix, sizeof(float) * 16 ); newModelView[12] += backEnd.viewParms.or.origin[0]; newModelView[13] += backEnd.viewParms.or.origin[1]; newModelView[14] += backEnd.viewParms.or.origin[2]; GFX_SetModelViewMatrix( newModelView ); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * 0.4; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range GFX_SetDepthRange( 1.0, 1.0 ); // FIXME: use quad stamp RB_BeginSurface( tr.sunShader, tess.fogNum ); VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); // back to normal depth range GFX_SetDepthRange( 0.0, 1.0 ); GFX_SetModelViewMatrix( cachedModelView ); }
/* ================== RB_RenderFlare ================== */ void RB_RenderFlare( flare_t *f ) { float size; vec3_t color; int iColor[3]; int iAlpha, srcBlend; float distance, intensity, factor; byte fogFactors[3] = {255, 255, 255}; backEnd.pc.c_flareRenders++; // We don't want too big values anyways when dividing by distance. if(f->eyeZ > -1.0f) distance = 1.0f; else distance = -f->eyeZ; // calculate the flare size.. size = backEnd.viewParms.viewportWidth * ( ( r_flareSize->value * f->scale )/640.0f + 8 / distance ); /* * This is an alternative to intensity scaling. It changes the size of the flare on screen instead * with growing distance. See in the description at the top why this is not the way to go. // size will change ~ 1/r. size = backEnd.viewParms.viewportWidth * ( ( r_flareSize->value * f->scale ) / (distance * -2.0f)); */ /* * As flare sizes stay nearly constant with increasing distance we must decrease the intensity * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be * got by considering the ratio of * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) * An important requirement is: * intensity <= 1 for all distances. * * The formula used here to compute the intensity is as follows: * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 * As you can see, the intensity will have a max. of 1 when the distance is 0. * The coefficient flareCoeff will determine the falloff speed with increasing distance. */ factor = distance + size * sqrt(flareCoeff); intensity = flareCoeff * size * size / (factor * factor); // Calculations for RGBA srcBlend = f->shader->stages[0] ? ( f->shader->stages[0]->stateBits & GLS_SRCBLEND_BITS ) : 0; if ( srcBlend == GLS_SRCBLEND_ONE ) { // Q3 flare, fade color. blendfunc GL_ONE GL_ONE VectorScale(f->color, f->drawIntensity * intensity, color); iAlpha = 65535; } else { // RTCW/ET flare, fade alpha. blendfunc GL_SRC_ALPHA GL_ONE // Note: RTCW source says it uses alpha blend/fade because overwise it doesn't blend in global fog and to switch back when it's fixed. VectorScale(f->color, intensity, color); iAlpha = f->drawIntensity * 255 * 257; } // Calculations for fogging if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs && !f->shader->noFog) { tess.numVertexes = 1; VectorCopy(f->origin, tess.xyz[0]); tess.fogNum = f->fogNum; RB_CalcModulateColorsByFog(fogFactors); // We don't need to render the flare if colors are 0 anyways. if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) return; } iColor[0] = color[0] * fogFactors[0] * 257; iColor[1] = color[1] * fogFactors[1] * 257; iColor[2] = color[2] * fogFactors[2] * 257; // fog calculation already done, use fogNum 0 RB_BeginSurface( f->shader, 0, 0 ); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); }
//QTZTODO: Support Centered Pic or vice versa? const void *RB_RotatedPic( const void *data ) { const stretchPicCommand_t *cmd; shader_t *shader; int numVerts, numIndexes; float angle; float pi2 = M_PI * 2; cmd = (const stretchPicCommand_t *)data; if ( !backEnd.projection2D ) RB_SetGL2D(); shader = cmd->shader; if ( shader != tess.shader ) { if ( tess.numIndexes ) RB_EndSurface(); backEnd.currentEntity = &backEnd.entity2D; RB_BeginSurface( shader, 0 ); } RB_CHECKOVERFLOW( 4, 6 ); numVerts = tess.numVertexes; numIndexes = tess.numIndexes; tess.numVertexes += 4; tess.numIndexes += 6; tess.indexes[ numIndexes ] = numVerts + 3; tess.indexes[ numIndexes + 1 ] = numVerts + 0; tess.indexes[ numIndexes + 2 ] = numVerts + 2; tess.indexes[ numIndexes + 3 ] = numVerts + 2; tess.indexes[ numIndexes + 4 ] = numVerts + 0; tess.indexes[ numIndexes + 5 ] = numVerts + 1; *(int *)tess.vertexColors[ numVerts ] = *(int *)tess.vertexColors[ numVerts + 1 ] = *(int *)tess.vertexColors[ numVerts + 2 ] = *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D; angle = cmd->angle * pi2; tess.xyz[ numVerts ].x = cmd->x + ( cosf( angle ) * cmd->w ); tess.xyz[ numVerts ].y = cmd->y + ( sinf( angle ) * cmd->h ); tess.xyz[ numVerts ].z = 0; tess.texCoords[ numVerts ][0].x = cmd->s1; tess.texCoords[ numVerts ][0].y = cmd->t1; angle = cmd->angle * pi2 + 0.25f * pi2; tess.xyz[ numVerts + 1 ].x = cmd->x + ( cosf( angle ) * cmd->w ); tess.xyz[ numVerts + 1 ].y = cmd->y + ( sinf( angle ) * cmd->h ); tess.xyz[ numVerts + 1 ].z = 0; tess.texCoords[ numVerts + 1 ][0].x = cmd->s2; tess.texCoords[ numVerts + 1 ][0].y = cmd->t1; angle = cmd->angle * pi2 + 0.50f * pi2; tess.xyz[ numVerts + 2 ].x = cmd->x + ( cosf( angle ) * cmd->w ); tess.xyz[ numVerts + 2 ].y = cmd->y + ( sinf( angle ) * cmd->h ); tess.xyz[ numVerts + 2 ].z = 0; tess.texCoords[ numVerts + 2 ][0].x = cmd->s2; tess.texCoords[ numVerts + 2 ][0].y = cmd->t2; angle = cmd->angle * pi2 + 0.75f * pi2; tess.xyz[ numVerts + 3 ].x = cmd->x + ( cosf( angle ) * cmd->w ); tess.xyz[ numVerts + 3 ].y = cmd->y + ( sinf( angle ) * cmd->h ); tess.xyz[ numVerts + 3 ].z = 0; tess.texCoords[ numVerts + 3 ][0].x = cmd->s1; tess.texCoords[ numVerts + 3 ][0].y = cmd->t2; return (const void *)( cmd + 1 ); }
/* ================== RB_RenderFlare ================== */ void RB_RenderFlare(flare_t *f) { float size; vec3_t color; int iColor[3]; backEnd.pc.c_flareRenders++; // changed to use alpha blend rather than additive blend // this is to accomidate the fact we can't right now do // additive blends and have them fog correctly with our distance fog. // /when/ we fix the blend problems with distance fog, this should // be changed back to additive since there's nearly no hit for that // but the alpha blend is noticably slower. VectorScale(f->color, tr.identityLight, color); // mod for alpha blend rather than additive iColor[0] = color[0] * 255; iColor[1] = color[1] * 255; iColor[2] = color[2] * 255; size = backEnd.viewParms.viewportWidth * ((r_flareSize->value * f->scale) / 640.0 + 8 / -f->eyeZ); RB_BeginSurface(tr.flareShader, f->fogNum); // FIXME: use quadstamp? tess.xyz[tess.numVertexes].v[0] = f->windowX - size; tess.xyz[tess.numVertexes].v[1] = f->windowY - size; tess.texCoords0[tess.numVertexes].v[0] = 0; tess.texCoords0[tess.numVertexes].v[1] = 0; tess.vertexColors[tess.numVertexes].v[0] = iColor[0]; tess.vertexColors[tess.numVertexes].v[1] = iColor[1]; tess.vertexColors[tess.numVertexes].v[2] = iColor[2]; tess.vertexColors[tess.numVertexes].v[3] = f->drawIntensity * 255; // mod for alpha blend rather than additive tess.numVertexes++; tess.xyz[tess.numVertexes].v[0] = f->windowX - size; tess.xyz[tess.numVertexes].v[1] = f->windowY + size; tess.texCoords0[tess.numVertexes].v[0] = 0; tess.texCoords0[tess.numVertexes].v[1] = 1; tess.vertexColors[tess.numVertexes].v[0] = iColor[0]; tess.vertexColors[tess.numVertexes].v[1] = iColor[1]; tess.vertexColors[tess.numVertexes].v[2] = iColor[2]; tess.vertexColors[tess.numVertexes].v[3] = f->drawIntensity * 255; // mod for alpha blend rather than additive tess.numVertexes++; tess.xyz[tess.numVertexes].v[0] = f->windowX + size; tess.xyz[tess.numVertexes].v[1] = f->windowY + size; tess.texCoords0[tess.numVertexes].v[0] = 1; tess.texCoords0[tess.numVertexes].v[1] = 1; tess.vertexColors[tess.numVertexes].v[0] = iColor[0]; tess.vertexColors[tess.numVertexes].v[1] = iColor[1]; tess.vertexColors[tess.numVertexes].v[2] = iColor[2]; tess.vertexColors[tess.numVertexes].v[3] = f->drawIntensity * 255; // mod for alpha blend rather than additive tess.numVertexes++; tess.xyz[tess.numVertexes].v[0] = f->windowX + size; tess.xyz[tess.numVertexes].v[1] = f->windowY - size; tess.texCoords0[tess.numVertexes].v[0] = 1; tess.texCoords0[tess.numVertexes].v[1] = 0; tess.vertexColors[tess.numVertexes].v[0] = iColor[0]; tess.vertexColors[tess.numVertexes].v[1] = iColor[1]; tess.vertexColors[tess.numVertexes].v[2] = iColor[2]; tess.vertexColors[tess.numVertexes].v[3] = f->drawIntensity * 255; // mod for alpha blend rather than additive //tess.vertexColors[tess.numVertexes].v[3] = 255; // mod for alpha blend rather than additive tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); }
/* * RB_StretchPic */ const void * RB_StretchPic(const void *data) { const stretchPicCommand_t *cmd; material_t *shader; int numVerts, numIndexes; cmd = (const stretchPicCommand_t*)data; /* FIXME: HUGE hack */ if(glRefConfig.framebufferObject && !glState.currentFBO){ if(backEnd.framePostProcessed){ FBO_Bind(tr.screenScratchFbo); }else{ FBO_Bind(tr.renderFbo); } } RB_SetGL2D(); shader = cmd->shader; if(shader != tess.shader){ if(tess.numIndexes){ RB_EndSurface(); } backEnd.currentEntity = &backEnd.entity2D; RB_BeginSurface(shader, 0); } RB_CHECKOVERFLOW(4, 6); numVerts = tess.numVertexes; numIndexes = tess.numIndexes; tess.numVertexes += 4; tess.numIndexes += 6; tess.indexes[ numIndexes ] = numVerts + 3; tess.indexes[ numIndexes + 1 ] = numVerts + 0; tess.indexes[ numIndexes + 2 ] = numVerts + 2; tess.indexes[ numIndexes + 3 ] = numVerts + 2; tess.indexes[ numIndexes + 4 ] = numVerts + 0; tess.indexes[ numIndexes + 5 ] = numVerts + 1; { Vec4 color; scalev34(backEnd.color2D, 1.0f / 255.0f, color); copyv34(color, tess.vertexColors[ numVerts ]); copyv34(color, tess.vertexColors[ numVerts + 1]); copyv34(color, tess.vertexColors[ numVerts + 2]); copyv34(color, tess.vertexColors[ numVerts + 3 ]); } tess.xyz[ numVerts ][0] = cmd->x; tess.xyz[ numVerts ][1] = cmd->y; tess.xyz[ numVerts ][2] = 0; tess.texCoords[ numVerts ][0][0] = cmd->s1; tess.texCoords[ numVerts ][0][1] = cmd->t1; tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; tess.xyz[ numVerts + 1 ][1] = cmd->y; tess.xyz[ numVerts + 1 ][2] = 0; tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; tess.xyz[ numVerts + 2 ][2] = 0; tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; tess.xyz[ numVerts + 3 ][0] = cmd->x; tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; tess.xyz[ numVerts + 3 ][2] = 0; tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; return (const void*)(cmd + 1); }
/* ** RB_DrawSun */ void RB_DrawSun( void ) { bfixed size; bfixed dist; bvec3_t origin; avec3_t vec1, vec2; bvec3_t bvec1, bvec2; bvec3_t temp; if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { return; } glLoadMatrixX( backEnd.viewParms.world.modelMatrix ); glTranslateX ( REINTERPRET_GFIXED(backEnd.viewParms._or.origin[0]), REINTERPRET_GFIXED(backEnd.viewParms._or.origin[1]), REINTERPRET_GFIXED(backEnd.viewParms._or.origin[2])); dist = backEnd.viewParms.zFar / BFIXED(1,75); // div sqrt(3) size = dist * BFIXED(0,4); FIXED_VEC3SCALE_R( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); FIXED_VEC3SCALE_R( vec1, size, bvec1 ); FIXED_VEC3SCALE_R( vec2, size, bvec2 ); // farthest depth range glDepthRangeX( GFIXED_1, GFIXED_1 ); // FIXME: use quad stamp RB_BeginSurface( tr.sunShader, tess.fogNum ); VectorCopy( origin, temp ); VectorSubtract( temp, bvec1, temp ); VectorSubtract( temp, bvec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = GFIXED_0; tess.texCoords[tess.numVertexes][0][1] = GFIXED_0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, bvec1, temp ); VectorSubtract( temp, bvec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = GFIXED_0; tess.texCoords[tess.numVertexes][0][1] = GFIXED_1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, bvec1, temp ); VectorAdd( temp, bvec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = GFIXED_1; tess.texCoords[tess.numVertexes][0][1] = GFIXED_1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, bvec1, temp ); VectorAdd( temp, bvec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = GFIXED_1; tess.texCoords[tess.numVertexes][0][1] = GFIXED_0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); // back to normal depth range glDepthRangeX( GFIXED_0, GFIXED_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); }