mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-25 11:21:58 +01:00
Tools: MeshExtractor is working now. Please note that this is not yet finished
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user