1123 lines
38 KiB
C++
1123 lines
38 KiB
C++
|
//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 16.0
|
||
|
#define kMaxAILongitunalAcceleration 4.8
|
||
|
#define kMaxAITurboLongitunalAcceleration 13.5
|
||
|
#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;
|
||
|
|
||
|
if(roadData->roadSize<10)
|
||
|
return;
|
||
|
|
||
|
|
||
|
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);
|
||
|
F32Swap(road[i].speedModifier);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
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;
|
||
|
int startTopVertices=gRoadTypes->types[(road[i].type)].startTopVertices;
|
||
|
int endTopVertices=gRoadTypes->types[(road[i].type)].endTopVertices;
|
||
|
|
||
|
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[startTopVertices].vertex1+(gRoadTypes->types[(road[i].type)].vertices[startTopVertices].vertex2-gRoadTypes->types[(road[i].type)].vertices[startTopVertices].vertex1)*startTypeSeg;
|
||
|
typePoint2=gRoadTypes->types[(road[i].type)].vertices[startTopVertices].vertex1+(gRoadTypes->types[(road[i].type)].vertices[startTopVertices].vertex2-gRoadTypes->types[(road[i].type)].vertices[startTopVertices].vertex1)*road[i].typeSeg;
|
||
|
typePoint1.x-=3;
|
||
|
typePoint2.x-=3;
|
||
|
}
|
||
|
else if(v==numVertices)
|
||
|
{
|
||
|
typePoint1=gRoadTypes->types[(road[i].type)].vertices[endTopVertices-1].vertex1+(gRoadTypes->types[(road[i].type)].vertices[endTopVertices-1].vertex2-gRoadTypes->types[(road[i].type)].vertices[endTopVertices-1].vertex1)*startTypeSeg;
|
||
|
typePoint2=gRoadTypes->types[(road[i].type)].vertices[endTopVertices-1].vertex1+(gRoadTypes->types[(road[i].type)].vertices[endTopVertices-1].vertex2-gRoadTypes->types[(road[i].type)].vertices[endTopVertices-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,float *track)
|
||
|
{
|
||
|
int i=RoadGetRoadSegment(pos,lastSegment);
|
||
|
if(i==-1)return 0;
|
||
|
|
||
|
tRoadData *roadData=(tRoadData*)FileGetDataPtr(gMapInfo->road);
|
||
|
tRoadSeg *road=roadData->road;
|
||
|
tConvertedRoad *convRoad=(tConvertedRoad*)gFileTable[gMapInfo->road].parsedData;
|
||
|
|
||
|
tVector3 point1=road[i].pos;
|
||
|
tVector3 point2=road[i+1].pos;
|
||
|
float localPosition=((pos-point1)*(point2-point1))/sqr(point2-point1);
|
||
|
if(track)
|
||
|
{
|
||
|
point1=(convRoad->road[i].trackl+convRoad->road[i+1].trackl)*0.5;
|
||
|
point2=(convRoad->road[i].trackr+convRoad->road[i+1].trackr)*0.5;
|
||
|
*track=((pos-point1)*(point2-point1))/sqr(point2-point1);
|
||
|
}
|
||
|
return localPosition+i;
|
||
|
}
|
||
|
|
||
|
float RoadGetLength(tVector3 pos,int lastSegment)
|
||
|
{
|
||
|
float f=RoadGetPosition(pos,lastSegment,NULL);
|
||
|
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,NULL);
|
||
|
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,NULL);
|
||
|
float pos2=RoadGetPosition(endPos,0,NULL);
|
||
|
/* 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;
|
||
|
|
||
|
float track;
|
||
|
float dropL=RoadGetLength(road[i].pos,i);
|
||
|
int trackChoose=0;
|
||
|
int ok;
|
||
|
do{
|
||
|
switch(trackChoose)
|
||
|
{
|
||
|
case 0:track=0.9;break;
|
||
|
case 1:track=0.1;break;
|
||
|
case 2:track=0.5;break;
|
||
|
case 3:track=0.7;break;
|
||
|
case 4:track=0.3;break;
|
||
|
}
|
||
|
ok=true;
|
||
|
for(int car=0;car<gGameInfo->numPlayers;car++)
|
||
|
if(gCarEntities[car]!=carEntity)
|
||
|
{
|
||
|
float l=RoadGetLength(gCarEntities[car]->pos,gCarEntities[car]->lastRoadIndex);
|
||
|
if(!gGameInfo->reverse)
|
||
|
{
|
||
|
if(dropL-l<4*~gCarEntities[car]->velo&&dropL-l>0)
|
||
|
{
|
||
|
float ctrack;
|
||
|
RoadGetPosition(gCarEntities[car]->pos,gCarEntities[car]->lastRoadIndex,&ctrack);
|
||
|
if(fabs(ctrack-track)<0.2)
|
||
|
ok=false;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if(l-dropL<4*~gCarEntities[car]->velo&&l-dropL>0)
|
||
|
{
|
||
|
float ctrack;
|
||
|
RoadGetPosition(gCarEntities[car]->pos,gCarEntities[car]->lastRoadIndex,&ctrack);
|
||
|
if(fabs(ctrack-track)<0.2)
|
||
|
ok=false;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
trackChoose++;
|
||
|
}while(!ok&&trackChoose<5);
|
||
|
|
||
|
tVector3 point=convRoad->road[i].trackl+(convRoad->road[i].trackr-convRoad->road[i].trackl)*track;
|
||
|
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,NULL);
|
||
|
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 0;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|