Tools: MeshExtractor is working now. Please note that this is not yet finished

This commit is contained in:
Subv
2012-09-28 13:30:43 -05:00
parent 1c6a44e4c5
commit 3eda479e29
13 changed files with 308 additions and 26 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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 )

View File

@@ -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);
}
}
}

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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;