#include "navmeshmanager.hpp" #include "debug.hpp" #include "makenavmesh.hpp" #include "settings.hpp" #include #include #include namespace DetourNavigator { NavMeshManager::NavMeshManager(const Settings& settings) : mSettings(settings) , mRecastMeshManager(settings) , mAsyncNavMeshUpdater(settings) {} bool NavMeshManager::removeObject(std::size_t id) { const auto object = mRecastMeshManager.removeObject(id); if (!object) return false; ++mRevision; addChangedTiles(*object->mShape, object->mTransform); return true; } void NavMeshManager::reset(const osg::Vec3f& agentHalfExtents) { mCache.erase(agentHalfExtents); } void NavMeshManager::update(const osg::Vec3f& agentHalfExtents) { auto cached = mCache.find(agentHalfExtents); if (cached == mCache.end()) cached = mCache.insert(std::make_pair(agentHalfExtents, std::make_shared(NavMeshCacheItem { makeEmptyNavMesh(agentHalfExtents, *mRecastMeshManager.getMesh(), mSettings), mRevision }))).first; else if (cached->second->mRevision >= mRevision) return; cached->second->mRevision = mRevision; const auto changedTiles = mChangedTiles.find(agentHalfExtents); if (changedTiles == mChangedTiles.end()) { mAsyncNavMeshUpdater.post(agentHalfExtents, mRecastMeshManager.getMesh(), cached->second, std::set()); } else { mAsyncNavMeshUpdater.post(agentHalfExtents, mRecastMeshManager.getMesh(), cached->second, std::move(changedTiles->second)); mChangedTiles.erase(changedTiles); } } void NavMeshManager::wait() { mAsyncNavMeshUpdater.wait(); } NavMeshConstPtr NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const { const auto it = mCache.find(agentHalfExtents); if (it == mCache.end()) return nullptr; return it->second->mValue; } void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform) { btVector3 aabbMin; btVector3 aabbMax; shape.getAabb(transform, aabbMin, aabbMax); osg::Vec3f min(aabbMin.x(), aabbMin.z(), aabbMin.y()); osg::Vec3f max(aabbMax.x(), aabbMax.z(), aabbMax.y()); min *= mSettings.mRecastScaleFactor; max *= mSettings.mRecastScaleFactor; for (auto& v : mCache) { if (const auto& item = v.second) { if (const auto& navMesh = item->mValue) { auto& changedTiles = mChangedTiles[v.first]; int minTileX; int minTileY; navMesh->calcTileLoc(min.ptr(), &minTileX, &minTileY); int maxTileX; int maxTileY; navMesh->calcTileLoc(max.ptr(), &maxTileX, &maxTileY); if (minTileX > maxTileX) std::swap(minTileX, maxTileX); if (minTileY > maxTileY) std::swap(minTileY, maxTileY); for (int tileX = minTileX; tileX <= maxTileX; ++tileX) for (int tileY = minTileY; tileY <= maxTileY; ++tileY) changedTiles.insert(TilePosition {tileX, tileY}); } } } } }