1
This commit is contained in:
parent
1f57e552ff
commit
7ff62bc87e
@ -49,6 +49,39 @@ struct TileCacheData
|
||||
int dataSize;
|
||||
};
|
||||
|
||||
struct RasterizationContext
|
||||
{
|
||||
RasterizationContext() :
|
||||
solid(0),
|
||||
triareas(0),
|
||||
lset(0),
|
||||
chf(0),
|
||||
ntiles(0)
|
||||
{
|
||||
memset(tiles, 0, sizeof(TileCacheData)*MAX_LAYERS);
|
||||
}
|
||||
|
||||
~RasterizationContext()
|
||||
{
|
||||
rcFreeHeightField(solid);
|
||||
delete [] triareas;
|
||||
rcFreeHeightfieldLayerSet(lset);
|
||||
rcFreeCompactHeightfield(chf);
|
||||
for (int i = 0; i < MAX_LAYERS; ++i)
|
||||
{
|
||||
dtFree(tiles[i].data);
|
||||
tiles[i].data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rcHeightfield* solid;
|
||||
unsigned char* triareas;
|
||||
rcHeightfieldLayerSet* lset;
|
||||
rcCompactHeightfield* chf;
|
||||
TileCacheData tiles[MAX_LAYERS];
|
||||
int ntiles;
|
||||
};
|
||||
|
||||
struct LinearAllocator : public dtTileCacheAlloc
|
||||
{
|
||||
unsigned char* buffer;
|
||||
@ -106,18 +139,14 @@ struct FastLZCompressor : public dtTileCacheCompressor
|
||||
virtual dtStatus compress(const unsigned char* buffer, const int bufferSize,
|
||||
unsigned char* compressed, const int /*maxCompressedSize*/, int* compressedSize)
|
||||
{
|
||||
#if 0
|
||||
*compressedSize = fastlz_compress((const void *const)buffer, bufferSize, compressed);
|
||||
#endif
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
virtual dtStatus decompress(const unsigned char* compressed, const int compressedSize,
|
||||
unsigned char* buffer, const int maxBufferSize, int* bufferSize)
|
||||
{
|
||||
#if 0
|
||||
*bufferSize = fastlz_decompress(compressed, compressedSize, buffer, maxBufferSize);
|
||||
#endif
|
||||
return *bufferSize < 0 ? DT_FAILURE : DT_SUCCESS;
|
||||
}
|
||||
};
|
||||
@ -164,72 +193,45 @@ void NavMeshBuilder::UnInit()
|
||||
|
||||
}
|
||||
|
||||
dtNavMesh* NavMeshBuilder::Build(MapInstance* map_instance)
|
||||
struct BuilderParams
|
||||
{
|
||||
float kCellSize = 64;
|
||||
|
||||
// Init cache
|
||||
const float* bmin = nullptr;
|
||||
const float* bmax = nullptr;
|
||||
rcConfig cfg;
|
||||
dtTileCacheParams tcparams;
|
||||
MapInstance* map_instance = nullptr;
|
||||
LinearAllocator* talloc = nullptr;
|
||||
FastLZCompressor* tcomp = nullptr;
|
||||
MeshProcess* tmproc = nullptr;
|
||||
};
|
||||
|
||||
dtNavMesh* NavMeshBuilder::Build(MapInstance* map_instance)
|
||||
{
|
||||
BuilderParams builder_params;
|
||||
// Init cache
|
||||
int gw = 0, gh = 0;
|
||||
rcCalcGridSize(bmin, bmax, kCellSize, &gw, &gh);
|
||||
rcCalcGridSize(builder_params.bmin, builder_params.bmax, builder_params.kCellSize, &gw, &gh);
|
||||
const int ts = (int)kTileSize;
|
||||
const int tw = (gw + ts-1) / ts;
|
||||
const int th = (gh + ts-1) / ts;
|
||||
|
||||
rcConfig cfg;
|
||||
{
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.cs = kCellSize;
|
||||
cfg.ch = kCellHeight;
|
||||
cfg.walkableSlopeAngle = kAgentMaxSlope;
|
||||
cfg.walkableHeight = (int)ceilf(kAgentHeight / cfg.ch);
|
||||
cfg.walkableClimb = (int)floorf(kAgentMaxClimb / cfg.ch);
|
||||
cfg.walkableRadius = (int)ceilf(kAgentRadius / cfg.cs);
|
||||
cfg.maxEdgeLen = (int)(kEdgeMaxLen / kCellSize);
|
||||
cfg.maxSimplificationError = kEdgeMaxError;
|
||||
cfg.minRegionArea = (int)rcSqr(kRegionMinSize); // Note: area = size*size
|
||||
cfg.mergeRegionArea = (int)rcSqr(kRegionMergeSize); // Note: area = size*size
|
||||
cfg.maxVertsPerPoly = (int)kVertsPerPoly;
|
||||
cfg.tileSize = (int)kTileSize;
|
||||
cfg.borderSize = cfg.walkableRadius + 3; // Reserve enough padding.
|
||||
cfg.width = cfg.tileSize + cfg.borderSize*2;
|
||||
cfg.height = cfg.tileSize + cfg.borderSize*2;
|
||||
cfg.detailSampleDist = kDetailSampleDist < 0.9f ? 0 : kCellSize * kDetailSampleDist;
|
||||
cfg.detailSampleMaxError = kCellHeight * kDetailSampleMaxError;
|
||||
rcVcopy(cfg.bmin, bmin);
|
||||
rcVcopy(cfg.bmax, bmax);
|
||||
}
|
||||
|
||||
dtTileCacheParams tcparams;
|
||||
{
|
||||
// Tile cache params.
|
||||
memset(&tcparams, 0, sizeof(tcparams));
|
||||
rcVcopy(tcparams.orig, bmin);
|
||||
tcparams.cs = kCellSize;
|
||||
tcparams.ch = kCellHeight;
|
||||
tcparams.width = (int)kTileSize;
|
||||
tcparams.height = (int)kTileSize;
|
||||
tcparams.walkableHeight = kAgentHeight;
|
||||
tcparams.walkableRadius = kAgentRadius;
|
||||
tcparams.walkableClimb = kAgentMaxClimb;
|
||||
tcparams.maxSimplificationError = kEdgeMaxError;
|
||||
tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE;
|
||||
tcparams.maxObstacles = 128;
|
||||
}
|
||||
InitRcConfig(builder_params);
|
||||
InitTileCacheParams(builder_params);
|
||||
|
||||
dtStatus status;
|
||||
|
||||
dtTileCache* tile_cache = dtAllocTileCache();
|
||||
#if 0
|
||||
dtStatus status = tile_cache->init(&tcparams, m_talloc, m_tcomp, m_tmproc);;
|
||||
#endif
|
||||
status = tile_cache->init(&builder_params.tcparams,
|
||||
builder_params.talloc,
|
||||
builder_params.tcomp,
|
||||
builder_params.tmproc);
|
||||
dtNavMeshParams params;
|
||||
{
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
rcVcopy(params.orig, bmin);
|
||||
params.tileWidth = kTileSize * kCellSize;
|
||||
params.tileHeight = kTileSize * kCellSize;
|
||||
rcVcopy(params.orig, builder_params.bmin);
|
||||
params.tileWidth = kTileSize * builder_params.kCellSize;
|
||||
params.tileHeight = kTileSize * builder_params.kCellSize;
|
||||
#if 0
|
||||
params.maxTiles = kMaxTiles;
|
||||
params.maxPolys = kMaxPolysPerTile;
|
||||
@ -253,11 +255,7 @@ dtNavMesh* NavMeshBuilder::Build(MapInstance* map_instance)
|
||||
{
|
||||
TileCacheData tiles[MAX_LAYERS];
|
||||
memset(tiles, 0, sizeof(tiles));
|
||||
#if 1
|
||||
int ntiles = 0;
|
||||
#else
|
||||
int ntiles = rasterizeTileLayers(x, y, cfg, tiles, MAX_LAYERS);
|
||||
#endif
|
||||
int ntiles = RasterizeTileLayers(x, y, builder_params.cfg, tiles, MAX_LAYERS);
|
||||
|
||||
for (int i = 0; i < ntiles; ++i)
|
||||
{
|
||||
@ -280,9 +278,11 @@ dtNavMesh* NavMeshBuilder::Build(MapInstance* map_instance)
|
||||
}
|
||||
|
||||
// Build initial meshes
|
||||
for (int y = 0; y < th; ++y)
|
||||
for (int x = 0; x < tw; ++x)
|
||||
for (int y = 0; y < th; ++y) {
|
||||
for (int x = 0; x < tw; ++x) {
|
||||
tile_cache->buildNavMeshTilesAt(x,y, navmesh);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
m_cacheBuildTimeMs = m_ctx->getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f;
|
||||
@ -291,13 +291,12 @@ dtNavMesh* NavMeshBuilder::Build(MapInstance* map_instance)
|
||||
|
||||
const dtNavMesh* nav = navmesh;
|
||||
int navmeshMemUsage = 0;
|
||||
for (int i = 0; i < nav->getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = nav->getTile(i);
|
||||
if (tile->header)
|
||||
navmeshMemUsage += tile->dataSize;
|
||||
}
|
||||
printf("navmeshMemUsage = %.1f kB", navmeshMemUsage/1024.0f);
|
||||
for (int i = 0; i < nav->getMaxTiles(); ++i) {
|
||||
const dtMeshTile* tile = nav->getTile(i);
|
||||
if (tile->header) {
|
||||
navmeshMemUsage += tile->dataSize;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -402,3 +401,261 @@ void NavMeshBuilder::OutputObjFile(MapInstance* map_instance)
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void NavMeshBuilder::InitRcConfig(BuilderParams& builder_params)
|
||||
{
|
||||
#if 0
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.cs = kCellSize;
|
||||
cfg.ch = kCellHeight;
|
||||
cfg.walkableSlopeAngle = kAgentMaxSlope;
|
||||
cfg.walkableHeight = (int)ceilf(kAgentHeight / cfg.ch);
|
||||
cfg.walkableClimb = (int)floorf(kAgentMaxClimb / cfg.ch);
|
||||
cfg.walkableRadius = (int)ceilf(kAgentRadius / cfg.cs);
|
||||
cfg.maxEdgeLen = (int)(kEdgeMaxLen / kCellSize);
|
||||
cfg.maxSimplificationError = kEdgeMaxError;
|
||||
cfg.minRegionArea = (int)rcSqr(kRegionMinSize); // Note: area = size*size
|
||||
cfg.mergeRegionArea = (int)rcSqr(kRegionMergeSize); // Note: area = size*size
|
||||
cfg.maxVertsPerPoly = (int)kVertsPerPoly;
|
||||
cfg.tileSize = (int)kTileSize;
|
||||
cfg.borderSize = cfg.walkableRadius + 3; // Reserve enough padding.
|
||||
cfg.width = cfg.tileSize + cfg.borderSize*2;
|
||||
cfg.height = cfg.tileSize + cfg.borderSize*2;
|
||||
cfg.detailSampleDist = kDetailSampleDist < 0.9f ? 0 : kCellSize * kDetailSampleDist;
|
||||
cfg.detailSampleMaxError = kCellHeight * kDetailSampleMaxError;
|
||||
rcVcopy(cfg.bmin, bmin);
|
||||
rcVcopy(cfg.bmax, bmax);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NavMeshBuilder::InitTileCacheParams(BuilderParams& builder_params)
|
||||
{
|
||||
#if 0
|
||||
// Tile cache params.
|
||||
memset(&tcparams, 0, sizeof(tcparams));
|
||||
rcVcopy(tcparams.orig, bmin);
|
||||
tcparams.cs = kCellSize;
|
||||
tcparams.ch = kCellHeight;
|
||||
tcparams.width = (int)kTileSize;
|
||||
tcparams.height = (int)kTileSize;
|
||||
tcparams.walkableHeight = kAgentHeight;
|
||||
tcparams.walkableRadius = kAgentRadius;
|
||||
tcparams.walkableClimb = kAgentMaxClimb;
|
||||
tcparams.maxSimplificationError = kEdgeMaxError;
|
||||
tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE;
|
||||
tcparams.maxObstacles = 128;
|
||||
#endif
|
||||
}
|
||||
|
||||
int NavMeshBuilder::RasterizeTileLayers(const int tx, const int ty,
|
||||
const rcConfig& cfg,
|
||||
TileCacheData* tiles,
|
||||
const int maxTiles)
|
||||
{
|
||||
#if 0
|
||||
if (!m_geom || !m_geom->getMesh() || !m_geom->getChunkyMesh())
|
||||
{
|
||||
m_ctx->log(RC_LOG_ERROR, "buildTile: Input mesh is not specified.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
FastLZCompressor comp;
|
||||
RasterizationContext rc;
|
||||
|
||||
struct rcChunkyTriMesh;
|
||||
#if 1
|
||||
const float* verts = nullptr;
|
||||
const int nverts = 0;
|
||||
const rcChunkyTriMesh* chunkyMesh = nullptr;
|
||||
#else
|
||||
const float* verts = m_geom->getMesh()->getVerts();
|
||||
const int nverts = m_geom->getMesh()->getVertCount();
|
||||
const rcChunkyTriMesh* chunkyMesh = m_geom->getChunkyMesh();
|
||||
#endif
|
||||
|
||||
// Tile bounds.
|
||||
const float tcs = cfg.tileSize * cfg.cs;
|
||||
|
||||
rcConfig tcfg;
|
||||
memcpy(&tcfg, &cfg, sizeof(tcfg));
|
||||
|
||||
tcfg.bmin[0] = cfg.bmin[0] + tx*tcs;
|
||||
tcfg.bmin[1] = cfg.bmin[1];
|
||||
tcfg.bmin[2] = cfg.bmin[2] + ty*tcs;
|
||||
tcfg.bmax[0] = cfg.bmin[0] + (tx+1)*tcs;
|
||||
tcfg.bmax[1] = cfg.bmax[1];
|
||||
tcfg.bmax[2] = cfg.bmin[2] + (ty+1)*tcs;
|
||||
tcfg.bmin[0] -= tcfg.borderSize*tcfg.cs;
|
||||
tcfg.bmin[2] -= tcfg.borderSize*tcfg.cs;
|
||||
tcfg.bmax[0] += tcfg.borderSize*tcfg.cs;
|
||||
tcfg.bmax[2] += tcfg.borderSize*tcfg.cs;
|
||||
|
||||
// Allocate voxel heightfield where we rasterize our input data to.
|
||||
rc.solid = rcAllocHeightfield();
|
||||
if (!rc.solid) {
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
if (!rcCreateHeightfield(m_ctx, *rc.solid, tcfg.width, tcfg.height, tcfg.bmin, tcfg.bmax, tcfg.cs, tcfg.ch)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allocate array that can hold triangle flags.
|
||||
// If you have multiple meshes you need to process, allocate
|
||||
// and array which can hold the max number of triangles you need to process.
|
||||
#if 0
|
||||
rc.triareas = new unsigned char[chunkyMesh->maxTrisPerChunk];
|
||||
#endif
|
||||
if (!rc.triareas) {
|
||||
#if 0
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (%d).", chunkyMesh->maxTrisPerChunk);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
float tbmin[2], tbmax[2];
|
||||
tbmin[0] = tcfg.bmin[0];
|
||||
tbmin[1] = tcfg.bmin[2];
|
||||
tbmax[0] = tcfg.bmax[0];
|
||||
tbmax[1] = tcfg.bmax[2];
|
||||
int cid[512];// TODO: Make grow when returning too many items.
|
||||
#if 1
|
||||
const int ncid = 0;
|
||||
#else
|
||||
const int ncid = rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, cid, 512);
|
||||
#endif
|
||||
if (!ncid) {
|
||||
return 0; // empty
|
||||
}
|
||||
|
||||
for (int i = 0; i < ncid; ++i) {
|
||||
#if 0
|
||||
const rcChunkyTriMeshNode& node = chunkyMesh->nodes[cid[i]];
|
||||
const int* tris = &chunkyMesh->tris[node.i*3];
|
||||
const int ntris = node.n;
|
||||
|
||||
memset(rc.triareas, 0, ntris*sizeof(unsigned char));
|
||||
rcMarkWalkableTriangles(m_ctx, tcfg.walkableSlopeAngle,
|
||||
verts, nverts, tris, ntris, rc.triareas,
|
||||
SAMPLE_AREAMOD_GROUND);
|
||||
|
||||
if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, rc.triareas, ntris, *rc.solid, tcfg.walkableClimb))
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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.
|
||||
#if 0
|
||||
if (m_filterLowHangingObstacles)
|
||||
rcFilterLowHangingWalkableObstacles(m_ctx, tcfg.walkableClimb, *rc.solid);
|
||||
if (m_filterLedgeSpans)
|
||||
rcFilterLedgeSpans(m_ctx, tcfg.walkableHeight, tcfg.walkableClimb, *rc.solid);
|
||||
if (m_filterWalkableLowHeightSpans)
|
||||
rcFilterWalkableLowHeightSpans(m_ctx, tcfg.walkableHeight, *rc.solid);
|
||||
#endif
|
||||
|
||||
rc.chf = rcAllocCompactHeightfield();
|
||||
if (!rc.chf) {
|
||||
#if 0
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
if (!rcBuildCompactHeightfield(m_ctx, tcfg.walkableHeight, tcfg.walkableClimb, *rc.solid, *rc.chf)) {
|
||||
#if 0
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Erode the walkable area by agent radius.
|
||||
#if 0
|
||||
if (!rcErodeWalkableArea(m_ctx, tcfg.walkableRadius, *rc.chf)) {
|
||||
#if 0
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// (Optional) Mark areas.
|
||||
const ConvexVolume* vols = m_geom->getConvexVolumes();
|
||||
for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i) {
|
||||
rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts,
|
||||
vols[i].hmin, vols[i].hmax,
|
||||
vols[i].areaMod, *rc.chf);
|
||||
}
|
||||
#endif
|
||||
|
||||
rc.lset = rcAllocHeightfieldLayerSet();
|
||||
if (!rc.lset) {
|
||||
#if 0
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'lset'.");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
if (!rcBuildHeightfieldLayers(m_ctx, *rc.chf, tcfg.borderSize, tcfg.walkableHeight, *rc.lset)) {
|
||||
#if 0
|
||||
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build heighfield layers.");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc.ntiles = 0;
|
||||
for (int i = 0; i < rcMin(rc.lset->nlayers, MAX_LAYERS); ++i) {
|
||||
TileCacheData* tile = &rc.tiles[rc.ntiles++];
|
||||
const rcHeightfieldLayer* layer = &rc.lset->layers[i];
|
||||
|
||||
// Store header
|
||||
dtTileCacheLayerHeader header;
|
||||
header.magic = DT_TILECACHE_MAGIC;
|
||||
header.version = DT_TILECACHE_VERSION;
|
||||
|
||||
// Tile layer location in the navmesh.
|
||||
header.tx = tx;
|
||||
header.ty = ty;
|
||||
header.tlayer = i;
|
||||
dtVcopy(header.bmin, layer->bmin);
|
||||
dtVcopy(header.bmax, layer->bmax);
|
||||
|
||||
// Tile info.
|
||||
header.width = (unsigned char)layer->width;
|
||||
header.height = (unsigned char)layer->height;
|
||||
header.minx = (unsigned char)layer->minx;
|
||||
header.maxx = (unsigned char)layer->maxx;
|
||||
header.miny = (unsigned char)layer->miny;
|
||||
header.maxy = (unsigned char)layer->maxy;
|
||||
header.hmin = (unsigned short)layer->hmin;
|
||||
header.hmax = (unsigned short)layer->hmax;
|
||||
|
||||
dtStatus status = dtBuildTileCacheLayer(&comp,
|
||||
&header,
|
||||
layer->heights,
|
||||
layer->areas,
|
||||
layer->cons,
|
||||
&tile->data,
|
||||
&tile->dataSize);
|
||||
if (dtStatusFailed(status)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer ownsership of tile data from build context to the caller.
|
||||
int n = 0;
|
||||
for (int i = 0; i < rcMin(rc.ntiles, maxTiles); ++i) {
|
||||
tiles[n++] = rc.tiles[i];
|
||||
rc.tiles[i].data = 0;
|
||||
rc.tiles[i].dataSize = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
struct rcConfig;
|
||||
struct dtTileCacheParams;
|
||||
struct BuilderParams;
|
||||
struct TileCacheData;
|
||||
class dtNavMesh;
|
||||
class MapInstance;
|
||||
class NavMeshBuilder : public a8::Singleton<NavMeshBuilder>
|
||||
@ -14,4 +18,12 @@ public:
|
||||
|
||||
dtNavMesh* Build(MapInstance* map_instance);
|
||||
void OutputObjFile(MapInstance* map_instance);
|
||||
|
||||
private:
|
||||
void InitRcConfig(BuilderParams& builder_params);
|
||||
void InitTileCacheParams(BuilderParams& builder_params);
|
||||
int RasterizeTileLayers(const int tx, const int ty,
|
||||
const rcConfig& cfg,
|
||||
TileCacheData* tiles,
|
||||
const int maxTiles);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user