//rendercar.cpp //code to render a car #include #include #include #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" #include "mVertex.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;inumGauges;i++) if(gauges->gauges[i].type==kGaugeTypeTacho) { int fit=gauges->gauges[i].gaugeMax-car->maxRPM; if(fit>=0&&fitnumGauges;i++) if(gauges->gauges[i].type==kGaugeTypeTacho) { int fit=fabs(gauges->gauges[i].gaugeMax-car->maxRPM); if(fitgauges+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;inumGauges;i++) if(gauges->gauges[i].type==(gConfig->metricUnits?kGaugeTypeSpeedoMetric:kGaugeTypeSpeedo)) { int fit=gauges->gauges[i].gaugeMax-maxV; if(fit>=0&&fitnumGauges;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;iphysics; 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(shiftDelaydriverPos.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;inumAddOns;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;inumWheels;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;inumAddOns;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;inumWheels;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); mVertex3fv((v-shadowVector)); } 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); mVertex3fv((v-shadowVector)); } tVector3 v=Vector(dir,normal.y,normal.z); glVertex3fv(&v.x); mVertex3fv((v-shadowVector)); 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;inumAddOns;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;inumWheels;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); } }