dtStatus dtTileCache::init(const dtTileCacheParams* params, dtTileCacheAlloc* talloc, dtTileCacheCompressor* tcomp, dtTileCacheMeshProcess* tmproc) { m_talloc = talloc; m_tcomp = tcomp; m_tmproc = tmproc; m_nreqs = 0; memcpy(&m_params, params, sizeof(m_params)); // Alloc space for obstacles. m_obstacles = (dtTileCacheObstacle*)dtAlloc(sizeof(dtTileCacheObstacle)*m_params.maxObstacles, DT_ALLOC_PERM); if (!m_obstacles) return DT_FAILURE | DT_OUT_OF_MEMORY; memset(m_obstacles, 0, sizeof(dtTileCacheObstacle)*m_params.maxObstacles); m_nextFreeObstacle = 0; for (int i = m_params.maxObstacles-1; i >= 0; --i) { m_obstacles[i].salt = 1; m_obstacles[i].next = m_nextFreeObstacle; m_nextFreeObstacle = &m_obstacles[i]; } // Init tiles m_tileLutSize = dtNextPow2(m_params.maxTiles/4); if (!m_tileLutSize) m_tileLutSize = 1; m_tileLutMask = m_tileLutSize-1; m_tiles = (dtCompressedTile*)dtAlloc(sizeof(dtCompressedTile)*m_params.maxTiles, DT_ALLOC_PERM); if (!m_tiles) return DT_FAILURE | DT_OUT_OF_MEMORY; m_posLookup = (dtCompressedTile**)dtAlloc(sizeof(dtCompressedTile*)*m_tileLutSize, DT_ALLOC_PERM); if (!m_posLookup) return DT_FAILURE | DT_OUT_OF_MEMORY; memset(m_tiles, 0, sizeof(dtCompressedTile)*m_params.maxTiles); memset(m_posLookup, 0, sizeof(dtCompressedTile*)*m_tileLutSize); m_nextFreeTile = 0; for (int i = m_params.maxTiles-1; i >= 0; --i) { m_tiles[i].salt = 1; m_tiles[i].next = m_nextFreeTile; m_nextFreeTile = &m_tiles[i]; } // Init ID generator values. m_tileBits = dtIlog2(dtNextPow2((unsigned int)m_params.maxTiles)); // Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow. m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits); if (m_saltBits < 10) return DT_FAILURE | DT_INVALID_PARAM; return DT_SUCCESS; }
bool dtProximityGrid::init(const int poolSize, const float cellSize) { dtAssert(poolSize > 0); dtAssert(cellSize > 0.0f); m_cellSize = cellSize; m_invCellSize = 1.0f / m_cellSize; // Allocate hashs buckets m_bucketsSize = dtNextPow2(poolSize); m_buckets = (unsigned short*)dtAlloc(sizeof(unsigned short)*m_bucketsSize, DT_ALLOC_PERM); if (!m_buckets) return false; // Allocate pool of items. m_poolSize = poolSize; m_poolHead = 0; m_pool = (Item*)dtAlloc(sizeof(Item)*m_poolSize, DT_ALLOC_PERM); if (!m_pool) return false; clear(); return true; }
dtStatus dtNavMesh::init(const dtNavMeshParams* params) { memcpy(&m_params, params, sizeof(dtNavMeshParams)); dtVcopy(m_orig, params->orig); m_tileWidth = params->tileWidth; m_tileHeight = params->tileHeight; // Init tiles m_maxTiles = params->maxTiles; m_tileLutSize = dtNextPow2(params->maxTiles/4); if (!m_tileLutSize) m_tileLutSize = 1; m_tileLutMask = m_tileLutSize-1; m_tiles = (dtMeshTile*)dtAlloc(sizeof(dtMeshTile)*m_maxTiles, DT_ALLOC_PERM); if (!m_tiles) return DT_FAILURE | DT_OUT_OF_MEMORY; m_posLookup = (dtMeshTile**)dtAlloc(sizeof(dtMeshTile*)*m_tileLutSize, DT_ALLOC_PERM); if (!m_posLookup) return DT_FAILURE | DT_OUT_OF_MEMORY; memset(m_tiles, 0, sizeof(dtMeshTile)*m_maxTiles); memset(m_posLookup, 0, sizeof(dtMeshTile*)*m_tileLutSize); m_nextFree = 0; for (int i = m_maxTiles-1; i >= 0; --i) { m_tiles[i].salt = 1; m_tiles[i].next = m_nextFree; m_nextFree = &m_tiles[i]; } // Init ID generator values. #ifndef DT_POLYREF64 m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles)); m_polyBits = dtIlog2(dtNextPow2((unsigned int)params->maxPolys)); // Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow. m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits - m_polyBits); if (m_saltBits < 10) return DT_FAILURE | DT_INVALID_PARAM; #endif return DT_SUCCESS; }
bool dtNavMesh::init(const dtNavMeshParams* params) { memcpy(&m_params, params, sizeof(dtNavMeshParams)); dtVcopy(m_orig, params->orig); m_tileWidth = params->tileWidth; m_tileHeight = params->tileHeight; // Init tiles m_maxTiles = params->maxTiles; m_tileLutSize = dtNextPow2(params->maxTiles/4); if (!m_tileLutSize) m_tileLutSize = 1; m_tileLutMask = m_tileLutSize-1; m_tiles = (dtMeshTile*)dtAlloc(sizeof(dtMeshTile)*m_maxTiles, DT_ALLOC_PERM); if (!m_tiles) return false; m_posLookup = (dtMeshTile**)dtAlloc(sizeof(dtMeshTile*)*m_tileLutSize, DT_ALLOC_PERM); if (!m_posLookup) return false; memset(m_tiles, 0, sizeof(dtMeshTile)*m_maxTiles); memset(m_posLookup, 0, sizeof(dtMeshTile*)*m_tileLutSize); m_nextFree = 0; for (int i = m_maxTiles-1; i >= 0; --i) { m_tiles[i].salt = 1; m_tiles[i].next = m_nextFree; m_nextFree = &m_tiles[i]; } // Init ID generator values. m_tileBits = dtMax((unsigned int)1, dtIlog2(dtNextPow2((unsigned int)params->maxTiles))); m_polyBits = dtMax((unsigned int)1, dtIlog2(dtNextPow2((unsigned int)params->maxPolys))); m_saltBits = 32 - m_tileBits - m_polyBits; if (m_saltBits < 10) return false; return true; }
dtNodePool::dtNodePool(int maxNodes, int hashSize) : m_nodes(0), m_first(0), m_next(0), m_maxNodes(maxNodes), m_hashSize(hashSize), m_nodeCount(0) { dtAssert(dtNextPow2(m_hashSize) == (unsigned int)m_hashSize); dtAssert(m_maxNodes > 0); m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM); m_next = (dtNodeRef*)dtAlloc(sizeof(dtNodeRef)*m_maxNodes, DT_ALLOC_PERM); m_first = (dtNodeRef*)dtAlloc(sizeof(dtNodeRef)*hashSize, DT_ALLOC_PERM); dtAssert(m_nodes); dtAssert(m_next); dtAssert(m_first); memset(m_first, 0xff, sizeof(dtNodeRef)*m_hashSize); memset(m_next, 0xff, sizeof(dtNodeRef)*m_maxNodes); }
dtStatus dtNavMesh::init(const dtNavMeshParams* params) { memcpy(&m_params, params, sizeof(dtNavMeshParams)); dtVcopy(m_orig, params->orig); m_tileWidth = params->tileWidth; m_tileHeight = params->tileHeight; // Init tiles m_maxTiles = params->maxTiles; m_tileLutSize = dtNextPow2(params->maxTiles/4); if (!m_tileLutSize) m_tileLutSize = 1; m_tileLutMask = m_tileLutSize-1; m_tiles = (dtMeshTile*)dtAlloc(sizeof(dtMeshTile)*m_maxTiles, DT_ALLOC_PERM); if (!m_tiles) return DT_FAILURE | DT_OUT_OF_MEMORY; m_posLookup = (dtMeshTile**)dtAlloc(sizeof(dtMeshTile*)*m_tileLutSize, DT_ALLOC_PERM); if (!m_posLookup) return DT_FAILURE | DT_OUT_OF_MEMORY; memset(m_tiles, 0, sizeof(dtMeshTile)*m_maxTiles); memset(m_posLookup, 0, sizeof(dtMeshTile*)*m_tileLutSize); m_nextFree = 0; for (int i = m_maxTiles-1; i >= 0; --i) { m_tiles[i].salt = 1; m_tiles[i].next = m_nextFree; m_nextFree = &m_tiles[i]; } // Init ID generator values. m_tileBits = STATIC_TILE_BITS; //dtIlog2(dtNextPow2((unsigned int)params->maxTiles)); m_polyBits = STATIC_POLY_BITS; //dtIlog2(dtNextPow2((unsigned int)params->maxPolys)); m_saltBits = STATIC_SALT_BITS; //sizeof(dtPolyRef)*8 - m_tileBits - m_polyBits; //if (m_saltBits < SALT_MIN_BITS) //return DT_FAILURE | DT_INVALID_PARAM; return DT_SUCCESS; }
dtStatus dtNavMesh::init(const dtNavMeshParams* params) { memcpy(&m_params, params, sizeof(dtNavMeshParams)); dtVcopy(m_orig, params->orig); m_tileWidth = params->tileWidth; m_tileHeight = params->tileHeight; // Init tiles m_maxTiles = params->maxTiles; m_tileLutSize = dtNextPow2(params->maxTiles/4); if (!m_tileLutSize) m_tileLutSize = 1; m_tileLutMask = m_tileLutSize-1; m_tiles = (dtMeshTile*)dtAlloc(sizeof(dtMeshTile)*m_maxTiles, DT_ALLOC_PERM); if (!m_tiles) return DT_FAILURE | DT_OUT_OF_MEMORY; m_posLookup = (dtMeshTile**)dtAlloc(sizeof(dtMeshTile*)*m_tileLutSize, DT_ALLOC_PERM); if (!m_posLookup) return DT_FAILURE | DT_OUT_OF_MEMORY; memset(m_tiles, 0, sizeof(dtMeshTile)*m_maxTiles); memset(m_posLookup, 0, sizeof(dtMeshTile*)*m_tileLutSize); m_nextFree = 0; for (int i = m_maxTiles-1; i >= 0; --i) { m_tiles[i].salt = 1; m_tiles[i].next = m_nextFree; m_nextFree = &m_tiles[i]; } // Edited by OC m_tileBits = STATIC_TILE_BITS; m_polyBits = STATIC_POLY_BITS; m_saltBits = STATIC_SALT_BITS; return DT_SUCCESS; }
bool OgreDetourTileCache::configure(InputGeom *inputGeom) { m_geom = inputGeom; // Reuse OgreRecast context for tiled navmesh building m_ctx = m_recast->m_ctx; if (!m_geom || m_geom->isEmpty()) { m_recast->m_pLog->logMessage("ERROR: OgreDetourTileCache::configure: No vertices and triangles."); return false; } if (!m_geom->getChunkyMesh()) { m_recast->m_pLog->logMessage("ERROR: OgreDetourTileCache::configure: Input mesh has no chunkyTriMesh built."); return false; } m_tmproc->init(m_geom); // Init cache bounding box const float* bmin = m_geom->getMeshBoundsMin(); const float* bmax = m_geom->getMeshBoundsMax(); // Navmesh generation params. // Use config from recast module m_cfg = m_recast->m_cfg; // Most params are taken from OgreRecast::configure, except for these: m_cfg.tileSize = m_tileSize; m_cfg.borderSize = (int) (m_cfg.walkableRadius + BORDER_PADDING); // Reserve enough padding. m_cfg.width = m_cfg.tileSize + m_cfg.borderSize*2; m_cfg.height = m_cfg.tileSize + m_cfg.borderSize*2; // Set mesh bounds rcVcopy(m_cfg.bmin, bmin); rcVcopy(m_cfg.bmax, bmax); // Also define navmesh bounds in recast component rcVcopy(m_recast->m_cfg.bmin, bmin); rcVcopy(m_recast->m_cfg.bmax, bmax); // Cell size navmesh generation property is copied from OgreRecast config m_cellSize = m_cfg.cs; // Determine grid size (number of tiles) based on bounding box and grid cell size int gw = 0, gh = 0; rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); // Calculates total size of voxel grid const int ts = m_tileSize; const int tw = (gw + ts-1) / ts; // Tile width const int th = (gh + ts-1) / ts; // Tile height m_tw = tw; m_th = th; Ogre::LogManager::getSingletonPtr()->logMessage("Total Voxels: "+Ogre::StringConverter::toString(gw) + " x " + Ogre::StringConverter::toString(gh)); Ogre::LogManager::getSingletonPtr()->logMessage("Tilesize: "+Ogre::StringConverter::toString(m_tileSize)+" Cellsize: "+Ogre::StringConverter::toString(m_cellSize)); Ogre::LogManager::getSingletonPtr()->logMessage("Tiles: "+Ogre::StringConverter::toString(m_tw)+" x "+Ogre::StringConverter::toString(m_th)); // 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; Ogre::LogManager::getSingletonPtr()->logMessage("Max Tiles: " + Ogre::StringConverter::toString(m_maxTiles)); Ogre::LogManager::getSingletonPtr()->logMessage("Max Polys: " + Ogre::StringConverter::toString(m_maxPolysPerTile)); // Tile cache params. memset(&m_tcparams, 0, sizeof(m_tcparams)); rcVcopy(m_tcparams.orig, bmin); m_tcparams.width = m_tileSize; m_tcparams.height = m_tileSize; m_tcparams.maxTiles = tw*th*EXPECTED_LAYERS_PER_TILE; m_tcparams.maxObstacles = MAX_OBSTACLES; // Max number of temp obstacles that can be added to or removed from navmesh // Copy the rest of the parameters from OgreRecast config m_tcparams.cs = m_cfg.cs; m_tcparams.ch = m_cfg.ch; m_tcparams.walkableHeight = (float) m_cfg.walkableHeight; m_tcparams.walkableRadius = (float) m_cfg.walkableRadius; m_tcparams.walkableClimb = (float) m_cfg.walkableClimb; m_tcparams.maxSimplificationError = m_cfg.maxSimplificationError; return initTileCache(); }
bool OgreDetourTileCache::loadAll(Ogre::String filename) { FILE* fp = fopen(filename.data(), "rb"); if (!fp) { Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not open file."); return false; } // Read header. TileCacheSetHeader header; fread(&header, sizeof(TileCacheSetHeader), 1, fp); if (header.magic != TILECACHESET_MAGIC) { fclose(fp); Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). File does not appear to contain valid tilecache data."); return false; } if (header.version != TILECACHESET_VERSION) { fclose(fp); Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). File contains a different version of the tilecache data format ("+Ogre::StringConverter::toString(header.version)+" instead of "+Ogre::StringConverter::toString(TILECACHESET_VERSION)+")."); return false; } m_recast->m_navMesh = dtAllocNavMesh(); if (!m_recast->m_navMesh) { fclose(fp); Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not allocate navmesh."); return false; } dtStatus status = m_recast->m_navMesh->init(&header.meshParams); if (dtStatusFailed(status)) { fclose(fp); Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not init navmesh."); return false; } m_tileCache = dtAllocTileCache(); if (!m_tileCache) { fclose(fp); Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not allocate tilecache."); return false; } status = m_tileCache->init(&header.cacheParams, m_talloc, m_tcomp, m_tmproc); if (dtStatusFailed(status)) { fclose(fp); Ogre::LogManager::getSingletonPtr()->logMessage("Error: OgreDetourTileCache::loadAll("+filename+"). Could not init tilecache."); return false; } memcpy(&m_cfg, &header.recastConfig, sizeof(rcConfig)); // Read tiles. for (int i = 0; i < header.numTiles; ++i) { TileCacheTileHeader tileHeader; fread(&tileHeader, sizeof(tileHeader), 1, fp); if (!tileHeader.tileRef || !tileHeader.dataSize) break; unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM); if (!data) break; memset(data, 0, tileHeader.dataSize); fread(data, tileHeader.dataSize, 1, fp); dtCompressedTileRef tile = 0; m_tileCache->addTile(data, tileHeader.dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tile); if (tile) m_tileCache->buildNavMeshTile(tile, m_recast->m_navMesh); } fclose(fp); // Init recast navmeshquery with created navmesh (in OgreRecast component) m_recast->m_navQuery = dtAllocNavMeshQuery(); m_recast->m_navQuery->init(m_recast->m_navMesh, 2048); // Config // TODO handle this nicer, also inputGeom is not inited, making some functions crash m_cellSize = m_cfg.cs; m_tileSize = m_cfg.tileSize; // cache bounding box const float* bmin = m_cfg.bmin; const float* bmax = m_cfg.bmax; // Copy loaded config back to recast module memcpy(&m_recast->m_cfg, &m_cfg, sizeof(rcConfig)); m_tileSize = m_cfg.tileSize; m_cellSize = m_cfg.cs; m_tcparams = header.cacheParams; // Determine grid size (number of tiles) based on bounding box and grid cell size int gw = 0, gh = 0; rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); // Calculates total size of voxel grid const int ts = m_tileSize; const int tw = (gw + ts-1) / ts; // Tile width const int th = (gh + ts-1) / ts; // Tile height m_tw = tw; m_th = th; Ogre::LogManager::getSingletonPtr()->logMessage("Total Voxels: "+Ogre::StringConverter::toString(gw) + " x " + Ogre::StringConverter::toString(gh)); Ogre::LogManager::getSingletonPtr()->logMessage("Tilesize: "+Ogre::StringConverter::toString(m_tileSize)+" Cellsize: "+Ogre::StringConverter::toString(m_cellSize)); Ogre::LogManager::getSingletonPtr()->logMessage("Tiles: "+Ogre::StringConverter::toString(m_tw)+" x "+Ogre::StringConverter::toString(m_th)); // 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; Ogre::LogManager::getSingletonPtr()->logMessage("Max Tiles: " + Ogre::StringConverter::toString(m_maxTiles)); Ogre::LogManager::getSingletonPtr()->logMessage("Max Polys: " + Ogre::StringConverter::toString(m_maxPolysPerTile)); // End config //// buildInitialNavmesh(); return true; }
//----------------------------------------------------------------------------- // 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(); }