2016-04-02 12:43:55 +00:00
|
|
|
//renderframe.cpp
|
|
|
|
//renders one graphics frame
|
|
|
|
|
|
|
|
#include <OpenGL/gl.h>
|
|
|
|
#include <math.h>
|
|
|
|
#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"
|
|
|
|
|
2016-04-04 21:17:52 +00:00
|
|
|
#include "mVertex.h"
|
|
|
|
|
2016-04-02 12:43:55 +00:00
|
|
|
#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;i<kNumClipPlanes;i++)
|
|
|
|
{
|
|
|
|
clipPlanes[i]=clipPlanes[i]*camera->dir;
|
|
|
|
}
|
|
|
|
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;plane<kNumClipPlanes;plane++)
|
|
|
|
if(relPoint*clipPlanes[plane]<0)
|
|
|
|
clip+=1<<plane;
|
|
|
|
|
|
|
|
relPoint=relPoint-clipPlanes[kClipFarPoint];
|
|
|
|
|
|
|
|
if(relPoint*clipPlanes[kClipRearPlane]>0)
|
|
|
|
clip+=1<<kClipFarPoint;
|
|
|
|
|
|
|
|
return clip;
|
|
|
|
}
|
|
|
|
|
|
|
|
//tests if the a point is inside the clipping volume given by clipPlanes,
|
|
|
|
//or within distance of it (useful as the objects we want to clip are usually bigger
|
|
|
|
//than a single point in space)
|
|
|
|
int ClipPointDistanced(tVector3 *clipPlanes,tVector3 *point,float distance)
|
|
|
|
{
|
|
|
|
if(!gClipEnable)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
tVector3 relPoint=*point-clipPlanes[kClipBasePoint];
|
|
|
|
int clip=0;
|
|
|
|
|
|
|
|
for(int plane=kClipRearPlane;plane<kNumClipPlanes;plane++)
|
|
|
|
if(relPoint*clipPlanes[plane]<-distance)
|
|
|
|
clip+=1<<plane;
|
|
|
|
|
|
|
|
relPoint=relPoint-clipPlanes[kClipFarPoint];
|
|
|
|
|
|
|
|
if(relPoint*clipPlanes[kClipRearPlane]>distance)
|
|
|
|
clip+=1<<kClipFarPoint;
|
|
|
|
|
|
|
|
return clip;
|
|
|
|
}
|
|
|
|
|
|
|
|
//swap the position of two entities in the gmae entity list
|
|
|
|
void SwitchEntities(tGameEntity* obj1,tGameEntity* obj2)
|
|
|
|
{
|
|
|
|
((tGameEntity*)obj1->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->zDist<entity->zDist)
|
|
|
|
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)<sqr(1.5))
|
|
|
|
break;
|
|
|
|
int drawInterior=drawEntity==gViewedEntity;
|
|
|
|
float clipInteriorDist=gConfig->gfxDynamics*200.0f;
|
|
|
|
if(drawEntity->zDist<clipInteriorDist)
|
|
|
|
drawInterior=true;
|
|
|
|
if(!gConfig->interiorDisplay)
|
|
|
|
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;i<gGameInfo->numPlayers;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)<sqr(30))==highQual)
|
|
|
|
{
|
|
|
|
int shad=true;
|
|
|
|
if(drawEntity->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->zDist<ClipDistance()-distance)
|
|
|
|
if(!ClipPointDistanced(clipPlanes,&drawEntity->pos,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;i<gMapInfo->numVisWalls;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));
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv(((gMapInfo->visWalls[i].c+(gMapInfo->visWalls[i].b-gMapInfo->visWalls[i].a))));
|
2016-04-02 12:43:55 +00:00
|
|
|
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;
|
|
|
|
}
|