diff options
-rw-r--r-- | src/tools/mesh_extractor/Cache.h | 28 | ||||
-rw-r--r-- | src/tools/mesh_extractor/Constants.h | 7 | ||||
-rw-r--r-- | src/tools/mesh_extractor/ContinentBuilder.cpp | 29 | ||||
-rw-r--r-- | src/tools/mesh_extractor/Geometry.cpp | 21 | ||||
-rw-r--r-- | src/tools/mesh_extractor/Geometry.h | 2 | ||||
-rw-r--r-- | src/tools/mesh_extractor/MPQManager.cpp | 2 | ||||
-rw-r--r-- | src/tools/mesh_extractor/MapChunk.cpp | 12 | ||||
-rw-r--r-- | src/tools/mesh_extractor/MapChunk.h | 3 | ||||
-rw-r--r-- | src/tools/mesh_extractor/MeshExtractor.cpp | 4 | ||||
-rw-r--r-- | src/tools/mesh_extractor/TileBuilder.cpp | 201 | ||||
-rw-r--r-- | src/tools/mesh_extractor/TileBuilder.h | 7 | ||||
-rw-r--r-- | src/tools/mesh_extractor/Utils.h | 16 | ||||
-rw-r--r-- | src/tools/mesh_extractor/WorldModelHandler.cpp | 2 |
13 files changed, 308 insertions, 26 deletions
diff --git a/src/tools/mesh_extractor/Cache.h b/src/tools/mesh_extractor/Cache.h index 2693ce4e1e1..799878bdd3b 100644 --- a/src/tools/mesh_extractor/Cache.h +++ b/src/tools/mesh_extractor/Cache.h @@ -1,12 +1,14 @@ #ifndef CACHE_H #define CACHE_H #include <string> +#include <map> #include "Common.h" class WorldModelRoot; class Model; +class ADT; -template<class T> +template<class K, class T> class GenericCache { public: @@ -14,32 +16,42 @@ public: static const int32 FlushLimit = 1000; - void Insert(std::string key, T* val) + void Insert(K key, T* val) { if (_items.size() > FlushLimit) Clear(); _items[key] = val; } - T* Get(std::string key) + T* Get(K key) { - UNORDERED_MAP<std::string, T*>::iterator itr = _items.find(key); + std::map<K, T*>::iterator itr = _items.find(key); if (itr != _items.end()) return itr->second; return NULL; } - void Clear() { _items.clear(); } + void Clear() + { + for (std::map<K, T*>::iterator itr = _items.begin(); itr != _items.end(); ++itr) + delete itr->second; + _items.clear(); + } private: - UNORDERED_MAP<std::string, T*> _items; + std::map<K, T*> _items; }; class CacheClass { public: CacheClass() {} - GenericCache<Model> ModelCache; - GenericCache<WorldModelRoot> WorldModelCache; + GenericCache<std::string, Model> ModelCache; + GenericCache<std::string, WorldModelRoot> WorldModelCache; + GenericCache<std::pair<int32,int32>, ADT> AdtCache; + void Clear() + { + AdtCache.Clear(); + } }; extern CacheClass* Cache; diff --git a/src/tools/mesh_extractor/Constants.h b/src/tools/mesh_extractor/Constants.h index 38fa0b2e35b..f44d5f16797 100644 --- a/src/tools/mesh_extractor/Constants.h +++ b/src/tools/mesh_extractor/Constants.h @@ -22,6 +22,13 @@ public: POLY_AREA_ROAD = 3, POLY_AREA_DANGER = 4, }; + + enum PolyFlag + { + POLY_FLAG_WALK = 1, + POLY_FLAG_SWIM = 2, + POLY_FLAG_FLIGHTMASTER = 4 + }; static const float TileSize; static const float MaxXY; static const float ChunkSize; diff --git a/src/tools/mesh_extractor/ContinentBuilder.cpp b/src/tools/mesh_extractor/ContinentBuilder.cpp index 8af6f3a02e8..f861dff1648 100644 --- a/src/tools/mesh_extractor/ContinentBuilder.cpp +++ b/src/tools/mesh_extractor/ContinentBuilder.cpp @@ -1,11 +1,38 @@ #include "ContinentBuilder.h" +#include "TileBuilder.h" #include "WDT.h" #include "Utils.h" +#include "DetourNavMesh.h" void ContinentBuilder::Build() { + FILE* mmap = fopen("608.mmap", "wb"); + dtNavMeshParams params; + params.maxPolys = 32768; + params.maxTiles = 4096; + params.orig[0] = -17066.666f; + params.orig[1] = 0.0f; + params.orig[2] = -17066.666f; + params.tileHeight = 533.33333f; + params.tileWidth = 533.33333f; + fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap); + fclose(mmap); for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr) { - + TileBuilder builder(Continent, itr->X, itr->Y, TileMap); + char buff[100]; + sprintf(buff, "%03u%02u%02u.mmtile", builder.MapId, itr->X, itr->Y); + FILE* f = fopen(buff, "wb"); + uint8* nav = builder.Build(); + if (nav) + { + MmapTileHeader header; + header.size = builder.DataSize; + fwrite(&header, sizeof(MmapTileHeader), 1, f); + fwrite(nav, sizeof(uint8), builder.DataSize, f); + } + fclose(f); + dtFree(nav); + printf("[%02u,%02u] Tile Built!\n", itr->X, itr->Y); } } diff --git a/src/tools/mesh_extractor/Geometry.cpp b/src/tools/mesh_extractor/Geometry.cpp index 130258b6908..2fbe99e3211 100644 --- a/src/tools/mesh_extractor/Geometry.cpp +++ b/src/tools/mesh_extractor/Geometry.cpp @@ -1,5 +1,8 @@ #include "Geometry.h" #include "Constants.h" +#include "ADT.h" +#include "WorldModelHandler.h" +#include "DoodadHandler.h" Geometry::Geometry() : Transform(false) { @@ -100,3 +103,21 @@ void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas ) } } +void Geometry::AddAdt( ADT* adt ) +{ + for (std::vector<MapChunk*>::iterator itr = adt->MapChunks.begin(); itr != adt->MapChunks.end(); ++itr) + { + std::vector<Triangle<uint32> > tmp; + tmp.reserve((*itr)->Triangles.size()); + for (std::vector<Triangle<uint8> >::iterator itr2 = (*itr)->Triangles.begin(); itr2 != (*itr)->Triangles.end(); ++itr2) + tmp.push_back(Triangle<uint32>(itr2->Type, itr2->V0, itr2->V1, itr2->V2)); + AddData((*itr)->Vertices, tmp); + } + + if (!adt->_DoodadHandler->Triangles.empty()) + AddData(adt->_DoodadHandler->Vertices, adt->_DoodadHandler->Triangles); + + if (!adt->_WorldModelHandler->Triangles.empty()) + AddData(adt->_WorldModelHandler->Vertices, adt->_WorldModelHandler->Triangles); +} + diff --git a/src/tools/mesh_extractor/Geometry.h b/src/tools/mesh_extractor/Geometry.h index 048d9fde578..9593c98044e 100644 --- a/src/tools/mesh_extractor/Geometry.h +++ b/src/tools/mesh_extractor/Geometry.h @@ -4,6 +4,7 @@ #include "Utils.h" +class ADT; class Geometry { public: @@ -12,6 +13,7 @@ public: void CalculateBoundingBox(float*& min, float*& max); void CalculateMinMaxHeight(float& min, float& max); void AddData(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris); + void AddAdt(ADT* adt); void GetRawData(float*& verts, int*& tris, uint8*& areas); std::vector<Vector3> Vertices; diff --git a/src/tools/mesh_extractor/MPQManager.cpp b/src/tools/mesh_extractor/MPQManager.cpp index 429b09ffe02..35d4c91fc14 100644 --- a/src/tools/mesh_extractor/MPQManager.cpp +++ b/src/tools/mesh_extractor/MPQManager.cpp @@ -46,7 +46,7 @@ void MPQManager::LoadMPQs() sprintf(filename, "Data/%s", Files[i]); Archives.push_front(new MPQArchive(filename)); } - printf("Loaded %u MPQ files succesfully", Archives.size()); + printf("Loaded %u MPQ files succesfully\n", Archives.size()); } FILE* MPQManager::GetFile( std::string path ) diff --git a/src/tools/mesh_extractor/MapChunk.cpp b/src/tools/mesh_extractor/MapChunk.cpp index 0b02a2a4a14..61c106f9766 100644 --- a/src/tools/mesh_extractor/MapChunk.cpp +++ b/src/tools/mesh_extractor/MapChunk.cpp @@ -2,7 +2,7 @@ #include "ADT.h" #include "LiquidHandler.h" -MapChunk::MapChunk( ADT* _adt, Chunk* chunk ) : Adt(_adt), Source(chunk), Vertices(NULL) +MapChunk::MapChunk( ADT* _adt, Chunk* chunk ) : Adt(_adt), Source(chunk) { FILE* stream = chunk->GetStream(); Header.Read(stream); @@ -46,16 +46,10 @@ void MapChunk::GenerateTriangles() } } -MapChunk::~MapChunk() -{ - delete[] Vertices; -} - void MapChunk::GenerateVertices( FILE* stream ) { fseek(stream, Header.OffsetMCVT, SEEK_CUR); - int32 vertIndex = 0; - Vertices = new Vector3[125]; + Vertices.reserve(125); for (int j = 0; j < 17; j++) { @@ -67,7 +61,7 @@ void MapChunk::GenerateVertices( FILE* stream ) Vector3 vert(Header.Position.x - (j * (Constants::UnitSize * 0.5f)), Header.Position.y - (i * Constants::UnitSize), Header.Position.z + tmp); if (values == 8) vert.y -= Constants::UnitSize * 0.5f; - Vertices[vertIndex++] = vert; + Vertices.push_back(vert); } } } diff --git a/src/tools/mesh_extractor/MapChunk.h b/src/tools/mesh_extractor/MapChunk.h index 9d7b02bbfe5..61dcabac9b0 100644 --- a/src/tools/mesh_extractor/MapChunk.h +++ b/src/tools/mesh_extractor/MapChunk.h @@ -10,7 +10,6 @@ class MapChunk { public: MapChunk(ADT* _adt, Chunk* chunk); - ~MapChunk(); void GenerateTriangles(); void GenerateVertices(FILE* stream); @@ -18,7 +17,7 @@ public: ADT* Adt; Chunk* Source; MapChunkHeader Header; - Vector3* Vertices; + std::vector<Vector3> Vertices; std::vector<Triangle<uint8> > Triangles; int32 Index; }; diff --git a/src/tools/mesh_extractor/MeshExtractor.cpp b/src/tools/mesh_extractor/MeshExtractor.cpp index 0611c9c2d58..38a120449bc 100644 --- a/src/tools/mesh_extractor/MeshExtractor.cpp +++ b/src/tools/mesh_extractor/MeshExtractor.cpp @@ -15,10 +15,10 @@ void ExtractAllMaps() WDT wdt("World\\maps\\DalaranPrison\\DalaranPrison.wdt"); if (!wdt.IsValid) return; - printf("Model valid!"); + printf("Model valid!\n"); if (wdt.IsGlobalModel) { - printf("Unsupported"); + printf("Unsupported\n"); return; } ContinentBuilder builder("DalaranPrison", &wdt); diff --git a/src/tools/mesh_extractor/TileBuilder.cpp b/src/tools/mesh_extractor/TileBuilder.cpp index 190607493fa..4736274706d 100644 --- a/src/tools/mesh_extractor/TileBuilder.cpp +++ b/src/tools/mesh_extractor/TileBuilder.cpp @@ -1,7 +1,15 @@ #include "TileBuilder.h" +#include "Geometry.h" #include "Constants.h" +#include "Utils.h" +#include "Cache.h" +#include "ADT.h" +#include "WDT.h" +#include "Recast.h" +#include "RecastAlloc.h" +#include "DetourNavMeshBuilder.h" -TileBuilder::TileBuilder(std::string world, int x, int y) : _Geometry(NULL), World(world), X(x), Y(y), MapId(608) +TileBuilder::TileBuilder(std::string world, int x, int y, WDT* wdt) : _Geometry(NULL), World(world), X(x), Y(y), MapId(608), DataSize(0), Wdt(wdt) { // Cell Size = TileSize / TileVoxelSize // 1800 = TileVoxelSize @@ -23,6 +31,8 @@ TileBuilder::TileBuilder(std::string world, int x, int y) : _Geometry(NULL), Wor Config.width = 1800; Config.maxVertsPerPoly = 6; Config.maxSimplificationError = 1.3f; + + Context = new rcContext; } void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax ) @@ -34,3 +44,192 @@ void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax ) bmax[0] = Constants::Origin[0] + (Constants::TileSize * (X + 1)); bmax[2] = Constants::Origin[2] + (Constants::TileSize * (Y + 1)); } + +uint8* TileBuilder::Build() +{ + _Geometry = new Geometry(); + _Geometry->Transform = true; + ADT* adt = Cache->AdtCache.Get(std::make_pair(X, Y)); + if (!adt) + { + adt = new ADT(Utils::GetAdtPath(World, X, Y)); + adt->Read(); + Cache->AdtCache.Insert(std::make_pair(X, Y), adt); + } + _Geometry->AddAdt(adt); + + if (_Geometry->Vertices.empty() && _Geometry->Triangles.empty()) + return NULL; + + float* bbMin; + float* bbMax; + CalculateTileBounds(bbMin, bbMax); + _Geometry->CalculateMinMaxHeight(bbMin[1], bbMax[1]); + + // again, we load everything - wasteful but who cares + for (int ty = Y - 1; ty <= Y + 1; ty++) + { + for (int tx = X - 1; tx <= X + 1; tx++) + { + // don't load main tile again + if (tx == X && ty == Y) + continue; + + ADT* _adt = Cache->AdtCache.Get(std::make_pair(tx, ty)); + if (!_adt) + { + _adt = new ADT(Utils::GetAdtPath(World, tx, ty)); + // If this condition is met, it means that this wdt does not contain the ADT + if (!_adt->Data->Stream) + { + delete _adt; + continue; + } + _adt->Read(); + Cache->AdtCache.Insert(std::make_pair(tx, ty), _adt); + } + _Geometry->AddAdt(adt); + } + } + uint32 numVerts = _Geometry->Vertices.size(); + uint32 numTris = _Geometry->Triangles.size(); + float* vertices; + int* triangles; + uint8* areas; + _Geometry->GetRawData(vertices, triangles, areas); + _Geometry->Vertices.clear(); + _Geometry->Triangles.clear(); + + bbMin[0] -= Config.borderSize * Config.cs; + bbMin[2] -= Config.borderSize * Config.cs; + bbMax[0] += Config.borderSize * Config.cs; + bbMax[0] += Config.borderSize * Config.cs; + + rcHeightfield* hf = rcAllocHeightfield(); + int width = Config.width + (Config.borderSize * 2); + rcCreateHeightfield(Context, *hf, width, width, bbMin, bbMax, Config.cs, Config.ch); + rcClearUnwalkableTriangles(Context, Config.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas); + rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, Config.walkableClimb); + + printf("[%02u,%02u] Triangles rasterized!\n", X, Y); + + // Once all geometry is rasterized, we do initial pass of filtering to + // remove unwanted overhangs caused by the conservative rasterization + // as well as filter spans where the character cannot possibly stand. + rcFilterLowHangingWalkableObstacles(Context, Config.walkableClimb, *hf); + rcFilterLedgeSpans(Context, Config.walkableHeight, Config.walkableClimb, *hf); + rcFilterWalkableLowHeightSpans(Context, Config.walkableHeight, *hf); + + printf("[%02u,%02u] Filtering done!\n", X, Y); + + // Compact the heightfield so that it is faster to handle from now on. + // This will result in more cache coherent data as well as the neighbours + // between walkable cells will be calculated. + rcCompactHeightfield* chf = rcAllocCompactHeightfield(); + rcBuildCompactHeightfield(Context, Config.walkableHeight, Config.walkableClimb, *hf, *chf); + + rcFreeHeightField(hf); + + printf("[%02u,%02u] Heightfield compressed!\n", X, Y); + + // Erode the walkable area by agent radius. + rcErodeWalkableArea(Context, Config.walkableRadius, *chf); + // Prepare for region partitioning, by calculating distance field along the walkable surface. + rcBuildDistanceField(Context, *chf); + // Partition the walkable surface into simple regions without holes. + rcBuildRegions(Context, *chf, Config.borderSize, Config.minRegionArea, Config.mergeRegionArea); + + printf("[%02u,%02u] Regions built!\n", X, Y); + + // Create contours. + rcContourSet* cset = rcAllocContourSet(); + rcBuildContours(Context, *chf, Config.maxSimplificationError, Config.maxEdgeLen, *cset); + + // Build polygon navmesh from the contours. + rcPolyMesh* pmesh = rcAllocPolyMesh(); + rcBuildPolyMesh(Context, *cset, Config.maxVertsPerPoly, *pmesh); + + printf("[%02u,%02u] Polymesh built!\n", X, Y); + + // Build detail mesh. + rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail(); + rcBuildPolyMeshDetail(Context, *pmesh, *chf, Config.detailSampleDist, Config.detailSampleMaxError, *dmesh); + + printf("[%02u,%02u] Polymesh detail built!\n", X, Y); + + rcFreeCompactHeightfield(chf); + rcFreeContourSet(cset); + + // Remove padding from the polymesh data. (Remove this odditity) + for (int i = 0; i < pmesh->nverts; ++i) + { + unsigned short* v = &pmesh->verts[i * 3]; + v[0] -= (unsigned short)Config.borderSize; + v[2] -= (unsigned short)Config.borderSize; + } + + // Set flags according to area types (e.g. Swim for Water) + for (int i = 0; i < pmesh->npolys; i++) + { + if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN) + pmesh->flags[i] = Constants::POLY_FLAG_WALK; + else if (pmesh->areas[i] == (int)Constants::POLY_AREA_WATER) + pmesh->flags[i] = Constants::POLY_FLAG_SWIM; + } + + // get original bounds + float* tilebMin; + float* tilebMax; + CalculateTileBounds(tilebMin, tilebMax); + tilebMin[1] = bbMin[1]; + tilebMax[1] = bbMax[1]; + + dtNavMeshCreateParams params; + // PolyMesh data + params.verts = pmesh->verts; + params.vertCount = pmesh->nverts; + params.polys = pmesh->polys; + params.polyAreas = pmesh->areas; + params.polyFlags = pmesh->flags; + params.polyCount = pmesh->npolys; + params.nvp = pmesh->nvp; + // PolyMeshDetail data + params.detailMeshes = dmesh->meshes; + params.detailVerts = dmesh->verts; + params.detailVertsCount = dmesh->nverts; + params.detailTris = dmesh->tris; + params.detailTriCount = dmesh->ntris; + // Copy bounding box + params.bmin[0] = tilebMin[0]; + params.bmin[1] = tilebMin[1]; + params.bmin[2] = tilebMin[2]; + params.bmax[0] = tilebMax[0]; + params.bmax[1] = tilebMax[1]; + params.bmax[2] = tilebMax[2]; + // General settings + params.ch = Config.ch; + params.cs = Config.cs; + params.walkableClimb = Config.walkableClimb; + params.walkableHeight = Config.walkableHeight; + params.walkableRadius = Config.walkableRadius; + params.tileX = X; + params.tileY = Y; + params.tileSize = Config.width; + int navDataSize; + uint8* navData; + printf("[%02u,%02u] Creating the navmesh!\n", X, Y); + bool result = dtCreateNavMeshData(¶ms, &navData, &navDataSize); + if (result) + { + printf("[%02u,%02u] NavMesh created, size %u!\n", X, Y, navDataSize); + DataSize = navDataSize; + rcFreePolyMesh(pmesh); + rcFreePolyMeshDetail(dmesh); + Cache->Clear(); + return navData; + } + + rcFreePolyMesh(pmesh); + rcFreePolyMeshDetail(dmesh); + return NULL; +} diff --git a/src/tools/mesh_extractor/TileBuilder.h b/src/tools/mesh_extractor/TileBuilder.h index badb05295e5..7dff363cabe 100644 --- a/src/tools/mesh_extractor/TileBuilder.h +++ b/src/tools/mesh_extractor/TileBuilder.h @@ -5,10 +5,12 @@ #include "Geometry.h" +class WDT; + class TileBuilder { public: - TileBuilder(std::string world, int x, int y); + TileBuilder(std::string world, int x, int y, WDT* wdt); void CalculateTileBounds(float*& bmin, float*& bmax); uint8* Build(); @@ -17,6 +19,9 @@ public: int Y; int MapId; rcConfig Config; + rcContext* Context; Geometry* _Geometry; + uint32 DataSize; + WDT* Wdt; }; #endif
\ No newline at end of file diff --git a/src/tools/mesh_extractor/Utils.h b/src/tools/mesh_extractor/Utils.h index ac14b9eca69..4cf20a4cf9d 100644 --- a/src/tools/mesh_extractor/Utils.h +++ b/src/tools/mesh_extractor/Utils.h @@ -5,6 +5,7 @@ #include <sstream> #include "g3d/Matrix4.h" +#include "DetourNavMesh.h" #include "Common.h" #include "Constants.h" @@ -523,6 +524,21 @@ public: virtual float Scale() const { return 1.0f; }; }; +#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' +#define MMAP_VERSION 3 + +struct MmapTileHeader +{ + uint32 mmapMagic; + uint32 dtVersion; + uint32 mmapVersion; + uint32 size; + bool usesLiquids : 1; + + MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION), + mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {} +}; + class Utils { public: diff --git a/src/tools/mesh_extractor/WorldModelHandler.cpp b/src/tools/mesh_extractor/WorldModelHandler.cpp index e5a14d55c0c..1a772a36558 100644 --- a/src/tools/mesh_extractor/WorldModelHandler.cpp +++ b/src/tools/mesh_extractor/WorldModelHandler.cpp @@ -92,7 +92,7 @@ void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::v } } - if (def.DoodadSet >= 0 && def.DoodadSet < root->DoodadSets.size()) + if (def.DoodadSet < root->DoodadSets.size()) { DoodadSet set = root->DoodadSets[def.DoodadSet]; std::vector<DoodadInstance> instances; |