NavMeshGenerator::NavMeshGenerator(rcContext* ctx) : m_ctx(ctx), m_keepInterResults(true), m_totalBuildTimeMs(0), m_solid(0), m_chf(0), m_cset(0), m_pmesh(0), m_dmesh(0), m_navMesh(0) { m_cellSize = 0.3f; m_cellHeight = 0.2f; m_agentHeight = 2.0f; m_agentRadius = 0.6f; m_agentMaxClimb = 0.9f; m_agentMaxSlope = 45.0f; m_regionMinSize = 8; m_regionMergeSize = 20; m_edgeMaxLen = 12.0f; m_edgeMaxError = 1.3f; m_vertsPerPoly = 6.0f; m_detailSampleDist = 6.0f; m_detailSampleMaxError = 1.0f; m_partitionType = 0; //SAMPLE_PARTITION_WATERSHED; m_navQuery = dtAllocNavMeshQuery(); m_crowd = dtAllocCrowd(); }
void CCollideInterface::ActivateMap(uint32 mapid) { m_navmaplock.Acquire(); std::map<uint32, NavMeshData*>::iterator itr = m_navdata.find(mapid); if(itr != m_navdata.end()) ++itr->second->refs; else { //load params char filename[1024]; sprintf(filename, "mmaps/%03i.mmap", mapid); FILE* f = fopen(filename, "rb"); if(f == NULL) { m_navmaplock.Release(); return; } dtNavMeshParams params; fread(¶ms, sizeof(params), 1, f); fclose(f); NavMeshData* d = new NavMeshData; d->mesh = dtAllocNavMesh(); d->query = dtAllocNavMeshQuery(); d->mesh->init(¶ms); d->query->init(d->mesh, 1024); d->AddRef(); m_navdata.insert(std::make_pair(mapid, d)); } m_navmaplock.Release(); }
dtCrowdQuery::dtCrowdQuery(unsigned maxAgents, const dtCrowdAgent* agents, const dtCrowdAgentEnvironment* env) : m_agents(agents), m_maxAgents(maxAgents), m_agentsEnv(env) { m_navMeshQuery = dtAllocNavMeshQuery(); }
void NavMesh::InitMesh() { // common setting m_cellSize = 0.3f; m_cellHeight = 0.2f; m_agentHeight = 2.0f; m_agentRadius = 0.6f; m_agentMaxClimb = 0.9f; m_agentMaxSlope = 45.0f; m_regionMinSize = 8; m_regionMergeSize = 20; m_edgeMaxLen = 12.0f; m_edgeMaxError = 1.3f; m_vertsPerPoly = 6.0f; m_detailSampleDist = 6.0f; m_detailSampleMaxError = 1.0f; // m_geom = 0; m_navMesh = 0; m_navQuery = dtAllocNavMeshQuery(); m_crowd = dtAllocCrowd(); m_tileCache = 0; m_maxTiles = 0; m_maxPolysPerTile = 0; m_tileSize = 48; m_talloc = new LinearAllocator(32000); m_tcomp = new FastLZCompressor; m_tmproc = new MeshProcess; }
bool nav_mesh::load(const char* file) { mesh_ = loadAll(file); if (mesh_ == nullptr) { return false; } query_ = dtAllocNavMeshQuery(); if (query_ == nullptr) { return false; } dtStatus status = query_->init(mesh_, 2048); if (dtStatusFailed(status)) { return false; } filter_.setIncludeFlags(SAMPLE_POLYFLAGS_ALL ^ SAMPLE_POLYFLAGS_DISABLED); filter_.setExcludeFlags(0); filter_.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); filter_.setAreaCost(SAMPLE_POLYAREA_WATER, 10.0f); filter_.setAreaCost(SAMPLE_POLYAREA_ROAD, 1.0f); filter_.setAreaCost(SAMPLE_POLYAREA_DOOR, 1.0f); filter_.setAreaCost(SAMPLE_POLYAREA_GRASS, 2.0f); filter_.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); return true; }
JNIEXPORT jlong JNICALL Java_ru_mmocore_external_recastnavigation_detour_NavMeshQuery_createContext (JNIEnv *env, jobject) { Classes::initJavaClasses(env); dtNavMeshQuery *context = dtAllocNavMeshQuery(); return reinterpret_cast<jlong>(context); }
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; }
dtNavMeshQuery* PathFinderManager::getNavQuery() { dtNavMeshQuery* query = m_navQuery.get(); if (query == NULL) { query = dtAllocNavMeshQuery(); m_navQuery.set(query); } return query; }
Sample::Sample() : m_geom(0), m_navMesh(0), m_navQuery(0), m_navMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS|DU_DRAWNAVMESH_CLOSEDLIST), m_tool(0), m_ctx(0) { resetCommonSettings(); m_navQuery = dtAllocNavMeshQuery(); }
Sample::Sample() : m_geom(0), m_navMesh(0), m_navQuery(0), m_crowd(0), m_ctx(0) { resetCommonSettings(); m_navQuery = dtAllocNavMeshQuery(); m_crowd = dtAllocCrowd(); }
Sample::Sample() : m_geom(0), m_navMesh(0), m_navQuery(0), m_crowd(0), m_navMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS|DU_DRAWNAVMESH_CLOSEDLIST), m_tool(0), m_ctx(0) { resetCommonSettings(); m_navQuery = dtAllocNavMeshQuery(); m_crowd = dtAllocCrowd(); for (int i = 0; i < MAX_TOOLS; i++) m_toolStates[i] = 0; }
bool dtPathQueue::init(const int maxPathSize, const int maxSearchNodeCount, dtNavMesh* nav) { purge(); m_navquery = dtAllocNavMeshQuery(); if (!m_navquery) return false; if (dtStatusFailed(m_navquery->init(nav, maxSearchNodeCount))) return false; m_maxPathSize = maxPathSize; for (int i = 0; i < MAX_QUEUE; ++i) { m_queue[i].ref = DT_PATHQ_INVALID; m_queue[i].path = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathSize, DT_ALLOC_PERM); if (!m_queue[i].path) return false; } m_queueHead = 0; return true; }
bool NavigationMesh::InitializeQuery() { if (!navMesh_ || !node_) return false; if (navMeshQuery_) return true; navMeshQuery_ = dtAllocNavMeshQuery(); if (!navMeshQuery_) { LOGERROR("Could not create navigation mesh query"); return false; } if (dtStatusFailed(navMeshQuery_->init(navMesh_, MAX_POLYS))) { LOGERROR("Could not init navigation mesh query"); return false; } return true; }
bool NavPath::onAdd() { if(!Parent::onAdd()) return false; if(gEditingMission) mNetFlags.set(Ghostable); resize(); addToScene(); if(isServerObject()) { mQuery = dtAllocNavMeshQuery(); if(!mQuery) return false; checkAutoUpdate(); if(!plan()) setProcessTick(true); } return true; }
////////////////// PathInfo ////////////////// PathInfo::PathInfo(const Unit* owner, const float destX, const float destY, const float destZ, bool useStraightPath) : m_pathPolyRefs(NULL), m_polyLength(0), m_type(PATHFIND_BLANK), m_useStraightPath(useStraightPath), m_sourceUnit(owner), m_navMesh(NULL), m_navMeshQuery(NULL) { PathNode endPoint(destX, destY, destZ); setEndPosition(endPoint); float x,y,z; m_sourceUnit->GetPosition(x, y, z); PathNode startPoint(x, y, z); setStartPosition(startPoint); PATH_DEBUG("++ PathInfo::PathInfo for %u \n", m_sourceUnit->GetGUID()); const Map* map = m_sourceUnit->GetMap(); if (map->IsPathfindingEnabled()) m_navMesh = map->GetNavMesh(); if (m_navMesh) { m_navMeshQuery = dtAllocNavMeshQuery(); ASSERT(m_navMeshQuery); if(DT_SUCCESS != m_navMeshQuery->init(m_navMesh, MESH_MAX_NODES)) { sLog->outError("%u's PathInfo navMeshQuery failed to init", m_sourceUnit->GetGUID()); return; } BuildPolyPath(startPoint, endPoint); } else { BuildShortcut(); m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH); } }
/// @par /// /// May be called more than once to purge and re-initialize the crowd. bool dtCrowd::init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav) { purge(); m_maxAgents = maxAgents; m_maxAgentRadius = maxAgentRadius; dtVset(m_ext, m_maxAgentRadius*2.0f,m_maxAgentRadius*1.5f,m_maxAgentRadius*2.0f); m_grid = dtAllocProximityGrid(); if (!m_grid) return false; if (!m_grid->init(m_maxAgents*4, maxAgentRadius*3)) return false; m_obstacleQuery = dtAllocObstacleAvoidanceQuery(); if (!m_obstacleQuery) return false; if (!m_obstacleQuery->init(6, 8)) return false; // Init obstacle query params. memset(m_obstacleQueryParams, 0, sizeof(m_obstacleQueryParams)); for (int i = 0; i < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS; ++i) { dtObstacleAvoidanceParams* params = &m_obstacleQueryParams[i]; params->velBias = 0.4f; params->weightDesVel = 2.0f; params->weightCurVel = 0.75f; params->weightSide = 0.75f; params->weightToi = 2.5f; params->horizTime = 2.5f; params->gridSize = 33; params->adaptiveDivs = 7; params->adaptiveRings = 2; params->adaptiveDepth = 5; } // Allocate temp buffer for merging paths. m_maxPathResult = 256; m_pathResult = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathResult, DT_ALLOC_PERM); if (!m_pathResult) return false; if (!m_pathq.init(m_maxPathResult, MAX_PATHQUEUE_NODES, nav)) return false; m_agents = (dtCrowdAgent*)dtAlloc(sizeof(dtCrowdAgent)*m_maxAgents, DT_ALLOC_PERM); if (!m_agents) return false; m_activeAgents = (dtCrowdAgent**)dtAlloc(sizeof(dtCrowdAgent*)*m_maxAgents, DT_ALLOC_PERM); if (!m_activeAgents) return false; m_agentAnims = (dtCrowdAgentAnimation*)dtAlloc(sizeof(dtCrowdAgentAnimation)*m_maxAgents, DT_ALLOC_PERM); if (!m_agentAnims) return false; for (int i = 0; i < m_maxAgents; ++i) { new(&m_agents[i]) dtCrowdAgent(); m_agents[i].active = 0; if (!m_agents[i].corridor.init(m_maxPathResult)) return false; } for (int i = 0; i < m_maxAgents; ++i) { m_agentAnims[i].active = 0; } // The navquery is mostly used for local searches, no need for large node pool. m_navquery = dtAllocNavMeshQuery(); if (!m_navquery) return false; if (dtStatusFailed(m_navquery->init(nav, MAX_COMMON_NODES))) return false; return true; }
qboolean BotSetupNav( const botClass_t *botClass, qhandle_t *navHandle ) { cvar_t *maxNavNodes = Cvar_Get( "bot_maxNavNodes", "4096", CVAR_ARCHIVE | CVAR_LATCH ); if ( !numNavData ) { vec3_t clearVec = { 0, 0, 0 }; dtAllocSetCustom( dtAllocCustom, dtFreeCustom ); for ( int i = 0; i < MAX_CLIENTS; i++ ) { // should only init the corridor once if ( !agents[ i ].corridor.getPath() ) { if ( !agents[ i ].corridor.init( MAX_BOT_PATH ) ) { return qfalse; } } agents[ i ].corridor.reset( 0, clearVec ); agents[ i ].clientNum = i; agents[ i ].needReplan = true; agents[ i ].nav = NULL; agents[ i ].offMesh = false; memset( agents[ i ].routeResults, 0, sizeof( agents[ i ].routeResults ) ); } #ifndef DEDICATED NavEditInit(); #endif } if ( numNavData == MAX_NAV_DATA ) { Com_Printf( "^3ERROR: maximum number of navigation meshes exceeded\n" ); return qfalse; } NavData_t *nav = &BotNavData[ numNavData ]; const char *filename = botClass->name; if ( !BotLoadNavMesh( filename, *nav ) ) { BotShutdownNav(); return qfalse; } Q_strncpyz( nav->name, botClass->name, sizeof( nav->name ) ); nav->query = dtAllocNavMeshQuery(); if ( !nav->query ) { Com_Printf( "Could not allocate Detour Navigation Mesh Query for navmesh %s\n", filename ); BotShutdownNav(); return qfalse; } if ( dtStatusFailed( nav->query->init( nav->mesh, maxNavNodes->integer ) ) ) { Com_Printf( "Could not init Detour Navigation Mesh Query for navmesh %s\n", filename ); BotShutdownNav(); return qfalse; } nav->filter.setIncludeFlags( botClass->polyFlagsInclude ); nav->filter.setExcludeFlags( botClass->polyFlagsExclude ); *navHandle = numNavData; numNavData++; return qtrue; }
DetourInterface::DetourInterface(rcPolyMesh* polyMesh,rcPolyMeshDetail* detailMesh,rcdtConfig& config) : _navMesh(nullptr), _navQuery(nullptr), _isMeshBuilt(false) { detourCleanup(); unsigned char* navData = 0; int navDataSize = 0; if(config.recastConfig->maxVertsPerPoly > DT_VERTS_PER_POLYGON) { return; } #if defined(DEBUG) || defined(_DEBUG) std::cout << "Detour - Stage 1" << std::endl; #endif for(int i = 0; i < polyMesh->npolys; ++i) { if(polyMesh->areas[i] == RC_WALKABLE_AREA) { polyMesh->areas[i] = DT_PA_GROUND; polyMesh->flags[i] = DT_PF_WALK; } } dtNavMeshCreateParams params; memset(¶ms,0,sizeof(params)); params.verts = polyMesh->verts; params.vertCount = polyMesh->nverts; params.polys = polyMesh->polys; params.polyAreas = polyMesh->areas; params.polyFlags = polyMesh->flags; params.polyCount = polyMesh->npolys; params.nvp = polyMesh->nvp; params.detailMeshes = detailMesh->meshes; params.detailVerts = detailMesh->verts; params.detailVertsCount = detailMesh->nverts; params.detailTris = detailMesh->tris; params.detailTriCount = detailMesh->ntris; //offmesh connections are not implemented. I don't even know what they are! params.offMeshConCount = 0; params.walkableHeight = config.userConfig->getAgentHeight(); params.walkableRadius = config.userConfig->getAgentRadius(); params.walkableClimb = config.userConfig->getAgentMaxClimb(); params.buildBvTree = true; rcVcopy(params.bmin, config.recastConfig->bmin); rcVcopy(params.bmax, config.recastConfig->bmax); params.cs = config.recastConfig->cs; params.ch = config.recastConfig->ch; #if defined(DEBUG) || defined(_DEBUG) std::cout << "Detour - Stage 2" << std::endl; #endif if(!dtCreateNavMeshData(¶ms,&navData,&navDataSize)) { std::cout << "Error! Detour - could not build navmesh!" << std::endl; std::cout << " - " << params.cs << std::endl; std::cout << " - " << params.ch << std::endl; std::cout << " - " << params.walkableRadius << std::endl; //_isMeshBuilt = false; return; } #if defined(DEBUG) || defined(_DEBUG) std::cout << "Detour - Stage 3" << std::endl; #endif _navMesh = dtAllocNavMesh(); if(!_navMesh) { dtFree(_navMesh); std::cout << "Error! Detour - could not create Detour navmesh!" << std::endl; return; } #if defined(DEBUG) || defined(_DEBUG) std::cout << "Detour - Stage 4" << std::endl; #endif dtStatus status; status = _navMesh->init(navData,navDataSize,DT_TILE_FREE_DATA); if(dtStatusFailed(status)) { dtFree(navData); std::cout << "Error! Could not initialize Detour NavMesh." << std::endl; return; } #if defined(DEBUG) || defined(_DEBUG) std::cout << "Detour - Stage 5" << std::endl; #endif _navQuery = dtAllocNavMeshQuery(); status = _navQuery->init(_navMesh,2048); if(dtStatusFailed(status)) { std::cout << "Error! Detour - could not initialize Detour navmesh query." << std::endl; return; } _isMeshBuilt = true; }
/// @par /// /// May be called more than once to purge and re-initialize the crowd. bool dtCrowd::init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav) { purge(); m_maxAgents = maxAgents; m_maxAgentRadius = maxAgentRadius; m_numActiveAgents = 0; dtVset(m_ext, m_maxAgentRadius*2.0f,m_maxAgentRadius*1.5f,m_maxAgentRadius*2.0f); m_grid = dtAllocProximityGrid(); if (!m_grid) return false; if (!m_grid->init(m_maxAgents*4, maxAgentRadius*3)) return false; // [UE4] moved avoidance query init to separate function // Allocate temp buffer for merging paths. m_maxPathResult = 256; m_pathResult = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathResult, DT_ALLOC_PERM); if (!m_pathResult) return false; if (!m_pathq.init(m_maxPathResult, MAX_PATHQUEUE_NODES, nav)) return false; m_agents = (dtCrowdAgent*)dtAlloc(sizeof(dtCrowdAgent)*m_maxAgents, DT_ALLOC_PERM); if (!m_agents) return false; m_activeAgents = (dtCrowdAgent**)dtAlloc(sizeof(dtCrowdAgent*)*m_maxAgents, DT_ALLOC_PERM); if (!m_activeAgents) return false; m_agentAnims = (dtCrowdAgentAnimation*)dtAlloc(sizeof(dtCrowdAgentAnimation)*m_maxAgents, DT_ALLOC_PERM); if (!m_agentAnims) return false; for (int i = 0; i < m_maxAgents; ++i) { new(&m_agents[i]) dtCrowdAgent(); m_agents[i].active = 0; if (!m_agents[i].corridor.init(m_maxPathResult)) return false; } for (int i = 0; i < m_maxAgents; ++i) { m_agentAnims[i].active = 0; } for (int i = 0; i < DT_MAX_AREAS; i++) { m_raycastFilter.setAreaCost(i, DT_UNWALKABLE_POLY_COST); } // The navquery is mostly used for local searches, no need for large node pool. m_navquery = dtAllocNavMeshQuery(); if (!m_navquery) return false; if (dtStatusFailed(m_navquery->init(nav, MAX_COMMON_NODES))) return false; return true; }
bool NavMesh::loadNavMeshFile() { auto data = FileUtils::getInstance()->getDataFromFile(_navFilePath); if (data.isNull()) return false; // Read header. unsigned int offset = 0; TileCacheSetHeader header = *((TileCacheSetHeader*)(data.getBytes() + offset)); offset += sizeof(TileCacheSetHeader); if (header.magic != TILECACHESET_MAGIC) { return false; } if (header.version != TILECACHESET_VERSION) { return false; } _navMesh = dtAllocNavMesh(); if (!_navMesh) { return false; } dtStatus status = _navMesh->init(&header.meshParams); if (dtStatusFailed(status)) { return false; } _tileCache = dtAllocTileCache(); if (!_tileCache) { return false; } _allocator = new LinearAllocator(32000); _compressor = new FastLZCompressor; _meshProcess = new MeshProcess(_geomData); status = _tileCache->init(&header.cacheParams, _allocator, _compressor, _meshProcess); if (dtStatusFailed(status)) { return false; } // Read tiles. for (int i = 0; i < header.numTiles; ++i) { TileCacheTileHeader tileHeader = *((TileCacheTileHeader*)(data.getBytes() + offset)); offset += sizeof(TileCacheTileHeader); if (!tileHeader.tileRef || !tileHeader.dataSize) break; unsigned char* tileData = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM); if (!tileData) break; memcpy(tileData, (data.getBytes() + offset), tileHeader.dataSize); offset += tileHeader.dataSize; dtCompressedTileRef tile = 0; _tileCache->addTile(tileData, tileHeader.dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tile); if (tile) _tileCache->buildNavMeshTile(tile, _navMesh); } //create crowed _crowed = dtAllocCrowd(); _crowed->init(MAX_AGENTS, header.cacheParams.walkableRadius, _navMesh); //create NavMeshQuery _navMeshQuery = dtAllocNavMeshQuery(); _navMeshQuery->init(_navMesh, 2048); _agentList.assign(MAX_AGENTS, nullptr); _obstacleList.assign(header.cacheParams.maxObstacles, nullptr); //duDebugDrawNavMesh(&_debugDraw, *_navMesh, DU_DRAWNAVMESH_OFFMESHCONS); return true; }
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; }
bool OgreRecast::NavMeshBuild(InputGeom* input) { // TODO: clean up unused variables m_pLog->logMessage("NavMeshBuild Start"); // // Step 1. Initialize build config. // // Reset build times gathering. m_ctx->resetTimers(); // Start the build process. m_ctx->startTimer(RC_TIMER_TOTAL); // // Step 2. Rasterize input polygon soup. // InputGeom *inputGeom = input; rcVcopy(m_cfg.bmin, inputGeom->getMeshBoundsMin()); rcVcopy(m_cfg.bmax, inputGeom->getMeshBoundsMax()); rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height); int nverts = inputGeom->getVertCount(); int ntris = inputGeom->getTriCount(); Ogre::Vector3 min; FloatAToOgreVect3(inputGeom->getMeshBoundsMin(), min); Ogre::Vector3 max; FloatAToOgreVect3(inputGeom->getMeshBoundsMax(), max); //Ogre::LogManager::getSingletonPtr()->logMessage("Bounds: "+Ogre::StringConverter::toString(min) + " "+ Ogre::StringConverter::toString(max)); m_pLog->logMessage("Building navigation:"); m_pLog->logMessage(" - " + Ogre::StringConverter::toString(m_cfg.width) + " x " + Ogre::StringConverter::toString(m_cfg.height) + " cells"); m_pLog->logMessage(" - " + Ogre::StringConverter::toString(nverts/1000.0f) + " K verts, " + Ogre::StringConverter::toString(ntris/1000.0f) + " K tris"); // Allocate voxel heightfield where we rasterize our input data to. m_solid = rcAllocHeightfield(); if (!m_solid) { m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'solid'."); return false; } if (!rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch)) { m_pLog->logMessage("ERROR: buildNavigation: Could not create solid heightfield. Possibly it requires too much memory, try setting a higher cellSize and cellHeight value."); return false; } // Allocate array that can hold triangle area types. // If you have multiple meshes you need to process, allocate // an array which can hold the max number of triangles you need to process. m_triareas = new unsigned char[ntris]; if (!m_triareas) { m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'm_triareas' ("+Ogre::StringConverter::toString(ntris)+")."); return false; } // Find triangles which are walkable based on their slope and rasterize them. // If your input data is multiple meshes, you can transform them here, calculate // the are type for each of the meshes and rasterize them. memset(m_triareas, 0, ntris*sizeof(unsigned char)); rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, inputGeom->getVerts(), inputGeom->getVertCount(), inputGeom->getTris(), inputGeom->getTriCount(), m_triareas); rcRasterizeTriangles(m_ctx, inputGeom->getVerts(), inputGeom->getVertCount(), inputGeom->getTris(), m_triareas, inputGeom->getTriCount(), *m_solid, m_cfg.walkableClimb); if (!m_keepInterResults) { delete [] m_triareas; m_triareas = 0; } // // Step 3. Filter walkables surfaces. // // Once all geoemtry 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(m_ctx, m_cfg.walkableClimb, *m_solid); rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid); rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, *m_solid); // // Step 4. Partition walkable surface to simple regions. // // Compact the heightfield so that it is faster to handle from now on. // This will result more cache coherent data as well as the neighbours // between walkable cells will be calculated. m_chf = rcAllocCompactHeightfield(); if (!m_chf) { m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'chf'."); return false; } if (!rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf)) { m_pLog->logMessage("ERROR: buildNavigation: Could not build compact data."); return false; } if (!m_keepInterResults) { rcFreeHeightField(m_solid); m_solid = 0; } // Erode the walkable area by agent radius. if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf)) { m_pLog->logMessage("ERROR: buildNavigation: Could not erode walkable areas."); return false; } // TODO implement // (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, (unsigned char)vols[i].area, *m_chf); // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!rcBuildDistanceField(m_ctx, *m_chf)) { m_pLog->logMessage("ERROR: buildNavigation: Could not build distance field."); return false; } // Partition the walkable surface into simple regions without holes. if (!rcBuildRegions(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) { m_pLog->logMessage("ERROR: buildNavigation: Could not build regions."); return false; } // // Step 5. Trace and simplify region contours. // // Create contours. m_cset = rcAllocContourSet(); if (!m_cset) { m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'cset'."); return false; } if (!rcBuildContours(m_ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset)) { m_pLog->logMessage("ERROR: buildNavigation: Could not create contours."); return false; } if (m_cset->nconts == 0) { // In case of errors see: http://groups.google.com/group/recastnavigation/browse_thread/thread/a6fbd509859a12c8 // You should probably tweak the parameters m_pLog->logMessage("ERROR: No contours created (Recast)!"); } // // Step 6. Build polygons mesh from contours. // // Build polygon navmesh from the contours. m_pmesh = rcAllocPolyMesh(); if (!m_pmesh) { m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'pmesh'."); return false; } if (!rcBuildPolyMesh(m_ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh)) { // Try modifying the parameters. I experienced this error when setting agentMaxClimb too high. m_pLog->logMessage("ERROR: buildNavigation: Could not triangulate contours."); return false; } // // Step 7. Create detail mesh which allows to access approximate height on each polygon. // m_dmesh = rcAllocPolyMeshDetail(); if (!m_dmesh) { m_pLog->logMessage("ERROR: buildNavigation: Out of memory 'pmdtl'."); return false; } if (!rcBuildPolyMeshDetail(m_ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh)) { m_pLog->logMessage("ERROR: buildNavigation: Could not build detail mesh."); return false; } if (!m_keepInterResults) { rcFreeCompactHeightfield(m_chf); m_chf = 0; rcFreeContourSet(m_cset); m_cset = 0; } // At this point the navigation mesh data is ready, you can access it from m_pmesh. // See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data. // // (Optional) Step 8. Create Detour data from Recast poly mesh. // // The GUI may allow more max points per polygon than Detour can handle. // Only build the detour navmesh if we do not exceed the limit. if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON) { m_pLog->logMessage("Detour 1000"); unsigned char* navData = 0; int navDataSize = 0; // Update poly flags from areas. for (int i = 0; i < m_pmesh->npolys; ++i) { if (m_pmesh->areas[i] == RC_WALKABLE_AREA) { m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND; m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK; } } // Set navmesh params dtNavMeshCreateParams params; memset(¶ms, 0, sizeof(params)); params.verts = m_pmesh->verts; params.vertCount = m_pmesh->nverts; params.polys = m_pmesh->polys; params.polyAreas = m_pmesh->areas; params.polyFlags = m_pmesh->flags; params.polyCount = m_pmesh->npolys; params.nvp = m_pmesh->nvp; params.detailMeshes = m_dmesh->meshes; params.detailVerts = m_dmesh->verts; params.detailVertsCount = m_dmesh->nverts; params.detailTris = m_dmesh->tris; params.detailTriCount = m_dmesh->ntris; // no off mesh connections yet m_offMeshConCount=0 ; params.offMeshConVerts = m_offMeshConVerts ; params.offMeshConRad = m_offMeshConRads ; params.offMeshConDir = m_offMeshConDirs ; params.offMeshConAreas = m_offMeshConAreas ; params.offMeshConFlags = m_offMeshConFlags ; params.offMeshConUserID = m_offMeshConId ; params.offMeshConCount = m_offMeshConCount ; params.walkableHeight = m_agentHeight; params.walkableRadius = m_agentRadius; params.walkableClimb = m_agentMaxClimb; rcVcopy(params.bmin, m_pmesh->bmin); rcVcopy(params.bmax, m_pmesh->bmax); params.cs = m_cfg.cs; params.ch = m_cfg.ch; m_pLog->logMessage("Detour 2000"); if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize)) { m_pLog->logMessage("ERROR: Could not build Detour navmesh."); return false; } m_pLog->logMessage("Detour 3000"); m_navMesh = dtAllocNavMesh(); if (!m_navMesh) { dtFree(navData); m_pLog->logMessage("ERROR: Could not create Detour navmesh"); return false; } m_pLog->logMessage("Detour 4000"); dtStatus status; status = m_navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA); if (dtStatusFailed(status)) { dtFree(navData); m_pLog->logMessage("ERROR: Could not init Detour navmesh"); return false; } m_pLog->logMessage("Detour 5000"); m_navQuery = dtAllocNavMeshQuery(); status = m_navQuery->init(m_navMesh, 2048); m_pLog->logMessage("Detour 5500"); if (dtStatusFailed(status)) { m_pLog->logMessage("ERROR: Could not init Detour navmesh query"); return false; } m_pLog->logMessage("Detour 6000"); } m_ctx->stopTimer(RC_TIMER_TOTAL); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cleanup stuff we don't need // delete [] rc_verts ; // delete [] rc_tris ; // delete [] rc_trinorms ; //CreateRecastPolyMesh(*m_pmesh) ; // Debug render it m_pLog->logMessage("NavMeshBuild End"); return true; }
bool NavMesher::Build() { // ******* Only for OBJ Loading **** cleanup(); const char * filepath = "../../media/models/"; if (!m_geom || !m_geom->loadMesh(filepath)) { delete m_geom; m_geom = 0; m_ctx->log(RC_LOG_ERROR, "Geom load log %s:"); } assert(m_geom); if (!m_geom || !m_geom->getMesh()) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified."); return false; } if(m_geom->getMesh()->getTriCount() <= 0 || m_geom->getMesh()->getVertCount()<=0) Ogre::Exception(0,Ogre::String("Bad verts or Triangle count. Verts: "+ StringConverter::toString( m_geom->getMesh()->getVertCount()) + "/n" + "Triangles :" +StringConverter::toString(m_geom->getMesh()->getTriCount())),"NavMesher::Build"); //reset timer Ogre::Timer tm; tm.reset(); unsigned long stime = tm.getMicroseconds(); //clear existing Clear(); // ******* Only for OBJ Loading **** const float* bmin = m_geom->getMeshBoundsMin(); const float* bmax = m_geom->getMeshBoundsMax(); const float* verts = m_geom->getMesh()->getVerts(); const int nverts = m_geom->getMesh()->getVertCount(); const int *tris = m_geom->getMesh()->getTris(); const int ntris = m_geom->getMesh()->getTriCount(); if(sizeof(tris) <= 0 || ntris <= 0) { return false; } // // Step 1. Initialize build config. // // Init build configuration from GUI memset(&m_cfg, 0, sizeof(m_cfg)); 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.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist; m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError; // Set the area where the navigation will be build. // Here the bounds of the input mesh are used, but the // area could be specified by an user defined box, etc. rcVcopy(m_cfg.bmin, bmin); rcVcopy(m_cfg.bmax, bmax); rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height); // Reset build times gathering. m_ctx->resetTimers(); // Start the build process. m_ctx->startTimer(RC_TIMER_TOTAL); m_ctx->log(RC_LOG_PROGRESS, "Building navigation:"); m_ctx->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height); m_ctx->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", nverts/1000.0f, ntris/1000.0f); // // Step 2. Rasterize input polygon soup. // // Allocate voxel heightfield where we rasterize our input data to. m_solid = rcAllocHeightfield(); if (!m_solid) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'."); return false; } if (!rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield."); return false; } // Allocate array that can hold triangle area types. // If you have multiple meshes you need to process, allocate // and array which can hold the max number of triangles you need to process. m_triareas = new unsigned char[ntris]; if (!m_triareas) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (%d).", ntris); return false; } // Find triangles which are walkable based on their slope and rasterize them. // If your input data is multiple meshes, you can transform them here, calculate // the are type for each of the meshes and rasterize them. memset(m_triareas, 0, ntris*sizeof(unsigned char)); rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas); rcRasterizeTriangles(m_ctx, verts, nverts, tris, m_triareas, ntris, *m_solid, m_cfg.walkableClimb); if (!m_keepInterResults) { delete [] m_triareas; m_triareas = 0; } // // Step 3. Filter walkables surfaces. // // Once all geoemtry 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(m_ctx, m_cfg.walkableClimb, *m_solid); rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid); rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, *m_solid); // // Step 4. Partition walkable surface to simple regions. // // Compact the heightfield so that it is faster to handle from now on. // This will result more cache coherent data as well as the neighbours // between walkable cells will be calculated. m_chf = rcAllocCompactHeightfield(); if (!m_chf) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'."); return false; } if (!rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data."); return false; } if (!m_keepInterResults) { rcFreeHeightField(m_solid); m_solid = 0; } // Erode the walkable area by agent radius. if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode."); return false; } // (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, (unsigned char)vols[i].area, *m_chf); if (m_monotonePartitioning) { // Partition the walkable surface into simple regions without holes. // Monotone partitioning does not need distancefield. if (!rcBuildRegionsMonotone(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions."); return false; } } else { // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!rcBuildDistanceField(m_ctx, *m_chf)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field."); return false; } // Partition the walkable surface into simple regions without holes. if (!rcBuildRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions."); return false; } } // // Step 5. Trace and simplify region contours. // // Create contours. m_cset = rcAllocContourSet(); if (!m_cset) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'."); return false; } if (!rcBuildContours(m_ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create contours."); return false; } // // Step 6. Build polygons mesh from contours. // // Build polygon navmesh from the contours. m_pmesh = rcAllocPolyMesh(); if (!m_pmesh) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'."); return false; } if (!rcBuildPolyMesh(m_ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours."); return false; } // // Step 7. Create detail mesh which allows to access approximate height on each polygon. // m_dmesh = rcAllocPolyMeshDetail(); if (!m_dmesh) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'."); return false; } if (!rcBuildPolyMeshDetail(m_ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build detail mesh."); return false; } if (!m_keepInterResults) { rcFreeCompactHeightfield(m_chf); m_chf = 0; rcFreeContourSet(m_cset); m_cset = 0; } // At this point the navigation mesh data is ready, you can access it from m_pmesh. // See rcDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data. // // (Optional) Step 8. Create Detour data from Recast poly mesh. // // The GUI may allow more max points per polygon than Detour can handle. // Only build the detour navmesh if we do not exceed the limit. unsigned char* navData = 0; int navDataSize = 0; // Update poly flags from areas. for (int i = 0; i < m_pmesh->npolys; ++i) { if (m_pmesh->areas[i] == RC_WALKABLE_AREA) m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND; if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND || m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS || m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD) { m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK; } else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_WATER) { m_pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM; } else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_DOOR) { m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR; } } memset(&m_params, 0, sizeof(m_params)); m_params.verts = m_pmesh->verts; m_params.vertCount = m_pmesh->nverts; m_params.polys = m_pmesh->polys; m_params.polyAreas = m_pmesh->areas; m_params.polyFlags = m_pmesh->flags; m_params.polyCount = m_pmesh->npolys; m_params.nvp = m_pmesh->nvp; m_params.detailMeshes = m_dmesh->meshes; m_params.detailVerts = m_dmesh->verts; m_params.detailVertsCount = m_dmesh->nverts; m_params.detailTris = m_dmesh->tris; m_params.detailTriCount = m_dmesh->ntris; m_params.walkableHeight = m_agentHeight; m_params.walkableRadius = m_agentRadius; m_params.walkableClimb = m_agentMaxClimb; rcVcopy(m_params.bmin, m_pmesh->bmin); rcVcopy(m_params.bmax, m_pmesh->bmax); m_params.cs = m_cfg.cs; m_params.ch = m_cfg.ch; m_params.buildBvTree = true; if (!dtCreateNavMeshData(&m_params, &navData, &navDataSize)) { m_ctx->log(RC_LOG_ERROR, "Could not build Detour navmesh."); return false; } m_navMesh = dtAllocNavMesh(); if (!m_navMesh) { delete [] navData; m_ctx->log(RC_LOG_ERROR, "Could not create Detour navmesh"); return false; } m_navQuery = dtAllocNavMeshQuery(); dtStatus status = m_navQuery->init(m_navMesh, 2048); if (dtStatusFailed(status)) { m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh query"); return false; } if (!m_navMesh->init(navData, navDataSize, true)) { delete [] navData; m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh"); return false; } //take time stime = tm.getMicroseconds() - stime; DrawDebug(); return true; }
bool NavMeshLoader::load_cai(const char* path) { FILE* fp = fopen(path, "rb"); if (!fp) return false; // Read header. NavMeshSetHeader_CAI header; size_t readLen = fread(&header, sizeof(NavMeshSetHeader_CAI), 1, fp); if (readLen != 1) { fclose(fp); return false; } if (header.version != NAVMESHSET_VERSION) { fclose(fp); return false; } dtNavMesh* mesh = dtAllocNavMesh(); if (!mesh) { fclose(fp); return false; } dtStatus status = mesh->init(&header.params); if (dtStatusFailed(status)) { fclose(fp); return false; } // Read tiles. for (int i = 0; i < header.tileCount; ++i) { NavMeshTileHeader tileHeader; readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp); if (readLen != 1) { fclose(fp); return false; } 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); readLen = fread(data, tileHeader.dataSize, 1, fp); if (readLen != 1) { fclose(fp); return false; } mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0); } fclose(fp); m_navMesh = mesh; m_navQuery = dtAllocNavMeshQuery(); status = m_navQuery->init(m_navMesh, 2048); if (dtStatusFailed(status)) { return false; } return true; }