//renderframe.cpp //renders one graphics frame #include #include #include "entities.h" #include "environment.h" #include "fileio.h" #include "sky.h" #include "models.h" #include "roads.h" #include "text.h" #include "screen.h" #include "renderframe.h" #include "rendercar.h" #include "particles.h" #include "tracks.h" #include "stencil.h" #include "config.h" #include "transparency.h" #include "gamemem.h" #include "collision.h" #include "gameinitexit.h" #include "carphysics.h" #include "random.h" #include "gameframe.h" #include "textures.h" #include "lights.h" #include "mVertex.h" #ifdef __POLYCOUNT int gPolyCount; #endif int gCameraMode,gCameraReverse,gClipEnable=true; tMatrix3 gTransformDir; tVector3 gTransformPos; void Beer(tMatrix4 m) { MatrixRotX(m,0.1*sin(gFrameCount*0.01)); MatrixRotY(m,0.02*sin(gFrameCount*0.1)); MatrixRotZ(m,0.3*sin(gFrameCount*0.008)); MatrixScale(m,1+0.1*sin(gFrameCount*0.01),1+0.4*cos(gFrameCount*0.001),1-0.15*sin(gFrameCount*0.02)); tMatrix4 mt; MatrixIdentity(mt); MatrixRotX(mt,0.01*sin(gFrameCount*0.01)); MatrixRotY(mt,0.002*sin(gFrameCount*0.1)); MatrixRotZ(mt,0.03*sin(gFrameCount*0.008)); glMatrixMode(GL_TEXTURE); glLoadMatrixf((float*)mt); glMatrixMode(GL_MODELVIEW); } //Set up the Modelview matrix to draw the object at objPos, rotated by objDir void SetupTranslation(tVector3 objPos,tMatrix3 objDir) { tMatrix4 m1,m2; tMatrix3 m,r,invTransformDir; MatrixIdentity(m1); MatrixMult(m1,objDir,m2); MatrixTranslateVector(m2,objPos-gCameraEntity->pos); MatrixTranspose(gCameraEntity->dir,m); r[0][0]=-1;r[0][1]=0;r[0][2]=0; r[1][0]=0; r[1][1]=1;r[1][2]=0; r[2][0]=0; r[2][1]=0;r[2][2]=-1; MatrixMult(m,r,m); MatrixMult(m2,m,m1); #ifndef __TARGET_TOOLAPP if(gGameInfo) if(gGameInfo->carsOnSpeed) Beer(m1); #endif glLoadMatrixf((float*)m1); MatrixCopy(objDir,gTransformDir); gTransformPos=objPos; MatrixTranspose(objDir,invTransformDir); GLfloat globalLightPosition[4]; *(tVector3*)globalLightPosition=gEnvironment->lightDir*invTransformDir; if(gMapEnv) if(!VectorZero(gMapEnv->lightDir)) *(tVector3*)globalLightPosition=gMapEnv->lightDir*invTransformDir; globalLightPosition[3]=0; glLightfv(GL_LIGHT0,GL_POSITION,globalLightPosition); if(gViewedEntity) { float objDist=~(objPos-gViewedEntity->pos); if(objDist==0) gShineFactor=0; else { gShineFactor=(objPos-gViewedEntity->pos)*(1/objDist)**MatrixGetZVector(gViewedEntity->dir); // gShineFactor=sqr(sqr(sqr(sqr(gShineFactor))))*gShineFactor; if(objDist>100) gShineFactor-=(objDist-100)*0.005; if(gShineFactor<0)gShineFactor=0; } } } //Set up the Modelview matrix to draw objects at world coordinates void SetupWorldTranslation() { tMatrix4 m1,m2; tMatrix3 m,r; MatrixIdentity(m1); MatrixTranslateVector(m1,-gCameraEntity->pos); MatrixTranspose(gCameraEntity->dir,m); r[0][0]=-1;r[0][1]=0;r[0][2]=0; r[1][0]=0; r[1][1]=1;r[1][2]=0; r[2][0]=0; r[2][1]=0;r[2][2]=-1; MatrixMult(m,r,m); MatrixMult(m1,m,m2); #ifndef __TARGET_TOOLAPP if(gGameInfo) if(gGameInfo->carsOnSpeed) Beer(m2); #endif glLoadMatrixf((float*)m2); GLfloat globalLightPosition[4]; *(tVector3*)globalLightPosition=gEnvironment->lightDir; if(gMapEnv) if(!VectorZero(gMapEnv->lightDir)) *(tVector3*)globalLightPosition=gMapEnv->lightDir; globalLightPosition[3]=0; glLightfv(GL_LIGHT0,GL_POSITION,globalLightPosition); MatrixIdentity(gTransformDir); gTransformPos=Vector(0,0,0); } //calculates the clipping planes from the camera position and rotation void SetupClipPlanes(tGameEntity *camera,tVector3 *clipPlanes) { clipPlanes[kClipBasePoint]=Vector(0,0,-kClipSaveDistance); clipPlanes[kClipFarPoint]=Vector(0,0,ClipDistance()-kClipSaveDistance); clipPlanes[kClipXPlane]=Vector(1,0,0); clipPlanes[kClipYPlane]=Vector(0,1,0); clipPlanes[kClipRearPlane]=Vector(0,0,1); clipPlanes[kClipRightPlane]=Vector(-cos(gFOVX*0.5),0,sin(gFOVX*0.5)); clipPlanes[kClipLeftPlane]=Vector(-clipPlanes[kClipRightPlane].x,0,clipPlanes[kClipRightPlane].z); clipPlanes[kClipTopPlane]=Vector(0,cos(gFOVY*0.5),sin(gFOVY*0.5)); clipPlanes[kClipBotPlane]=Vector(0,-clipPlanes[kClipTopPlane].y,clipPlanes[kClipTopPlane].z); for(int i=0;idir; } clipPlanes[kClipBasePoint]=clipPlanes[kClipBasePoint]+camera->pos; } //tests if the a point is inside the clipping volume given by clipPlanes int ClipPoint(tVector3 *clipPlanes,tVector3 *point) { if(!gClipEnable) return false; tVector3 relPoint=*point-clipPlanes[kClipBasePoint]; int clip=0; for(int plane=kClipRearPlane;plane0) clip+=1<distance) clip+=1<prev)->next=obj2; ((tGameEntity*)obj2->next)->prev=obj1; obj1->next=obj2->next; obj2->prev=obj1->prev; obj1->prev=obj2; obj2->next=obj1; } void SortEntities() { tGameEntity *entity=(tGameEntity*)gFirstEntity->next; while(entity!=gFirstEntity) { if(entity->renderType==kRenderTypeModel||entity->renderType==kRenderTypeCar||entity->renderType==kRenderTypeGhost) { tVector3 center=ModelGetCenter(entity->renderData); center=center*entity->dir; center=center+entity->pos; entity->zDist=(center-gCameraEntity->pos)**MatrixGetZVector(gCameraEntity->dir); } else entity->zDist=(entity->pos-gCameraEntity->pos)**MatrixGetZVector(gCameraEntity->dir); entity=(tGameEntity*)entity->next; } tGameEntity *start=(tGameEntity*)gFirstEntity->next; tGameEntity *end=gFirstEntity; int change; do{ //since in most cases there wont be much change a shaking sort is often the fastest entity=start; change=false; while(entity->next!=end) { tGameEntity *next=(tGameEntity*)entity->next; if(next->zDist>entity->zDist) {SwitchEntities(entity,next);change=true;} else entity=next; } if(change) { end=(tGameEntity*)end->prev; entity=end; while(entity->prev!=start) { tGameEntity *prev=(tGameEntity*)entity->prev; if(prev->zDistzDist) SwitchEntities(prev,entity); else entity=prev; } start=(tGameEntity*)start->next; if(start==end) change=false; } }while(change); } void RenderObjectPass(tVector3 *clipPlanes) { glPushAttrib(GL_LIGHTING_BIT+GL_TEXTURE_BIT+GL_POLYGON_BIT+GL_COLOR_BUFFER_BIT); tGameEntity *drawEntity=(tGameEntity*)gFirstEntity->prev; while(drawEntity!=gFirstEntity) { if(drawEntity->renderType==kRenderTypeModel||drawEntity->renderType==kRenderTypeCar||drawEntity->renderType==kRenderTypeGhost) { float distance=ModelGetCenterMaxExtends(drawEntity->renderData); tVector3 center=ModelGetCenter(drawEntity->renderData); center=center*drawEntity->dir; center=center+drawEntity->pos; if(drawEntity->zDist>-distance||!gClipEnable) if(!ClipPointDistanced(clipPlanes,¢er,distance)) { SetupTranslation(drawEntity->pos,drawEntity->dir); switch(drawEntity->renderType) { case kRenderTypeModel: DrawModel(drawEntity->renderData,true,*((int*)drawEntity->physics)); break; case kRenderTypeCar: { if(gCameraMode==kCameraCockpitCarHidden&&drawEntity==gCarEntities[gReplayViewedEntityID]&&sqr(gCameraEntity->pos-drawEntity->pos)gfxDynamics*200.0f; if(drawEntity->zDistinteriorDisplay) drawInterior=false; CarRenderEntity(drawEntity,drawInterior,drawEntity->controlType!=kControlTypeNone&&!(drawEntity==gViewedEntity&&gCameraMode==kCameraCockpit)); if(gConfig->showPlayerNames&&gGameInfo->network&&(drawEntity!=gCarEntities[gReplayViewedEntityID])) { tVector3 pos=drawEntity->pos+Vector(0,3,0); pos=pos-gCameraEntity->pos; tMatrix3 inv; MatrixTranspose(gCameraEntity->dir,inv); pos=pos*inv; float size=0.8+pos.z*0.005; for(int i=0;inumPlayers;i++) if(gCarEntities[i]==drawEntity) TextPrintfToBufferFormatedVector3(pos,size,kTextAlignMiddle,gGameInfo->playerNames[i]); } } break; case kRenderTypeGhost: if(!gConfig->noGhost) CarRenderEntityGhost(drawEntity); break; } } } drawEntity=(tGameEntity*)drawEntity->prev; } glPopAttrib(); } #define kEntMinShadow 6 void RenderShadowPass(tVector3 *clipPlanes,int highQual) { glPushAttrib(GL_ENABLE_BIT+GL_POLYGON_BIT); tGameEntity *drawEntity=(tGameEntity*)gFirstEntity->next; while(drawEntity!=gFirstEntity&&drawEntity->zDist>-200) { if(gConfig->gfxDynamics>=0.2||drawEntity==gViewedEntity) if(drawEntity->renderType==kRenderTypeModel||drawEntity->renderType==kRenderTypeCar) if((sqr(drawEntity->pos-gCameraEntity->pos)renderType==kRenderTypeModel) if(drawEntity->physicsType!=kPhysicsTypeSolid) shad=false; else { tSolidEntityPhysics *ent=(tSolidEntityPhysics*)gFileTable[drawEntity->physicsData].parsedData; if(ent->shadowModel==kFileErr) shad=false; } if(shad) { float shadowLength=GetGroundOffset(drawEntity->pos,&drawEntity->lastRoadIndex,0,0)+kEntMinShadow; shadowLength/=gEnvironment->lightDir.y; float distance=ModelGetMaxExtends(drawEntity->renderData)+shadowLength; if(drawEntity->zDist>-distance&&drawEntity->zDistpos,distance)) { SetupTranslation(drawEntity->pos,drawEntity->dir); switch(drawEntity->renderType) { case kRenderTypeCar: if(gCameraMode!=kCameraCockpitCarHidden||drawEntity!=gCarEntities[gReplayViewedEntityID]) CarRenderEntityShadow(drawEntity,0); break; case kRenderTypeModel: tSolidEntityPhysics *ent=(tSolidEntityPhysics*)gFileTable[drawEntity->physicsData].parsedData; DrawModelShadow(ent->shadowModel,shadowLength); break; } } } } drawEntity=(tGameEntity*)drawEntity->next; } glPopAttrib(); } #define kLightConeClip 200 void RenderLightConesPass(tVector3 *clipPlanes) { tGameEntity *drawEntity=(tGameEntity*)gFirstEntity->next; while(drawEntity!=gFirstEntity&&drawEntity->zDist>-25) { if(!ClipPointDistanced(clipPlanes,&drawEntity->pos,kLightConeClip)) { switch(drawEntity->renderType) { case kRenderTypeCar: if(drawEntity==gViewedEntity) { tCarPhysics *phys=(tCarPhysics*)drawEntity->physics; tCarDefinition *car=&(phys->car); RenderEntityLightCones(drawEntity,car->numLights,phys->lightFlags,car->lights); } break; case kRenderTypeModel: if(drawEntity->physicsType==kPhysicsTypeSolid) { tSolidEntityPhysics *ent=(tSolidEntityPhysics*)gFileTable[drawEntity->physicsData].parsedData; RenderEntityLightCones(drawEntity,ent->numLights,0xffff,ent->lights); } break; } } drawEntity=(tGameEntity*)drawEntity->next; } } void RenderLightsPass(tVector3 *clipPlanes) { gTexturesQualityModifier=-255; tGameEntity *drawEntity=(tGameEntity*)gFirstEntity->next; while(drawEntity!=gFirstEntity) { SetupTranslation(drawEntity->pos,drawEntity->dir); switch(drawEntity->renderType) { case kRenderTypeCar:{ tCarPhysics *phys=(tCarPhysics*)drawEntity->physics; tCarDefinition *car=&(phys->car); RenderEntityLights(drawEntity,car->numLights,phys->lightFlags,phys->echo,car->lights); }break; case kRenderTypeModel: if(drawEntity->physicsType==kPhysicsTypeSolid) { int objFrameCount=gFrameCount+10*((drawEntity->id*31)%17); int allLightEnable=gEnvironment->spotLightEnable; if(gMapEnv) if(gMapEnv->lightEnable) allLightEnable=true; int objLightFlags=0x1 |(((int)(objFrameCount/(2*kFPS))%2)?0x2:0) |(((int)(objFrameCount/(1*kFPS))%2)?0x4:0) |(((int)(objFrameCount/(0.5*kFPS))%2)?0x8:0) |(((int)(objFrameCount/(0.3*kFPS))%4)?0:0x10) |(allLightEnable?0x20:0); tSolidEntityPhysics *ent=(tSolidEntityPhysics*)gFileTable[drawEntity->physicsData].parsedData; RenderEntityLights(drawEntity,ent->numLights,objLightFlags,0,ent->lights); } break; } drawEntity=(tGameEntity*)drawEntity->next; } gTexturesQualityModifier=0; } void SetupLighting() { if(gCameraEntity) SetupWorldTranslation(); GLfloat globalLightAmbient[4]; *(tVector3*)globalLightAmbient=gEnvironment->ambient; globalLightAmbient[3]=1; GLfloat globalLightDiffuse[4]; *(tVector3*)globalLightDiffuse=gEnvironment->diffuse; globalLightDiffuse[3]=1; GLfloat globalLightSpecular[4]; *(tVector3*)globalLightSpecular=gEnvironment->specular; globalLightSpecular[3]=1; GLfloat globalLightPosition[4]; *(tVector3*)globalLightPosition=gEnvironment->lightDir; if(gMapEnv) if(!VectorZero(gMapEnv->lightDir)) *(tVector3*)globalLightPosition=gMapEnv->lightDir; globalLightPosition[3]=0; if(gLightning) { globalLightAmbient[0]=1; globalLightAmbient[1]=1; globalLightAmbient[2]=1; globalLightDiffuse[0]=1; globalLightDiffuse[1]=1; globalLightDiffuse[2]=1; globalLightSpecular[0]=1; globalLightSpecular[1]=1; globalLightSpecular[2]=1; } glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0,GL_AMBIENT,globalLightAmbient); glLightfv(GL_LIGHT0,GL_DIFFUSE,globalLightDiffuse); glLightfv(GL_LIGHT0,GL_SPECULAR,globalLightSpecular); glLightfv(GL_LIGHT0,GL_POSITION,globalLightPosition); if(gMapEnv) if(gMapEnv->fogBegin) { GLfloat fogColor[4]; *(tVector3*)fogColor=gMapEnv->fogColor; fogColor[3]=1; glFogfv(GL_FOG_COLOR,fogColor); glFogf(GL_FOG_START,gMapEnv->fogBegin*(1+0.3*gMapEnv->fogOscillation*sin(gFrameCount*kFrameTime*0.7*gMapEnv->fogOscillationSpeed))); glFogf(GL_FOG_END,gMapEnv->fogEnd*(1+0.5*gMapEnv->fogOscillation*sin(gFrameCount*kFrameTime*0.3*gMapEnv->fogOscillationSpeed))); } } void DrawFlare(tFileRef texture,float x,float y,float size,float alpha) { glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_TEXTURE_BIT+GL_CURRENT_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_ONE,GL_ONE); glLoadIdentity(); glTranslatef(0.0f,0.0f,-1.0f); glTranslatef(x,y,0); glScalef(size*0.5,size*0.5,0); glColor4f(1,1,1,alpha); TexturesSelectTex(texture); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); glBegin(GL_TRIANGLE_STRIP); glTexCoord2d(1,1); glVertex2f(1,-1); glTexCoord2d(1,0); glVertex2f(1,1); glTexCoord2d(0,1); glVertex2f(-1,-1); glTexCoord2d(0,0); glVertex2f(-1,1); glEnd(); glPopAttrib(); } void FlaresDraw1() { if(gEnvironment->flaresEnable) { tMatrix3 cameraInverse; MatrixTranspose(gCameraEntity->dir,cameraInverse); tVector3 flarePos=gEnvironment->flareDir*cameraInverse; if(gMapEnv) if(!VectorZero(gMapEnv->flareDir)) flarePos=gMapEnv->flareDir*cameraInverse; if(flarePos.z<=0)return; tVector2 flarePosProjected=Vector(flarePos.x/flarePos.z,-flarePos.y/flarePos.z); DrawFlare(FileGetReference("flare1.tif"),-flarePosProjected.x*0.5,-flarePosProjected.y*0.5,0.6,1.0); } } void FlaresDraw2() { if(gEnvironment->flaresEnable) { tMatrix3 cameraInverse; MatrixTranspose(gCameraEntity->dir,cameraInverse); tVector3 flarePos=gEnvironment->flareDir*cameraInverse; if(gMapEnv) if(!VectorZero(gMapEnv->flareDir)) flarePos=gMapEnv->flareDir*cameraInverse; if(flarePos.z<=0)return; tVector2 flarePosProjected=Vector(flarePos.x/flarePos.z,-flarePos.y/flarePos.z); DrawFlare(FileGetReference("flare5.tif"),flarePosProjected.x*1.5,flarePosProjected.y*1.5,0.6,1.0); DrawFlare(FileGetReference("flare4.tif"),flarePosProjected.x*0.5,flarePosProjected.y*0.5,0.6,1.0); DrawFlare(FileGetReference("flare3.tif"),flarePosProjected.x*0.25,flarePosProjected.y*0.25,0.6,1.0); DrawFlare(FileGetReference("flare2.tif"),-flarePosProjected.x*0.1,-flarePosProjected.y*0.1,0.6,1.0); } } void GameShowInfo(); void RenderVisWalls() { SetupWorldTranslation(); glColorMask(0,0,0,0); glDisable(GL_CULL_FACE); for(int i=0;inumVisWalls;i++) { glBegin(GL_TRIANGLES); glVertex3fv(&(gMapInfo->visWalls[i].a.x)); glVertex3fv(&(gMapInfo->visWalls[i].b.x)); glVertex3fv(&(gMapInfo->visWalls[i].c.x)); glVertex3fv(&(gMapInfo->visWalls[i].b.x)); glVertex3fv(&(gMapInfo->visWalls[i].c.x)); mVertex3fv(((gMapInfo->visWalls[i].c+(gMapInfo->visWalls[i].b-gMapInfo->visWalls[i].a)))); glEnd(); } glEnable(GL_CULL_FACE); glColorMask(1,1,1,1); } int gLastFrameBlur=false; int gLastGraphFrame=0; #define kMaxBlur 0.925 void MotionBlur() { float blur; if(gConfig->carsOnSpeed) //blur=0.9+0.25*sin(gFrameCount*kFrameTime*0.2); blur=1; else { if(!gConfig->motionBlur) return; blur=((~gCameraEntity->velo-30)/55.0); } int blurExp=gFrameCount-gLastGraphFrame-1; if(blurExp>10)blurExp=10; if(blurExp<0)blurExp=0; blur*=pow(kMaxBlur,blurExp); if(blur>0&&(gGameInfo->arcade==kGameModeArcade||gGameInfo->arcade==kGameModeTurbo||gConfig->carsOnSpeed)&&gConfig->motionBlur) { if(blur>1) blur=1; glPushAttrib(GL_ENABLE_BIT+GL_CURRENT_BIT); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glLoadIdentity(); glColor4f(1,1,1,kMaxBlur*blur); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0,gConfig->screenXSize,0,gConfig->screenYSize,-1,2); for(int i=0;i<4;i++) if(gScreenTextures[i].xSize) { glBindTexture(GL_TEXTURE_2D,gScreenTextures[i].texture); if(gLastFrameBlur) { glBegin(GL_TRIANGLE_STRIP); glTexCoord2d(1,1); glVertex3f(gScreenTextures[i].xSize+gScreenTextures[i].xOffset, gScreenTextures[i].ySize+gScreenTextures[i].yOffset,1); glTexCoord2d(1,0); glVertex3f(gScreenTextures[i].xSize+gScreenTextures[i].xOffset, gScreenTextures[i].yOffset,1); glTexCoord2d(0,1); glVertex3f(0+gScreenTextures[i].xOffset, gScreenTextures[i].ySize+gScreenTextures[i].yOffset,1); glTexCoord2d(0,0); glVertex3f(0+gScreenTextures[i].xOffset, gScreenTextures[i].yOffset,1); glEnd(); } glCopyTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,gScreenTextures[i].xOffset,gScreenTextures[i].yOffset,gScreenTextures[i].xSize,gScreenTextures[i].ySize,0); } glPopMatrix(); glPopAttrib(); glMatrixMode(GL_MODELVIEW); gLastFrameBlur=true; } else gLastFrameBlur=false; } void RenderFrame(int screenUpdate) { #ifdef __POLYCOUNT gPolyCount=0; #endif //gClipEnable=false; // SetupAspect(kNormalFOVY+~gCameraEntity->velo*0.002*gGameInfo->arcade); float fov=1.0; if(gGameInfo->arcade==kGameModeArcade||gGameInfo->arcade==kGameModeTurbo) fov+=~gCameraEntity->velo*0.0015*(gGameInfo->arcade+1); if(fov>1.6)fov=1.6; SetupAspect(fov); tVector3 clipPlanes[kNumClipPlanes]; SetupClipPlanes(gCameraEntity,clipPlanes); SetupLighting(); SkyRender(); FlaresDraw1(); RenderVisWalls(); SortEntities(); RenderObjectPass(clipPlanes); //first pass: objects if(!gMapInfo->dontDrawRoad) RoadRender(clipPlanes); TracksRender(clipPlanes); if(gConfig->stencil)//second pass: shadows/light Cones { int stencil=4.0f*gConfig->gfxDynamics; if(stencil<=0) stencil=1; if(gEnvironment->shadowEnable) { for(int i=1;i<=stencil;i++) { gStencilZoom=0.9+0.1*i/(float)(stencil); RenderShadowPass(clipPlanes,true); RenderStencilLayer(true,stencil); } gStencilZoom=1.0; RenderShadowPass(clipPlanes,false); RenderStencilLayer(true,1); } if(gEnvironment->spotLightEnable) { for(int i=1;i<=stencil*1.5;i++) { gStencilZoom=0.75+0.25*i/((float)stencil*1.5); RenderLightConesPass(clipPlanes); RenderStencilLayer(false,stencil); } } } DrawTransparentPolys(clipPlanes);//third pass: transparent stuff RenderLightsPass(clipPlanes); //fourth pass: lights ParticlesDraw(); SetupAspect(kNormalFOVY); FlaresDraw2(); if(!gBackgroundReplay) { GameShowInfo(); MotionBlur(); if(screenUpdate) ScreenBlit(); } gLastGraphFrame=gFrameCount; }