From e5f445e9c8e77eda67275b0e9c9c38440db9453c Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 20 Jul 2022 15:07:51 +0200 Subject: [PATCH] NavEditor cleanup Moved functions and structures to their own files. --- r5dev/naveditor/GameUtils.cpp | 174 +++++++++++++++++ r5dev/naveditor/Sample.cpp | 250 ++---------------------- r5dev/naveditor/include/FileTypes.h | 67 +++++++ r5dev/naveditor/include/GameUtils.h | 20 ++ r5dev/naveditor/include/MeshLoaderObj.h | 6 +- r5dev/vproj/naveditor.vcxproj | 3 + r5dev/vproj/naveditor.vcxproj.filters | 9 + 7 files changed, 294 insertions(+), 235 deletions(-) create mode 100644 r5dev/naveditor/GameUtils.cpp create mode 100644 r5dev/naveditor/include/FileTypes.h create mode 100644 r5dev/naveditor/include/GameUtils.h diff --git a/r5dev/naveditor/GameUtils.cpp b/r5dev/naveditor/GameUtils.cpp new file mode 100644 index 00000000..e2cfcce9 --- /dev/null +++ b/r5dev/naveditor/GameUtils.cpp @@ -0,0 +1,174 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#include "pch.h" +#include "NavEditor/include/GameUtils.h" +#include "NavEditor/include/FileTypes.h" + +void coordGameSwap(float* c) +{ + std::swap(c[1], c[2]); + c[2] *= -1; +} +void coordGameUnswap(float* c) +{ + c[2] *= -1; + std::swap(c[1], c[2]); +} +void coordShortGameSwap(unsigned short* c) +{ + std::swap(c[1], c[2]); + c[2] = std::numeric_limits::max() - c[2]; +} +void coordShortGameUnswap(unsigned short* c) +{ + c[2] = std::numeric_limits::max() - c[2]; + std::swap(c[1], c[2]); +} +void patchHeaderGame(NavMeshSetHeader& h) +{ + coordGameSwap(h.params.orig); +} +void unpatchHeaderGame(NavMeshSetHeader& h) +{ + coordGameUnswap(h.params.orig); +} + +void patchTileGame(dtMeshTile* t) +{ + coordGameSwap(t->header->bmin); + coordGameSwap(t->header->bmax); + + for (size_t i = 0; i < t->header->vertCount * 3; i += 3) + coordGameSwap(t->verts + i); + for (size_t i = 0; i < t->header->detailVertCount * 3; i += 3) + coordGameSwap(t->detailVerts + i); + for (size_t i = 0; i < t->header->polyCount; i++) + coordGameSwap(t->polys[i].org); + //might be wrong because of coord change might break tree layout + for (size_t i = 0; i < t->header->bvNodeCount; i++) + { + coordShortGameSwap(t->bvTree[i].bmax); + coordShortGameSwap(t->bvTree[i].bmin); + } + for (size_t i = 0; i < t->header->offMeshConCount; i++) + { + coordGameSwap(t->offMeshCons[i].pos); + coordGameSwap(t->offMeshCons[i].pos + 3); + coordGameSwap(t->offMeshCons[i].unk); + } +} +void unpatchTileGame(dtMeshTile* t) +{ + coordGameUnswap(t->header->bmin); + coordGameUnswap(t->header->bmax); + + for (size_t i = 0; i < t->header->vertCount * 3; i += 3) + coordGameUnswap(t->verts + i); + for (size_t i = 0; i < t->header->detailVertCount * 3; i += 3) + coordGameUnswap(t->detailVerts + i); + for (size_t i = 0; i < t->header->polyCount; i++) + coordGameUnswap(t->polys[i].org); + //might be wrong because of coord change might break tree layout + for (size_t i = 0; i < t->header->bvNodeCount; i++) + { + coordShortGameUnswap(t->bvTree[i].bmax); + coordShortGameUnswap(t->bvTree[i].bmin); + } + for (size_t i = 0; i < t->header->offMeshConCount; i++) + { + coordGameUnswap(t->offMeshCons[i].pos); + coordGameUnswap(t->offMeshCons[i].pos + 3); + coordGameUnswap(t->offMeshCons[i].unk); + } +} + +void buildLinkTable(dtNavMesh* mesh, LinkTableData& data) +{ + //clear all labels + for (int i = 0; i < mesh->getMaxTiles(); ++i) + { + dtMeshTile* tile = mesh->getTile(i); + if (!tile || !tile->header || !tile->dataSize) continue; + auto pcount = tile->header->polyCount; + for (int j = 0; j < pcount; j++) + { + auto& poly = tile->polys[j]; + poly.disjointSetId = -1; + } + } + //first pass + std::set nlabels; + for (int i = 0; i < mesh->getMaxTiles(); ++i) + { + dtMeshTile* tile = mesh->getTile(i); + if (!tile || !tile->header || !tile->dataSize) continue; + auto pcount = tile->header->polyCount; + for (int j = 0; j < pcount; j++) + { + auto& poly = tile->polys[j]; + auto plink = poly.firstLink; + while (plink != DT_NULL_LINK) + { + auto l = tile->links[plink]; + const dtMeshTile* t; + const dtPoly* p; + mesh->getTileAndPolyByRefUnsafe(l.ref, &t, &p); + + if (p->disjointSetId != (unsigned short)-1) + nlabels.insert(p->disjointSetId); + plink = l.next; + } + if (nlabels.empty()) + { + poly.disjointSetId = data.insert_new(); + } + else + { + auto l = *nlabels.begin(); + poly.disjointSetId = l; + for (auto nl : nlabels) + data.set_union(l, nl); + } + nlabels.clear(); + } + } + //second pass + for (int i = 0; i < mesh->getMaxTiles(); ++i) + { + dtMeshTile* tile = mesh->getTile(i); + if (!tile || !tile->header || !tile->dataSize) continue; + auto pcount = tile->header->polyCount; + for (int j = 0; j < pcount; j++) + { + auto& poly = tile->polys[j]; + auto id = data.find(poly.disjointSetId); + poly.disjointSetId = id; + } + } +} +void setReachable(std::vector& data, int count, int id1, int id2, bool value) +{ + int w = ((count + 31) / 32); + auto& cell = data[id1 * w + id2 / 32]; + uint32_t value_mask = ~(1 << (id2 & 0x1f)); + if (!value) + cell = (cell & value_mask); + else + cell = (cell & value_mask) | (1 << (id2 & 0x1f)); +} \ No newline at end of file diff --git a/r5dev/naveditor/Sample.cpp b/r5dev/naveditor/Sample.cpp index fc2d3807..7580f82f 100644 --- a/r5dev/naveditor/Sample.cpp +++ b/r5dev/naveditor/Sample.cpp @@ -23,8 +23,10 @@ #include "DetourCrowd/Include/DetourCrowd.h" #include "DebugUtils/Include/RecastDebugDraw.h" #include "DebugUtils/Include/DetourDebugDraw.h" -#include "NavEditor/Include/Sample.h" +#include "NavEditor/Include/FileTypes.h" +#include "NavEditor/Include/GameUtils.h" #include "NavEditor/Include/InputGeom.h" +#include "NavEditor/Include/Sample.h" unsigned int SampleDebugDraw::areaToCol(unsigned int area) { @@ -330,222 +332,8 @@ void Sample::renderOverlayToolStates(double* proj, double* model, int* view) } } -static const int NAVMESHSET_MAGIC = 'M'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'MSET'; -static const int NAVMESHSET_VERSION = 8; - -struct NavMeshSetHeader -{ - int magic; - int version; - int numTiles; - dtNavMeshParams params; -}; - -struct NavMeshTileHeader -{ - dtTileRef tileRef; - int dataSize; -}; - -void coord_tf_fix(float* c) -{ - std::swap(c[1], c[2]); - c[2] *= -1; -} -void coord_tf_unfix(float* c) -{ - c[2] *= -1; - std::swap(c[1], c[2]); -} -void coord_short_tf_fix(unsigned short* c) -{ - std::swap(c[1], c[2]); - c[2] = std::numeric_limits::max() - c[2]; -} -void coord_short_tf_unfix(unsigned short* c) -{ - c[2] = std::numeric_limits::max() - c[2]; - std::swap(c[1], c[2]); -} -void patch_headertf2(NavMeshSetHeader& h) -{ - coord_tf_fix(h.params.orig); -} -void unpatch_headertf2(NavMeshSetHeader& h) -{ - coord_tf_unfix(h.params.orig); -} - -void patch_tiletf2(dtMeshTile* t) -{ - coord_tf_fix(t->header->bmin); - coord_tf_fix(t->header->bmax); - - for (size_t i = 0; i < t->header->vertCount * 3; i += 3) - coord_tf_fix(t->verts + i); - for (size_t i = 0; i < t->header->detailVertCount * 3; i += 3) - coord_tf_fix(t->detailVerts + i); - for (size_t i = 0; i < t->header->polyCount; i++) - coord_tf_fix(t->polys[i].org); - //might be wrong because of coord change might break tree layout - for (size_t i = 0; i < t->header->bvNodeCount; i++) - { - coord_short_tf_fix(t->bvTree[i].bmax); - coord_short_tf_fix(t->bvTree[i].bmin); - } - for (size_t i = 0; i < t->header->offMeshConCount; i++) - { - coord_tf_fix(t->offMeshCons[i].pos); - coord_tf_fix(t->offMeshCons[i].pos + 3); - coord_tf_fix(t->offMeshCons[i].unk); - } -} -void unpatch_tiletf2(dtMeshTile* t) -{ - coord_tf_unfix(t->header->bmin); - coord_tf_unfix(t->header->bmax); - - for (size_t i = 0; i < t->header->vertCount * 3; i += 3) - coord_tf_unfix(t->verts + i); - for (size_t i = 0; i < t->header->detailVertCount * 3; i += 3) - coord_tf_unfix(t->detailVerts + i); - for (size_t i = 0; i < t->header->polyCount; i++) - coord_tf_unfix(t->polys[i].org); - //might be wrong because of coord change might break tree layout - for (size_t i = 0; i < t->header->bvNodeCount; i++) - { - coord_short_tf_unfix(t->bvTree[i].bmax); - coord_short_tf_unfix(t->bvTree[i].bmin); - } - for (size_t i = 0; i < t->header->offMeshConCount; i++) - { - coord_tf_unfix(t->offMeshCons[i].pos); - coord_tf_unfix(t->offMeshCons[i].pos+3); - coord_tf_unfix(t->offMeshCons[i].unk); - } -} -struct LinkTableData -{ - //disjoint set algo from some crappy site because i'm too lazy to think - int setCount = 0; - std::vector rank; - std::vector parent; - void init(int size) - { - rank.resize(size); - parent.resize(size); - - for (int i = 0; i < parent.size(); i++) - parent[i] = i; - } - int insert_new() - { - rank.push_back(0); - parent.push_back(setCount); - return setCount++; - } - int find(int id) - { - if (parent[id] != id) - return find(parent[id]); - return id; - } - void set_union(int x, int y) - { - int sx = find(x); - int sy = find(y); - if (sx == sy) //same set already - return; - - if (rank[sx] < rank[sy]) - parent[sx] = sy; - else if (rank[sx] > rank[sy]) - parent[sy] = sx; - else - { - parent[sy] = sx; - rank[sx] += 1; - } - } -}; -void build_link_table(dtNavMesh* mesh, LinkTableData& data) -{ - //clear all labels - for (int i = 0; i < mesh->getMaxTiles(); ++i) - { - dtMeshTile* tile = mesh->getTile(i); - if (!tile || !tile->header || !tile->dataSize) continue; - auto pcount = tile->header->polyCount; - for (int j = 0; j < pcount; j++) - { - auto& poly = tile->polys[j]; - poly.disjointSetId = -1; - } - } - //first pass - std::set nlabels; - for (int i = 0; i < mesh->getMaxTiles(); ++i) - { - dtMeshTile* tile = mesh->getTile(i); - if (!tile || !tile->header || !tile->dataSize) continue; - auto pcount = tile->header->polyCount; - for (int j = 0; j < pcount; j++) - { - auto& poly = tile->polys[j]; - auto plink = poly.firstLink; - while (plink != DT_NULL_LINK) - { - auto l = tile->links[plink]; - const dtMeshTile* t; - const dtPoly* p; - mesh->getTileAndPolyByRefUnsafe(l.ref, &t, &p); - - if (p->disjointSetId != (unsigned short)-1) - nlabels.insert(p->disjointSetId); - plink = l.next; - } - if (nlabels.empty()) - { - poly.disjointSetId = data.insert_new(); - } - else - { - auto l = *nlabels.begin(); - poly.disjointSetId = l; - for (auto nl : nlabels) - data.set_union(l, nl); - } - nlabels.clear(); - } - } - //second pass - for (int i = 0; i < mesh->getMaxTiles(); ++i) - { - dtMeshTile* tile = mesh->getTile(i); - if (!tile || !tile->header || !tile->dataSize) continue; - auto pcount = tile->header->polyCount; - for (int j = 0; j < pcount; j++) - { - auto& poly = tile->polys[j]; - auto id = data.find(poly.disjointSetId); - poly.disjointSetId = id; - } - } -} -void set_reachable(std::vector& data, int count, int id1, int id2, bool value) -{ - int w = ((count + 31) / 32); - auto& cell = data[id1 * w + id2 / 32]; - uint32_t value_mask = ~(1 << (id2 & 0x1f)); - if (!value) - cell = (cell & value_mask); - else - cell = (cell & value_mask) | (1 << (id2 & 0x1f)); -} - dtNavMesh* Sample::loadAll(const char* path) { - char buffer[256]; sprintf(buffer, "%s_%s.nm", path, m_navmeshName); @@ -577,7 +365,7 @@ dtNavMesh* Sample::loadAll(const char* path) fclose(fp); return 0; } - if(*is_tf2) patch_headertf2(header); + if(*is_tf2) patchHeaderGame(header); dtStatus status = mesh->init(&header.params); if (dtStatusFailed(status)) { @@ -612,7 +400,7 @@ dtNavMesh* Sample::loadAll(const char* path) dtTileRef result; mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, &result); auto tile = const_cast(mesh->getTileByRef(result)); - if (*is_tf2) patch_tiletf2(tile); + if (*is_tf2) patchTileGame(tile); } fclose(fp); @@ -652,13 +440,13 @@ void Sample::saveAll(std::string path, dtNavMesh* mesh) } memcpy(&header.params, mesh->getParams(), sizeof(dtNavMeshParams)); - //LinkTableData link_data; - //build_link_table(mesh, link_data); - //int table_size = ((link_data.setCount + 31) / 32) * link_data.setCount * 32; + //LinkTableData linkData; + //buildLinkTable(mesh, linkData); + //int tableSize = ((linkData.setCount + 31) / 32) * linkData.setCount * 32; - //std::vector reachability(table_size, 0); - //for (int i = 0; i < link_data.setCount; i++) - // set_reachable(reachability, link_data.setCount, i, i, true); + //std::vector reachability(tableSize, 0); + //for (int i = 0; i < linkData.setCount; i++) + // setReachable(reachability, linkData.setCount, i, i, true); //if (reachability.size() > 0) //{ @@ -667,22 +455,22 @@ void Sample::saveAll(std::string path, dtNavMesh* mesh) // if (reachability[i] == 0) // { // reachability.erase(reachability.begin() + i); - // table_size--; + // tableSize--; // } // else // break; // } //} - //header.params.disjointPolyGroupCount = link_data.setCount; + //header.params.disjointPolyGroupCount = linkData.setCount; //header.params.reachabilityTableCount = m_reachabilityTableCount; - //header.params.reachabilityTableSize = table_size; + //header.params.reachabilityTableSize = tableSize; header.params.disjointPolyGroupCount = 4; header.params.reachabilityTableCount = m_reachabilityTableCount; header.params.reachabilityTableSize = ((header.params.disjointPolyGroupCount + 31) / 32) * header.params.disjointPolyGroupCount * 32; - if (*is_tf2)unpatch_headertf2(header); + if (*is_tf2)unpatchHeaderGame(header); fwrite(&header, sizeof(NavMeshSetHeader), 1, fp); // Store tiles. @@ -696,18 +484,18 @@ void Sample::saveAll(std::string path, dtNavMesh* mesh) tileHeader.dataSize = tile->dataSize; fwrite(&tileHeader, sizeof(tileHeader), 1, fp); - if (*is_tf2)unpatch_tiletf2(const_cast(tile)); + if (*is_tf2)unpatchTileGame(const_cast(tile)); fwrite(tile->data, tile->dataSize, 1, fp); - if (*is_tf2)patch_tiletf2(const_cast(tile)); + if (*is_tf2)patchTileGame(const_cast(tile)); } ////still dont know what this thing is... //int header_sth = 0; - //for (int i = 0; i < link_data.setCount; i++) + //for (int i = 0; i < linkData.setCount; i++) // fwrite(&header_sth, sizeof(int), 1, fp); //for (int i = 0; i < header.params.reachabilityTableCount; i++) - // fwrite(reachability.data(), sizeof(int), table_size, fp); + // fwrite(reachability.data(), sizeof(int), tableSize, fp); int header_sth[4] = { 0,0,0 }; fwrite(header_sth, sizeof(int), 4, fp); diff --git a/r5dev/naveditor/include/FileTypes.h b/r5dev/naveditor/include/FileTypes.h new file mode 100644 index 00000000..cbb69b35 --- /dev/null +++ b/r5dev/naveditor/include/FileTypes.h @@ -0,0 +1,67 @@ +#ifndef FILETYPES_H +#define FILETYPES_H +#include "Detour/Include/DetourNavMesh.h" + +static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET'; +static const int NAVMESHSET_VERSION = 8; + +struct NavMeshSetHeader +{ + int magic; + int version; + int numTiles; + dtNavMeshParams params; +}; + +struct NavMeshTileHeader +{ + dtTileRef tileRef; + int dataSize; +}; + +struct LinkTableData +{ + //disjoint set algo from some crappy site because i'm too lazy to think + int setCount = 0; + std::vector rank; + std::vector parent; + void init(int size) + { + rank.resize(size); + parent.resize(size); + + for (int i = 0; i < parent.size(); i++) + parent[i] = i; + } + int insert_new() + { + rank.push_back(0); + parent.push_back(setCount); + return setCount++; + } + int find(int id) + { + if (parent[id] != id) + return find(parent[id]); + return id; + } + void set_union(int x, int y) + { + int sx = find(x); + int sy = find(y); + if (sx == sy) //same set already + return; + + if (rank[sx] < rank[sy]) + parent[sx] = sy; + else if (rank[sx] > rank[sy]) + parent[sy] = sx; + else + { + parent[sy] = sx; + rank[sx] += 1; + } + } +}; + +#endif // FILETYPES_H \ No newline at end of file diff --git a/r5dev/naveditor/include/GameUtils.h b/r5dev/naveditor/include/GameUtils.h new file mode 100644 index 00000000..83b53738 --- /dev/null +++ b/r5dev/naveditor/include/GameUtils.h @@ -0,0 +1,20 @@ +#ifndef GAMEUTILS_H +#define GAMEUTILS_H +#include "NavEditor/Include/FileTypes.h" + +void coordGameSwap(float* c); +void coordGameUnswap(float* c); + +void coordShortGameSwap(unsigned short* c); +void coordShortGameUnswap(unsigned short* c); + +void patchHeaderGame(NavMeshSetHeader& h); +void unpatchHeaderGame(NavMeshSetHeader& h); + +void patchTileGame(dtMeshTile* t); +void unpatchTileGame(dtMeshTile* t); + +void buildLinkTable(dtNavMesh* mesh, LinkTableData& data); +void setReachable(std::vector& data, int count, int id1, int id2, bool value); + +#endif // GAMEUTILS_H \ No newline at end of file diff --git a/r5dev/naveditor/include/MeshLoaderObj.h b/r5dev/naveditor/include/MeshLoaderObj.h index dfeaeba1..b14e8c08 100644 --- a/r5dev/naveditor/include/MeshLoaderObj.h +++ b/r5dev/naveditor/include/MeshLoaderObj.h @@ -34,8 +34,8 @@ public: virtual int getTriCount() const = 0; virtual const std::string& getFileName() const = 0; - bool m_tf2_import_flip = false; // !TODO: ImGui import option. - bool m_flip_tris = false; // !TODO: ImGui import option. + bool m_flipAxis = false; // !TODO: ImGui import option. + bool m_flipTris = false; // !TODO: ImGui import option. }; class rcMeshLoaderObj:public IMeshLoader { @@ -67,8 +67,6 @@ private: float* m_normals; int m_vertCount; int m_triCount; - - }; #endif // MESHLOADER_OBJ diff --git a/r5dev/vproj/naveditor.vcxproj b/r5dev/vproj/naveditor.vcxproj index 685c6fe9..b4bdfac0 100644 --- a/r5dev/vproj/naveditor.vcxproj +++ b/r5dev/vproj/naveditor.vcxproj @@ -15,6 +15,8 @@ + + @@ -41,6 +43,7 @@ + diff --git a/r5dev/vproj/naveditor.vcxproj.filters b/r5dev/vproj/naveditor.vcxproj.filters index 5b7485fe..d5b2f295 100644 --- a/r5dev/vproj/naveditor.vcxproj.filters +++ b/r5dev/vproj/naveditor.vcxproj.filters @@ -111,6 +111,12 @@ core\include + + utils\include + + + io\include + @@ -188,5 +194,8 @@ core + + utils + \ No newline at end of file