/* ================ RB_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void RB_StageIteratorSky( void ) { int clearBits = 0; if ( r_fastsky->integer ) { if (r_fastsky->integer == 2 && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used if (*r_fastSkyColor->string) { int v, tr, tg, tb; v = r_fastSkyColor->integer; tr = (v & 0xff0000) / 0x010000; tg = (v & 0x00ff00) / 0x000100; tb = (v & 0x0000ff) / 0x000001; qglClearColor((float)tr / 255.0, (float)tg / 255.0, (float)tb / 255.0, 1.0); } else { qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); // FIXME: get color of sky } qglClear(clearBits); } return; } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn RB_ClipSkyPolygons( &tess ); // r_showsky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showsky->integer ) { qglDepthRange( 0.0, 0.0 ); } else { qglDepthRange( 1.0, 1.0 ); } // draw the outer skybox if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglPushMatrix (); GL_State( 0 ); GL_Cull( CT_FRONT_SIDED ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); DrawSkyBox( tess.shader ); qglPopMatrix(); } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine R_BuildCloudData( &tess ); if (tess.numVertexes) { // yes, sky has cloud stages RB_StageIteratorGeneric(); } // draw the inner skybox //FIXME not even done // back to normal depth range qglDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; }
/* * RB_DepthRange */ void RB_DepthRange( float depthmin, float depthmax ) { gldepthmin = bound( 0, depthmin, 1 ); gldepthmax = bound( 0, depthmax, 1 ); qglDepthRange( gldepthmin, gldepthmax ); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int pshadowed, oldPshadowed; int cubemapIndex, oldCubemapIndex; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; FBO_t* fbo = NULL; qboolean inQuery = qfalse; float depth[2]; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; fbo = glState.currentFBO; // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldPshadowed = qfalse; oldCubemapIndex = -1; oldSort = -1; depth[0] = 0.f; depth[1] = 1.f; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) { if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) continue; // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); cubemapIndex = drawSurf->cubemapIndex; // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { if (oldShader != NULL) { RB_EndSurface(); } RB_BeginSurface( shader, fogNum, cubemapIndex ); backEnd.pc.c_surfBatches++; oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; oldPshadowed = pshadowed; oldCubemapIndex = cubemapIndex; } if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) continue; // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { qboolean sunflare = qfalse; depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } GL_SetModelviewMatrix( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, 0, qfalse); GL_SetProjectionMatrix( temp.projectionMatrix ); } } if(!oldDepthRange) { depth[0] = 0; depth[1] = 0.3f; qglDepthRange (depth[0], depth[1]); } } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); } if (!sunflare) qglDepthRange (0, 1); depth[0] = 0; depth[1] = 1; } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } if (inQuery) { qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } if (glRefConfig.framebufferObject) FBO_Bind(fbo); // go back to the world modelview matrix GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix ); qglDepthRange (0, 1); }
/* ** RB_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.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.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_DrawSun (SA) FIXME: sun should render behind clouds, so passing dark areas cover it up ============== */ void RB_DrawSun( float scale, shader_t *shader ) { float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; // vec4_t color; if ( !shader ) { return; } 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) // (SA) shrunk the size of the sun 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 ); // color[0] = color[1] = color[2] = color[3] = 1; RB_AddQuadStamp(origin, vec1, vec2, colorWhite); RB_EndSurface(); if ( r_drawSun->integer > 1 ) { // draw flare effect // (SA) FYI: This is cheezy and was only a test so far. // If we decide to use the flare business I will /definatly/ improve all this // get a point a little closer dist = dist * 0.7; VectorScale( tr.sunDirection, dist, origin ); // and make the flare a little smaller VectorScale( vec1, 0.5f, vec1 ); VectorScale( vec2, 0.5f, vec2 ); // add the vectors to give an 'off angle' result VectorAdd( tr.sunDirection, backEnd.viewParms.or.axis[0], temp ); VectorNormalize( temp ); // amplify the result origin[0] += temp[0] * 500.0; origin[1] += temp[1] * 500.0; origin[2] += temp[2] * 500.0; // (SA) FIXME: todo: flare effect should render last (on top of everything else) and only when sun is in view (sun moving out of camera past degree n should start to cause flare dimming until view angle to sun is off by angle n + x. // draw the flare RB_BeginSurface( tr.sunflareShader_old[0], 0, 0 ); RB_AddQuadStamp( origin, vec1, vec2, colorWhite ); RB_EndSurface(); } // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
/* ================== 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 R_DrawAliasModel (entity_t *ent, aliashdr_t *hdr, aliasstate_t *state, qbool showtris) { int v; trivertx_t *verts1, *verts2; float blend, iblend; qbool lerping; aliasmesh_t *mesh; trivertx_t *trivert1; trivertx_t *trivert2; float lerpnormal[3]; float alias_forward[3], alias_right[3], alias_up[3]; float r_plightvec[3], lightvec[3] = {-1, 0, 0}; r_aliasmesh_t *r_aliasmesh; float *r_aliasst; // hack the depth range to prevent view model from poking into walls if (ent->renderfx & RF_WEAPONMODEL) qglDepthRange (QGL_DEPTH_3D_BEGIN, QGL_DEPTH_VM_END); ent->angles[0] = -ent->angles[0]; // stupid quake bug AngleVectors (ent->angles, alias_forward, alias_right, alias_up); ent->angles[0] = -ent->angles[0]; // stupid quake bug // rotate the lighting vector into the model's frame of reference r_plightvec[0] = DotProduct (lightvec, alias_forward); r_plightvec[1] = -DotProduct (lightvec, alias_right); r_plightvec[2] = DotProduct (lightvec, alias_up); // go back to the world matrix GL_LoadMatrix (&ent->matrix, &r_world_matrix); if (state->origin[0] || state->origin[1] || state->origin[2]) GL_TranslateMatrix (&ent->matrix, state->origin[0], state->origin[1], state->origin[2]); if (state->angles[1]) GL_RotateMatrix (&ent->matrix, state->angles[1], 0, 0, 1); if (state->angles[0]) GL_RotateMatrix (&ent->matrix, -state->angles[0], 0, 1, 0); if (state->angles[2]) GL_RotateMatrix (&ent->matrix, state->angles[2], 1, 0, 0); GL_TranslateMatrix (&ent->matrix, hdr->scale_origin[0], hdr->scale_origin[1], hdr->scale_origin[2]); GL_ScaleMatrix (&ent->matrix, hdr->scale[0], hdr->scale[1], hdr->scale[2]); qglLoadMatrixf (ent->matrix.m16); r_aliasmesh = (r_aliasmesh_t *) r_meshbuffer; r_aliasst = (float *) (r_aliasmesh + hdr->numverts); mesh = (aliasmesh_t *) ((byte *) hdr + hdr->aliasmesh); if (state->pose1 != state->pose2) { lerping = true; verts1 = (trivertx_t *) ((byte *) hdr + hdr->vertexes + hdr->framevertexsize * state->pose1); verts2 = (trivertx_t *) ((byte *) hdr + hdr->vertexes + hdr->framevertexsize * state->pose2); blend = state->blend; iblend = 1.0f - blend; } else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled { lerping = false; verts1 = (trivertx_t *) ((byte *) hdr + hdr->vertexes + hdr->framevertexsize * state->pose1); verts2 = verts1; blend = iblend = 0; // avoid bogus compiler warning } GL_SetStreamSource (GLSTREAM_POSITION, 3, GL_FLOAT, sizeof (r_aliasmesh_t), r_aliasmesh->xyz); GL_SetStreamSource (GLSTREAM_COLOR, 4, GL_FLOAT, sizeof (r_aliasmesh_t), r_aliasmesh->rgba); if (showtris) { GL_SetStreamSource (GLSTREAM_TEXCOORD0, 0, GL_NONE, 0, NULL); GL_SetStreamSource (GLSTREAM_TEXCOORD1, 0, GL_NONE, 0, NULL); } else { GL_SetStreamSource (GLSTREAM_TEXCOORD0, 2, GL_FLOAT, 0, r_aliasst); if (state->fb) GL_SetStreamSource (GLSTREAM_TEXCOORD1, 2, GL_FLOAT, 0, r_aliasst); else GL_SetStreamSource (GLSTREAM_TEXCOORD1, 0, GL_NONE, 0, NULL); } GL_SetStreamSource (GLSTREAM_TEXCOORD2, 0, GL_NONE, 0, NULL); if (lerping) { for (v = 0; v < hdr->numverts; v++, r_aliasmesh++, mesh++) { trivert1 = &verts1[mesh->vertindex]; trivert2 = &verts2[mesh->vertindex]; // interpolate the normals lerpnormal[0] = r_avertexnormals[trivert1->lightnormalindex][0] * iblend + r_avertexnormals[trivert2->lightnormalindex][0] * blend; lerpnormal[1] = r_avertexnormals[trivert1->lightnormalindex][1] * iblend + r_avertexnormals[trivert2->lightnormalindex][1] * blend; lerpnormal[2] = r_avertexnormals[trivert1->lightnormalindex][2] * iblend + r_avertexnormals[trivert2->lightnormalindex][2] * blend; mesh->light = DotProduct (lerpnormal, r_plightvec) * -0.5f + 1.0f; r_aliasmesh->xyz[0] = trivert1->v[0] * iblend + trivert2->v[0] * blend; r_aliasmesh->xyz[1] = trivert1->v[1] * iblend + trivert2->v[1] * blend; r_aliasmesh->xyz[2] = trivert1->v[2] * iblend + trivert2->v[2] * blend; } } else { for (v = 0; v < hdr->numverts; v++, r_aliasmesh++, mesh++) { trivert1 = &verts1[mesh->vertindex]; mesh->light = DotProduct (r_avertexnormals[trivert1->lightnormalindex], r_plightvec) * -0.5f + 1.0f; r_aliasmesh->xyz[0] = trivert1->v[0]; r_aliasmesh->xyz[1] = trivert1->v[1]; r_aliasmesh->xyz[2] = trivert1->v[2]; } } // reset these for lighting r_aliasmesh = (r_aliasmesh_t *) r_meshbuffer; r_aliasst = (float *) (r_aliasmesh + hdr->numverts); mesh = (aliasmesh_t *) ((byte *) hdr + hdr->aliasmesh); if (showtris) { for (v = 0; v < hdr->numverts; v++, r_aliasmesh++, mesh++) { r_aliasmesh->rgba[0] = 1; r_aliasmesh->rgba[1] = 1; r_aliasmesh->rgba[2] = 1; r_aliasmesh->rgba[3] = 1; } } else { for (v = 0; v < hdr->numverts; v++, r_aliasmesh++, mesh++, r_aliasst += 2) { r_aliasst[0] = mesh->st[0]; r_aliasst[1] = mesh->st[1]; r_aliasmesh->rgba[0] = state->shadelight[0] * mesh->light; r_aliasmesh->rgba[1] = state->shadelight[1] * mesh->light; r_aliasmesh->rgba[2] = state->shadelight[2] * mesh->light; r_aliasmesh->rgba[3] = state->shadelight[3]; } } // for testing of light shading // glDisable (GL_TEXTURE_2D); GL_SetIndices (((byte *) hdr + hdr->indexes)); GL_DrawIndexedPrimitive (GL_TRIANGLES, hdr->numindexes, hdr->numverts); // glEnable (GL_TEXTURE_2D); // restore normal depth range if (ent->renderfx & RF_WEAPONMODEL) qglDepthRange (QGL_DEPTH_3D_BEGIN, QGL_DEPTH_3D_END); }
/* ================ RB_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void RB_StageIteratorSky( void ) { if ( r_fastsky->integer ) { return; } // when portal sky exists, only render skybox for the portal sky scene if ( skyboxportal && !( backEnd.refdef.rdflags & RDF_SKYBOXPORTAL ) ) { return; } // does the current fog require fastsky? if ( backEnd.viewParms.glFog.registered ) { if ( !backEnd.viewParms.glFog.drawsky ) { return; } } else if ( glfogNum > FOG_NONE ) { if ( !glfogsettings[FOG_CURRENT].drawsky ) { return; } } backEnd.refdef.rdflags |= RDF_DRAWINGSKY; // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn RB_ClipSkyPolygons( &tess ); // r_showsky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showsky->integer ) { qglDepthRange( 0.0, 0.0 ); } else { qglDepthRange( 1.0, 1.0 ); } // draw the outer skybox if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglPushMatrix(); GL_State( 0 ); qglTranslatef( backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2] ); DrawSkyBox( tess.shader ); qglPopMatrix(); } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine R_BuildCloudData( &tess ); RB_StageIteratorGeneric(); // draw the inner skybox // Rafael - drawing inner skybox if ( tess.shader->sky.innerbox[0] && tess.shader->sky.innerbox[0] != tr.defaultImage ) { qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglPushMatrix(); GL_State( 0 ); qglTranslatef( backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2] ); DrawSkyBoxInner( tess.shader ); qglPopMatrix(); } // Rafael - end // back to normal depth range qglDepthRange( 0.0, 1.0 ); backEnd.refdef.rdflags &= ~RDF_DRAWINGSKY; // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; }
/* ================== GL_SetDefaultState ================== */ void GL_SetDefaultState (){ int i; QGL_LogPrintf("---------- GL_SetDefaultState ----------\n"); // Reset the state manager glState.projectionMatrixIdentity = true; glState.modelviewMatrixIdentity = true; for (i = 0; i < MAX_TEXTURE_UNITS; i++) glState.textureMatrixIdentity[i] = true; for (i = 0; i < MAX_TEXTURE_UNITS; i++) glState.texture[i] = NULL; glState.program = NULL; glState.indexBuffer = NULL; glState.vertexBuffer = NULL; glState.viewportX = 0; glState.viewportY = 0; glState.viewportWidth = glConfig.videoWidth; glState.viewportHeight = glConfig.videoHeight; glState.scissorX = 0; glState.scissorY = 0; glState.scissorWidth = glConfig.videoWidth; glState.scissorHeight = glConfig.videoHeight; glState.depthBoundsMin = 0.0f; glState.depthBoundsMax = 1.0f; glState.texUnit = 0; for (i = 0; i < MAX_TEXTURE_UNITS; i++){ glState.texTarget[i] = 0; glState.texEnv[i] = GL_MODULATE; glState.texGen[i][0] = GL_OBJECT_LINEAR; glState.texGen[i][1] = GL_OBJECT_LINEAR; glState.texGen[i][2] = GL_OBJECT_LINEAR; glState.texGen[i][3] = GL_OBJECT_LINEAR; } glState.cullFace = false; glState.polygonOffsetFill = false; glState.polygonOffsetLine = false; glState.blend = false; glState.alphaTest = false; glState.depthTest = false; glState.stencilTest = false; for (i = 0; i < MAX_TEXTURE_UNITS; i++){ glState.textureGen[i][0] = false; glState.textureGen[i][1] = false; glState.textureGen[i][2] = false; glState.textureGen[i][3] = false; } glState.cullMode = GL_FRONT; glState.polygonMode = GL_FILL; glState.polygonOffsetFactor = 0.0f; glState.polygonOffsetUnits = 0.0f; glState.blendSrc = GL_ONE; glState.blendDst = GL_ZERO; glState.blendMode = GL_FUNC_ADD; glState.alphaFunc = GL_GREATER; glState.alphaFuncRef = 0.0f; glState.depthFunc = GL_LEQUAL; glState.stencilFunc[0] = GL_ALWAYS; glState.stencilFunc[1] = GL_ALWAYS; glState.stencilFuncRef[0] = 0; glState.stencilFuncRef[1] = 0; glState.stencilFuncMask[0] = 255; glState.stencilFuncMask[1] = 255; glState.stencilOpFail[0] = GL_KEEP; glState.stencilOpFail[1] = GL_KEEP; glState.stencilOpZFail[0] = GL_KEEP; glState.stencilOpZFail[1] = GL_KEEP; glState.stencilOpZPass[0] = GL_KEEP; glState.stencilOpZPass[1] = GL_KEEP; glState.depthMin = 0.0f; glState.depthMax = 1.0f; glState.colorMask[0] = GL_TRUE; glState.colorMask[1] = GL_TRUE; glState.colorMask[2] = GL_TRUE; glState.colorMask[3] = GL_TRUE; glState.depthMask = GL_TRUE; glState.stencilMask[0] = 255; glState.stencilMask[1] = 255; // Set default state qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); for (i = MAX_TEXTURE_UNITS - 1; i >= 0; i--){ if (i >= glConfig.maxTextureImageUnits) continue; if (i >= glConfig.maxTextureUnits){ qglActiveTexture(GL_TEXTURE0 + i); qglBindTexture(GL_TEXTURE_2D, 0); qglBindTexture(GL_TEXTURE_3D, 0); qglBindTexture(GL_TEXTURE_CUBE_MAP, 0); qglBindTexture(GL_TEXTURE_2D_ARRAY, 0); continue; } qglActiveTexture(GL_TEXTURE0 + i); qglMatrixMode(GL_TEXTURE); qglLoadIdentity(); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_3D); qglDisable(GL_TEXTURE_CUBE_MAP); qglDisable(GL_TEXTURE_2D_ARRAY); qglBindTexture(GL_TEXTURE_2D, 0); qglBindTexture(GL_TEXTURE_3D, 0); qglBindTexture(GL_TEXTURE_CUBE_MAP, 0); qglBindTexture(GL_TEXTURE_2D_ARRAY, 0); qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglDisable(GL_TEXTURE_GEN_S); qglDisable(GL_TEXTURE_GEN_T); qglDisable(GL_TEXTURE_GEN_R); qglDisable(GL_TEXTURE_GEN_Q); qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); qglTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); qglTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); } qglDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); qglUseProgram(0); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); qglBindBuffer(GL_ARRAY_BUFFER, 0); qglViewport(0, 0, glConfig.videoWidth, glConfig.videoHeight); qglEnable(GL_SCISSOR_TEST); qglScissor(0, 0, glConfig.videoWidth, glConfig.videoHeight); qglEnable(GL_DEPTH_BOUNDS_TEST_EXT); qglDepthBoundsEXT(0.0f, 1.0f); qglFrontFace(GL_CCW); qglShadeModel(GL_SMOOTH); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); qglDisable(GL_CULL_FACE); qglCullFace(GL_FRONT); qglDisable(GL_POLYGON_OFFSET_FILL); qglDisable(GL_POLYGON_OFFSET_LINE); qglPolygonOffset(0.0f, 0.0f); qglDisable(GL_BLEND); qglBlendFunc(GL_ONE, GL_ZERO); qglBlendEquation(GL_FUNC_ADD); qglDisable(GL_ALPHA_TEST); qglAlphaFunc(GL_GREATER, 0.0f); qglDisable(GL_DEPTH_TEST); qglDepthFunc(GL_LEQUAL); qglDisable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 128, 255); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglDepthRange(0.0f, 1.0f); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); qglDepthMask(GL_TRUE); qglStencilMask(255); qglDisable(GL_DEPTH_CLAMP); qglDisable(GL_CLIP_PLANE0); if (glConfig.multiSamples > 1){ qglDisable(GL_MULTISAMPLE); qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglClearDepth(1.0f); qglClearStencil(128); qglEnableClientState(GL_VERTEX_ARRAY); qglDisableVertexAttribArray(GL_ATTRIB_NORMAL); qglDisableVertexAttribArray(GL_ATTRIB_TANGENT1); qglDisableVertexAttribArray(GL_ATTRIB_TANGENT2); qglDisableVertexAttribArray(GL_ATTRIB_TEXCOORD); qglDisableVertexAttribArray(GL_ATTRIB_COLOR); QGL_LogPrintf("--------------------\n"); }
/* ================ DrawNormals Draws vertex normals for debugging ================ */ static void DrawNormals(shaderCommands_t *input) { vec3_t temp; GL_Bind(tr.whiteImage); qglColor3f(1, 1, 1); qglDepthRange(0, 0); // never occluded GL_State(GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE); // light direction if (r_shownormals->integer == 2) { trRefEntity_t *ent = backEnd.currentEntity; vec3_t temp2; if (ent->e.renderfx & RF_LIGHTING_ORIGIN) { VectorSubtract(ent->e.lightingOrigin, backEnd.orientation.origin, temp2); } else { VectorClear(temp2); } temp[0] = DotProduct(temp2, backEnd.orientation.axis[0]); temp[1] = DotProduct(temp2, backEnd.orientation.axis[1]); temp[2] = DotProduct(temp2, backEnd.orientation.axis[2]); qglColor3f(ent->ambientLight[0] / 255, ent->ambientLight[1] / 255, ent->ambientLight[2] / 255); qglPointSize(5); qglBegin(GL_POINTS); qglVertex3fv(temp); qglEnd(); qglPointSize(1); if (fabs(VectorLengthSquared(ent->lightDir) - 1.0f) > 0.2f) { qglColor3f(1, 0, 0); } else { qglColor3f(ent->directedLight[0] / 255, ent->directedLight[1] / 255, ent->directedLight[2] / 255); } qglLineWidth(3); qglBegin(GL_LINES); qglVertex3fv(temp); VectorMA(temp, 32, ent->lightDir, temp); qglVertex3fv(temp); qglEnd(); qglLineWidth(1); } // normals drawing else { int i; qglBegin(GL_LINES); for (i = 0 ; i < input->numVertexes ; i++) { qglVertex3fv(input->xyz[i].v); VectorMA(input->xyz[i].v, r_normallength->value, input->normal[i].v, temp); qglVertex3fv(temp); } qglEnd(); } qglDepthRange(0, 1); }
/* ============== RB_DrawSun (SA) FIXME: sun should render behind clouds, so passing dark areas cover it up ============== */ void RB_DrawSun( void ) { float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; byte color[4]; if ( !tr.sunShader ) { return; } if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { 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) // (SA) shrunk the size of the sun size = dist * 0.2; 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 ); color[0] = color[1] = color[2] = color[3] = 255; // (SA) simpler sun drawing RB_BeginSurface( tr.sunShader, tess.fogNum ); RB_AddQuadStamp( origin, vec1, vec2, color ); /* 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(); if ( r_drawSun->integer > 1 ) { // draw flare effect // (SA) FYI: This is cheezy and was only a test so far. // If we decide to use the flare business I will /definatly/ improve all this // get a point a little closer dist = dist * 0.7; VectorScale( tr.sunDirection, dist, origin ); // and make the flare a little smaller VectorScale( vec1, 0.5f, vec1 ); VectorScale( vec2, 0.5f, vec2 ); // add the vectors to give an 'off angle' result VectorAdd( tr.sunDirection, backEnd.viewParms.or.axis[0], temp ); VectorNormalize( temp ); // amplify the result origin[0] += temp[0] * 500.0; origin[1] += temp[1] * 500.0; origin[2] += temp[2] * 500.0; // (SA) FIXME: todo: flare effect should render last (on top of everything else) and only when sun is in view (sun moving out of camera past degree n should start to cause flare dimming until view angle to sun is off by angle n + x. // draw the flare RB_BeginSurface( tr.sunflareShader[0], tess.fogNum ); RB_AddQuadStamp( origin, vec1, vec2, color ); RB_EndSurface(); } // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
/* ================ DrawTris Draws triangle outlines for debugging ================ */ static void DrawTris(shaderCommands_t *input) { char *s = r_trisColor->string; vec4_t trisColor = { 1, 1, 1, 1 }; unsigned int stateBits = 0; GL_Bind(tr.whiteImage); if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) { s += 2; if (Q_IsHexColorString(s)) { trisColor[0] = ((float)(gethex(*(s)) * 16 + gethex(*(s + 1)))) / 255.00; trisColor[1] = ((float)(gethex(*(s + 2)) * 16 + gethex(*(s + 3)))) / 255.00; trisColor[2] = ((float)(gethex(*(s + 4)) * 16 + gethex(*(s + 5)))) / 255.00; if (Q_HexColorStringHasAlpha(s)) { trisColor[3] = ((float)(gethex(*(s + 6)) * 16 + gethex(*(s + 7)))) / 255.00; } } } else { int i; char *token; for (i = 0 ; i < 4 ; i++) { token = COM_Parse(&s); if (token) { trisColor[i] = atof(token); } else { trisColor[i] = 1.f; } } if (!trisColor[3]) { trisColor[3] = 1.f; } } if (trisColor[3] < 1.f) { stateBits |= (GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); } qglColor4fv(trisColor); if (r_showtris->integer == 2) { stateBits |= (GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE); GL_State(stateBits); qglDepthRange(0, 0); } #ifdef CELSHADING_HACK else if (r_showtris->integer == 3) { stateBits |= (GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE); GL_State(stateBits); qglEnable(GL_POLYGON_OFFSET_LINE); qglPolygonOffset(4.0, 0.5); qglLineWidth(5.0); } #endif else { stateBits |= (GLS_POLYMODE_LINE); GL_State(stateBits); qglEnable(GL_POLYGON_OFFSET_LINE); qglPolygonOffset(r_offsetFactor->value, r_offsetUnits->value); } qglDisableClientState(GL_COLOR_ARRAY); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglVertexPointer(3, GL_FLOAT, 16, input->xyz); // padded for SIMD if (qglLockArraysEXT) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment("glLockArraysEXT\n"); } R_DrawElements(input->numIndexes, input->indexes); if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment("glUnlockArraysEXT\n"); } qglDepthRange(0, 1); qglDisable(GL_POLYGON_OFFSET_LINE); }
/* ================== 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(); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader; int fogNum; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; int oldSort; const surfaceType_t *surface; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // Prepare initial values that will trigger the needed settings backEnd.currentModel = (sceneModel_t*)-1; oldDepthRange = qfalse; oldSort = -1; depthRange = qfalse; // Clear for endsurface first run tess.numIndexes = 0; backEnd.pc.c_surfaces += numDrawSurfs; if (!(backEnd.refdef->rdflags & RDF_NOWORLDMODEL)) { backEnd.sceneZfar = backEnd.viewParms.zFar; } for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { /* Rendering a model? */ if ( drawSurf->sort & QSORT_HAVEMODEL_MASK ) { const drawModel_t *drawModel; unsigned int index; RB_EndSurface(); oldSort = drawSurf->sort; drawModel = (drawModel_t*) drawSurf->data; backEnd.currentModel = drawModel->model; index = R_SortToIndex( oldSort ); surface = drawModel->surface[index]; // set up the transformation matrix R_RotateForEntity( backEnd.currentModel, &backEnd.viewParms, &backEnd.or ); R_TransformDlights( backEnd.refdef->numDlights, backEnd.refdef->dlights, &backEnd.or ); //Load the temporary matrix to show the model qglLoadMatrixf( backEnd.or.modelMatrix ); depthRange = 0; //figure this stuff out now and store it if ( backEnd.currentModel->renderfx & RF_NODEPTH ) { depthRange = 2; } else if ( backEnd.currentModel->renderfx & RF_DEPTHHACK ) { depthRange = 1; } if ( oldDepthRange != depthRange ) { oldDepthRange = depthRange; switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } } shader = R_SortToShader( oldSort ); fogNum = R_SortToFog( oldSort ); RB_BeginSurface( shader, fogNum ); if ( mme_saveStencil->integer == 1) { if ( backEnd.currentModel->renderfx & RF_STENCIL) { if (!backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); backEnd.doingStencil = qtrue; } } else { if (backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); backEnd.doingStencil = qfalse; } } } rb_surfaceTable[ *surface ]( surface ); continue; } if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *((byte *)drawSurf->data) ]( drawSurf->data ); continue; } RB_EndSurface(); oldSort = drawSurf->sort; shader = R_SortToShader( oldSort ); fogNum = R_SortToFog( oldSort ); RB_BeginSurface( shader, fogNum ); if ( backEnd.currentModel ) { if (backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); backEnd.doingStencil = qfalse; } backEnd.currentModel = 0; backEnd.or = backEnd.viewParms.world; R_TransformDlights( backEnd.refdef->numDlights, backEnd.refdef->dlights, &backEnd.or ); qglLoadMatrixf( backEnd.or.modelMatrix ); if ( oldDepthRange ) { depthRange = 0; oldDepthRange = 0; qglDepthRange (0, 1); } } rb_surfaceTable[ *((byte *)drawSurf->data) ]( drawSurf->data ); if ( mme_saveStencil->integer == 1) { if (backEnd.currentModel && backEnd.currentModel->renderfx & RF_STENCIL) { if (!backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); backEnd.doingStencil = qtrue; } } else { if (backEnd.doingStencil) { qglStencilOp( GL_KEEP, GL_KEEP, GL_ZERO ); backEnd.doingStencil = qfalse; } } } // add the triangles for this surface } // if ( backEnd.currentModel && tess.numVertexes ) // Com_Printf( "Shader batch for a model?\n" ); // draw the contents of the last shader batch RB_EndSurface(); // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }
/* * RB_RenderDrawSurfList */ void RB_RenderDrawSurfList(drawSurf_t *drawSurfs, int numDrawSurfs) { 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_DrawSun */ void RB_DrawSun(void) { float size; float dist; Vec3 origin, vec1, vec2; Vec3 temp; if(!backEnd.skyRenderedThisView){ return; } if(!r_drawSun->integer){ 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 * 0.4; scalev3(tr.sunDirection, dist, origin); perpv3(vec1, tr.sunDirection); crossv3(tr.sunDirection, vec1, vec2); scalev3(vec1, size, vec1); scalev3(vec2, size, vec2); /* farthest depth range */ qglDepthRange(1.0, 1.0); /* FIXME: use quad stamp */ RB_BeginSurface(tr.sunShader, tess.fogNum); copyv3(origin, temp); subv3(temp, vec1, temp); subv3(temp, vec2, temp); copyv3(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++; copyv3(origin, temp); addv3(temp, vec1, temp); subv3(temp, vec2, temp); copyv3(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++; copyv3(origin, temp); addv3(temp, vec1, temp); addv3(temp, vec2, temp); copyv3(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++; copyv3(origin, temp); subv3(temp, vec1, temp); addv3(temp, vec2, temp); copyv3(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); }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i; dmdl_t *paliashdr; float an; vec3_t bbox[8]; image_t *skin; if ( !( e->flags & RF_WEAPONMODEL ) ) { if ( R_CullAliasModel( bbox, e ) ) return; } if ( e->flags & RF_WEAPONMODEL ) { if ( r_lefthand->value == 2 ) return; } paliashdr = (dmdl_t *)currentmodel->extradata; // // get lighting information // // PMM - rewrote, reordered to handle new shells & mixing // if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { // PMM -special case for godmode if ( (currententity->flags & RF_SHELL_RED) && (currententity->flags & RF_SHELL_BLUE) && (currententity->flags & RF_SHELL_GREEN) ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if ( currententity->flags & RF_SHELL_RED ) { shadelight[0] = 1.0; if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) ) shadelight[2] = 1.0; } else if ( currententity->flags & RF_SHELL_BLUE ) { if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[1] = 1.0; shadelight[2] = 1.0; } else { shadelight[2] = 1.0; } } else if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } } else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) ) { VectorClear (shadelight); // PMM - new colors if ( currententity->flags & RF_SHELL_HALF_DAM ) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_GREEN ) { shadelight[1] = 1.0; } } } //PMM - ok, now flatten these down to range from 0 to 1.0. // max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2])); // if (max_shell_val > 0) // { // for (i=0; i<3; i++) // { // shadelight[i] = shadelight[i] / max_shell_val; // } // } // pmm else if ( currententity->flags & RF_FULLBRIGHT ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else { R_LightPoint (currententity->origin, shadelight); // player lighting hack for communication back to server // big hack! if ( currententity->flags & RF_WEAPONMODEL ) { // pick the greatest component, which should be the same // as the mono value returned by software if (shadelight[0] > shadelight[1]) { if (shadelight[0] > shadelight[2]) r_lightlevel->value = 150*shadelight[0]; else r_lightlevel->value = 150*shadelight[2]; } else { if (shadelight[1] > shadelight[2]) r_lightlevel->value = 150*shadelight[1]; else r_lightlevel->value = 150*shadelight[2]; } } if ( gl_monolightmap->string[0] != '0' ) { float s = shadelight[0]; if ( s < shadelight[1] ) s = shadelight[1]; if ( s < shadelight[2] ) s = shadelight[2]; shadelight[0] = s; shadelight[1] = s; shadelight[2] = s; } } if ( currententity->flags & RF_MINLIGHT ) { for (i=0 ; i<3 ; i++) if (shadelight[i] > 0.1) break; if (i == 3) { shadelight[0] = 0.1; shadelight[1] = 0.1; shadelight[2] = 0.1; } } if ( currententity->flags & RF_GLOW ) { // bonus items will pulse with time float scale; float min; scale = 0.1 * sin(r_newrefdef.time*7); for (i=0 ; i<3 ; i++) { min = shadelight[i] * 0.8; shadelight[i] += scale; if (shadelight[i] < min) shadelight[i] = min; } } // ================= // PGM ir goggles color override if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) { shadelight[0] = 1.0; shadelight[1] = 0.0; shadelight[2] = 0.0; } // PGM // ================= shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; an = currententity->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // c_alias_polys += paliashdr->num_tris; // // draw all the triangles // if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); qglMatrixMode( GL_PROJECTION ); qglPushMatrix(); qglLoadIdentity(); qglScalef( -1, 1, 1 ); MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_BACK ); } qglPushMatrix (); e->angles[PITCH] = -e->angles[PITCH]; // sigh. R_RotateForEntity (e); e->angles[PITCH] = -e->angles[PITCH]; // sigh. // select skin if (currententity->skin) skin = currententity->skin; // custom player skin else { if (currententity->skinnum >= MAX_MD2SKINS) skin = currentmodel->skins[0]; else { skin = currentmodel->skins[currententity->skinnum]; if (!skin) skin = currentmodel->skins[0]; } } if (!skin) skin = r_notexture; // fallback... GL_Bind(skin->texnum); // draw it qglShadeModel (GL_SMOOTH); GL_TexEnv( GL_MODULATE ); if ( currententity->flags & RF_TRANSLUCENT ) { qglEnable (GL_BLEND); } if ( (currententity->frame >= paliashdr->num_frames) || (currententity->frame < 0) ) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame); currententity->frame = 0; currententity->oldframe = 0; } if ( (currententity->oldframe >= paliashdr->num_frames) || (currententity->oldframe < 0)) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe); currententity->frame = 0; currententity->oldframe = 0; } if ( !r_lerpmodels->value ) currententity->backlerp = 0; GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp); GL_TexEnv( GL_REPLACE ); qglShadeModel (GL_FLAT); qglPopMatrix (); #if 0 qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDisable( GL_TEXTURE_2D ); qglBegin( GL_TRIANGLE_STRIP ); for ( i = 0; i < 8; i++ ) { qglVertex3fv( bbox[i] ); } qglEnd(); qglEnable( GL_TEXTURE_2D ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglEnable( GL_CULL_FACE ); #endif if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { qglMatrixMode( GL_PROJECTION ); qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_FRONT ); } if ( currententity->flags & RF_TRANSLUCENT ) { qglDisable (GL_BLEND); } if (currententity->flags & RF_DEPTHHACK) qglDepthRange (gldepthmin, gldepthmax); #if 1 if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL))) { qglPushMatrix (); R_RotateForEntity (e); qglDisable (GL_TEXTURE_2D); qglEnable (GL_BLEND); qglColor4f (0,0,0,0.5); GL_DrawAliasShadow (paliashdr, currententity->frame ); qglEnable (GL_TEXTURE_2D); qglDisable (GL_BLEND); qglPopMatrix (); } #endif qglColor4f (1,1,1,1); }
void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; int depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; unsigned int oldSort; float originalTime; trRefEntity_t *curEnt; postRender_t *pRender; bool didShadowPass = false; #ifdef __MACOS__ int macEventTime; Sys_PumpEvents(); // crutch up the mac's limited buffer queue size // we don't want to pump the event loop too often and waste time, so // we are going to check every shader change macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC; #endif if (g_bRenderGlowingObjects) { //only shadow on initial passes didShadowPass = true; } // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; oldDlighted = qfalse; oldSort = (unsigned int) -1; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // If we're rendering glowing objects, but this shader has no stages with glow, skip it! if ( g_bRenderGlowingObjects && !shader->hasGlow ) { shader = oldShader; entityNum = oldEntityNum; fogNum = oldFogNum; dlighted = oldDlighted; continue; } oldSort = drawSurf->sort; // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if (entityNum != TR_WORLDENT && g_numPostRenders < MAX_POST_RENDERS) { if ( (backEnd.refdef.entities[entityNum].e.renderfx & RF_DISTORTION)/* || (backEnd.refdef.entities[entityNum].e.renderfx & RF_FORCE_ENT_ALPHA)*/) //not sure if we need this alpha fix for sp or not, leaving it out for now -rww { //must render last curEnt = &backEnd.refdef.entities[entityNum]; pRender = &g_postRenders[g_numPostRenders]; g_numPostRenders++; depthRange = 0; //figure this stuff out now and store it if ( curEnt->e.renderfx & RF_NODEPTH ) { depthRange = 2; } else if ( curEnt->e.renderfx & RF_DEPTHHACK ) { depthRange = 1; } pRender->depthRange = depthRange; //It is not necessary to update the old* values because //we are not updating now with the current values. depthRange = oldDepthRange; //store off the ent num pRender->entNum = entityNum; //remember the other values necessary for rendering this surf pRender->drawSurf = drawSurf; pRender->dlighted = dlighted; pRender->fogNum = fogNum; pRender->shader = shader; //assure the info is back to the last set state shader = oldShader; entityNum = oldEntityNum; fogNum = oldFogNum; dlighted = oldDlighted; oldSort = (unsigned int)-1; //invalidate this thing, cause we may want to postrender more surfs of the same sort //continue without bothering to begin a draw surf continue; } } if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { #ifdef __MACOS__ // crutch up the mac's limited buffer queue size int t; t = ri.Milliseconds(); if ( t > macEventTime ) { macEventTime = t + MAC_EVENT_PUMP_MSEC; Sys_PumpEvents(); } #endif RB_EndSurface(); if (!didShadowPass && shader && shader->sort > SS_BANNER) { RB_ShadowFinish(); didShadowPass = true; } } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = qfalse; if ( entityNum != TR_WORLDENT ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } if ( backEnd.currentEntity->e.renderfx & RF_NODEPTH ) { // No depth at all, very rare but some things for seeing through walls depthRange = 2; } else if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.ori = backEnd.viewParms.world; #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } qglLoadMatrixf( backEnd.ori.modelMatrix ); // // change depthrange if needed // if ( oldDepthRange != depthRange ) { switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } oldDepthRange = depthRange; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } if (tr_stencilled && tr_distortionPrePost) { //ok, cap it now RB_CaptureScreenImage(); RB_DistortionFill(); } //render distortion surfs (or anything else that needs to be post-rendered) if (g_numPostRenders > 0) { int lastPostEnt = -1; while (g_numPostRenders > 0) { g_numPostRenders--; pRender = &g_postRenders[g_numPostRenders]; RB_BeginSurface( pRender->shader, pRender->fogNum ); backEnd.currentEntity = &backEnd.refdef.entities[pRender->entNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { #ifdef VV_LIGHTING VVLightMan.R_TransformDlights( &backEnd.ori ); #else R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); #endif } qglLoadMatrixf( backEnd.ori.modelMatrix ); depthRange = pRender->depthRange; switch ( depthRange ) { default: case 0: qglDepthRange (0, 1); break; case 1: qglDepthRange (0, .3); break; case 2: qglDepthRange (0, 0); break; } if ((backEnd.currentEntity->e.renderfx & RF_DISTORTION) && lastPostEnt != pRender->entNum) { //do the capture now, we only need to do it once per ent int x, y; int rad = backEnd.currentEntity->e.radius; //We are going to just bind this, and then the CopyTexImage is going to //stomp over this texture num in texture memory. GL_Bind( tr.screenImage ); if (R_WorldCoordToScreenCoord( backEnd.currentEntity->e.origin, &x, &y )) { int cX, cY; cX = glConfig.vidWidth-x-(rad/2); cY = glConfig.vidHeight-y-(rad/2); if (cX+rad > glConfig.vidWidth) { //would it go off screen? cX = glConfig.vidWidth-rad; } else if (cX < 0) { //cap it off at 0 cX = 0; } if (cY+rad > glConfig.vidHeight) { //would it go off screen? cY = glConfig.vidHeight-rad; } else if (cY < 0) { //cap it off at 0 cY = 0; } //now copy a portion of the screen to this texture qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, cX, cY, rad, rad, 0); lastPostEnt = pRender->entNum; } } rb_surfaceTable[ *pRender->drawSurf->surface ]( pRender->drawSurf->surface ); RB_EndSurface(); } } // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif if (tr_stencilled && !tr_distortionPrePost) { //draw in the stencil buffer's cutout RB_DistortionFill(); } if (!didShadowPass) { // darken down any stencil shadows RB_ShadowFinish(); didShadowPass = true; } // add light flares on lights that aren't obscured // RB_RenderFlares(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }
/* ================== 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 }
/** * @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(); }
static void RB_RenderDrawSurfaces( qboolean opaque, qboolean depthFill ) { trRefEntity_t *entity, *oldEntity; shader_t *shader, *oldShader; int lightmapNum, oldLightmapNum; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; GLimp_LogComment( "--- RB_RenderDrawSurfaces ---\n" ); // draw everything oldEntity = NULL; oldShader = NULL; oldLightmapNum = -1; oldDepthRange = qfalse; depthRange = qfalse; backEnd.currentLight = NULL; for ( i = 0, drawSurf = backEnd.viewParms.drawSurfs; i < backEnd.viewParms.numDrawSurfs; i++, drawSurf++ ) { // update locals entity = drawSurf->entity; shader = tr.sortedShaders[ drawSurf->shaderNum ]; lightmapNum = drawSurf->lightmapNum; if ( opaque ) { // skip all translucent surfaces that don't matter for this pass if ( shader->sort > SS_OPAQUE ) { break; } } else { // skip all opaque surfaces that don't matter for this pass if ( shader->sort <= SS_OPAQUE ) { continue; } } if ( entity == oldEntity && shader == oldShader && lightmapNum == oldLightmapNum ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } // change the tess parameters if needed // an "entityMergable" shader is a shader that can have surfaces from separate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != oldShader || lightmapNum != oldLightmapNum || ( entity != oldEntity && !shader->entityMergable ) ) { if ( oldShader != NULL ) { Tess_End(); } if ( depthFill ) { Tess_Begin( Tess_StageIteratorDepthFill, NULL, shader, NULL, qtrue, qfalse, lightmapNum, tess.fogNum ); } else { Tess_Begin( Tess_StageIteratorGeneric, NULL, shader, NULL, qfalse, qfalse, lightmapNum, tess.fogNum ); } oldShader = shader; oldLightmapNum = lightmapNum; } // change the modelview matrix if needed if ( entity != oldEntity ) { depthRange = qfalse; if ( entity != &tr.worldEntity ) { backEnd.currentEntity = entity; // set up the transformation matrix R_RotateEntityForViewParms( backEnd.currentEntity, &backEnd.viewParms, &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.orientation = backEnd.viewParms.world; } #if defined( USE_D3D10 ) // TODO #else GL_LoadModelViewMatrix( backEnd.orientation.modelViewMatrix ); #endif // change depthrange if needed if ( oldDepthRange != depthRange ) { #if defined( USE_D3D10 ) // TODO #else if ( depthRange ) { qglDepthRange( 0, 0.3 ); } else { qglDepthRange( 0, 1 ); } #endif oldDepthRange = depthRange; } oldEntity = entity; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } // draw the contents of the last shader batch if ( oldShader != NULL ) { Tess_End(); } // go back to the world modelview matrix #if defined( USE_D3D10 ) // TODO #else GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); #endif if ( depthRange ) { #if defined( USE_D3D10 ) // TODO #else qglDepthRange( 0, 1 ); #endif } #if defined( USE_D3D10 ) // TODO #else GL_CheckErrors(); #endif }
void R_DrawAliasModel ( entity_t *e ) { int i; dmdl_t *paliashdr; float an; vec3_t bbox [ 8 ]; image_t *skin; if ( !( e->flags & RF_WEAPONMODEL ) ) { if ( R_CullAliasModel( bbox, e ) ) { return; } } if ( e->flags & RF_WEAPONMODEL ) { if ( gl_lefthand->value == 2 ) { return; } } paliashdr = (dmdl_t *) currentmodel->extradata; /* get lighting information */ if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear( shadelight ); if ( currententity->flags & RF_SHELL_HALF_DAM ) { shadelight [ 0 ] = 0.56; shadelight [ 1 ] = 0.59; shadelight [ 2 ] = 0.45; } if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight [ 0 ] = 0.9; shadelight [ 1 ] = 0.7; } if ( currententity->flags & RF_SHELL_RED ) { shadelight [ 0 ] = 1.0; } if ( currententity->flags & RF_SHELL_GREEN ) { shadelight [ 1 ] = 1.0; } if ( currententity->flags & RF_SHELL_BLUE ) { shadelight [ 2 ] = 1.0; } } else if ( currententity->flags & RF_FULLBRIGHT ) { for ( i = 0; i < 3; i++ ) { shadelight [ i ] = 1.0; } } else { R_LightPoint( currententity->origin, shadelight ); /* player lighting hack for communication back to server */ if ( currententity->flags & RF_WEAPONMODEL ) { /* pick the greatest component, which should be the same as the mono value returned by software */ if ( shadelight [ 0 ] > shadelight [ 1 ] ) { if ( shadelight [ 0 ] > shadelight [ 2 ] ) { gl_lightlevel->value = 150 * shadelight [ 0 ]; } else { gl_lightlevel->value = 150 * shadelight [ 2 ]; } } else { if ( shadelight [ 1 ] > shadelight [ 2 ] ) { gl_lightlevel->value = 150 * shadelight [ 1 ]; } else { gl_lightlevel->value = 150 * shadelight [ 2 ]; } } } } if ( currententity->flags & RF_MINLIGHT ) { for ( i = 0; i < 3; i++ ) { if ( shadelight [ i ] > 0.1 ) { break; } } if ( i == 3 ) { shadelight [ 0 ] = 0.1; shadelight [ 1 ] = 0.1; shadelight [ 2 ] = 0.1; } } if ( currententity->flags & RF_GLOW ) { /* bonus items will pulse with time */ float scale; float min; scale = 0.1 * sin( r_newrefdef.time * 7 ); for ( i = 0; i < 3; i++ ) { min = shadelight [ i ] * 0.8; shadelight [ i ] += scale; if ( shadelight [ i ] < min ) { shadelight [ i ] = min; } } } /* ir goggles color override */ if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE ) { shadelight [ 0 ] = 1.0; shadelight [ 1 ] = 0.0; shadelight [ 2 ] = 0.0; } shadedots = r_avertexnormal_dots [ ( (int) ( currententity->angles [ 1 ] * ( SHADEDOT_QUANT / 360.0 ) ) ) & ( SHADEDOT_QUANT - 1 ) ]; an = currententity->angles [ 1 ] / 180 * M_PI; shadevector [ 0 ] = cos( -an ); shadevector [ 1 ] = sin( -an ); shadevector [ 2 ] = 1; VectorNormalize( shadevector ); /* locate the proper data */ c_alias_polys += paliashdr->num_tris; /* draw all the triangles */ if ( currententity->flags & RF_DEPTHHACK ) /* hack the depth range to prevent view model from poking into walls */ { qglDepthRange( gldepthmin, gldepthmin + 0.3 * ( gldepthmax - gldepthmin ) ); } if ( ( currententity->flags & RF_WEAPONMODEL ) && ( gl_lefthand->value == 1.0F ) ) { extern void R_MYgluPerspective ( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); qglMatrixMode( GL_PROJECTION ); qglPushMatrix(); qglLoadIdentity(); qglScalef( -1, 1, 1 ); R_MYgluPerspective( r_newrefdef.fov_y, (float) r_newrefdef.width / r_newrefdef.height, 4, 4096 ); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_BACK ); } qglPushMatrix(); e->angles [ PITCH ] = -e->angles [ PITCH ]; R_RotateForEntity( e ); e->angles [ PITCH ] = -e->angles [ PITCH ]; /* select skin */ if ( currententity->skin ) { skin = currententity->skin; /* custom player skin */ } else { if ( currententity->skinnum >= MAX_MD2SKINS ) { skin = currentmodel->skins [ 0 ]; } else { skin = currentmodel->skins [ currententity->skinnum ]; if ( !skin ) { skin = currentmodel->skins [ 0 ]; } } } if ( !skin ) { skin = r_notexture; /* fallback... */ } R_Bind( skin->texnum ); /* draw it */ qglShadeModel( GL_SMOOTH ); R_TexEnv( GL_MODULATE ); if ( currententity->flags & RF_TRANSLUCENT ) { qglEnable( GL_BLEND ); } if ( ( currententity->frame >= paliashdr->num_frames ) || ( currententity->frame < 0 ) ) { ri.Con_Printf( PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame ); currententity->frame = 0; currententity->oldframe = 0; } if ( ( currententity->oldframe >= paliashdr->num_frames ) || ( currententity->oldframe < 0 ) ) { ri.Con_Printf( PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe ); currententity->frame = 0; currententity->oldframe = 0; } if ( !gl_lerpmodels->value ) { currententity->backlerp = 0; } R_DrawAliasFrameLerp( paliashdr, currententity->backlerp ); R_TexEnv( GL_REPLACE ); qglShadeModel( GL_FLAT ); qglPopMatrix(); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( gl_lefthand->value == 1.0F ) ) { qglMatrixMode( GL_PROJECTION ); qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_FRONT ); } if ( currententity->flags & RF_TRANSLUCENT ) { qglDisable( GL_BLEND ); } if ( currententity->flags & RF_DEPTHHACK ) { qglDepthRange( gldepthmin, gldepthmax ); } if ( gl_shadows->value && !( currententity->flags & ( RF_TRANSLUCENT | RF_WEAPONMODEL | RF_NOSHADOW ) ) ) { qglPushMatrix(); /* don't rotate shadows on ungodly axes */ qglTranslatef( e->origin [ 0 ], e->origin [ 1 ], e->origin [ 2 ] ); qglRotatef( e->angles [ 1 ], 0, 0, 1 ); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_BLEND ); qglColor4f( 0, 0, 0, 0.5f ); R_DrawAliasShadow( paliashdr, currententity->frame ); qglEnable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglPopMatrix(); } qglColor4f( 1, 1, 1, 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; 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_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void RB_StageIteratorSky( void ) { if ( g_bRenderGlowingObjects ) return; if ( r_fastsky->integer ) { return; } if (skyboxportal && !(backEnd.refdef.rdflags & RDF_SKYBOXPORTAL)) { return; } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn RB_ClipSkyPolygons( &tess ); // r_showsky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showsky->integer ) { qglDepthRange( 0.0, 0.0 ); } else { #ifdef _XBOX qglDepthRange( 0.99, 1.0 ); #else qglDepthRange( 1.0, 1.0 ); #endif } // draw the outer skybox if ( tess.shader->sky->outerbox[0] && tess.shader->sky->outerbox[0] != tr.defaultImage ) { qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglPushMatrix (); GL_State( 0 ); qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); DrawSkyBox( tess.shader ); qglPopMatrix(); } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine R_BuildCloudData( &tess ); if (tess.numIndexes && tess.numVertexes) { RB_StageIteratorGeneric(); } // draw the inner skybox // back to normal depth range qglDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; }