From 85da6224e0082630b12100415c0a65686c6701af Mon Sep 17 00:00:00 2001 From: Ian Brown Date: Thu, 1 Apr 2021 23:49:11 +0100 Subject: [PATCH] starting world reading --- buildscripts/generate_vs2019_64_laptop.cmd | 5 ++ snowlib/DataUtil.h | 43 +++++++++++++- snowlib/Mesh.h | 11 ++++ snowlib/Model.h | 19 +++++- snowlib/VertexDefs.h | 28 ++++++++- snowlib/World.cpp | 9 ++- snowlib/World.h | 30 +++++++++- snowlib/WorldReader.cpp | 67 +++++++++++++++++++++- snowlib/WorldReader.h | 5 +- 9 files changed, 203 insertions(+), 14 deletions(-) create mode 100644 buildscripts/generate_vs2019_64_laptop.cmd diff --git a/buildscripts/generate_vs2019_64_laptop.cmd b/buildscripts/generate_vs2019_64_laptop.cmd new file mode 100644 index 0000000..297d4f2 --- /dev/null +++ b/buildscripts/generate_vs2019_64_laptop.cmd @@ -0,0 +1,5 @@ +@echo off +mkdir build_vs2019 +pushd build_vs2019 +"C:\Program Files\CMake\bin\cmake" -G "Visual Studio 16 2019" -A x64 -DADDITIONAL_FIND_PATH="C:\Qt6\6.0.2\msvc2019_64" -DVCPKG_TARGET_TRIPLET=x64-windows -DCMAKE_TOOLCHAIN_FILE="C:\dev\vcpkg\scripts\buildsystems\vcpkg.cmake" ../.. +popd diff --git a/snowlib/DataUtil.h b/snowlib/DataUtil.h index aed524a..432d664 100644 --- a/snowlib/DataUtil.h +++ b/snowlib/DataUtil.h @@ -5,16 +5,53 @@ class DataUtil { public: - static int getLEInt(const unsigned char* data, int offset){ + DataUtil(const unsigned char* p_in, int offset_in) : p(p_in), offset(offset_in) + { + } + + float getLEFloat() + { + const float f = *(float*)(p + offset); + offset += 4; + return f; + } + + int getLEInt() + { + const int i = *(int32_t*)(p + offset); + offset += 4; + return i; + } + + unsigned short getLEUShort() + { + const unsigned short s = *(uint16_t*)(p + offset); + offset += 2; + return s; + } + + static int getLEInt(const unsigned char* data, int offset) + { return *(int32_t *)(data + offset); } - static short getLEShort(const unsigned char* data, int offset){ + static short getLEShort(const unsigned char* data, int offset) + { return *(int16_t *)(data + offset); } - static unsigned short getLEUShort(const unsigned char* data, int offset){ + static unsigned short getLEUShort(const unsigned char* data, int offset) + { return *(uint16_t *)(data + offset); } + + static float getLEFloat(const unsigned char* data, int offset) + { + return *(float*)(data + offset); + } + +private: + const unsigned char* p; + int offset; }; diff --git a/snowlib/Mesh.h b/snowlib/Mesh.h index e6da1ad..346ac25 100644 --- a/snowlib/Mesh.h +++ b/snowlib/Mesh.h @@ -7,6 +7,17 @@ class Mesh { public: + Mesh() { + positions = normals = nullptr; + uvCoords = nullptr; + numVertices = 0; + } + ~Mesh() { + delete positions; positions = nullptr; + delete normals; normals = nullptr; + delete uvCoords; uvCoords = nullptr; + } + std::vector triangleIndices; FloatVector* positions; FloatVector* normals; diff --git a/snowlib/Model.h b/snowlib/Model.h index 2312c1e..9000327 100644 --- a/snowlib/Model.h +++ b/snowlib/Model.h @@ -1,12 +1,21 @@ #pragma once #include -class Texture; -class AnimData; +#include "Texture.h" +#include "AnimData.h" +class Mesh; class TexturedMesh { public: + TexturedMesh() { + meshList = nullptr; + texture = nullptr; + } + ~TexturedMesh() { + delete meshList; meshList = nullptr; + delete texture; texture = nullptr; + } std::vector* meshList; Texture* texture; }; @@ -14,6 +23,12 @@ public: class Model { public: + Model() { + animData = nullptr; + } + ~Model() { + delete animData; animData = nullptr; + } std::vector texturedMeshList; AnimData* animData; }; diff --git a/snowlib/VertexDefs.h b/snowlib/VertexDefs.h index e6a1f3c..7c95771 100644 --- a/snowlib/VertexDefs.h +++ b/snowlib/VertexDefs.h @@ -2,7 +2,7 @@ struct FloatVector { - FloatVector(){} + FloatVector() : x(0.0f), y(0.0f), z(0.0f){} FloatVector(float xx, float yy, float zz) : x(xx), y(yy), z(zz){} float x; @@ -10,6 +10,30 @@ struct FloatVector float z; }; +struct FloatRect +{ + FloatRect() : x0(0.0f), y0(0.0f), x1(0.0f), y1(0.0f) {} + FloatRect(float xx0, float yy0, float xx1, float yy1) : x0(xx0), y0(yy0), x1(xx1), y1(yy1) {} + + float x0; + float y0; + float x1; + float y1; +}; + +struct FloatBox +{ + FloatBox() : x0(0.0f), y0(0.0f), z0(0.0f), x1(0.0f), y1(0.0f), z1(0.0f) {} + FloatBox(float xx0, float yy0, float zz0, float xx1, float yy1, float zz1) : x0(xx0), y0(yy0), z0(zz0), x1(xx1), y1(yy1), z1(zz1) {} + + float x0; + float y0; + float z0; + float x1; + float y1; + float z1; +}; + struct ShortVector { ShortVector(short xx, short yy, short zz) : x(xx), y(yy), z(zz){} @@ -30,7 +54,7 @@ struct SByteVector struct Point { - Point(){} + Point() : x(0), y(0){} Point(int xx, int yy) : x(xx), y(yy){} int x; diff --git a/snowlib/World.cpp b/snowlib/World.cpp index 5d1a870..bb44e1d 100644 --- a/snowlib/World.cpp +++ b/snowlib/World.cpp @@ -18,10 +18,17 @@ World::~World() { delete patch; } + for (auto& element : elements) + { + delete element; + } } TopoPatch::TopoPatch(int width, int height) { + minHeight = 0; + maxHeight = 0; + x0 = y0 = 0; w = width; h = height; heights = new int[w * h]; @@ -29,5 +36,5 @@ TopoPatch::TopoPatch(int width, int height) TopoPatch::~TopoPatch() { - delete[] heights; + delete[] heights; heights = nullptr; } diff --git a/snowlib/World.h b/snowlib/World.h index f757540..2f2380c 100644 --- a/snowlib/World.h +++ b/snowlib/World.h @@ -1,6 +1,9 @@ #pragma once #include +#include +#include "VertexDefs.h" +#include "Model.h" class TopoPatch { @@ -18,13 +21,35 @@ class TopoElement public: int llx, lly, urx, ury; int int8; - TopoPatch* patch; + std::shared_ptr patch; int flags; int x0, y0; int baseHeight; double cos_alpha, sin_alpha; }; +class WorldElement +{ +public: + FloatBox boundingBox; + TexturedMesh mesh; + + // The position before rotation + FloatVector pos; + + bool usesRotFlags; + int xyzRotFlags; + + double cosAlpha; + double sinAlpha; + // Whether we should flip the y axis (when not using rot flags) + bool negYaxis; + + // Store info to access again + int VifDataOffset; + int VifDataLength; +}; + class World { public: @@ -60,6 +85,9 @@ public: // All of the topo patches. This collection owns the patches. std::vector topoPatches; + // All of the elements. This collection owns the elements. + std::vector elements; + // The texture chunk offsets. 2D array with a 100 x 100 dimension. std::vector textureChunkOffsets; diff --git a/snowlib/WorldReader.cpp b/snowlib/WorldReader.cpp index b24d153..525231e 100644 --- a/snowlib/WorldReader.cpp +++ b/snowlib/WorldReader.cpp @@ -2,6 +2,7 @@ #include "World.h" #include "LmpRepository.h" #include "DataUtil.h" +#include "VifDecoder.h" World* WorldReader::readWorld(LmpRepository* lmpRepository, const char* name) { @@ -51,6 +52,66 @@ void WorldReader::decodeWorldFile(World* world, const unsigned char* data, int d int worldTexOffsetsOffset = DataUtil::getLEInt(data, 0x6C); readTextureChunkOffsets(world, data, dataLength, worldTexOffsetsOffset, texMinx, texMiny, texMaxx+1, texMaxy); + readElements(world, data, dataLength, elementBase, numElements, texMinx, texMiny); +} + +void WorldReader::readElements(World* world, const unsigned char* data, int dataLength, int elementBase, int numElements, int texMinx, int texMiny) +{ + for (int idx = 0; idx < numElements; ++idx) { + auto element = new WorldElement(); + int elementSize = 0x38; + if (GameType::CHAMPIONS_RTA == gameType || GameType::JL_HEROES == gameType) { + elementSize = 0x3C; + } + int elementOffset = elementBase + idx * elementSize; + + DataUtil reader(data, elementOffset); + + int vifDataOffset = reader.getLEInt(); + + if (GameType::DARK_ALLIANCE == gameType) { + int Tex2 = reader.getLEInt(); + } + int vifLen = reader.getLEInt(); + float x1 = reader.getLEFloat(); + float y1 = reader.getLEFloat(); + float z1 = reader.getLEFloat(); + float x2 = reader.getLEFloat(); + float y2 = reader.getLEFloat(); + float z2 = reader.getLEFloat(); + + element->boundingBox = FloatBox(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); + + int textureNum = reader.getLEInt() / 0x40; + + int texCellxy = reader.getLEUShort(); + int y = texCellxy / 100; + int x = texCellxy % 100; + if (GameType::CHAMPIONS_RTA == gameType || GameType::JL_HEROES == gameType) { + x += texMinx; + y += texMiny; + } + if (textureNum != 0) { + // TODO + } + int texWidth = 100; + int texHeight = 100; + /* + if (element.Texture != null) + { + texWidth = element.Texture.PixelWidth; + texHeight = element.Texture.PixelHeight; + } + */ + unsigned char nregs = data[vifDataOffset + 0x10]; + int vifStartOffset = (nregs + 2) * 0x10; + int vifDataLength = vifLen * 0x10 - vifStartOffset; + + element->mesh.meshList = VifDecoder().decode(data, vifDataOffset + vifStartOffset); + + + world->elements.push_back(element); + } } void WorldReader::readTextureChunkOffsets(World* world, const unsigned char* data, int dataLength, int worldTexOffsetsOffset, int texMinx, int texMiny, int texMaxx, int texMaxy) @@ -91,7 +152,7 @@ void WorldReader::decodeTopography(World* world, const unsigned char* data, int int topoArrayOffset = DataUtil::getLEInt(data, 0x20); // Allows us to quickly look up patches from the offsets stored in the file. - std::unordered_map patchAddressMap; + std::unordered_map> patchAddressMap; world->topoElements.resize(numTopoElements); for (int el = 0; el < numTopoElements; ++el){ @@ -138,11 +199,11 @@ void WorldReader::decodeTopography(World* world, const unsigned char* data, int } } -TopoPatch* WorldReader::readTopoPatch(const unsigned char* data, int offset) +std::shared_ptr 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); + auto patch = std::make_shared(w, h); patch->x0 = DataUtil::getLEInt(data, offset); patch->y0 = DataUtil::getLEInt(data, offset + 4); patch->minHeight = DataUtil::getLEShort(data, offset + 0x10); diff --git a/snowlib/WorldReader.h b/snowlib/WorldReader.h index 3163ae3..e588bdd 100644 --- a/snowlib/WorldReader.h +++ b/snowlib/WorldReader.h @@ -1,5 +1,6 @@ #pragma once +#include #include "GameType.h" class World; @@ -17,7 +18,7 @@ private: void decodeWorldFile(World* world, const unsigned char* data, int dataLength); void decodeTopography(World* world, const unsigned char* data, int dataLength); - TopoPatch* readTopoPatch(const unsigned char* data, int offset); + std::shared_ptr readTopoPatch(const unsigned char* data, int offset); void readTextureChunkOffsets(World* world, const unsigned char* data, int dataLength, int worldTexOffsetsOffset, int texMinx, int texMiny, int texMaxx, int texMaxy); - + void readElements(World* world, const unsigned char* data, int dataLength, int elementBase, int numElements, int texMinx, int texMiny); }; \ No newline at end of file