130 lines
4.8 KiB
C++
130 lines
4.8 KiB
C++
#include "WorldReader.h"
|
|
#include "World.h"
|
|
#include "LmpRepository.h"
|
|
#include "DataUtil.h"
|
|
|
|
World* WorldReader::readWorld(LmpRepository* lmpRepository, const char* name)
|
|
{
|
|
World* world = new World();
|
|
std::string worldLmpName = std::string(name) + ".lmp";
|
|
LmpFile* world_lmp = lmpRepository->getLmp(worldLmpName);
|
|
LmpEntry* world_entry = world_lmp->findEntry(world_lmp->findFilenamesByExtension("world")[0].c_str());
|
|
decodeWorldFile(world, world_entry->data, world_entry->length);
|
|
return world;
|
|
}
|
|
|
|
void WorldReader::decodeWorldFile(World* world, const unsigned char* data, int dataLength)
|
|
{
|
|
int numElements = DataUtil::getLEInt(data, 0);
|
|
int offset4 = DataUtil::getLEInt(data, 4);
|
|
|
|
decodeTopography(world, data, dataLength);
|
|
|
|
int elementBase = DataUtil::getLEInt(data, 0x24);
|
|
int i28 = DataUtil::getLEInt(data, 0x28);
|
|
int i2C = DataUtil::getLEInt(data, 0x2C);
|
|
|
|
int cols_38 = DataUtil::getLEInt(data, 0x30);
|
|
int rows_38 = DataUtil::getLEInt(data, 0x34);
|
|
int offset_38 = DataUtil::getLEInt(data, 0x38);
|
|
|
|
int i3C = DataUtil::getLEInt(data, 0x3C);
|
|
int i40 = DataUtil::getLEInt(data, 0x40);
|
|
int i44 = DataUtil::getLEInt(data, 0x44);
|
|
int i48 = DataUtil::getLEInt(data, 0x48);
|
|
|
|
int offset4C = DataUtil::getLEInt(data, 0x4C);
|
|
int len50 = DataUtil::getLEInt(data, 0x50);
|
|
int offset54 = DataUtil::getLEInt(data, 0x54);
|
|
|
|
int texMinxy = DataUtil::getLEInt(data, 0x58);
|
|
int texMaxxy = DataUtil::getLEInt(data, 0x5C);
|
|
|
|
int texMinx = texMinxy % 100;
|
|
int texMiny = texMinxy / 100;
|
|
int texMaxx = texMaxxy % 100;
|
|
int texMaxy = texMaxxy / 100;
|
|
|
|
int offset60 = DataUtil::getLEInt(data, 0x60);
|
|
int textureArrayOffset = DataUtil::getLEInt(data, 0x64);
|
|
int offset68 = DataUtil::getLEInt(data, 0x68);
|
|
int offsetTex6C = DataUtil::getLEInt(data, 0x6C);
|
|
}
|
|
|
|
void WorldReader::decodeTopography(World* world, const unsigned char* data, int dataLength)
|
|
{
|
|
world->topoStartCol = DataUtil::getLEInt(data, 8);
|
|
world->topoStartRow = DataUtil::getLEInt(data, 0x0C);
|
|
|
|
world->numTopoCols = DataUtil::getLEInt(data, 0x10);
|
|
world->numTopoRows = DataUtil::getLEInt(data, 0x14);
|
|
int topoElementsPerCellOffset = DataUtil::getLEInt(data, 0x18);
|
|
int numTopoElements = DataUtil::getLEInt(data, 0x1C);
|
|
int topoArrayOffset = DataUtil::getLEInt(data, 0x20);
|
|
|
|
// Allows us to quickly look up patches from the offsets stored in the file.
|
|
std::unordered_map<int, TopoPatch*> patchAddressMap;
|
|
|
|
world->topoElements.resize(numTopoElements);
|
|
for (int el = 0; el < numTopoElements; ++el){
|
|
int topoElementOffset = topoArrayOffset + el * 0x1C;
|
|
TopoElement* element = new TopoElement();
|
|
element->llx = DataUtil::getLEShort(data, topoElementOffset);
|
|
element->lly = DataUtil::getLEShort(data, topoElementOffset + 2);
|
|
element->urx = DataUtil::getLEShort(data, topoElementOffset + 4);
|
|
element->ury = DataUtil::getLEShort(data, topoElementOffset + 6);
|
|
element->int8 = DataUtil::getLEInt(data, topoElementOffset + 8);
|
|
|
|
int patchOffset = DataUtil::getLEInt(data, topoElementOffset + 0xc);
|
|
if (patchAddressMap.find(patchOffset) == patchAddressMap.end()){
|
|
patchAddressMap[patchOffset] = readTopoPatch(data, patchOffset);
|
|
}
|
|
element->patch = patchAddressMap[patchOffset];
|
|
element->flags = DataUtil::getLEShort(data, topoElementOffset + 0x10);
|
|
element->x0 = DataUtil::getLEShort(data, topoElementOffset + 0x12);
|
|
element->y0 = DataUtil::getLEShort(data, topoElementOffset + 0x14);
|
|
element->baseHeight = DataUtil::getLEShort(data, topoElementOffset + 0x16);
|
|
element->cos_alpha = DataUtil::getLEShort(data, topoElementOffset + 0x18) / 32767.0;
|
|
element->sin_alpha = DataUtil::getLEShort(data, topoElementOffset + 0x1A) / 32767.0;
|
|
world->topoElements.push_back(element);
|
|
}
|
|
|
|
world->topoElementsPerCell.resize(world->numTopoCols * world->numTopoRows);
|
|
|
|
int index = 0;
|
|
for (int r = 0; r < world->numTopoRows; ++r){
|
|
for (int c = 0; c < world->numTopoCols; ++c){
|
|
int elementsInCellListOffset = DataUtil::getLEInt(data, topoElementsPerCellOffset + index*4);
|
|
|
|
auto& elementList = world->topoElementsPerCell[index];
|
|
|
|
int elementId = DataUtil::getLEShort(data, elementsInCellListOffset);
|
|
while (elementId >= 0){
|
|
elementsInCellListOffset += 2;
|
|
elementList.push_back(world->topoElements[elementId]);
|
|
elementId = DataUtil::getLEShort(data, elementsInCellListOffset);
|
|
}
|
|
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
TopoPatch* WorldReader::readTopoPatch(const unsigned char* data, int offset)
|
|
{
|
|
int w = DataUtil::getLEInt(data, offset + 8);
|
|
int h = DataUtil::getLEInt(data, offset + 0x0c);
|
|
TopoPatch* patch = new TopoPatch(w, h);
|
|
patch->x0 = DataUtil::getLEInt(data, offset);
|
|
patch->y0 = DataUtil::getLEInt(data, offset + 4);
|
|
patch->minHeight = DataUtil::getLEShort(data, offset + 0x10);
|
|
patch->maxHeight = DataUtil::getLEShort(data, offset + 0x12);
|
|
int j = 0;
|
|
for (int y = 0; y < h; ++y) {
|
|
for (int x = 0; x < w; ++x) {
|
|
int i = y * w + x;
|
|
patch->heights[j++] = DataUtil::getLEShort(data, offset + 0x14 + i * 2);
|
|
}
|
|
}
|
|
return patch;
|
|
} |