diff --git a/src/gamedata.cpp b/src/gamedata.cpp index d0c306c..0471e9a 100644 --- a/src/gamedata.cpp +++ b/src/gamedata.cpp @@ -139,29 +139,13 @@ void GameData::extractFile(std::string_view dataFilePath, std::string_view outPa fmt::print("file size = {}\n", info.fileSize); - if(info.fileType != FileType::Standard) { - throw std::runtime_error("File type is not handled yet for " + std::string(dataFilePath)); - } - struct Block { int32_t offset; int16_t dummy; int16_t dummy2; }; - std::vector blocks; - - for(int i = 0; i < info.numBlocks; i++) { - Block block; - fread(&block, sizeof(Block), 1, file); - - blocks.push_back(block); - } - - std::vector data; - - const size_t startingPos = offset + info.size; - for(auto block : blocks) { + const auto readFileBlock = [](FILE* file, size_t startingPos) -> std::vector { struct BlockHeader { int32_t size; int32_t dummy; @@ -169,7 +153,7 @@ void GameData::extractFile(std::string_view dataFilePath, std::string_view outPa int32_t decompressedLength; } header; - fseek(file, startingPos + block.offset, SEEK_SET); + fseek(file, startingPos, SEEK_SET); fread(&header, sizeof(BlockHeader), 1, file); @@ -184,23 +168,249 @@ void GameData::extractFile(std::string_view dataFilePath, std::string_view outPa fread(compressed_data.data(), header.compressedLength, 1, file); zlib::no_header_decompress(reinterpret_cast(compressed_data.data()), - compressed_data.size(), - reinterpret_cast(localdata.data()), - header.decompressedLength); + compressed_data.size(), + reinterpret_cast(localdata.data()), + header.decompressedLength); } else { localdata.resize(header.decompressedLength); fread(localdata.data(), header.decompressedLength, 1, file); } - data.insert(data.end(), localdata.begin(), localdata.end()); + return localdata; + }; + + if(info.fileType == FileType::Standard) { + std::vector blocks; + + for(int i = 0; i < info.numBlocks; i++) { + Block block; + fread(&block, sizeof(Block), 1, file); + + blocks.push_back(block); + } + + std::vector data; + + const size_t startingPos = offset + info.size; + for(auto block : blocks) { + struct BlockHeader { + int32_t size; + int32_t dummy; + int32_t compressedLength; // < 32000 is uncompressed data + int32_t decompressedLength; + } header; + + fseek(file, startingPos + block.offset, SEEK_SET); + + fread(&header, sizeof(BlockHeader), 1, file); + + std::vector localdata; + + bool isCompressed = header.compressedLength < 32000; + if(isCompressed) { + localdata.resize(header.decompressedLength); + + std::vector compressed_data; + compressed_data.resize(header.compressedLength); + fread(compressed_data.data(), header.compressedLength, 1, file); + + zlib::no_header_decompress(reinterpret_cast(compressed_data.data()), + compressed_data.size(), + reinterpret_cast(localdata.data()), + header.decompressedLength); + } else { + localdata.resize(header.decompressedLength); + + fread(localdata.data(), header.decompressedLength, 1, file); + } + + data.insert(data.end(), localdata.begin(), localdata.end()); + } + + fclose(file); + + FILE* newFile = fopen(outPath.data(), "w"); + fwrite(data.data(), data.size(), 1, newFile); + fclose(newFile); + + } else if(info.fileType == FileType::Model) { + FILE* newFile = fopen(outPath.data(), "w"); + + // reset + fseek(file, offset, SEEK_SET); + + struct ModelFileInfo { + uint32_t size; + FileType fileType; + uint32_t fileSize; + uint32_t numBlocks; + uint32_t numUsedBlocks; + uint32_t version; + uint32_t stackSize; + uint32_t runtimeSize; + uint32_t vertexBufferSize[3]; + uint32_t edgeGeometryVertexBufferSize[3]; + uint32_t indexBufferSize[3]; + uint32_t compressedStackMemorySize; + uint32_t compressedRuntimeMemorySize; + uint32_t compressedVertexBufferSize[3]; + uint32_t compressedEdgeGeometrySize[3]; + uint32_t compressedIndexBufferSize[3]; + uint32_t stackOffset; + uint32_t runtimeOffset; + uint32_t vertexBufferOffset[3]; + uint32_t edgeGeometryVertexBufferOffset[3]; + uint32_t indexBufferOffset[3]; + uint16_t stackBlockIndex; + uint16_t runtimeBlockIndex; + uint16_t vertexBufferBlockIndex[3]; + uint16_t edgeGeometryVertexBufferBlockIndex[3]; + uint16_t indexBufferBlockIndex[3]; + uint16_t stackBlockNum; + uint16_t runtimeBlockNum; + uint16_t vertexBlockBufferBlockNum[3]; + uint16_t edgeGeometryVertexBufferBlockNum[3]; + uint16_t indexBufferBlockNum[3]; + uint16_t vertexDeclarationNum; + uint16_t materialNum; + uint8_t numLods; + bool indexBufferStreamingEnabled; + bool edgeGeometryEnabled; + uint8_t padding; + } modelInfo; + + fread(&modelInfo, sizeof(ModelFileInfo), 1, file); + + const size_t baseOffset = offset + modelInfo.size; + + int totalBlocks = modelInfo.stackBlockNum; + totalBlocks += modelInfo.runtimeBlockNum; + for(int i = 0; i < 3; i++) { + totalBlocks += modelInfo.vertexBlockBufferBlockNum[i]; + totalBlocks += modelInfo.edgeGeometryVertexBufferBlockNum[i]; + totalBlocks += modelInfo.indexBufferBlockNum[i]; + } + + std::vector compressedBlockSizes(totalBlocks); + fread(compressedBlockSizes.data(), compressedBlockSizes.size() * sizeof(uint16_t), 1, file); + int currentBlock = 0; + int stackSize = 0; + int runtimeSize = 0; + + std::array vertexDataOffsets; + std::array indexDataOffsets; + + std::array vertexDataSizes; + std::array indexDataSizes; + + // data.append 0x44 + fseek(newFile, 0x44, SEEK_SET); + + fseek(file, baseOffset + modelInfo.stackOffset, SEEK_SET); + size_t stackStart = ftell(newFile); + for(int i = 0; i < modelInfo.stackBlockNum; i++) { + size_t lastPos = ftell(file); + auto data = readFileBlock(file, lastPos); + fwrite(data.data(), data.size(), 1, newFile); // i think we write this to file? + fseek(file, lastPos + compressedBlockSizes[currentBlock], SEEK_SET); + currentBlock++; + } + + size_t stackEnd = ftell(newFile); + stackSize = (int)(stackEnd - stackStart); + + fseek(file, baseOffset + modelInfo.runtimeOffset, SEEK_SET); + size_t runtimeStart = ftell(newFile); + for(int i = 0; i < modelInfo.runtimeBlockNum; i++) { + size_t lastPos = ftell(file); + auto data = readFileBlock(file, lastPos); + fwrite(data.data(), data.size(), 1, newFile); + fseek(file, lastPos + compressedBlockSizes[currentBlock], SEEK_SET); + currentBlock++; + } + + size_t runtimeEnd = ftell(newFile); + runtimeSize = (int)(runtimeEnd - runtimeStart); + + fmt::print("stack size: {}\n", stackSize); + fmt::print("runtime size: {}\n", runtimeSize); + + // process all 3 lods + for(int i = 0; i < 3; i++) { + if(modelInfo.vertexBlockBufferBlockNum[i] != 0) { + int currentVertexOffset = ftell(newFile); + if(i == 0 || currentVertexOffset != vertexDataOffsets[i - 1]) + vertexDataOffsets[i] = currentVertexOffset; + else + vertexDataOffsets[i] = 0; + + fseek(file, baseOffset + modelInfo.vertexBufferOffset[i], SEEK_SET); + + for(int j = 0; j < modelInfo.vertexBlockBufferBlockNum[i]; j++) { + size_t lastPos = ftell(file); + auto data = readFileBlock(file, lastPos); + fwrite(data.data(), data.size(), 1, newFile); // i think we write this to file? + vertexDataSizes[i] += (int)data.size(); + fseek(file, lastPos + compressedBlockSizes[currentBlock], SEEK_SET); + currentBlock++; + } + } + + // TODO: lol no edge geometry + + if(modelInfo.indexBufferBlockNum[i] != 0) { + int currentIndexOffset = ftell(newFile); + if(i == 0 || currentIndexOffset != indexDataOffsets[i - 1]) + indexDataOffsets[i] = currentIndexOffset; + else + indexDataOffsets[i] = 0; + + for(int j = 0; j < modelInfo.indexBufferBlockNum[i]; j++) { + size_t lastPos = ftell(file); + auto data = readFileBlock(file, lastPos); + fwrite(data.data(), data.size(), 1, newFile); // i think we write this to file? + indexDataSizes[i] += (int)data.size(); + fseek(file, lastPos + compressedBlockSizes[currentBlock], SEEK_SET); + currentBlock++; + } + } + } + + // now write mdl header + fseek(newFile, 0, SEEK_SET); + fwrite(&modelInfo.version, sizeof(uint32_t), 1, newFile); + fwrite(&stackSize, sizeof(int), 1, newFile); + fwrite(&runtimeSize, sizeof(int), 1, newFile); + fwrite(&modelInfo.vertexDeclarationNum, sizeof(uint16_t), 1, newFile); + fwrite(&modelInfo.materialNum, sizeof(uint16_t), 1, newFile); + + for(int i = 0; i < 3; i++) + fwrite(&vertexDataOffsets[i], sizeof(int), 1, newFile); + + for(int i = 0; i < 3; i++) + fwrite(&indexDataOffsets[i], sizeof(int), 1, newFile); + + for(int i = 0; i < 3; i++) + fwrite(&vertexDataSizes[i], sizeof(int), 1, newFile); + + for(int i = 0; i < 3; i++) + fwrite(&indexDataSizes[i], sizeof(int), 1, newFile); + + fwrite(&modelInfo.numLods, sizeof(uint8_t), 1, file); + fwrite(&modelInfo.indexBufferStreamingEnabled, sizeof(bool), 1, file); + fwrite(&modelInfo.edgeGeometryEnabled, sizeof(bool), 1, file); + + uint8_t dummy[] = {0}; + fwrite(&dummy, sizeof(dummy), 1, file); + + fmt::print("data size: {}\n", modelInfo.fileSize); + + fclose(newFile); + fclose(file); + } else { + throw std::runtime_error("File type is not handled yet for " + std::string(dataFilePath)); } - - fclose(file); - - FILE* newFile = fopen(outPath.data(), "w"); - fwrite(data.data(), data.size(), 1, newFile); - fclose(newFile); } }