void drawDetailOverlay(const dtTileCache* tc, const int tx, const int ty, double* proj, double* model, int* view) { dtCompressedTileRef tiles[MAX_LAYERS]; const int ntiles = tc->getTilesAt(tx,ty,tiles,MAX_LAYERS); if (!ntiles) return; const int rawSize = calcLayerBufferSize(tc->getParams()->width, tc->getParams()->height); char text[128]; for (int i = 0; i < ntiles; ++i) { const dtCompressedTile* tile = tc->getTileByRef(tiles[i]); float pos[3]; pos[0] = (tile->header->bmin[0]+tile->header->bmax[0])/2.0f; pos[1] = tile->header->bmin[1]; pos[2] = (tile->header->bmin[2]+tile->header->bmax[2])/2.0f; GLdouble x, y, z; if (gluProject((GLdouble)pos[0], (GLdouble)pos[1], (GLdouble)pos[2], model, proj, view, &x, &y, &z)) { snprintf(text,128,"(%d,%d)/%d", tile->header->tx,tile->header->ty,tile->header->tlayer); imguiDrawText((int)x, (int)y-25, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,220)); snprintf(text,128,"Compressed: %.1f kB", tile->dataSize/1024.0f); imguiDrawText((int)x, (int)y-45, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,128)); snprintf(text,128,"Raw:%.1fkB", rawSize/1024.0f); imguiDrawText((int)x, (int)y-65, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,128)); } } }
bool OgreDetourTileCache::TileCacheBuild(InputGeom *inputGeom) { // Init configuration for specified geometry configure(inputGeom); dtStatus status; // Preprocess tiles. // Prepares navmesh tiles in a 2D intermediary format that allows quick conversion to a 3D navmesh m_cacheLayerCount = 0; m_cacheCompressedSize = 0; m_cacheRawSize = 0; for (int y = 0; y < m_th; ++y) { for (int x = 0; x < m_tw; ++x) { TileCacheData tiles[MAX_LAYERS]; memset(tiles, 0, sizeof(tiles)); int ntiles = rasterizeTileLayers(m_geom, x, y, m_cfg, tiles, MAX_LAYERS); // This is where the tile is built for (int i = 0; i < ntiles; ++i) { TileCacheData* tile = &tiles[i]; status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0); // Add compressed tiles to tileCache if (dtStatusFailed(status)) { dtFree(tile->data); tile->data = 0; continue; } m_cacheLayerCount++; m_cacheCompressedSize += tile->dataSize; m_cacheRawSize += calcLayerBufferSize(m_tcparams.width, m_tcparams.height); } } } 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; }
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 OgreDetourTileCache::TileCacheBuild(InputGeom *inputGeom) { // Init configuration for specified geometry configure(inputGeom); dtStatus status; // Preprocess tiles. // Prepares navmesh tiles in a 2D intermediary format that allows quick conversion to a 3D navmesh // ctx->resetTimers(); m_cacheLayerCount = 0; m_cacheCompressedSize = 0; m_cacheRawSize = 0; for (int y = 0; y < m_th; ++y) { for (int x = 0; x < m_tw; ++x) { TileCacheData tiles[MAX_LAYERS]; memset(tiles, 0, sizeof(tiles)); int ntiles = rasterizeTileLayers(m_geom, x, y, m_cfg, tiles, MAX_LAYERS); // This is where the tile is built for (int i = 0; i < ntiles; ++i) { TileCacheData* tile = &tiles[i]; status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0); // Add compressed tiles to tileCache if (dtStatusFailed(status)) { dtFree(tile->data); tile->data = 0; continue; } m_cacheLayerCount++; m_cacheCompressedSize += tile->dataSize; m_cacheRawSize += calcLayerBufferSize(m_tcparams.width, m_tcparams.height); } } } // Build initial meshes // Builds detour compatible navmesh from all tiles. // A tile will have to be rebuilt if something changes, eg. a temporary obstacle is placed on it. // ctx->startTimer(RC_TIMER_TOTAL); for (int y = 0; y < m_th; ++y) for (int x = 0; x < m_tw; ++x) m_tileCache->buildNavMeshTilesAt(x,y, m_recast->m_navMesh); // This immediately builds the tile, without the need of a dtTileCache::update() // ctx->stopTimer(RC_TIMER_TOTAL); // m_cacheBuildTimeMs = ctx->getAccumulatedTime(RC_TIMER_TOTAL)/1000.0f; m_cacheBuildMemUsage = m_talloc->high; // Count the total size of all generated tiles of the tiled navmesh const dtNavMesh* nav = m_recast->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\n", navmeshMemUsage/1024.0f); Ogre::LogManager::getSingletonPtr()->logMessage("Navmesh Mem Usage = "+ Ogre::StringConverter::toString(navmeshMemUsage/1024.0f) +" kB"); Ogre::LogManager::getSingletonPtr()->logMessage("Tilecache Mem Usage = " +Ogre::StringConverter::toString(m_cacheCompressedSize/1024.0f) +" kB"); return true; }