Redline/source/roads~.cpp

1070 lines
37 KiB
C++
Raw Normal View History

//roads.cpp
//draws the road and detects collisions agains the road.
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <math.h>
#include "entities.h"
#include "config.h"
#include "vectors.h"
#include "fileio.h"
#include "textures.h"
#include "gamemem.h"
#include "renderframe.h"
#include "roads.h"
#include "environment.h"
#include "gameinitexit.h"
#include "transparency.h"
#include "network.h"
#include <stdio.h>
#include "error.h"
#define kExtraLength 80
tRoadTypeList *gRoadTypes;
tSurfaceTypeList *gSurfaceTypes;
int gRoadRestrictedBorders=false;
int gQuickRoadCollision=false;
#define kMaxAILateralAcceleration 4.0
#define kMaxAITurboLateralAcceleration 12.0
#define kMaxAILongitunalAcceleration 4.8
#define kMaxAITurboLongitunalAcceleration 10.0
#define kMaxSpeedIndex 100
tVector2 GetFlatTrack(tConvertedRoad *convRoad,int i,int roadSize)
{
if(i<0)i=0;
if(i>roadSize-2)i=roadSize-2;
tVector3 pos_3=convRoad->road[i].trackl+(convRoad->road[i].trackr-convRoad->road[i].trackl)*((convRoad->road[i].track+1)*0.5);
return Vector(pos_3.x,pos_3.z);
}
#define kMinSignLateralAccel 2.5
#define kSignDistance 100.0
void CalcSpeedInfo(int ref)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(ref);
tRoadSeg *road=roadData->road;
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[ref].parsedData;
for(int i=2;i<(roadData->roadSize)-2;i++)
{
float traction=gRoadTypes->types[road[i].type].traction;
if(traction==0)traction=1;
tVector2 pos1=GetFlatTrack(convRoad,i-7,(roadData->roadSize));
tVector2 pos2=GetFlatTrack(convRoad,i,(roadData->roadSize));
tVector2 pos3=GetFlatTrack(convRoad,i+7,(roadData->roadSize));
tVector2 v1=!(pos2-pos1);
tVector2 v2=!(pos3-pos2);
float veloDiff=~(v2-v1);
float dist=~(pos1-pos2)+~(pos2-pos3);
if(dist>0&&veloDiff>0)
{
float accel=dist/veloDiff;
convRoad->road[i].speedIndex=sqrt(kMaxAILateralAcceleration*accel*traction);
if(convRoad->road[i].speedIndex>kMaxSpeedIndex)
convRoad->road[i].speedIndex=kMaxSpeedIndex;
convRoad->road[i].turboSpeedIndex=sqrt(kMaxAITurboLateralAcceleration*accel*traction);
if(convRoad->road[i].turboSpeedIndex>kMaxSpeedIndex)
convRoad->road[i].turboSpeedIndex=kMaxSpeedIndex;
}
else
{
convRoad->road[i].speedIndex=kMaxSpeedIndex;
convRoad->road[i].turboSpeedIndex=kMaxSpeedIndex;
}
convRoad->road[i].lateralAccel=(v1.y*v2.x-v2.y*v1.x)/dist*1000;
if(road[i].speedModifier>=-1&&road[i].speedModifier<=1)
{
convRoad->road[i].speedIndex*=(1+road[i].speedModifier);
convRoad->road[i].turboSpeedIndex*=(1+road[i].speedModifier);
}
convRoad->road[i].reverseSpeedIndex=convRoad->road[i].speedIndex;
convRoad->road[i].reverseTurboSpeedIndex=convRoad->road[i].turboSpeedIndex;
}
convRoad->road[0].speedIndex=kMaxSpeedIndex;
convRoad->road[1].speedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-1].speedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-2].speedIndex=kMaxSpeedIndex;
convRoad->road[0].reverseSpeedIndex=kMaxSpeedIndex;
convRoad->road[1].reverseSpeedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-1].reverseSpeedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-2].reverseSpeedIndex=kMaxSpeedIndex;
convRoad->road[0].turboSpeedIndex=kMaxSpeedIndex;
convRoad->road[1].turboSpeedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-1].turboSpeedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-2].turboSpeedIndex=kMaxSpeedIndex;
convRoad->road[0].reverseTurboSpeedIndex=kMaxSpeedIndex;
convRoad->road[1].reverseTurboSpeedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-1].reverseTurboSpeedIndex=kMaxSpeedIndex;
convRoad->road[(roadData->roadSize)-2].reverseTurboSpeedIndex=kMaxSpeedIndex;
for(int i=(roadData->roadSize)-2;i>=0;i--)
{
float traction=gRoadTypes->types[road[i].type].traction;
if(traction==0)traction=1;
tVector2 pos1=Vector(road[i].pos.x,road[i].pos.z);
tVector2 pos2=Vector(road[i+1].pos.x,road[i+1].pos.z);
float dist=~(pos1-pos2);
float speedIndex2=convRoad->road[i+1].speedIndex;
float maxSpeedIndex1=sqrt(sqr(speedIndex2)+kMaxAILongitunalAcceleration*2*dist*traction);
float maxTurboSpeedIndex1=sqrt(sqr(speedIndex2)+kMaxAITurboLongitunalAcceleration*2*dist*traction);
if(convRoad->road[i].speedIndex>maxSpeedIndex1)
convRoad->road[i].speedIndex=maxSpeedIndex1;
if(convRoad->road[i].turboSpeedIndex>maxTurboSpeedIndex1)
convRoad->road[i].turboSpeedIndex=maxTurboSpeedIndex1;
}
for(int i=1;i<(roadData->roadSize)-2;i++)
{
float traction=gRoadTypes->types[road[i].type].traction;
if(traction==0)traction=1;
tVector2 pos1=Vector(road[i].pos.x,road[i].pos.z);
tVector2 pos2=Vector(road[i-1].pos.x,road[i-1].pos.z);
float dist=~(pos1-pos2);
float speedIndex2=convRoad->road[i-1].reverseSpeedIndex;
float maxSpeedIndex1=sqrt(sqr(speedIndex2)+kMaxAILongitunalAcceleration*2*dist*traction);
float maxTurboSpeedIndex1=sqrt(sqr(speedIndex2)+kMaxAITurboLongitunalAcceleration*2*dist*traction);
if(convRoad->road[i].reverseSpeedIndex>maxSpeedIndex1)
convRoad->road[i].reverseSpeedIndex=maxSpeedIndex1;
if(convRoad->road[i].reverseTurboSpeedIndex>maxTurboSpeedIndex1)
convRoad->road[i].reverseTurboSpeedIndex=maxTurboSpeedIndex1;
}
int cornerStart=-1;
float corner=0;
float iminus2=convRoad->road[0].lateralAccel;
float iminus1=convRoad->road[1].lateralAccel;
//smooth lateralAccel
for(int i=2;i<(roadData->roadSize)-3;i++)
{
float temp=convRoad->road[i].lateralAccel;
convRoad->road[i].lateralAccel=
(convRoad->road[i].lateralAccel+
convRoad->road[i+1].lateralAccel+
convRoad->road[i+2].lateralAccel+
iminus1+iminus2)/5;
iminus2=iminus1;
iminus1=temp;
}
for(int i=1;i<(roadData->roadSize)-2;i++)
{
if((convRoad->road[i].lateralAccel>kMinSignLateralAccel&&corner>=0)||
(convRoad->road[i].lateralAccel>1.5&&corner>0))
{
if(corner==0)
cornerStart=i;
if(convRoad->road[i].lateralAccel>corner)
corner=convRoad->road[i].lateralAccel;
}
else if((convRoad->road[i].lateralAccel<-kMinSignLateralAccel&&corner<=0)||
(convRoad->road[i].lateralAccel<-1.5&&corner<0))
{
if(corner==0)
cornerStart=i;
if(convRoad->road[i].lateralAccel<corner)
corner=convRoad->road[i].lateralAccel;
}
else if(corner)
{
for(int j=cornerStart;j<i;j++)
convRoad->road[j].lateralAccel=corner;
convRoad->road[i].lateralAccel=0;
corner=0;
cornerStart=-1;
}
else
convRoad->road[i].lateralAccel=0;
}
if(corner)
{
for(int j=cornerStart;j<(roadData->roadSize)-3;j++)
convRoad->road[j].lateralAccel=corner;
}
}
float Interpolation(float x)
{
return -x*x*x*x+2*x*x;
}
float InterpolateTrack(float l1, float l2, float l, float track1, float track2)
{
return track1+(track2-track1)*Interpolation((l-l1)/(l2-l1));
}
void ConvertRoadEndianess(tRoadData *roadData)
{
tRoadSeg *road=roadData->road;
S32Swap(roadData->roadSize);
for(int i=0;i<roadData->roadSize;i++)
{
F32Swap(road[i].pos.x);
F32Swap(road[i].pos.y);
F32Swap(road[i].pos.z);
F32Swap(road[i].normal.x);
F32Swap(road[i].normal.y);
F32Swap(road[i].normal.z);
S32Swap(road[i].type);
F32Swap(road[i].track);
F32Swap(road[i].typeSeg);
}
}
void CompileRoadPoints(int id)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(id);
tRoadSeg *road=roadData->road;
ConvertRoadEndianess(roadData);
tConvertedRoad *convRoad=(tConvertedRoad*)MemoryAllocateBlock(((roadData->roadSize)-1)*sizeof(tConvertedRoadSeg)+sizeof(tConvertedRoad));
int vertexCount=0;
for(int i=0;i<(roadData->roadSize)-1;i++)
vertexCount+=gRoadTypes->types[(road[i].type)].numVertices+2;
convRoad->vertexStorage=(tConvertedRoadVertex*)MemoryAllocateBlock(sizeof(tConvertedRoadVertex)*vertexCount);
tVector3 prevSegDir,prevJunction2;
tVector3 curSegDir,curJunction1,curJunction2;
tVector3 nextSegDir,nextJunction1,nextJunction2;
tVector3 junction1,junction2;
float totalLength=0;
float startTypeSeg=0;
vertexCount=0;
curSegDir=road[1].pos-road[0].pos;
curJunction1=!(curSegDir%road[0].normal);
curJunction2=!(curSegDir%road[1].normal);
prevSegDir=curSegDir;
prevJunction2=curJunction1;
junction1=!(curJunction1+prevJunction2);
if(road[0].track>1)road[0].track=0;
float lastTrackLength=0,lastTrack=road[0].track;
float nextTrackLength=0,nextTrack=road[0].track;
int lastTrackIndex=0,nextTrackIndex=0;
for(int i=0;i<(roadData->roadSize)-1;i++)
{
if(nextTrackIndex<=i)
{
float l=totalLength;
for(int j=i+1;j<(roadData->roadSize)&&nextTrackIndex<=i;j++)
{
l+=~(road[j].pos-road[j-1].pos);
if(road[j].track<=1||j==(roadData->roadSize)-1)
{
lastTrackLength=nextTrackLength;
lastTrack=nextTrack;
lastTrackIndex=nextTrackIndex;
nextTrackIndex=j;
nextTrackLength=l;
nextTrack=(j==(roadData->roadSize)-1?road[0].track:road[nextTrackIndex].track);
}
}
}
nextSegDir=i<(roadData->roadSize)-2?road[i+2].pos-road[i+1].pos:curSegDir;
nextJunction1=!(nextSegDir%road[i+1].normal);
nextJunction2=i<(roadData->roadSize)-2?!(nextSegDir%road[i+2].normal):nextJunction1;
junction2=!(nextJunction1+curJunction1);
convRoad->road[i].vertices=convRoad->vertexStorage+vertexCount+1;
convRoad->road[i].maxExtends=0;
int numVertices=gRoadTypes->types[(road[i].type)].numVertices;
vertexCount+=numVertices+2;
convRoad->road[i].track=InterpolateTrack(lastTrackLength,nextTrackLength,totalLength,lastTrack,nextTrack);
convRoad->road[i].trackl=road[i].pos+junction1*gRoadTypes->types[(road[i].type)].minTrack;
convRoad->road[i].trackr=road[i].pos+junction1*gRoadTypes->types[(road[i].type)].maxTrack;
for(int v=-1;v<numVertices+1;v++)
{
tVector2 typePoint1,typePoint2;
if(v==-1)
{
typePoint1=gRoadTypes->types[(road[i].type)].vertices[v+1].vertex1+(gRoadTypes->types[(road[i].type)].vertices[v+1].vertex2-gRoadTypes->types[(road[i].type)].vertices[v+1].vertex1)*startTypeSeg;
typePoint2=gRoadTypes->types[(road[i].type)].vertices[v+1].vertex1+(gRoadTypes->types[(road[i].type)].vertices[v+1].vertex2-gRoadTypes->types[(road[i].type)].vertices[v+1].vertex1)*road[i].typeSeg;
typePoint1.x-=3;
typePoint2.x-=3;
}
else if(v==numVertices)
{
typePoint1=gRoadTypes->types[(road[i].type)].vertices[v-1].vertex1+(gRoadTypes->types[(road[i].type)].vertices[v-1].vertex2-gRoadTypes->types[(road[i].type)].vertices[v-1].vertex1)*startTypeSeg;
typePoint2=gRoadTypes->types[(road[i].type)].vertices[v-1].vertex1+(gRoadTypes->types[(road[i].type)].vertices[v-1].vertex2-gRoadTypes->types[(road[i].type)].vertices[v-1].vertex1)*road[i].typeSeg;
typePoint1.x+=3;
typePoint2.x+=3;
}
else
{
typePoint1=gRoadTypes->types[(road[i].type)].vertices[v].vertex1+(gRoadTypes->types[(road[i].type)].vertices[v].vertex2-gRoadTypes->types[(road[i].type)].vertices[v].vertex1)*startTypeSeg;
typePoint2=gRoadTypes->types[(road[i].type)].vertices[v].vertex1+(gRoadTypes->types[(road[i].type)].vertices[v].vertex2-gRoadTypes->types[(road[i].type)].vertices[v].vertex1)*road[i].typeSeg;
}
if(sqr(typePoint1)>convRoad->road[i].maxExtends)
convRoad->road[i].maxExtends=sqr(typePoint1);
if(sqr(typePoint2)>convRoad->road[i].maxExtends)
convRoad->road[i].maxExtends=sqr(typePoint2);
convRoad->road[i].vertices[v].v1=road[i].pos+road[i].normal*typePoint1.y+junction1*typePoint1.x;
convRoad->road[i].vertices[v].v2=road[i+1].pos+road[i+1].normal*typePoint2.y+junction2*typePoint2.x;
convRoad->road[i].vertices[v].d2=convRoad->road[i].vertices[v].v2.y-convRoad->road[i].vertices[v].v1.y;
convRoad->road[i].vertices[v].d1=convRoad->road[i].vertices[v].v2.y-convRoad->road[i].vertices[v].v1.y;
if(i>0)
if((road[i-1].type)==(road[i].type))
{
tVector3 v1=convRoad->road[i].vertices[v].v2-convRoad->road[i].vertices[v].v1;
tVector3 v2=convRoad->road[i].vertices[v].v1-convRoad->road[i-1].vertices[v].v1;
float l1=~v1;
float l2=~v2;
tVector3 v12=!(!v1+!v2);
float d=v12.y/sqrt(sqr(v12.x)+sqr(v12.z));
if(fabs(convRoad->road[i].vertices[v].d1-d*l1)<2)
{
convRoad->road[i].vertices[v].d1=d*l1;
convRoad->road[i-1].vertices[v].d2=d*l2;
}
}
}
startTypeSeg=road[i].typeSeg;
if(startTypeSeg>=1)startTypeSeg=0;
for(int v=-1;v<numVertices;v++)
{
if(v==-1)
{
convRoad->road[i].vertices[v].n1=!(junction1);
convRoad->road[i].vertices[v].n2=!(junction2);
}
else if(v==numVertices-1)
{
convRoad->road[i].vertices[v].n1=!(-junction1);
convRoad->road[i].vertices[v].n2=!(-junction2);
}
else
{
tVector2 typeNormal1=(gRoadTypes->types[(road[i].type)].vertices[v].vertex1-gRoadTypes->types[(road[i].type)].vertices[v+1].vertex1);
tVector2 typeNormal2=(gRoadTypes->types[(road[i].type)].vertices[v].vertex2-gRoadTypes->types[(road[i].type)].vertices[v+1].vertex2);
if(VectorEqual(typeNormal1,Vector(0,0)))
typeNormal1=Vector(-1,0);
if(VectorEqual(typeNormal2,Vector(0,0)))
typeNormal2=Vector(-1,0);
typeNormal1=!typeNormal1;
typeNormal2=!typeNormal2;
convRoad->road[i].vertices[v].n1=!(-road[i].normal*typeNormal1.x+junction1*typeNormal1.y);
convRoad->road[i].vertices[v].n2=!(-road[i+1].normal*typeNormal2.x+junction2*typeNormal2.y);
}
}
convRoad->road[i].length=totalLength;
totalLength+=~curSegDir;
convRoad->road[i].maxExtends=sqrt(convRoad->road[i].maxExtends);
prevJunction2=curJunction2;
curSegDir=nextSegDir;
curJunction1=nextJunction1;
curJunction2=nextJunction2;
junction1=junction2;
}
gFileTable[id].parsedData=convRoad;
gFileTable[id].parsed=true;
CalcSpeedInfo(id);
}
//Renders the Road
void RoadRender(tVector3 *clipPlanes)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tRoadSeg *road=roadData->road;
if(!gFileTable[gMapInfo->road].parsed)
CompileRoadPoints(gMapInfo->road);
if(!gFileTable[gMapInfo->road].parsed)
return;
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
SetupWorldTranslation();
glPushAttrib(GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_POLYGON_BIT);
/* GLfloat specularReflectance[]={0.0,0.0,0.0,1};
GLfloat ambientReflectance[]={0.6,0.6,0.6,1};
GLfloat diffuseReflectance[]={0.4,0.4,0.4,1};
*/
GLfloat specularReflectance[]={0.0,0.0,0.0,1};
GLfloat ambientReflectance[]={0.4,0.4,0.4,1};
GLfloat diffuseReflectance[]={0.6,0.6,0.6,1};
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuseReflectance);
glMaterialfv(GL_FRONT,GL_AMBIENT,ambientReflectance);
glMaterialfv(GL_FRONT,GL_SPECULAR,specularReflectance);
glMaterialf(GL_FRONT,GL_SHININESS,20);
int lastClipped=0;
int texture=-1;
tPolyMaterial mat;
mat.flags=kMaterialBothSides+kMaterialUseAlphaChannel+kMaterialDisableWrapS;
mat.shininess=0;
mat.specular=Vector(0,0,0);
mat.ambient=Vector(0.6,0.6,0.6);
mat.diffuse=Vector(0.4,0.4,0.4);
for(int i=0;i<(roadData->roadSize)-2;i++)
{
float len1=convRoad->road[i].length;
float len2=convRoad->road[i+1].length;
int clipped=ClipPointDistanced(clipPlanes,&road[i+1].pos,convRoad->road[i].maxExtends);
if(!(clipped&lastClipped))
{
int numVertices=gRoadTypes->types[(road[i].type)].numVertices;
for(int v=0;v<numVertices-1;v++)
{
float texZoom=gRoadTypes->types[(road[i].type)].vertices[v].texZoom;
if(texZoom>=0)
{
if(!(gRoadTypes->types[(road[i].type)].vertices[v].materialFlags&1))
{
if(gRoadTypes->types[(road[i].type)].vertices[v].materialFlags&2)
glDisable(GL_CULL_FACE);
else
glEnable(GL_CULL_FACE);
if(texture!=gRoadTypes->types[(road[i].type)].vertices[v].texture)
{
texture=gRoadTypes->types[(road[i].type)].vertices[v].texture;
TexturesSelectTex(texture);
if(!gConfig->carsOnSpeed)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
}
glBegin(GL_TRIANGLE_STRIP);
glNormal3fv(&convRoad->road[i].vertices[v].n2.x);
glTexCoord2f(gRoadTypes->types[(road[i].type)].vertices[v+1].texCoord1,texZoom?convRoad->road[i+1].length*texZoom:1);
glVertex3fv(&convRoad->road[i].vertices[v+1].v2.x);
glNormal3fv(&convRoad->road[i].vertices[v].n1.x);
glTexCoord2f(gRoadTypes->types[(road[i].type)].vertices[v].texCoord2,texZoom?convRoad->road[i+1].length*texZoom:1);
glVertex3fv(&convRoad->road[i].vertices[v].v2.x);
glNormal3fv(&convRoad->road[i].vertices[v].n2.x);
glTexCoord2f(gRoadTypes->types[(road[i].type)].vertices[v+1].texCoord1,texZoom?convRoad->road[i].length*texZoom:0);
glVertex3fv(&convRoad->road[i].vertices[v+1].v1.x);
glNormal3fv(&convRoad->road[i].vertices[v].n1.x);
glTexCoord2f(gRoadTypes->types[(road[i].type)].vertices[v].texCoord2,texZoom?convRoad->road[i].length*texZoom:0);
glVertex3fv(&convRoad->road[i].vertices[v].v1.x);
glEnd();
/*
glBegin(GL_LINES);
glVertex3fv(&convRoad->road[i].vertices[v+1].v2.x);
glVertex3fv(&(convRoad->road[i].vertices[v+1].v2+convRoad->road[i].vertices[v].n2).x);
glVertex3fv(&convRoad->road[i].vertices[v+1].v1.x);
glVertex3fv(&(convRoad->road[i].vertices[v+1].v1+convRoad->road[i].vertices[v].n1*2).x);
glVertex3fv(&convRoad->road[i].vertices[v].v2.x);
glVertex3fv(&(convRoad->road[i].vertices[v].v2+convRoad->road[i].vertices[v].n2).x);
glVertex3fv(&convRoad->road[i].vertices[v].v1.x);
glVertex3fv(&(convRoad->road[i].vertices[v].v1+convRoad->road[i].vertices[v].n1*2).x);
glEnd();*/
}
else if(tTransparentPoly *p=GetNextTransparentPoly(true))
{
mat.texRef=gRoadTypes->types[(road[i].type)].vertices[v].texture;
*p->mat=mat;
p->textureSet=0;
p->v[0].vertex=convRoad->road[i].vertices[v+1].v2;
p->v[1].vertex=convRoad->road[i].vertices[v].v2;
p->v[2].vertex=convRoad->road[i].vertices[v+1].v1;
p->v[0].normal=convRoad->road[i].vertices[v].n2;
p->v[1].normal=convRoad->road[i].vertices[v].n1;
p->v[2].normal=convRoad->road[i].vertices[v].n2;
p->v[0].texel=Vector(gRoadTypes->types[(road[i].type)].vertices[v+1].texCoord1,texZoom?convRoad->road[i+1].length*texZoom:1);
p->v[1].texel=Vector(gRoadTypes->types[(road[i].type)].vertices[v].texCoord2,texZoom?convRoad->road[i+1].length*texZoom:1);
p->v[2].texel=Vector(gRoadTypes->types[(road[i].type)].vertices[v+1].texCoord1,texZoom?convRoad->road[i].length*texZoom:0);
if(tTransparentPoly *p=GetNextTransparentPoly(true))
{
*p->mat=mat;
p->textureSet=0;
p->v[0].vertex=convRoad->road[i].vertices[v].v1;
p->v[1].vertex=convRoad->road[i].vertices[v].v2;
p->v[2].vertex=convRoad->road[i].vertices[v+1].v1;
p->v[0].normal=convRoad->road[i].vertices[v].n1;
p->v[1].normal=convRoad->road[i].vertices[v].n1;
p->v[2].normal=convRoad->road[i].vertices[v].n2;
p->v[0].texel=Vector(gRoadTypes->types[(road[i].type)].vertices[v].texCoord2,texZoom?convRoad->road[i].length*texZoom:0);
p->v[1].texel=Vector(gRoadTypes->types[(road[i].type)].vertices[v].texCoord2,texZoom?convRoad->road[i+1].length*texZoom:1);
p->v[2].texel=Vector(gRoadTypes->types[(road[i].type)].vertices[v+1].texCoord1,texZoom?convRoad->road[i].length*texZoom:0);
}
}
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
}
}
}
lastClipped=clipped;
}
glPopAttrib();
}
tVector2 OrtoVec(tVector2 v)
{
return Vector(v.y,-v.x);
}
float GetPlaneHeight(tVector3 pos,tVector3 planeNormal,tVector3 planePoint)
{
return -(planeNormal.x*pos.x+planeNormal.z*pos.z-planeNormal*planePoint)/planeNormal.y;
}
int RoadGetRoadSegment(tVector3 pos,int lastSegment)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tRoadSeg *road=roadData->road;
if(!gFileTable[gMapInfo->road].parsed)
CompileRoadPoints(gMapInfo->road);
if(!gFileTable[gMapInfo->road].parsed)
return 0;
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
tVector2 flatPos=Vector(pos.x,pos.z);
int max=(gRoadRestrictedBorders&&lastSegment)?15:(roadData->roadSize)*2;
//a hack to always get a result for the camera, which jumps around a lot.
//if((lastSegment==gCameraEntity->lastRoadIndex)||gReplay||lastSegment==0)
// max=(roadData->roadSize)*2;
for(int ind=1;ind<max;ind++)
{
int i=lastSegment+((ind&1)?(ind/2):-(ind/2));
while(i<0)i+=(roadData->roadSize)-2;
while(i>=(roadData->roadSize)-2)i-=(roadData->roadSize)-2;
if(sqr(road[i].pos.x-flatPos.x)+sqr(road[i].pos.z-flatPos.y)<sqr(convRoad->road[i+1].length-convRoad->road[i].length+kExtraLength))
{
int numVertices=gRoadTypes->types[(road[i].type)].numVertices;
// int endTopVertices=gRoadTypes->types[(road[i].type)].endTopVertices;
// int startTopVertices=gRoadTypes->types[(road[i].type)].startTopVertices;
int endTopVertices=gRoadTypes->types[(road[i].type)].numVertices+1;
int startTopVertices=-1;
tVector2 right1,left1,right2,left2;
tVector2 rDir=Vector(road[i+1].pos.x-road[i].pos.x,road[i+1].pos.z-road[i].pos.z);
do{
right1=Vector(convRoad->road[i].vertices[startTopVertices].v1.x, convRoad->road[i].vertices[startTopVertices].v1.z );
right2=Vector(convRoad->road[i].vertices[startTopVertices].v2.x, convRoad->road[i].vertices[startTopVertices].v2.z );
startTopVertices++;
}while((right2-right1)*rDir<0);
do{
left1= Vector(convRoad->road[i].vertices[endTopVertices-1].v1.x, convRoad->road[i].vertices[endTopVertices-1].v1.z );
left2= Vector(convRoad->road[i].vertices[endTopVertices-1].v2.x, convRoad->road[i].vertices[endTopVertices-1].v2.z );
endTopVertices--;
}while((left2-left1)*rDir<0);
if((right1-flatPos) *!OrtoVec(left1-right1)<=0.5)
if((left2-flatPos) *OrtoVec(right2-left2)<=0)
if((right1-flatPos) *!OrtoVec(right1-right2)<=0.5)
if((left2-flatPos) *OrtoVec(left2-left1)<=0)
return i;
}
}
return -1;
}
float RoadGetPosition(tVector3 pos,int lastSegment)
{
int i=RoadGetRoadSegment(pos,lastSegment);
if(i==-1)return 0;
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tRoadSeg *road=roadData->road;
tVector3 point1=road[i].pos;
tVector3 point2=road[i+1].pos;
float localPosition=((pos-point1)*(point2-point1))/sqr(point2-point1);
return localPosition+i;
}
float RoadGetLength(tVector3 pos,int lastSegment)
{
float f=RoadGetPosition(pos,lastSegment);
int i=floor(f);
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
if(i<0)i=0;
if(i<roadData->roadSize-1)
return convRoad->road[i].length+(convRoad->road[i+1].length-convRoad->road[i].length)*(f-i);
else
return convRoad->road[i].length;
}
void RoadInitCheckPoints(tVector3 startPos)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
float pos=RoadGetPosition(startPos,0);
float stepSize=((roadData->roadSize)-3)/kNumCheckPoints;
for(int i=0;i<kNumCheckPoints;i++)
{
gCheckPoints[i].index=pos;
pos+=gGameInfo->reverse?-stepSize:stepSize;
if(pos>((roadData->roadSize)-3))
pos-=((roadData->roadSize)-3);
if(pos<0)
pos+=(roadData->roadSize)-3;
for(int j=0;j<kMaxLaps+1;j++)
{
gCheckPoints[i].passTimes[j].setBy=nil;
gCheckPoints[i].passTimes[j].hit=false;
}
}
}
void RoadInitCheckPoints(tVector3 startPos,tVector3 endPos)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
float pos1=RoadGetPosition(startPos,0);
float pos2=RoadGetPosition(endPos,0);
/* if(gGameInfo->reverse)
{
float tmp=pos2;
pos2=pos1;
pos1=tmp;
}*/
float pos=pos1;
float stepSize=(pos2-pos1)/kNumCheckPoints;
for(int i=0;i<kNumCheckPoints;i++)
{
gCheckPoints[i].index=pos;
pos+=stepSize;
for(int j=0;j<kMaxLaps+1;j++)
{
gCheckPoints[i].passTimes[j].setBy=nil;
gCheckPoints[i].passTimes[j].hit=false;
}
}
}
float RoadPosFromLength(int initPos,float length)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
float l=convRoad->road[initPos].length+length;
int i=initPos;
if(l<0)
l+=convRoad->road[(roadData->roadSize)-2].length;
if(l>convRoad->road[(roadData->roadSize)-2].length)
l-=convRoad->road[(roadData->roadSize)-2].length;
if(l<convRoad->road[initPos].length)
while(i>0&&convRoad->road[i].length>l)
i--;
else
while(i<(roadData->roadSize)-1&&convRoad->road[i].length<l)
i++;
return i;
}
#define kCornerSignDistance 120
void RoadInitCornerSigns()
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
if(!gFileTable[gMapInfo->road].parsed)
CompileRoadPoints(gMapInfo->road);
if(!gFileTable[gMapInfo->road].parsed)
return;
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
gNumCornerSigns=0;
float accel=0;
int lastCurvePos=0;
if(gGameInfo->reverse)
for(int i=(roadData->roadSize)-3;i>0;i--)
{
if(convRoad->road[i].lateralAccel!=accel)
{
if(convRoad->road[i].lateralAccel!=0&&gNumCornerSigns<kMaxCornerSigns)
{
gCornerSigns[gNumCornerSigns].pos=RoadPosFromLength(i,kCornerSignDistance);
if(gCornerSigns[gNumCornerSigns].pos>lastCurvePos)
gCornerSigns[gNumCornerSigns].pos=lastCurvePos;
gCornerSigns[gNumCornerSigns].accel=convRoad->road[i].lateralAccel;
gNumCornerSigns++;
}
accel=convRoad->road[i].lateralAccel;
lastCurvePos=i;
}
}
else for(int i=1;i<(roadData->roadSize)-2;i++)
{
if(convRoad->road[i].lateralAccel!=accel)
{
if(convRoad->road[i].lateralAccel!=0&&gNumCornerSigns<kMaxCornerSigns)
{
gCornerSigns[gNumCornerSigns].pos=RoadPosFromLength(i,-kCornerSignDistance);
if(gCornerSigns[gNumCornerSigns].pos<lastCurvePos)
gCornerSigns[gNumCornerSigns].pos=lastCurvePos;
gCornerSigns[gNumCornerSigns].accel=convRoad->road[i].lateralAccel;
gNumCornerSigns++;
}
accel=convRoad->road[i].lateralAccel;
lastCurvePos=i;
}
}
}
tVector3 RoadGetDir(int segment)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tRoadSeg *road=roadData->road;
tVector3 point1=road[segment].pos;
tVector3 point2=road[segment+1].pos;
return !(gGameInfo->reverse?point1-point2:point2-point1);
}
void RoadCenterCar(tGameEntity *carEntity)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tRoadSeg *road=roadData->road;
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
int i=RoadGetRoadSegment(carEntity->pos,carEntity->lastRoadIndex);
if(i==-1)return;
tVector3 point=(convRoad->road[i].trackl+convRoad->road[i].trackr)*0.5;
tVector3 dir=RoadGetDir(i);
*MatrixGetZVector(carEntity->dir)=dir;
*MatrixGetYVector(carEntity->dir)=Vector(0,1,0);
MatrixReAdjust(carEntity->dir);
carEntity->pos=point+((carEntity->pos-point)*dir)*dir;
carEntity->pos.y+=2+gRoadTypes->types[(road[i].type)].reviveY;
carEntity->pos=carEntity->pos-*MatrixGetXVector(carEntity->dir)*gRoadTypes->types[(road[i].type)].reviveX;
carEntity->velo=Vector(0,0,0);
MatrixIdentity(carEntity->rVelo);
}
tVector3 RoadGetNextWaypoint(tVector3 pos,int *lastRoadIndex,float *overtaking,float *speedIndex,float aheadDistance)
{
*lastRoadIndex=RoadGetRoadSegment(pos,*lastRoadIndex);
float l=RoadGetLength(pos,*lastRoadIndex)+(gGameInfo->reverse?-aheadDistance:aheadDistance);
int i=*lastRoadIndex;
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
if(l<0)
l+=convRoad->road[(roadData->roadSize)-2].length;
if(l>convRoad->road[(roadData->roadSize)-2].length)
l-=convRoad->road[(roadData->roadSize)-2].length;
if(l<RoadGetLength(pos,*lastRoadIndex))
while(i>0&&convRoad->road[i].length>l)
i--;
else
while(i<(roadData->roadSize)-1&&convRoad->road[i].length<l)
i++;
float f=RoadGetPosition(pos,*lastRoadIndex);
if(gGameInfo->reverse)
if(gGameInfo->arcade==2)
*speedIndex=convRoad->road[(int)f].reverseTurboSpeedIndex+(convRoad->road[((int)f)+1].reverseTurboSpeedIndex-convRoad->road[(int)f].reverseTurboSpeedIndex)*(f-(int)f);
else
*speedIndex=convRoad->road[(int)f].reverseSpeedIndex+(convRoad->road[((int)f)+1].reverseSpeedIndex-convRoad->road[(int)f].reverseSpeedIndex)*(f-(int)f);
else
if(gGameInfo->arcade==2)
*speedIndex=convRoad->road[(int)f].turboSpeedIndex+(convRoad->road[((int)f)+1].turboSpeedIndex-convRoad->road[(int)f].turboSpeedIndex)*(f-(int)f);
else
*speedIndex=convRoad->road[(int)f].speedIndex+(convRoad->road[((int)f)+1].speedIndex-convRoad->road[(int)f].speedIndex)*(f-(int)f);
if(i<=0)i=1;
f=(l-convRoad->road[i-1].length)/(convRoad->road[i].length-convRoad->road[i-1].length);
if(f<0)f=0;
if(f>1)f=1;
float track1=convRoad->road[i-1].track+(*overtaking>0?(1-convRoad->road[i-1].track)**overtaking:(1+convRoad->road[i-1].track)**overtaking);
tVector3 trackPos1=convRoad->road[i-1].trackl+((convRoad->road[i-1].trackr-convRoad->road[i-1].trackl)*((track1+1)/2));
float track2=convRoad->road[i].track+(*overtaking>0?(1-convRoad->road[i].track)**overtaking:(1+convRoad->road[i].track)**overtaking);
tVector3 trackPos2=convRoad->road[i].trackl+((convRoad->road[i].trackr-convRoad->road[i].trackl)*((track2+1)/2));
*overtaking=convRoad->road[i].track;
return trackPos1+f*(trackPos2-trackPos1)+Vector(0,gRoadTypes->types[(roadData->road[i].type)].reviveY,0);
}
float InterpolateSplineAt(float y0,float y1,float d0,float d1,float x)
{
float a= 2*y0-2*y1+ d0+ d1;
float b=-3*y0+3*y1-2*d0- d1;
float c= d0 ;
float d= y0 ;
return a*x*x*x+b*x*x+c*x+d;
}
float RoadGetYValue(tVector3 point,int *lastRoadIndex,tVector3 *groundNormal,int *surfaceType,float *bumpOut)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tRoadSeg *road=roadData->road;
if(!gFileTable[gMapInfo->road].parsed)
CompileRoadPoints(gMapInfo->road);
if(!gFileTable[gMapInfo->road].parsed)
return -INFINITY;
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
tVector2 flatPos=Vector(point.x,point.z);
int i=RoadGetRoadSegment(point,*lastRoadIndex);
if(i!=-1)
{
*lastRoadIndex=i;
int numVertices=gRoadTypes->types[(road[i].type)].numVertices;
int endTopVertices=gRoadTypes->types[(road[i].type)].endTopVertices;
int startTopVertices=gRoadTypes->types[(road[i].type)].startTopVertices;
// int endTopVertices=gRoadTypes->types[(road[i].type)].numVertices+1;
// int startTopVertices=-1;
unsigned int min=startTopVertices,max=endTopVertices-1;
tVector2 min1v2=Vector(convRoad->road[i].vertices[min].v1.x, convRoad->road[i].vertices[min].v1.z );
tVector2 min2v2=Vector(convRoad->road[i].vertices[min].v2.x, convRoad->road[i].vertices[min].v2.z );
if((min1v2-flatPos)*OrtoVec(min1v2-min2v2)>=0)
{
if(surfaceType)
*surfaceType=gMapInfo->baseSurfaceType;
if(groundNormal)
*groundNormal=convRoad->road[i].vertices[-1].n1;
if(bumpOut)
*bumpOut=0;
return -(min1v2-flatPos)*!OrtoVec(min1v2-min2v2);
}
tVector2 max1v2=Vector(convRoad->road[i].vertices[max].v1.x, convRoad->road[i].vertices[max].v1.z );
tVector2 max2v2=Vector(convRoad->road[i].vertices[max].v2.x, convRoad->road[i].vertices[max].v2.z );
if((max1v2-flatPos)*OrtoVec(max1v2-max2v2)<=0)
{
if(surfaceType)
*surfaceType=gMapInfo->baseSurfaceType;
if(groundNormal)
*groundNormal=convRoad->road[i].vertices[gRoadTypes->types[(road[i].type)].numVertices-1].n1;
// *groundNormal=!(road[i].pos-point);
if(bumpOut)
*bumpOut=0;
//printf("max %f\n",(max1v2-flatPos)*!OrtoVec(max1v2-max2v2));
return (max1v2-flatPos)*!OrtoVec(max1v2-max2v2);
}
while(max>min+1)
{
unsigned int mid=(min+max)/2;
tVector2 mid1=Vector(convRoad->road[i].vertices[mid].v1.x, convRoad->road[i].vertices[mid].v1.z );
tVector2 mid2=Vector(convRoad->road[i].vertices[mid].v2.x, convRoad->road[i].vertices[mid].v2.z );
if((mid1-flatPos)*OrtoVec(mid1-mid2)>=0)
max=mid;
else
min=mid;
}
int surface;
if(min!=-1&&max!=endTopVertices-1)
surface=gRoadTypes->types[(road[i].type)].vertices[min].surfaceType;
else
surface=gMapInfo->baseSurfaceType;
if(surfaceType)
*surfaceType=surface;
tVector3 min2=convRoad->road[i].vertices[min].v2;
tVector3 max2=convRoad->road[i].vertices[max].v2;
tVector3 min1=convRoad->road[i].vertices[min].v1;
tVector3 max1=convRoad->road[i].vertices[max].v1;
tVector2 flatMin1=Vector(min1.x,min1.z);
tVector2 flatMin2=Vector(min2.x,min2.z);
tVector2 flatMax1=Vector(max1.x,max1.z);
tVector2 flatMax2=Vector(max2.x,max2.z);
float u,v;
tVector2 a,b,c;
if(((flatMin1-flatPos)*OrtoVec(flatMin1-flatMax2)<=0||sqr(flatMax1-flatMin1)==0)&&!(sqr(flatMin2-flatMax2)==0))
{
a=flatMin2-flatMax2;
b=flatMax1-flatMax2;
c=flatPos-flatMax2;
}
else
{
a=flatMax1-flatMin1;
b=flatMin2-flatMin1;
c=(flatMin1+a+b)-flatPos;
}
if(a.x!=0&&a.y!=0&&b.x!=0&&b.y!=0){
if(a.x==0)
{
v=(c.x)/(b.x);
u=(c.y-v*b.y)/(a.y);
}
else if(a.y==0)
{
v=(c.y)/(b.y);
u=(c.x-v*b.x)/(a.x);
}
else
{
u=(b.x*c.y-b.y*c.x)/(a.y*b.x-a.x*b.y);
if(b.y==0)
{
v=(c*a)/sqr(a);
}
else
v=(c.y-u*a.y)/b.y;
}
// float miny=InterpolateSplineAt(min1.y,min2.y,convRoad->road[i].vertices[min].d1,convRoad->road[i].vertices[min].d2,1-v);
// float maxy=InterpolateSplineAt(max1.y,max2.y,convRoad->road[i].vertices[max].d1,convRoad->road[i].vertices[max].d2,1-v);
float miny=min2.y-v*(min2.y-min1.y);
float maxy=max2.y-v*(max2.y-max1.y);
float y=maxy-u*(maxy-miny);
if(groundNormal)
{
tVector3 vmin=min2-v*(min2-min1);
vmin.y=miny;
tVector3 vmax=max2-v*(max2-max1);
vmax.y=maxy;
tVector3 v1=max1-u*(max1-min1);
tVector3 v2=max2-u*(max2-min2);
*groundNormal=!((vmin-vmax)%(v1-v2));
}
float bumpFreq=gSurfaceTypes->types[surface].bumpFreq;
float bump=gSurfaceTypes->types[surface].bumpHeight*sin(flatPos.x*bumpFreq)*sin(flatPos.y*bumpFreq);
if(bumpOut)*bumpOut=bump;
return point.y-y-bump;
}
else
{
tVector3 normal=!((min1-max2)%(max1-min2));
if(groundNormal)
*groundNormal=normal;
float bumpFreq=gSurfaceTypes->types[surface].bumpFreq;
float bump=gSurfaceTypes->types[surface].bumpHeight*sin(flatPos.x*bumpFreq)*sin(flatPos.y*bumpFreq);
if(bumpOut)*bumpOut=bump;
return point.y-GetPlaneHeight(point,normal,min2)-bump;
}
}
if(!gQuickRoadCollision)
{
int closestRoadSeg=-1;
float closestRoadSegDist=INFINITY;
tVector2 normal;
for(int i=0;i<(roadData->roadSize)-2;i++)
{
if(sqr(road[i].pos.x-point.x)+sqr(road[i].pos.z-point.z)<sqr(convRoad->road[i+1].length-convRoad->road[i].length+kExtraLength))
{
int numVertices=gRoadTypes->types[(road[i].type)].numVertices;
int endTopVertices=gRoadTypes->types[(road[i].type)].endTopVertices;
int startTopVertices=gRoadTypes->types[(road[i].type)].startTopVertices;
tVector2 right1=Vector(convRoad->road[i].vertices[startTopVertices].v1.x, convRoad->road[i].vertices[startTopVertices].v1.z );
tVector2 left1= Vector(convRoad->road[i].vertices[endTopVertices-1].v1.x, convRoad->road[i].vertices[endTopVertices-1].v1.z );
tVector2 right2=Vector(convRoad->road[i].vertices[startTopVertices].v2.x, convRoad->road[i].vertices[startTopVertices].v2.z );
tVector2 left2= Vector(convRoad->road[i].vertices[endTopVertices-1].v2.x, convRoad->road[i].vertices[endTopVertices-1].v2.z );
float dist;
tVector2 testNormal;
if(((right1-flatPos)*!OrtoVec(right1-left1))>=0)
if(((left2-flatPos)*!OrtoVec(right2-left2))<=0)
{
if((dist=(right1-flatPos)*(testNormal=!OrtoVec(right1-right2)))<=closestRoadSegDist)
if(dist>=0)
{
closestRoadSeg=i;
closestRoadSegDist=dist;
normal=testNormal;
}
if((dist=(left2-flatPos)*(testNormal=!OrtoVec(left2-left1)))<=closestRoadSegDist)
if(dist>=0)
{
closestRoadSeg=i;
closestRoadSegDist=dist;
normal=testNormal;
}
}
}
}
if(closestRoadSeg!=-1)
{
if(surfaceType)
*surfaceType=gMapInfo->baseSurfaceType;
if(groundNormal)
*groundNormal=Vector(normal.x,0,normal.y);
return -closestRoadSegDist;
}
}
if(surfaceType)
*surfaceType=gMapInfo->baseSurfaceType;
if(groundNormal)
*groundNormal=Vector(0,1,0);
return -INFINITY;
}
void RoadGetWayPointData(int startRoadSeg,float dist,float *minTrack,float *maxTrack,float *minSpeed)
{
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
tRoadSeg *road=roadData->road;
if(!gFileTable[gMapInfo->road].parsed)
CompileRoadPoints(gMapInfo->road);
if(!gFileTable[gMapInfo->road].parsed)
return;
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
float l=0;
*minTrack=1;
*maxTrack=-1;
*minSpeed=INFINITY;
while(l<dist)
{
if(convRoad->road[startRoadSeg].track<*minTrack)
*minTrack=convRoad->road[startRoadSeg].track;
if(convRoad->road[startRoadSeg].track>*maxTrack)
*maxTrack=convRoad->road[startRoadSeg].track;
if(convRoad->road[startRoadSeg].speedIndex<*minSpeed)
*minSpeed=convRoad->road[startRoadSeg].speedIndex;
startRoadSeg++;
if(startRoadSeg>=(roadData->roadSize)-1)
startRoadSeg=0;
else
l+=convRoad->road[startRoadSeg].length-convRoad->road[startRoadSeg-1].length;
}
}