00001
00002 #include "revolt.h"
00003 #include "coll.h"
00004 #include "geom.h"
00005 #ifdef _PC
00006 #include "text.h"
00007 #include "main.h"
00008 #endif
00009 #include "NewColl.h"
00010
00011
00012 #ifdef _PC
00013 short CollNum;
00014 #else
00015 long CollNum;
00016 #endif
00017
00018 COLL_POLY *CollPtr;
00019
00020 #ifdef _N64
00021
00022
00023
00024
00025
00026
00027
00028 void COL_LoadCollision(FIL_ID Fil)
00029 {
00030 COLL_HEADER ch;
00031 FIL *skin;
00032
00033 printf("Loading collision data...\n");
00034 skin = FFS_Open(Fil);
00035 if (skin == NULL)
00036 {
00037 ERROR("COL", "COL_LoadCollision", "Failed to open collision skin file", 1);
00038 }
00039
00040 FFS_Read((char *)&CollNum, sizeof(long), skin);
00041
00042 printf("...collision skin has %d polys.\n", CollNum);
00043
00044 CollPtr = malloc(CollNum * sizeof(COLL_POLY));
00045 if (CollPtr == NULL)
00046 {
00047 ERROR("COL", "COL_LoadCollision", "Could not allocate memory for collision skin", 1);
00048 }
00049
00050 FFS_Read((char *)CollPtr, sizeof(COLL_POLY) * CollNum, skin);
00051
00052 FFS_Close(skin);
00053 }
00054
00055
00056
00057
00058
00059
00060
00061
00062 void COL_FreeCollision(void)
00063 {
00064 free(CollPtr);
00065 }
00066
00067 #else
00068
00070
00072
00073 bool LoadCollision(char *file)
00074 {
00075 COLL_HEADER ch;
00076 FILE *fp;
00077
00078
00079
00080 fp = fopen(file, "rb");
00081 if (fp == NULL)
00082 {
00083 char buff[128];
00084 wsprintf(buff, "Can't load collision file: '%s'", file);
00085 Box("ERROR", buff, MB_OK);
00086 return FALSE;
00087 }
00088
00089
00090
00091 fread(&ch, sizeof(ch), 1, fp);
00092 CollNum = ch.CollNum;
00093 CollPtr = (COLL_POLY*)malloc(CollNum * sizeof(COLL_POLY));
00094 if (CollPtr == NULL) return FALSE;
00095
00096
00097
00098 fread(CollPtr, sizeof(COLL_POLY), CollNum, fp);
00099
00100
00101
00102 fclose(fp);
00103
00104
00105
00106 return TRUE;
00107 }
00108
00110
00112
00113 void FreeCollision(void)
00114 {
00115 free(CollPtr);
00116 CollPtr = NULL;
00117 CollNum = 0;
00118 }
00119
00120 #endif //_N64
00121
00123
00125
00126 char PointInsidePlane(VECTOR *point, COLL_POLY *p)
00127 {
00128 VECTOR vec1, vec2;
00129
00130
00131
00132 if (p->Flag & 1)
00133 {
00134 SubVector(&p->v1, &p->v0, &vec1);
00135 SubVector(point, &p->v0, &vec2);
00136 if (CrossProduct3(&vec1, &vec2, (VECTOR*)&p->Plane) > 0) return FALSE;
00137
00138 SubVector(&p->v2, &p->v1, &vec1);
00139 SubVector(point, &p->v1, &vec2);
00140 if (CrossProduct3(&vec1, &vec2, (VECTOR*)&p->Plane) > 0) return FALSE;
00141
00142 SubVector(&p->v3, &p->v2, &vec1);
00143 SubVector(point, &p->v2, &vec2);
00144 if (CrossProduct3(&vec1, &vec2, (VECTOR*)&p->Plane) > 0) return FALSE;
00145
00146 SubVector(&p->v0, &p->v3, &vec1);
00147 SubVector(point, &p->v3, &vec2);
00148 if (CrossProduct3(&vec1, &vec2, (VECTOR*)&p->Plane) > 0) return FALSE;
00149 }
00150 else
00151 {
00152 SubVector(&p->v1, &p->v0, &vec1);
00153 SubVector(point, &p->v0, &vec2);
00154 if (CrossProduct3(&vec1, &vec2, (VECTOR*)&p->Plane) > 0) return FALSE;
00155
00156 SubVector(&p->v2, &p->v1, &vec1);
00157 SubVector(point, &p->v1, &vec2);
00158 if (CrossProduct3(&vec1, &vec2, (VECTOR*)&p->Plane) > 0) return FALSE;
00159
00160 SubVector(&p->v0, &p->v2, &vec1);
00161 SubVector(point, &p->v2, &vec2);
00162 if (CrossProduct3(&vec1, &vec2, (VECTOR*)&p->Plane) > 0) return FALSE;
00163 }
00164
00165
00166
00167 return TRUE;
00168 }
00169
00171
00173
00174 float PointToPolyEdge(VECTOR *point, COLL_POLY *p, VECTOR *out)
00175 {
00176 VECTOR linepoint;
00177 float linedist, dist;
00178
00179
00180
00181 if (p->Flag & 1)
00182 {
00183 dist = FindNearestPointOnLine(&p->v0, &p->v1, point, out);
00184
00185 linedist = FindNearestPointOnLine(&p->v1, &p->v2, point, &linepoint);
00186 if (linedist < dist)
00187 {
00188 dist = linedist;
00189 SetVector(out, linepoint.v[X], linepoint.v[Y], linepoint.v[Z]);
00190 }
00191
00192 linedist = FindNearestPointOnLine(&p->v2, &p->v3, point, &linepoint);
00193 if (linedist < dist)
00194 {
00195 dist = linedist;
00196 SetVector(out, linepoint.v[X], linepoint.v[Y], linepoint.v[Z]);
00197 }
00198
00199 linedist = FindNearestPointOnLine(&p->v3, &p->v0, point, &linepoint);
00200 if (linedist < dist)
00201 {
00202 dist = linedist;
00203 SetVector(out, linepoint.v[X], linepoint.v[Y], linepoint.v[Z]);
00204 }
00205 }
00206
00207
00208
00209 else
00210 {
00211 dist = FindNearestPointOnLine(&p->v0, &p->v1, point, out);
00212
00213 linedist = FindNearestPointOnLine(&p->v1, &p->v2, point, &linepoint);
00214 if (linedist < dist)
00215 {
00216 dist = linedist;
00217 SetVector(out, linepoint.v[X], linepoint.v[Y], linepoint.v[Z]);
00218 }
00219
00220 linedist = FindNearestPointOnLine(&p->v2, &p->v0, point, &linepoint);
00221 if (linedist < dist)
00222 {
00223 dist = linedist;
00224 SetVector(out, linepoint.v[X], linepoint.v[Y], linepoint.v[Z]);
00225 }
00226 }
00227
00228
00229
00230 return dist;
00231 }
00232
00234
00236
00237 float FindNearestPointOnLine(VECTOR *lp1, VECTOR *lp2, VECTOR *point, VECTOR *out)
00238 {
00239 PLANE plane;
00240 VECTOR diff;
00241 float linedist, pointdist;
00242
00243
00244
00245 SubVector(lp2, lp1, &diff);
00246 linedist = Length(&diff);
00247
00248
00249
00250 SetVector((VECTOR*)&plane, diff.v[X] / linedist, diff.v[Y] / linedist, diff.v[Z] / linedist);
00251 plane.v[D] = -DotProduct(lp1, (VECTOR*)&plane);
00252 pointdist = PlaneDist(&plane, point);
00253
00254
00255
00256 if (pointdist < 0) pointdist = 0;
00257 else if (pointdist > linedist) pointdist = linedist;
00258
00259
00260
00261 out->v[X] = lp1->v[X] + (diff.v[X] / linedist * pointdist);
00262 out->v[Y] = lp1->v[Y] + (diff.v[Y] / linedist * pointdist);
00263 out->v[Z] = lp1->v[Z] + (diff.v[Z] / linedist * pointdist);
00264
00265
00266
00267 SubVector(out, point, &diff);
00268 return Length(&diff);
00269 }
00270
00272
00274
00275 void FindIntersection(VECTOR *point1, float dist1, VECTOR *point2, float dist2, VECTOR *out)
00276 {
00277 float mul;
00278 VECTOR diff;
00279
00280
00281
00282 SubVector(point2, point1, &diff);
00283 mul = -dist1 / (dist2 - dist1);
00284
00285
00286
00287 out->v[X] = point1->v[X] + diff.v[X] * mul;
00288 out->v[Y] = point1->v[Y] + diff.v[Y] * mul;
00289 out->v[Z] = point1->v[Z] + diff.v[Z] * mul;
00290 }
00291
00293
00295
00296 short SpheresToPlane(VECTOR *o, VECTOR *n, VECTOR *out, float rad, COLL_POLY *p)
00297 {
00298 char flag = FALSE;
00299 float odist, ndist, mul;
00300 VECTOR inter, diff;
00301
00302
00303
00304 ndist = -PlaneDist(&p->Plane, n);
00305 if (ndist <= -rad) return FALSE;
00306
00307 odist = -PlaneDist(&p->Plane, o);
00308 if (odist >= 0) return FALSE;
00309
00310 if (ndist <= odist) return FALSE;
00311
00312
00313
00314 SubVector(n, o, &diff);
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 if (!flag)
00327 {
00328 if (!ndist) memcpy(&inter, n, sizeof(VECTOR));
00329 else
00330 {
00331 mul = -odist / (ndist - odist);
00332 inter.v[X] = o->v[X] + diff.v[X] * mul;
00333 inter.v[Y] = o->v[Y] + diff.v[Y] * mul;
00334 inter.v[Z] = o->v[Z] + diff.v[Z] * mul;
00335 }
00336 if (PointInsidePlane(&inter, p)) flag = TRUE;
00337 }
00338
00339
00340
00341 if (!flag) return FALSE;
00342
00343
00344
00345 odist += rad;
00346 ndist += rad;
00347
00348 if (!odist) memcpy(out, o, sizeof(VECTOR));
00349 else
00350 {
00351 mul = -odist / (ndist - odist);
00352 out->v[X] = o->v[X] + diff.v[X] * mul;
00353 out->v[Y] = o->v[Y] + diff.v[Y] * mul;
00354 out->v[Z] = o->v[Z] + diff.v[Z] * mul;
00355 }
00356
00357 return TRUE;
00358 }
00359
00361
00363
00364 short SpheresToPlaneNorm(VECTOR *o, VECTOR *n, VECTOR *out, float rad, COLL_POLY *p)
00365 {
00366 float odist, ndist;
00367
00368
00369
00370 ndist = -PlaneDist(&p->Plane, n);
00371 if (ndist <= -rad) return FALSE;
00372
00373 odist = -PlaneDist(&p->Plane, o);
00374 if (odist >= 0) return FALSE;
00375
00376 if (ndist <= odist) return FALSE;
00377
00378
00379
00380 if (PointInsidePlane(n, p))
00381 {
00382
00383
00384
00385 ndist += rad;
00386
00387 out->v[X] = n->v[X] + p->Plane.v[A] * ndist;
00388 out->v[Y] = n->v[Y] + p->Plane.v[B] * ndist;
00389 out->v[Z] = n->v[Z] + p->Plane.v[C] * ndist;
00390
00391 return TRUE;
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 return FALSE;
00415 }
00416
00418
00420
00421 char SphereCollTest(VECTOR *from, VECTOR *to, float radius, VECTOR *result, float *friction, VECTOR *norm)
00422 {
00423 short i;
00424 char flag;
00425 COLL_POLY *p;
00426 VECTOR vec, old;
00427 float MinX, MaxX, MinY, MaxY, MinZ, MaxZ;
00428
00429
00430
00431 *friction = 0;
00432
00433
00434
00435 MinX = from->v[X] - radius;
00436 MaxX = from->v[X] + radius;
00437 MinY = from->v[Y] - radius;
00438 MaxY = from->v[Y] + radius;
00439 MinZ = from->v[Z] - radius;
00440 MaxZ = from->v[Z] + radius;
00441
00442 if (to->v[X] - radius < MinX) MinX = to->v[X] - radius;
00443 if (to->v[X] + radius > MaxX) MaxX = to->v[X] + radius;
00444 if (to->v[Y] - radius < MinY) MinY = to->v[Y] - radius;
00445 if (to->v[Y] + radius > MaxY) MaxY = to->v[Y] + radius;
00446 if (to->v[Z] - radius < MinZ) MinZ = to->v[Z] - radius;
00447 if (to->v[Z] + radius > MaxZ) MaxZ = to->v[Z] + radius;
00448
00449
00450
00451 flag = FALSE;
00452 p = CollPtr;
00453 SetVector(&old, from->v[X], from->v[Y], from->v[Z]);
00454 SetVector(result, to->v[X], to->v[Y], to->v[Z]);
00455
00456 for (i = 0 ; i < CollNum ; i++, p++)
00457 {
00458
00459
00460
00461 if (MinX > p->MaxX || MaxX < p->MinX || MinY > p->MaxY || MaxY < p->MinY || MinZ > p->MaxZ || MaxZ < p->MinZ) continue;
00462
00463
00464
00465 if (SpheresToPlane(&old, result, &vec, radius, p))
00466 {
00467 SubVector(&vec, result, &vec);
00468 AddVector(&old, &vec, &old);
00469 AddVector(result, &vec, result);
00470 *friction = 1;
00471 memcpy(norm, &p->Plane, sizeof(VECTOR));
00472 flag = TRUE;
00473 }
00474 }
00475
00476
00477
00478 return flag;
00479 }
00480
00482
00484
00485 char SphereCollTestNorm(VECTOR *from, VECTOR *to, float radius, VECTOR *result, float *friction, VECTOR *norm)
00486 {
00487 short i;
00488 char flag;
00489 COLL_POLY *p;
00490 VECTOR vec, old;
00491 float MinX, MaxX, MinY, MaxY, MinZ, MaxZ;
00492
00493
00494
00495 *friction = 0;
00496
00497
00498
00499 MinX = from->v[X] - radius;
00500 MaxX = from->v[X] + radius;
00501 MinY = from->v[Y] - radius;
00502 MaxY = from->v[Y] + radius;
00503 MinZ = from->v[Z] - radius;
00504 MaxZ = from->v[Z] + radius;
00505
00506 if (to->v[X] - radius < MinX) MinX = to->v[X] - radius;
00507 if (to->v[X] + radius > MaxX) MaxX = to->v[X] + radius;
00508 if (to->v[Y] - radius < MinY) MinY = to->v[Y] - radius;
00509 if (to->v[Y] + radius > MaxY) MaxY = to->v[Y] + radius;
00510 if (to->v[Z] - radius < MinZ) MinZ = to->v[Z] - radius;
00511 if (to->v[Z] + radius > MaxZ) MaxZ = to->v[Z] + radius;
00512
00513
00514
00515 flag = FALSE;
00516 p = CollPtr;
00517 SetVector(&old, from->v[X], from->v[Y], from->v[Z]);
00518 SetVector(result, to->v[X], to->v[Y], to->v[Z]);
00519
00520 for (i = 0 ; i < CollNum ; i++, p++)
00521 {
00522
00523
00524
00525 if (MinX > p->MaxX || MaxX < p->MinX || MinY > p->MaxY || MaxY < p->MinY || MinZ > p->MaxZ || MaxZ < p->MinZ) continue;
00526
00527
00528
00529 if (SpheresToPlaneNorm(&old, result, &vec, radius, p))
00530 {
00531 SubVector(&vec, result, &vec);
00532 AddVector(&old, &vec, &old);
00533 AddVector(result, &vec, result);
00534 *friction = 1;
00535 memcpy(norm, &p->Plane, sizeof(VECTOR));
00536 flag = TRUE;
00537 }
00538 }
00539
00540
00541
00542 return flag;
00543 }
00544