void BotShutdownNav( void ) { for ( int i = 0; i < numNavData; i++ ) { NavData_t *nav = &BotNavData[ i ]; if ( nav->cache ) { dtFreeTileCache( nav->cache ); nav->cache = 0; } if ( nav->mesh ) { dtFreeNavMesh( nav->mesh ); nav->mesh = 0; } if ( nav->query ) { dtFreeNavMeshQuery( nav->query ); nav->query = 0; } nav->process.con.reset(); memset( nav->name, 0, sizeof( nav->name ) ); } #ifndef DEDICATED NavEditShutdown(); #endif numNavData = 0; }
bool OgreDetourTileCache::initTileCache() { // BUILD TileCache dtFreeTileCache(m_tileCache); dtStatus status; m_tileCache = dtAllocTileCache(); if (!m_tileCache) { m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not allocate tile cache."); return false; } status = m_tileCache->init(&m_tcparams, m_talloc, m_tcomp, m_tmproc); if (dtStatusFailed(status)) { m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not init tile cache."); return false; } dtFreeNavMesh(m_recast->m_navMesh); m_recast->m_navMesh = dtAllocNavMesh(); if (!m_recast->m_navMesh) { m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not allocate navmesh."); return false; } // Init multi-tile navmesh parameters dtNavMeshParams params; memset(¶ms, 0, sizeof(params)); rcVcopy(params.orig, m_tcparams.orig); // Set world-space origin of tile grid params.tileWidth = m_tileSize*m_tcparams.cs; params.tileHeight = m_tileSize*m_tcparams.cs; params.maxTiles = m_maxTiles; params.maxPolys = m_maxPolysPerTile; status = m_recast->m_navMesh->init(¶ms); if (dtStatusFailed(status)) { m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not init navmesh."); return false; } // Init recast navmeshquery with created navmesh (in OgreRecast component) m_recast->m_navQuery = dtAllocNavMeshQuery(); status = m_recast->m_navQuery->init(m_recast->m_navMesh, 2048); if (dtStatusFailed(status)) { m_recast->m_pLog->logMessage("ERROR: buildTiledNavigation: Could not init Detour navmesh query"); return false; } return true; }
void NavMesh::SetMesh(InputGeom* geom) { m_geom = geom; dtFreeTileCache(m_tileCache); m_tileCache = 0; dtFreeNavMesh(m_navMesh); m_navMesh = 0; }
void Sample_TempObstacles::handleMeshChanged(class InputGeom* geom) { Sample::handleMeshChanged(geom); dtFreeTileCache(m_tileCache); m_tileCache = 0; dtFreeNavMesh(m_navMesh); m_navMesh = 0; if (m_tool) { m_tool->reset(); m_tool->init(this); m_tmproc->init(m_geom); } resetToolStates(); initToolStates(this); }
NavMesh::~NavMesh() { dtFreeTileCache(_tileCache); dtFreeCrowd(_crowed); dtFreeNavMesh(_navMesh); dtFreeNavMeshQuery(_navMeshQuery); CC_SAFE_DELETE(_allocator); CC_SAFE_DELETE(_compressor); CC_SAFE_DELETE(_meshProcess); CC_SAFE_DELETE(_geomData); for (auto iter : _agentList){ CC_SAFE_RELEASE(iter); } _agentList.clear(); for (auto iter : _obstacleList){ CC_SAFE_RELEASE(iter); } _obstacleList.clear(); }
OgreDetourTileCache::~OgreDetourTileCache() { // dtFreeNavMesh(m_navMesh); // m_navMesh = 0; dtFreeTileCache(m_tileCache); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CRecastMesh::Build( CMapMesh *pMapMesh ) { double fStartTime = Plat_FloatTime(); Reset(); // Clean any existing data BuildContext ctx; ctx.enableLog( true ); dtStatus status; V_memset(&m_cfg, 0, sizeof(m_cfg)); // Init cache rcCalcBounds( pMapMesh->GetVerts(), pMapMesh->GetNumVerts(), m_cfg.bmin, m_cfg.bmax ); rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height); int gw = 0, gh = 0; rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cellSize, &gw, &gh); const int ts = (int)m_tileSize; const int tw = (gw + ts-1) / ts; const int th = (gh + ts-1) / ts; // Max tiles and max polys affect how the tile IDs are caculated. // There are 22 bits available for identifying a tile and a polygon. int tileBits = rcMin((int)dtIlog2(dtNextPow2(tw*th*EXPECTED_LAYERS_PER_TILE)), 14); if (tileBits > 14) tileBits = 14; int polyBits = 22 - tileBits; m_maxTiles = 1 << tileBits; m_maxPolysPerTile = 1 << polyBits; // Generation params. m_cfg.cs = m_cellSize; m_cfg.ch = m_cellHeight; m_cfg.walkableSlopeAngle = m_agentMaxSlope; m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch); m_cfg.walkableClimb = (int)floorf(m_agentMaxClimb / m_cfg.ch); m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs); m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); m_cfg.maxSimplificationError = m_edgeMaxError; m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly; m_cfg.tileSize = (int)m_tileSize; m_cfg.borderSize = m_cfg.walkableRadius + 3; // Reserve enough padding. m_cfg.width = m_cfg.tileSize + m_cfg.borderSize*2; m_cfg.height = m_cfg.tileSize + m_cfg.borderSize*2; m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist; m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError; // Tile cache params. dtTileCacheParams tcparams; memset(&tcparams, 0, sizeof(tcparams)); rcVcopy(tcparams.orig, m_cfg.bmin); tcparams.cs = m_cellSize; tcparams.ch = m_cellHeight; tcparams.width = (int)m_tileSize; tcparams.height = (int)m_tileSize; tcparams.walkableHeight = m_agentHeight; tcparams.walkableRadius = m_agentRadius; tcparams.walkableClimb = m_agentMaxClimb; tcparams.maxSimplificationError = m_edgeMaxError; tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE; tcparams.maxObstacles = 2048; dtFreeTileCache(m_tileCache); m_tileCache = dtAllocTileCache(); if (!m_tileCache) { ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate tile cache."); return false; } status = m_tileCache->init(&tcparams, m_talloc, m_tcomp, m_tmproc); if (dtStatusFailed(status)) { ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not init tile cache."); return false; } dtFreeNavMesh(m_navMesh); m_navMesh = dtAllocNavMesh(); if (!m_navMesh) { ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate navmesh."); return false; } dtNavMeshParams params; memset(¶ms, 0, sizeof(params)); rcVcopy(params.orig, m_cfg.bmin); params.tileWidth = m_tileSize*m_cellSize; params.tileHeight = m_tileSize*m_cellSize; params.maxTiles = m_maxTiles; params.maxPolys = m_maxPolysPerTile; status = m_navMesh->init(¶ms); if (dtStatusFailed(status)) { ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not init navmesh."); return false; } status = m_navQuery->init( m_navMesh, RECAST_NAVQUERY_MAXNODES ); if (dtStatusFailed(status)) { ctx.log(RC_LOG_ERROR, "buildTiledNavigation: Could not init Detour navmesh query"); return false; } // Preprocess tiles. ctx.resetTimers(); m_cacheLayerCount = 0; m_cacheCompressedSize = 0; m_cacheRawSize = 0; for (int y = 0; y < th; ++y) { for (int x = 0; x < tw; ++x) { TileCacheData tiles[MAX_LAYERS]; memset(tiles, 0, sizeof(tiles)); int ntiles = rasterizeTileLayers(&ctx, pMapMesh, x, y, m_cfg, tiles, MAX_LAYERS); for (int i = 0; i < ntiles; ++i) { TileCacheData* tile = &tiles[i]; status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0); if (dtStatusFailed(status)) { dtFree(tile->data); tile->data = 0; continue; } m_cacheLayerCount++; m_cacheCompressedSize += tile->dataSize; m_cacheRawSize += calcLayerBufferSize(tcparams.width, tcparams.height); } } } // Build initial meshes ctx.startTimer(RC_TIMER_TOTAL); for (int y = 0; y < th; ++y) for (int x = 0; x < tw; ++x) m_tileCache->buildNavMeshTilesAt(x,y, m_navMesh); ctx.stopTimer(RC_TIMER_TOTAL); m_cacheBuildTimeMs = ctx.getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f; m_cacheBuildMemUsage = ((LinearAllocator *)m_talloc)->high; const dtNavMesh* nav = m_navMesh; int navmeshMemUsage = 0; for (int i = 0; i < nav->getMaxTiles(); ++i) { const dtMeshTile* tile = nav->getTile(i); if (tile->header) navmeshMemUsage += tile->dataSize; } DevMsg( "CRecastMesh: Generated navigation mesh %s in %f seconds\n", m_Name.Get(), Plat_FloatTime() - fStartTime ); return true; }
void Sample_TempObstacles::handleSettings() { Sample::handleCommonSettings(); if (imguiCheck("Keep Itermediate Results", m_keepInterResults)) m_keepInterResults = !m_keepInterResults; imguiLabel("Tiling"); imguiSlider("TileSize", &m_tileSize, 16.0f, 128.0f, 8.0f); int gridSize = 1; if (m_geom) { const float* bmin = m_geom->getNavMeshBoundsMin(); const float* bmax = m_geom->getNavMeshBoundsMax(); char text[64]; int gw = 0, gh = 0; rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); const int ts = (int)m_tileSize; const int tw = (gw + ts-1) / ts; const int th = (gh + ts-1) / ts; snprintf(text, 64, "Tiles %d x %d", tw, th); imguiValue(text); // Max tiles and max polys affect how the tile IDs are caculated. // There are 22 bits available for identifying a tile and a polygon. int tileBits = rcMin((int)dtIlog2(dtNextPow2(tw*th*EXPECTED_LAYERS_PER_TILE)), 14); if (tileBits > 14) tileBits = 14; int polyBits = 22 - tileBits; m_maxTiles = 1 << tileBits; m_maxPolysPerTile = 1 << polyBits; snprintf(text, 64, "Max Tiles %d", m_maxTiles); imguiValue(text); snprintf(text, 64, "Max Polys %d", m_maxPolysPerTile); imguiValue(text); gridSize = tw*th; } else { m_maxTiles = 0; m_maxPolysPerTile = 0; } imguiSeparator(); imguiLabel("Tile Cache"); char msg[64]; const float compressionRatio = (float)m_cacheCompressedSize / (float)(m_cacheRawSize+1); snprintf(msg, 64, "Layers %d", m_cacheLayerCount); imguiValue(msg); snprintf(msg, 64, "Layers (per tile) %.1f", (float)m_cacheLayerCount/(float)gridSize); imguiValue(msg); snprintf(msg, 64, "Memory %.1f kB / %.1f kB (%.1f%%)", m_cacheCompressedSize/1024.0f, m_cacheRawSize/1024.0f, compressionRatio*100.0f); imguiValue(msg); snprintf(msg, 64, "Navmesh Build Time %.1f ms", m_cacheBuildTimeMs); imguiValue(msg); snprintf(msg, 64, "Build Peak Mem Usage %.1f kB", m_cacheBuildMemUsage/1024.0f); imguiValue(msg); imguiSeparator(); imguiIndent(); imguiIndent(); if (imguiButton("Save")) { saveAll("all_tiles_tilecache.bin"); } if (imguiButton("Load")) { dtFreeNavMesh(m_navMesh); dtFreeTileCache(m_tileCache); loadAll("all_tiles_tilecache.bin"); m_navQuery->init(m_navMesh, 2048); } imguiUnindent(); imguiUnindent(); imguiSeparator(); }
Sample_TempObstacles::~Sample_TempObstacles() { dtFreeNavMesh(m_navMesh); m_navMesh = 0; dtFreeTileCache(m_tileCache); }
bool Sample_TempObstacles::handleBuild() { dtStatus status; if (!m_geom || !m_geom->getMesh()) { m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: No vertices and triangles."); return false; } m_tmproc->init(m_geom); // Init cache const float* bmin = m_geom->getNavMeshBoundsMin(); const float* bmax = m_geom->getNavMeshBoundsMax(); int gw = 0, gh = 0; rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); const int ts = (int)m_tileSize; const int tw = (gw + ts-1) / ts; const int th = (gh + ts-1) / ts; // Generation params. rcConfig cfg; memset(&cfg, 0, sizeof(cfg)); cfg.cs = m_cellSize; cfg.ch = m_cellHeight; cfg.walkableSlopeAngle = m_agentMaxSlope; cfg.walkableHeight = (int)ceilf(m_agentHeight / cfg.ch); cfg.walkableClimb = (int)floorf(m_agentMaxClimb / cfg.ch); cfg.walkableRadius = (int)ceilf(m_agentRadius / cfg.cs); cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); cfg.maxSimplificationError = m_edgeMaxError; cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size cfg.maxVertsPerPoly = (int)m_vertsPerPoly; cfg.tileSize = (int)m_tileSize; cfg.borderSize = cfg.walkableRadius + 3; // Reserve enough padding. cfg.width = cfg.tileSize + cfg.borderSize*2; cfg.height = cfg.tileSize + cfg.borderSize*2; cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist; cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError; rcVcopy(cfg.bmin, bmin); rcVcopy(cfg.bmax, bmax); // Tile cache params. dtTileCacheParams tcparams; memset(&tcparams, 0, sizeof(tcparams)); rcVcopy(tcparams.orig, bmin); tcparams.cs = m_cellSize; tcparams.ch = m_cellHeight; tcparams.width = (int)m_tileSize; tcparams.height = (int)m_tileSize; tcparams.walkableHeight = m_agentHeight; tcparams.walkableRadius = m_agentRadius; tcparams.walkableClimb = m_agentMaxClimb; tcparams.maxSimplificationError = m_edgeMaxError; tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE; tcparams.maxObstacles = 128; dtFreeTileCache(m_tileCache); m_tileCache = dtAllocTileCache(); if (!m_tileCache) { m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate tile cache."); return false; } status = m_tileCache->init(&tcparams, m_talloc, m_tcomp, m_tmproc); if (dtStatusFailed(status)) { m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init tile cache."); return false; } dtFreeNavMesh(m_navMesh); m_navMesh = dtAllocNavMesh(); if (!m_navMesh) { m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not allocate navmesh."); return false; } dtNavMeshParams params; memset(¶ms, 0, sizeof(params)); rcVcopy(params.orig, bmin); params.tileWidth = m_tileSize*m_cellSize; params.tileHeight = m_tileSize*m_cellSize; params.maxTiles = m_maxTiles; params.maxPolys = m_maxPolysPerTile; status = m_navMesh->init(¶ms); if (dtStatusFailed(status)) { m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init navmesh."); return false; } status = m_navQuery->init(m_navMesh, 2048); if (dtStatusFailed(status)) { m_ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not init Detour navmesh query"); return false; } // Preprocess tiles. m_ctx->resetTimers(); m_cacheLayerCount = 0; m_cacheCompressedSize = 0; m_cacheRawSize = 0; for (int y = 0; y < th; ++y) { for (int x = 0; x < tw; ++x) { TileCacheData tiles[MAX_LAYERS]; memset(tiles, 0, sizeof(tiles)); int ntiles = rasterizeTileLayers(m_ctx, m_geom, x, y, cfg, tiles, MAX_LAYERS); for (int i = 0; i < ntiles; ++i) { TileCacheData* tile = &tiles[i]; status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0); if (dtStatusFailed(status)) { dtFree(tile->data); tile->data = 0; continue; } m_cacheLayerCount++; m_cacheCompressedSize += tile->dataSize; m_cacheRawSize += calcLayerBufferSize(tcparams.width, tcparams.height); } } } // Build initial meshes m_ctx->startTimer(RC_TIMER_TOTAL); for (int y = 0; y < th; ++y) for (int x = 0; x < tw; ++x) m_tileCache->buildNavMeshTilesAt(x,y, m_navMesh); m_ctx->stopTimer(RC_TIMER_TOTAL); m_cacheBuildTimeMs = m_ctx->getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f; m_cacheBuildMemUsage = m_talloc->high; const dtNavMesh* nav = m_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); if (m_tool) m_tool->init(this); initToolStates(this); return true; }
bool BotLoadNavMesh( const char *filename, NavData_t &nav ) { char mapname[ MAX_QPATH ]; char filePath[ MAX_QPATH ]; char gameName[ MAX_STRING_CHARS ]; fileHandle_t f = 0; BotLoadOffMeshConnections( filename, &nav ); Cvar_VariableStringBuffer( "mapname", mapname, sizeof( mapname ) ); Cvar_VariableStringBuffer( "fs_game", gameName, sizeof( gameName ) ); Com_sprintf( filePath, sizeof( filePath ), "maps/%s-%s.navMesh", mapname, filename ); Com_Printf( " loading navigation mesh file '%s'...\n", filePath ); int len = FS_FOpenFileRead( filePath, &f, qtrue ); if ( !f ) { Com_Printf( S_COLOR_RED "ERROR: Cannot open Navigaton Mesh file\n" ); return false; } if ( len < 0 ) { Com_Printf( S_COLOR_RED "ERROR: Negative Length for Navigation Mesh file\n" ); return false; } NavMeshSetHeader header; FS_Read( &header, sizeof( header ), f ); SwapNavMeshSetHeader( header ); if ( header.magic != NAVMESHSET_MAGIC ) { Com_Printf( S_COLOR_RED "ERROR: File is wrong magic\n" ); FS_FCloseFile( f ); return false; } if ( header.version != NAVMESHSET_VERSION ) { Com_Printf( S_COLOR_RED "ERROR: File is wrong version found: %d want: %d\n", header.version, NAVMESHSET_VERSION ); FS_FCloseFile( f ); return false; } nav.mesh = dtAllocNavMesh(); if ( !nav.mesh ) { Com_Printf( S_COLOR_RED "ERROR: Unable to allocate nav mesh\n" ); FS_FCloseFile( f ); return false; } dtStatus status = nav.mesh->init( &header.params ); if ( dtStatusFailed( status ) ) { Com_Printf( S_COLOR_RED "ERROR: Could not init navmesh\n" ); dtFreeNavMesh( nav.mesh ); nav.mesh = NULL; FS_FCloseFile( f ); return false; } nav.cache = dtAllocTileCache(); if ( !nav.cache ) { Com_Printf( S_COLOR_RED "ERROR: Could not allocate tile cache\n" ); dtFreeNavMesh( nav.mesh ); nav.mesh = NULL; FS_FCloseFile( f ); return false; } status = nav.cache->init( &header.cacheParams, &alloc, &comp, &nav.process ); if ( dtStatusFailed( status ) ) { Com_Printf( S_COLOR_RED "ERROR: Could not init tile cache\n" ); dtFreeNavMesh( nav.mesh ); dtFreeTileCache( nav.cache ); nav.mesh = NULL; nav.cache = NULL; FS_FCloseFile( f ); return false; } for ( int i = 0; i < header.numTiles; i++ ) { NavMeshTileHeader tileHeader; FS_Read( &tileHeader, sizeof( tileHeader ), f ); SwapNavMeshTileHeader( tileHeader ); if ( !tileHeader.tileRef || !tileHeader.dataSize ) { Com_Printf( S_COLOR_RED "ERROR: NUll Tile in navmesh\n" ); dtFreeNavMesh( nav.mesh ); dtFreeTileCache( nav.cache ); nav.cache = NULL; nav.mesh = NULL; FS_FCloseFile( f ); return false; } unsigned char *data = ( unsigned char * ) dtAlloc( tileHeader.dataSize, DT_ALLOC_PERM ); if ( !data ) { Com_Printf( S_COLOR_RED "ERROR: Failed to allocate memory for tile data\n" ); dtFreeNavMesh( nav.mesh ); dtFreeTileCache( nav.cache ); nav.cache = NULL; nav.mesh = NULL; FS_FCloseFile( f ); return false; } memset( data, 0, tileHeader.dataSize ); FS_Read( data, tileHeader.dataSize, f ); if ( LittleLong( 1 ) != 1 ) { dtTileCacheHeaderSwapEndian( data, tileHeader.dataSize ); } dtCompressedTileRef tile = 0; dtStatus status = nav.cache->addTile( data, tileHeader.dataSize, DT_TILE_FREE_DATA, &tile ); if ( dtStatusFailed( status ) ) { Com_Printf( S_COLOR_RED "ERROR: Failed to add tile to navmesh\n" ); dtFree( data ); dtFreeTileCache( nav.cache ); dtFreeNavMesh( nav.mesh ); nav.cache = NULL; nav.mesh = NULL; FS_FCloseFile( f ); return false; } if ( tile ) { nav.cache->buildNavMeshTile( tile, nav.mesh ); } } FS_FCloseFile( f ); return true; }
bool NavMesh::BuildMesh() { dtStatus status; if (!m_geom || !m_geom->getMesh()) return false; m_tmproc->init(m_geom); // Init cache const float* bmin = m_geom->getMeshBoundsMin(); const float* bmax = m_geom->getMeshBoundsMax(); int gw = 0, gh = 0; rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); const int ts = (int)m_tileSize; const int tw = (gw + ts-1) / ts; const int th = (gh + ts-1) / ts; // Generation params. rcConfig cfg; memset(&cfg, 0, sizeof(cfg)); cfg.cs = m_cellSize; cfg.ch = m_cellHeight; cfg.walkableSlopeAngle = m_agentMaxSlope; cfg.walkableHeight = (int)ceilf(m_agentHeight / cfg.ch); cfg.walkableClimb = (int)floorf(m_agentMaxClimb / cfg.ch); cfg.walkableRadius = (int)ceilf(m_agentRadius / cfg.cs); cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize); cfg.maxSimplificationError = m_edgeMaxError; cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size cfg.maxVertsPerPoly = (int)m_vertsPerPoly; cfg.tileSize = (int)m_tileSize; cfg.borderSize = cfg.walkableRadius + 3; // Reserve enough padding. cfg.width = cfg.tileSize + cfg.borderSize*2; cfg.height = cfg.tileSize + cfg.borderSize*2; cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist; cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError; rcVcopy(cfg.bmin, bmin); rcVcopy(cfg.bmax, bmax); // Tile cache params. dtTileCacheParams tcparams; memset(&tcparams, 0, sizeof(tcparams)); rcVcopy(tcparams.orig, bmin); tcparams.cs = m_cellSize; tcparams.ch = m_cellHeight; tcparams.width = (int)m_tileSize; tcparams.height = (int)m_tileSize; tcparams.walkableHeight = m_agentHeight; tcparams.walkableRadius = m_agentRadius; tcparams.walkableClimb = m_agentMaxClimb; tcparams.maxSimplificationError = m_edgeMaxError; tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE; tcparams.maxObstacles = 128; dtFreeTileCache(m_tileCache); m_tileCache = dtAllocTileCache(); if (!m_tileCache) return false; status = m_tileCache->init(&tcparams, m_talloc, m_tcomp, m_tmproc); if (dtStatusFailed(status)) return false; dtFreeNavMesh(m_navMesh); m_navMesh = dtAllocNavMesh(); if (!m_navMesh) return false; dtNavMeshParams params; memset(¶ms, 0, sizeof(params)); rcVcopy(params.orig, m_geom->getMeshBoundsMin()); params.tileWidth = m_tileSize*m_cellSize; params.tileHeight = m_tileSize*m_cellSize; params.maxTiles = m_maxTiles; params.maxPolys = m_maxPolysPerTile; status = m_navMesh->init(¶ms); if (dtStatusFailed(status)) return false; status = m_navQuery->init(m_navMesh, 2048); if (dtStatusFailed(status)) return false; for (int y = 0; y < th; ++y) { for (int x = 0; x < tw; ++x) { TileCacheData tiles[MAX_LAYERS]; memset(tiles, 0, sizeof(tiles)); int n = rasterizeTileLayers(m_geom, x, y, cfg, tiles, MAX_LAYERS); for (int i = 0; i < n; ++i) { TileCacheData* tile = &tiles[i]; status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0); if (dtStatusFailed(status)) { dtFree(tile->data); tile->data = 0; continue; } } } } for (int y = 0; y < th; ++y) for (int x = 0; x < tw; ++x) m_tileCache->buildNavMeshTilesAt(x,y, m_navMesh); }
NavMesh::~NavMesh() { dtFreeNavMesh(m_navMesh); m_navMesh = 0; dtFreeTileCache(m_tileCache); }