mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-20 06:59:46 -04:00
9b97a89ef8
First glances of multithreading ( need to figure out a way around StormLib )
245 lines
8.4 KiB
C++
245 lines
8.4 KiB
C++
#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, uint32 mapId) : _Geometry(NULL), World(world), X(x), Y(y), MapId(mapId), DataSize(0)
|
|
{
|
|
// Cell Size = TileSize / TileVoxelSize
|
|
// 1800 = TileVoxelSize
|
|
Config.cs = Constants::TileSize / 1800;
|
|
// Cell Height
|
|
Config.ch = 0.3f;
|
|
// Min Region Area = 6^2
|
|
Config.minRegionArea = 36;
|
|
// Merge Region Area = 12^2
|
|
Config.mergeRegionArea = 144;
|
|
Config.walkableSlopeAngle = 50.0f;
|
|
Config.detailSampleDist = 3.0f;
|
|
Config.detailSampleMaxError = 1.25f;
|
|
Config.walkableClimb = 1.0f / Config.ch;
|
|
Config.walkableHeight = 2.1f / Config.ch;
|
|
Config.walkableRadius = 0.6f / Config.cs;
|
|
Config.maxEdgeLen = Config.walkableRadius * 8;
|
|
Config.borderSize = Config.walkableRadius + 8;
|
|
Config.width = 1800;
|
|
Config.maxVertsPerPoly = 6;
|
|
Config.maxSimplificationError = 1.3f;
|
|
|
|
Context = new rcContext;
|
|
}
|
|
|
|
void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax )
|
|
{
|
|
bmin = new float[3];
|
|
bmax = new float[3];
|
|
bmin[0] = Constants::Origin[0] + (Constants::TileSize * X);
|
|
bmin[2] = Constants::Origin[2] + (Constants::TileSize * Y);
|
|
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();
|
|
if (!adt->Data)
|
|
{
|
|
delete adt;
|
|
return NULL;
|
|
}
|
|
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("[%02i,%02i] 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("[%02i,%02i] 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("[%02i,%02i] 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("[%02i,%02i] 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("[%02i,%02i] Polymesh built!\n", X, Y);
|
|
|
|
// Build detail mesh.
|
|
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
|
|
rcBuildPolyMeshDetail(Context, *pmesh, *chf, Config.detailSampleDist, Config.detailSampleMaxError, *dmesh);
|
|
|
|
printf("[%02i,%02i] 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;
|
|
|
|
// Offmesh-connection settings
|
|
params.offMeshConCount = 0; // none for now
|
|
|
|
int navDataSize;
|
|
uint8* navData;
|
|
printf("[%02i,%02i] Creating the navmesh!\n", X, Y);
|
|
bool result = dtCreateNavMeshData(¶ms, &navData, &navDataSize);
|
|
if (result)
|
|
{
|
|
printf("[%02i,%02i] NavMesh created, size %i!\n", X, Y, navDataSize);
|
|
DataSize = navDataSize;
|
|
rcFreePolyMesh(pmesh);
|
|
rcFreePolyMeshDetail(dmesh);
|
|
Cache->Clear();
|
|
return navData;
|
|
}
|
|
|
|
rcFreePolyMesh(pmesh);
|
|
rcFreePolyMeshDetail(dmesh);
|
|
return NULL;
|
|
}
|