1 #include "navigatorimpl.hpp" 2 #include "debug.hpp" 3 #include "settingsutils.hpp" 4 5 #include <components/esm/loadpgrd.hpp> 6 #include <components/misc/coordinateconverter.hpp> 7 8 namespace DetourNavigator 9 { NavigatorImpl(const Settings & settings)10 NavigatorImpl::NavigatorImpl(const Settings& settings) 11 : mSettings(settings) 12 , mNavMeshManager(mSettings) 13 , mUpdatesEnabled(true) 14 { 15 } 16 addAgent(const osg::Vec3f & agentHalfExtents)17 void NavigatorImpl::addAgent(const osg::Vec3f& agentHalfExtents) 18 { 19 if(agentHalfExtents.length2() <= 0) 20 return; 21 ++mAgents[agentHalfExtents]; 22 mNavMeshManager.addAgent(agentHalfExtents); 23 } 24 removeAgent(const osg::Vec3f & agentHalfExtents)25 void NavigatorImpl::removeAgent(const osg::Vec3f& agentHalfExtents) 26 { 27 const auto it = mAgents.find(agentHalfExtents); 28 if (it == mAgents.end()) 29 return; 30 if (it->second > 0) 31 --it->second; 32 } 33 addObject(const ObjectId id,const osg::ref_ptr<const osg::Object> & holder,const btHeightfieldTerrainShape & shape,const btTransform & transform)34 bool NavigatorImpl::addObject(const ObjectId id, const osg::ref_ptr<const osg::Object>& holder, 35 const btHeightfieldTerrainShape& shape, const btTransform& transform) 36 { 37 const CollisionShape collisionShape {holder, shape}; 38 return mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground); 39 } 40 addObject(const ObjectId id,const ObjectShapes & shapes,const btTransform & transform)41 bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) 42 { 43 const CollisionShape collisionShape {shapes.mShapeInstance, *shapes.mShapeInstance->getCollisionShape()}; 44 bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground); 45 if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->getAvoidCollisionShape()) 46 { 47 const ObjectId avoidId(avoidShape); 48 const CollisionShape collisionShape {shapes.mShapeInstance, *avoidShape}; 49 if (mNavMeshManager.addObject(avoidId, collisionShape, transform, AreaType_null)) 50 { 51 updateAvoidShapeId(id, avoidId); 52 result = true; 53 } 54 } 55 return result; 56 } 57 addObject(const ObjectId id,const DoorShapes & shapes,const btTransform & transform)58 bool NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) 59 { 60 if (addObject(id, static_cast<const ObjectShapes&>(shapes), transform)) 61 { 62 const osg::Vec3f start = toNavMeshCoordinates(mSettings, shapes.mConnectionStart); 63 const osg::Vec3f end = toNavMeshCoordinates(mSettings, shapes.mConnectionEnd); 64 mNavMeshManager.addOffMeshConnection(id, start, end, AreaType_door); 65 mNavMeshManager.addOffMeshConnection(id, end, start, AreaType_door); 66 return true; 67 } 68 return false; 69 } 70 updateObject(const ObjectId id,const ObjectShapes & shapes,const btTransform & transform)71 bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) 72 { 73 const CollisionShape collisionShape {shapes.mShapeInstance, *shapes.mShapeInstance->getCollisionShape()}; 74 bool result = mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground); 75 if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->getAvoidCollisionShape()) 76 { 77 const ObjectId avoidId(avoidShape); 78 const CollisionShape collisionShape {shapes.mShapeInstance, *avoidShape}; 79 if (mNavMeshManager.updateObject(avoidId, collisionShape, transform, AreaType_null)) 80 { 81 updateAvoidShapeId(id, avoidId); 82 result = true; 83 } 84 } 85 return result; 86 } 87 updateObject(const ObjectId id,const DoorShapes & shapes,const btTransform & transform)88 bool NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) 89 { 90 return updateObject(id, static_cast<const ObjectShapes&>(shapes), transform); 91 } 92 removeObject(const ObjectId id)93 bool NavigatorImpl::removeObject(const ObjectId id) 94 { 95 bool result = mNavMeshManager.removeObject(id); 96 const auto avoid = mAvoidIds.find(id); 97 if (avoid != mAvoidIds.end()) 98 result = mNavMeshManager.removeObject(avoid->second) || result; 99 const auto water = mWaterIds.find(id); 100 if (water != mWaterIds.end()) 101 result = mNavMeshManager.removeObject(water->second) || result; 102 mNavMeshManager.removeOffMeshConnections(id); 103 return result; 104 } 105 addWater(const osg::Vec2i & cellPosition,const int cellSize,const btScalar level,const btTransform & transform)106 bool NavigatorImpl::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, 107 const btTransform& transform) 108 { 109 return mNavMeshManager.addWater(cellPosition, cellSize, 110 btTransform(transform.getBasis(), btVector3(transform.getOrigin().x(), transform.getOrigin().y(), level))); 111 } 112 removeWater(const osg::Vec2i & cellPosition)113 bool NavigatorImpl::removeWater(const osg::Vec2i& cellPosition) 114 { 115 return mNavMeshManager.removeWater(cellPosition); 116 } 117 addPathgrid(const ESM::Cell & cell,const ESM::Pathgrid & pathgrid)118 void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) 119 { 120 Misc::CoordinateConverter converter(&cell); 121 for (auto edge : pathgrid.mEdges) 122 { 123 const auto src = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV0])); 124 const auto dst = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV1])); 125 mNavMeshManager.addOffMeshConnection( 126 ObjectId(&pathgrid), 127 toNavMeshCoordinates(mSettings, src), 128 toNavMeshCoordinates(mSettings, dst), 129 AreaType_pathgrid 130 ); 131 } 132 } 133 removePathgrid(const ESM::Pathgrid & pathgrid)134 void NavigatorImpl::removePathgrid(const ESM::Pathgrid& pathgrid) 135 { 136 mNavMeshManager.removeOffMeshConnections(ObjectId(&pathgrid)); 137 } 138 update(const osg::Vec3f & playerPosition)139 void NavigatorImpl::update(const osg::Vec3f& playerPosition) 140 { 141 if (!mUpdatesEnabled) 142 return; 143 removeUnusedNavMeshes(); 144 for (const auto& v : mAgents) 145 mNavMeshManager.update(playerPosition, v.first); 146 } 147 updatePlayerPosition(const osg::Vec3f & playerPosition)148 void NavigatorImpl::updatePlayerPosition(const osg::Vec3f& playerPosition) 149 { 150 const TilePosition tilePosition = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition)); 151 if (mLastPlayerPosition.has_value() && *mLastPlayerPosition == tilePosition) 152 return; 153 update(playerPosition); 154 mLastPlayerPosition = tilePosition; 155 } 156 setUpdatesEnabled(bool enabled)157 void NavigatorImpl::setUpdatesEnabled(bool enabled) 158 { 159 mUpdatesEnabled = enabled; 160 } 161 wait(Loading::Listener & listener,WaitConditionType waitConditionType)162 void NavigatorImpl::wait(Loading::Listener& listener, WaitConditionType waitConditionType) 163 { 164 mNavMeshManager.wait(listener, waitConditionType); 165 } 166 getNavMesh(const osg::Vec3f & agentHalfExtents) const167 SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const 168 { 169 return mNavMeshManager.getNavMesh(agentHalfExtents); 170 } 171 getNavMeshes() const172 std::map<osg::Vec3f, SharedNavMeshCacheItem> NavigatorImpl::getNavMeshes() const 173 { 174 return mNavMeshManager.getNavMeshes(); 175 } 176 getSettings() const177 const Settings& NavigatorImpl::getSettings() const 178 { 179 return mSettings; 180 } 181 reportStats(unsigned int frameNumber,osg::Stats & stats) const182 void NavigatorImpl::reportStats(unsigned int frameNumber, osg::Stats& stats) const 183 { 184 mNavMeshManager.reportStats(frameNumber, stats); 185 } 186 getRecastMeshTiles()187 RecastMeshTiles NavigatorImpl::getRecastMeshTiles() 188 { 189 return mNavMeshManager.getRecastMeshTiles(); 190 } 191 updateAvoidShapeId(const ObjectId id,const ObjectId avoidId)192 void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId) 193 { 194 updateId(id, avoidId, mWaterIds); 195 } 196 updateWaterShapeId(const ObjectId id,const ObjectId waterId)197 void NavigatorImpl::updateWaterShapeId(const ObjectId id, const ObjectId waterId) 198 { 199 updateId(id, waterId, mWaterIds); 200 } 201 updateId(const ObjectId id,const ObjectId updateId,std::unordered_map<ObjectId,ObjectId> & ids)202 void NavigatorImpl::updateId(const ObjectId id, const ObjectId updateId, std::unordered_map<ObjectId, ObjectId>& ids) 203 { 204 auto inserted = ids.insert(std::make_pair(id, updateId)); 205 if (!inserted.second) 206 { 207 mNavMeshManager.removeObject(inserted.first->second); 208 inserted.first->second = updateId; 209 } 210 } 211 removeUnusedNavMeshes()212 void NavigatorImpl::removeUnusedNavMeshes() 213 { 214 for (auto it = mAgents.begin(); it != mAgents.end();) 215 { 216 if (it->second == 0 && mNavMeshManager.reset(it->first)) 217 it = mAgents.erase(it); 218 else 219 ++it; 220 } 221 } 222 getMaxNavmeshAreaRealRadius() const223 float NavigatorImpl::getMaxNavmeshAreaRealRadius() const 224 { 225 const auto& settings = getSettings(); 226 return getRealTileSize(settings) * getMaxNavmeshAreaRadius(settings); 227 } 228 } 229