00001
00002 #include "ReVolt.h"
00003 #include "NewColl.h"
00004 #include "Particle.h"
00005 #include "Body.h"
00006 #include "Wheel.h"
00007 #include "Car.h"
00008 #include "Geom.h"
00009 #include "Main.h"
00010 #include "Ctrlread.h"
00011 #include "Object.h"
00012 #include "Control.h"
00013 #include "Player.h"
00014 #include "level.h"
00015 #include "Ghost.h"
00016 #include "main.h"
00017 #include "light.h"
00018 #include "timing.h"
00019
00020 static GHOST_INFO GhostInfoStore1;
00021 static GHOST_DATA GhostDataStore1[GHOST_DATA_MAX];
00022 static GHOST_INFO GhostInfoStore2;
00023 static GHOST_DATA GhostDataStore2[GHOST_DATA_MAX];
00024
00025 GHOST_INFO *GHO_BestGhostInfo = &GhostInfoStore1;
00026 GHOST_DATA *BestGhostData = GhostDataStore1;
00027 long GHO_BestFrame = 0;
00028 long GhostSolid = FALSE;
00029
00030 GHOST_INFO *GhostInfo = &GhostInfoStore2;
00031 GHOST_DATA *GhostData = GhostDataStore2;
00032
00033 bool GHO_GhostExists = FALSE;
00034 PLAYER *GHO_GhostPlayer = NULL;
00035
00036 LIGHT *GhostLight;
00037
00038 REAL DBG_dt = ZERO;
00039
00041
00042
00043
00045
00046 void InitGhostData(PLAYER *player)
00047 {
00048
00049 GhostInfo->CarID = player->car.CarID;
00050 strncpy(GhostInfo->PlayerName, player->PlayerName, MAX_PLAYER_NAME);
00051 GhostInfo->NFrames = 0;
00052
00053 }
00054
00055 void EndGhostData(PLAYER *player)
00056 {
00057 GhostInfo->Time[GHOST_LAP_TIME] = player->car.LastLapTime;
00058 }
00059
00060 void InitBestGhostData()
00061 {
00062 if (!GHO_GhostPlayer)
00063 return;
00064
00065 GHO_BestFrame = 0;
00066 GHO_GhostPlayer->car.CurrentLapTime = 0;
00067 GHO_GhostPlayer->car.CurrentLapStartTime = CurrentTimer();
00068 strncpy(GHO_BestGhostInfo->PlayerName, GHO_GhostPlayer->PlayerName, MAX_PLAYER_NAME);
00069
00070 if (GHO_GhostPlayer->car.CarID != GHO_BestGhostInfo->CarID)
00071 SetupCar(GHO_GhostPlayer, GHO_BestGhostInfo->CarID);
00072 }
00073
00074
00075 void ClearBestGhostData()
00076 {
00077 int iWheel;
00078
00079 GHO_BestFrame = 0;
00080 GHO_BestGhostInfo->Time[GHOST_LAP_TIME] = MAKE_TIME(10, 0, 0);
00081 GHO_BestGhostInfo->CarID = 0;
00082 GHO_BestGhostInfo->PlayerName[0] = '\0';
00083 GHO_BestGhostInfo->NFrames = 1;
00084
00085 BestGhostData[0].Time = MAKE_TIME(0, 0, 0);
00086 BestGhostData[1].Time = MAKE_TIME(10, 0, 0);
00087 CopyVec(&GHO_GhostPlayer->car.Body->Centre.Pos, &BestGhostData[0].Pos);
00088 #pragma warning(disable : 4244)
00089 BestGhostData[0].Quat.v[VX] = (char)(GHOST_VECTOR_SCALE * GHO_GhostPlayer->car.Body->Centre.Quat.v[VX]);
00090 BestGhostData[0].Quat.v[VY] = (char)(GHOST_VECTOR_SCALE * GHO_GhostPlayer->car.Body->Centre.Quat.v[VY]);
00091 BestGhostData[0].Quat.v[VZ] = (char)(GHOST_VECTOR_SCALE * GHO_GhostPlayer->car.Body->Centre.Quat.v[VZ]);
00092 BestGhostData[0].Quat.v[S] = (char)(GHOST_VECTOR_SCALE * GHO_GhostPlayer->car.Body->Centre.Quat.v[S]);
00093 #pragma warning(default : 4244)
00094
00095 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
00096 BestGhostData[0].WheelAngle[iWheel] = 0;
00097 BestGhostData[0].WheelPos[iWheel] = 0;
00098 }
00099
00100 GHO_GhostExists = FALSE;
00101 }
00102
00104
00105
00106
00107
00109
00110 void SwitchGhostDataStores()
00111 {
00112 GHOST_DATA *tmpData;
00113 GHOST_INFO *tmpInfo;
00114
00115 if (GhostInfo->NFrames == 0) return;
00116
00117 tmpData = GhostData;
00118 tmpInfo = GhostInfo;
00119 GhostData = BestGhostData;
00120 GhostInfo = GHO_BestGhostInfo;
00121 BestGhostData = tmpData;
00122 GHO_BestGhostInfo = tmpInfo;
00123 if (GHO_BestGhostInfo->NFrames < GHOST_DATA_MAX) {
00124 BestGhostData[GHO_BestGhostInfo->NFrames].Time = GHO_BestGhostInfo->Time[GHOST_LAP_TIME];
00125 }
00126
00127
00128 GHO_GhostExists = TRUE;
00129
00130 }
00131
00133
00134
00135
00137
00138 #define GHOST_POS_DEVIATION 500.0f
00139 #define GHOST_QUAT_DEVIATION 0.85f
00140
00141 bool StoreGhostData(CAR *car)
00142 {
00143 int iWheel;
00144 GHOST_DATA *data;
00145
00146
00147
00148 if (GhostInfo->NFrames >= GHOST_DATA_MAX) {
00149 return FALSE;
00150 }
00151
00152
00153 if (car->CurrentLapTime - GhostData[GhostInfo->NFrames - 1].Time < GHOST_MIN_TIMESTEP) {
00154 return FALSE;
00155 }
00156
00157
00158 data = &GhostData[GhostInfo->NFrames];
00159
00160 data->Time = car->CurrentLapTime;
00161 CopyVec(&car->Body->Centre.Pos, &data->Pos);
00162
00163 data->Quat.v[VX] = (char)(GHOST_VECTOR_SCALE * car->Body->Centre.Quat.v[VX]);
00164 data->Quat.v[VY] = (char)(GHOST_VECTOR_SCALE * car->Body->Centre.Quat.v[VY]);
00165 data->Quat.v[VZ] = (char)(GHOST_VECTOR_SCALE * car->Body->Centre.Quat.v[VZ]);
00166 data->Quat.v[S] = (char)(GHOST_VECTOR_SCALE * car->Body->Centre.Quat.v[S]);
00167
00168 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
00169 data->WheelPos[iWheel] = (char)(GHOST_WHEEL_SCALE * car->Wheel[iWheel].Pos);
00170 data->WheelAngle[iWheel] = (char)(GHOST_ANGLE_SCALE * car->Wheel[iWheel].TurnAngle);
00171 }
00172
00173
00174 if (GhostInfo->NFrames > 2) {
00175 REAL dt;
00176 VEC intPos, dR;
00177 QUATERNION intQuat, lastQuat, nextQuat;
00178 GHOST_DATA *lastData = &GhostData[GhostInfo->NFrames - 2];
00179 GHOST_DATA *nextData = &GhostData[GhostInfo->NFrames - 1];
00180 bool posOkay = FALSE;
00181 bool quatOkay = FALSE;
00182
00183
00184 VecMinusVec(&nextData->Pos, &lastData->Pos, &dR);
00185 dt = Real(nextData->Time - lastData->Time);
00186 if (dt > SMALL_REAL) {
00187 dt = Real(data->Time - lastData->Time) / dt;
00188 } else {
00189 dt = ZERO;
00190 }
00191 Assert(dt >= ZERO);
00192 VecPlusScalarVec(&lastData->Pos, dt, &dR, &intPos);
00193
00194 VecMinusVec(&intPos, &car->Body->Centre.Pos, &dR);
00195 if (VecDotVec(&dR, &dR) < GHOST_POS_DEVIATION) {
00196 posOkay = TRUE;
00197 }
00198
00199
00200 lastQuat.v[VX] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[VX]);
00201 lastQuat.v[VY] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[VY]);
00202 lastQuat.v[VZ] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[VZ]);
00203 lastQuat.v[S] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[S]);
00204 nextQuat.v[VX] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[VX]);
00205 nextQuat.v[VY] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[VY]);
00206 nextQuat.v[VZ] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[VZ]);
00207 nextQuat.v[S] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[S]);
00208 LerpQuat(&lastQuat, &nextQuat, dt, &intQuat);
00209 NormalizeQuat(&intQuat);
00210 if (QuatDotQuat(&intQuat, &car->Body->Centre.Quat) > GHOST_QUAT_DEVIATION) {
00211 quatOkay = TRUE;
00212 }
00213
00214
00215 if (posOkay && quatOkay) return FALSE;
00216
00217 }
00218
00219 GhostInfo->NFrames++;
00220
00221 return TRUE;
00222
00223 }
00224
00225
00227
00228
00229
00231
00232 void InterpGhostData(CAR *car)
00233 {
00234 REAL dt;
00235 VEC dR;
00236 MAT tmpMat;
00237 QUATERNION lastQuat, nextQuat;
00238 int iWheel;
00239
00240 GHOST_DATA *lastData, *nextData;
00241
00242
00243 while ((GHO_BestFrame > 0) && (car->CurrentLapTime < BestGhostData[GHO_BestFrame - 1].Time)) {
00244 GHO_BestFrame--;
00245 }
00246 while ((GHO_BestFrame < GHO_BestGhostInfo->NFrames - 1) && (car->CurrentLapTime > BestGhostData[GHO_BestFrame + 1].Time)) {
00247 GHO_BestFrame++;
00248 }
00249 lastData = &BestGhostData[GHO_BestFrame];
00250 nextData = &BestGhostData[GHO_BestFrame + 1];
00251
00252
00253 if (GHO_BestFrame > GHO_BestGhostInfo->NFrames - 3) {
00254 lastData = &BestGhostData[GHO_BestGhostInfo->NFrames - 2];
00255 nextData = &BestGhostData[GHO_BestGhostInfo->NFrames - 2];
00256 GHO_BestFrame = GHO_BestGhostInfo->NFrames - 2;
00257 }
00258
00259
00260 CopyVec(&car->Body->Centre.Pos, &car->Body->Centre.OldPos);
00261 VecMinusVec(&nextData->Pos, &lastData->Pos, &dR);
00262 dt = Real(nextData->Time - lastData->Time);
00263 if (dt > SMALL_REAL) {
00264 dt = Real(car->CurrentLapTime - lastData->Time) / dt;
00265 } else {
00266 dt = ZERO;
00267 }
00268 if (dt < ZERO) dt = ZERO;
00269 if (dt > ONE) dt = ONE;
00270
00271 DBG_dt = dt;
00272
00273 VecPlusScalarVec(&lastData->Pos, dt, &dR, &car->Body->Centre.Pos);
00274
00275
00276 if (TimeStep > SMALL_REAL) {
00277 VecMinusVec(&car->Body->Centre.Pos, &car->Body->Centre.OldPos, &car->Body->Centre.Vel);
00278 VecDivScalar(&car->Body->Centre.Vel, TimeStep);
00279 } else {
00280 SetVecZero(&car->Body->Centre.Vel);
00281 }
00282
00283 lastQuat.v[VX] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[VX]);
00284 lastQuat.v[VY] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[VY]);
00285 lastQuat.v[VZ] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[VZ]);
00286 lastQuat.v[S] = GHOST_VECTOR_INVSCALE * (REAL)(lastData->Quat.v[S]);
00287 nextQuat.v[VX] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[VX]);
00288 nextQuat.v[VY] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[VY]);
00289 nextQuat.v[VZ] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[VZ]);
00290 nextQuat.v[S] = GHOST_VECTOR_INVSCALE * (REAL)(nextData->Quat.v[S]);
00291
00292
00293 LerpQuat(&lastQuat, &nextQuat, dt, &car->Body->Centre.Quat);
00294 NormalizeQuat(&car->Body->Centre.Quat);
00295 QuatToMat(&car->Body->Centre.Quat, &car->Body->Centre.WMatrix);
00296
00297
00298 car->Revs = ZERO;
00299 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
00300 car->Wheel[iWheel].Pos = GHOST_WHEEL_INVSCALE * (REAL)lastData->WheelPos[iWheel];
00301 car->Wheel[iWheel].TurnAngle = GHOST_ANGLE_INVSCALE * (REAL)lastData->WheelAngle[iWheel];
00302
00303
00304 VecPlusScalarVec(&car->WheelOffset[iWheel], car->Wheel[iWheel].Pos, &DownVec, &dR);
00305 VecMulMat(&dR, &car->Body->Centre.WMatrix, &car->Wheel[iWheel].WPos);
00306 VecPlusEqVec(&car->Wheel[iWheel].WPos, &car->Body->Centre.Pos);
00307
00308
00309 car->Wheel[iWheel].AngVel = VecDotVec(&car->Body->Centre.Vel, &car->Body->Centre.WMatrix.mv[L]) / car->Wheel[iWheel].Radius;
00310 car->Wheel[iWheel].AngPos += TimeStep * car->Wheel[iWheel].AngVel;
00311 GoodWrap(&car->Wheel[iWheel].AngPos, ZERO, FULL_CIRCLE);
00312 car->Revs += car->Wheel[iWheel].AngVel;
00313
00314
00315 RotationY(&tmpMat, car->Wheel[iWheel].TurnAngle);
00316 MatMulMat(&tmpMat, &car->Body->Centre.WMatrix, &car->Wheel[iWheel].Axes);
00317 RotationX(&tmpMat, car->Wheel[iWheel].AngPos);
00318 MatMulMat(&tmpMat, &car->Wheel[iWheel].Axes, &car->Wheel[iWheel].WMatrix);
00319 }
00320 car->Revs *= Real(0.25);
00321
00322
00323 CopyVec(&car->Body->Centre.Pos, (VEC*)&GhostLight->x);
00324 GhostLight->r = 0;
00325 GhostLight->g = 32;
00326 GhostLight->b = 64;
00327 }
00328
00329
00331
00332
00333
00335
00336 bool LoadGhostData(LEVELINFO *levelInfo)
00337 {
00338 size_t nRead;
00339 FILE *fp;
00340
00341
00342 if (GameSettings.Mirrored)
00343 fp = fopen(GetLevelFilename(GHOST_FILENAME_MIRRORED, FILENAME_GAME_SETTINGS), "rb");
00344 else
00345 fp = fopen(GetLevelFilename(GHOST_FILENAME, FILENAME_GAME_SETTINGS), "rb");
00346
00347 if (fp == NULL) {
00348 return FALSE;
00349 }
00350
00351
00352 nRead = fread(GHO_BestGhostInfo, sizeof(GHOST_INFO), 1, fp);
00353 if (nRead < 1) {
00354 fclose(fp);
00355 return FALSE;
00356 }
00357
00358
00359 nRead = fread(BestGhostData, sizeof(GHOST_DATA), GHOST_DATA_MAX, fp);
00360 if (nRead < GHOST_DATA_MAX) {
00361 fclose(fp);
00362 return FALSE;
00363 }
00364
00365
00366 fclose(fp);
00367 return TRUE;
00368 }
00369
00370
00372
00373
00374
00376
00377 bool SaveGhostData(LEVELINFO *levelInfo)
00378 {
00379 int nWritten;
00380 FILE *fp;
00381
00382
00383 if (!GHO_GhostExists) {
00384 return FALSE;
00385 }
00386
00387
00388 if (GameSettings.Mirrored) {
00389 fp = fopen(GetLevelFilename(GHOST_FILENAME_MIRRORED, FILENAME_GAME_SETTINGS), "wb");
00390 } else {
00391 fp = fopen(GetLevelFilename(GHOST_FILENAME, FILENAME_GAME_SETTINGS), "wb");
00392 }
00393
00394 if (fp == NULL) {
00395 return FALSE;
00396 }
00397
00398
00399 nWritten = fwrite(GHO_BestGhostInfo, sizeof(GHOST_INFO), 1, fp);
00400 if (nWritten < 1) {
00401 fclose(fp);
00402 return FALSE;
00403 }
00404
00405
00406 nWritten = fwrite(BestGhostData, sizeof(GHOST_DATA), GHOST_DATA_MAX, fp);
00407 if (nWritten < GHOST_DATA_MAX) {
00408 fclose(fp);
00409 return FALSE;
00410 }
00411
00412
00413 fclose(fp);
00414 return TRUE;
00415 }
00416
00418
00419
00420
00422
00423 void InitGhostLight(void)
00424 {
00425 if ((GhostLight = AllocLight()))
00426 {
00427 GhostLight->Reach = 768;
00428 GhostLight->Flag = LIGHT_FIXED | LIGHT_MOVING;
00429 GhostLight->Type = LIGHT_OMNI;
00430 }
00431 }