int readChunk(chunk &outChunk, unsigned char *chunkData) { outChunk.data = chunkData; outChunk.magic = getHword(chunkData, CHUNK_MAGIC, true); outChunk.type = getHword(chunkData, CHUNK_TYPE, true); outChunk.CID = getWord(chunkData, CHUNK_CID, true); outChunk.entryCount = getWord(chunkData, CHUNK_ENTRYCOUNT, true); outChunk.checksum = getWord(chunkData, CHUNK_CHECKSUM, true); if (outChunk.type == 0) { unsigned long prevOffset = 0; for (unsigned long count = 0; count < outChunk.entryCount; count++) { unsigned long offset = getWord(chunkData, CHUNK_ENTRYOFFSETS+(count*4), true); outChunk.entryData[count] = &chunkData[offset]; outChunk.entrySize[count] = offset - prevOffset; readEntry(outChunk.entries[count], outChunk.entryData[count]); prevOffset = offset; } } return outChunk.type; }
//sub_800260AC void updateLevelMisc(unsigned char *headerMisc, unsigned long flags) { //*(0x57970) = *(0x34520) var_57964 = var_57968 & 0xFFFFFF00; var_5796C = (getHword(headerMisc, 0x2C, true) << 8) | getHword(headerMisc, 0x2E, true); unsigned long zoneFlags = getWord(headerMisc, 0x1C, true); globals[0x1E] = zoneFlags; if (flags & 4) flagUnknown = true; }
void readCrashZoneEntity(unsigned char *zoneEntity, crash_zone_entity &crashZoneEntity) { crashZoneEntity.reserved = getWord(zoneEntity, 0, true); crashZoneEntity.initModeFlags = getHword(zoneEntity, 0x4, true); crashZoneEntity.group = getHword(zoneEntity, 0x6, true); crashZoneEntity.ID = getHword(zoneEntity, 0x8, true); crashZoneEntity.pathCount = getHword(zoneEntity, 0xA, true); crashZoneEntity.initFlagsA = getHword(zoneEntity, 0xC, true); crashZoneEntity.initFlagsB = getHword(zoneEntity, 0xE, true); crashZoneEntity.initFlagsC = getHword(zoneEntity, 0x10, true); crashZoneEntity.type = zoneEntity[0x12]; crashZoneEntity.subtype = zoneEntity[0x13]; crashZoneEntity.camPath = (crash_zone_entity::objectCamPathNode*)malloc(crashZoneEntity.pathCount * sizeof(crash_zone_entity::objectCamPathNode)); for (int lp=0; lp<crashZoneEntity.pathCount; lp++) { crashZoneEntity.camPath[lp].camX = getHword(zoneEntity, 0x14+(lp*6), true); crashZoneEntity.camPath[lp].camY = getHword(zoneEntity, 0x16+(lp*6), true); crashZoneEntity.camPath[lp].camZ = getHword(zoneEntity, 0x18+(lp*6), true); } }
void readCrashZoneSection(unsigned char *zoneSection, crash_zone_section &crashZoneSection) { crashZoneSection.slst = getWord(zoneSection, 0, true); crashZoneSection.parentZone = getWord(zoneSection, 4, true); crashZoneSection.neighborSectionCount = getWord(zoneSection, 8, true); for (int lp=0; lp<4; lp++) { crash_zone_section::neighborSectionDescriptor *neighborSection = &crashZoneSection.neighborSection[lp]; neighborSection->relation = zoneSection[0xC+(lp*4)]; neighborSection->neighborZoneIndex = zoneSection[0xD+(lp*4)]; neighborSection->sectionIndex = zoneSection[0xE +(lp*4)]; neighborSection->goal = zoneSection[0xF+(lp*4)]; } crashZoneSection.entranceIndex = zoneSection[0x1C]; crashZoneSection.exitIndex = zoneSection[0x1D]; crashZoneSection.length = getHword(zoneSection, 0x1E, true); crashZoneSection.camMode = getHword(zoneSection, 0x20, true); crashZoneSection.avgNodeDist = getHword(zoneSection, 0x22, true); crashZoneSection.camZoom = getHword(zoneSection, 0x24, true); crashZoneSection.unknownA = getHword(zoneSection, 0x26, true); crashZoneSection.unknownB = getHword(zoneSection, 0x28, true); crashZoneSection.unknownC = getHword(zoneSection, 0x2A, true); crashZoneSection.pathDirectionX = getHword(zoneSection, 0x2C, true); crashZoneSection.pathDirectionY = getHword(zoneSection, 0x2E, true); crashZoneSection.pathDirectionZ = getHword(zoneSection, 0x30, true); crashZoneSection.camPath = (crash_zone_section::sectionCamPathNode*)malloc(crashZoneSection.length * sizeof(crash_zone_section::sectionCamPathNode)); for (int lp=0; lp<crashZoneSection.length; lp++) { crashZoneSection.camPath[lp].camX = getHword(zoneSection, 0x32+(lp*12), true); crashZoneSection.camPath[lp].camY = getHword(zoneSection, 0x34+(lp*12), true); crashZoneSection.camPath[lp].camZ = getHword(zoneSection, 0x36+(lp*12), true); crashZoneSection.camPath[lp].camRotX = getHword(zoneSection, 0x38+(lp*12), true); crashZoneSection.camPath[lp].camRotY = getHword(zoneSection, 0x40+(lp*12), true); crashZoneSection.camPath[lp].camRotZ = getHword(zoneSection, 0x42+(lp*12), true); } }
void readCrashZoneHeader(entry *zone, crash_zone_header &crashZoneHeader) { unsigned char *zoneHeader = zone->itemData[0]; crashZoneHeader.worldCount = getWord(zoneHeader, 0, true); for (int lp=0; lp<8; lp++) crashZoneHeader.world[lp].world = getWord(zoneHeader, 4+(lp*0x40), true); crashZoneHeader.headerColCount = getWord(zoneHeader, 0x204, true); crashZoneHeader.sectionCount = getWord(zoneHeader, 0x208, true); crashZoneHeader.entityCount = getWord(zoneHeader, 0x20C, true); crashZoneHeader.neighborCount = getWord(zoneHeader, 0x210, true); for (int lp=0; lp<8; lp++) crashZoneHeader.neighbor[lp] = getWord(zoneHeader, 0x214+(lp*4), true); crashZoneHeader.tpageCount = getWord(zoneHeader, 0x234, true); crashZoneHeader.tchunkCount = getWord(zoneHeader, 0x238, true); for (int lp=0; lp<8; lp++) crashZoneHeader.tpage[lp] = getWord(zoneHeader, 0x23C+(lp*4), true); for (int lp=0; lp<32; lp++) crashZoneHeader.tchunk[lp] = getWord(zoneHeader, 0x25C+(lp*4), true); crashZoneHeader.gameFlags = getWord(zoneHeader, 0x2DC, true); crashZoneHeader.vramFillHeight = getWord(zoneHeader, 0x2E0, true); crashZoneHeader.unknownA = getWord(zoneHeader, 0x2E4, true); crashZoneHeader.visibilityDepth= getWord(zoneHeader, 0x2E8, true); crashZoneHeader.unknownB = getWord(zoneHeader, 0x2EC, true); crashZoneHeader.unknownC = getWord(zoneHeader, 0x2F0, true); crashZoneHeader.unknownD = getWord(zoneHeader, 0x2F4, true); crashZoneHeader.unknownE = getWord(zoneHeader, 0x2F8, true); crashZoneHeader.flags = getWord(zoneHeader, 0x2FC, true); crashZoneHeader.deathY = getWord(zoneHeader, 0x300, true); crashZoneHeader.unknownF = getWord(zoneHeader, 0x304, true); crashZoneHeader.unknownG = getWord(zoneHeader, 0x308, true); crashZoneHeader.unknownH = getWord(zoneHeader, 0x30C, true); crashZoneHeader.vramFillR = zoneHeader[0x310]; crashZoneHeader.vramFillG = zoneHeader[0x311]; crashZoneHeader.vramFillB = zoneHeader[0x312]; crashZoneHeader.unusedA = zoneHeader[0x313]; crashZoneHeader.farColorR = zoneHeader[0x314]; crashZoneHeader.farColorG = zoneHeader[0x315]; crashZoneHeader.farColorB = zoneHeader[0x316]; crashZoneHeader.unusedB = zoneHeader[0x317]; for (int lp=0; lp<9; lp++) crashZoneHeader.objectLightMatrix[lp] = getHword(zoneHeader, 0x318+(lp*2), true); for (int lp=0; lp<3; lp++) crashZoneHeader.objectBackColor[lp] = getHword(zoneHeader, 0x32A+(lp*2), true); for (int lp=0; lp<9; lp++) crashZoneHeader.objectColorMatrix[lp] = getHword(zoneHeader, 0x330+(lp*2), true); for (int lp=0; lp<3; lp++) crashZoneHeader.objectBackColorIntensity[lp] = getHword(zoneHeader, 0x342+(lp*2), true); for (int lp=0; lp<9; lp++) crashZoneHeader.playerLightMatrix[lp] = getHword(zoneHeader, 0x348+(lp*2), true); for (int lp=0; lp<3; lp++) crashZoneHeader.playerBackColor[lp] = getHword(zoneHeader, 0x35A+(lp*2), true); for (int lp=0; lp<9; lp++) crashZoneHeader.playerColorMatrix[lp] = getHword(zoneHeader, 0x360+(lp*2), true); for (int lp=0; lp<3; lp++) crashZoneHeader.playerBackColorIntensity[lp] = getHword(zoneHeader, 0x372+(lp*2), true); }
//sub_80025A60(zone, section, progressV, flags) void updateLevel(entry *zone, unsigned char *section, signed long progressV, unsigned long flags) { //var_78 = zone //var_70 = section //var_68 = progressV //var_60 = flag if (!zone || !section) { return; } unsigned short sectionDepth = getHword(section, 0x1E, true); unsigned short sectionDepthV = sectionDepth << 8; //restrict the progress value from the input if it does not lie in the section if (progressV < (sectionDepthV - 1)) { if (progressV < 0) progressV = 0; } else progressV = (sectionDepthV - 1); unsigned char *zoneHeader = zone->itemData[0]; unsigned long zoneModelCount = getWord(zoneHeader, 0, true); unsigned long progress = progressV >> 8; unsigned long currentProgress = currentProgressV >> 8; //if the zone is not a blank area and contains models if (zoneModelCount != 0) { if (zone == currentZone && section == currentSection && progress == currentProgress) { //wouldn't they be the same though at this point? currentProgressV = progressV; } //else there is a new zone, new zone section, or change in section progress else { /* we don't care about the display lists quite yet although their format has been cracked... unsigned long slstEID = getWord(section, 0, true); changeProgress = abs((progressV - curProgressV) >> 8); if (section == curSection && (progress >= changeProgress && (sectionDepth - (progress + 1)) >= changeProgress)) { startItem = curProgress; } else { swap(gp[0x2C0], gp[0x304]); sectionCenter = sectionDepth / 2; if (progress < sectionCenter) { itemFirst = slst[0x10]; gp[0x2BC] = sub_80029B0C(itemFirst, gp[0x2BC], gp[0x304], 1); startItem = 0; } else { itemLast = slst[0x10 + (sectionDepth*4)]; gp[0x2BC] = sub_80029B0C(itemLast, gp[0x2BC], gp[0x304], 0); startItem = sectionDepth - 1; } } count = progress - startItem; itemIndex = startItem; while (count != 0) { swap(gp[0x2C0], gp[0x304]); if (count < 0) { itemIndex--; count++; flag = 0; } else //count is > 0 { itemIndex++; count--; flag = 1; } item = slst[0x10 + (itemIndex*4)]; gp[0x2BC] = sub_80029B0C(itemLast, gp[0x2BC], gp[0x304], flag); } sub_80015458(section, 1); */ } } //if the zone has no wgeo models OR there has been a change in zone, section, or progress if (zoneModelCount == 0 || zone != currentZone || section != currentSection || progress != currentProgress) { if (currentZone != zone) { bool processPages = true; //*(0x61998) = 0; globals[0x43] = 0; //set by camera routine/camera mode //if (*(0x618D0) == 0x600) // processPages = !(flags & 2); if (currentZone) { oldZoneHeader = currentZone->itemData[0]; unsigned char *newZoneHeader = zone->itemData[0]; processPages = (flags & 2); unsigned long oldNeighborCount = getWord(oldZoneHeader, 0x210, true); //count of neighboring Zdat entrys? including itself? unsigned long newNeighborCount = getWord(newZoneHeader, 0x210, true); for (int countA = 0; countA < oldNeighborCount; countA++) { //oldNeighborZone = EID_PROCESS(getWord(oldZoneHeader, 0x214+(countA*4), true)); // unsigned long EID = getWord(oldZoneHeader, 0x214 + (countA*4), true); entry *oldNeighborZone = crashSystemPage(EID); bool match = false; for (int countB = 0; countB < newNeighborCount; countB++) { //entry *newNeighborZone = EID_PROCESS(getWord(newZoneHeader, 0x214+(countB*4), true); EID = getWord(newZoneHeader, 0x214 + (countB*4), true); entry *newNeighborZone = crashSystemPage(EID); if (newNeighborZone == oldNeighborZone) { match = true; break; } } if (match) { unsigned char *oldNeighbHeader = oldNeighborZone->itemData[0]; //if zone is loaded then remove it from the system and reset bits unsigned long zoneFlags = getWord(oldNeighbHeader, 0x2DC, true); if (zoneFlags & 1) { //sub_8001D200(oldNeighborZone); //remove it from the system setWord(oldNeighbHeader, 0x2DC, true, zoneFlags & 0xFFFFFFFC); //clear bits 1 & 2 } } } } if ((flags & 1) == 0) { for (int count = 0; count < 0x130; count++) states[count] &= 0xFFFFFFF9; //clear bit 2 & 3 } currentZone = zone; currentSection = section; currentProgressV = progressV; /* can't do any of the following yet; paging system not implemented //texture page entry/chunk array routine (gets set up for load to appropriate slots?) if (section) sub_8001495C(&zoneHeader[0x234], 0); else sub_8001495C(0, 0); //load all zone tpage entries unsigned long texCount = getWord(zoneHeader, 0x234, true); for (int count = 0; count < texCount; count++) { unsigned long texEID = getWord(zoneHeader, 0x23C+(count*4), true); sub_80015118(texEID, 0, 1); } unsigned long CIDCount = getWord(zoneHeader, 0x238, true); for (int count = 0; count < CIDCount; count++) { unsigned long texCID = getWord(zoneHeader, 0x25C, true); sub_80014DD0(texCID, 0, 1, 0x6396347F); } if (processPages != 0) //bit 2 from the flags if set sub_80013748(); //process ALL pages in the CID list */ unsigned long neighborCount = getWord(zoneHeader, 0x210, true); unsigned char *neighborHeader; for (int count = 0; count < neighborCount; count++) { //neighborZone = EID_PROCESS(neighborEID); unsigned long EID = getWord(zoneHeader, 0x214 + (count*4), true); entry *neighborZone = crashSystemPage(EID); neighborHeader = neighborZone->itemData[0]; if ((getWord(neighborHeader, 0x2DC, true) & 1) == 0) //if bit 1 not set { var_61A5C = 0; var_61A64 = 0; var_61A60 = 0x19000; setWord(neighborHeader, 0x2DC, true, getWord(neighborHeader, 0x2DC, true) | 3); //set bits 1 & 2 } if (processPages) setWord(neighborHeader, 0x2DC, true, getWord(neighborHeader, 0x2DC, true) | 4); //set bit 3 else setWord(neighborHeader, 0x2DC, true, getWord(neighborHeader, 0x2DC, true) & 3); //clear bit 3 } //use this function on the last neighbor updateLevelMisc(neighborHeader + 0x2E0, flags); } else { currentZone = zone; currentSection = section; currentProgressV = progressV; } } camRotBefore.X = camera.rot.X; //copy camera X rotation angle value before sub camRotBefore.Y = camera.rot.Y; //copy camera Y rotation angle value before sub camRotBefore.Z = camera.rot.Z; //copy camera Z rotation angle value before sub cameraCalculate(currentSection, -currentProgressV, &camera); //adjust camera for current zone camRotAfter.X = camera.rot.X; //copy camera X rotation angle value after sub camRotAfter.Y = camera.rot.Y; //copy camera Y rotation angle value after sub camRotAfter.Z = camera.rot.Z; //copy camera Z rotation angle value after sub var_5CFC0 = 0; }
void zoneList::occupy(entry *zone) { unsigned char *zoneHeader = zone->itemData[0]; modelCount = getWord(zoneHeader, 0, true); headerColCount = getWord(zoneHeader, 0x204, true); sectionCount = getWord(zoneHeader, 0x208, true); entityCount = getWord(zoneHeader, 0x20C, true); neighborCount = getWord(zoneHeader, 0x210, true); char zoneModelString[8][30]; for (unsigned long lp=0; lp<modelCount; lp++) { unsigned long modelEID = getWord(zoneHeader, 4+(lp*0x40), true); getEIDstring(zoneModelString[lp], modelEID); unsigned long parentCID = nsd->lookupCID(modelEID); if (parentCID != -1) { chunk *parentChunk = nsf->lookupChunk(parentCID); zoneModel[lp] = lookupEntry(modelEID, parentChunk); } else { char temp[6]; getEIDstring(temp, modelEID); sprintf(zoneModelString[lp], "BAD REF: %s", temp); zoneModel[lp] = 0; } } char zoneEntityString[20][10]; for (unsigned long lp=0; lp<entityCount; lp++) { unsigned char *entity = zone->itemData[headerColCount+sectionCount+lp]; unsigned short entityID = getHword(entity, 0x8, true); unsigned char codeIndex = entity[0x12]; unsigned long entityCodeEID = nsd->levelEIDs[codeIndex]; char entityCodeEIDString[6]; getEIDstring(entityCodeEIDString, entityCodeEID); sprintf(zoneEntityString[lp], "%i: %s", entityID, entityCodeEIDString); } char zoneNeighborString[20][10]; for (unsigned long lp=0; lp<neighborCount; lp++) { unsigned long neighborEID = getWord(zoneHeader, 0x214+(lp*4), true); getEIDstring(zoneNeighborString[lp], neighborEID); unsigned long parentCID = nsd->lookupCID(neighborEID); if (parentCID != -1) { chunk *parentChunk = nsf->lookupChunk(parentCID); zoneNeighbor[lp] = lookupEntry(neighborEID, parentChunk); } else { char temp[6]; getEIDstring(temp, neighborEID); sprintf(zoneNeighborString[lp], "BAD REF: %s", temp); zoneNeighbor[lp] = 0; } } char zoneEIDString[6]; getEIDstring(zoneEIDString, zone->EID); char zoneString[20]; sprintf(zoneString, "Zone: %s", zoneEIDString); AddItemToTree(hwnd, zoneString, 1, 1); AddItemToTree(hwnd, "Models", 2, 0); for (unsigned long lp=0; lp<modelCount; lp++) AddItemToTree(hwnd, zoneModelString[lp], 3, (lp << 8) | 3); AddItemToTree(hwnd, "Entities", 2, 0); for (unsigned long lp=0; lp<entityCount; lp++) AddItemToTree(hwnd, zoneEntityString[lp], 3, (lp << 8) | 5); AddItemToTree(hwnd, "Sections", 2, 0); for (unsigned long lp=0; lp<sectionCount; lp++) { char sectionString[20]; sprintf(sectionString, "Section %i", lp); AddItemToTree(hwnd, sectionString, 3, 0); AddItemToTree(hwnd, "Camera", 4, (lp << 8) | (0 << 3) | 4); AddItemToTree(hwnd, "Neighbor Sections", 4, (lp << 8) | (1 << 3) | 4); } AddItemToTree(hwnd, "Neighbor Zones", 2, 0); for (unsigned long lp=0; lp<neighborCount; lp++) { AddItemToTree(hwnd, zoneNeighborString[lp], 3, (lp << 8) | 2); } AddItemToTree(hwnd, "Lighting properties", 2, (1 << 3) | 1); AddItemToTree(hwnd, "Shading/rendering properties", 2, (2 << 3) | 1); AddItemToTree(hwnd, "Collision octree", 2, (3 << 3) | 1); }
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 // } }
void collisionVectors(cvector *vectA, cvector *vectB) { if ((vectB->X == 0) && (vectB->Y == 0) && (vectB->Z == 0)) return; unsigned char *currentZoneHeader = currentZone->itemData[0]; unsigned long retval = 0; do { // number of neighbor zones unsigned long neighborCount = getWord(currentZoneHeader, 0x210, true); // counter/iterator unsigned long count = 0; if (neighborCount > 0) { do { unsigned long neighborEID = getWord(currentZoneHeader, 0x214+(count*4), true); entry *neighborZone = goolSystemPage(neighborEID); unsigned char *neighborCollisions = neighborZone->itemData[1]; // get zone location and dimensions signed long zoneX = getWord(neighborCollisions, 0, true) << 8; signed long zoneY = getWord(neighborCollisions, 4, true) << 8; signed long zoneZ = getWord(neighborCollisions, 8, true) << 8; unsigned long zoneW = getWord(neighborCollisions, 0xC, true) << 8; unsigned long zoneH = getWord(neighborCollisions, 0x10, true) << 8; unsigned long zoneD = getWord(neighborCollisions, 0x14, true) << 8; // if vector A lies within the zone if (vectA->X >= zoneX && vectA->Y >= zoneY && vectA->Z >= zoneZ && vectA->X < (zoneX + zoneW) && vectA->Y < (zoneY + zoneH) && vectA->Z < (zoneZ + zoneD)) { cspace zoneSpace; zoneSpace.xyz1.X = zoneX; zoneSpace.xyz1.Y = zoneY; zoneSpace.xyz1.Z = zoneZ; zoneSpace.xyz2.X = zoneX + zoneW; zoneSpace.xyz2.Y = zoneY + zoneH; zoneSpace.xyz2.Z = zoneZ + zoneD; unsigned short rootNode = getHword(neighborCollisions, 0x1E, true); unsigned short level = 0; retval = findNode(neighborCollisions, rootNode, zoneSpace, vectA, vectB, level); break; } } while (count < neighborCount); if (count == neighborCount) { return; } } } while (!retval); return; }
void model_obj::loadVertices(entry *svtx, int frame, prim_alloc *prims) { unsigned char *buffer = svtx->itemData[frame]; //load the vertices/normals for this frame vertCount = getWord(buffer, 0, true); signed long offsetX = getWord(buffer, 0x8, true); signed long offsetY = getWord(buffer, 0xC, true); signed long offsetZ = getWord(buffer, 0x10, true); //**the game subtracts a default of 128 from the model coordinate offset //(scaling here is also done to shift the sign to the appropriate position) signed short offsetXP = (signed short) ((offsetX - 128) * SCALE_OBJECT); signed short offsetYP = (signed short) ((offsetY - 128) * SCALE_OBJECT); signed short offsetZP = (signed short) ((offsetZ - 128) * SCALE_OBJECT); vertices = prims->allocVertices(vertCount); normals = prims->allocNormals(vertCount); #define SVTX_VERTICES 0x38 for (int lp = 0; lp < vertCount; lp++) { unsigned long bufferOffset = lp * 6; //first grab AAZZYYXXCCBB values from binary model data unsigned long CNXZYX = getWord(buffer, SVTX_VERTICES + bufferOffset, true); unsigned short CNZCNY = getHword(buffer, SVTX_VERTICES + bufferOffset+4, true); //then separate appropriately, performing any additional scaling //like the game does before sending to the GTE unsigned short vertX = ((CNXZYX & 0x000000FF) >> 0) * SCALE_OBJECT; unsigned short vertY = ((CNXZYX & 0x0000FF00) >> 8) * SCALE_OBJECT; unsigned short vertZ = ((CNXZYX & 0x00FF0000) >> 16) * SCALE_OBJECT; signed char CNX = (CNXZYX & 0xFF000000) >> 24; signed char CNY = (CNZCNY & 0x00FF); signed char CNZ = (CNZCNY & 0xFF00) >> 8; //now calculate total vertex position signed short X = offsetXP + vertX; signed short Y = offsetYP + vertY; signed short Z = offsetZP + vertZ; //psx GTE reads these values as fixed point, gl as floats //do the appropriate conversions before storing so gl can interpret correctly vertices[lp].X = ((float)X * 8) / 0x1000; vertices[lp].Y = ((float)Y * 8) / 0x1000; vertices[lp].Z = ((float)Z * 8) / 0x1000; //pre-emptively sets the object to be drawn white if texture information is not found vertices[lp].Rf = 1.0; vertices[lp].Gf = 1.0; vertices[lp].Bf = 1.0; normals[lp].X = (float)CNX / (16); normals[lp].Y = (float)CNY / (16); normals[lp].Z = (float)CNZ / (16); } //load the bound box for this frame signed long boundX1 = getWord(buffer, 0x14, true); signed long boundY1 = getWord(buffer, 0x18, true); signed long boundZ1 = getWord(buffer, 0x1C, true); signed long boundX2 = getWord(buffer, 0x20, true); signed long boundY2 = getWord(buffer, 0x24, true); signed long boundZ2 = getWord(buffer, 0x28, true); bound.P1.X = ((float)boundX1 * 8) / 0x1000; bound.P1.Y = ((float)boundY1 * 8) / 0x1000; bound.P1.Z = ((float)boundZ1 * 8) / 0x1000; bound.P2.X = ((float)boundX2 * 8) / 0x1000; bound.P2.Y = ((float)boundY2 * 8) / 0x1000; bound.P2.Z = ((float)boundZ2 * 8) / 0x1000; }
void model_obj::loadPolygons(entry *tgeo, texture_buffer *texbuf, prim_alloc *prims) { if (tgeo->itemData[0] == 0 || tgeo->itemSize[0] == 0) { return; } if (tgeo->itemData[1] == 0 || tgeo->itemSize[1] == 0) { return; } unsigned char *buffer = tgeo->itemData[0]; unsigned char *texInfoArray = tgeo->itemData[0] + 0x14; //or -are- these actually scale values? //where are these used in the assembly? unsigned long scaleX = getWord(buffer, 0x4, true); unsigned long scaleY = getWord(buffer, 0x8, true); unsigned long scaleZ = getWord(buffer, 0xC, true); polyCount = getWord(buffer, 0, true); polyTexCount = 0; vertex *vertex_list = vertices; fvector *normal_list = normals; prims->preparepPolygons(vertices, normals, texcoords); vertex *pVertex; fvector *pNormal; fpoint2 *pTexcoord; buffer = tgeo->itemData[1]; for (int lp = 0; lp < polyCount; lp++) { unsigned long bufferOffset = lp * 8; unsigned short flagTex = getHword(buffer, bufferOffset+6, true); unsigned short texInfoOffset = (flagTex & 0x7FFF); unsigned long texInfoA = getWord(texInfoArray, texInfoOffset*4, true); bool textured = (texInfoA >> 31) & 1; if (textured) { prims->allocpPolygon(pVertex, pNormal, pTexcoord); unsigned short aOffset = getHword(buffer, bufferOffset+0, true); unsigned short bOffset = getHword(buffer, bufferOffset+2, true); unsigned short cOffset = getHword(buffer, bufferOffset+4, true); pVertex[0] = vertex_list[(aOffset/6)]; pVertex[1] = vertex_list[(bOffset/6)]; pVertex[2] = vertex_list[(cOffset/6)]; pNormal[0] = normal_list[(aOffset/6)]; pNormal[1] = normal_list[(bOffset/6)]; pNormal[2] = normal_list[(cOffset/6)]; unsigned char modelFlag = (flagTex & 0x8000) >> 15; unsigned short texInfoOffset = (flagTex & 0x7FFF); unsigned char semiTrans = (texInfoA >> 29) & 3; unsigned long texEID = getWord(texInfoArray, (texInfoOffset*4)+4, true); unsigned long texInfoB = getWord(texInfoArray, (texInfoOffset*4)+8, true); unsigned short texCoordsOffset = ((texInfoB >> 22) & 0x3FF); unsigned short colorMode = ((texInfoB >> 20) & 3); unsigned short section128 = ((texInfoB >> 18) & 3); //unsigned short offsetX = ((texInfoB >> 10) & 0xF8) >> colorMode; //multiple of 4 or else, varies for cmode //unsigned short offsetY = (texInfoB & 0x1F) << 2; unsigned short offsetX = ((texInfoB >> 13) & 0x1F); unsigned short offsetY = (texInfoB & 0x1F); unsigned char clutIndex = (texInfoB >> 6) & 0x7F; unsigned char clutPalette = (texInfoA >> 24) & 0xF; textureEntry texEntry; texEntry.coords = texCoordsOffset; texEntry.colorMode = colorMode; texEntry.sect128 = section128; texEntry.offsetX = offsetX; texEntry.offsetY = offsetY; texEntry.clutIndex = clutIndex; texEntry.clutPalette = clutPalette; texEntry.chunkIndex = texbuf->getTextureChunk(texEID); texture *tex = texbuf->getTexture(&texEntry); pTexcoord[0] = tex->coords.A; pTexcoord[1] = tex->coords.B; pTexcoord[2] = tex->coords.C; polyTexCount++; } } polyNonCount = 0; for (int lp = 0; lp < polyCount; lp++) { unsigned long bufferOffset = lp * 8; unsigned short flagTex = getHword(buffer, bufferOffset+6, true); unsigned short texInfoOffset = (flagTex & 0x7FFF); unsigned long texInfoA = getWord(texInfoArray, texInfoOffset*4, true); bool textured = (texInfoA >> 31) & 1; if (!textured) { prims->allocpPolygon(pVertex, pNormal); unsigned short aOffset = getHword(buffer, bufferOffset+0, true); unsigned short bOffset = getHword(buffer, bufferOffset+2, true); unsigned short cOffset = getHword(buffer, bufferOffset+4, true); pVertex[0] = vertex_list[(aOffset/6)]; pVertex[1] = vertex_list[(bOffset/6)]; pVertex[2] = vertex_list[(cOffset/6)]; pNormal[0] = normal_list[(aOffset/6)]; pNormal[1] = normal_list[(bOffset/6)]; pNormal[2] = normal_list[(cOffset/6)]; unsigned char R = (texInfoA >> 0) & 0xFF; unsigned char G = (texInfoA >> 8) & 0xFF; unsigned char B = (texInfoA >> 16) & 0xFF; pVertex[0].Rf = (float)R/256; pVertex[0].Gf = (float)G/256; pVertex[0].Bf = (float)B/256; pVertex[1].Rf = (float)R/256; pVertex[1].Gf = (float)G/256; pVertex[1].Bf = (float)B/256; pVertex[2].Rf = (float)R/256; pVertex[2].Gf = (float)G/256; pVertex[2].Bf = (float)B/256; polyNonCount++; } }