Redline/source/rendercar.cpp
maride 02061d74c2 Original 1.0.5 code
(as received from Jonas Echterhoff)
2016-04-02 14:43:55 +02:00

669 lines
22 KiB
C++
Executable File

//rendercar.cpp
//code to render a car
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <math.h>
#include "carphysics.h"
#include "vectors.h"
#include "models.h"
#include "entities.h"
#include "fileio.h"
#include "textures.h"
#include "renderframe.h"
#include "screen.h"
#include "collision.h"
#include "environment.h"
#include "text.h"
#include "config.h"
#include "gameinitexit.h"
#include "roads.h"
#include "rendercar.h"
#include "gameframe.h"
#include "config.h"
#include "transparency.h"
#include "stencil.h"
#include "random.h"
#define sign(x) ((x)<0?-1:1)
#define kCarMinShadow 3
void RenderGauge(tGauge *gauge,float value,float xPos,float yPos,float size,float opacity,float redline)
{
gTexturesQualityModifier=-255;
glPushMatrix();
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_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
glColor4f(gEnvironment->instrumentColor.x,gEnvironment->instrumentColor.y,gEnvironment->instrumentColor.z,opacity*(1-gConfig->hudTransparency));
glTranslatef(xPos,yPos,0);
glScalef(size*0.5,size*0.5,0);
if(redline)
{
float redlineAngle=(gauge->gaugeZero-2*gauge->gaugeZero*(redline/gauge->gaugeMax)+90)*kDegreeRadians;
float t=tanf(-redlineAngle);
TexturesSelectTex(FileGetReference("tachoredline.tif"));
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glBegin(GL_TRIANGLES);
glTexCoord2d(0.5,0.5); glVertex2f(0,0);
glTexCoord2d(1,1); glVertex2f(1,-1);
glTexCoord2d(1,0.5-0.5*t); glVertex2f(1,t);
glEnd();
}
TexturesSelectTex(gauge->gaugeTexture);
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();
float tachoAngle=(gauge->gaugeZero-2*gauge->gaugeZero*(value/gauge->gaugeMax))*kDegreeRadians;
float width=gauge->pointerWidth;
float c=cos(tachoAngle);
float s=sin(tachoAngle);
TexturesSelectTex(gauge->pointerTexture);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(-s+c*width,-c-s*width);
glTexCoord2d(1,0); glVertex2f(s+c*width,c-s*width);
glTexCoord2d(0,1); glVertex2f(-s-c*width,-c+s*width);
glTexCoord2d(0,0); glVertex2f(s-c*width,c+s*width);
glEnd();
glPopAttrib();
glPopMatrix();
gTexturesQualityModifier=0;
}
#define kPanelSize 0.32
#define kPanelOffsetX -0.02
#define kPanelOffsetY 0.08
//Render the car status panels (tacho,speedo) on screen
void CarRenderPanels(tGameEntity *carEntity,float opacity)
{
tCarPhysics *phys=(tCarPhysics*)carEntity->physics;
tCarDefinition *car=&(phys->car);
tGaugesList *gauges=(tGaugesList*)FileGetParsedDataPtr(FileGetReference(kGaugesFileName),kParserTypeGaugesListDesc,sizeof(tGaugesList));
float width,c,s;
//Tacho
int tachoGauge=-1;
float gaugeFit=INFINITY;
for(int i=0;i<gauges->numGauges;i++)
if(gauges->gauges[i].type==kGaugeTypeTacho)
{
int fit=gauges->gauges[i].gaugeMax-car->maxRPM;
if(fit>=0&&fit<gaugeFit)
{
gaugeFit=fit;
tachoGauge=i;
}
}
if(tachoGauge==-1)
for(int i=0;i<gauges->numGauges;i++)
if(gauges->gauges[i].type==kGaugeTypeTacho)
{
int fit=fabs(gauges->gauges[i].gaugeMax-car->maxRPM);
if(fit<gaugeFit)
{
gaugeFit=fit;
tachoGauge=i;
}
}
if(tachoGauge!=-1)
RenderGauge(gauges->gauges+tachoGauge,phys->rpm,(0.5-kPanelOffsetX-0.5*kPanelSize),-(0.5-kPanelOffsetY-0.5*kPanelSize),kPanelSize,opacity,car->maxRPM*0.9);
//Speedo
int speedoGauge=-1;
float maxV=car->maxRPM/(car->gearRatios[car->numGears-1]*car->finalDriveRatio)*car->wheels[0].radius*2*PI/60*0.9;
gaugeFit=INFINITY;
for(int i=0;i<gauges->numGauges;i++)
if(gauges->gauges[i].type==(gConfig->metricUnits?kGaugeTypeSpeedoMetric:kGaugeTypeSpeedo))
{
int fit=gauges->gauges[i].gaugeMax-maxV;
if(fit>=0&&fit<gaugeFit)
{
gaugeFit=fit;
speedoGauge=i;
}
}
if(speedoGauge==-1)
for(int i=0;i<gauges->numGauges;i++)
if(gauges->gauges[i].type==(gConfig->metricUnits?kGaugeTypeSpeedoMetric:kGaugeTypeSpeedo))
speedoGauge=i;
if(speedoGauge!=-1)
RenderGauge(gauges->gauges+speedoGauge,~carEntity->velo,-(0.5-kPanelOffsetX-0.5*kPanelSize),-(0.5-kPanelOffsetY-0.5*kPanelSize),kPanelSize,opacity,0);
//Selected Gear
if(phys->gear==-1)
TextPrintfToBufferFormatedColored(Vector(0.8,-0.9),0.07,kTextAlignLeft,1,1,1,opacity,"R");
else if(phys->gear==0)
TextPrintfToBufferFormatedColored(Vector(0.8,-0.9),0.07,kTextAlignLeft,1,1,1,opacity,"N");
/* else if(gGameInfo->playerAutomatic)
TextPrintfToBufferFormated(Vector(0.8,-0.9),0.07,kTextAlignLeft,"D");*/
else
TextPrintfToBufferFormatedColored(Vector(0.8,-0.9),0.07,kTextAlignLeft,1,1,1,opacity,"%d",phys->gear);
#ifdef __POLYCOUNT
gPolyCount+=8;
#endif
}
#define kShiftAnimationTime 0.3
#define kArmNumEdges 6
#define kArmRadius 0.04
void RenderArm(tVector3 point1,tVector3 point2,tVector3 point3)
{
tVector3 dir12=!(point2-point1);
tVector3 dir13=!(point3-point1);
tVector3 dir23=!(point3-point2);
tVector3 dir1=!(dir12%Vector(0,1,0));
tVector3 dir2=!(dir13%Vector(0,1,0));
tVector3 dir3=!(dir23%Vector(0,1,0));
tMatrix3 mat1;
tMatrix3 mat2;
tMatrix3 mat3;
RotationVectorToMatrix(-dir12*((2*PI)/(kArmNumEdges)),mat1);
RotationVectorToMatrix(-dir13*((2*PI)/(kArmNumEdges)),mat2);
RotationVectorToMatrix(-dir23*((2*PI)/(kArmNumEdges)),mat3);
for(int i=0;i<kArmNumEdges;i++)
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3fv(&(point1).x);
glNormal3fv(&dir1.x);
glVertex3fv(&(point1+dir1*kArmRadius).x);
dir1=dir1*mat1;
glNormal3fv(&dir1.x);
glVertex3fv(&(point1+dir1*kArmRadius).x);
glNormal3fv(&dir2.x);
glVertex3fv(&(point2+dir2*kArmRadius).x);
dir2=dir2*mat2;
glNormal3fv(&dir2.x);
glVertex3fv(&(point2+dir2*kArmRadius).x);
glNormal3fv(&dir3.x);
glVertex3fv(&(point3+dir3*kArmRadius).x);
dir3=dir3*mat3;
glNormal3fv(&dir3.x);
glVertex3fv(&(point3+dir3*kArmRadius).x);
glVertex3fv(&(point3).x);
glEnd();
}
}
void CarRenderDriver(tGameEntity *carEntity)
{
tCarPhysics *phys=(tCarPhysics*)carEntity->physics;
tCarDefinition *car=&(phys->car);
if(car->noDriverModel!=1)
{
tVector3 innerShoulder=Vector(-0.13*sign(car->driverPos.x),0.365,-0.047)+car->driverPos;
tVector3 outerShoulder=Vector(0.13*sign(car->driverPos.x),0.365,-0.047)+car->driverPos;
tMatrix3 steeringDir;
MatrixIdentity(steeringDir);
MatrixRotZ(steeringDir,-car->steeringWheelTurns*PI*phys->steering);
MatrixRotX(steeringDir,car->steeringWheelAngle*(2*PI/360.0));
//hands on steering wheel
tVector3 innerHand=Vector(-car->steeringWheelRadius*sign(car->driverPos.x),0,0)*steeringDir+car->steeringWheelPos;
tVector3 outerHand=Vector(car->steeringWheelRadius*sign(car->driverPos.x),0,0)*steeringDir+car->steeringWheelPos;
//hand on handbrake
if(phys->handbrake)
innerHand=Vector(car->driverPos.x-sign(car->driverPos.x)*0.47
,car->driverPos.y-0.3+0.3*phys->handbrake
,car->driverPos.z+0.3);
//hand on shifter
float shiftDelay=gFrameCount*kFrameTime-phys->lastGearSwitch;
if(shiftDelay<kShiftAnimationTime)
innerHand=Vector(car->driverPos.x-sign(car->driverPos.x)*0.47
,car->driverPos.y+0.13
,car->driverPos.z+0.6-0.3*(shiftDelay/kShiftAnimationTime));
float maxArmLength=~(car->steeringWheelPos-outerShoulder);
tVector3 innerArm=innerHand-innerShoulder;
tVector3 outerArm=outerHand-outerShoulder;
float innerArmLength=~innerArm;
float outerArmLength=~outerArm;
float innerArmBend=innerArmLength>=maxArmLength?0:sqrt(sqr(maxArmLength)-sqr(innerArmLength))*0.5;
float outerArmBend=outerArmLength>=maxArmLength?0:sqrt(sqr(maxArmLength)-sqr(outerArmLength))*0.5;
tVector3 innerElbow=innerShoulder+innerArm*0.5+((innerHand.z>innerShoulder.z)?1:-1)*!((innerArm)%Vector(0,1,0))*innerArmBend;
tVector3 outerElbow=outerShoulder+outerArm*0.5-((outerHand.z>outerShoulder.z)?1:-1)*!((outerArm)%Vector(0,1,0))*outerArmBend;
glPushAttrib(GL_LIGHTING_BIT+GL_CURRENT_BIT+GL_TEXTURE_BIT);
TexturesSelectTextureUnit(2);
glDisable(GL_TEXTURE_2D);
TexturesSelectTextureUnit(1);
glDisable(GL_TEXTURE_2D);
TexturesSelectTextureUnit(0);
glDisable(GL_TEXTURE_2D);
GLfloat col[4]={0.1,0.1,0.1,1};
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,col);
RenderArm(innerShoulder,innerElbow,innerHand);
RenderArm(outerShoulder,outerElbow,outerHand);
glPopAttrib();
}
if(!car->noDriverModel){
tVector3 driverPos=car->driverPos*carEntity->dir+carEntity->pos;
SetupTranslation(driverPos,carEntity->dir);
DrawModel(FileGetReference("driver.mdl"),true,0);
}
}
void CarRenderEntityGhost(tGameEntity *carEntity)
{
gGhostShine=true;
tCarPhysics *phys=(tCarPhysics*)carEntity->physics;
tCarDefinition *car=&(phys->car);
//draw the car model
if(gConfig->interiorDisplay||gCameraMode==kCameraCockpitCarHidden)
DrawModel(car->model,kTransparencyGhost,phys->color);
else
DrawModel(car->model,kTransparencyOff,phys->color);
//draw add-ons.
for(int i=0;i<car->numAddOns;i++)
//is this add-on installed?
if(((phys->addOns|car->initialAddOns)>>i)&1)
//do we need to draw a model?
if(car->addOns[i].hasGraphic)
if(gConfig->interiorDisplay>0||gCameraMode==kCameraCockpitCarHidden)
DrawModel(car->addOns[i].model,kTransparencyGhost,phys->color);
else
DrawModel(car->addOns[i].model,kTransparencyOff,phys->color);
//draw the car's wheels
for(int i=0;i<car->numWheels;i++){
tMatrix3 wheelDir,brakeDir;
MatrixIdentity(wheelDir);
//correctly rotate wheel
MatrixScale(wheelDir,car->wheels[i].width/1,car->wheels[i].radius/1,car->wheels[i].radius/1);
MatrixCopy(wheelDir,brakeDir);
MatrixRotX(wheelDir,-sign(car->wheels[i].pos.x)*phys->wheels[i].rotation);
MatrixRotY(wheelDir,(car->wheels[i].pos.x<0?0:PI)+phys->wheels[i].angle);
MatrixRotZ(wheelDir,-sign(car->wheels[i].pos.x)*car->wheels[i].tilt);
MatrixMult(wheelDir,carEntity->dir,wheelDir);
tVector3 wheelPos=car->wheels[i].pos;
wheelPos.y-=phys->wheels[i].suspension;
wheelPos=wheelPos*carEntity->dir+carEntity->pos;
SetupTranslation(wheelPos,wheelDir);
gGlowFactor=phys->wheels[i].glow;
gBlurMapFactor=fabs(phys->wheels[i].angularVelo/(2*PI*12));
if(gBlurMapFactor>1)gBlurMapFactor=1;
if(gConfig->interiorDisplay>0||gCameraMode==kCameraCockpitCarHidden)
DrawModel(car->wheels[i].model,kTransparencyGhost,car->wheels[i].texture);
else
DrawModel(car->wheels[i].model,kTransparencyOff,car->wheels[i].texture);
}
gGhostShine=false;
}
void DrawLicensePlate(char *text)
{
GLfloat specularReflectance[4]={1,1,1,1};
GLfloat ambientReflectance[4]={0.75,0.75,0.75,1};
GLfloat diffuseReflectance[4]={0.8,0.8,0.8,1};
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuseReflectance);
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambientReflectance);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specularReflectance);
glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,30);
glNormal3f(0,0,1);
TexturesSelectTex(FileGetReference("license.pct"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(0,0); glVertex3f(-0.3,-0.18,-0.02);
glTexCoord2d(1,0); glVertex3f(0.3,-0.18,-0.02);
glTexCoord2d(0,1); glVertex3f(-0.3,0.0,-0.02);
glTexCoord2d(1,1); glVertex3f(0.3,0.0,-0.02);
glEnd();
glDepthMask(0);
TextDrawSimple(text,0.56,0.18,kTextAlignMiddle);
glDepthMask(1);
}
//render a car.
void CarRenderEntity(tGameEntity *carEntity,int allowTransparency,int showDriver)
{
gTexturesQualityModifier=-2;
tCarPhysics *phys=(tCarPhysics*)carEntity->physics;
tCarDefinition *car=&(phys->car);
if(car->numColors>phys->color)
car->colorLoaded[phys->color]=true;
int drawDirt=gEnvironment->dirtEnable;
if(gMapInfo)
if(gMapInfo->dirtEnable)
drawDirt=true;
if(drawDirt)
if(TexturesSelectTextureUnit(2))
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
TexturesSelectTex(gMapInfo->dirtEnable?gMapInfo->dirtMap:gEnvironment->dirtMap);
glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
float extends=ModelGetMaxExtends(car->model);
GLfloat plane1[4]={phys->dirtStretch[0]/extends,0,phys->dirtStretch[1]/extends,0};
GLfloat plane2[4]={0.5*phys->dirtStretch[2]/extends,0.5*phys->dirtStretch[3]/extends,phys->dirtStretch[4]/extends,0};
glTexGenfv(GL_S,GL_OBJECT_PLANE,plane1);
glTexGenfv(GL_T,GL_OBJECT_PLANE,plane2);
GLfloat color[4]={1,1,1,phys->dirt*0.01*(gMapInfo->dirtEnable?gMapInfo->dirtIntensity:gEnvironment->dirtIntensity)};
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_INTERPOLATE_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE2_RGB_ARB,GL_CONSTANT_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND2_RGB_ARB,GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,color);
TexturesSelectTextureUnit(0);
}
gTunnelFactor=phys->echo;
//draw the car model
DrawModel(car->model,allowTransparency,phys->color);
if(drawDirt)
if(TexturesSelectTextureUnit(2)){
glDisable(GL_TEXTURE_2D);
TexturesSelectTextureUnit(0);
}
//draw add-ons.
for(int i=0;i<car->numAddOns;i++)
//is this add-on installed?
if(((phys->addOns|car->initialAddOns)>>i)&1)
//do we need to draw a model?
if(car->addOns[i].hasGraphic)
DrawModel(car->addOns[i].model,allowTransparency,phys->color);
//if we have transparency, we need to draw the interior
if(allowTransparency)
{
//draw interior model
DrawModel(car->interiorModel,true,phys->color);
//if we aren't "inside" the driver, render him.
if(showDriver)
CarRenderDriver(carEntity);
//and the steering wheel
if(car->steeringWheelRadius)
{
tMatrix3 steeringDir;
tVector3 steeringWheelPos=car->steeringWheelPos*carEntity->dir+carEntity->pos;
MatrixIdentity(steeringDir);
MatrixRotZ(steeringDir,-car->steeringWheelTurns*PI*phys->steering);
MatrixRotX(steeringDir,car->steeringWheelAngle*(2*PI/360.0));
MatrixMult(steeringDir,carEntity->dir,steeringDir);
SetupTranslation(steeringWheelPos,steeringDir);
if(tTransparentPoly *p=GetNextTransparentPoly(true)){
p->v[0].texel=Vector(0,1);
p->v[1].texel=Vector(0,0);
p->v[2].texel=Vector(1,1);
p->v[0].normal=Vector(0,0,1)*gTransformDir;
p->v[1].normal=Vector(0,0,1)*gTransformDir;
p->v[2].normal=Vector(0,0,1)*gTransformDir;
p->v[0].vertex=Vector(-car->steeringWheelRadius,-car->steeringWheelRadius,0)*gTransformDir+gTransformPos;
p->v[1].vertex=Vector(-car->steeringWheelRadius,car->steeringWheelRadius,0)*gTransformDir+gTransformPos;
p->v[2].vertex=Vector(car->steeringWheelRadius,-car->steeringWheelRadius,0)*gTransformDir+gTransformPos;
p->mat->flags=kMaterialBothSides+kMaterialUseAlphaChannel+kMaterialDisableWrapS;
p->mat->shininess=0;
p->mat->specular=Vector(0,0,0);
p->mat->ambient=Vector(0.6,0.6,0.6);
p->mat->diffuse=Vector(0.4,0.4,0.4);
p->mat->texRef=car->steeringWheelTexture;
if(tTransparentPoly *p2=GetNextTransparentPoly(false)){
p2->v[0].texel=Vector(0,0);
p2->v[1].texel=Vector(1,1);
p2->v[2].texel=Vector(1,0);
p2->v[0].normal=Vector(0,0,1)*gTransformDir;
p2->v[1].normal=Vector(0,0,1)*gTransformDir;
p2->v[2].normal=Vector(0,0,1)*gTransformDir;
p2->v[0].vertex=Vector(-car->steeringWheelRadius,car->steeringWheelRadius,0)*gTransformDir+gTransformPos;
p2->v[1].vertex=Vector(car->steeringWheelRadius,-car->steeringWheelRadius,0)*gTransformDir+gTransformPos;
p2->v[2].vertex=Vector(car->steeringWheelRadius,car->steeringWheelRadius,0)*gTransformDir+gTransformPos;
p2->mat=p->mat;
}
}
}
}
//draw License plates
if(phys->plateName)
{
TextLoadFont(FileGetReference("license.font"));
if(!VectorZero(car->frontLicensePlatePos))
{
tVector3 licensePlatePos=car->frontLicensePlatePos*carEntity->dir+carEntity->pos;
SetupTranslation(licensePlatePos,carEntity->dir);
DrawLicensePlate(phys->plateName);
}
if(!VectorZero(car->rearLicensePlatePos))
{
tVector3 licensePlatePos=car->rearLicensePlatePos*carEntity->dir+carEntity->pos;
tMatrix3 licenseDir;
MatrixIdentity(licenseDir);
MatrixRotY(licenseDir,PI);
MatrixMult(licenseDir,carEntity->dir,licenseDir);
SetupTranslation(licensePlatePos,licenseDir);
DrawLicensePlate(phys->plateName);
}
TextLoadFont(FileGetReference("test.font"));
}
gTexturesQualityModifier=-4;
//draw the car's wheels
for(int i=0;i<car->numWheels;i++){
tMatrix3 wheelDir,brakeDir;
MatrixIdentity(wheelDir);
//correctly rotate wheel
MatrixScale(wheelDir,car->wheels[i].width/1,car->wheels[i].radius/1,car->wheels[i].radius/1);
MatrixCopy(wheelDir,brakeDir);
MatrixRotX(wheelDir,-sign(car->wheels[i].pos.x)*phys->wheels[i].rotation);
MatrixRotY(wheelDir,(car->wheels[i].pos.x<0?0:PI)+phys->wheels[i].angle);
MatrixRotZ(wheelDir,-sign(car->wheels[i].pos.x)*car->wheels[i].tilt);
MatrixMult(wheelDir,carEntity->dir,wheelDir);
tVector3 wheelPos=car->wheels[i].pos;
wheelPos.y-=phys->wheels[i].suspension;
wheelPos=wheelPos*carEntity->dir+carEntity->pos;
SetupTranslation(wheelPos,wheelDir);
gGlowFactor=phys->wheels[i].glow;
gBlurMapFactor=fabs(phys->wheels[i].angularVelo/(2*PI*12));
if(gBlurMapFactor>1)gBlurMapFactor=1;
glMatrixMode(GL_TEXTURE);
glPushMatrix();
tMatrix4 m;
MatrixIdentity(m);
MatrixTranslate(m,0,0,0.25+0.5*(gBlurMapFactor*2<1?gBlurMapFactor*2:1));
glLoadMatrixf((float*)m);
DrawModel(car->wheels[i].model,allowTransparency,car->wheels[i].texture);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
if(allowTransparency)
{
MatrixRotX(brakeDir,(car->wheels[i].pos.x<0?0:PI));
MatrixRotY(brakeDir,(car->wheels[i].pos.x<0?0:PI)+phys->wheels[i].angle);
MatrixRotZ(brakeDir,-sign(car->wheels[i].pos.x)*car->wheels[i].tilt);
MatrixMult(brakeDir,carEntity->dir,brakeDir);
SetupTranslation(wheelPos,brakeDir);
if(car->wheels[i].customBrakeModel>0)
DrawModel(car->wheels[i].customBrakeModel,allowTransparency,0);
else
DrawModel(FileGetReference("brakedischousing.mdl"),allowTransparency,0);
}
}
gTexturesQualityModifier=0;
}
#define kNumWheelSides 12
void CarRenderWheelShadowPass(float width,float radius,float shadowLength,int cw)
{
tVector3 lightDir=gEnvironment->lightDir;
if(gMapEnv)
if(!VectorZero(gMapEnv->lightDir))
lightDir=gMapEnv->lightDir;
tMatrix3 tr;
MatrixTranspose(gTransformDir,tr);
lightDir=lightDir*tr;
tVector3 shadowVector=lightDir*shadowLength;
if(lightDir.x!=0)
{
tVector3 lightDirFlat=lightDir;
lightDirFlat.x=0;
lightDirFlat=!lightDirFlat;
tVector3 normal=lightDirFlat%Vector(1,0,0);
lightDirFlat=lightDirFlat*radius;
normal=normal*radius;
float dir=-sign(lightDir.x)*width/2;
glFrontFace(lightDir.x<0?(cw?GL_CW:GL_CCW):(cw?GL_CCW:GL_CW));
glBegin(GL_TRIANGLE_STRIP);
for(int i=0;i<=kNumWheelSides/2;i++)
{
float f=((float)i/kNumWheelSides)*2*PI;
float s=sin(f);
float c=cos(f);
tVector3 v=Vector(dir,c*normal.y+s*lightDirFlat.y,c*normal.z+s*lightDirFlat.z);
glVertex3fv(&v.x);
glVertex3fv(&(v-shadowVector).x);
}
for(int i=kNumWheelSides/2;i<=kNumWheelSides;i++)
{
float f=((float)i/kNumWheelSides)*2*PI;
float s=sin(f);
float c=cos(f);
tVector3 v=Vector(-dir,c*normal.y+s*lightDirFlat.y,c*normal.z+s*lightDirFlat.z);
glVertex3fv(&v.x);
glVertex3fv(&(v-shadowVector).x);
}
tVector3 v=Vector(dir,normal.y,normal.z);
glVertex3fv(&v.x);
glVertex3fv(&(v-shadowVector).x);
glEnd();
}
#ifdef __POLYCOUNT
gPolyCount+=kNumWheelSides*2+4;
#endif
}
void CarRenderWheelShadow(float width,float radius,float shadowLength)
{
//disable actual drawing
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glDepthMask(GL_FALSE);
glColorMask(0, 0, 0, 0);
//enable stencil buffer drawing
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
//zPass Rendering
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
CarRenderWheelShadowPass(width,radius,shadowLength,false);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
CarRenderWheelShadowPass(width,radius,shadowLength,true);
glDepthMask(GL_TRUE);
glColorMask(1, 1, 1, 1);
}
//draw the car's shadow
void CarRenderEntityShadow(tGameEntity *carEntity,float shadowLength)
{
tCarPhysics *phys=(tCarPhysics*)carEntity->physics;
tCarDefinition *car=&(phys->car);
tFileRef nullModel=FileGetReference("null.mdl");
if(shadowLength==0)
{
shadowLength=GetGroundOffset(carEntity->pos,&carEntity->lastRoadIndex,0,0)+kCarMinShadow;
shadowLength*=1/(gEnvironment->lightDir*Vector(0,1,0));
}
//draw the shadow for the car model
if(car->shadowModel)
DrawModelShadow(car->shadowModel,shadowLength);
else
DrawModelShadow(car->model,shadowLength);
//draw add-ons shadows.
for(int i=0;i<car->numAddOns;i++)
//is this add-on installed?
if(((phys->addOns|car->initialAddOns)>>i)&1)
//do we need to draw a model?
if(car->addOns[i].hasGraphic)
DrawModelShadow(car->addOns[i].model,shadowLength);
//draw the shadow for the wheels
for(int i=0;i<car->numWheels;i++)
if(car->wheels[i].model!=nullModel&&!car->wheels[i].noShadow)
{
tMatrix3 wheelDir;
MatrixIdentity(wheelDir);
//MatrixScale(wheelDir,car->wheels[i].widthRatio,1,1);
MatrixRotX(wheelDir,sign(car->wheels[i].pos.x)*phys->wheels[i].rotation);
MatrixRotY(wheelDir,PI+phys->wheels[i].angle);
MatrixRotZ(wheelDir,-sign(car->wheels[i].pos.x)*car->wheels[i].tilt);
MatrixMult(wheelDir,carEntity->dir,wheelDir);
tVector3 wheelPos=car->wheels[i].pos;
wheelPos.y-=phys->wheels[i].suspension;
wheelPos=wheelPos*carEntity->dir+carEntity->pos;
SetupTranslation(wheelPos,wheelDir);
CarRenderWheelShadow(car->wheels[i].width*sqr(gStencilZoom),car->wheels[i].radius*sqr(gStencilZoom),shadowLength);
}
}