//roads.cpp //draws the road and detects collisions agains the road. #include #include #include #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 #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].lateralAccelroad[i].lateralAccel; } else if(corner) { for(int j=cornerStart;jroad[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;iroadSize;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;vtypes[(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;vroad[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;vtypes[(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;indroadSize)-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)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(iroadSize-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;ireverse?-stepSize:stepSize; if(pos>((roadData->roadSize)-3)) pos-=((roadData->roadSize)-3); if(pos<0) pos+=(roadData->roadSize)-3; for(int j=0;jroad); 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;iroad); 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(lroad[initPos].length) while(i>0&&convRoad->road[i].length>l) i--; else while(i<(roadData->roadSize)-1&&convRoad->road[i].lengthroad); 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&&gNumCornerSignslastCurvePos) 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&&gNumCornerSignsroad[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(l0&&convRoad->road[i].length>l) i--; else while(i<(roadData->roadSize)-1&&convRoad->road[i].lengthreverse) 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)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(lroad[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; } }