/* ** RB_DrawSun */ void RB_DrawSun( float scale, shader_t *shader ) { float size; float dist; vec3_t origin, vec1, vec2; byte sunColor[4] = { 255, 255, 255, 255 }; if ( !backEnd.skyRenderedThisView ) { return; } qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * scale; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range qglDepthRange( 1.0, 1.0 ); RB_BeginSurface( shader, 0 ); RB_AddQuadStamp(origin, vec1, vec2, sunColor); RB_EndSurface(); // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
/* =============== RB_LeaveDepthHack =============== */ void RB_LeaveDepthHack() { qglDepthRange( 0, 1 ); qglMatrixMode(GL_PROJECTION); qglLoadMatrixf( backEnd.viewDef->projectionMatrix ); qglMatrixMode(GL_MODELVIEW); }
/* ====================== RB_BindStageTexture ====================== */ void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *texture, const drawSurf_t *surf ) { // image RB_BindVariableStageImage( texture, shaderRegisters ); // texgens if ( texture->texgen == TG_DIFFUSE_CUBE ) { qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() ); } if ( texture->texgen == TG_SKYBOX_CUBE || texture->texgen == TG_WOBBLESKY_CUBE ) { qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) ); } if ( texture->texgen == TG_REFLECT_CUBE ) { qglEnable( GL_TEXTURE_GEN_S ); qglEnable( GL_TEXTURE_GEN_T ); qglEnable( GL_TEXTURE_GEN_R ); qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); qglEnableClientState( GL_NORMAL_ARRAY ); qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() ); qglMatrixMode( GL_TEXTURE ); float mat[16]; R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat ); qglLoadMatrixf( mat ); qglMatrixMode( GL_MODELVIEW ); } // matrix if ( texture->hasMatrix ) { RB_LoadShaderTextureMatrix( shaderRegisters, texture ); } }
void RB_RenderWorldEffects(void) { float elapseTime = backEnd.refdef.frametime / 1000.0; if (tr.refdef.rdflags & RDF_NOWORLDMODEL || !tr.world || CL_IsRunningInGameCinematic()) { // no world rendering or no world return; } SetViewportAndScissor(); qglMatrixMode(GL_MODELVIEW); // qglPushMatrix(); qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); originContents = ri.CM_PointContents(backEnd.viewParms.or.origin, 0); if (rainSystem) { rainSystem->Update(elapseTime); rainSystem->Render(); } if (snowSystem) { snowSystem->Update(elapseTime); snowSystem->Render(); } // qglMatrixMode(GL_MODELVIEW); // qglPopMatrix(); }
/* ====================== RB_LoadShaderTextureMatrix ====================== */ void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ) { float matrix[16]; RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix ); qglMatrixMode( GL_TEXTURE ); qglLoadMatrixf( matrix ); qglMatrixMode( GL_MODELVIEW ); }
/* =============== RB_EnterModelDepthHack =============== */ static void RB_EnterModelDepthHack( float depth ) { float matrix[16]; memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); matrix[14] -= depth; qglMatrixMode( GL_PROJECTION ); qglLoadMatrixf( matrix ); qglMatr
void R_DrawAliasBatchPass (entity_t **ents, int numents, qbool showtris) { int i; gltexture_t *lasttexture = NULL; gltexture_t *lastfullbright = NULL; if (!numents) return; if (showtris) GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_REPLACE); else if (gl_overbright.value) GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_RGB_SCALE_ARB); else GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_MODULATE); for (i = 0; i < numents; i++) { entity_t *ent = ents[i]; aliasstate_t *state = &ent->aliasstate; aliashdr_t *hdr = Mod_Extradata (ent->model); // we need a separate test for culling here as r_shadows mode doesn't cull if (ent->visframe != r_framecount) continue; if (!showtris && ((state->tx != lasttexture) || (state->fb != lastfullbright))) { if (state->fb) { GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_ADD); GL_BindTexture (GL_TEXTURE1_ARB, state->fb); } else GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_NONE); GL_BindTexture (GL_TEXTURE0_ARB, state->tx); lasttexture = state->tx; lastfullbright = state->fb; } // OK, this works better in GL... go figure... R_DrawAliasModel (ent, hdr, state, showtris); } GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_NONE); GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_REPLACE); qglColor4f (1, 1, 1, 1); // go back to the world matrix qglLoadMatrixf (r_world_matrix.m16); }
/* =============== RB_EnterModelDepthHack =============== */ void RB_EnterModelDepthHack( float depth ) { float matrix[16]; qglDepthRange( 0.0f, 1.0f ); memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); matrix[14] -= depth; qglMatrixMode( GL_PROJECTION ); qglLoadMatrixf( matrix ); qglMatrixMode( GL_MODELVIEW ); }
/* =============== RB_EnterWeaponDepthHack =============== */ void RB_EnterWeaponDepthHack() { float matrix[16]; qglDepthRange( 0.0f, 0.5f ); memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); matrix[14] *= 0.25f; qglMatrixMode( GL_PROJECTION ); qglLoadMatrixf( matrix ); qglMatrixMode( GL_MODELVIEW ); }
void SetViewportAndScissor( void ) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf( backEnd.viewParms.projectionMatrix ); qglMatrixMode(GL_MODELVIEW); // set the window clipping qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); }
/* ================ RB_SimpleWorldSetup ================ */ static void RB_SimpleWorldSetup() { backEnd.currentSpace = &backEnd.viewDef->worldSpace; qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix ); GL_Scissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1, backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1, backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1, backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 ); backEnd.currentScissor = backEnd.viewDef->scissor; }
static void SetViewportAndScissor( void ) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf( backEnd.viewParms.projectionMatrix ); qglMatrixMode(GL_MODELVIEW); // set the window clipping qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); Matrix4Copy(backEnd.viewParms.projectionMatrix, glState.currentProjectionMatrix); Matrix4Multiply(glState.currentProjectionMatrix, glState.currentModelViewMatrix, glState.currentModelViewProjectionMatrix); }
void R_ScrollSkyMatrix (float speed) { float scroll = cl.time * speed; glmatrix texmatrix; scroll -= (int) scroll & ~127; scroll /= 128.0f; qglMatrixMode (GL_TEXTURE); GL_IdentityMatrix (&texmatrix); GL_TranslateMatrix (&texmatrix, scroll, scroll, 0); qglLoadMatrixf (texmatrix.m16); qglMatrixMode (GL_MODELVIEW); }
/* =============== RB_EnterWeaponDepthHack =============== */ static void RB_EnterWeaponDepthHack() { float matrix[16]; memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); const float modelDepthHack = 0.25f; matrix[2] *= modelDepthHack; matrix[6] *= modelDepthHack; matrix[10] *= modelDepthHack; matrix[14] *= modelDepthHack; qglMatrixMode( GL_PROJECTION ); qglLoadMatrixf( matrix ); qglMatrixMode( GL_MODELVIEW ); }
/* ================ RB_SimpleSurfaceSetup ================ */ static void RB_SimpleSurfaceSetup( const drawSurf_t *drawSurf ) { // change the matrix if needed if ( drawSurf->space != backEnd.currentSpace ) { qglLoadMatrixf( drawSurf->space->modelViewMatrix ); backEnd.currentSpace = drawSurf->space; } // change the scissor if needed if ( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) { GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1, backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1, drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1, drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 ); backEnd.currentScissor = drawSurf->scissorRect; } }
static void SetViewportAndScissor( void ) { qglMatrixMode( GL_PROJECTION ); qglLoadMatrixf( backEnd.viewParms.projectionMatrix ); qglMatrixMode( GL_MODELVIEW ); // set the window clipping qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); // TODO: insert handling for widescreen? (when looking through camera) qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); }
// This could be two functions, but I want to keep the number of different API calls to a minimum void GLRB_SetPortalRendering( qboolean enabled, const float* flipMatrix, const float* plane ) { if ( enabled ) { double dplane[4] = { plane[0], plane[1], plane[2], plane[3] }; qglLoadMatrixf( flipMatrix ); qglClipPlane( GL_CLIP_PLANE0, dplane ); qglEnable( GL_CLIP_PLANE0 ); } else { qglDisable( GL_CLIP_PLANE0 ); } }
/* ==================== RB_RenderDrawSurfListWithFunction The triangle functions can check backEnd.currentSpace != surf->space to see if they need to perform any new matrix setup. The modelview matrix will already have been loaded, and backEnd.currentSpace will be updated after the triangle function completes. ==================== */ void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs, void (*triFunc_)( const drawSurf_t *) ) { int i; const drawSurf_t *drawSurf; backEnd.currentSpace = NULL; for (i = 0 ; i < numDrawSurfs ; i++ ) { drawSurf = drawSurfs[i]; // change the matrix if needed if ( drawSurf->space != backEnd.currentSpace ) { qglLoadMatrixf( drawSurf->space->modelViewMatrix ); } if ( drawSurf->space->weaponDepthHack ) { RB_EnterWeaponDepthHack(); } if ( drawSurf->space->modelDepthHack != 0.0f ) { RB_EnterModelDepthHack( drawSurf->space->modelDepthHack ); } // change the scissor if needed if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) { backEnd.currentScissor = drawSurf->scissorRect; qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); } // render it triFunc_( drawSurf ); if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) { RB_LeaveDepthHack(); } backEnd.currentSpace = drawSurf->space; } }
/* ================== GL_LoadMatrix ================== */ void GL_LoadMatrix (uint mode, const mat4_t matrix){ switch (mode){ case GL_PROJECTION: glState.projectionMatrixIdentity = false; break; case GL_MODELVIEW: glState.modelviewMatrixIdentity = false; break; case GL_TEXTURE: glState.textureMatrixIdentity[glState.texUnit] = false; break; } qglMatrixMode(mode); qglLoadMatrixf(matrix); }
static void SetViewportAndScissor( void ) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf( backEnd.viewParms.projectionMatrix ); qglMatrixMode(GL_MODELVIEW); // set the window clipping qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); if(r_subviewScissor->integer) { qglScissor( backEnd.viewParms.scissorMinX, backEnd.viewParms.scissorMinY, backEnd.viewParms.scissorMaxX - backEnd.viewParms.scissorMinX, backEnd.viewParms.scissorMaxY - backEnd.viewParms.scissorMinY ); } else { qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); } }
void Sky_RenderLayers (void) { glmatrix skymatrix; // standard layers GL_BindTexture (GL_TEXTURE0_ARB, solidskytexture); R_ScrollSkyMatrix (8); GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_DECAL); GL_BindTexture (GL_TEXTURE1_ARB, alphaskytexture); R_ScrollSkyMatrix (16); GL_IdentityMatrix (&skymatrix); GL_TranslateMatrix (&skymatrix, -r_origin[0], -r_origin[1], -r_origin[2]); GL_ScaleMatrix (&skymatrix, 65536, 65536, 65536); qglMultMatrixf (skymatrix.m16); GL_SetStreamSource (GLSTREAM_POSITION, 3, GL_FLOAT, sizeof (dpskyvert_t), r_dpskyverts->xyz); GL_SetStreamSource (GLSTREAM_COLOR, 0, GL_NONE, 0, NULL); GL_SetStreamSource (GLSTREAM_TEXCOORD0, 2, GL_FLOAT, sizeof (dpskyvert_t), r_dpskyverts->st); GL_SetStreamSource (GLSTREAM_TEXCOORD1, 2, GL_FLOAT, sizeof (dpskyvert_t), r_dpskyverts->st); GL_SetStreamSource (GLSTREAM_TEXCOORD2, 0, GL_NONE, 0, NULL); GL_SetIndices (r_dpskyindexes); GL_DrawIndexedPrimitive (GL_TRIANGLES, SKYSPHERE_NUMINDEXES, SKYSPHERE_NUMVERTS); GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_NONE); qglMatrixMode (GL_TEXTURE); qglLoadIdentity (); qglMatrixMode (GL_MODELVIEW); GL_ActiveTexture (GL_TEXTURE0_ARB); qglMatrixMode (GL_TEXTURE); qglLoadIdentity (); qglMatrixMode (GL_MODELVIEW); qglLoadMatrixf (r_world_matrix.m16); }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView (void) { // set the modelview matrix for the viewer qglMatrixMode(GL_PROJECTION); qglLoadMatrixf( backEnd.viewDef->projectionMatrix ); qglMatrixMode(GL_MODELVIEW); // set the window clipping qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1, tr.viewportOffset[1] + backEnd.viewDef->viewport.y1, backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1, backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 ); // the scissor may be smaller than the viewport for subviews qglScissor( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1, tr.viewportOffset[1] + backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1, backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1, backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 ); backEnd.currentScissor = backEnd.viewDef->scissor; // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); // we don't have to clear the depth / stencil buffer for 2D rendering if ( backEnd.viewDef->viewEntitys ) { qglStencilMask( 0xff ); // some cards may have 7 bit stencil buffers, so don't assume this // should be 128 qglClearStencil( 1<<(glConfig.stencilBits-1) ); qglClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); qglEnable( GL_DEPTH_TEST ); } else { qglDisable( GL_DEPTH_TEST ); qglDisable( GL_STENCIL_TEST ); } backEnd.glState.faceCulling = -1; // force face culling to set next time GL_Cull( CT_FRONT_SIDED ); }
/* ** RB_DrawSun */ void RB_DrawSun( void ) { float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { return; } qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * 0.4; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range qglDepthRange( 1.0, 1.0 ); // FIXME: use quad stamp RB_BeginSurface( tr.sunShader, tess.fogNum ); VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; #ifdef __MACOS__ int macEventTime; Sys_PumpEvents(); // crutch up the mac's limited buffer queue size // we don't want to pump the event loop too often and waste time, so // we are going to check every shader change macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC; #endif // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { #ifdef __MACOS__ // crutch up the mac's limited buffer queue size int t; t = ri.Milliseconds(); if ( t > macEventTime ) { macEventTime = t + MAC_EVENT_PUMP_MSEC; Sys_PumpEvents(); } #endif RB_EndSurface(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = qfalse; if ( entityNum != ENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } qglLoadMatrixf( backEnd.or.modelMatrix ); // // change depthrange if needed // if ( oldDepthRange != depthRange ) { if ( depthRange ) { qglDepthRange (0, 0.3); } else { qglDepthRange (0, 1); } oldDepthRange = depthRange; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); #ifdef __MACOS__ Sys_PumpEvents(); // crutch up the mac's limited buffer queue size #endif }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView (void) { int clearBits = 0; // sync with gl if needed if ( r_finish->integer == 1 && !glState.finishCalled ) { qglFinish (); glState.finishCalled = qtrue; } if ( r_finish->integer == 0 ) { glState.finishCalled = qtrue; } // we will need to change the projection matrix before drawing // 2D images again backEnd.projection2D = qfalse; // // set the modelview matrix for the viewer // SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); // clear relevant buffers clearBits = GL_DEPTH_BUFFER_BIT; if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) { clearBits |= GL_STENCIL_BUFFER_BIT; } if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used #ifdef _DEBUG qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f ); // FIXME: get color of sky #else qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky #endif } qglClear( clearBits ); if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); return; } else { backEnd.isHyperspace = qfalse; } glState.faceCulling = -1; // force face culling to set next time // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; qglLoadMatrixf( s_flipMatrix ); qglClipPlane (GL_CLIP_PLANE0, plane2); qglEnable (GL_CLIP_PLANE0); } else { qglDisable (GL_CLIP_PLANE0); } }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; int oldSort; float originalTime; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); // draw everything oldEntityNum = -1; backEnd.currentEntity = &tr.worldEntity; oldShader = NULL; oldFogNum = -1; oldDepthRange = qfalse; wasCrosshair = qfalse; oldDlighted = qfalse; oldSort = -1; depthRange = qfalse; backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { if ( drawSurf->sort == oldSort ) { // fast path, same as previous sort rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); continue; } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { if (oldShader != NULL) { RB_EndSurface(); } RB_BeginSurface( shader, fogNum ); oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; } // // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls depthRange = qtrue; if(backEnd.currentEntity->e.renderfx & RF_CROSSHAIR) isCrosshair = qtrue; } } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; backEnd.or = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } qglLoadMatrixf( backEnd.or.modelMatrix ); // // change depthrange. Also change projection matrix so first person weapon does not look like coming // out of the screen. // if (oldDepthRange != depthRange || wasCrosshair != isCrosshair) { if (depthRange) { if(backEnd.viewParms.stereoFrame != STEREO_CENTER) { if(isCrosshair) { if(oldDepthRange) { // was not a crosshair but now is, change back proj matrix qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } else { viewParms_t temp = backEnd.viewParms; R_SetupProjection(&temp, r_znear->value, qfalse); qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(temp.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } } if(!oldDepthRange) qglDepthRange (0, 0.3); } else { if(!wasCrosshair && backEnd.viewParms.stereoFrame != STEREO_CENTER) { qglMatrixMode(GL_PROJECTION); qglLoadMatrixf(backEnd.viewParms.projectionMatrix); qglMatrixMode(GL_MODELVIEW); } qglDepthRange (0, 1); } oldDepthRange = depthRange; wasCrosshair = isCrosshair; } oldEntityNum = entityNum; } // add the triangles for this surface rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); } backEnd.refdef.floatTime = originalTime; // draw the contents of the last shader batch if (oldShader != NULL) { RB_EndSurface(); } // go back to the world modelview matrix qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); if ( depthRange ) { qglDepthRange (0, 1); } #if 0 RB_DrawSun(); #endif // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); }
/* ================== RB_RenderDrawSurfList ================== */ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { shader_t *shader, *oldShader; int fogNum, oldFogNum; int entityNum, oldEntityNum; int dlighted, oldDlighted; 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_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView( void ) { int clearBits = 0; // sync with gl if needed if ( r_finish->integer == 1 && !glState.finishCalled ) { qglFinish(); glState.finishCalled = qtrue; } if ( r_finish->integer == 0 ) { glState.finishCalled = qtrue; } // we will need to change the projection matrix before drawing // 2D images again backEnd.projection2D = qfalse; // // set the modelview matrix for the viewer // SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); ////////// (SA) modified to ensure one glclear() per frame at most // clear relevant buffers clearBits = 0; if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) { clearBits |= GL_STENCIL_BUFFER_BIT; } if ( r_uiFullScreen->integer ) { clearBits = GL_DEPTH_BUFFER_BIT; // (SA) always just clear depth for menus } else if ( skyboxportal ) { if ( backEnd.refdef.rdflags & RDF_SKYBOXPORTAL ) { // portal scene, clear whatever is necessary clearBits |= GL_DEPTH_BUFFER_BIT; if ( r_fastsky->integer || backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { // fastsky: clear color // try clearing first with the portal sky fog color, then the world fog color, then finally a default clearBits |= GL_COLOR_BUFFER_BIT; if ( glfogsettings[FOG_PORTALVIEW].registered ) { qglClearColor( glfogsettings[FOG_PORTALVIEW].color[0], glfogsettings[FOG_PORTALVIEW].color[1], glfogsettings[FOG_PORTALVIEW].color[2], glfogsettings[FOG_PORTALVIEW].color[3] ); } else if ( glfogNum > FOG_NONE && glfogsettings[FOG_CURRENT].registered ) { qglClearColor( glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3] ); } else { // qglClearColor ( 1.0, 0.0, 0.0, 1.0 ); // red clear for testing portal sky clear qglClearColor( 0.5, 0.5, 0.5, 1.0 ); } } else { // rendered sky (either clear color or draw quake sky) if ( glfogsettings[FOG_PORTALVIEW].registered ) { qglClearColor( glfogsettings[FOG_PORTALVIEW].color[0], glfogsettings[FOG_PORTALVIEW].color[1], glfogsettings[FOG_PORTALVIEW].color[2], glfogsettings[FOG_PORTALVIEW].color[3] ); if ( glfogsettings[FOG_PORTALVIEW].clearscreen ) { // portal fog requests a screen clear (distance fog rather than quake sky) clearBits |= GL_COLOR_BUFFER_BIT; } } } } else { // world scene with portal sky, don't clear any buffers, just set the fog color if there is one clearBits |= GL_DEPTH_BUFFER_BIT; // this will go when I get the portal sky rendering way out in the zbuffer (or not writing to zbuffer at all) if ( glfogNum > FOG_NONE && glfogsettings[FOG_CURRENT].registered ) { if ( backEnd.refdef.rdflags & RDF_UNDERWATER ) { if ( glfogsettings[FOG_CURRENT].mode == GL_LINEAR ) { clearBits |= GL_COLOR_BUFFER_BIT; } } else if ( !( r_portalsky->integer ) ) { // portal skies have been manually turned off, clear bg color clearBits |= GL_COLOR_BUFFER_BIT; } qglClearColor( glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3] ); } } } else { // world scene with no portal sky clearBits |= GL_DEPTH_BUFFER_BIT; // NERVE - SMF - we don't want to clear the buffer when no world model is specified if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { clearBits &= ~GL_COLOR_BUFFER_BIT; } // -NERVE - SMF // (SA) well, this is silly then else if ( r_fastsky->integer ) { // || backEnd.refdef.rdflags & RDF_NOWORLDMODEL clearBits |= GL_COLOR_BUFFER_BIT; if ( glfogsettings[FOG_CURRENT].registered ) { // try to clear fastsky with current fog color qglClearColor( glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3] ); } else { // qglClearColor ( 0.0, 0.0, 1.0, 1.0 ); // blue clear for testing world sky clear qglClearColor( 0.5, 0.5, 0.5, 1.0 ); } } else { // world scene, no portal sky, not fastsky, clear color if fog says to, otherwise, just set the clearcolor if ( glfogsettings[FOG_CURRENT].registered ) { // try to clear fastsky with current fog color qglClearColor( glfogsettings[FOG_CURRENT].color[0], glfogsettings[FOG_CURRENT].color[1], glfogsettings[FOG_CURRENT].color[2], glfogsettings[FOG_CURRENT].color[3] ); if ( glfogsettings[FOG_CURRENT].clearscreen ) { // world fog requests a screen clear (distance fog rather than quake sky) clearBits |= GL_COLOR_BUFFER_BIT; } } } } if ( clearBits ) { qglClear( clearBits ); } //----(SA) done if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); return; } else { backEnd.isHyperspace = qfalse; } glState.faceCulling = -1; // force face culling to set next time // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct( backEnd.viewParms.or.axis[0], plane ); plane2[1] = DotProduct( backEnd.viewParms.or.axis[1], plane ); plane2[2] = DotProduct( backEnd.viewParms.or.axis[2], plane ); plane2[3] = DotProduct( plane, backEnd.viewParms.or.origin ) - plane[3]; qglLoadMatrixf( s_flipMatrix ); qglClipPlane( GL_CLIP_PLANE0, plane2 ); qglEnable( GL_CLIP_PLANE0 ); } else { qglDisable( GL_CLIP_PLANE0 ); } }
void R_DrawAliasShadows (entity_t **ents, int numents, void *meshbuffer) { if (r_shadows.value > 0.01f) { int i; qbool stateset = false; byte shadecolor[4] = {0, 0, 0, 128}; // extern int gl_stencilbits; for (i = 0; i < numents; i++) { entity_t *ent = ents[i]; glmatrix eshadow; if (!(ent->model->flags & MOD_NOSHADOW)) { aliasstate_t *state = &ent->aliasstate; aliashdr_t *hdr = Mod_Extradata (ent->model); float lheight = state->origin[2] - state->lightspot[2]; if (!stateset) { float *mesh = (float *) meshbuffer; qglDepthMask (GL_FALSE); qglEnable (GL_BLEND); GL_TexEnv (GL_TEXTURE1_ARB, GL_TEXTURE_2D, GL_NONE); GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_NONE); qglColor4f (0, 0, 0, r_shadows.value); shadecolor[3] = BYTE_CLAMPF (r_shadows.value); /* if (gl_stencilbits) { qglEnable (GL_STENCIL_TEST); qglStencilFunc (GL_EQUAL, 1, 2); qglStencilOp (GL_KEEP, GL_KEEP, GL_INCR); } */ GL_SetStreamSource (GLSTREAM_POSITION, 3, GL_FLOAT, sizeof (float) * 4, mesh); GL_SetStreamSource (GLSTREAM_COLOR, 4, GL_UNSIGNED_BYTE, sizeof (float) * 4, &mesh[3]); GL_SetStreamSource (GLSTREAM_TEXCOORD0, 0, GL_NONE, 0, NULL); GL_SetStreamSource (GLSTREAM_TEXCOORD1, 0, GL_NONE, 0, NULL); GL_SetStreamSource (GLSTREAM_TEXCOORD2, 0, GL_NONE, 0, NULL); stateset = true; } GL_LoadMatrix (&eshadow, &r_world_matrix); if (state->origin[0] || state->origin[1] || state->origin[2]) GL_TranslateMatrix (&eshadow, state->origin[0], state->origin[1], state->origin[2]); GL_TranslateMatrix (&eshadow, 0, 0, -lheight); GL_MultiplyMatrix (&eshadow, &shadowmatrix, &eshadow); GL_TranslateMatrix (&eshadow, 0, 0, lheight); if (state->angles[1]) GL_RotateMatrix (&eshadow, state->angles[1], 0, 0, 1); GL_TranslateMatrix (&eshadow, hdr->scale_origin[0], hdr->scale_origin[1], hdr->scale_origin[2]); GL_ScaleMatrix (&eshadow, hdr->scale[0], hdr->scale[1], hdr->scale[2]); qglLoadMatrixf (eshadow.m16); R_DrawAliasShadow (ent, hdr, state, (float *) meshbuffer, (float *) shadecolor); } } if (stateset) { /* if (gl_stencilbits) qglDisable (GL_STENCIL_TEST); */ GL_TexEnv (GL_TEXTURE0_ARB, GL_TEXTURE_2D, GL_REPLACE); qglDisable (GL_BLEND); qglDepthMask (GL_TRUE); qglColor4f (1, 1, 1, 1); qglLoadMatrixf (r_world_matrix.m16); } } }
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); }