From e6c7f744b5530ef1bdd50f7ba4548b452efcd676 Mon Sep 17 00:00:00 2001 From: Jett <55758076+Jettford@users.noreply.github.com> Date: Thu, 4 Aug 2022 01:59:47 +0100 Subject: [PATCH] Implement terrain file reading to generate navmeshes in the future (#703) * Implement terrain file reading to generate navmeshes in the future * Make Emo's suggested changes. --- CMakeLists.txt | 1 + dNavigation/CMakeLists.txt | 6 ++ dNavigation/dNavMesh.cpp | 4 ++ dNavigation/dTerrain/CMakeLists.txt | 3 + dNavigation/dTerrain/RawChunk.cpp | 92 +++++++++++++++++++++++++++ dNavigation/dTerrain/RawChunk.h | 24 +++++++ dNavigation/dTerrain/RawFile.cpp | 82 ++++++++++++++++++++++++ dNavigation/dTerrain/RawFile.h | 27 ++++++++ dNavigation/dTerrain/RawHeightMap.cpp | 27 ++++++++ dNavigation/dTerrain/RawHeightMap.h | 21 ++++++ dNavigation/dTerrain/RawMesh.h | 10 +++ dWorldServer/WorldServer.cpp | 2 +- dZoneManager/Zone.h | 2 + 13 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 dNavigation/dTerrain/CMakeLists.txt create mode 100644 dNavigation/dTerrain/RawChunk.cpp create mode 100644 dNavigation/dTerrain/RawChunk.h create mode 100644 dNavigation/dTerrain/RawFile.cpp create mode 100644 dNavigation/dTerrain/RawFile.h create mode 100644 dNavigation/dTerrain/RawHeightMap.cpp create mode 100644 dNavigation/dTerrain/RawHeightMap.h create mode 100644 dNavigation/dTerrain/RawMesh.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cdc73d69..6acca4d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ set(INCLUDED_DIRECTORIES "dGame/dUtilities" "dPhysics" "dNavigation" + "dNavigation/dTerrain" "dZoneManager" "dDatabase" "dDatabase/Tables" diff --git a/dNavigation/CMakeLists.txt b/dNavigation/CMakeLists.txt index beb498e3..5891c77d 100644 --- a/dNavigation/CMakeLists.txt +++ b/dNavigation/CMakeLists.txt @@ -1,4 +1,10 @@ set(DNAVIGATION_SOURCES "dNavMesh.cpp") +add_subdirectory(dTerrain) + +foreach(file ${DNAVIGATIONS_DTERRAIN_SOURCES}) + set(DNAVIGATION_SOURCES ${DNAVIGATION_SOURCES} "dTerrain/${file}") +endforeach() + add_library(dNavigation STATIC ${DNAVIGATION_SOURCES}) target_link_libraries(dNavigation detour recast) diff --git a/dNavigation/dNavMesh.cpp b/dNavigation/dNavMesh.cpp index da471882..c0bbf4b2 100644 --- a/dNavigation/dNavMesh.cpp +++ b/dNavigation/dNavMesh.cpp @@ -1,11 +1,15 @@ #include "dNavMesh.h" +#include "RawFile.h" + #include "Game.h" #include "dLogger.h" #include "dPlatforms.h" #include "NiPoint3.h" #include "BinaryIO.h" +#include "dZoneManager.h" + dNavMesh::dNavMesh(uint32_t zoneId) { m_ZoneId = zoneId; diff --git a/dNavigation/dTerrain/CMakeLists.txt b/dNavigation/dTerrain/CMakeLists.txt new file mode 100644 index 00000000..91d0741b --- /dev/null +++ b/dNavigation/dTerrain/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DNAVIGATIONS_DTERRAIN_SOURCES "RawFile.cpp" + "RawChunk.cpp" + "RawHeightMap.cpp" PARENT_SCOPE) diff --git a/dNavigation/dTerrain/RawChunk.cpp b/dNavigation/dTerrain/RawChunk.cpp new file mode 100644 index 00000000..e4f753cd --- /dev/null +++ b/dNavigation/dTerrain/RawChunk.cpp @@ -0,0 +1,92 @@ +#include "RawChunk.h" + +#include "BinaryIO.h" + +#include "RawMesh.h" +#include "RawHeightMap.h" + +RawChunk::RawChunk(std::ifstream& stream) { + // Read the chunk index and info + + BinaryIO::BinaryRead(stream, m_ChunkIndex); + BinaryIO::BinaryRead(stream, m_Width); + BinaryIO::BinaryRead(stream, m_Height); + BinaryIO::BinaryRead(stream, m_X); + BinaryIO::BinaryRead(stream, m_Z); + + m_HeightMap = new RawHeightMap(stream, m_Height, m_Width); + + // We can just skip the rest of the data so we can read the next chunks, we don't need anymore data + + uint32_t colorMapSize; + BinaryIO::BinaryRead(stream, colorMapSize); + stream.seekg((uint32_t)stream.tellg() + (colorMapSize * colorMapSize * 4)); + + uint32_t lightmapSize; + BinaryIO::BinaryRead(stream, lightmapSize); + stream.seekg((uint32_t)stream.tellg() + (lightmapSize)); + + uint32_t colorMapSize2; + BinaryIO::BinaryRead(stream, colorMapSize2); + stream.seekg((uint32_t)stream.tellg() + (colorMapSize2 * colorMapSize2 * 4)); + + uint8_t unknown; + BinaryIO::BinaryRead(stream, unknown); + + uint32_t blendmapSize; + BinaryIO::BinaryRead(stream, blendmapSize); + stream.seekg((uint32_t)stream.tellg() + (blendmapSize)); + + uint32_t pointSize; + BinaryIO::BinaryRead(stream, pointSize); + stream.seekg((uint32_t)stream.tellg() + (pointSize * 9 * 4)); + + stream.seekg((uint32_t)stream.tellg() + (colorMapSize * colorMapSize)); + + uint32_t endCounter; + BinaryIO::BinaryRead(stream, endCounter); + stream.seekg((uint32_t)stream.tellg() + (endCounter * 2)); + + if (endCounter != 0) { + stream.seekg((uint32_t)stream.tellg() + (32)); + + for (int i = 0; i < 0x10; i++) { + uint16_t finalCountdown; + BinaryIO::BinaryRead(stream, finalCountdown); + stream.seekg((uint32_t)stream.tellg() + (finalCountdown * 2)); + } + } + + // Generate our mesh/geo data for this chunk + + this->GenerateMesh(); +} + +RawChunk::~RawChunk() { + if (m_Mesh) delete m_Mesh; + if (m_HeightMap) delete m_HeightMap; +} + +void RawChunk::GenerateMesh() { + RawMesh* meshData = new RawMesh(); + + for (int i = 0; i < m_Width; ++i) { + for (int j = 0; j < m_Height; ++j) { + float y = *std::next(m_HeightMap->m_FloatMap.begin(), m_Width * i + j); + + meshData->m_Vertices.push_back(NiPoint3(i, y, j)); + + if (i == 0 || j == 0) continue; + + meshData->m_Triangles.push_back(m_Width * i + j); + meshData->m_Triangles.push_back(m_Width * i + j - 1); + meshData->m_Triangles.push_back(m_Width * (i - 1) + j - 1); + + meshData->m_Triangles.push_back(m_Width * (i - 1) + j - 1); + meshData->m_Triangles.push_back(m_Width * (i - 1) + j); + meshData->m_Triangles.push_back(m_Width * i + j); + } + } + + m_Mesh = meshData; +} diff --git a/dNavigation/dTerrain/RawChunk.h b/dNavigation/dTerrain/RawChunk.h new file mode 100644 index 00000000..1e26f11d --- /dev/null +++ b/dNavigation/dTerrain/RawChunk.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +struct RawMesh; +class RawHeightMap; + +class RawChunk { +public: + RawChunk(std::ifstream& stream); + ~RawChunk(); + + void GenerateMesh(); + + uint32_t m_ChunkIndex; + uint32_t m_Width; + uint32_t m_Height; + float m_X; + float m_Z; + + RawHeightMap* m_HeightMap; + RawMesh* m_Mesh; +}; diff --git a/dNavigation/dTerrain/RawFile.cpp b/dNavigation/dTerrain/RawFile.cpp new file mode 100644 index 00000000..d4496b2f --- /dev/null +++ b/dNavigation/dTerrain/RawFile.cpp @@ -0,0 +1,82 @@ +#include "RawFile.h" + +#include "BinaryIO.h" +#include "RawChunk.h" +#include "RawMesh.h" +#include "RawHeightMap.h" + +RawFile::RawFile(std::string fileName) { + if (!BinaryIO::DoesFileExist(fileName)) return; + + std::ifstream file(fileName, std::ios::binary); + + // Read header + + BinaryIO::BinaryRead(file, m_Version); + BinaryIO::BinaryRead(file, m_Padding); + BinaryIO::BinaryRead(file, m_ChunkCount); + BinaryIO::BinaryRead(file, m_Width); + BinaryIO::BinaryRead(file, m_Height); + + + if (m_Version < 0x20) { + return; // Version too crusty to handle + } + + // Read in chunks + + m_Chunks = {}; + + for (uint32_t i = 0; i < m_ChunkCount; i++) { + RawChunk* chunk = new RawChunk(file); + m_Chunks.push_back(chunk); + } + + this->GenerateFinalMeshFromChunks(); +} + +RawFile::~RawFile() { + delete m_FinalMesh; + for (const auto* item : m_Chunks) { + delete item; + } +} + +void RawFile::GenerateFinalMeshFromChunks() { + uint32_t lenOfLastChunk = 0; // index of last vert set in the last chunk + + for (const auto& chunk : m_Chunks) { + for (const auto& vert : chunk->m_Mesh->m_Vertices) { + auto tempVert = vert; + + tempVert.SetX(tempVert.GetX() + (chunk->m_X / 4)); + tempVert.SetZ(tempVert.GetZ() + (chunk->m_Z / 4)); + + tempVert* chunk->m_HeightMap->m_ScaleFactor; + + m_FinalMesh->m_Vertices.push_back(tempVert); + } + + for (const auto& tri : chunk->m_Mesh->m_Triangles) { + m_FinalMesh->m_Triangles.push_back(tri + lenOfLastChunk); + } + + lenOfLastChunk += chunk->m_Mesh->m_Vertices.size(); + } +} + +void RawFile::WriteFinalMeshToOBJ(std::string path) { + std::ofstream file(path); + std::string vertData; + + for (const auto& v : m_FinalMesh->m_Vertices) { + vertData += "v " + std::to_string(v.x) + " " + std::to_string(v.y) + " " + std::to_string(v.z) + "\n"; + } + + for (int i = 0; i < m_FinalMesh->m_Triangles.size(); i += 3) { + vertData += "f " + std::to_string(*std::next(m_FinalMesh->m_Triangles.begin(), i) + 1) + " " + std::to_string(*std::next(m_FinalMesh->m_Triangles.begin(), i + 1) + 1) + " " + std::to_string(*std::next(m_FinalMesh->m_Triangles.begin(), i + 2) + 1) + "\n"; + } + + file.write(vertData.c_str(), vertData.size()); + file.close(); +} diff --git a/dNavigation/dTerrain/RawFile.h b/dNavigation/dTerrain/RawFile.h new file mode 100644 index 00000000..84afae94 --- /dev/null +++ b/dNavigation/dTerrain/RawFile.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +class RawChunk; +struct RawMesh; + +class RawFile { +public: + RawFile(std::string filePath); + ~RawFile(); + +private: + + void GenerateFinalMeshFromChunks(); + void WriteFinalMeshToOBJ(std::string path); + + uint8_t m_Version; + uint16_t m_Padding; + uint32_t m_ChunkCount; + uint32_t m_Width; + uint32_t m_Height; + + std::vector m_Chunks; + RawMesh* m_FinalMesh; +}; diff --git a/dNavigation/dTerrain/RawHeightMap.cpp b/dNavigation/dTerrain/RawHeightMap.cpp new file mode 100644 index 00000000..e1310669 --- /dev/null +++ b/dNavigation/dTerrain/RawHeightMap.cpp @@ -0,0 +1,27 @@ +#include "RawHeightMap.h" + +#include "BinaryIO.h" + +RawHeightMap::RawHeightMap() {} + +RawHeightMap::RawHeightMap(std::ifstream& stream, float height, float width) { + // Read in height map data header and scale + + BinaryIO::BinaryRead(stream, m_Unknown1); + BinaryIO::BinaryRead(stream, m_Unknown2); + BinaryIO::BinaryRead(stream, m_Unknown3); + BinaryIO::BinaryRead(stream, m_Unknown4); + BinaryIO::BinaryRead(stream, m_ScaleFactor); + + // read all vertices in + + for (uint64_t i = 0; i < width * height; i++) { + float value; + BinaryIO::BinaryRead(stream, value); + m_FloatMap.push_back(value); + } +} + +RawHeightMap::~RawHeightMap() { + +} diff --git a/dNavigation/dTerrain/RawHeightMap.h b/dNavigation/dTerrain/RawHeightMap.h new file mode 100644 index 00000000..9a4bda3b --- /dev/null +++ b/dNavigation/dTerrain/RawHeightMap.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include + +class RawHeightMap { +public: + RawHeightMap(); + RawHeightMap(std::ifstream& stream, float height, float width); + ~RawHeightMap(); + + uint32_t m_Unknown1; + uint32_t m_Unknown2; + uint32_t m_Unknown3; + uint32_t m_Unknown4; + + float m_ScaleFactor; + + std::vector m_FloatMap = {}; +}; diff --git a/dNavigation/dTerrain/RawMesh.h b/dNavigation/dTerrain/RawMesh.h new file mode 100644 index 00000000..ed8eb4f3 --- /dev/null +++ b/dNavigation/dTerrain/RawMesh.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "NiPoint3.h" + +struct RawMesh { + std::vector m_Vertices; + std::vector m_Triangles; +}; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index df5484fd..74c730f6 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -233,9 +233,9 @@ int main(int argc, char** argv) { //Load our level: if (zoneID != 0) { + dZoneManager::Instance()->Initialize(LWOZONEID(zoneID, instanceID, cloneID)); dpWorld::Instance().Initialize(zoneID); Game::physicsWorld = &dpWorld::Instance(); //just in case some old code references it - dZoneManager::Instance()->Initialize(LWOZONEID(zoneID, instanceID, cloneID)); g_CloneID = cloneID; // pre calculate the FDB checksum diff --git a/dZoneManager/Zone.h b/dZoneManager/Zone.h index 5d3dc424..50530273 100644 --- a/dZoneManager/Zone.h +++ b/dZoneManager/Zone.h @@ -190,6 +190,8 @@ public: uint32_t GetWorldID() const { return m_WorldID; } [[nodiscard]] std::string GetZoneName() const { return m_ZoneName; } + std::string GetZoneRawPath() const { return m_ZoneRawPath;} + std::string GetZonePath() const { return m_ZonePath; } const NiPoint3& GetSpawnPos() const { return m_Spawnpoint; } const NiQuaternion& GetSpawnRot() const { return m_SpawnpointRotation; }