00001 /********************************************************************************************* 00002 * 00003 * grid.cpp 00004 * 00005 * Re-Volt (PC) Copyright (c) Probe Entertainment 1998 00006 * 00007 * Contents: 00008 * Object and AI node grid system, incorporating object test mark-off system. 00009 * 00010 ********************************************************************************************* 00011 * 00012 * 22/07/98 MTaylor 00013 * File inception. Basic grid and object mark-off functions created. 00014 * 00015 *********************************************************************************************/ 00016 00017 #include "revolt.h" 00018 #include "main.h" 00019 #include "geom.h" 00020 #include "particle.h" 00021 #include "model.h" 00022 #include "aerial.h" 00023 #include "newcoll.h" 00024 #include "body.h" 00025 #include "car.h" 00026 #include "ctrlread.h" 00027 #include "object.h" 00028 #include "ainode.h" 00029 #include "editai.h" 00030 00031 // 00032 // Static variables 00033 // 00034 00035 static char *s_ObjPair; 00036 00037 00038 // 00039 // Global variables 00040 // 00041 00042 OBJGRIDUNIT *ObjGrid[MAX_GRIDS]; 00043 NODEGRIDUNIT *NodeGrid[MAX_GRIDS]; 00044 00045 00046 // 00047 // Static Functions 00048 // 00049 00050 static long s_LineIntersect(REAL x0, REAL z0, REAL x1, REAL z1, REAL x2, REAL z2, REAL x3, REAL z3); 00051 static REAL s_PointLine(REAL x, REAL y, REAL x0, REAL y0, REAL x1, REAL y1); 00052 static long s_PointInNodePoly(REAL x, REAL y, AINODE *Node, long Path); 00053 00054 00055 // 00056 // Global functions 00057 // 00058 00059 long GRD_AllocGrids(void); 00060 void GRD_FreeGrids(void); 00061 void GRD_UpdateObjGrid(void); 00062 void GRD_RemoveObject(OBJECT *Obj); 00063 void GRD_ResetObjPairs(void); 00064 long GRD_ObjectPair(OBJECT *Obj1, OBJECT *Obj2); 00065 void GRD_GridNodes(AINODE *Src, long Num); 00066 00067 00068 //-------------------------------------------------------------------------------------------------------------------------- 00069 00070 // 00071 // GRD_AllocGrids 00072 // 00073 // Allocates buffers for the grids and object pair system 00074 // 00075 00076 long GRD_AllocGrids(void) 00077 { 00078 long ii; 00079 00080 for (ii = 0; ii < MAX_GRIDS; ii++) 00081 { 00082 ObjGrid[ii] = (OBJGRIDUNIT *)malloc(OBJ_GRID_SIZE * sizeof(OBJGRIDUNIT)); 00083 if (!ObjGrid[ii]) 00084 { 00085 Error("GRD", "GRD_AllocGrid", "Could not alloc memory for object grid system", 1); 00086 return(FALSE); 00087 } 00088 memset(ObjGrid[ii], 0, OBJ_GRID_SIZE * sizeof(OBJGRIDUNIT)); // Initialise pointers to NULL (memset, rather than memclr for N64 compatability) 00089 00090 NodeGrid[ii] = (NODEGRIDUNIT *)malloc(NODE_GRID_SIZE * sizeof(NODEGRIDUNIT)); 00091 if (!NodeGrid[ii]) 00092 { 00093 Error("GRD", "GRD_AllocGrid", "Could not alloc memory for object grid system", 1); 00094 return(FALSE); 00095 } 00096 memset(NodeGrid[ii], 0, NODE_GRID_SIZE * sizeof(NODEGRIDUNIT)); // Initialise pointers to NULL (memset, rather than memclr for N64 compatability) 00097 } 00098 00099 s_ObjPair = (char *)malloc(MAX_OBJECTS * MAX_OBJECTS); 00100 if (!s_ObjPair) 00101 { 00102 Error("GRD", "GRD_AllocGrid", "Could not alloc memory for object pair buffer", 1); 00103 return(FALSE); 00104 } 00105 memset(s_ObjPair, 0, MAX_OBJECTS * MAX_OBJECTS); 00106 00107 return (TRUE); 00108 } 00109 00110 //-------------------------------------------------------------------------------------------------------------------------- 00111 00112 // 00113 // GRD_FreeGrid 00114 // 00115 // Deallocates the buffers used by the grid system 00116 // 00117 00118 void GRD_FreeGrids(void) 00119 { 00120 long ii; 00121 00122 for (ii = 0; ii < MAX_GRIDS; ii++) 00123 { 00124 free(ObjGrid[ii]); 00125 free(NodeGrid[ii]); 00126 } 00127 free(s_ObjPair); 00128 } 00129 00130 //-------------------------------------------------------------------------------------------------------------------------- 00131 00132 // 00133 // GRD_UpdateObjGrid 00134 // 00135 // Checks all active objects to see if they have changed grid location for each grid, updating if necessary. 00136 // Also adds new objects into grid. 00137 // 00138 00139 void GRD_UpdateObjGrid(void) 00140 { 00141 long x, z; 00142 long xShift, zShift; 00143 long xOff, zOff; 00144 long Grid; 00145 OBJECT *Obj; 00146 OBJECT *TempObj; 00147 00148 for (zShift = 0; zShift < MAX_SHIFTS; zShift++) 00149 { 00150 zOff = zShift * OBJ_SHIFT_OFFSET; 00151 for (xShift = 0; xShift < MAX_SHIFTS; xShift++) 00152 { 00153 xOff = xShift * OBJ_SHIFT_OFFSET; 00154 Grid = xShift + (zShift * MAX_SHIFTS); 00155 for (Obj = OBJ_ObjectHead; Obj; Obj = Obj->next) 00156 { // First off, generate x & z indices for grid access 00157 x = (long)(Obj->body.Centre.Pos.v[X] + 32768 - xOff) / OBJ_UNIT_SIZE; // !MT! This needs to be done with shifts on PSX 00158 z = (long)(Obj->body.Centre.Pos.v[Z] + 32768 - zOff) / OBJ_UNIT_SIZE; // !MT! So OBJ_UNIT_SIZE would need to be a power of 2 00159 if (x < 0) continue; // Bounds check x & z 00160 if (z < 0) continue; 00161 if (x > (OBJ_GRID_WIDTH - 1)) continue; 00162 if (z > (OBJ_GRID_WIDTH - 1)) continue; 00163 if ((Obj->flag.IsInGrid) && (x == Obj->GridX[Grid]) 00164 && (z == Obj->GridZ[Grid])) continue; 00165 00166 if (ObjGrid[Grid][x + (z * OBJ_GRID_WIDTH)].ObjHead) 00167 { 00168 TempObj = ObjGrid[Grid][x + (z * OBJ_GRID_WIDTH)].ObjHead; 00169 ObjGrid[Grid][x + (z * OBJ_GRID_WIDTH)].ObjHead = Obj; 00170 Obj->GridNext[Grid] = TempObj; 00171 Obj->GridPrev[Grid] = NULL; 00172 TempObj->GridPrev[Grid] = Obj; 00173 } 00174 else 00175 { 00176 ObjGrid[Grid][x + (z * OBJ_GRID_WIDTH)].ObjHead = Obj; 00177 Obj->GridPrev[Grid] = NULL; 00178 Obj->GridNext[Grid] = NULL; 00179 } 00180 Obj->GridX[Grid] = (unsigned short)x; // Update current grid location 00181 Obj->GridZ[Grid] = (unsigned short)z; 00182 Obj->flag.IsInGrid = 1; // Mark object as being in grid 00183 } 00184 } 00185 } 00186 } 00187 00188 //-------------------------------------------------------------------------------------------------------------------------- 00189 00190 void GRD_RemoveObject(OBJECT *Obj) 00191 { 00192 #if 0 00193 long ii; 00194 long Offset; 00195 00196 Assert((bool)Obj->flag.IsInGrid); 00197 00198 for (ii = 0; ii < MAX_GRIDS; ii++) 00199 { 00200 Offset = Obj->GridX[ii] + (Obj->GridZ[ii] * OBJ_GRID_WIDTH); 00201 if (ObjGrid[ii][Offset].ObjHead) 00202 { // Remove object from this list 00203 if (Obj->GridPrev[ii] == NULL) 00204 { // Object is at head of list 00205 if (Obj->GridNext[ii] == NULL) 00206 { // Object is only one in list 00207 ObjGrid[ii][Offset].ObjHead = NULL; 00208 } 00209 else 00210 { 00211 Obj->GridNext[ii]->GridPrev[ii] = NULL; 00212 ObjGrid[ii][Offset].ObjHead = Obj->GridNext[ii]; 00213 } 00214 } 00215 else 00216 { // Object is mid-list 00217 Obj->GridPrev[ii]->GridNext[ii] = Obj->GridNext[ii]; 00218 if (Obj->GridNext[ii] != NULL) 00219 { 00220 Obj->GridNext[ii]->GridPrev[ii] = Obj->GridPrev[ii]; 00221 } 00222 } 00223 } 00224 } 00225 Obj->flag.IsInGrid = 0; // Mark object as not in grid yet 00226 #endif 00227 } 00228 00229 //-------------------------------------------------------------------------------------------------------------------------- 00230 00231 // 00232 // GRD_ResetObjPairs 00233 // 00234 // Resets object pair buffer 00235 // 00236 00237 void GRD_ResetObjPairs(void) 00238 { 00239 memset(s_ObjPair, 0, MAX_OBJECTS * MAX_OBJECTS); 00240 } 00241 00242 //-------------------------------------------------------------------------------------------------------------------------- 00243 00244 long GRD_ObjectPair(OBJECT *Obj1, OBJECT *Obj2) 00245 { 00246 long ii, jj; 00247 00248 ii = Obj1->ObjID; 00249 jj = Obj2->ObjID; 00250 00251 if (s_ObjPair[ii + (jj * MAX_OBJECTS)]) 00252 { 00253 return(TRUE); 00254 } 00255 else 00256 { 00257 s_ObjPair[ii + (jj * MAX_OBJECTS)] = (char)0xFF; 00258 return(FALSE); 00259 } 00260 } 00261 00262 //-------------------------------------------------------------------------------------------------------------------------- 00263 00264 // 00265 // GRD_GridNodes 00266 // 00267 // Builds grid lists of nodes. 00268 // There are 3 cases we need to test WRT each node: 00269 // 00270 // 1. Is one of the node vertices within a grid square 00271 // 2. Does the span between the two node vertices intersect a grid square 00272 // 3. Does any part of the grid square intersect with a polygon built from the two node vertices and forward node vertices 00273 // 00274 00275 void GRD_GridNodes(AINODE *Src, long Num) 00276 { 00277 /* long ii; 00278 long Include; 00279 REAL xUnit, zUnit; 00280 REAL x0, z0, x1, z1; 00281 long xCnt, zCnt, nodeCnt; 00282 long xShift, zShift; 00283 long xOff, zOff; 00284 long Grid; 00285 AINODE *Node; 00286 AINODE *TempNode; 00287 00288 for (zShift = 0; zShift < MAX_SHIFTS; zShift++) 00289 { 00290 zOff = zShift * NODE_SHIFT_OFFSET; 00291 for (xShift = 0; xShift < MAX_SHIFTS; xShift++) 00292 { 00293 xOff = xShift * NODE_SHIFT_OFFSET; 00294 Grid = xShift + (zShift * MAX_SHIFTS); 00295 for (zCnt = 0; zCnt < NODE_GRID_WIDTH; zCnt++) 00296 { 00297 zUnit = (REAL)(zCnt * NODE_UNIT_SIZE) - 32768 + zOff; 00298 for (xCnt = 0; xCnt < NODE_GRID_WIDTH; xCnt++) 00299 { 00300 xUnit = (REAL)(xCnt * NODE_UNIT_SIZE) - 32768 + xOff; 00301 for (nodeCnt = 0, Node = Src; nodeCnt < Num; nodeCnt++, Node++) 00302 { 00303 Include = FALSE; 00304 00305 // Check if either node vertex is inside this grid square 00306 x0 = Node->Node[0].Pos.v[X]; 00307 z0 = Node->Node[0].Pos.v[Z]; 00308 x1 = Node->Node[1].Pos.v[X]; 00309 z1 = Node->Node[1].Pos.v[Z]; 00310 if ((x0 >= xUnit) && (x0 < (xUnit + NODE_UNIT_SIZE)) && (z0 >= zUnit) && (z0 < (zUnit + NODE_UNIT_SIZE))) Include = TRUE; 00311 if ((x1 >= xUnit) && (x1 < (xUnit + NODE_UNIT_SIZE)) && (z1 >= zUnit) && (z1 < (zUnit + NODE_UNIT_SIZE))) Include = TRUE; 00312 00313 if(!Include) 00314 { 00315 // Check for node/grid line intersections 00316 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit + NODE_GRID_WIDTH, zUnit)) { Include = TRUE; } 00317 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit + NODE_GRID_WIDTH, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00318 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00319 if (s_LineIntersect(x0, z0, x1, z1, xUnit + NODE_GRID_WIDTH, zUnit, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00320 00321 for (ii = 0; ii < MAX_AINODE_LINKS; ii++) 00322 { 00323 if (!Node->Next[ii]) continue; 00324 if(!Include) 00325 { 00326 x0 = Node->Node[0].Pos.v[X]; 00327 z0 = Node->Node[0].Pos.v[Z]; 00328 x1 = Node->Next[ii]->Node[1].Pos.v[X]; 00329 z1 = Node->Next[ii]->Node[1].Pos.v[Z]; 00330 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit + NODE_GRID_WIDTH, zUnit)) { Include = TRUE; } 00331 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit + NODE_GRID_WIDTH, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00332 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00333 if (s_LineIntersect(x0, z0, x1, z1, xUnit + NODE_GRID_WIDTH, zUnit, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00334 } 00335 if(!Include) 00336 { 00337 x0 = Node->Next[ii]->Node[0].Pos.v[X]; 00338 z0 = Node->Next[ii]->Node[0].Pos.v[Z]; 00339 x1 = Node->Next[ii]->Node[1].Pos.v[X]; 00340 z1 = Node->Next[ii]->Node[1].Pos.v[Z]; 00341 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit + NODE_GRID_WIDTH, zUnit)) { Include = TRUE; } 00342 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit + NODE_GRID_WIDTH, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00343 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00344 if (s_LineIntersect(x0, z0, x1, z1, xUnit + NODE_GRID_WIDTH, zUnit, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00345 } 00346 if(!Include) 00347 { 00348 x0 = Node->Next[ii]->Node[1].Pos.v[X]; 00349 z0 = Node->Next[ii]->Node[1].Pos.v[Z]; 00350 x1 = Node->Node[1].Pos.v[X]; 00351 z1 = Node->Node[1].Pos.v[Z]; 00352 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit + NODE_GRID_WIDTH, zUnit)) { Include = TRUE; } 00353 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit + NODE_GRID_WIDTH, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00354 if (s_LineIntersect(x0, z0, x1, z1, xUnit, zUnit, xUnit, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00355 if (s_LineIntersect(x0, z0, x1, z1, xUnit + NODE_GRID_WIDTH, zUnit, xUnit + NODE_GRID_WIDTH, zUnit + NODE_GRID_WIDTH)) { Include = TRUE; } 00356 } 00357 } 00358 } 00359 00360 if(!Include) 00361 { 00362 for (ii = 0; ii < MAX_AINODE_LINKS; ii++) 00363 { 00364 Include = FALSE; 00365 // This node and each forward node is used to form a polygon, and each grid square vertex is tested against 00366 // it to see if the two intersect - if they do then the nodes are added. 00367 if (!Node->Next[ii]) continue; 00368 if (s_PointInNodePoly(xUnit, zUnit, Node, ii)) 00369 { 00370 Include = TRUE; 00371 break; 00372 } 00373 if (s_PointInNodePoly(xUnit + NODE_UNIT_SIZE, zUnit, Node, ii)) 00374 { 00375 Include = TRUE; 00376 break; 00377 } 00378 if (s_PointInNodePoly(xUnit, zUnit + NODE_UNIT_SIZE, Node, ii)) 00379 { 00380 Include = TRUE; 00381 break; 00382 } 00383 if (s_PointInNodePoly(xUnit + NODE_UNIT_SIZE, zUnit + NODE_UNIT_SIZE, Node, ii)) 00384 { 00385 Include = TRUE; 00386 break; 00387 } 00388 } 00389 } 00390 00391 if (Include) 00392 { 00393 if (NodeGrid[Grid][xCnt + (zCnt * NODE_GRID_WIDTH)].NodeHead) 00394 { 00395 for (TempNode = NodeGrid[Grid][xCnt + (zCnt * NODE_GRID_WIDTH)].NodeHead; TempNode; TempNode = TempNode->GridNext[Grid]) 00396 { 00397 if (TempNode == Node) 00398 { 00399 Include = FALSE; 00400 } 00401 } 00402 } 00403 00404 if (Include) 00405 { 00406 if (NodeGrid[Grid][xCnt + (zCnt * NODE_GRID_WIDTH)].NodeHead) 00407 { 00408 TempNode = NodeGrid[Grid][xCnt + (zCnt * NODE_GRID_WIDTH)].NodeHead; 00409 NodeGrid[Grid][xCnt + (zCnt * NODE_GRID_WIDTH)].NodeHead = Node; 00410 Node->GridNext[Grid] = TempNode; 00411 Node->GridPrev[Grid] = NULL; 00412 TempNode->GridPrev[Grid] = Node; 00413 } 00414 else 00415 { 00416 NodeGrid[Grid][xCnt + (zCnt * NODE_GRID_WIDTH)].NodeHead = Node; 00417 Node->GridPrev[Grid] = NULL; 00418 Node->GridNext[Grid] = NULL; 00419 } 00420 } 00421 } 00422 } 00423 } 00424 } 00425 } 00426 }*/ 00427 } 00428 00429 //-------------------------------------------------------------------------------------------------------------------------- 00430 00431 // s_LineIntersect 00432 // 00433 // Check if two lines (x0,z0)->(x1,z1) and (x2,z2)->(x3,z3) intersect 00434 // 00435 // (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) 00436 // r = ----------------------------- (eqn 1) 00437 // (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) 00438 // 00439 // (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) 00440 // s = ----------------------------- (eqn 2) 00441 // (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) 00442 // 00443 // If 0<=r<=1 & 0<=s<=1, intersection exists 00444 00445 00446 long s_LineIntersect(REAL x0, REAL z0, REAL x1, REAL z1, REAL x2, REAL z2, REAL x3, REAL z3) 00447 { 00448 REAL ieq1, ieq2; 00449 REAL ieqdiv; 00450 00451 ieqdiv = ((x1 - x0) * (z3 - z2)) - ((z1 - z0) * (x3 - x2)); 00452 ieq1 = (((z0 - z2) * (x3 - x2)) - ((x0 - x2) * (z3 - z2))) / ieqdiv; 00453 ieq2 = (((z0 - z2) * (x1 - x0)) - ((x0 - x2) * (z1 - z0))) / ieqdiv; 00454 00455 if (ieq1 < 0) return (FALSE); 00456 if (ieq1 > 1) return (FALSE); 00457 if (ieq2 < 0) return (FALSE); 00458 if (ieq2 > 1) return (FALSE); 00459 return(TRUE); 00460 } 00461 00462 //-------------------------------------------------------------------------------------------------------------------------- 00463 00464 // 00465 // s_PointLine 00466 // 00467 // Determines which 'side' of a vector the specified point resides 00468 // 00469 // result > 0 point is to the left of vector 00470 // result < 0 point is to the right of vector 00471 // result = 0 point is on vector 00472 // 00473 00474 static REAL s_PointLine(REAL x, REAL y, REAL x0, REAL y0, REAL x1, REAL y1) 00475 { 00476 REAL result; 00477 00478 result = ((y - y0) * (x1 - x0)) - ((x - x0) * (y1 - y0)); 00479 00480 return(result); 00481 } 00482 00483 //-------------------------------------------------------------------------------------------------------------------------- 00484 00485 // 00486 // s_PointInNodePoly 00487 // 00488 // Determines if the specified point resides within a polygon built forwards from the specified node to the forward node 00489 // specified by Path 00490 // 00491 // Returns TRUE if point is within poly, FALSE otherwise. 00492 // 00493 00494 static long s_PointInNodePoly(REAL x, REAL y, AINODE *Node, long Path) 00495 { 00496 // Check first clockwise edge 00497 if (s_PointLine(x, y, 00498 Node->Node[1].Pos.v[X], Node->Node[1].Pos.v[Z], 00499 Node->Next[Path]->Node[1].Pos.v[X], Node->Next[Path]->Node[1].Pos.v[Z]) > 0) return(FALSE); 00500 00501 // Check second clockwise edge 00502 if (s_PointLine(x, y, 00503 Node->Next[Path]->Node[1].Pos.v[X], Node->Next[Path]->Node[1].Pos.v[Z], 00504 Node->Next[Path]->Node[0].Pos.v[X], Node->Next[Path]->Node[0].Pos.v[Z]) > 0) return(FALSE); 00505 00506 // Check third clockwise edge 00507 if (s_PointLine(x, y, 00508 Node->Next[Path]->Node[0].Pos.v[X], Node->Next[Path]->Node[0].Pos.v[Z], 00509 Node->Node[0].Pos.v[X], Node->Node[0].Pos.v[Z]) > 0) return(FALSE); 00510 00511 // Check fouth clockwise edge 00512 if (s_PointLine(x, y, 00513 Node->Node[0].Pos.v[X], Node->Node[0].Pos.v[Z], 00514 Node->Node[1].Pos.v[X], Node->Node[1].Pos.v[Z]) > 0) return(FALSE); 00515 00516 return(TRUE); 00517 } 00518 00519 //--------------------------------------------------------------------------------------------------------------------------