//sub_80026DD4 entry *findZone(entry *zone, cpoint *location) { unsigned char *zoneHeader = zone->itemData[0]; //subtracting one; we exclude itself unsigned long neighborCount = getWord(zoneHeader, 0x210, true) - 1; entry *found = 0; //work backwards thru specified zone neighbors do { unsigned long neighborEID = getWord(zoneHeader, 0x214+(neighborCount*4), true); entry *neighbor = crashSystemPage(neighborEID); unsigned char *neighbDimItem = neighbor->itemData[1]; signed long neighbW = CTCVC(getWord(neighbDimItem, 0xC, true)); signed long neighbH = CTCVC(getWord(neighbDimItem, 0x10, true)); signed long neighbD = CTCVC(getWord(neighbDimItem, 0x14, true)); signed long neighbX1 = CTCVC(getWord(neighbDimItem, 0, true)); signed long neighbY1 = CTCVC(getWord(neighbDimItem, 4, true)); signed long neighbZ1 = CTCVC(getWord(neighbDimItem, 8, true)); signed long neighbX2 = neighbX1 + neighbW; signed long neighbY2 = neighbY1 + neighbH; signed long neighbZ2 = neighbZ1 + neighbD; signed long locX = location->X; signed long locY = location->Y; signed long locZ = location->Z; //the conditions pass/loop ends when the zone is found that //the point lies within if (locX > neighbX1 && locY > neighbY1 && locZ > neighbZ1 &&locX < neighbX2 && locY < neighbY2 && locZ < neighbZ2) { found = neighbor; break; } } while (neighborCount-- > 0); if (found) return found; //if a neighbor was not found that contains the point else { //then see if it can be found in the current zone's neighbors if (zone != currentZone) { zoneHeader = currentZone->itemData[0]; //subtracting one; we exclude itself neighborCount = getWord(zoneHeader, 0x210, true) - 1; do { unsigned long neighborEID = getWord(zoneHeader, 0x214+(neighborCount*4), true); //entry *neighbor = EID_PROCESS(neighborEID); entry *neighbor = crashSystemPage(neighborEID); unsigned char *neighbDimItem = neighbor->itemData[1]; signed long neighbW = CTCVC(getWord(neighbDimItem, 0xC, true)); signed long neighbH = CTCVC(getWord(neighbDimItem, 0x10, true)); signed long neighbD = CTCVC(getWord(neighbDimItem, 0x14, true)); signed long neighbX1 = CTCVC(getWord(neighbDimItem, 0, true)); signed long neighbY1 = CTCVC(getWord(neighbDimItem, 4, true)); signed long neighbZ1 = CTCVC(getWord(neighbDimItem, 8, true)); signed long neighbX2 = neighbX1 + neighbW; signed long neighbY2 = neighbY1 + neighbH; signed long neighbZ2 = neighbZ1 + neighbD; signed long locX = location->X; signed long locY = location->Y; signed long locZ = location->Z; //the conditions pass/loop ends when the zone is found that //the point lies within if (locX > neighbX1 && locY > neighbY1 && locZ > neighbZ1 &&locX < neighbX2 && locY < neighbY2 && locZ < neighbZ2) { found = neighbor; break; } } while (neighborCount-- > 0); if (found) { return found; } } } return (entry*)0xFFFFFFE9; }
void findNode(unsigned char *zoneCollisions, unsigned short node, cspace zoneSpace, cvector *vectA, cvector *vectB, unsigned short level) { // we want to search the given 'node's -child- nodes unsigned short *childNodes; // if the given node a non-leaf node (has children) // or the given node is an empty node // (i.e. refers to an non-occupied, non-solid, empty region of space) if ((node & 1) == 0) { // if the node is a non-leaf node if (node & 0xFFFF) childNodes = (unsigned short*) &zoneCollisions[node & 0xFFFF]; //it can be subdivided into its children else childNodes = 0; //else it can be subdivided no further } // if the given node is a non-leaf node if (((node & 1) == 0) && (node & 0xFFFF)) { // we'd like to determine the dimensions of its child nodes cspace childSpace; memset(&childSpace, 0, sizeof(cspace)); // firstly, we'd like to determine the width, height, and depth // get the max levels/depths (number of recursive subdivisions) of the tree // for each dimension unsigned short depthW = getHword(zoneCollisions, 0x1E, true); unsigned short depthH = getHword(zoneCollisions, 0x20, true); unsigned short depthD = getHword(zoneCollisions, 0x22, true); // if the current level does not exceed the maximum level for the X dimension if (level < depthW) // then the node's corresponding space (zoneSpace) childSpace.W = zoneSpace.W / 2; // can be subdivided (halved) further by width.. else // otherwise, the node's space childSpace.W = zoneSpace.W; // can not be subdivided further by width // if the current level does not exceed the maximum level for the Y dimension if (level < depthH) // then the node's corresponding space (zoneSpace) childSpace.H = zoneSpace.H / 2; // can also be subdivided (halved) further by height.. else // otherwise, the node's space childSpace.H = zoneSpace.H; // can not be subdivided further by height // if the current level does not exceed the maximum level for the Z dimension if (level < depthD) // then the node's corresponding space (zoneSpace) childSpace.D = zoneSpace.D / 2; // can also be subdivided (halved) further by depth.. else // otherwise, the node's space childSpace.D = zoneSpace.D; // can not be subdivided further by depth // then we determine the (location) x, y, and z of each of its child nodes unsigned long countX = 0; unsigned long countY = 0; unsigned long countZ = 0; unsigned short child = 0; do { if ((depthW == 0) && (countX > 0)) break; do { if ((depthH == 0) && (countY > 0)) break; do { if ((depthD == 0) && (countZ > 0)) break; childSpace.X = zoneSpace.X; if (countX != 0) childSpace.X += childSpace.W; childSpace.Y = zoneSpace.Y; if (countY != 0) childSpace.Y += childSpace.H; childSpace.Z = zoneSpace.Z; if (countZ != 0) childSpace.Z += childSpace.D; // if vectA lies within the current child node/subdivision if ((childSpace.X < vectA->X) && (childSpace.Y < vectA->Y) && (childSpace.Z < vectA->Z) && ((childSpace.X + childSpace.W) > vectA->X) && ((childSpace.Y + childSpace.H) > vectA->Y) && ((childSpace.Z + childSpace.D) > vectA->Z)) { unsigned long childNode = childNodes[child]; findNode(zoneCollisions, childNode, childSpace, vectA, vectB, level+1); } child++; } while (++countZ < 2); } while (++countY < 2); } while (++countX < 2); return; //retval; } // else the given node is an empty node // (i.e. refers to an non-occupied, non-solid, empty region of space) // we have to interpolate the ray one unit further than the closest face // that it intersects to get the location of the next potentially solid // node at its direction else if ((node & 1) == 0) { signed long xval, yval, zval; // let R be a ray starting at origin A (vectA/pointA) // and pointing in direction B (vectB) // R = A + Bt // (we can find each point on the ray R for each // corresponding value of t) // we also know that, at this point, the origin point A is // within the box/space of the containing node // we want to find which of the containing node's faces // that this ray will -first- intersect with (considering // this is collision testing, we typically desire that // the object on this ray path is stopped at the first // intersection pt, such that it could not travel any // further to reach those inevitable points of // intersection with faces further away) // then we can move the object at origin pt.A (vectA) // in the given direction B (vectB) exactly up to the // closest face // since we know that the origin point A is within the box // space of the containing node, then based on the ray's // direction B, right off the bat we can eliminate 3 of the // 6 node/cube faces: those aligned with the respective x, // y, and z axes that are 'behind' the origin pt A, since // these could not possibly be reached at the ray's direction // thus we consider only the offsets (locations) of the // 3 faces that the ray point towards, each in their // separate respective axis if (vectB->X <= 0) //if negative in the x direction xval = zoneSpace.X; //we may hit the left of the node else //else if positive xval = zoneSpace.X + zoneSpace.W; //we may hit the right of the node if (vectB->Y <= 0) //if negative in the y direction yval = zoneSpace.Y; //we may hit the top of the node else //else if positive yval = zoneSpace.Y + zoneSpace.H; //we may hit the bottom of the node if (vectB->Z <= 0) //if negative in the z direction zval = zoneSpace.Z; //we may hit the back of the node else //else if positive zval = zoneSpace.Z + zoneSpace.D; //we may hit the front of the node // note that, given the offsets in the respective axes of // each face, we have the respective equations of their // planes: // // X = xval // Y = yval // Z = zval // // then we can solve for t for where each // component of the ray intersects the respective // axis aligned plane: // // R = A + Bt = // Rx = Ax + Bxt // Ry = Ay + Byt // Rz = Az + Bzt // // (we want to find t when the component R* is at // the location/offset of the plane/face in axis '*'; // that is, what is t for when the ray intersects the // face/plane at for each respective component) // // xval = Ax + Bxt // Bxt = xval - Ax // tX = (xval - Ax)/Bx // // similarly for y and z // tY = (yval - Ay)/By // tZ = (zval - Az)/Bz // // since for -larger- t, we get a *point* -further- along // the rays path as a result, the -smallest- t from these 3 // calculations determines the -closest- *point* along the // rays path that is also a point on the respective -closest- // face; thus we determine the min: unsigned long min = 0x7FFFFFFF; if (vectB->X != 0) { long tX = CTCVC(xval - vectA->X)/vectB->X; if (tX < min) min = tX; } if (vectB->Y != 0) { long tY = CTCVC(yval - vectA->Y)/vectB->Y; if (tY < min) min = tY; } if (vectB->Z != 0) { long tZ = CTCVC(zval - vectA->Z)/vectB->Z; if (tZ < min) min = tZ; } // after the following line, min will refer to one point // -further- than the point of the closest plane/edge of // the node (this is to move vectA into the realm of an // adjacent, possibly solid node, at the specified dir. of // vectB) min += CTCVC(1); // now we move the object at given pt A (vectA) in // direction B (vectB), i.e. along ray R, until it // reaches one point further than the point on the closest // face (plane) at t = min, vectA->X += CTGVC(min * vectB->X); vectA->Y += CTGVC(min * vectB->Y); vectA->Z += CTGVC(min * vectB->Z); return; } // else the node is a leaf node, so we use its value else { // previously, we were within a non-solid node and after // travelling in the direction of the ray, we crossed over the // closest face; the crossing took place such that we are now // one unit outside of/away from that node and within the // current, solid (adjacent) node. since we know we are within // a solid node, now we reverse trace, or trace the ray back // in the opposite direction, to see which of the faces that // was crossed (but now in terms of this node). // by vector subtraction: // // A - B = C // // we get point C, a point that approximates our previous // position within the non-solid node such that we can then // find the dist between that point and -now- the faces of the // solid cube we are within // } }