2016-04-02 12:43:55 +00:00
|
|
|
//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"
|
|
|
|
|
2016-04-04 21:17:52 +00:00
|
|
|
#include "mVertex.h"
|
|
|
|
|
2016-04-02 12:43:55 +00:00
|
|
|
#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);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((point1+dir1*kArmRadius));
|
2016-04-02 12:43:55 +00:00
|
|
|
dir1=dir1*mat1;
|
|
|
|
glNormal3fv(&dir1.x);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((point1+dir1*kArmRadius));
|
2016-04-02 12:43:55 +00:00
|
|
|
glNormal3fv(&dir2.x);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((point2+dir2*kArmRadius));
|
2016-04-02 12:43:55 +00:00
|
|
|
dir2=dir2*mat2;
|
|
|
|
glNormal3fv(&dir2.x);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((point2+dir2*kArmRadius));
|
2016-04-02 12:43:55 +00:00
|
|
|
glNormal3fv(&dir3.x);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((point3+dir3*kArmRadius));
|
2016-04-02 12:43:55 +00:00
|
|
|
dir3=dir3*mat3;
|
|
|
|
glNormal3fv(&dir3.x);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((point3+dir3*kArmRadius));
|
2016-04-02 12:43:55 +00:00
|
|
|
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);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((v-shadowVector));
|
2016-04-02 12:43:55 +00:00
|
|
|
}
|
|
|
|
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);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((v-shadowVector));
|
2016-04-02 12:43:55 +00:00
|
|
|
}
|
|
|
|
tVector3 v=Vector(dir,normal.y,normal.z);
|
|
|
|
glVertex3fv(&v.x);
|
2016-04-04 21:17:52 +00:00
|
|
|
mVertex3fv((v-shadowVector));
|
2016-04-02 12:43:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|