00001 #include "Revolt.h"
00002
00003 #ifndef _PSX
00004 #include "Main.h"
00005 #endif
00006 #ifdef _PC
00007 #include "input.h"
00008 #endif
00009 #include "Geom.h"
00010 #include "NewColl.h"
00011 #ifndef _PSX
00012 #include "Model.h"
00013 #endif
00014 #include "Particle.h"
00015 #include "Body.h"
00016 #include "Aerial.h"
00017 #include "Wheel.h"
00018 #include "Car.h"
00019 #ifndef _PSX
00020 #include "ctrlread.h"
00021 #endif
00022 #include "object.h"
00023 #include "Control.h"
00024 #include "move.h"
00025 #ifndef _PSX
00026 #include "DrawObj.h"
00027 #endif
00028 #include "player.h"
00029 #ifndef _PSX
00030 #include "timing.h"
00031 #endif
00032 #ifdef _PC
00033 #include "registry.h"
00034 #include "sfx.h"
00035 #endif
00036 #ifndef _PSX
00037 #include "Spark.h"
00038 #endif
00039 #include "weapon.h"
00040
00041
00042 #if MSCOMPILER_FUDGE_OPTIMISATIONS
00043 #pragma optimize("", off)
00044 #endif
00045
00046
00047
00048
00049 #ifdef _PSX
00050 VEC LEV_StartPos;
00051 long LEV_StartGrid;
00052 extern CAR_MODEL Car_Model[];
00053 #endif
00054
00055 #if USE_DEBUG_ROUTINES
00056 extern long DEBUG_CollGrid;
00057 #endif
00058
00059 CAR_INFO *CarInfo = NULL;
00060 REAL MaxCannotMoveTime = 3;
00061
00062
00063 long NCarTypes = 0;
00064
00065 bool CAR_WheelsHaveSuspension = TRUE;
00066 bool CAR_DrawCarBBoxes = FALSE;
00067 bool CAR_DrawCarAxes = FALSE;
00068
00069 VEC SmokeVel = {ZERO, -72.0f, ZERO};
00070 VEC TurboVel = {ZERO, -64.0f, ZERO};
00071
00072
00073
00074
00075
00076 void InitAllCars(void);
00077 void SetupCar(struct PlayerStruct *player, int carType);
00078 void SetCarPos(CAR *car, VEC *pos, MAT *mat);
00079 void BuildTurnMatrices(CAR *car);
00080 void Car2Car(CAR *MyCar);
00081 void CarWorldColls(CAR *car);
00082 void CarCarColls(CAR *car1, CAR *car2);
00083 int DetectWheelBodyColls(CAR *car, NEWBODY *body);
00084 int DetectWheelSphereColls(CAR *car, int iWheel, NEWBODY *body);
00085 int DetectWheelConvexColls(CAR *car, int iWheel, NEWBODY *body);
00086 int DetectWheelPolyColls(CAR *car, int iWheel, NEWBODY *body);
00087 void InitRemoteCarData(CAR *car);
00088 int NextValidCarID(int currentID);
00089 int PrevValidCarID(int currentID);
00090 void RemoveWheelColl(CAR *car, COLLINFO_WHEEL *collInfo);
00091 COLLINFO_WHEEL *AddWheelColl(CAR *car, COLLINFO_WHEEL *newHead);
00092
00093
00094
00095
00096
00097
00098 GRID_POS CarGridStarts[][MAX_NUM_PLAYERS] = {
00099
00100
00101
00102 {
00103 {TO_LENGTH(Real(-128)), TO_LENGTH(Real(0)), TO_LENGTH(Real(0.0f))},
00104 {TO_LENGTH(Real(128)), TO_LENGTH(Real(-64)), TO_LENGTH(Real(0.0f))},
00105 {TO_LENGTH(Real(-128)), TO_LENGTH(Real(-128)), TO_LENGTH(Real(0.0f))},
00106 {TO_LENGTH(Real(128)), TO_LENGTH(Real(-192)), TO_LENGTH(Real(0.0f))},
00107 #ifdef _PC
00108 {-128, -256, 0.0f},
00109 {128, -320, 0.0f},
00110 {-128, -384, 0.0f},
00111 {128, -448, 0.0f},
00112 {-128, -512, 0.0f},
00113 {128, -576, 0.0f},
00114 {-128, -640, 0.0f},
00115 {128, -704, 0.0f},
00116 #endif
00117 },
00118
00119 {
00120 {0, 0, 0},
00121 {-250, 0, 0},
00122 {250, 0, 0},
00123 {0, -320, 0},
00124 #ifdef _PC
00125 {-250, -320, 0},
00126 {250, -320, 0},
00127 {0, -640, 0},
00128 {-250, -640, 0},
00129 {250, -640, 0},
00130 #endif
00131 },
00132
00133 {
00134 {-150, 0, 0},
00135 {-50, 0, 0},
00136 {50, 0, 0},
00137 {150, 0, 0},
00138 #ifdef _PC
00139 {-150, -256, 0},
00140 {-50, -256, 0},
00141 {50, -256, 0},
00142 {150, -256, 0},
00143 #endif
00144 },
00145
00146 {
00147 {-200, 0, 0},
00148 {200, 0, 0},
00149 {-200, -320, 0},
00150 {200, -320, 0},
00151 #ifdef _PC
00152 {-200, -640, 0},
00153 {200, -640, 0},
00154 {-200, -960, 0},
00155 {200, -960, 0},
00156 {-200, -1080, 0},
00157 {200, -1080, 0},
00158 #endif
00159 }
00160 };
00161
00162
00163
00164
00166
00168
00169 void InitCar(CAR *car)
00170 {
00171
00172
00173
00174 InitBodyDefault(car->Body);
00175 car->Models = NULL;
00176
00177
00178
00179 car->NextSplit = 0;
00180 car->Laps = 0;
00181 car->CurrentLapTime = 0;
00182 car->LastLapTime = 0;
00183 car->LastRaceTime = 0;
00184 #ifdef _PC
00185 car->BestLapTime = MAKE_TIME(5, 0, 0);
00186 car->BestRaceTime = MAKE_TIME(60, 0, 0);
00187 #endif
00188 car->Best0to15 = 100;
00189 car->Best0to25 = 100;
00190 car->Current0to15 = -ONE;
00191 car->Current0to25 = -ONE;
00192 car->Timing0to15 = FALSE;
00193 car->Timing0to25 = FALSE;
00194 car->Righting = FALSE;
00195 car->AddLit = 0;
00196 car->DrawScale = ONE;
00197 car->PowerTimer = ZERO;
00198 car->IsBomb = FALSE;
00199 car->WillDetonate = FALSE;
00200 car->NoReturnTimer = ZERO;
00201 }
00202
00203
00205
00206
00207
00208
00210
00211 int NextValidCarID(int currentID)
00212 {
00213 int carID;
00214
00215
00216 for (carID = currentID + 1; carID < NCarTypes; carID++) {
00217 if (CarInfo[carID].Selectable) {
00218 return carID;
00219 }
00220 }
00221
00222 for (carID = 0; carID < currentID; carID++) {
00223 if (CarInfo[carID].Selectable) {
00224 return carID;
00225 }
00226 }
00227
00228 return currentID;
00229 }
00230
00231 int PrevValidCarID(int currentID)
00232 {
00233 int carID;
00234
00235
00236 for (carID = currentID - 1; carID >= 0; carID--) {
00237 if (CarInfo[carID].Selectable) {
00238 return carID;
00239 }
00240 }
00241
00242 for (carID = NCarTypes - 1; carID > currentID; carID--) {
00243 if (CarInfo[carID].Selectable) {
00244 return carID;
00245 }
00246 }
00247
00248 return currentID;
00249 }
00250
00252
00253
00255
00256 void SetupCar(struct PlayerStruct *player, int carType)
00257 {
00258 long ii;
00259 CAR *car = &player->car;
00260
00261
00262 #ifndef _PSX
00263 if (car->Models) {
00264 FreeOneCarModelSet(player);
00265 }
00266 car->Models = &player->carmodels;
00267 LoadOneCarModelSet(player, carType);
00268 #else
00269 car->Models = &Car_Model[0];
00270 #endif
00271
00272
00273 if (car->Body->CollSkin.WorldConvex != NULL) {
00274 DestroyConvex(car->Body->CollSkin.WorldConvex, car->Body->CollSkin.NConvex);
00275 car->Body->CollSkin.WorldConvex = NULL;
00276 }
00277 if (car->Body->CollSkin.OldWorldConvex != NULL) {
00278 DestroyConvex(car->Body->CollSkin.OldWorldConvex, car->Body->CollSkin.NConvex);
00279 car->Body->CollSkin.OldWorldConvex = NULL;
00280 }
00281 if (car->Body->CollSkin.WorldSphere != NULL) {
00282 DestroySpheres(car->Body->CollSkin.WorldSphere);
00283 car->Body->CollSkin.WorldSphere = NULL;
00284 }
00285 if (car->Body->CollSkin.OldWorldSphere != NULL) {
00286 DestroySpheres(car->Body->CollSkin.OldWorldSphere);
00287 car->Body->CollSkin.OldWorldSphere = NULL;
00288 }
00289 car->Body->CollSkin.NConvex = car->Models->CollSkin.NConvex;
00290 car->Body->CollSkin.NSpheres = car->Models->CollSkin.NSpheres;
00291 car->Body->CollSkin.Convex = car->Models->CollSkin.Convex;
00292 car->Body->CollSkin.Sphere = car->Models->CollSkin.Sphere;
00293 CopyBBox(&car->Models->CollSkin.TightBBox, &car->Body->CollSkin.TightBBox);
00294 CreateCopyCollSkin(&car->Body->CollSkin);
00295
00296
00297 #ifndef _PSX
00298
00299
00300 CopyMatrix(&IdentityMatrix, &car->EnvMatrix);
00301
00302 #endif
00303
00304
00305
00306 car->CarID = carType;
00307
00308
00309 car->SteerRate = CarInfo[carType].SteerRate;
00310 car->SteerModifier = CarInfo[carType].SteerModifier;
00311 car->EngineRate = CarInfo[carType].EngineRate;
00312 car->TopSpeed = car->DefaultTopSpeed = CarInfo[carType].TopSpeed;
00313 car->MaxRevs = CarInfo[carType].MaxRevs;
00314 car->AllowedBestTime = CarInfo[carType].AllowedBestTime;
00315 car->DownForceMod = CarInfo[carType].DownForceMod;
00316 car->Selectable = CarInfo[carType].Selectable;
00317 CopyVec(&CarInfo[carType].WeaponOffset, &car->WeaponOffset);
00318 car->Best0to15 = -ONE;
00319 car->Best0to25 = -ONE;
00320 car->Current0to15 = ZERO;
00321 car->Current0to25 = ZERO;
00322
00323
00324 SetBodyConvex(car->Body);
00325 CopyVec(&CarInfo[carType].Body.Offset, &car->BodyOffset);
00326 SetParticleMass(&car->Body->Centre, CarInfo[carType].Body.Mass);
00327 SetBodyInertia(car->Body, &CarInfo[carType].Body.Inertia);
00328 car->Body->Centre.Gravity = CarInfo[carType].Body.Gravity;
00329 car->Body->Centre.Hardness = CarInfo[carType].Body.Hardness;
00330 car->Body->Centre.Resistance = CarInfo[carType].Body.Resistance;
00331 car->Body->Centre.StaticFriction = CarInfo[carType].Body.StaticFriction;
00332 car->Body->Centre.KineticFriction = CarInfo[carType].Body.KineticFriction;
00333 car->Body->DefaultAngRes = CarInfo[carType].Body.AngResistance;
00334 car->Body->AngResistance = CarInfo[carType].Body.AngResistance;
00335 car->Body->AngResMod = CarInfo[carType].Body.ResModifier;
00336 car->Body->Centre.Grip = CarInfo[carType].Body.Grip;
00337 car->Body->AllowSparks = TRUE;
00338
00339
00340 car->Body->JitterCountMax = 2;
00341 car->Body->JitterFramesMax = 10;
00342
00343
00344 for (ii = 0; ii < CAR_NWHEELS; ii++) {
00345
00346 CopyVec(&CarInfo[carType].Wheel[ii].Offset1, &car->WheelOffset[ii]);
00347 CopyVec(&CarInfo[carType].Wheel[ii].Offset2, &car->WheelCentre[ii]);
00348
00349 SetupWheel(&car->Wheel[ii], &CarInfo[carType].Wheel[ii]);
00350 }
00351
00352
00353
00354 for (ii = 0; ii < CAR_NWHEELS; ii++) {
00355 #ifndef _PSX
00356 car->Sus[ii].SpringLen = car->Models->SpringLen[ii];
00357 car->Sus[ii].AxleLen = car->Models->AxleLen[ii];
00358 car->Sus[ii].PinLen = car->Models->PinLen[ii];
00359 #endif
00360 CopyVec(&CarInfo[carType].Spring[ii].Offset, &car->SuspOffset[ii]);
00361 CopyVec(&CarInfo[carType].Axle[ii].Offset, &car->AxleOffset[ii]);
00362 SetupSuspension(&car->Spring[ii], &CarInfo[carType].Spring[ii]);
00363 }
00364
00365
00366 CopyMat(&Identity, &car->Spinner.Matrix);
00367 CopyVec(&CarInfo[carType].Spinner.Offset, &car->SpinnerOffset);
00368 CopyVec(&CarInfo[carType].Spinner.Axis, &car->Spinner.Axis);
00369 car->Spinner.AngVel = CarInfo[carType].Spinner.AngVel;
00370
00371
00372
00373 CopyVec(&CarInfo[carType].Aerial.Offset, &car->AerialOffset);
00374 #ifndef _PSX
00375 InitAerial(&car->Aerial,
00376 &car->Models->DirAerial,
00377 car->Models->AerialLen,
00378 1.0f, 1.0f, 0.00f, 100.0f);
00379 #else
00380 InitAerial(&car->Aerial,
00381 &UpVec,
00382 TO_LENGTH(20<<16),
00383 1.0f, 1.0f, 0.00f, 100.0f);
00384 #endif
00385 SetAerialSprings(&car->Aerial,
00386 CarInfo[carType].Aerial.Stiffness,
00387 CarInfo[carType].Aerial.Damping,
00388 6000.0f);
00389
00390
00391
00392 }
00393
00395
00396
00397
00399
00400 void FreeCar(struct PlayerStruct *player)
00401 {
00402 CAR *car = &player->car;
00403
00404 #ifndef _PSX
00405 FreeOneCarModelSet(player);
00406 #endif
00407 DestroyConvex(car->Body->CollSkin.OldWorldConvex, car->Body->CollSkin.NConvex);
00408 DestroyConvex(car->Body->CollSkin.WorldConvex, car->Body->CollSkin.NConvex);
00409 car->Body->CollSkin.OldWorldConvex = NULL;
00410 car->Body->CollSkin.WorldConvex = NULL;
00411
00412 DestroySpheres(car->Body->CollSkin.OldWorldSphere);
00413 DestroySpheres(car->Body->CollSkin.WorldSphere);
00414 car->Body->CollSkin.OldWorldSphere = NULL;
00415 car->Body->CollSkin.WorldSphere = NULL;
00416 }
00417
00419
00421
00422 void GetCarGrid(long position, VEC *pos, MAT *mat)
00423 {
00424 GRID_POS *grid;
00425 VEC off;
00426
00427
00428
00429 grid = &CarGridStarts[LEV_StartGrid][position];
00430
00431
00432
00433 #ifndef _PSX
00434 RotMatrixY(mat, -LEV_StartRot - grid->rotoff);
00435 #else
00436 SetMatUnit(mat);
00437 #endif
00438
00439
00440
00441 SetVector(&off, grid->xoff, 0, grid->zoff);
00442 VecMulMat(&off, mat, pos);
00443 VecPlusEqVec(pos, &LEV_StartPos);
00444
00445 }
00446
00448
00450
00451 void SetCarPos(CAR *car, VEC *pos, MAT *mat)
00452 {
00453
00454 int iWheel;
00455
00456
00457 SetBodyPos(car->Body, pos, mat);
00458
00459
00460 car->SteerAngle = ZERO;
00461 car->EngineVolt = ZERO;
00462
00463
00464 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
00465 ResetCarWheelPos(car, iWheel);
00466 }
00467
00468
00469 CopyBBox(&car->Body->CollSkin.BBox, &car->BBox);
00470 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
00471 AddPosRadToBBox(&car->BBox, &car->Wheel[iWheel].WPos, car->Wheel[iWheel].Radius);
00472 }
00473
00474
00475 SetCarAerialPos(car);
00476
00477
00478 #ifdef _PC
00479 SetVecZero(&car->FieldVec);
00480
00481 InitRemoteCarData(car);
00482 #endif
00483 }
00484
00485 #ifdef _PC
00487 //
00488
00489
00490
00492
00493 void InitRemoteCarData(CAR *car)
00494 {
00495 long i;
00496
00497 car->OldDat = 0;
00498 car->Dat = 1;
00499 car->NewDat = 2;
00500
00501 for (i = 0 ; i < 3 ; i++)
00502 {
00503 car->RemoteData[i].PacketInfo = 0xffffffff;
00504 car->RemoteData[i].NewData = FALSE;
00505 CopyVec(&car->Body->Centre.Pos, &car->RemoteData[i].Pos);
00506 CopyVec(&car->Body->Centre.Vel, &car->RemoteData[i].Vel);
00507 CopyVec(&car->Body->AngVel, &car->RemoteData[i].AngVel);
00508 CopyQuat(&car->Body->Centre.Quat, &car->RemoteData[i].Quat);
00509 }
00510 }
00511
00513
00514
00515
00516
00517
00518
00519
00521
00522 REMOTE_DATA *NextRemoteData(CAR *car)
00523 {
00524 int tmp;
00525
00526
00527 if (car->RemoteData[car->NewDat].NewData) {
00528 return &car->RemoteData[car->NewDat];
00529 }
00530
00531
00532 tmp = car->OldDat;
00533 car->OldDat = car->Dat;
00534 car->Dat = car->NewDat;
00535 car->NewDat = tmp;
00536
00537 return &car->RemoteData[tmp];
00538
00539 }
00540
00542
00544
00545 void SendLocalCarData(void)
00546 {
00547 MESSAGE_HEADER *header = (MESSAGE_HEADER*)TransmitBuff;
00548 CAR *car = &PLR_LocalPlayer->car;
00549 short *sh;
00550 char *ptr = (CHAR*)(header + 1);
00551
00552
00553
00554 header->Type = MESSAGE_CAR_DATA;
00555 header->Contents = 0;
00556
00557
00558
00559 CopyVec(&car->Body->Centre.Pos, (VEC*)ptr);
00560 ptr += sizeof(VEC);
00561 header->Contents |= MESSAGE_CONTENTS_CAR_POS;
00562
00563
00564
00565 *ptr++ = (char)(car->Body->Centre.Quat.v[VX] * CAR_REMOTE_QUAT_SCALE);
00566 *ptr++ = (char)(car->Body->Centre.Quat.v[VY] * CAR_REMOTE_QUAT_SCALE);
00567 *ptr++ = (char)(car->Body->Centre.Quat.v[VZ] * CAR_REMOTE_QUAT_SCALE);
00568 *ptr++ = (char)(car->Body->Centre.Quat.v[S] * CAR_REMOTE_QUAT_SCALE);
00569 header->Contents |= MESSAGE_CONTENTS_CAR_QUAT;
00570
00571
00572
00573
00574
00575 sh = (short*)ptr;
00576 *sh++ = (short)(car->Body->Centre.Vel.v[X] * CAR_REMOTE_VEL_SCALE);
00577 *sh++ = (short)(car->Body->Centre.Vel.v[Y] * CAR_REMOTE_VEL_SCALE);
00578 *sh++ = (short)(car->Body->Centre.Vel.v[Z] * CAR_REMOTE_VEL_SCALE);
00579 header->Contents |= MESSAGE_CONTENTS_CAR_VEL;
00580 ptr = (char*)sh;
00581
00582
00583
00584
00585
00586 sh = (short*)ptr;
00587 *sh++ = (short)(car->Body->AngVel.v[X] * CAR_REMOTE_ANGVEL_SCALE);
00588 *sh++ = (short)(car->Body->AngVel.v[Y] * CAR_REMOTE_ANGVEL_SCALE);
00589 *sh++ = (short)(car->Body->AngVel.v[Z] * CAR_REMOTE_ANGVEL_SCALE);
00590 header->Contents |= MESSAGE_CONTENTS_CAR_ANGVEL;
00591 ptr = (char*)sh;
00592
00593
00594
00595
00596
00597 *ptr++ = PLR_LocalPlayer->controls.dx;
00598 *ptr++ = PLR_LocalPlayer->controls.dy;
00599 header->Contents |= MESSAGE_CONTENTS_CAR_CONTROL;
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 TransmitMessage(TransmitBuff, (short)(ptr - TransmitBuff), DPID_ALLPLAYERS, MESSAGE_PRIORITY_CAR);
00611 }
00612
00613 #endif
00614
00616
00617
00618
00620
00621 #ifndef _PSX
00622
00623 void SetCarAerialPos(CAR *car)
00624 {
00625 VEC vecTemp;
00626 VEC wDirection;
00627 int iSec, iCount;
00628 PARTICLE *pSection = &car->Aerial.Section[0];
00629 iCount = 0;
00630
00631
00632 VecMulMat(&car->Aerial.Direction, &car->Body->Centre.WMatrix, &wDirection);
00633 VecMulMat(&car->AerialOffset, &car->Body->Centre.WMatrix, &vecTemp);
00634 VecPlusVec(&vecTemp, &car->Body->Centre.Pos, &pSection->Pos);
00635
00636 SetVecZero(&pSection->Vel);
00637 SetVecZero(&pSection->Acc);
00638 SetVecZero(&pSection->Impulse);
00639
00640
00641 for (iSec = AERIAL_START; iSec < AERIAL_NSECTIONS; iSec += AERIAL_SKIP) {
00642 iCount++;
00643
00644 pSection = &car->Aerial.Section[iSec];
00645
00646
00647 VecEqScalarVec(&pSection->Pos, MulScalar(iCount, car->Aerial.Length), &wDirection);
00648 VecPlusEqVec(&pSection->Pos, &car->Aerial.Section[0].Pos);
00649
00650
00651 SetVecZero(&pSection->Vel);
00652 SetVecZero(&pSection->Acc);
00653 SetVecZero(&pSection->Impulse);
00654
00655 }
00656 }
00657
00658 #else
00659
00660 void SetCarAerialPos(CAR *car)
00661 {
00662 VEC vecTemp;
00663 VEC wDirection;
00664 int iSec, iCount;
00665 PARTICLE *pSection = &car->Aerial.Section[0];
00666 VEC Temp;
00667
00668 MAT Matrix;
00669
00670
00671 Matrix.m[0] = car->Matrix.m[0][0] << 4;
00672 Matrix.m[1] = car->Matrix.m[1][0] << 4;
00673 Matrix.m[2] = car->Matrix.m[2][0] << 4;
00674 Matrix.m[3] = car->Matrix.m[0][1] << 4;
00675 Matrix.m[4] = car->Matrix.m[1][1] << 4;
00676 Matrix.m[5] = car->Matrix.m[2][1] << 4;
00677 Matrix.m[6] = car->Matrix.m[0][2] << 4;
00678 Matrix.m[7] = car->Matrix.m[1][2] << 4;
00679 Matrix.m[8] = car->Matrix.m[2][2] << 4;
00680
00681 iCount = 0;
00682
00683
00684
00685 VecMulMat(&car->Aerial.Direction, &Matrix, &wDirection);
00686
00687 VecMulMat(&car->AerialOffset, &Matrix, &vecTemp);
00688
00689
00690 Temp.v[X] = car->Pos.vx << 16;
00691 Temp.v[Y] = car->Pos.vy << 16;
00692 Temp.v[Z] = car->Pos.vz << 16;
00693
00694 VecPlusVec(&vecTemp, &Temp, &pSection->Pos);
00695
00696 SetVecZero(&pSection->Vel);
00697 SetVecZero(&pSection->Acc);
00698 SetVecZero(&pSection->Impulse);
00699
00700
00701
00702 for (iSec = AERIAL_START; iSec < AERIAL_NSECTIONS; iSec += AERIAL_SKIP)
00703 {
00704 iCount++;
00705
00706 pSection = &car->Aerial.Section[iSec];
00707
00708
00709 VecEqScalarVec(&pSection->Pos, MulScalar(iCount<<16, car->Aerial.Length), &wDirection);
00710 VecPlusEqVec(&pSection->Pos, &car->Aerial.Section[0].Pos);
00711
00712
00713 SetVecZero(&pSection->Vel);
00714 SetVecZero(&pSection->Acc);
00715 SetVecZero(&pSection->Impulse);
00716 }
00717 }
00718
00719 #endif
00720
00721
00722
00724
00725
00726
00728
00729 #ifndef _PSX
00730
00731 void UpdateCarAerial2(CAR *car, REAL dt)
00732 {
00733 int iSec;
00734 VEC vecTemp;
00735 VEC dRPrev;
00736 REAL prevLen;
00737 REAL scale;
00738 VEC dRThis;
00739 REAL thisLen;
00740 VEC thisCrossPrev;
00741 REAL crossLen;
00742 REAL velDotThis;
00743 REAL velDotDir;
00744 VEC velPar;
00745 VEC impulse = {ZERO, ZERO, ZERO};
00746 VEC dRTot = {ZERO, ZERO, ZERO};
00747
00748
00749
00750
00751 VecMulMat(&car->AerialOffset, &car->Body->Centre.WMatrix, &vecTemp);
00752 VecPlusVec(&vecTemp, &car->Body->Centre.Pos, &car->Aerial.Section[0].Pos);
00753 VecMulMat(&car->Aerial.Direction, &car->Body->Centre.WMatrix, &dRPrev);
00754
00755 prevLen = ONE;
00756
00757
00758 for (iSec = AERIAL_START; iSec < AERIAL_NSECTIONS; iSec += AERIAL_SKIP) {
00759
00760
00761 UpdateParticle(&car->Aerial.Section[iSec], dt);
00762
00763
00764
00765 VecMinusVec(&car->Aerial.Section[iSec].Pos, &car->Aerial.Section[iSec - AERIAL_SKIP].Pos, &dRThis);
00766 thisLen = Length(&dRThis);
00767
00768 VecDivScalar(&dRThis, thisLen);
00769
00770
00771 VecPlusEqScalarVec(&car->Aerial.Section[iSec].Pos, car->Aerial.Length - thisLen, &dRThis);
00772
00773
00774 VecCrossVec(&dRThis, &dRPrev, &thisCrossPrev);
00775 crossLen = VecLen(&thisCrossPrev);
00776 VecCrossVec(&dRThis, &thisCrossPrev, &vecTemp);
00777 scale = MulScalar(car->Aerial.Length, car->Aerial.Stiffness);
00778 scale = MulScalar(scale, crossLen);
00779 VecEqScalarVec(&impulse, -scale, &vecTemp);
00780
00781
00782 VecMinusVec(&car->Aerial.Section[iSec].Vel, &car->Aerial.Section[0].Vel, &velPar);
00783 velDotDir = VecDotVec(&velPar, &dRPrev);
00784 VecPlusEqScalarVec(&velPar, -velDotDir, &dRPrev);
00785 VecPlusEqScalarVec(&impulse, -car->Aerial.Damping, &velPar);
00786
00787
00788 VecMulScalar(&impulse, dt);
00789
00790
00791 ApplyParticleImpulse(&car->Aerial.Section[iSec], &impulse);
00792
00793
00794 CopyVec(&dRThis, &dRPrev);
00795 prevLen = thisLen;
00796
00797
00798 VecMinusVec(&car->Aerial.Section[iSec].Pos, &car->Aerial.Section[iSec - AERIAL_SKIP].Pos, &dRThis);
00799 thisLen = VecLen(&dRThis);
00800
00801 VecDivScalar(&dRThis, thisLen);
00802
00803 VecPlusEqScalarVec(&car->Aerial.Section[iSec].Pos, car->Aerial.Length - thisLen, &dRThis);
00804
00805
00806 #ifdef _PC
00807 ParticleWorldColls(&car->Aerial.Section[iSec]);
00808 #endif
00809
00810
00811 VecMinusVec(&car->Aerial.Section[iSec].Vel, &car->Aerial.Section[iSec - AERIAL_SKIP].Vel, &vecTemp);
00812 velDotThis = VecDotVec(&vecTemp, &dRThis);
00813 VecPlusEqScalarVec(&car->Aerial.Section[iSec].Vel, -velDotThis, &dRThis);
00814
00815
00816 }
00817
00818 }
00819
00820 #else
00821
00822 void UpdateCarAerial2(CAR *car, REAL dt)
00823 {
00824 int iSec;
00825 VEC vecTemp;
00826 VEC dRPrev;
00827 REAL prevLen;
00828 REAL scale;
00829 VEC dRThis;
00830 REAL thisLen;
00831 VEC thisCrossPrev;
00832 REAL crossLen;
00833 REAL velDotThis;
00834 REAL velDotDir;
00835 VEC velPar;
00836 VEC impulse = {ZERO, ZERO, ZERO};
00837 VEC dRTot = {ZERO, ZERO, ZERO};
00838 VEC Temp;
00839
00840 MAT Matrix;
00841
00842 Matrix.m[0] = car->Matrix.m[0][0]<<4;
00843 Matrix.m[1] = car->Matrix.m[1][0]<<4;
00844 Matrix.m[2] = car->Matrix.m[2][0]<<4;
00845 Matrix.m[3] = car->Matrix.m[0][1]<<4;
00846 Matrix.m[4] = car->Matrix.m[1][1]<<4;
00847 Matrix.m[5] = car->Matrix.m[2][1]<<4;
00848 Matrix.m[6] = car->Matrix.m[0][2]<<4;
00849 Matrix.m[7] = car->Matrix.m[1][2]<<4;
00850 Matrix.m[8] = car->Matrix.m[2][2]<<4;
00851
00852
00853
00854
00855
00856
00857
00858 VecMulMat(&car->AerialOffset, &Matrix, &vecTemp);
00859
00860 Temp.v[0] = car->Pos.vx << 16;
00861 Temp.v[1] = car->Pos.vy << 16;
00862 Temp.v[2] = car->Pos.vz << 16;
00863 VecPlusVec(&vecTemp, &Temp, &car->Aerial.Section[0].Pos);
00864
00865
00866 VecMulMat(&car->Aerial.Direction, &Matrix, &dRPrev);
00867
00868 prevLen = ONE;
00869
00870
00871 for (iSec = AERIAL_START; iSec < AERIAL_NSECTIONS; iSec += AERIAL_SKIP) {
00872
00873
00874 UpdateParticle(&car->Aerial.Section[iSec], dt);
00875
00876
00877
00878 VecMinusVec(&car->Aerial.Section[iSec - AERIAL_SKIP].Pos, &car->Aerial.Section[iSec].Pos, &dRThis);
00879
00880
00881 thisLen = Length(&dRThis);
00882
00883 VecDivScalar(&dRThis, thisLen);
00884
00885
00886 VecPlusEqScalarVec(&car->Aerial.Section[iSec].Pos, (car->Aerial.Length - thisLen), &dRThis);
00887
00888
00889 VecCrossVec(&dRThis, &dRPrev, &thisCrossPrev);
00890 crossLen = VecLen(&thisCrossPrev);
00891 VecCrossVec(&dRThis, &thisCrossPrev, &vecTemp);
00892 scale = MulScalar(car->Aerial.Length, car->Aerial.Stiffness);
00893 scale = MulScalar(scale, crossLen);
00894 VecEqScalarVec(&impulse, -scale, &vecTemp);
00895
00896
00897 VecMinusVec(&car->Aerial.Section[iSec].Vel, &car->Aerial.Section[0].Vel, &velPar);
00898 velDotDir = VecDotVec(&velPar, &dRPrev);
00899 VecPlusEqScalarVec(&velPar, -velDotDir, &dRPrev);
00900 VecPlusEqScalarVec(&impulse, -car->Aerial.Damping, &velPar);
00901
00902
00903 VecMulScalar(&impulse, dt);
00904
00905
00906 ApplyParticleImpulse(&car->Aerial.Section[iSec], &impulse);
00907
00908
00909 CopyVec(&dRThis, &dRPrev);
00910 prevLen = thisLen;
00911
00912
00913 VecMinusVec(&car->Aerial.Section[iSec].Pos, &car->Aerial.Section[iSec - AERIAL_SKIP].Pos, &dRThis);
00914 thisLen = VecLen(&dRThis);
00915
00916 VecDivScalar(&dRThis, thisLen);
00917
00918 VecPlusEqScalarVec(&car->Aerial.Section[iSec].Pos, car->Aerial.Length - thisLen, &dRThis);
00919
00920
00921 VecMinusVec(&car->Aerial.Section[iSec].Vel, &car->Aerial.Section[iSec - AERIAL_SKIP].Vel, &vecTemp);
00922 velDotThis = VecDotVec(&vecTemp, &dRThis);
00923 VecPlusEqScalarVec(&car->Aerial.Section[iSec].Vel, -velDotThis, &dRThis);
00924
00925 }
00926
00927
00928 car->AerialPos[0] = car->Aerial.Section[0].Pos;
00929 car->AerialPos[2] = car->Aerial.Section[1].Pos;
00930 car->AerialPos[4] = car->Aerial.Section[2].Pos;
00931
00932 Interpolate3D( &car->Aerial.Section[0].Pos, &car->Aerial.Section[1].Pos, &car->Aerial.Section[2].Pos, 16384, &car->AerialPos[1] );
00933 Interpolate3D( &car->Aerial.Section[0].Pos, &car->Aerial.Section[1].Pos, &car->Aerial.Section[2].Pos, 49152, &car->AerialPos[3] );
00934
00935 }
00936
00937
00938 #endif
00939
00940
00941
00943
00944
00945
00946
00948
00949 CAR_INFO *CreateCarInfo(long nInfo)
00950 {
00951 return (CAR_INFO *)malloc(sizeof(CAR_INFO) * nInfo);
00952 }
00953
00954 void DestroyCarInfo()
00955 {
00956 if ((CarInfo == NULL) || (NCarTypes == 0)) return;
00957 free(CarInfo);
00958 CarInfo = NULL;
00959 NCarTypes = 0;
00960 }
00961
00963
00964
00965
00966
00968
00969 CAR_MODEL *CreateCarModels(long nModels)
00970 {
00971 return (CAR_MODEL *)malloc(sizeof(CAR_MODEL) * nModels);
00972 }
00973
00974 void DestroyCarModels(CAR_MODEL *carModels)
00975 {
00976 free(carModels);
00977 }
00978
00979
00981
00982
00983
00985
00986 void ResetCarWheelPos(CAR *car, int iWheel)
00987 {
00988 WHEEL *wheel = &car->Wheel[iWheel];
00989
00990 wheel->Pos = ZERO;
00991 wheel->Vel = ZERO;
00992 wheel->Acc = ZERO;
00993 wheel->Impulse = ZERO;
00994 wheel->AngPos = ZERO;
00995 wheel->AngVel = ZERO;
00996 wheel->AngAcc = ZERO;
00997 wheel->AngImpulse = ZERO;
00998
00999 wheel->TurnAngle = ZERO;
01000
01001 VecMulMat(&car->WheelOffset[iWheel], &car->Body->Centre.WMatrix, &wheel->WPos);
01002 VecPlusEqVec(&wheel->WPos, &car->Body->Centre.Pos);
01003 CopyVec(&wheel->WPos, &wheel->OldWPos);
01004 VecMulMat(&car->WheelCentre[iWheel], &car->Body->Centre.WMatrix, &wheel->CentrePos);
01005 VecPlusEqVec(&wheel->CentrePos, &wheel->WPos);
01006 CopyVec(&wheel->CentrePos, &wheel->OldCentrePos);
01007
01008
01009 SetBBox(&wheel->BBox,
01010 Min(wheel->OldCentrePos.v[X], wheel->CentrePos.v[X]) - wheel->Radius,
01011 Max(wheel->OldCentrePos.v[X], wheel->CentrePos.v[X]) + wheel->Radius,
01012 Min(wheel->OldCentrePos.v[Y], wheel->CentrePos.v[Y]) - wheel->Radius,
01013 Max(wheel->OldCentrePos.v[Y], wheel->CentrePos.v[Y]) + wheel->Radius,
01014 Min(wheel->OldCentrePos.v[Z], wheel->CentrePos.v[Z]) - wheel->Radius,
01015 Max(wheel->OldCentrePos.v[Z], wheel->CentrePos.v[Z]) + wheel->Radius);
01016
01017 CopyMat(&car->Body->Centre.WMatrix, &wheel->Axes);
01018
01019 }
01020
01022
01023
01024
01025
01027
01028 void UpdateCarWheel(CAR *car, int iWheel, REAL dt)
01029 {
01030 REAL scale;
01031 VEC tmpVec;
01032 VEC dR, centAcc;
01033 MAT tmpMat;
01034 WHEEL *wheel = &car->Wheel[iWheel];
01035 SPRING *spring = &car->Spring[iWheel];
01036
01037
01038 if ((IsWheelPowered(wheel) && !IsWheelInContact(wheel)) || (IsWheelSpinning(wheel) && IsWheelInContact(wheel))) {
01039
01040 wheel->AngImpulse += MulScalar(dt, MulScalar(car->EngineVolt, wheel->SpinAngImp));
01041 }
01042
01043
01044 wheel->Acc = MulScalar(wheel->InvMass, wheel->Impulse);
01045 wheel->AngAcc = MulScalar(wheel->InvInertia, wheel->AngImpulse);
01046
01047 if (CAR_WheelsHaveSuspension) {
01048
01049
01050
01051 #ifndef _PSX
01052 VecMinusVec(&wheel->WPos, &car->Body->Centre.Pos, &dR);
01053 VecCrossVec(&dR, &car->Body->AngVel, &tmpVec);
01054 VecCrossVec(&car->Body->AngVel, &tmpVec, ¢Acc);
01055 wheel->Acc += MulScalar(dt, VecDotVec(¢Acc, &car->Body->Centre.WMatrix.mv[U]));
01056 wheel->Acc -= VecDotVec(&car->Body->Centre.Acc, &car->Body->Centre.WMatrix.mv[U]);
01057 #endif
01058
01059 }
01060
01061
01062 wheel->Vel += wheel->Acc;
01063 wheel->AngVel += wheel->AngAcc;
01064
01065
01066 scale = MulScalar(MulScalar(FRICTION_TIME_SCALE, dt), wheel->AxleFriction);
01067 wheel->AngVel = MulScalar(wheel->AngVel, (ONE - scale));
01068
01069
01070 wheel->Pos += MulScalar(wheel->Vel, dt);
01071 Limit(wheel->Pos, -wheel->MaxPos, wheel->MaxPos);
01072 wheel->AngPos += MulScalar(wheel->AngVel, dt);
01073 GoodWrap(&wheel->AngPos, ZERO, FULL_CIRCLE);
01074
01075 if (CAR_WheelsHaveSuspension) {
01076
01077
01078 if (!IsWheelInContact(wheel)) {
01079 wheel->Vel += MulScalar(wheel->InvMass, MulScalar(SpringDampedForce(spring, wheel->Pos, wheel->Vel), dt));
01080 } else {
01081 wheel->Vel += MulScalar(wheel->InvMass, MulScalar(SpringDampedForce(spring, wheel->Pos, wheel->Vel), dt)) / 2;
01082 }
01083
01084 }
01085
01086
01087 if (IsWheelTurnable(wheel)) {
01088 wheel->TurnAngle = MulScalar(car->SteerAngle, wheel->SteerRatio);
01089 }
01090
01091
01092 CopyVec(&wheel->WPos, &wheel->OldWPos);
01093 VecPlusScalarVec(&car->WheelOffset[iWheel], wheel->Pos, &DownVec, &tmpVec);
01094 VecMulMat(&tmpVec, &car->Body->Centre.WMatrix, &wheel->WPos);
01095 VecPlusEqVec(&wheel->WPos, &car->Body->Centre.Pos);
01096
01097 CopyVec(&wheel->CentrePos, &wheel->OldCentrePos);
01098 VecMulMat(&car->WheelCentre[iWheel], &car->Body->Centre.WMatrix, &tmpVec);
01099 VecPlusVec(&wheel->WPos, &tmpVec, &wheel->CentrePos);
01100
01101
01102 RotationY(&tmpMat, wheel->TurnAngle);
01103 MatMulMat(&tmpMat, &car->Body->Centre.WMatrix, &wheel->Axes);
01104 RotationX(&tmpMat, wheel->AngPos);
01105 MatMulMat(&tmpMat, &wheel->Axes, &wheel->WMatrix);
01106
01107
01108
01109
01110 SetBBox(&wheel->BBox,
01111 Min(wheel->OldCentrePos.v[X], wheel->CentrePos.v[X]) - wheel->Radius,
01112 Max(wheel->OldCentrePos.v[X], wheel->CentrePos.v[X]) + wheel->Radius,
01113 Min(wheel->OldCentrePos.v[Y], wheel->CentrePos.v[Y]) - wheel->Radius,
01114 Max(wheel->OldCentrePos.v[Y], wheel->CentrePos.v[Y]) + wheel->Radius,
01115 Min(wheel->OldCentrePos.v[Z], wheel->CentrePos.v[Z]) - wheel->Radius,
01116 Max(wheel->OldCentrePos.v[Z], wheel->CentrePos.v[Z]) + wheel->Radius);
01117
01118
01119 wheel->Impulse = ZERO;
01120 wheel->AngImpulse = ZERO;
01121
01122 }
01123
01124
01125
01126 void DetectCarWheelColls2(CAR *car, int iWheel, NEWCOLLPOLY *worldPoly)
01127 {
01128 VEC tmpVec;
01129 REAL time;
01130 WHEEL *wheel = &car->Wheel[iWheel];
01131 COLLINFO_WHEEL *wheelColl;
01132
01133
01134 if ((wheelColl = NextWheelCollInfo()) == NULL) return;
01135
01136
01137 if (!BBTestYXZ(&wheel->BBox, &worldPoly->BBox)) return;
01138
01139
01140 if (SphereCollPoly(&wheel->OldCentrePos, &wheel->CentrePos,
01141 wheel->Radius,
01142 worldPoly,
01143 &wheelColl->Plane,
01144 &wheelColl->Pos,
01145 &wheelColl->WorldPos,
01146 &wheelColl->Depth,
01147 &time))
01148 {
01149
01150
01151 VecPlusEqScalarVec(&wheelColl->WorldPos, SKID_RAISE, PlaneNormal(&wheelColl->Plane));
01152
01153
01154 VecPlusEqVec(&wheelColl->Pos, &wheel->CentrePos);
01155 VecMinusEqVec(&wheelColl->Pos, &car->Body->Centre.Pos);
01156
01157
01158 VecCrossVec(&car->Body->AngVel, &wheelColl->Pos, &wheelColl->Vel);
01159 VecPlusEqVec(&wheelColl->Vel, &car->Body->Centre.Vel);
01160
01161
01162 VecPlusScalarVec(&wheelColl->Vel, wheel->Vel, &car->Body->Centre.WMatrix.mv[U], &tmpVec);
01163 if (VecDotVec(&tmpVec, PlaneNormal(&wheelColl->Plane)) > ZERO) return;
01164
01165
01166 wheelColl->Material = &COL_MaterialInfo[worldPoly->Material];
01167 AdjustWheelColl(wheelColl, wheelColl->Material);
01168
01169
01170 wheelColl->Car = car;
01171 wheelColl->IWheel = iWheel;
01172 wheelColl->Grip = MulScalar(wheel->Grip, wheelColl->Material->Gripiness);
01173 wheelColl->StaticFriction = MulScalar(wheel->StaticFriction, wheelColl->Material->Roughness);
01174 wheelColl->KineticFriction = MulScalar(wheel->KineticFriction, wheelColl->Material->Roughness);
01175 wheelColl->Restitution = ZERO;
01176 wheelColl->Body2 = &BDY_MassiveBody;
01177 SetVecZero(&wheelColl->Pos2);
01178
01179
01180
01181 SetWheelInContact(wheel);
01182 SetWheelNotSpinning(wheel);
01183
01184
01185 AddWheelColl(car, wheelColl);
01186
01187 }
01188 }
01189
01190
01192
01193
01194
01196
01197 void PreProcessCarWheelColls(CAR *car)
01198 {
01199 bool keepGoing;
01200 int iOil;
01201 WHEEL *wheel;
01202 COLLINFO_WHEEL *wheelColl1, *wheelColl2;
01203 VEC *collpos;
01204 REAL dx, dz;
01205
01206 for (wheelColl1 = car->WheelCollHead; wheelColl1 != NULL; wheelColl1 = wheelColl1->Next) {
01207
01208 wheel = &car->Wheel[wheelColl1->IWheel];
01209
01210 #ifndef _PSX
01211
01212 collpos = &wheelColl1->WorldPos;
01213
01214 for (iOil = 0 ; iOil < OilSlickCount ; iOil++)
01215 {
01216 if (collpos->v[Y] < OilSlickList[iOil].Ymin)
01217 continue;
01218
01219 if (collpos->v[Y] > OilSlickList[iOil].Ymax)
01220 continue;
01221
01222 dx = OilSlickList[iOil].X - collpos->v[X];
01223 if (abs(dx) > OilSlickList[iOil].Radius)
01224 continue;
01225
01226 dz = OilSlickList[iOil].Z - collpos->v[Z];
01227 if (abs(dz) > OilSlickList[iOil].Radius)
01228 continue;
01229
01230 if ((dx * dx + dz * dz) > OilSlickList[iOil].SquaredRadius)
01231 continue;
01232
01233 SetWheelInOil(&wheelColl1->Car->Wheel[wheelColl1->IWheel]);
01234 break;
01235 }
01236
01237
01238 if (wheel->OilTime < OILY_WHEEL_TIME) {
01239 wheelColl1->StaticFriction *= HALF * (wheel->OilTime + TO_TIME(Real(0.2))) / (OILY_WHEEL_TIME + TO_TIME(Real(0.2)));
01240 wheelColl1->KineticFriction *= HALF * (wheel->OilTime + TO_TIME(Real(0.2))) / (OILY_WHEEL_TIME + TO_TIME(Real(0.2)));
01241 }
01242 #endif
01243
01244
01245
01246 keepGoing = TRUE;
01247 for (wheelColl2 = wheelColl1->Next; (wheelColl2 != NULL) && keepGoing; wheelColl2 = wheelColl2->Next) {
01248
01249 if (wheelColl1->IWheel != wheelColl2->IWheel) continue;
01250
01251
01252
01253 if (VecDotVec(PlaneNormal(&wheelColl1->Plane), PlaneNormal(&wheelColl2->Plane)) > CLOSE_WHEEL_COLL_ANGLE) {
01254
01255 if (wheelColl1->Depth > wheelColl2->Depth) {
01256 RemoveWheelColl(car, wheelColl1);
01257 keepGoing = FALSE;
01258 } else {
01259 RemoveWheelColl(car, wheelColl2);
01260 }
01261
01262
01263 }
01264
01265 }
01266 }
01267 }
01268
01269
01271
01272
01273
01274
01275
01276
01277
01278
01280
01281 void ProcessCarWheelColls(CAR *car)
01282 {
01283 COLLINFO_WHEEL *wheelColl;
01284 WHEEL *wheel;
01285 REAL shiftLen, shiftDotUp;
01286 VEC collImpulse, tmpVec, shift;
01287 VEC totImpulse = {0, 0, 0};
01288 VEC totAngImpulse = {0, 0, 0};
01289
01290 for (wheelColl = car->WheelCollHead; wheelColl != NULL; wheelColl = wheelColl->Next) {
01291
01292 wheel = &car->Wheel[wheelColl->IWheel];
01293
01294
01295 if (CAR_WheelsHaveSuspension) {
01296 if (wheelColl->Depth < ZERO) {
01297
01298 CopyVec(PlaneNormal(&wheelColl->Plane), &shift);
01299 VecMulScalar(&shift, -wheelColl->Depth);
01300 shiftDotUp = VecDotVec(&shift, &car->Body->Centre.WMatrix.mv[U]);
01301 wheel->Pos += shiftDotUp;
01302 if (wheel->Pos > wheel->MaxPos) {
01303 shiftDotUp -= wheel->Pos - wheel->MaxPos;
01304 wheel->Pos = wheel->MaxPos;
01305 } else if (wheel->Pos < -wheel->MaxPos) {
01306 shiftDotUp -= wheel->Pos + wheel->MaxPos;
01307 wheel->Pos = -wheel->MaxPos;
01308 }
01309
01310
01311 shiftDotUp = MulScalar(shiftDotUp, VecDotVec(PlaneNormal(&wheelColl->Plane), &car->Body->Centre.WMatrix.mv[U]));
01312 shiftLen = -wheelColl->Depth - shiftDotUp;
01313 if (shiftLen > ZERO) {
01314 ModifyShift(&car->Body->Centre.Shift, shiftLen, PlaneNormal(&wheelColl->Plane));
01315 }
01316
01317
01318 VecCrossVec(&car->Body->AngVel, &wheelColl->Pos, &tmpVec);
01319 VecPlusEqVec(&tmpVec, &car->Body->Centre.Vel);
01320 wheel->Vel = -MulScalar(VecDotVec(PlaneNormal(&wheelColl->Plane), &car->Body->Centre.WMatrix.mv[U]), VecDotVec(&tmpVec, PlaneNormal(&wheelColl->Plane)));
01321 wheel->Vel += MulScalar(MulScalar(wheel->Gravity, TimeStep), VecDotVec(&DownVec, &car->Body->Centre.WMatrix.mv[U]));
01322 }
01323 } else {
01324 if (wheelColl->Depth < ZERO) {
01325 ModifyShift(&car->Body->Centre.Shift, -wheelColl->Depth, PlaneNormal(&wheelColl->Plane));
01326 }
01327 }
01328
01329
01330 CarWheelImpulse2(car, wheelColl, &collImpulse);
01331
01332
01333 VecPlusEqVec(&totImpulse, &collImpulse);
01334 CalcAngImpulse(&collImpulse, &wheelColl->Pos, &tmpVec);
01335 VecPlusEqVec(&totAngImpulse, &tmpVec);
01336
01337 }
01338
01339
01340 ApplyBodyAngImpulse(car->Body, &totAngImpulse);
01341 ApplyParticleImpulse(&car->Body->Centre, &totImpulse);
01342
01343 }
01344
01345
01347
01348
01349
01350
01352 #define SKID_MAX_VELPAR 1000.0f
01353
01354
01355 void PostProcessCarWheelColls(CAR *car)
01356 {
01357 long skidColour;
01358 REAL velParLen, dRLen;
01359 REAL velDotNorm;
01360 REAL normDotNorm, dirDotDir, carDotUp;
01361 VEC velPar, dR, lookVec, vel;
01362 COLLINFO_WHEEL *wheelColl;
01363 WHEEL *wheel;
01364 SKIDMARK_START skidEnd;
01365
01366 carDotUp = VecDotVec(&car->Body->Centre.WMatrix.mv[U], &DownVec);
01367
01368 for (wheelColl = car->WheelCollHead; wheelColl != NULL; wheelColl = wheelColl->Next) {
01369
01370 wheel = &car->Wheel[wheelColl->IWheel];
01371
01372
01373 if (carDotUp > ZERO) {
01374 if ( MulScalar(carDotUp, VecDotVec(PlaneNormal(&wheelColl->Plane), &UpVec) ) > HALF) {
01375 car->NWheelFloorContacts++;
01376 }
01377 }
01378
01379
01380 if ((wheelColl->Material == NULL) || !(wheelColl->Material->Type & MATERIAL_SKID)) {
01381
01382 wheel->Skid.Started = FALSE;
01383 }
01384
01385
01386 velDotNorm = VecDotVec(&wheelColl->Vel, PlaneNormal(&wheelColl->Plane));
01387 VecPlusScalarVec(&wheelColl->Vel, -velDotNorm, PlaneNormal(&wheelColl->Plane), &velPar);
01388 velParLen = Length(&velPar);
01389 if (velParLen > SMALL_REAL) {
01390 VecDivScalar(&velPar, velParLen);
01391 } else {
01392 SetVecZero(&velPar);
01393 }
01394
01395
01396
01397 if (IsWheelSkidding(wheel) && wheel->Skid.Started) {
01398
01399 VecMinusVec(&wheelColl->WorldPos, &wheel->Skid.Pos, &dR);
01400 dRLen = Length(&dR);
01401
01402
01403 VecCrossVec(PlaneNormal(&wheelColl->Plane), &wheel->Axes.mv[R], &lookVec);
01404 CopyVec(&wheelColl->WorldPos, &skidEnd.Pos);
01405 CopyVec(&velPar, &skidEnd.Dir);
01406 CopyVec(PlaneNormal(&wheelColl->Plane), &skidEnd.Normal);
01407 skidEnd.Width = MulScalar( wheel->SkidWidth / 2, abs(VecDotVec(&lookVec, &skidEnd.Dir)) );
01408 if (skidEnd.Width < MulScalar( Real(0.2), wheel->SkidWidth) ) skidEnd.Width = MulScalar( Real(0.2), wheel->SkidWidth );
01409 skidEnd.Material = wheelColl->Material;
01410
01411 dirDotDir = VecDotVec(&skidEnd.Dir, &wheel->Skid.Dir);
01412 normDotNorm = VecDotVec(&skidEnd.Normal, &wheel->Skid.Normal);
01413
01414
01415
01416 if (wheel->Skid.CurrentSkid == NULL) {
01417
01418 if ((normDotNorm > SKID_MAX_DOT) && (skidEnd.Material == wheel->Skid.Material)) {
01419
01420 if (wheel->OilTime < OILY_WHEEL_TIME) {
01421 skidColour = 0xffffff;
01422 } else {
01423
01424
01425 skidColour = wheelColl->Material->SkidColour;
01426 }
01427 wheel->Skid.CurrentSkid = AddSkid(&wheel->Skid, &skidEnd, skidColour);
01428 } else {
01429 wheel->Skid.Started = FALSE;
01430 continue;
01431 }
01432 } else {
01433 if (dirDotDir < ZERO) {
01434 NegateVec(&skidEnd.Dir);
01435 }
01436
01437 if ((normDotNorm > SKID_MAX_DOT) && (skidEnd.Material == wheel->Skid.Material)) {
01438 MoveSkidEnd(wheel->Skid.CurrentSkid, &skidEnd);
01439 }
01440 }
01441
01442 #ifndef _PSX
01443
01444 wheel->Skid.LastSmokeTime += TimeStep;
01445 if (car->Rendered && (wheel->Skid.LastSmokeTime > SKID_SMOKE_TIME)) {
01446 VecPlusVec(&SmokeVel, &velPar, &vel)
01447 CreateSpark(SPARK_SMOKE1, &wheelColl->WorldPos, &vel, ZERO, 0);
01448 wheel->Skid.LastSmokeTime = ZERO;
01449 }
01450 #endif
01451
01452
01453 if ((dRLen > SKID_MAX_LEN) ||
01454 ((dRLen > SKID_MIN_LEN) && (dirDotDir < SKID_MAX_DOT)) ||
01455 (normDotNorm < SKID_MAX_DOT))
01456 {
01457
01458 wheel->Skid.Started = FALSE;
01459 }
01460 }
01461
01462
01463 if (!IsWheelSkidding(wheel) || !wheel->Skid.Started) {
01464
01465 VecCrossVec(PlaneNormal(&wheelColl->Plane), &wheel->Axes.mv[R], &lookVec);
01466 CopyVec(&wheelColl->WorldPos, &wheel->Skid.Pos);
01467 CopyVec(&velPar, &wheel->Skid.Dir);
01468 CopyVec(PlaneNormal(&wheelColl->Plane), &wheel->Skid.Normal);
01469 wheel->Skid.Width = MulScalar( wheel->SkidWidth / 2, abs(VecDotVec(&lookVec, &wheel->Skid.Dir)) );
01470 if (wheel->Skid.Width < MulScalar( Real(0.2), wheel->SkidWidth) ) wheel->Skid.Width = MulScalar( Real(0.2), wheel->SkidWidth );
01471 wheel->Skid.Material = wheelColl->Material;
01472 wheel->Skid.LastSmokeTime = ZERO;
01473
01474
01475 wheel->Skid.Started = TRUE;
01476 wheel->Skid.CurrentSkid = NULL;
01477 }
01478 }
01479 }
01480
01481
01483
01484
01485
01486
01488
01489 void SetAllCarCoMs()
01490 {
01491 int iCar;
01492
01493 for (iCar = 0; iCar < NCarTypes; iCar++) {
01494
01495 MoveCarCoM(&CarInfo[iCar], &CarInfo[iCar].CoMOffset);
01496
01497 }
01498 }
01499
01500
01502
01503
01504
01505
01507
01508 void MoveCarCoM(CAR_INFO *carInfo, VEC *dR)
01509 {
01510 int iWheel;
01511
01512
01513 VecPlusEqVec(&carInfo->Body.Offset, dR);
01514
01515
01516 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
01517 VecPlusEqVec(&carInfo->Wheel[iWheel].Offset1, dR);
01518 VecPlusEqVec(&carInfo->Spring[iWheel].Offset, dR);
01519 VecPlusEqVec(&carInfo->Pin[iWheel].Offset, dR);
01520 VecPlusEqVec(&carInfo->Axle[iWheel].Offset, dR);
01521 }
01522
01523
01524 VecPlusEqVec(&carInfo->Aerial.Offset, dR);
01525
01526
01527 VecPlusEqVec(&carInfo->Spinner.Offset, dR);
01528 }
01529
01530 #ifndef _PSX
01531 void CarWheelImpulse2(CAR *car, COLLINFO_WHEEL *collInfo, VEC *impulse)
01532 {
01533 REAL hardness;
01534 REAL dVelNorm, impUp, scale, impDotNorm, knock;
01535 REAL velTanLen, impTanLen, angVel;
01536 REAL lookLen, velDotNorm, impDotLook, torque;
01537 REAL fricMod, maxTorque, tReal;
01538 VEC dVel, tmpVec;
01539 VEC velTan, lookVec;
01540 VEC sparkVel;
01541
01542
01543 bool doSpark = FALSE;
01544 VEC impNorm = {ZERO, ZERO, ZERO};
01545 VEC impTan = {ZERO, ZERO, ZERO};
01546 WHEEL *wheel = &car->Wheel[collInfo->IWheel];
01547 NEWBODY *body = car->Body;
01548
01549
01550 VecCrossVec(PlaneNormal(&collInfo->Plane), &wheel->Axes.mv[R], &lookVec);
01551 lookLen = VecLen(&lookVec);
01552
01553
01554 if (lookLen > Real(0.7)) {
01555 hardness = collInfo->Restitution;
01556 VecDivScalar(&lookVec, lookLen);
01557 fricMod = ONE;
01558 } else {
01559 hardness = Real(0.1);
01560 doSpark = TRUE;
01561 if (abs(collInfo->Plane.v[B]) > HALF) {
01562 fricMod = ONE;
01563 } else {
01564 fricMod = Real(0.1) + lookLen / 4;
01565 }
01566 }
01567
01568
01569 VecEqScalarVec(&dVel, -(ONE + hardness), &collInfo->Vel);
01570 dVelNorm = VecDotVec(&dVel, PlaneNormal(&collInfo->Plane));
01571
01572
01573
01574 TwoBodyZeroFrictionImpulse(body, collInfo->Body2, &collInfo->Pos, &collInfo->Pos2, PlaneNormal(&collInfo->Plane), dVelNorm, &impNorm);
01575
01576
01577 if (CAR_WheelsHaveSuspension) {
01578
01579
01580
01581
01582 impUp = VecDotVec(&impNorm, &body->Centre.WMatrix.mv[U]);
01583 impUp = MulScalar(impUp, VecDotVec(&body->Centre.WMatrix.mv[U], PlaneNormal(&collInfo->Plane)));
01584 scale = MulScalar((car->Spring[collInfo->IWheel].Restitution), impUp);
01585 VecPlusEqScalarVec(&impNorm, scale, PlaneNormal(&collInfo->Plane));
01586
01587
01588 VecMinusVec(&wheel->CentrePos, &car->Body->Centre.Pos, &tmpVec);
01589 VecMinusEqVec(&tmpVec, &collInfo->Pos);
01590 if (Sign(wheel->Pos) == Sign(VecDotVec(&tmpVec, &body->Centre.WMatrix.mv[U]))) {
01591 scale = MulScalar(TimeStep, SpringDampedForce(&car->Spring[collInfo->IWheel], wheel->Pos, wheel->Vel));
01592 scale = MulScalar(scale, VecDotVec(&body->Centre.WMatrix.mv[U], PlaneNormal(&collInfo->Plane)));
01593 VecPlusEqScalarVec(&impNorm, -scale, PlaneNormal(&collInfo->Plane));
01594 }
01595
01596 impDotNorm = VecDotVec(&impNorm, PlaneNormal(&collInfo->Plane));
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 }
01625
01626
01627 knock = MulScalar(abs(impDotNorm), car->Body->Centre.InvMass);
01628 if (knock > car->Body->BangMag) {
01629 car->Body->BangMag = knock;
01630 CopyPlane(&collInfo->Plane, &car->Body->BangPlane);
01631 }
01632
01633
01634 velDotNorm = VecDotVec(&collInfo->Vel, PlaneNormal(&collInfo->Plane));
01635 VecPlusScalarVec(&collInfo->Vel, -velDotNorm, PlaneNormal(&collInfo->Plane), &velTan);
01636 velTanLen = Length(&velTan);
01637
01638
01639 impTanLen = -MulScalar(collInfo->Grip, impDotNorm);
01640 VecEqScalarVec(&impTan, impTanLen, &velTan);
01641 impTanLen = MulScalar(impTanLen, velTanLen);
01642
01643
01644 if (!IsWheelLocked(wheel)) {
01645 impDotLook = VecDotVec(&lookVec, &impTan);
01646 VecPlusEqScalarVec(&impTan, -impDotLook, &lookVec);
01647 }
01648
01649 if (!IsWheelLocked(wheel)) {
01650
01651 if (IsWheelPowered(wheel)) {
01652 torque = MulScalar(TimeStep, MulScalar(car->EngineVolt, wheel->EngineRatio));
01653 tReal = Sign(torque) * MulScalar(torque, DivScalar(MulScalar(wheel->AngVel, wheel->Radius), car->TopSpeed));
01654 if (abs(tReal) > abs(torque)) {
01655 torque = MulScalar(0.01f, torque);
01656 } else {
01657 torque -= tReal;
01658 }
01659 } else {
01660 torque = ZERO;
01661 }
01662
01663
01664 if ((GameSettings.AutoBrake && abs(car->EngineVolt) < Real(0.01)) || (Sign(car->EngineVolt) == -Sign(wheel->AngVel))) {
01665 tReal = MulScalar(wheel->AxleFriction, MulScalar(wheel->AngVel, wheel->Radius));
01666 tReal = MulScalar(tReal, MulScalar(FRICTION_TIME_SCALE, TimeStep));
01667 torque -= tReal;
01668 }
01669
01670
01671 maxTorque = MulScalar(MulScalar(wheel->Radius, fricMod), MulScalar(collInfo->StaticFriction, impDotNorm));
01672 if (abs(torque) > abs(maxTorque)) {
01673 SetWheelSpinning(wheel);
01674 }
01675
01676 VecPlusEqScalarVec(&impTan, DivScalar(torque, wheel->Radius), &lookVec);
01677 }
01678
01679
01680 impTanLen = VecLen(&impTan);
01681 maxTorque = 2 * MulScalar(MulScalar(TimeStep, car->Body->Centre.Mass), car->Body->Centre.Gravity);
01682 if (impTanLen > maxTorque) {
01683 VecMulScalar(&impTan, DivScalar(maxTorque, impTanLen));
01684 impTanLen = maxTorque;
01685 SetWheelSliding(wheel);
01686 }
01687 maxTorque = MulScalar(MulScalar(collInfo->StaticFriction, fricMod), impDotNorm);
01688 if (impTanLen > maxTorque) {
01689 maxTorque = MulScalar(MulScalar(collInfo->KineticFriction, fricMod), impDotNorm);
01690 VecMulScalar(&impTan, DivScalar(maxTorque, impTanLen));
01691 impTanLen = maxTorque;
01692 SetWheelSliding(wheel);
01693 }
01694
01695
01696 if (IsWheelLocked(wheel)) {
01697 wheel->AngVel = ZERO;
01698 } else {
01699 #ifndef _PSX
01700 if (IsWheelSpinning(wheel)) {
01701
01702
01703 } else {
01704 angVel = DivScalar(VecDotVec(&collInfo->Vel, &lookVec), wheel->Radius);
01705 wheel->AngVel += MulScalar((angVel - wheel->AngVel), DivScalar(MulScalar(FRICTION_TIME_SCALE, TimeStep), 4));
01706 }
01707 #else
01708 angVel = DivScalar(VecDotVec(&collInfo->Vel, &lookVec), wheel->Radius);
01709 wheel->AngVel = angVel;
01710 #endif
01711 }
01712
01713 #ifndef _PSX
01714
01715 if (car->Rendered && doSpark && (collInfo->Material != NULL) && (velTanLen > MIN_SPARK_VEL))
01716 {
01717 body->ScrapeMaterial = collInfo->Material - COL_MaterialInfo;
01718 body->LastScrapeTime = ZERO;
01719 if ((frand(2.0f) < SparkProbability(velTanLen)) && MaterialAllowsSparks(collInfo->Material))
01720 {
01721 VecEqScalarVec(&sparkVel, HALF, &velTan);
01722 CreateSpark(SPARK_SPARK, &collInfo->WorldPos, &sparkVel, velTanLen / 3, 0);
01723 }
01724 }
01725
01726
01727 if (car->Rendered && collInfo->Material != NULL && MaterialDusty(collInfo->Material) && impTanLen > 5 * body->Centre.InvMass * MIN_DUST_IMPULSE &&(frand(1.0f) < COL_DustInfo[collInfo->Material->DustType].SparkProbability, 0))
01728 {
01729 enum SparkTypeEnum sparkType;
01730 sparkType = (enum SparkTypeEnum)COL_DustInfo[collInfo->Material->DustType].SparkType;
01731 scale = body->Centre.InvMass * DUST_SCALE;
01732 VecEqScalarVec(&sparkVel, -scale, &impTan);
01733 VecPlusEqScalarVec(&sparkVel, HALF * scale * impTanLen, &UpVec);
01734 VecPlusEqScalarVec(&sparkVel, HALF * body->Centre.InvMass * torque, &lookVec);
01735 CreateSpark(sparkType, &collInfo->WorldPos, &sparkVel, COL_DustInfo[collInfo->Material->DustType].SparkVar * scale * impTanLen, 0);
01736 }
01737 #endif
01738
01739
01740 VecPlusVec(&impNorm, &impTan, impulse);
01741
01742
01743 if (abs(impulse->v[X]) < SMALL_IMPULSE_COMPONENT) impulse->v[X] = ZERO;
01744 if (abs(impulse->v[Y]) < SMALL_IMPULSE_COMPONENT) impulse->v[Y] = ZERO;
01745 if (abs(impulse->v[Z]) < SMALL_IMPULSE_COMPONENT) impulse->v[Z] = ZERO;
01746
01747
01748 }
01749
01750 #else // PSX
01751 #if FALSE
01752 void CarWheelImpulse2(CAR *car, COLLINFO_WHEEL *collInfo, VEC *impulse)
01753 {
01754
01755 REAL dVelNorm, impUp, scale, impDotNorm;
01756 REAL velTanLen, impTanLen, angVel;
01757 REAL lookLen, velDotNorm, velDotLook, impDotLook, torque;
01758 REAL fricMod, maxTorque, tReal;
01759 VEC dVel, tmpVec;
01760 VEC velTan, lookVec;
01761 VEC sparkVel;
01762 COLLINFO_BODY *bodyColl;
01763
01764 bool doSpark = FALSE;
01765 VEC impNorm = {ZERO, ZERO, ZERO};
01766 VEC impTan = {ZERO, ZERO, ZERO};
01767 WHEEL *wheel = &car->Wheel[collInfo->IWheel];
01768 NEWBODY *body = car->Body;
01769
01770
01771 VecCrossVecUnit(PlaneNormal(&collInfo->Plane), &wheel->Axes.mv[R], &lookVec);
01772 lookLen = VecLenUnit(&lookVec);
01773
01774
01775 if (lookLen > Real(0.7)) {
01776 VecDivScalar(&lookVec, lookLen);
01777 fricMod = ONE;
01778 } else {
01779 doSpark = TRUE;
01780 if (abs(collInfo->Plane.v[B]) > HALF) {
01781 fricMod = ONE;
01782 } else {
01783 fricMod = Real(0.1) + lookLen / 4;
01784 }
01785 }
01786
01787
01788 VecEqScalarVec(&dVel, -(ONE + collInfo->Restitution), &collInfo->Vel);
01789 dVelNorm = VecDotVec(&dVel, PlaneNormal(&collInfo->Plane));
01790
01791
01792 TwoBodyZeroFrictionImpulse(body, collInfo->Body2, &collInfo->Pos, &collInfo->Pos2, PlaneNormal(&collInfo->Plane), dVelNorm, &impNorm);
01793
01794
01795 if (CAR_WheelsHaveSuspension) {
01796
01797 impUp = VecDotVec(&impNorm, &body->Centre.WMatrix.mv[U]);
01798 impUp = MulScalar(impUp, VecDotVec(&body->Centre.WMatrix.mv[U], PlaneNormal(&collInfo->Plane)));
01799 scale = MulScalar((car->Spring[collInfo->IWheel].Restitution), impUp);
01800 VecPlusEqScalarVec(&impNorm, scale, PlaneNormal(&collInfo->Plane));
01801
01802
01803 VecMinusVec(&wheel->CentrePos, &car->Body->Centre.Pos, &tmpVec);
01804 VecMinusEqVec(&tmpVec, &collInfo->Pos);
01805 if (Sign(wheel->Pos) == Sign(VecDotVec(&tmpVec, &body->Centre.WMatrix.mv[U]))) {
01806 scale = MulScalar(TimeStep, SpringDampedForce(&car->Spring[collInfo->IWheel], wheel->Pos, wheel->Vel));
01807 scale = MulScalar(scale, VecDotVec(&body->Centre.WMatrix.mv[U], PlaneNormal(&collInfo->Plane)));
01808 VecPlusEqScalarVec(&impNorm, -scale, PlaneNormal(&collInfo->Plane));
01809 }
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828 }
01829
01830
01831 impDotNorm = VecDotVec(&impNorm, PlaneNormal(&collInfo->Plane));
01832 velDotNorm = VecDotVec(&collInfo->Vel, PlaneNormal(&collInfo->Plane));
01833 VecPlusScalarVec(&collInfo->Vel, -velDotNorm, PlaneNormal(&collInfo->Plane), &velTan);
01834 velTanLen = VecLen(&velTan);
01835 velDotLook = VecDotVec(&collInfo->Vel, &lookVec);
01836
01837
01838 impTanLen = -MulScalar(collInfo->Grip, impDotNorm);
01839 tReal = MulScalar(impTanLen, velTanLen);
01840 if (abs(tReal) < 15000) {
01841 VecEqScalarVec(&impTan, impTanLen, &velTan);
01842 impTanLen = tReal;
01843 } else {
01844 VecEqScalarVec(&impTan, -DivScalar(15000, velTanLen), &velTan);
01845 impTanLen = 15000;
01846 }
01847 printf("before: %8d (%8d) ", VecDotVec(&impTan, &lookVec), VecLen(&impTan));
01848
01849
01850 if (!IsWheelLocked(wheel)) {
01851 RemoveComponent(&impTan, &lookVec);
01852 }
01853 printf("after: %8d (%8d)\n", VecDotVec(&impTan, &lookVec), VecLen(&impTan));
01854
01855 if (!IsWheelLocked(wheel)) {
01856 if (IsWheelPowered(wheel)) {
01857
01858 torque = MulScalar(TimeStep, MulScalar(car->EngineVolt, wheel->EngineRatio));
01859 scale = MulScalar(wheel->AngVel, wheel->Radius);
01860 torque -= MulScalar(torque, DivScalar(scale, car->TopSpeed));
01861 } else {
01862 torque = ZERO;
01863 }
01864
01865
01866 if ((GameSettings.AutoBrake && abs(car->EngineVolt) < Real(0.01)) || (Sign(car->EngineVolt) != Sign(wheel->AngVel))) {
01867 tReal = MulScalar(wheel->AxleFriction, wheel->AngVel);
01868 tReal = MulScalar(tReal, MulScalar(FRICTION_TIME_SCALE, TimeStep));
01869 torque -= tReal;
01870 }
01871
01872
01873 maxTorque = MulScalar(fricMod, MulScalar(collInfo->StaticFriction, impDotNorm));
01874 if (abs(torque) > abs(maxTorque)) {
01875 SetWheelSpinning(wheel);
01876 }
01877
01878 VecPlusEqScalarVec(&impTan, torque, &lookVec);
01879 }
01880
01881
01882 impTanLen = VecLen(&impTan);
01883 maxTorque = MulScalar(MulScalar(TimeStep, car->Body->Centre.Mass), car->Body->Centre.Gravity) << 1;
01884 if (impTanLen > maxTorque) {
01885 VecMulScalar(&impTan, DivScalar(maxTorque, impTanLen));
01886 impTanLen = maxTorque;
01887 SetWheelSliding(wheel);
01888 }
01889 maxTorque = MulScalar(MulScalar(collInfo->StaticFriction, fricMod), impDotNorm);
01890 if (impTanLen > maxTorque) {
01891 maxTorque = MulScalar(MulScalar(collInfo->KineticFriction, fricMod), impDotNorm);
01892 VecMulScalar(&impTan, DivScalar(maxTorque, impTanLen));
01893 impTanLen = maxTorque;
01894 SetWheelSliding(wheel);
01895 }
01896
01897
01898 if (IsWheelLocked(wheel)) {
01899 wheel->AngVel = ZERO;
01900 } else {
01901 #ifndef _PSX
01902 if (IsWheelSpinning(wheel)) {
01903 wheel->AngImpulse += torque;
01904 } else {
01905 angVel = DivScalar(VecDotVec(&collInfo->Vel, &lookVec), wheel->Radius);
01906 wheel->AngVel = angVel;
01907 }
01908 #else
01909 angVel = DivScalar(velDotLook, wheel->Radius);
01910 wheel->AngVel = angVel;
01911 #endif
01912 }
01913
01914
01915
01916
01917
01918
01919 impTan.v[X] >> SMALL_SHIFT;
01920 impTan.v[Y] >> SMALL_SHIFT;
01921 impTan.v[Z] >> SMALL_SHIFT;
01922
01923
01924 VecPlusVec(&impNorm, &impTan, impulse);
01925
01926
01927 if (abs(impulse->v[X]) < SMALL_IMPULSE_COMPONENT) impulse->v[X] = ZERO;
01928 if (abs(impulse->v[Y]) < SMALL_IMPULSE_COMPONENT) impulse->v[Y] = ZERO;
01929 if (abs(impulse->v[Z]) < SMALL_IMPULSE_COMPONENT) impulse->v[Z] = ZERO;
01930
01931 }
01932 #endif
01933 #endif
01934
01935 #if TRUE && defined(_PSX)
01936 void CarWheelImpulse2(CAR *car, COLLINFO_WHEEL *collInfo, VEC *impulse)
01937 {
01938 REAL lookLen, velDotLook, upDotNorm, velDotNorm, knock;
01939 REAL impDotNorm, impDotNormTrue, impDotLook, impSlide, scale, dVelNorm;
01940 REAL impTanLen, max, velSlideLen;
01941 VEC lookVec, relPos, velSideways;
01942
01943 VEC impTan = {0, 0, 0};
01944 WHEEL *wheel = &car->Wheel[collInfo->IWheel];
01945 NEWBODY *body = car->Body;
01946
01947
01948 VecCrossVecUnit(PlaneNormal(&collInfo->Plane), &wheel->Axes.mv[R], &lookVec);
01949 lookLen = VecLenUnit(&lookVec);
01950 if (lookLen > Real(0.7)) {
01951 VecDivScalar(&lookVec, lookLen);
01952 lookLen = ONE;
01953 }
01954
01955
01956 if (abs(collInfo->Plane.v[B]) < Real(0.5)) {
01957 lookLen /= 5;
01958 }
01959
01960
01961 velDotLook = VecDotVec(&collInfo->Vel, &lookVec);
01962 velDotNorm = VecDotVec(&collInfo->Vel, PlaneNormal(&collInfo->Plane));
01963 upDotNorm = VecDotVec(&body->Centre.WMatrix.mv[U], PlaneNormal(&collInfo->Plane));
01964
01965
01966 VecPlusScalarVec(&collInfo->Vel, -velDotNorm, PlaneNormal(&collInfo->Plane), &velSideways);
01967 VecPlusEqScalarVec(&velSideways, -velDotLook, &lookVec);
01968 RemoveComponent(&velSideways, &lookVec);
01969 velSlideLen = VecLen(&velSideways);
01970
01971
01972
01973 dVelNorm = -velDotNorm;
01974 impDotNormTrue = OneBodyZeroFrictionImpulse(body, &collInfo->Pos, PlaneNormal(&collInfo->Plane), dVelNorm);
01975 impDotNormTrue = MulScalar(impDotNormTrue, ONE + collInfo->Restitution);
01976 impDotNormTrue -= MulScalar(impDotNormTrue, abs(upDotNorm));
01977
01978
01979 VecMinusVec(&wheel->CentrePos, &car->Body->Centre.Pos, &relPos);
01980 VecMinusEqVec(&relPos, &collInfo->Pos);
01981
01982
01983 if (Sign(wheel->Pos) == Sign(VecDotVec(&relPos, &body->Centre.WMatrix.mv[U]))) {
01984 scale = MulScalar(TimeStep, SpringDampedForce(&car->Spring[collInfo->IWheel], wheel->Pos, wheel->Vel));
01985 scale = MulScalar(scale, upDotNorm);
01986 impDotNormTrue -= scale;
01987 }
01988
01989
01990 knock = MulScalar(impDotNormTrue, car->Body->Centre.InvMass);
01991 if (knock > car->Body->BangMag) {
01992 car->Body->BangMag = knock;
01993 CopyPlane(&collInfo->Plane, &car->Body->BangPlane);
01994 }
01995
01996
01997 if (impDotNormTrue > 1000) {
01998 impDotNorm = 1000;
01999 } else {
02000 impDotNorm = impDotNormTrue;
02001 }
02002
02003
02004
02005 if (IsWheelPowered(wheel)) {
02006 impDotLook = ONE - DivScalar(velDotLook, car->TopSpeed);
02007 impDotLook = MulScalar(impDotLook, MulScalar(car->EngineVolt, wheel->EngineRatio));
02008 impDotLook = MulScalar(impDotLook, TimeStep);
02009 } else {
02010 impDotLook = ZERO;
02011 }
02012
02013
02014 if ((GameSettings.AutoBrake && abs(car->EngineVolt) < Real(0.01)) || (Sign(car->EngineVolt) != Sign(velDotLook))) {
02015 scale = MulScalar(wheel->AxleFriction, velDotLook);
02016 scale = MulScalar(scale, MulScalar(FRICTION_TIME_SCALE, TimeStep));
02017 impDotLook -= scale;
02018 }
02019
02020
02021
02022 max = MulScalar(collInfo->StaticFriction, impDotNorm) << SMALL_SHIFT;
02023 if (abs(impDotLook) > max) {
02024 if (impDotLook > 0) {
02025 impDotLook = MulScalar(collInfo->KineticFriction, impDotNorm) << SMALL_SHIFT;
02026 } else {
02027 impDotLook = -MulScalar(collInfo->KineticFriction, impDotNorm) << SMALL_SHIFT;
02028 }
02029 SetWheelSpinning(wheel);
02030 }
02031
02032
02033 impSlide = MulScalar(collInfo->Grip, impDotNorm);
02034 scale = MulScalar(impSlide, velSlideLen);
02035 if (scale > max) {
02036 impSlide = MulScalar(collInfo->KineticFriction, impDotNorm) << SMALL_SHIFT;
02037 impSlide = MulScalar(lookLen, DivScalar(impSlide, velSlideLen));
02038 SetWheelSliding(wheel);
02039 }
02040
02041
02042
02043 ScalarVecPlusScalarVec(impDotLook, &lookVec, -impSlide, &velSideways, &impTan);
02044
02045 impTan.v[X] >>= SMALL_SHIFT;
02046 impTan.v[Y] >>= SMALL_SHIFT;
02047 impTan.v[Z] >>= SMALL_SHIFT;
02048
02049
02050 VecPlusScalarVec(&impTan, impDotNormTrue, PlaneNormal(&collInfo->Plane), impulse);
02051
02052
02053 wheel->AngVel = DivScalar(&velDotLook, wheel->Radius);
02054
02055
02056 if (abs(impulse->v[X]) < SMALL_IMPULSE_COMPONENT) impulse->v[X] = ZERO;
02057 if (abs(impulse->v[Y]) < SMALL_IMPULSE_COMPONENT) impulse->v[Y] = ZERO;
02058 if (abs(impulse->v[Z]) < SMALL_IMPULSE_COMPONENT) impulse->v[Z] = ZERO;
02059
02060 }
02061
02062 #endif // PSX
02063
02064
02065
02067
02068
02069
02071
02072 void SetCarAngResistance(CAR *car)
02073 {
02074 int iWhl;
02075
02076 int nCont = 0;
02077
02078
02079 for (iWhl = 0; iWhl < CAR_NWHEELS; iWhl++) {
02080 if (IsWheelInContact(&car->Wheel[iWhl])) {
02081 nCont++;
02082 }
02083 }
02084
02085
02086 if (nCont == 0) {
02087 car->Body->AngResistance = MulScalar(car->Body->AngResMod, car->Body->DefaultAngRes);
02088 } else {
02089 car->Body->AngResistance = car->Body->DefaultAngRes;
02090 }
02091
02092 }
02093
02094
02096
02097
02098
02099
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138
02139
02141
02142
02143
02144
02146
02147 void DetectCarWorldColls(CAR *car)
02148 {
02149 long iPoly, iWheel;
02150 long nCollPolys;
02151 COLLGRID *collGrid;
02152
02153 #ifndef _PSX
02154 NEWCOLLPOLY **collPolyPtr;
02155 #endif
02156 NEWCOLLPOLY *collPoly;
02157
02158
02159 collGrid = PosToCollGrid(&car->Body->Centre.Pos);
02160 if (collGrid == NULL) return;
02161
02162 #ifndef _PSX
02163 collPolyPtr = collGrid->CollPolyPtr;
02164 #endif
02165 nCollPolys = collGrid->NCollPolys;
02166
02167
02168 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
02169
02170 if (!IsWheelInContact(&car->Wheel[iWheel])) {
02171 car->Wheel[iWheel].Skid.Started = FALSE;
02172 }
02173
02174
02175 SetWheelNotInContact(&car->Wheel[iWheel]);
02176 SetWheelNotSliding(&car->Wheel[iWheel]);
02177 if (IsWheelinOil(&car->Wheel[iWheel])) {
02178 SetWheelNotInOil(&car->Wheel[iWheel]);
02179 car->Wheel[iWheel].OilTime = ZERO;
02180 } else {
02181 car->Wheel[iWheel].OilTime += TimeStep;
02182 }
02183 }
02184
02185
02186 for (iPoly = 0; iPoly < nCollPolys; iPoly++) {
02187
02188 #ifndef _PSX
02189 collPoly = collPolyPtr[iPoly];
02190 #else
02191 collPoly = &COL_WorldCollPoly[collGrid->CollPolyIndices[iPoly]];
02192 #endif
02193
02194 if (PolyCameraOnly(collPoly)) continue;
02195
02196
02197 if (!BBTestYXZ(&collPoly->BBox, &car->BBox)) continue;
02198
02199 COL_NCollsTested++;
02200
02201
02202 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
02203 if (IsWheelPresent(&car->Wheel[iWheel])) {
02204
02205 DetectCarWheelColls2(car, iWheel, collPoly);
02206 }
02207 }
02208
02209
02210 DetectBodyPolyColls(car->Body, collPoly);
02211
02212 }
02213
02214 #if USE_DEBUG_ROUTINES
02215 DEBUG_CollGrid = collGrid - COL_CollGrid;
02216 #endif
02217 }
02218
02219
02221
02222
02223
02225
02226 int DetectWheelBodyColls(CAR *car, NEWBODY *body)
02227 {
02228 int iWheel;
02229 WHEEL *wheel;
02230 int nColls = 0;
02231
02232
02233 for (iWheel = 0; iWheel < CAR_NWHEELS; iWheel++) {
02234 wheel = &car->Wheel[iWheel];
02235 if (!IsWheelPresent(wheel)) continue;
02236
02237 if (IsBodyConvex(body)) {
02238 nColls += DetectWheelConvexColls(car, iWheel, body);
02239 }
02240 else if (IsBodySphere(body)) {
02241 nColls += DetectWheelSphereColls(car, iWheel, body);
02242 }
02243 else if (IsBodyPoly(body)) {
02244 nColls += DetectWheelPolyColls(car, iWheel, body);
02245 }
02246 }
02247
02248 return nColls;
02249 }
02250
02251 int DetectWheelPolyColls(CAR *car, int iWheel, NEWBODY *body)
02252 {
02253 int iPoly;
02254 VEC tmpVec;
02255 REAL time;
02256 NEWCOLLPOLY *collPoly;
02257 int nColls = 0;
02258 WHEEL *wheel = &car->Wheel[iWheel];
02259 COLLINFO_WHEEL *wheelColl;
02260
02261 Assert(IsBodyPoly(body));
02262
02263
02264 if (!BBTestYXZ(&wheel->BBox, &body->CollSkin.BBox)) return 0;
02265
02266 for (iPoly = 0; iPoly < body->CollSkin.NCollPolys; iPoly++) {
02267 collPoly = &body->CollSkin.CollPoly[iPoly];
02268
02269 if ((wheelColl = NextWheelCollInfo()) == NULL) return nColls;
02270
02271
02272 if (!BBTestYXZ(&wheel->BBox, &collPoly->BBox)) continue;
02273
02274
02275 if (SphereCollPoly(&wheel->OldCentrePos, &wheel->CentrePos,
02276 wheel->Radius,
02277 collPoly,
02278 &wheelColl->Plane,
02279 &wheelColl->Pos,
02280 &wheelColl->WorldPos,
02281 &wheelColl->Depth,
02282 &time))
02283 {
02284
02285
02286 VecPlusEqScalarVec(&wheelColl->WorldPos, SKID_RAISE, PlaneNormal(&wheelColl->Plane));
02287
02288
02289 VecPlusEqVec(&wheelColl->Pos, &wheel->CentrePos);
02290 VecMinusEqVec(&wheelColl->Pos, &car->Body->Centre.Pos);
02291
02292
02293 VecCrossVec(&car->Body->AngVel, &wheelColl->Pos, &wheelColl->Vel);
02294 VecPlusEqVec(&wheelColl->Vel, &car->Body->Centre.Vel);
02295 VecMinusEqVec(&wheelColl->Vel, &body->Centre.Vel);
02296
02297
02298 VecPlusScalarVec(&wheelColl->Vel, wheel->Vel, &car->Body->Centre.WMatrix.mv[U], &tmpVec);
02299 if (VecDotVec(&tmpVec, PlaneNormal(&wheelColl->Plane)) > ZERO) continue;
02300
02301
02302 wheelColl->Material = &COL_MaterialInfo[collPoly->Material];
02303
02304
02305
02306 wheelColl->Car = car;
02307 wheelColl->IWheel = iWheel;
02308 wheelColl->Grip = MulScalar(wheel->Grip, wheelColl->Material->Gripiness);
02309 wheelColl->StaticFriction = MulScalar(wheel->StaticFriction, wheelColl->Material->Roughness);
02310 wheelColl->KineticFriction = MulScalar(wheel->KineticFriction, wheelColl->Material->Roughness);
02311 wheelColl->Restitution = ZERO;
02312 wheelColl->Body2 = &BDY_MassiveBody;
02313 SetVecZero(&wheelColl->Pos2);
02314
02315
02316
02317 SetWheelInContact(wheel);
02318 SetWheelNotSpinning(wheel);
02319
02320 AddWheelColl(car, wheelColl);
02321 nColls++;
02322
02323 }
02324 }
02325 return nColls;
02326 }
02327
02328
02329 int DetectWheelSphereColls(CAR *car, int iWheel, NEWBODY *body)
02330 {
02331 VEC dR;
02332 REAL dRLen;
02333 COLLINFO_WHEEL *wheelColl;
02334 COLLINFO_BODY *bodyColl;
02335 WHEEL *wheel = &car->Wheel[iWheel];
02336 SPHERE *sphere = &body->CollSkin.WorldSphere[0];
02337
02338
02339 if (!BBTestYXZ(&wheel->BBox, &body->CollSkin.BBox)) return 0;
02340
02341
02342 if ((wheelColl = NextWheelCollInfo()) == NULL) return 0;
02343 if ((bodyColl = NextBodyCollInfo()) == NULL) return 0;
02344
02345
02346 VecMinusVec(&wheel->CentrePos, &sphere->Pos, &dR);
02347 dRLen = VecLen(&dR);
02348
02349
02350 if (dRLen > wheel->Radius + sphere->Radius) return 0;
02351
02352
02353
02354 bodyColl->Body1 = body;
02355 bodyColl->Body2 = car->Body;
02356 wheelColl->Car = car;
02357 wheelColl->IWheel = iWheel;
02358 wheelColl->Body2 = body;
02359 SetVecZero(&wheelColl->WorldPos);
02360 SetVecZero(&bodyColl->WorldPos);
02361
02362 bodyColl->Depth = HALF * (dRLen - wheel->Radius - sphere->Radius);
02363 wheelColl->Depth = bodyColl->Depth;
02364
02365
02366 if (dRLen > SMALL_REAL) {
02367 CopyVec(&dR, PlaneNormal(&wheelColl->Plane));
02368 VecDivScalar(PlaneNormal(&wheelColl->Plane), dRLen);
02369 wheelColl->Time = ONE - (wheelColl->Depth / dRLen);
02370 } else {
02371 SetVec(PlaneNormal(&wheelColl->Plane), ONE, ZERO, ZERO);
02372 wheelColl->Time = ONE;
02373 }
02374 FlipPlane(&wheelColl->Plane, &bodyColl->Plane);
02375 bodyColl->Time = wheelColl->Time;
02376
02377
02378 VecEqScalarVec(&wheelColl->Pos, wheel->Radius, PlaneNormal(&wheelColl->Plane));
02379 VecPlusEqVec(&wheelColl->Pos, &wheel->CentrePos);
02380 VecMinusEqVec(&wheelColl->Pos, &car->Body->Centre.Pos);
02381
02382 VecPlusScalarVec(&wheel->CentrePos, HALF, &dR, &wheelColl->WorldPos);
02383 CopyVec(&wheelColl->Pos, &bodyColl->Pos2);
02384 CopyVec(&wheelColl->WorldPos, &bodyColl->WorldPos);
02385 VecPlusScalarVec(&sphere->Pos, -sphere->Radius, PlaneNormal(&wheelColl->Plane), &bodyColl->Pos1);
02386 VecMinusEqVec(&bodyColl->Pos1, &body->Centre.Pos);
02387 VecMinusVec(&bodyColl->WorldPos, &body->Centre.Pos, &bodyColl->Pos1);
02388 CopyVec(&bodyColl->Pos1, &wheelColl->Pos2);
02389
02390
02391 VecCrossVec(&car->Body->AngVel, &wheelColl->Pos, &wheelColl->Vel);
02392 VecPlusEqVec(&wheelColl->Vel, &car->Body->Centre.Vel);
02393 VecCrossVec(&body->AngVel, &bodyColl->Pos1, &bodyColl->Vel);
02394 VecPlusEqVec(&bodyColl->Vel, &body->Centre.Vel);
02395 VecMinusEqVec(&bodyColl->Vel, &wheelColl->Vel);
02396 CopyVec(&bodyColl->Vel, &wheelColl->Vel);
02397 NegateVec(&wheelColl->Vel);
02398
02399 wheelColl->Grip = wheel->Grip * body->Centre.Grip;
02400 wheelColl->StaticFriction = wheel->StaticFriction * body->Centre.StaticFriction;
02401 wheelColl->KineticFriction = wheel->KineticFriction * body->Centre.KineticFriction;
02402 wheelColl->Restitution = car->Spring[iWheel].Restitution;
02403 wheelColl->Material = NULL;
02404 bodyColl->Grip = wheelColl->Grip;
02405 bodyColl->StaticFriction = wheelColl->StaticFriction;
02406 bodyColl->KineticFriction = wheelColl->KineticFriction;
02407 bodyColl->Restitution = wheelColl->Restitution;
02408 bodyColl->Material = NULL;
02409
02410 AddWheelColl(car, wheelColl);
02411 AddBodyColl(body, bodyColl);
02412
02413 return 1;
02414 }
02415
02416 int DetectWheelConvexColls(CAR *car, int iWheel, NEWBODY *body)
02417 {
02418 int iSkin;
02419 COLLINFO_WHEEL *wheelColl;
02420 COLLINFO_BODY *bodyColl;
02421 WHEEL *wheel = &car->Wheel[iWheel];
02422 int nColls = 0;
02423
02424 Assert(body != NULL);
02425 Assert(car != NULL);
02426 Assert((iWheel >= 0) && (iWheel < CAR_NWHEELS));
02427
02428
02429 if (!BBTestYXZ(&wheel->BBox, &body->CollSkin.BBox)) return 0;
02430
02431
02432 for (iSkin = 0; iSkin < body->CollSkin.NConvex; iSkin++) {
02433
02434
02435 if (!BBTestYXZ(&wheel->BBox, &body->CollSkin.WorldConvex[iSkin].BBox)) continue;
02436
02437
02438 if ((wheelColl = NextWheelCollInfo()) == NULL) return nColls;
02439 if ((bodyColl = NextBodyCollInfo()) == NULL) return nColls;
02440
02441
02442 if (!SphereConvex(&wheel->CentrePos, wheel->Radius, &body->CollSkin.WorldConvex[iSkin], &wheelColl->Pos, &wheelColl->Plane, &wheelColl->Depth)) {
02443 continue;
02444 }
02445
02446
02447
02448 bodyColl->Body1 = body;
02449 bodyColl->Body2 = car->Body;
02450 wheelColl->Car = car;
02451 wheelColl->IWheel = iWheel;
02452 wheelColl->Body2 = body;
02453 SetVecZero(&wheelColl->WorldPos);
02454 SetVecZero(&bodyColl->WorldPos);
02455
02456
02457
02458 VecMinusVec(&wheelColl->Pos, &body->Centre.Pos, &bodyColl->Pos1);
02459 VecMinusEqVec(&wheelColl->Pos, &car->Body->Centre.Pos);
02460 CopyVec(&wheelColl->Pos, &bodyColl->Pos2);
02461 CopyVec(&bodyColl->Pos1, &wheelColl->Pos2);
02462
02463
02464 VecCrossVec(&car->Body->AngVel, &wheelColl->Pos, &wheelColl->Vel);
02465 VecPlusEqVec(&wheelColl->Vel, &car->Body->Centre.Vel);
02466 VecCrossVec(&body->AngVel, &bodyColl->Pos1, &bodyColl->Vel);
02467 VecPlusEqVec(&bodyColl->Vel, &body->Centre.Vel);
02468 VecMinusEqVec(&bodyColl->Vel, &wheelColl->Vel);
02469 CopyVec(&bodyColl->Vel, &wheelColl->Vel);
02470 NegateVec(&wheelColl->Vel);
02471
02472 FlipPlane(&wheelColl->Plane, &bodyColl->Plane);
02473 bodyColl->Depth = wheelColl->Depth;
02474 bodyColl->Time = ZERO;
02475
02476
02477
02478
02479
02480 wheelColl->Grip = wheel->Grip * body->Centre.Grip;
02481 wheelColl->StaticFriction = wheel->StaticFriction * body->Centre.StaticFriction;
02482 wheelColl->KineticFriction = wheel->KineticFriction * body->Centre.KineticFriction;
02483 wheelColl->Restitution = car->Spring[iWheel].Restitution;
02484 wheelColl->Material = NULL;
02485 bodyColl->Grip = wheelColl->Grip;
02486 bodyColl->StaticFriction = wheelColl->StaticFriction;
02487 bodyColl->KineticFriction = wheelColl->KineticFriction;
02488 bodyColl->Restitution = wheelColl->Restitution;
02489 bodyColl->Material = NULL;
02490
02491 AddBodyColl(body, bodyColl);
02492 AddWheelColl(car, wheelColl);
02493 nColls++;
02494
02495 }
02496
02497 return nColls;
02498 }
02499
02500
02501 int DetectWheelWheelColls(CAR *car1, CAR *car2)
02502 {
02503 int iWheel1, iWheel2;
02504 VEC dR;
02505 REAL dRLen;
02506 COLLINFO_WHEEL *wheelColl;
02507 COLLINFO_WHEEL *wheelColl2;
02508 WHEEL *wheel1;
02509 WHEEL *wheel2;
02510 int nColls = 0;
02511
02512
02513 for (iWheel1 = 0; iWheel1 < CAR_NWHEELS; iWheel1++) {
02514 wheel1 = &car1->Wheel[iWheel1];
02515 if (!IsWheelPresent(wheel1)) continue;
02516
02517 for (iWheel2 = 0; iWheel2 < CAR_NWHEELS; iWheel2++) {
02518 wheel2 = &car2->Wheel[iWheel2];
02519 if (!IsWheelPresent(wheel2)) continue;
02520
02521
02522 if (!BBTestYXZ(&wheel1->BBox, &wheel2->BBox)) continue;
02523
02524
02525 VecMinusVec(&wheel1->CentrePos, &wheel2->CentrePos, &dR);
02526 dRLen = VecLen(&dR);
02527
02528
02529 if (dRLen > wheel1->Radius + wheel2->Radius) continue;
02530
02531
02532 if ((wheelColl = NextWheelCollInfo()) == NULL) return nColls;
02533 AddWheelColl(car1, wheelColl);
02534 if ((wheelColl2 = NextWheelCollInfo()) == NULL) {
02535 RemoveWheelColl(car1, wheelColl);
02536 return nColls;
02537 }
02538 AddWheelColl(car2, wheelColl2);
02539
02540
02541
02542 wheelColl2->Car = car2;
02543 wheelColl2->IWheel = iWheel2;
02544 wheelColl2->Body2 = car2->Body;
02545 wheelColl->Car = car1;
02546 wheelColl->IWheel = iWheel1;
02547 wheelColl->Body2 = car1->Body;
02548 SetVecZero(&wheelColl->WorldPos);
02549 SetVecZero(&wheelColl2->WorldPos);
02550
02551 wheelColl2->Depth = dRLen - wheel1->Radius - wheel2->Radius;
02552 wheelColl->Depth = wheelColl2->Depth;
02553
02554
02555 if (dRLen > SMALL_REAL) {
02556 CopyVec(&dR, PlaneNormal(&wheelColl->Plane));
02557 VecDivScalar(PlaneNormal(&wheelColl->Plane), dRLen);
02558 wheelColl->Time = ONE - (wheelColl->Depth / dRLen);
02559 } else {
02560 SetVec(PlaneNormal(&wheelColl->Plane), ONE, ZERO, ZERO);
02561 wheelColl->Time = ONE;
02562 }
02563 FlipPlane(&wheelColl->Plane, &wheelColl2->Plane);
02564 wheelColl2->Time = wheelColl->Time;
02565
02566
02567 VecEqScalarVec(&wheelColl->Pos, wheel1->Radius, PlaneNormal(&wheelColl->Plane));
02568 VecPlusEqVec(&wheelColl->Pos, &wheel1->CentrePos);
02569 VecMinusEqVec(&wheelColl->Pos, &car1->Body->Centre.Pos);
02570
02571 VecEqScalarVec(&wheelColl2->Pos, wheel2->Radius, PlaneNormal(&wheelColl2->Plane));
02572 VecPlusEqVec(&wheelColl2->Pos, &wheel2->CentrePos);
02573 VecMinusEqVec(&wheelColl2->Pos, &car2->Body->Centre.Pos);
02574
02575 VecPlusScalarVec(&wheel1->CentrePos, HALF, &dR, &wheelColl->WorldPos);
02576 CopyVec(&wheelColl->WorldPos, &wheelColl2->WorldPos);
02577
02578
02579 VecCrossVec(&car1->Body->AngVel, &wheelColl->Pos, &wheelColl->Vel);
02580 VecPlusEqVec(&wheelColl->Vel, &car1->Body->Centre.Vel);
02581
02582 VecCrossVec(&car2->Body->AngVel, &wheelColl2->Pos, &wheelColl2->Vel);
02583 VecPlusEqVec(&wheelColl2->Vel, &car2->Body->Centre.Vel);
02584
02585 VecMinusEqVec(&wheelColl2->Vel, &wheelColl->Vel);
02586 CopyVec(&wheelColl2->Vel, &wheelColl->Vel);
02587 NegateVec(&wheelColl->Vel);
02588
02589 wheelColl->Grip = wheel1->Grip * wheel2->Grip;
02590 wheelColl->StaticFriction = wheel1->StaticFriction * wheel2->StaticFriction;
02591 wheelColl->KineticFriction = wheel1->KineticFriction * wheel2->KineticFriction;
02592 wheelColl->Restitution = car1->Spring[iWheel1].Restitution;
02593 wheelColl->Material = NULL;
02594 wheelColl2->Grip = wheelColl->Grip;
02595 wheelColl2->StaticFriction = wheelColl->StaticFriction;
02596 wheelColl2->KineticFriction = wheelColl->KineticFriction;
02597 wheelColl2->Restitution = car2->Spring[iWheel2].Restitution;
02598 wheelColl2->Material = NULL;
02599
02600 nColls++;
02601 }
02602 }
02603
02604 return nColls;
02605 }
02606
02608
02609
02610
02612
02613 int DetectCarCarColls(CAR *car1, CAR *car2)
02614 {
02615 int nColls = 0;
02616
02617
02618 if (!BBTestXZY(&car1->BBox, &car2->BBox)) return nColls;
02619
02620
02621 nColls += DetectBodyBodyColls(car1->Body, car2->Body);
02622 nColls += DetectWheelBodyColls(car1, car2->Body);
02623 nColls += DetectWheelBodyColls(car2, car1->Body);
02624 nColls += DetectWheelWheelColls(car1, car2);
02625
02626 return nColls;
02627 }
02628
02629
02631
02632
02633
02635
02636 int DetectCarBodyColls(CAR *car, NEWBODY *body)
02637 {
02638 int nColls = 0;
02639
02640
02641 if (!BBTestXZY(&car->BBox, &body->CollSkin.BBox)) return nColls;
02642
02643
02644 nColls += DetectBodyBodyColls(car->Body, body);
02645 nColls += DetectWheelBodyColls(car, body);
02646
02647 return nColls;
02648
02649 }
02650
02651
02653
02654
02655
02656
02658 #ifdef _PC
02659 VEC DBG_PosDiff;
02660 VEC DBG_VelDiff;
02661
02662 void UpdateRemotePlayer(PLAYER *player)
02663 {
02664 REMOTE_DATA *rem;
02665 CAR *car;
02666
02667 car = &player->car;
02668 rem = &car->RemoteData[car->NewDat];
02669
02670
02671 if (!rem->NewData) return;
02672
02673
02674 player->controls.dx = rem->dx;
02675 player->controls.dy = rem->dy;
02676
02677
02678 VecMinusVec(&rem->Pos, &car->Body->Centre.Pos, &DBG_PosDiff);
02679 VecMinusVec(&rem->Vel, &car->Body->Centre.Vel, &DBG_VelDiff);
02680
02681
02682 CopyVec(&rem->Pos, &car->Body->Centre.Pos);
02683 CopyVec(&rem->Vel, &car->Body->Centre.Vel);
02684 CopyVec(&rem->AngVel, &car->Body->AngVel);
02685 CopyQuat(&rem->Quat, &car->Body->Centre.Quat);
02686
02687
02688 rem->NewData = FALSE;
02689
02690 }
02691 #endif
02692
02693
02695
02697 #ifdef _PC
02698
02699 void LoadOneCarModelSet(struct PlayerStruct *player, long car)
02700 {
02701 CAR_INFO *ci;
02702 CAR_MODEL *cm = &player->carmodels;
02703 COLLSKIN_INFO *collinfo = &cm->CollSkin;
02704 CONVEX *pSkin;
02705 FILE *fp;
02706 long i, iSkin, iFace, iPt;
02707 char tPage;
02708
02709
02710
02711 car %= NCarTypes;
02712 ci = &CarInfo[car];
02713
02714
02715
02716 cm->BodyPartsFlag = 0;
02717 cm->WheelPartsFlag[FL] = cm->WheelPartsFlag[FR] = cm->WheelPartsFlag[BL] = cm->WheelPartsFlag[BR] = 0;
02718
02719
02720
02721 for (i = 0 ; i < MAX_CAR_MODEL_TYPES; i++)
02722 {
02723 if (strlen(ci->ModelFile[i]))
02724 {
02725 if (i == 17 || i == 18) {
02726 tPage = TPAGE_FX1;
02727 } else {
02728 tPage = TPAGE_CAR_START + (char)player->Slot;
02729 }
02730 LoadModel(ci->ModelFile[i], cm->Model[i], tPage, MAX_CAR_LOD, LOADMODEL_FORCE_TPAGE, LevelInf[GameSettings.Level].ModelRGBper);
02731 }
02732 else
02733 {
02734 cm->Model[i]->AllocPtr = NULL;
02735 }
02736 }
02737
02738
02739
02740 if (strlen(ci->TPageFile))
02741 {
02742 LoadTextureClever(ci->TPageFile, TPAGE_CAR_START + (char)player->Slot, 256, 256, 0, CarTextureSet, TRUE);
02743 }
02744
02745
02746
02747
02748 cm->EnvRGB = ci->EnvRGB;
02749
02750
02751
02752 if (ci->CollFile && ci->CollFile[0])
02753 {
02754 if ((fp = fopen(ci->CollFile, "rb")) != NULL)
02755 {
02756
02757
02758 if ((collinfo->Convex = LoadConvex(fp, &collinfo->NConvex, 0)) != NULL)
02759 {
02760 collinfo->CollType = BODY_COLL_CONVEX;
02761
02762
02763 for (iSkin = 0; iSkin < collinfo->NConvex; iSkin++) {
02764 pSkin = &collinfo->Convex[iSkin];
02765
02766
02767
02768
02769
02770 for (iFace = 0; iFace < pSkin->NFaces; iFace++) {
02771 MovePlane(&pSkin->Faces[iFace], &ci->CoMOffset);
02772 }
02773
02774
02775 for (iPt = 0; iPt < pSkin->NPts; iPt++) {
02776 VecPlusEqVec(&pSkin->Pts[iPt], &ci->CoMOffset);
02777 }
02778 }
02779
02780 }
02781
02782
02783 if ((collinfo->Sphere = LoadSpheres(fp, &collinfo->NSpheres)) != NULL)
02784 {
02785
02786 for (iSkin = 0; iSkin < collinfo->NSpheres; iSkin++) {
02787
02788 VecPlusEqVec(&collinfo->Sphere[iSkin].Pos, &ci->CoMOffset);
02789 }
02790 }
02791
02792 MakeTightLocalBBox(collinfo);
02793
02794 fclose(fp);
02795 }
02796 }
02797 else
02798 {
02799 collinfo->NConvex = 0;
02800 collinfo->Convex = NULL;
02801 collinfo->NSpheres = 0;
02802 collinfo->Sphere = NULL;
02803 SetBBox(&collinfo->BBox, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO);
02804 }
02805
02806
02807
02808 cm->Body = cm->Model[ci->Body.ModelNum];
02809 CopyVec(&ci->Body.Offset, &cm->OffBody);
02810
02811
02812
02813 for (i = 0; i < 4; i++)
02814 {
02815 cm->Wheel[i] = cm->Model[ci->Wheel[i].ModelNum];
02816 CopyVec(&ci->Wheel[i].Offset1, &cm->OffWheel[i]);
02817 CopyVec(&ci->Wheel[i].Offset2, &cm->OffWheelColl[i])
02818 cm->WheelRad[i] = ci->Wheel[i].Radius;
02819 }
02820
02821
02822
02823 if (ci->Spinner.ModelNum != CAR_MODEL_NONE)
02824 {
02825 cm->BodyPartsFlag |= CAR_MODEL_SPINNER;
02826 cm->Spinner = cm->Model[ci->Spinner.ModelNum];
02827 CopyVec(&ci->Spinner.Offset, &cm->OffSpinner);
02828 }
02829
02830
02831
02832 if (ci->Aerial.SecModelNum != CAR_MODEL_NONE && ci->Aerial.TopModelNum != CAR_MODEL_NONE)
02833 {
02834 cm->BodyPartsFlag |= CAR_MODEL_AERIAL;
02835 cm->Aerial[0] = cm->Model[ci->Aerial.SecModelNum];
02836 cm->Aerial[1] = cm->Model[ci->Aerial.TopModelNum];
02837 CopyVec(&ci->Aerial.Offset, &cm->OffAerial);
02838 CopyVec(&ci->Aerial.Direction, &cm->DirAerial);
02839 cm->AerialLen = ci->Aerial.SecLen;
02840 }
02841
02842
02843
02844 for (i = 0; i < 4; i++)
02845 {
02846
02847
02848
02849 if (ci->Spring[i].ModelNum != CAR_MODEL_NONE)
02850 {
02851 cm->Spring[i] = cm->Model[ci->Spring[i].ModelNum];
02852 CopyVec(&ci->Spring[i].Offset, &cm->OffSpring[i]);
02853 cm->WheelPartsFlag[i] |= CAR_MODEL_SPRING;
02854 cm->SpringLen[i] = ci->Spring[i].Length;
02855 }
02856
02857
02858
02859 if (ci->Axle[i].ModelNum != CAR_MODEL_NONE)
02860 {
02861 cm->Axle[i] = cm->Model[ci->Axle[i].ModelNum];
02862 CopyVec(&ci->Axle[i].Offset, &cm->OffAxle[i]);
02863 cm->AxleLen[i] = ci->Axle[i].Length;
02864 cm->WheelPartsFlag[i] |= CAR_MODEL_AXLE;
02865 }
02866
02867
02868
02869 if (ci->Pin[i].ModelNum != CAR_MODEL_NONE)
02870 {
02871 cm->Pin[i] = cm->Model[ci->Pin[i].ModelNum];
02872 CopyVec(&ci->Pin[i].Offset, &cm->OffPin[i]);
02873 cm->PinLen[i] = ci->Pin[i].Length;
02874 cm->WheelPartsFlag[i] |= CAR_MODEL_PIN;
02875 }
02876 }
02877 }
02878 #endif
02879
02880
02881
02882 #ifdef _N64
02883
02884 void LoadOneCarModelSet(struct PlayerStruct *player, long car)
02885 {
02886 CAR_INFO *ci;
02887 CAR_MODEL *cm = &player->carmodels;
02888 COLLSKIN_INFO *collinfo = &cm->CollSkin;
02889 CONVEX *pSkin;
02890 long ii, jj, iSkin, iFace, iPt;
02891 FIL *fp;
02892 long Flag = 0;
02893
02894
02895
02896 car %= NCarTypes;
02897 ci = &CarInfo[car];
02898
02899
02900
02901 cm->BodyPartsFlag = 0;
02902 cm->WheelPartsFlag[FL] = cm->WheelPartsFlag[FR] = cm->WheelPartsFlag[BL] = cm->WheelPartsFlag[BR] = 0;
02903
02904
02905
02906 for (ii = 0 ; ii < MAX_CAR_MODEL_TYPES; ii++)
02907 {
02908 if (ci->EnvRGB) { Flag = MODEL_ENV; }
02909 if (ci->ModelFile[ii])
02910 {
02911 MOD_LoadModel(ci->ModelFile[ii], ci->TextureFile[ii], &cm->Model[ii][0], ci->EnvRGB, LevelInf[GameSettings.Level].ModelRGBper, Flag);
02912 }
02913 else
02914 {
02915 cm->Model[ii][0].hdr = NULL;
02916 }
02917 }
02918
02919
02920 cm->EnvRGB = ci->EnvRGB;
02921
02922
02923
02924 if (ci->CollFile)
02925 {
02926 if ((fp = FFS_Open(ci->CollFile)) != NULL)
02927 {
02928
02929
02930 if ((collinfo->Convex = LoadConvex(fp, &collinfo->NConvex, 0)) != NULL)
02931 {
02932 collinfo->CollType = BODY_COLL_CONVEX;
02933
02934
02935 for (iSkin = 0; iSkin < collinfo->NConvex; iSkin++)
02936 {
02937 pSkin = &collinfo->Convex[iSkin];
02938
02939
02940
02941
02942
02943 for (iFace = 0; iFace < pSkin->NFaces; iFace++)
02944 {
02945 MovePlane(&pSkin->Faces[iFace], &ci->CoMOffset);
02946 }
02947
02948
02949 for (iPt = 0; iPt < pSkin->NPts; iPt++)
02950 {
02951 VecPlusEqVec(&pSkin->Pts[iPt], &ci->CoMOffset);
02952 }
02953 }
02954 }
02955
02956
02957 if ((collinfo->Sphere = LoadSpheres(fp, &collinfo->NSpheres)) != NULL)
02958 {
02959
02960 for (iSkin = 0; iSkin < collinfo->NSpheres; iSkin++)
02961 {
02962
02963 VecPlusEqVec(&collinfo->Sphere[iSkin].Pos, &ci->CoMOffset);
02964 }
02965 }
02966
02967 MakeTightLocalBBox(collinfo);
02968
02969 FFS_Close(fp);
02970 }
02971 }
02972 else
02973 {
02974 collinfo->NConvex = 0;
02975 collinfo->Convex = NULL;
02976 collinfo->NSpheres = 0;
02977 collinfo->Sphere = NULL;
02978 SetBBox(&collinfo->BBox, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO);
02979 }
02980
02981
02982
02983 cm->Body = cm->Model[ci->Body.ModelNum];
02984 CopyVec(&ci->Body.Offset, &cm->OffBody);
02985
02986
02987
02988 for (ii = 0; ii < 4; ii++)
02989 {
02990 cm->Wheel[ii] = cm->Model[ci->Wheel[ii].ModelNum];
02991 CopyVec(&ci->Wheel[ii].Offset1, &cm->OffWheel[ii]);
02992 CopyVec(&ci->Wheel[ii].Offset2, &cm->OffWheelColl[ii])
02993 cm->WheelRad[ii] = ci->Wheel[ii].Radius;
02994 }
02995
02996
02997
02998 if (ci->Spinner.ModelNum != CAR_MODEL_NONE)
02999 {
03000 cm->BodyPartsFlag |= CAR_MODEL_SPINNER;
03001 cm->Spinner = cm->Model[ci->Spinner.ModelNum];
03002 CopyVec(&ci->Spinner.Offset, &cm->OffSpinner);
03003 }
03004
03005
03006
03007 if (ci->Aerial.SecModelNum != CAR_MODEL_NONE && ci->Aerial.TopModelNum != CAR_MODEL_NONE)
03008 {
03009 cm->BodyPartsFlag |= CAR_MODEL_AERIAL;
03010 cm->Aerial[0] = cm->Model[ci->Aerial.SecModelNum];
03011 cm->Aerial[1] = cm->Model[ci->Aerial.TopModelNum];
03012 CopyVec(&ci->Aerial.Offset, &cm->OffAerial);
03013 CopyVec(&ci->Aerial.Direction, &cm->DirAerial);
03014 cm->AerialLen = ci->Aerial.SecLen;
03015 }
03016
03017
03018
03019 for (ii = 0; ii < 4; ii++)
03020 {
03021
03022
03023
03024 if (ci->Spring[ii].ModelNum != CAR_MODEL_NONE)
03025 {
03026 cm->Spring[ii] = cm->Model[ci->Spring[ii].ModelNum];
03027 CopyVec(&ci->Spring[ii].Offset, &cm->OffSpring[ii]);
03028 cm->WheelPartsFlag[ii] |= CAR_MODEL_SPRING;
03029 cm->SpringLen[ii] = ci->Spring[ii].Length;
03030 }
03031
03032
03033
03034 if (ci->Axle[ii].ModelNum != CAR_MODEL_NONE)
03035 {
03036 cm->Axle[ii] = cm->Model[ci->Axle[ii].ModelNum];
03037 CopyVec(&ci->Axle[ii].Offset, &cm->OffAxle[ii]);
03038 cm->AxleLen[ii] = ci->Axle[ii].Length;
03039 cm->WheelPartsFlag[ii] |= CAR_MODEL_AXLE;
03040 }
03041
03042
03043
03044 if (ci->Pin[ii].ModelNum != CAR_MODEL_NONE)
03045 {
03046 cm->Pin[ii] = cm->Model[ci->Pin[ii].ModelNum];
03047 CopyVec(&ci->Pin[ii].Offset, &cm->OffPin[ii]);
03048 cm->PinLen[ii] = ci->Pin[ii].Length;
03049 cm->WheelPartsFlag[ii] |= CAR_MODEL_PIN;
03050 }
03051 }
03052 }
03053
03054 #endif
03055
03056
03057
03059
03061 #ifdef _PC
03062
03063 void FreeOneCarModelSet(struct PlayerStruct *player)
03064 {
03065 long i;
03066
03067
03068
03069 for (i = 0 ; i < MAX_CAR_MODEL_TYPES ; i++)
03070 {
03071 if (player->carmodels.Model[i]->AllocPtr)
03072 {
03073 FreeModel(player->carmodels.Model[i], MAX_CAR_LOD);
03074 }
03075 }
03076
03077
03078
03079 FreeOneTexture(TPAGE_CAR_START + (char)player->Slot);
03080
03081
03082
03083 DestroyConvex(player->car.Models->CollSkin.Convex, player->car.Models->CollSkin.NConvex);
03084 player->car.Models->CollSkin.Convex = NULL;
03085 player->car.Body->CollSkin.Convex = NULL;
03086 player->car.Models->CollSkin.NConvex = 0;
03087
03088 DestroySpheres(player->car.Models->CollSkin.Sphere);
03089 player->car.Models->CollSkin.Sphere = NULL;
03090 player->car.Body->CollSkin.Sphere = NULL;
03091 player->car.Models->CollSkin.NSpheres = 0;
03092 }
03093 #endif
03094
03095
03096
03097
03098 #ifdef _N64
03099
03100 void FreeOneCarModelSet(struct PlayerStruct *player)
03101 {
03102 long i;
03103
03104
03105
03106 for (i = 0 ; i < MAX_CAR_MODEL_TYPES ; i++)
03107 {
03108 if (player->carmodels.Model[i])
03109 {
03110 MOD_FreeModel(player->carmodels.Model[i]);
03111 }
03112 }
03113
03114
03115
03116 DestroyConvex(player->car.Models->CollSkin.Convex, player->car.Models->CollSkin.NConvex);
03117 player->car.Models->CollSkin.Convex = NULL;
03118 player->car.Body->CollSkin.Convex = NULL;
03119 player->car.Models->CollSkin.NConvex = 0;
03120
03121 DestroySpheres(player->car.Models->CollSkin.Sphere);
03122 player->car.Models->CollSkin.Sphere = NULL;
03123 player->car.Body->CollSkin.Sphere = NULL;
03124 player->car.Models->CollSkin.NSpheres = 0;
03125
03126 }
03127
03128 #endif
03129
03130
03131
03133
03134
03135
03136
03138
03139 #ifndef _PSX
03140
03141 void CarAccTimings(CAR *car)
03142 {
03143 REAL carVel;
03144
03145 carVel = OGU2MPH_SPEED * VecLen(&car->Body->Centre.Vel);
03146
03147
03148 if (carVel < Real(0.01)) {
03149 car->Timing0to15 = TRUE;
03150 car->Timing0to25 = TRUE;
03151 car->Current0to15 = ZERO;
03152 car->Current0to25 = ZERO;
03153 return;
03154 }
03155
03156
03157 if (car->Timing0to15) {
03158 car->Current0to15 += TimeStep;
03159 }
03160 if (car->Timing0to25) {
03161 car->Current0to25 += TimeStep;
03162 }
03163
03164
03165 if (car->Timing0to15 && carVel > 15) {
03166 if ((car->Current0to15 < car->Best0to15) || (car->Best0to15 < ZERO)) {
03167 car->Best0to15 = car->Current0to15;
03168 }
03169 car->Timing0to15 = FALSE;
03170 }
03171 if (car->Timing0to25 && carVel > 25) {
03172 if ((car->Current0to25 < car->Best0to25) || (car->Best0to25 < ZERO)) {
03173 car->Best0to25 = car->Current0to25;
03174 }
03175 car->Timing0to25 = FALSE;
03176 }
03177
03178 }
03179
03180
03181 #endif
03182
03184
03185
03186
03188
03189 #define WFL_CONTACT 1
03190 #define WFR_CONTACT 2
03191 #define WBL_CONTACT 4
03192 #define WBR_CONTACT 8
03193 #if USE_DEBUG_ROUTINES
03194 VEC DEBUG_DownForce;
03195 #endif
03196
03197 void CarDownForce(CAR *car)
03198 {
03199 #ifndef _PSX
03200 int ii;
03201 REAL vel, mod;
03202 VEC downForce = {ZERO, ZERO, ZERO};
03203 long contact = 0;
03204
03205
03206 for (ii = 0; ii < CAR_NWHEELS; ii++) {
03207 if (IsWheelPresent(&car->Wheel[ii]) && IsWheelInContact(&car->Wheel[ii])) {
03208 contact |= 1 << ii;
03209 }
03210 }
03211
03212
03213 if (contact == (WFL_CONTACT | WFR_CONTACT | WBL_CONTACT | WBR_CONTACT)) return;
03214
03215 mod = ONE + HALF - abs(VecDotVec(&car->Body->Centre.WMatrix.mv[U], &UpVec));
03216 if (mod > ONE) mod = ONE;
03217
03218
03219 if (contact == (WFL_CONTACT | WBL_CONTACT)) {
03220 vel = MulScalar(TimeStep, VecDotVec(&car->Body->Centre.Vel, &car->Body->Centre.WMatrix.mv[L]));
03221 vel = MulScalar(vel, mod);
03222 VecPlusEqScalarVec(&downForce, MulScalar(car->DownForceMod, vel), &car->Body->Centre.WMatrix.mv[U]);
03223 }
03224
03225
03226 if (contact == (WFR_CONTACT | WBR_CONTACT)) {
03227 vel = MulScalar(TimeStep, VecDotVec(&car->Body->Centre.Vel, &car->Body->Centre.WMatrix.mv[L]));
03228 vel = MulScalar(vel, mod);
03229 VecPlusEqScalarVec(&downForce, MulScalar(car->DownForceMod, vel), &car->Body->Centre.WMatrix.mv[U]);
03230 }
03231
03232 VecPlusEqVec(&car->Body->Centre.Impulse, &downForce);
03233
03234 #if USE_DEBUG_ROUTINES
03235 CopyVec(&downForce, &DEBUG_DownForce);
03236 #endif
03237
03238 #endif
03239 }
03240
03241
03243
03244
03245
03247
03248 COLLINFO_WHEEL *AddWheelColl(CAR *car, COLLINFO_WHEEL *newHead)
03249 {
03250 COLLINFO_WHEEL *oldHead = car->WheelCollHead;
03251
03252 car->WheelCollHead = newHead;
03253 newHead->Next = oldHead;
03254 newHead->Prev = NULL;
03255
03256 if (oldHead != NULL) {
03257 oldHead->Prev = newHead;
03258 }
03259
03260 car->NWheelColls++;
03261 COL_NWheelColls++;
03262
03263 return newHead;
03264 }
03265
03267
03268
03269
03271
03272 void RemoveWheelColl(CAR *car, COLLINFO_WHEEL *collInfo)
03273 {
03274 Assert(collInfo != NULL);
03275
03276 if (collInfo->Next != NULL) {
03277 (collInfo->Next)->Prev = collInfo->Prev;
03278 }
03279
03280 if (collInfo->Prev != NULL) {
03281 (collInfo->Prev)->Next = collInfo->Next;
03282 } else {
03283 car->WheelCollHead = collInfo->Next;
03284 }
03285
03286 car->NWheelColls--;
03287
03288 Assert((car->NWheelColls == 0)? (car->WheelCollHead == NULL): (car->WheelCollHead != NULL));
03289 }
03290
03291
03292
03293
03294 #if MSCOMPILER_FUDGE_OPTIMISATIONS
03295 #pragma optimize("", on)
03296 #endif