aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/mesh_extractor/Cache.h28
-rw-r--r--src/tools/mesh_extractor/Constants.h7
-rw-r--r--src/tools/mesh_extractor/ContinentBuilder.cpp29
-rw-r--r--src/tools/mesh_extractor/Geometry.cpp21
-rw-r--r--src/tools/mesh_extractor/Geometry.h2
-rw-r--r--src/tools/mesh_extractor/MPQManager.cpp2
-rw-r--r--src/tools/mesh_extractor/MapChunk.cpp12
-rw-r--r--src/tools/mesh_extractor/MapChunk.h3
-rw-r--r--src/tools/mesh_extractor/MeshExtractor.cpp4
-rw-r--r--src/tools/mesh_extractor/TileBuilder.cpp201
-rw-r--r--src/tools/mesh_extractor/TileBuilder.h7
-rw-r--r--src/tools/mesh_extractor/Utils.h16
-rw-r--r--src/tools/mesh_extractor/WorldModelHandler.cpp2
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(&params, 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(&params, &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;