diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index e8a4be1e46..976f7a46e1 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -13,7 +13,7 @@ namespace struct Key { - osg::Vec3f mAgentHalfExtents; + AgentBounds mAgentBounds; TilePosition mTilePosition; RecastMesh mRecastMesh; }; @@ -137,6 +137,7 @@ namespace template Key generateKey(std::size_t triangles, Random& random) { + const CollisionShapeType agentShapeType = CollisionShapeType::Aabb; const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random); const TilePosition tilePosition = generateVec2i(10000, random); const std::size_t generation = std::uniform_int_distribution(0, 100)(random); @@ -146,7 +147,7 @@ namespace generateWater(std::back_inserter(water), 1, random); RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water), {generateHeightfield(random)}, {generateFlatHeightfield(random)}, {}); - return Key {agentHalfExtents, tilePosition, std::move(recastMesh)}; + return Key {AgentBounds {agentShapeType, agentHalfExtents}, tilePosition, std::move(recastMesh)}; } constexpr std::size_t trianglesPerTile = 239; @@ -165,7 +166,7 @@ namespace while (true) { Key key = generateKey(trianglesPerTile, random); - cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, + cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh, std::make_unique()); *out++ = std::move(key); const std::size_t newSize = cache.getStats().mNavMeshCacheSize; @@ -188,7 +189,7 @@ namespace while (state.KeepRunning()) { const auto& key = keys[n++ % keys.size()]; - const auto result = cache.get(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh); + const auto result = cache.get(key.mAgentBounds, key.mTilePosition, key.mRecastMesh); benchmark::DoNotOptimize(result); } } @@ -216,7 +217,7 @@ namespace while (state.KeepRunning()) { const auto& key = keys[n++ % keys.size()]; - const auto result = cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, + const auto result = cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh, std::make_unique()); benchmark::DoNotOptimize(result); } diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index c1f8a8e90a..ea0046b1ae 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -173,7 +174,9 @@ namespace NavMeshTool Settings::Manager settings; settings.load(config); + const DetourNavigator::CollisionShapeType agentCollisionShape = DetourNavigator::defaultCollisionShapeType; const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game"); + const DetourNavigator::AgentBounds agentBounds {agentCollisionShape, agentHalfExtents}; const std::uint64_t maxDbFileSize = static_cast(Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); const std::string dbPath = (config.getUserDataPath() / "navmesh.db").string(); @@ -201,7 +204,7 @@ namespace NavMeshTool WorldspaceData cellsData = gatherWorldspaceData(navigatorSettings, readers, vfs, bulletShapeManager, esmData, processInteriorCells, writeBinaryLog); - const Status status = generateAllNavMeshTiles(agentHalfExtents, navigatorSettings, threadsNumber, + const Status status = generateAllNavMeshTiles(agentBounds, navigatorSettings, threadsNumber, removeUnusedTiles, writeBinaryLog, cellsData, std::move(db)); switch (status) diff --git a/apps/navmeshtool/navmesh.cpp b/apps/navmeshtool/navmesh.cpp index a51d0bbc81..053809eca4 100644 --- a/apps/navmeshtool/navmesh.cpp +++ b/apps/navmeshtool/navmesh.cpp @@ -32,6 +32,7 @@ namespace NavMeshTool { namespace { + using DetourNavigator::AgentBounds; using DetourNavigator::GenerateNavMeshTile; using DetourNavigator::NavMeshDb; using DetourNavigator::NavMeshTileInfo; @@ -250,7 +251,7 @@ namespace NavMeshTool }; } - Status generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const Settings& settings, + Status generateAllNavMeshTiles(const AgentBounds& agentBounds, const Settings& settings, std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& data, NavMeshDb&& db) { @@ -291,7 +292,7 @@ namespace NavMeshTool input->mWorldspace, tilePosition, RecastMeshProvider(input->mTileCachedRecastMeshManager), - agentHalfExtents, + agentBounds, settings, navMeshTileConsumer )); diff --git a/apps/navmeshtool/navmesh.hpp b/apps/navmeshtool/navmesh.hpp index fa340b5de7..f0199ea1c4 100644 --- a/apps/navmeshtool/navmesh.hpp +++ b/apps/navmeshtool/navmesh.hpp @@ -9,6 +9,7 @@ namespace DetourNavigator { class NavMeshDb; struct Settings; + struct AgentBounds; } namespace NavMeshTool @@ -22,7 +23,7 @@ namespace NavMeshTool NotEnoughSpace, }; - Status generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const DetourNavigator::Settings& settings, + Status generateAllNavMeshTiles(const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Settings& settings, std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& cellsData, DetourNavigator::NavMeshDb&& db); } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index b20ae33d63..2c96a07851 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -79,6 +79,7 @@ namespace MWMechanics namespace DetourNavigator { struct Navigator; + struct AgentBounds; } namespace MWWorld @@ -644,14 +645,13 @@ namespace MWBase virtual DetourNavigator::Navigator* getNavigator() const = 0; virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const = 0; + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const = 0; virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0; virtual void setNavMeshNumberToRender(const std::size_t value) = 0; - /// Return physical half extents of the given actor to be used in pathfinding - virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0; + virtual DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const = 0; virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 38bd9ed4b5..5bb03bb751 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -268,11 +268,11 @@ namespace MWMechanics { const MWBase::World* world = MWBase::Environment::get().getWorld(); // Try to build path to the target. - const auto halfExtents = world->getPathfindingHalfExtents(actor); + const auto agentBounds = world->getPathfindingAgentBounds(actor); const auto navigatorFlags = getNavigatorFlags(actor); const auto areaCosts = getAreaCosts(actor); const auto pathGridGraph = getPathGridGraph(actor.getCell()); - mPathFinder.buildPath(actor, vActorPos, vTargetPos, actor.getCell(), pathGridGraph, halfExtents, + mPathFinder.buildPath(actor, vActorPos, vTargetPos, actor.getCell(), pathGridGraph, agentBounds, navigatorFlags, areaCosts, storage.mAttackRange, PathType::Full); if (!mPathFinder.isPathConstructed()) @@ -280,12 +280,12 @@ namespace MWMechanics // If there is no path, try to find a point on a line from the actor position to target projected // on navmesh to attack the target from there. const auto navigator = world->getNavigator(); - const auto hit = DetourNavigator::raycast(*navigator, halfExtents, vActorPos, vTargetPos, navigatorFlags); + const auto hit = DetourNavigator::raycast(*navigator, agentBounds, vActorPos, vTargetPos, navigatorFlags); if (hit.has_value() && (*hit - vTargetPos).length() <= rangeAttack) { // If the point is close enough, try to find a path to that point. - mPathFinder.buildPath(actor, vActorPos, *hit, actor.getCell(), pathGridGraph, halfExtents, + mPathFinder.buildPath(actor, vActorPos, *hit, actor.getCell(), pathGridGraph, agentBounds, navigatorFlags, areaCosts, storage.mAttackRange, PathType::Full); if (mPathFinder.isPathConstructed()) { diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 24bfe41165..906894dd9c 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -113,6 +113,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& const osg::Vec3f position = actor.getRefData().getPosition().asVec3(); //position of the actor MWBase::World* world = MWBase::Environment::get().getWorld(); + const DetourNavigator::AgentBounds agentBounds = world->getPathfindingAgentBounds(actor); /// Stops the actor when it gets too close to a unloaded cell //... At current time, this test is unnecessary. AI shuts down when actor is more than "actors processing range" setting value @@ -122,7 +123,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& { actor.getClass().getMovementSettings(actor).mPosition[0] = 0; actor.getClass().getMovementSettings(actor).mPosition[1] = 0; - world->updateActorPath(actor, mPathFinder.getPath(), world->getPathfindingHalfExtents(actor), position, dest); + world->updateActorPath(actor, mPathFinder.getPath(), agentBounds, position, dest); return false; } @@ -148,9 +149,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& { if (wasShortcutting || doesPathNeedRecalc(dest, actor)) // if need to rebuild path { - const auto pathfindingHalfExtents = world->getPathfindingHalfExtents(actor); mPathFinder.buildLimitedPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), - pathfindingHalfExtents, getNavigatorFlags(actor), getAreaCosts(actor), endTolerance, pathType); + agentBounds, getNavigatorFlags(actor), getAreaCosts(actor), endTolerance, pathType); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity @@ -178,13 +178,13 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& } } - const osg::Vec3f halfExtents = world->getHalfExtents(actor); - const float pointTolerance = getPointTolerance(actor.getClass().getMaxSpeed(actor), duration, halfExtents); + const float pointTolerance = getPointTolerance(actor.getClass().getMaxSpeed(actor), duration, + world->getHalfExtents(actor)); static const bool smoothMovement = Settings::Manager::getBool("smooth movement", "Game"); mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE, /*shortenIfAlmostStraight=*/smoothMovement, actorCanMoveByZ, - halfExtents, getNavigatorFlags(actor)); + agentBounds, getNavigatorFlags(actor)); if (isDestReached || mPathFinder.checkPathCompleted()) // if path is finished { @@ -197,7 +197,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& else if (mPathFinder.getPath().empty()) return false; - world->updateActorPath(actor, mPathFinder.getPath(), world->getPathfindingHalfExtents(actor), position, dest); + world->updateActorPath(actor, mPathFinder.getPath(), agentBounds, position, dest); if (mRotateOnTheRunChecks == 0 || isReachableRotatingOnTheRun(actor, *mPathFinder.getPath().begin())) // to prevent circling around a path point diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 378099e7d1..14b416ac61 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d7f2026b82..0bd424785b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -71,7 +71,7 @@ namespace MWMechanics const auto position = actor.getRefData().getPosition().asVec3(); const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor); - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor).mHalfExtents; osg::Vec3f direction = destination - position; direction.normalize(); const auto visibleDestination = ( @@ -210,10 +210,10 @@ namespace MWMechanics } else { - const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); + const auto agentBounds = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor); constexpr float endTolerance = 0; mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor), getAreaCosts(actor), + getPathGridGraph(actor.getCell()), agentBounds, getNavigatorFlags(actor), getAreaCosts(actor), endTolerance, PathType::Full); } @@ -345,7 +345,7 @@ namespace MWMechanics const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor); const auto world = MWBase::Environment::get().getWorld(); - const auto halfExtents = world->getPathfindingHalfExtents(actor); + const auto agentBounds = world->getPathfindingAgentBounds(actor); const auto navigator = world->getNavigator(); const auto navigatorFlags = getNavigatorFlags(actor); const auto areaCosts = getAreaCosts(actor); @@ -358,7 +358,7 @@ namespace MWMechanics if (!isWaterCreature && !isFlyingCreature) { // findRandomPointAroundCircle uses wanderDistance as limit for random and not as exact distance - if (const auto destination = DetourNavigator::findRandomPointAroundCircle(*navigator, halfExtents, + if (const auto destination = DetourNavigator::findRandomPointAroundCircle(*navigator, agentBounds, mInitialActorPosition, wanderDistance, navigatorFlags, []() { auto& prng = MWBase::Environment::get().getWorld()->getPrng(); return Misc::Rng::rollProbability(prng); @@ -385,7 +385,7 @@ namespace MWMechanics if (isWaterCreature || isFlyingCreature) mPathFinder.buildStraightPath(mDestination); else - mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, halfExtents, navigatorFlags, + mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, agentBounds, navigatorFlags, areaCosts, endTolerance, PathType::Full); if (mPathFinder.isPathConstructed()) @@ -532,8 +532,8 @@ namespace MWMechanics { if (mUsePathgrid) { - const auto halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor); - mPathFinder.buildPathByNavMeshToNextPoint(actor, halfExtents, getNavigatorFlags(actor), + const auto agentBounds = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor); + mPathFinder.buildPathByNavMeshToNextPoint(actor, agentBounds, getNavigatorFlags(actor), getAreaCosts(actor)); } diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 3d64eae862..0f73890eb7 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" @@ -80,7 +81,7 @@ namespace MWMechanics std::vector* occupyingActors) { const auto world = MWBase::Environment::get().getWorld(); - const osg::Vec3f halfExtents = world->getPathfindingHalfExtents(actor); + const osg::Vec3f halfExtents = world->getPathfindingAgentBounds(actor).mHalfExtents; const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z())); if (ignorePlayer) { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1cc4526193..4f4c35bb40 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -109,12 +109,12 @@ namespace struct IsValidShortcut { const DetourNavigator::Navigator* mNavigator; - const osg::Vec3f mHalfExtents; + const DetourNavigator::AgentBounds mAgentBounds; const DetourNavigator::Flags mFlags; bool operator()(const osg::Vec3f& start, const osg::Vec3f& end) const { - const auto position = DetourNavigator::raycast(*mNavigator, mHalfExtents, start, end, mFlags); + const auto position = DetourNavigator::raycast(*mNavigator, mAgentBounds, start, end, mFlags); return position.has_value() && std::abs((position.value() - start).length2() - (end - start).length2()) <= 1; } }; @@ -307,8 +307,8 @@ namespace MWMechanics } void PathFinder::update(const osg::Vec3f& position, float pointTolerance, float destinationTolerance, - bool shortenIfAlmostStraight, bool canMoveByZ, const osg::Vec3f& halfExtents, - const DetourNavigator::Flags flags) + bool shortenIfAlmostStraight, bool canMoveByZ, const DetourNavigator::AgentBounds& agentBounds, + const DetourNavigator::Flags flags) { if (mPath.empty()) return; @@ -318,7 +318,7 @@ namespace MWMechanics const IsValidShortcut isValidShortcut { MWBase::Environment::get().getWorld()->getNavigator(), - halfExtents, flags + agentBounds, flags }; if (shortenIfAlmostStraight) @@ -375,13 +375,13 @@ namespace MWMechanics } void PathFinder::buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, - const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags, + const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType) { mPath.clear(); // If it's not possible to build path over navmesh due to disabled navmesh generation fallback to straight path - DetourNavigator::Status status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, + DetourNavigator::Status status = buildPathByNavigatorImpl(actor, startPoint, endPoint, agentBounds, flags, areaCosts, endTolerance, pathType, std::back_inserter(mPath)); if (status != DetourNavigator::Status::Success) @@ -394,7 +394,7 @@ namespace MWMechanics } void PathFinder::buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, - const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType) { @@ -405,7 +405,7 @@ namespace MWMechanics if (!actor.getClass().isPureWaterCreature(actor) && !actor.getClass().isPureFlyingCreature(actor)) { - status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, areaCosts, + status = buildPathByNavigatorImpl(actor, startPoint, endPoint, agentBounds, flags, areaCosts, endTolerance, pathType, std::back_inserter(mPath)); if (status != DetourNavigator::Status::Success) mPath.clear(); @@ -413,7 +413,7 @@ namespace MWMechanics if (status != DetourNavigator::Status::NavMeshNotFound && mPath.empty() && (flags & DetourNavigator::Flag_usePathgrid) == 0) { - status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, + status = buildPathByNavigatorImpl(actor, startPoint, endPoint, agentBounds, flags | DetourNavigator::Flag_usePathgrid, areaCosts, endTolerance, pathType, std::back_inserter(mPath)); if (status != DetourNavigator::Status::Success) mPath.clear(); @@ -429,14 +429,14 @@ namespace MWMechanics } DetourNavigator::Status PathFinder::buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, - const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags, + const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType, std::back_insert_iterator> out) { const auto world = MWBase::Environment::get().getWorld(); const auto stepSize = getPathStepSize(actor); const auto navigator = world->getNavigator(); - const auto status = DetourNavigator::findPath(*navigator, halfExtents, stepSize, + const auto status = DetourNavigator::findPath(*navigator, agentBounds, stepSize, startPoint, endPoint, flags, areaCosts, endTolerance, out); if (pathType == PathType::Partial && status == DetourNavigator::Status::PartialPath) @@ -453,8 +453,9 @@ namespace MWMechanics return status; } - void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents, - const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts) + void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, + const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, + const DetourNavigator::AreaCosts& areaCosts) { if (mPath.empty()) return; @@ -469,7 +470,7 @@ namespace MWMechanics std::deque prePath; auto prePathInserter = std::back_inserter(prePath); const float endTolerance = 0; - const auto status = DetourNavigator::findPath(*navigator, halfExtents, stepSize, + const auto status = DetourNavigator::findPath(*navigator, agentBounds, stepSize, startPoint, mPath.front(), flags, areaCosts, endTolerance, prePathInserter); if (status == DetourNavigator::Status::NavMeshNotFound) @@ -494,9 +495,9 @@ namespace MWMechanics } void PathFinder::buildLimitedPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, - const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, - const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, - PathType pathType) + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, + const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, + const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType) { const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); const auto maxDistance = std::min( @@ -506,9 +507,9 @@ namespace MWMechanics const auto startToEnd = endPoint - startPoint; const auto distance = startToEnd.length(); if (distance <= maxDistance) - return buildPath(actor, startPoint, endPoint, cell, pathgridGraph, halfExtents, flags, areaCosts, + return buildPath(actor, startPoint, endPoint, cell, pathgridGraph, agentBounds, flags, areaCosts, endTolerance, pathType); const auto end = startPoint + startToEnd * maxDistance / distance; - buildPath(actor, startPoint, end, cell, pathgridGraph, halfExtents, flags, areaCosts, endTolerance, pathType); + buildPath(actor, startPoint, end, cell, pathgridGraph, agentBounds, flags, areaCosts, endTolerance, pathType); } } diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 17b355682a..c07b085e5a 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -18,6 +18,11 @@ namespace MWWorld class Ptr; } +namespace DetourNavigator +{ + struct AgentBounds; +} + namespace MWMechanics { class PathgridGraph; @@ -98,25 +103,26 @@ namespace MWMechanics const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); void buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, - const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags, - const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType); - - void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, - const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, + const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType); - void buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents, + void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, + const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, + const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType); + + void buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts); void buildLimitedPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, - const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType); /// Remove front point if exist and within tolerance void update(const osg::Vec3f& position, float pointTolerance, float destinationTolerance, - bool shortenIfAlmostStraight, bool canMoveByZ, const osg::Vec3f& halfExtents, + bool shortenIfAlmostStraight, bool canMoveByZ, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags); bool checkPathCompleted() const @@ -219,7 +225,7 @@ namespace MWMechanics const PathgridGraph& pathgridGraph, std::back_insert_iterator> out); [[nodiscard]] DetourNavigator::Status buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, - const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, + const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType, std::back_insert_iterator> out); }; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 455237dfc8..64e38559f6 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -57,7 +57,18 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic } mShape = std::make_unique(Misc::Convert::toBullet(mOriginalHalfExtents)); - mRotationallyInvariant = (mMeshTranslation.x() == 0.0 && mMeshTranslation.y() == 0.0) && std::fabs(mOriginalHalfExtents.x() - mOriginalHalfExtents.y()) < 2.2; + + if ((mMeshTranslation.x() == 0.0 && mMeshTranslation.y() == 0.0) + && std::fabs(mOriginalHalfExtents.x() - mOriginalHalfExtents.y()) < 2.2) + { + mRotationallyInvariant = true; + mCollisionShapeType = DetourNavigator::CollisionShapeType::Aabb; + } + else + { + mRotationallyInvariant = false; + mCollisionShapeType = DetourNavigator::CollisionShapeType::RotatingBox; + } mConvexShape = static_cast(mShape.get()); mConvexShape->setMargin(0.001); // make sure bullet isn't using the huge default convex shape margin of 0.04 diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 2b67f265c6..322ad74d7c 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -6,6 +6,8 @@ #include "ptrholder.hpp" +#include + #include #include #include @@ -156,6 +158,8 @@ namespace MWPhysics void setActive(bool value) { mActive = value; } + DetourNavigator::CollisionShapeType getCollisionShapeType() const { return mCollisionShapeType; } + private: MWWorld::Ptr mStandingOnPtr; /// Removes then re-adds the collision object to the dynamics world @@ -171,6 +175,8 @@ namespace MWPhysics bool mRotationallyInvariant; + DetourNavigator::CollisionShapeType mCollisionShapeType; + std::unique_ptr mShape; btConvexShape* mConvexShape; diff --git a/apps/openmw/mwrender/actorspaths.cpp b/apps/openmw/mwrender/actorspaths.cpp index ae2d6bccb8..45b35df4b9 100644 --- a/apps/openmw/mwrender/actorspaths.cpp +++ b/apps/openmw/mwrender/actorspaths.cpp @@ -38,7 +38,7 @@ namespace MWRender } void ActorsPaths::update(const MWWorld::ConstPtr& actor, const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end, + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end, const DetourNavigator::Settings& settings) { if (!mEnabled) @@ -48,7 +48,7 @@ namespace MWRender if (group != mGroups.end()) mRootNode->removeChild(group->second.mNode); - auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings.mRecast); + auto newGroup = SceneUtil::createAgentPathGroup(path, agentBounds, start, end, settings.mRecast); if (newGroup) { MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug"); diff --git a/apps/openmw/mwrender/actorspaths.hpp b/apps/openmw/mwrender/actorspaths.hpp index d6cec9357b..304d5c09b3 100644 --- a/apps/openmw/mwrender/actorspaths.hpp +++ b/apps/openmw/mwrender/actorspaths.hpp @@ -17,6 +17,7 @@ namespace osg namespace DetourNavigator { struct Settings; + struct AgentBounds; } namespace MWRender @@ -30,7 +31,7 @@ namespace MWRender bool toggle(); void update(const MWWorld::ConstPtr& actor, const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end, + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end, const DetourNavigator::Settings& settings); void remove(const MWWorld::ConstPtr& actor); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e639880b37..214e6cf731 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1518,9 +1518,9 @@ namespace MWRender } void RenderingManager::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const { - mActorsPaths->update(actor, path, halfExtents, start, end, mNavigator.getSettings()); + mActorsPaths->update(actor, path, agentBounds, start, end, mNavigator.getSettings()); } void RenderingManager::removeActorPath(const MWWorld::ConstPtr& actor) const diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 12f5bb073d..0424d20b23 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -66,6 +66,7 @@ namespace DetourNavigator { struct Navigator; struct Settings; + struct AgentBounds; } namespace MWWorld @@ -236,7 +237,7 @@ namespace MWRender bool toggleBorders(); void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const; + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const; void removeActorPath(const MWWorld::ConstPtr& actor) const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 24b4786759..57eec9d2dd 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -187,7 +187,7 @@ namespace } else if (physics.getActor(ptr)) { - navigator.addAgent(world.getPathfindingHalfExtents(ptr)); + navigator.addAgent(world.getPathfindingAgentBounds(ptr)); } } @@ -332,7 +332,7 @@ namespace MWWorld } else if (mPhysics->getActor(ptr)) { - mNavigator.removeAgent(mWorld.getPathfindingHalfExtents(ptr)); + mNavigator.removeAgent(mWorld.getPathfindingAgentBounds(ptr)); mRendering.removeActorPath(ptr); mPhysics->remove(ptr); } @@ -940,7 +940,7 @@ namespace MWWorld } else if (mPhysics->getActor(ptr)) { - mNavigator.removeAgent(mWorld.getPathfindingHalfExtents(ptr)); + mNavigator.removeAgent(mWorld.getPathfindingAgentBounds(ptr)); } mPhysics->remove(ptr); mRendering.removeObject (ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bec6a9064a..d2470fd678 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1275,7 +1275,7 @@ namespace MWWorld if (!force && scale == ptr.getCellRef().getScale()) return; if (mPhysics->getActor(ptr)) - mNavigator->removeAgent(getPathfindingHalfExtents(ptr)); + mNavigator->removeAgent(getPathfindingAgentBounds(ptr)); ptr.getCellRef().setScale(scale); mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr); @@ -1285,7 +1285,7 @@ namespace MWWorld mWorldScene->updateObjectScale(ptr); if (mPhysics->getActor(ptr)) - mNavigator->addAgent(getPathfindingHalfExtents(ptr)); + mNavigator->addAgent(getPathfindingAgentBounds(ptr)); else if (const auto object = mPhysics->getObject(ptr)) updateNavigatorObject(*object); } @@ -2416,7 +2416,7 @@ namespace MWWorld { // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr(), true); - mNavigator->removeAgent(getPathfindingHalfExtents(getPlayerConstPtr())); + mNavigator->removeAgent(getPathfindingAgentBounds(getPlayerConstPtr())); mPhysics->remove(getPlayerPtr()); mRendering->removePlayer(getPlayerPtr()); MWBase::Environment::get().getLuaManager()->objectRemovedFromScene(getPlayerPtr()); @@ -2453,7 +2453,7 @@ namespace MWWorld applyLoopingParticles(player); - mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr())); + mNavigator->addAgent(getPathfindingAgentBounds(getPlayerConstPtr())); } World::RestPermitted World::canRest () const @@ -3898,9 +3898,9 @@ namespace MWWorld } void World::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const { - mRendering->updateActorPath(actor, path, halfExtents, start, end); + mRendering->updateActorPath(actor, path, agentBounds, start, end); } void World::removeActorPath(const MWWorld::ConstPtr& actor) const @@ -3913,12 +3913,13 @@ namespace MWWorld mRendering->setNavMeshNumber(value); } - osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const + DetourNavigator::AgentBounds World::getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const { - if (actor.isInCell() && actor.getCell()->isExterior()) - return mDefaultHalfExtents; // Using default half extents for better performance + const MWPhysics::Actor* physicsActor = mPhysics->getActor(actor); + if (physicsActor == nullptr || (actor.isInCell() && actor.getCell()->isExterior())) + return DetourNavigator::AgentBounds {DetourNavigator::defaultCollisionShapeType, mDefaultHalfExtents}; else - return getHalfExtents(actor); + return DetourNavigator::AgentBounds {physicsActor->getCollisionShapeType(), physicsActor->getHalfExtents()}; } bool World::hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 50aff408d5..c4024cec29 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -727,14 +727,13 @@ namespace MWWorld DetourNavigator::Navigator* getNavigator() const override; void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const override; + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const override; void removeActorPath(const MWWorld::ConstPtr& actor) const override; void setNavMeshNumberToRender(const std::size_t value) override; - /// Return physical half extents of the given actor to be used in pathfinding - osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override; + DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const override; bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override; diff --git a/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp b/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp index db8cfb83dc..71a833cc26 100644 --- a/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp +++ b/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp @@ -50,7 +50,7 @@ namespace Settings mSettings = makeSettings(); TileCachedRecastMeshManager mRecastMeshManager {mSettings.mRecast}; OffMeshConnectionsManager mOffMeshConnectionsManager {mSettings.mRecast}; - const osg::Vec3f mAgentHalfExtents {29, 29, 66}; + const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {29, 29, 66}}; const TilePosition mPlayerTile {0, 0}; const std::string mWorldspace = "sys::default"; const btBoxShape mBox {btVector3(100, 100, 20)}; @@ -76,7 +76,7 @@ namespace AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::add}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); EXPECT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0); } @@ -88,14 +88,14 @@ namespace AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::add}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); { const auto stats = updater.getStats(); ASSERT_EQ(stats.mCache.mGetCount, 1); ASSERT_EQ(stats.mCache.mHitCount, 0); } - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); { const auto stats = updater.getStats(); @@ -111,14 +111,14 @@ namespace AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::update}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); { const auto stats = updater.getStats(); ASSERT_EQ(stats.mCache.mGetCount, 1); ASSERT_EQ(stats.mCache.mHitCount, 0); } - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); { const auto stats = updater.getStats(); @@ -138,7 +138,7 @@ namespace const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const TilePosition tilePosition {0, 0}; const std::map changedTiles {{tilePosition, ChangeType::add}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); updater.stop(); const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition); @@ -146,10 +146,11 @@ namespace ShapeId nextShapeId {1}; const std::vector objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(), [&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v, nextShapeId); }); - const auto tile = dbPtr->findTile(mWorldspace, tilePosition, serialize(mSettings.mRecast, *recastMesh, objects)); + const auto tile = dbPtr->findTile(mWorldspace, tilePosition, + serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects)); ASSERT_TRUE(tile.has_value()); EXPECT_EQ(tile->mTileId, 1); - EXPECT_EQ(tile->mVersion, mSettings.mNavMeshVersion); + EXPECT_EQ(tile->mVersion, navMeshVersion); } TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write_tiles) @@ -164,7 +165,7 @@ namespace const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const TilePosition tilePosition {0, 0}; const std::map changedTiles {{tilePosition, ChangeType::add}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); updater.stop(); const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition); @@ -172,7 +173,8 @@ namespace ShapeId nextShapeId {1}; const std::vector objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(), [&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v, nextShapeId); }); - const auto tile = dbPtr->findTile(mWorldspace, tilePosition, serialize(mSettings.mRecast, *recastMesh, objects)); + const auto tile = dbPtr->findTile(mWorldspace, tilePosition, + serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects)); ASSERT_FALSE(tile.has_value()); } @@ -188,7 +190,7 @@ namespace const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const TilePosition tilePosition {0, 0}; const std::map changedTiles {{tilePosition, ChangeType::add}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); updater.stop(); const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition); @@ -207,7 +209,7 @@ namespace std::make_unique(":memory:", std::numeric_limits::max())); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::add}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); { const auto stats = updater.getStats(); @@ -217,7 +219,7 @@ namespace ASSERT_EQ(stats.mDb->mGetTileCount, 1); ASSERT_EQ(stats.mDbGetTileHits, 0); } - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); { const auto stats = updater.getStats(); @@ -236,12 +238,12 @@ namespace AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTilesAdd {{TilePosition {0, 0}, ChangeType::add}}; - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTilesAdd); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTilesAdd); updater.wait(mListener, WaitConditionType::allJobsDone); ASSERT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0); const std::map changedTilesRemove {{TilePosition {0, 0}, ChangeType::remove}}; const TilePosition playerTile(100, 100); - updater.post(mAgentHalfExtents, navMeshCacheItem, playerTile, mWorldspace, changedTilesRemove); + updater.post(mAgentBounds, navMeshCacheItem, playerTile, mWorldspace, changedTilesRemove); updater.wait(mListener, WaitConditionType::allJobsDone); EXPECT_EQ(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0); } @@ -261,7 +263,7 @@ namespace for (int x = -5; x <= 5; ++x) for (int y = -5; y <= 5; ++y) changedTiles.emplace(TilePosition {x, y}, ChangeType::add); - updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); updater.wait(mListener, WaitConditionType::allJobsDone); updater.stop(); const std::set present { @@ -276,7 +278,6 @@ namespace TilePosition(0, 2), TilePosition(1, -1), TilePosition(1, 0), - TilePosition(1, 1), }; for (int x = -5; x <= 5; ++x) for (int y = -5; y <= 5; ++y) @@ -288,7 +289,8 @@ namespace [&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v); }); if (!objects.has_value()) continue; - EXPECT_EQ(dbPtr->findTile(mWorldspace, tilePosition, serialize(mSettings.mRecast, *recastMesh, *objects)).has_value(), + EXPECT_EQ(dbPtr->findTile(mWorldspace, tilePosition, + serialize(mSettings.mRecast, mAgentBounds, *recastMesh, *objects)).has_value(), present.find(tilePosition) != present.end()) << tilePosition.x() << " " << tilePosition.y() << " present=" << (present.find(tilePosition) != present.end()); } diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index d8df4e00ae..f49f3cdc74 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -42,7 +42,7 @@ namespace std::unique_ptr mNavigator; const osg::Vec3f mPlayerPosition; const std::string mWorldspace; - const osg::Vec3f mAgentHalfExtents; + const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {29, 29, 66}}; osg::Vec3f mStart; osg::Vec3f mEnd; std::deque mPath; @@ -59,7 +59,6 @@ namespace DetourNavigatorNavigatorTest() : mPlayerPosition(256, 256, 0) , mWorldspace("sys::default") - , mAgentHalfExtents(29, 29, 66) , mStart(52, 460, 1) , mEnd(460, 52, 1) , mOut(mPath) @@ -122,24 +121,24 @@ namespace TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty) { - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::NavMeshNotFound); EXPECT_EQ(mPath, std::deque()); } TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception) { - mNavigator->addAgent(mAgentHalfExtents); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + mNavigator->addAgent(mAgentBounds); + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::StartPolygonNotFound); } TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent) { - mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addAgent(mAgentHalfExtents); - mNavigator->removeAgent(mAgentHalfExtents); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + mNavigator->addAgent(mAgentBounds); + mNavigator->addAgent(mAgentBounds); + mNavigator->removeAgent(mAgentBounds); + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::StartPolygonNotFound); } @@ -155,12 +154,12 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -204,12 +203,12 @@ namespace CollisionShapeInstance compound(std::make_unique()); compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -243,7 +242,7 @@ namespace mPath.clear(); mOut = std::back_inserter(mPath); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -288,13 +287,13 @@ namespace CollisionShapeInstance compound(std::make_unique()); compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -331,7 +330,7 @@ namespace mPath.clear(); mOut = std::back_inserter(mPath); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -382,13 +381,13 @@ namespace CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2)); heightfield2.shape().setLocalScaling(btVector3(128, 128, 1)); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform), mTransform); mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform), mTransform); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -439,7 +438,7 @@ namespace const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2); const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, surface1)); EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, surface2)); } @@ -472,12 +471,12 @@ namespace osg::ref_ptr instance(new Resource::BulletShapeInstance(bulletShape)); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addObject(ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -519,7 +518,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addWater(mCellPosition, cellSize, 300); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); @@ -530,7 +529,7 @@ namespace mEnd.x() = 256; mEnd.z() = 300; - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_swim, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -567,7 +566,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addWater(mCellPosition, cellSize, -25); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); @@ -576,7 +575,7 @@ namespace mStart.x() = 256; mEnd.x() = 256; - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -613,7 +612,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->addWater(mCellPosition, std::numeric_limits::max(), -25); mNavigator->update(mPlayerPosition); @@ -622,7 +621,7 @@ namespace mStart.x() = 256; mEnd.x() = 256; - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -659,7 +658,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addWater(mCellPosition, cellSize, -25); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); @@ -668,7 +667,7 @@ namespace mStart.x() = 256; mEnd.x() = 256; - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -703,7 +702,7 @@ namespace CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData)); heightfield.shape().setLocalScaling(btVector3(128, 128, 1)); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -716,7 +715,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -757,7 +756,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -770,7 +769,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -812,14 +811,14 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); Misc::Rng::init(42); - const auto result = findRandomPointAroundCircle(*mNavigator, mAgentHalfExtents, mStart, 100.0, Flag_walk, + const auto result = findRandomPointAroundCircle(*mNavigator, mAgentBounds, mStart, 100.0, Flag_walk, []() { return Misc::Rng::rollClosedProbability(); }); ASSERT_THAT(result, Optional(Vec3fEq(70.35845947265625, 335.592041015625, -2.6667339801788330078125))) @@ -849,7 +848,7 @@ namespace std::vector> boxes; std::generate_n(std::back_inserter(boxes), 100, [] { return std::make_unique(btVector3(20, 20, 100)); }); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); @@ -870,7 +869,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -905,7 +904,7 @@ namespace std::vector> shapes; std::generate_n(std::back_inserter(shapes), 100, [] { return std::make_unique(btVector3(64, 64, 64)); }); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); for (std::size_t i = 0; i < shapes.size(); ++i) { @@ -950,14 +949,14 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); const osg::Vec3f start(57, 460, 1); const osg::Vec3f end(460, 57, 1); - const auto result = raycast(*mNavigator, mAgentHalfExtents, start, end, Flag_walk); + const auto result = raycast(*mNavigator, mAgentBounds, start, end, Flag_walk); ASSERT_THAT(result, Optional(Vec3fEq(end.x(), end.y(), 1.95257937908172607421875))) << (result ? *result : osg::Vec3f()); @@ -979,7 +978,7 @@ namespace const btVector3 oscillatingBoxShapePosition(288, 288, 400); CollisionShapeInstance borderBox(std::make_unique(btVector3(50, 50, 50))); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform), btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition)); @@ -1013,12 +1012,12 @@ namespace const HeightfieldPlane plane {100}; const int cellSize = mHeightfieldTileSize * 4; - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, plane); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -1063,13 +1062,13 @@ namespace compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)), new btBoxShape(btVector3(200, 200, 1000))); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::PartialPath); EXPECT_THAT(mPath, ElementsAre( @@ -1102,7 +1101,7 @@ namespace compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)), new btBoxShape(btVector3(100, 100, 1000))); - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); mNavigator->addHeightfield(mCellPosition, cellSize, surface); mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); mNavigator->update(mPlayerPosition); @@ -1110,7 +1109,7 @@ namespace const float endTolerance = 1000.0f; - EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, endTolerance, mOut), + EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, endTolerance, mOut), Status::Success); EXPECT_THAT(mPath, ElementsAre( @@ -1142,7 +1141,7 @@ namespace const int cellSize2 = 200; const float level2 = 2; - mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addAgent(mAgentBounds); EXPECT_TRUE(mNavigator->addWater(mCellPosition, cellSize1, level1)); EXPECT_FALSE(mNavigator->addWater(mCellPosition, cellSize2, level2)); } diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index cbd68e0fe1..0180373e10 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -95,7 +95,7 @@ namespace struct DetourNavigatorNavMeshTilesCacheTest : Test { - const osg::Vec3f mAgentHalfExtents {1, 2, 3}; + const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {1, 2, 3}}; const TilePosition mTilePosition {0, 0}; const std::size_t mGeneration = 0; const std::size_t mRevision = 0; @@ -117,7 +117,7 @@ namespace const std::size_t maxSize = 0; NavMeshTilesCache cache(maxSize); - EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh)); + EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, mRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_for_not_enought_cache_size_should_return_empty_value) @@ -125,7 +125,7 @@ namespace const std::size_t maxSize = 0; NavMeshTilesCache cache(maxSize); - EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData))); + EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData))); EXPECT_NE(mPreparedNavMeshData, nullptr); } @@ -136,7 +136,7 @@ namespace const auto copy = clone(*mPreparedNavMeshData); ASSERT_EQ(*mPreparedNavMeshData, *copy); - const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); ASSERT_TRUE(result); EXPECT_EQ(result.get(), *copy); } @@ -148,9 +148,9 @@ namespace auto copy = clone(*mPreparedNavMeshData); const auto sameCopy = clone(*mPreparedNavMeshData); - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); EXPECT_EQ(mPreparedNavMeshData, nullptr); - const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(copy)); + const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(copy)); ASSERT_TRUE(result); EXPECT_EQ(result.get(), *sameCopy); } @@ -161,8 +161,8 @@ namespace NavMeshTilesCache cache(maxSize); const auto copy = clone(*mPreparedNavMeshData); - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - const auto result = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh); + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + const auto result = cache.get(mAgentBounds, mTilePosition, mRecastMesh); ASSERT_TRUE(result); EXPECT_EQ(result.get(), *copy); } @@ -171,10 +171,10 @@ namespace { const std::size_t maxSize = 1; NavMeshTilesCache cache(maxSize); - const osg::Vec3f unexsistentAgentHalfExtents {1, 1, 1}; + const AgentBounds absentAgentBounds {CollisionShapeType::Aabb, {1, 1, 1}}; - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - EXPECT_FALSE(cache.get(unexsistentAgentHalfExtents, mTilePosition, mRecastMesh)); + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + EXPECT_FALSE(cache.get(absentAgentBounds, mTilePosition, mRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_tile_position_should_return_empty_value) @@ -183,8 +183,8 @@ namespace NavMeshTilesCache cache(maxSize); const TilePosition unexistentTilePosition {1, 1}; - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - EXPECT_FALSE(cache.get(mAgentHalfExtents, unexistentTilePosition, mRecastMesh)); + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + EXPECT_FALSE(cache.get(mAgentBounds, unexistentTilePosition, mRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_recast_mesh_should_return_empty_value) @@ -194,8 +194,8 @@ namespace const std::vector water(1, CellWater {osg::Vec2i(), Water {1, 0.0f}}); const RecastMesh unexistentRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources); - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh)); + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, unexistentRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_value) @@ -208,12 +208,12 @@ namespace auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); const auto copy = clone(*anotherPreparedNavMeshData); - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - const auto result = cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + const auto result = cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherPreparedNavMeshData)); ASSERT_TRUE(result); EXPECT_EQ(result.get(), *copy); - EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh)); + EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, mRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_used_value) @@ -225,9 +225,9 @@ namespace const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources); auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); - const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, + const auto value = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, + EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherPreparedNavMeshData))); } @@ -247,17 +247,17 @@ namespace mHeightfields, mFlatHeightfields, mSources); auto mostRecentlySetData = makePeparedNavMeshData(3); - ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh, + ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, leastRecentlySetRecastMesh, std::move(leastRecentlySetData))); - ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh, + ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, mostRecentlySetRecastMesh, std::move(mostRecentlySetData))); - const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, + const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); EXPECT_EQ(result.get(), *copy); - EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh)); - EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh)); + EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, leastRecentlySetRecastMesh)); + EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mostRecentlySetRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_used_value) @@ -277,28 +277,28 @@ namespace auto mostRecentlyUsedData = makePeparedNavMeshData(3); const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData); - cache.set(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh, std::move(leastRecentlyUsedData)); - cache.set(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh, std::move(mostRecentlyUsedData)); + cache.set(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh, std::move(leastRecentlyUsedData)); + cache.set(mAgentBounds, mTilePosition, mostRecentlyUsedRecastMesh, std::move(mostRecentlyUsedData)); { - const auto value = cache.get(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh); + const auto value = cache.get(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh); ASSERT_TRUE(value); ASSERT_EQ(value.get(), *leastRecentlyUsedCopy); } { - const auto value = cache.get(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh); + const auto value = cache.get(mAgentBounds, mTilePosition, mostRecentlyUsedRecastMesh); ASSERT_TRUE(value); ASSERT_EQ(value.get(), *mostRecentlyUsedCopy); } const auto copy = clone(*mPreparedNavMeshData); - const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, + const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); EXPECT_EQ(result.get(), *copy); - EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh)); - EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh)); + EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh)); + EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mostRecentlyUsedRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_cache_max_size) @@ -311,9 +311,9 @@ namespace mHeightfields, mFlatHeightfields, mSources); auto tooLargeData = makePeparedNavMeshData(10); - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh, std::move(tooLargeData))); - EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh)); + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, tooLargeRecastMesh, std::move(tooLargeData))); + EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_size_of_unused_items) @@ -331,15 +331,15 @@ namespace mHeightfields, mFlatHeightfields, mSources); auto tooLargeData = makePeparedNavMeshData(10); - const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, + const auto value = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); ASSERT_TRUE(value); - ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, + ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherData))); - EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh, + EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, tooLargeRecastMesh, std::move(tooLargeData))); - EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh)); - EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, anotherRecastMesh)); + EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh)); + EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, anotherRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_used_after_set_then_used_by_get_item_should_left_this_item_available) @@ -351,14 +351,14 @@ namespace const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources); auto anotherData = makePeparedNavMeshData(3); - const auto firstCopy = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + const auto firstCopy = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); ASSERT_TRUE(firstCopy); { - const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh); + const auto secondCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh); ASSERT_TRUE(secondCopy); } - EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, std::move(anotherData))); - EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh)); + EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherData))); + EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh)); } TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_twice_used_item_should_left_this_item_available) @@ -370,14 +370,14 @@ namespace const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources); auto anotherData = makePeparedNavMeshData(3); - cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); - const auto firstCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh); + cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); + const auto firstCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh); ASSERT_TRUE(firstCopy); { - const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh); + const auto secondCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh); ASSERT_TRUE(secondCopy); } - EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, std::move(anotherData))); - EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh)); + EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherData))); + EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh)); } } diff --git a/components/detournavigator/agentbounds.hpp b/components/detournavigator/agentbounds.hpp new file mode 100644 index 0000000000..b45a2fa6cc --- /dev/null +++ b/components/detournavigator/agentbounds.hpp @@ -0,0 +1,34 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_AGENTBOUNDS_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_AGENTBOUNDS_H + +#include "collisionshapetype.hpp" + +#include + +#include + +namespace DetourNavigator +{ + struct AgentBounds + { + CollisionShapeType mShapeType; + osg::Vec3f mHalfExtents; + }; + + inline auto tie(const AgentBounds& value) + { + return std::tie(value.mShapeType, value.mHalfExtents); + } + + inline bool operator==(const AgentBounds& lhs, const AgentBounds& rhs) + { + return tie(lhs) == tie(rhs); + } + + inline bool operator<(const AgentBounds& lhs, const AgentBounds& rhs) + { + return tie(lhs) < tie(rhs); + } +} + +#endif diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 22086c67ea..b9424e406a 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -32,12 +32,12 @@ namespace DetourNavigator } int getMinDistanceTo(const TilePosition& position, int maxDistance, - const std::set>& pushedTiles, - const std::set>& presentTiles) + const std::set>& pushedTiles, + const std::set>& presentTiles) { int result = maxDistance; - for (const auto& [halfExtents, tile] : pushedTiles) - if (presentTiles.find(std::tie(halfExtents, tile)) == presentTiles.end()) + for (const auto& [agentBounds, tile] : pushedTiles) + if (presentTiles.find(std::tie(agentBounds, tile)) == presentTiles.end()) result = std::min(result, getManhattanDistance(position, tile)); return result; } @@ -84,14 +84,14 @@ namespace DetourNavigator auto getAgentAndTile(const Job& job) noexcept { - return std::make_tuple(job.mAgentHalfExtents, job.mChangedTile); + return std::make_tuple(job.mAgentBounds, job.mChangedTile); } std::unique_ptr makeDbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr&& db, const Settings& settings) { if (db == nullptr) return nullptr; - return std::make_unique(updater, std::move(db), TileVersion(settings.mNavMeshVersion), + return std::make_unique(updater, std::move(db), TileVersion(navMeshVersion), settings.mRecast, settings.mWriteToNavMeshDb); } @@ -112,11 +112,11 @@ namespace DetourNavigator } } - Job::Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr navMeshCacheItem, + Job::Job(const AgentBounds& agentBounds, std::weak_ptr navMeshCacheItem, std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer, std::chrono::steady_clock::time_point processTime) : mId(getNextJobId()) - , mAgentHalfExtents(agentHalfExtents) + , mAgentBounds(agentBounds) , mNavMeshCacheItem(std::move(navMeshCacheItem)) , mWorldspace(worldspace) , mChangedTile(changedTile) @@ -145,7 +145,7 @@ namespace DetourNavigator stop(); } - void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& navMeshCacheItem, + void AsyncNavMeshUpdater::post(const AgentBounds& agentBounds, const SharedNavMeshCacheItem& navMeshCacheItem, const TilePosition& playerTile, std::string_view worldspace, const std::map& changedTiles) { @@ -169,16 +169,16 @@ namespace DetourNavigator for (const auto& [changedTile, changeType] : changedTiles) { - if (mPushed.emplace(agentHalfExtents, changedTile).second) + if (mPushed.emplace(agentBounds, changedTile).second) { const auto processTime = changeType == ChangeType::update - ? mLastUpdates[std::tie(agentHalfExtents, changedTile)] + mSettings.get().mMinUpdateInterval + ? mLastUpdates[std::tie(agentBounds, changedTile)] + mSettings.get().mMinUpdateInterval : std::chrono::steady_clock::time_point(); - const JobIt it = mJobs.emplace(mJobs.end(), agentHalfExtents, navMeshCacheItem, worldspace, + const JobIt it = mJobs.emplace(mJobs.end(), agentBounds, navMeshCacheItem, worldspace, changedTile, changeType, getManhattanDistance(changedTile, playerTile), processTime); - Log(Debug::Debug) << "Post job " << it->mId << " for agent=(" << it->mAgentHalfExtents << ")" + Log(Debug::Debug) << "Post job " << it->mId << " for agent=(" << it->mAgentBounds << ")" << " changedTile=(" << it->mChangedTile << ")"; if (playerTileChanged) @@ -342,7 +342,7 @@ namespace DetourNavigator switch (status) { case JobStatus::Done: - unlockTile(job->mAgentHalfExtents, job->mChangedTile); + unlockTile(job->mAgentBounds, job->mChangedTile); if (job->mGeneratedNavMeshData != nullptr) mDbWorker->enqueueJob(job); else @@ -419,7 +419,7 @@ namespace DetourNavigator return JobStatus::Done; } - NavMeshTilesCache::Value cachedNavMeshData = mNavMeshTilesCache.get(job.mAgentHalfExtents, job.mChangedTile, *recastMesh); + NavMeshTilesCache::Value cachedNavMeshData = mNavMeshTilesCache.get(job.mAgentBounds, job.mChangedTile, *recastMesh); std::unique_ptr preparedNavMeshData; const PreparedNavMeshData* preparedNavMeshDataPtr = nullptr; @@ -435,7 +435,7 @@ namespace DetourNavigator return JobStatus::MemoryCacheMiss; } - preparedNavMeshData = prepareNavMeshTileData(*recastMesh, job.mChangedTile, job.mAgentHalfExtents, mSettings.get().mRecast); + preparedNavMeshData = prepareNavMeshTileData(*recastMesh, job.mChangedTile, job.mAgentBounds, mSettings.get().mRecast); if (preparedNavMeshData == nullptr) { @@ -450,7 +450,7 @@ namespace DetourNavigator } else { - cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentHalfExtents, job.mChangedTile, + cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentBounds, job.mChangedTile, *recastMesh, std::move(preparedNavMeshData)); preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get(); } @@ -459,7 +459,7 @@ namespace DetourNavigator const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile); const UpdateNavMeshStatus status = navMeshCacheItem.lock()->updateTile(job.mChangedTile, std::move(cachedNavMeshData), - makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentHalfExtents, job.mChangedTile, mSettings.get().mRecast)); + makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentBounds, job.mChangedTile, mSettings.get().mRecast)); return handleUpdateNavMeshStatus(status, job, navMeshCacheItem, *recastMesh); } @@ -471,7 +471,7 @@ namespace DetourNavigator std::unique_ptr preparedNavMeshData; bool generatedNavMeshData = false; - if (job.mCachedTileData.has_value() && job.mCachedTileData->mVersion == mSettings.get().mNavMeshVersion) + if (job.mCachedTileData.has_value() && job.mCachedTileData->mVersion == navMeshVersion) { preparedNavMeshData = std::make_unique(); if (deserialize(job.mCachedTileData->mData, *preparedNavMeshData)) @@ -482,7 +482,7 @@ namespace DetourNavigator if (preparedNavMeshData == nullptr) { - preparedNavMeshData = prepareNavMeshTileData(*job.mRecastMesh, job.mChangedTile, job.mAgentHalfExtents, mSettings.get().mRecast); + preparedNavMeshData = prepareNavMeshTileData(*job.mRecastMesh, job.mChangedTile, job.mAgentBounds, mSettings.get().mRecast); generatedNavMeshData = true; } @@ -493,14 +493,14 @@ namespace DetourNavigator return JobStatus::Done; } - auto cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentHalfExtents, job.mChangedTile, *job.mRecastMesh, + auto cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentBounds, job.mChangedTile, *job.mRecastMesh, std::move(preparedNavMeshData)); const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile); const PreparedNavMeshData* preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get(); const UpdateNavMeshStatus status = navMeshCacheItem.lock()->updateTile(job.mChangedTile, std::move(cachedNavMeshData), - makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentHalfExtents, job.mChangedTile, mSettings.get().mRecast)); + makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentBounds, job.mChangedTile, mSettings.get().mRecast)); const JobStatus result = handleUpdateNavMeshStatus(status, job, navMeshCacheItem, *job.mRecastMesh); @@ -522,12 +522,12 @@ namespace DetourNavigator if (status == UpdateNavMeshStatus::removed || status == UpdateNavMeshStatus::lost) { const std::scoped_lock lock(mMutex); - mPresentTiles.erase(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile)); + mPresentTiles.erase(std::make_tuple(job.mAgentBounds, job.mChangedTile)); } else if (isSuccess(status) && status != UpdateNavMeshStatus::ignored) { const std::scoped_lock lock(mMutex); - mPresentTiles.insert(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile)); + mPresentTiles.insert(std::make_tuple(job.mAgentBounds, job.mChangedTile)); } writeDebugFiles(job, &recastMesh); @@ -564,7 +564,7 @@ namespace DetourNavigator if (job->mRecastMesh != nullptr) return job; - if (!lockTile(job->mAgentHalfExtents, job->mChangedTile)) + if (!lockTile(job->mAgentBounds, job->mChangedTile)) { Log(Debug::Debug) << "Failed to lock tile by " << job->mId; ++job->mTryNumber; @@ -604,14 +604,14 @@ namespace DetourNavigator void AsyncNavMeshUpdater::repost(JobIt job) { - unlockTile(job->mAgentHalfExtents, job->mChangedTile); + unlockTile(job->mAgentBounds, job->mChangedTile); if (mShouldStop || job->mTryNumber > 2) return; const std::lock_guard lock(mMutex); - if (mPushed.emplace(job->mAgentHalfExtents, job->mChangedTile).second) + if (mPushed.emplace(job->mAgentBounds, job->mChangedTile).second) { ++job->mTryNumber; insertPrioritizedJob(job, mWaiting); @@ -622,17 +622,17 @@ namespace DetourNavigator mJobs.erase(job); } - bool AsyncNavMeshUpdater::lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile) + bool AsyncNavMeshUpdater::lockTile(const AgentBounds& agentBounds, const TilePosition& changedTile) { - Log(Debug::Debug) << "Locking tile agent=(" << agentHalfExtents << ") changedTile=(" << changedTile << ")"; - return mProcessingTiles.lock()->emplace(agentHalfExtents, changedTile).second; + Log(Debug::Debug) << "Locking tile agent=" << agentBounds << " changedTile=(" << changedTile << ")"; + return mProcessingTiles.lock()->emplace(agentBounds, changedTile).second; } - void AsyncNavMeshUpdater::unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile) + void AsyncNavMeshUpdater::unlockTile(const AgentBounds& agentBounds, const TilePosition& changedTile) { auto locked = mProcessingTiles.lock(); - locked->erase(std::tie(agentHalfExtents, changedTile)); - Log(Debug::Debug) << "Unlocked tile agent=(" << agentHalfExtents << ") changedTile=(" << changedTile << ")"; + locked->erase(std::tie(agentBounds, changedTile)); + Log(Debug::Debug) << "Unlocked tile agent=" << agentBounds << " changedTile=(" << changedTile << ")"; if (locked->empty()) mProcessed.notify_all(); } @@ -819,7 +819,7 @@ namespace DetourNavigator { const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(), [&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); }); - job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects); + job->mInput = serialize(mRecastSettings, job->mAgentBounds, *job->mRecastMesh, objects); } else { @@ -827,7 +827,7 @@ namespace DetourNavigator [&] (const MeshSource& v) { return resolveMeshSource(*mDb, v); }); if (!objects.has_value()) return; - job->mInput = serialize(mRecastSettings, *job->mRecastMesh, *objects); + job->mInput = serialize(mRecastSettings, job->mAgentBounds, *job->mRecastMesh, *objects); } } @@ -850,7 +850,7 @@ namespace DetourNavigator Log(Debug::Debug) << "Serializing input for job " << job->mId; const std::vector objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(), [&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); }); - job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects); + job->mInput = serialize(mRecastSettings, job->mAgentBounds, *job->mRecastMesh, objects); } if (const auto& cachedTileData = job->mCachedTileData) diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index ec8c849ca8..d0850f0249 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -9,6 +9,7 @@ #include "waitconditiontype.hpp" #include "navmeshdb.hpp" #include "changetype.hpp" +#include "agentbounds.hpp" #include @@ -42,7 +43,7 @@ namespace DetourNavigator struct Job { const std::size_t mId; - const osg::Vec3f mAgentHalfExtents; + const AgentBounds mAgentBounds; const std::weak_ptr mNavMeshCacheItem; const std::string mWorldspace; const TilePosition mChangedTile; @@ -57,7 +58,7 @@ namespace DetourNavigator std::optional mCachedTileData; std::unique_ptr mGeneratedNavMeshData; - Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr navMeshCacheItem, + Job(const AgentBounds& agentBounds, std::weak_ptr navMeshCacheItem, std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer, std::chrono::steady_clock::time_point processTime); }; @@ -166,7 +167,7 @@ namespace DetourNavigator OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr&& db); ~AsyncNavMeshUpdater(); - void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& navMeshCacheItem, + void post(const AgentBounds& agentBounds, const SharedNavMeshCacheItem& navMeshCacheItem, const TilePosition& playerTile, std::string_view worldspace, const std::map& changedTiles); @@ -191,12 +192,12 @@ namespace DetourNavigator std::condition_variable mProcessed; std::list mJobs; std::deque mWaiting; - std::set> mPushed; + std::set> mPushed; Misc::ScopeGuarded mPlayerTile; NavMeshTilesCache mNavMeshTilesCache; - Misc::ScopeGuarded>> mProcessingTiles; - std::map, std::chrono::steady_clock::time_point> mLastUpdates; - std::set> mPresentTiles; + Misc::ScopeGuarded>> mProcessingTiles; + std::map, std::chrono::steady_clock::time_point> mLastUpdates; + std::set> mPresentTiles; std::vector mThreads; std::unique_ptr mDbWorker; std::atomic_size_t mDbGetTileHits {0}; @@ -220,9 +221,9 @@ namespace DetourNavigator void repost(JobIt job); - bool lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile); + bool lockTile(const AgentBounds& agentBounds, const TilePosition& changedTile); - void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile); + void unlockTile(const AgentBounds& agentBounds, const TilePosition& changedTile); inline std::size_t getTotalJobs() const; diff --git a/components/detournavigator/collisionshapetype.hpp b/components/detournavigator/collisionshapetype.hpp new file mode 100644 index 0000000000..3964840ecf --- /dev/null +++ b/components/detournavigator/collisionshapetype.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_COLLISIONSHAPETYPE_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_COLLISIONSHAPETYPE_H + +#include + +namespace DetourNavigator +{ + enum class CollisionShapeType : std::uint8_t + { + Aabb = 0, + RotatingBox = 1, + }; + + inline constexpr CollisionShapeType defaultCollisionShapeType = CollisionShapeType::Aabb; +} + +#endif diff --git a/components/detournavigator/debug.hpp b/components/detournavigator/debug.hpp index ce1e2d2023..091e49821c 100644 --- a/components/detournavigator/debug.hpp +++ b/components/detournavigator/debug.hpp @@ -4,6 +4,7 @@ #include "tilebounds.hpp" #include "status.hpp" #include "recastmesh.hpp" +#include "agentbounds.hpp" #include @@ -69,6 +70,21 @@ namespace DetourNavigator return s << ", .mOriginalSize=" << v.mOriginalSize << "}"; } + inline std::ostream& operator<<(std::ostream& s, CollisionShapeType v) + { + switch (v) + { + case CollisionShapeType::Aabb: return s << "AgentShapeType::Aabb"; + case CollisionShapeType::RotatingBox: return s << "AgentShapeType::RotatingBox"; + } + return s << "AgentShapeType::" << static_cast>(v); + } + + inline std::ostream& operator<<(std::ostream& s, const AgentBounds& v) + { + return s << "AgentBounds {" << v.mShapeType << ", " << v.mHalfExtents << "}"; + } + class RecastMesh; struct RecastSettings; diff --git a/components/detournavigator/generatenavmeshtile.cpp b/components/detournavigator/generatenavmeshtile.cpp index 3475b4ee8a..41b60d4a75 100644 --- a/components/detournavigator/generatenavmeshtile.cpp +++ b/components/detournavigator/generatenavmeshtile.cpp @@ -38,12 +38,12 @@ namespace DetourNavigator } GenerateNavMeshTile::GenerateNavMeshTile(std::string worldspace, const TilePosition& tilePosition, - RecastMeshProvider recastMeshProvider, const osg::Vec3f& agentHalfExtents, + RecastMeshProvider recastMeshProvider, const AgentBounds& agentBounds, const DetourNavigator::Settings& settings, std::weak_ptr consumer) : mWorldspace(std::move(worldspace)) , mTilePosition(tilePosition) , mRecastMeshProvider(recastMeshProvider) - , mAgentHalfExtents(agentHalfExtents) + , mAgentBounds(agentBounds) , mSettings(settings) , mConsumer(std::move(consumer)) {} @@ -70,25 +70,25 @@ namespace DetourNavigator const std::vector objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(), [&] (const MeshSource& v) { return consumer->resolveMeshSource(v); }); - std::vector input = serialize(mSettings.mRecast, *recastMesh, objects); + std::vector input = serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects); const std::optional info = consumer->find(mWorldspace, mTilePosition, input); - if (info.has_value() && info->mVersion == mSettings.mNavMeshVersion) + if (info.has_value() && info->mVersion == navMeshVersion) { consumer->identity(mWorldspace, mTilePosition, info->mTileId); ignore.mConsumer = nullptr; return; } - const auto data = prepareNavMeshTileData(*recastMesh, mTilePosition, mAgentHalfExtents, mSettings.mRecast); + const auto data = prepareNavMeshTileData(*recastMesh, mTilePosition, mAgentBounds, mSettings.mRecast); if (data == nullptr) return; if (info.has_value()) - consumer->update(mWorldspace, mTilePosition, info->mTileId, mSettings.mNavMeshVersion, *data); + consumer->update(mWorldspace, mTilePosition, info->mTileId, navMeshVersion, *data); else - consumer->insert(mWorldspace, mTilePosition, mSettings.mNavMeshVersion, input, *data); + consumer->insert(mWorldspace, mTilePosition, navMeshVersion, input, *data); ignore.mConsumer = nullptr; } diff --git a/components/detournavigator/generatenavmeshtile.hpp b/components/detournavigator/generatenavmeshtile.hpp index ecdf1c8bc0..0fc7341ff1 100644 --- a/components/detournavigator/generatenavmeshtile.hpp +++ b/components/detournavigator/generatenavmeshtile.hpp @@ -3,6 +3,7 @@ #include "recastmeshprovider.hpp" #include "tileposition.hpp" +#include "agentbounds.hpp" #include @@ -57,7 +58,7 @@ namespace DetourNavigator { public: GenerateNavMeshTile(std::string worldspace, const TilePosition& tilePosition, - RecastMeshProvider recastMeshProvider, const osg::Vec3f& agentHalfExtents, const Settings& settings, + RecastMeshProvider recastMeshProvider, const AgentBounds& agentBounds, const Settings& settings, std::weak_ptr consumer); void doWork() final; @@ -66,7 +67,7 @@ namespace DetourNavigator const std::string mWorldspace; const TilePosition mTilePosition; const RecastMeshProvider mRecastMeshProvider; - const osg::Vec3f mAgentHalfExtents; + const AgentBounds mAgentBounds; const Settings& mSettings; std::weak_ptr mConsumer; diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 97c5377558..3b26ad696f 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -101,9 +101,9 @@ namespace return result; } - float getHeight(const RecastSettings& settings,const osg::Vec3f& agentHalfExtents) + float getHeight(const RecastSettings& settings,const AgentBounds& agentBounds) { - return getAgentHeight(agentHalfExtents) * settings.mRecastScaleFactor; + return getAgentHeight(agentBounds) * settings.mRecastScaleFactor; } float getMaxClimb(const RecastSettings& settings) @@ -111,14 +111,14 @@ namespace return settings.mMaxClimb * settings.mRecastScaleFactor; } - float getRadius(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents) + float getRadius(const RecastSettings& settings, const AgentBounds& agentBounds) { - return getAgentRadius(agentHalfExtents) * settings.mRecastScaleFactor; + return getAgentRadius(agentBounds) * settings.mRecastScaleFactor; } float getSwimLevel(const RecastSettings& settings, const float waterLevel, const float agentHalfExtentsZ) { - return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;; + return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ; } struct RecastParams @@ -131,13 +131,13 @@ namespace int mWalkableRadius = 0; }; - RecastParams makeRecastParams(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents) + RecastParams makeRecastParams(const RecastSettings& settings, const AgentBounds& agentBounds) { RecastParams result; - result.mWalkableHeight = static_cast(std::ceil(getHeight(settings, agentHalfExtents) / settings.mCellHeight)); + result.mWalkableHeight = static_cast(std::ceil(getHeight(settings, agentBounds) / settings.mCellHeight)); result.mWalkableClimb = static_cast(std::floor(getMaxClimb(settings) / settings.mCellHeight)); - result.mWalkableRadius = static_cast(std::ceil(getRadius(settings, agentHalfExtents) / settings.mCellSize)); + result.mWalkableRadius = static_cast(std::ceil(getRadius(settings, agentBounds) / settings.mCellSize)); result.mMaxEdgeLen = static_cast(std::round(static_cast(settings.mMaxEdgeLen) / settings.mCellSize)); result.mSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : settings.mCellSize * settings.mDetailSampleDist; result.mSampleMaxError = settings.mCellHeight * settings.mDetailSampleMaxError; @@ -227,7 +227,7 @@ namespace ); } - bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector& water, + bool rasterizeTriangles(rcContext& context, float agentHalfExtentsZ, const std::vector& water, const RecastSettings& settings, const RecastParams& params, const TileBounds& realTileBounds, rcHeightfield& solid) { for (const CellWater& cellWater : water) @@ -237,7 +237,7 @@ namespace { const Rectangle rectangle { toNavMeshCoordinates(settings, *intersection), - toNavMeshCoordinates(settings, getSwimLevel(settings, cellWater.mWater.mLevel, agentHalfExtents.z())) + toNavMeshCoordinates(settings, getSwimLevel(settings, cellWater.mWater.mLevel, agentHalfExtentsZ)) }; if (!rasterizeTriangles(context, rectangle, AreaType_water, params, solid)) return false; @@ -277,12 +277,12 @@ namespace return true; } - bool rasterizeTriangles(rcContext& context, const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, + bool rasterizeTriangles(rcContext& context, const TilePosition& tilePosition, float agentHalfExtentsZ, const RecastMesh& recastMesh, const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid) { const TileBounds realTileBounds = makeRealTileBoundsWithBorder(settings, tilePosition); return rasterizeTriangles(context, recastMesh.getMesh(), settings, params, solid) - && rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, params, realTileBounds, solid) + && rasterizeTriangles(context, agentHalfExtentsZ, recastMesh.getWater(), settings, params, realTileBounds, solid) && rasterizeTriangles(context, recastMesh.getHeightfields(), settings, params, solid) && rasterizeTriangles(context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid); } @@ -389,7 +389,7 @@ namespace return power; } - std::pair getBoundsByZ(const RecastMesh& recastMesh, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings) + std::pair getBoundsByZ(const RecastMesh& recastMesh, float agentHalfExtentsZ, const RecastSettings& settings) { float minZ = 0; float maxZ = 0; @@ -403,7 +403,7 @@ namespace for (const CellWater& water : recastMesh.getWater()) { - const float swimLevel = getSwimLevel(settings, water.mWater.mLevel, agentHalfExtents.z()); + const float swimLevel = getSwimLevel(settings, water.mWater.mLevel, agentHalfExtentsZ); minZ = std::min(minZ, swimLevel); maxZ = std::max(maxZ, swimLevel); } @@ -431,19 +431,19 @@ namespace namespace DetourNavigator { std::unique_ptr prepareNavMeshTileData(const RecastMesh& recastMesh, - const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings) + const TilePosition& tilePosition, const AgentBounds& agentBounds, const RecastSettings& settings) { rcContext context; - const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentHalfExtents, settings); + const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentBounds.mHalfExtents.z(), settings); rcHeightfield solid; initHeightfield(context, tilePosition, toNavMeshCoordinates(settings, minZ), toNavMeshCoordinates(settings, maxZ), settings, solid); - const RecastParams params = makeRecastParams(settings, agentHalfExtents); + const RecastParams params = makeRecastParams(settings, agentBounds); - if (!rasterizeTriangles(context, tilePosition, agentHalfExtents, recastMesh, settings, params, solid)) + if (!rasterizeTriangles(context, tilePosition, agentBounds.mHalfExtents.z(), recastMesh, settings, params, solid)) return nullptr; rcFilterLowHangingWalkableObstacles(&context, params.mWalkableClimb, solid); @@ -462,11 +462,11 @@ namespace DetourNavigator } NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data, - const std::vector& offMeshConnections, const osg::Vec3f& agentHalfExtents, + const std::vector& offMeshConnections, const AgentBounds& agentBounds, const TilePosition& tile, const RecastSettings& settings) { const auto offMeshConVerts = getOffMeshVerts(offMeshConnections); - const std::vector offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents)); + const std::vector offMeshConRad(offMeshConnections.size(), getRadius(settings, agentBounds)); const std::vector offMeshConDir(offMeshConnections.size(), 0); const std::vector offMeshConAreas = getOffMeshConAreas(offMeshConnections); const std::vector offMeshConFlags = getOffMeshFlags(offMeshConnections); @@ -491,8 +491,8 @@ namespace DetourNavigator params.offMeshConFlags = offMeshConFlags.data(); params.offMeshConUserID = nullptr; params.offMeshConCount = static_cast(offMeshConnections.size()); - params.walkableHeight = getHeight(settings, agentHalfExtents); - params.walkableRadius = getRadius(settings, agentHalfExtents); + params.walkableHeight = getHeight(settings, agentBounds); + params.walkableRadius = getRadius(settings, agentBounds); params.walkableClimb = getMaxClimb(settings); rcVcopy(params.bmin, data.mPolyMesh.bmin); rcVcopy(params.bmax, data.mPolyMesh.bmax); diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 14919ab134..b890c5fcff 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -51,10 +51,10 @@ namespace DetourNavigator } std::unique_ptr prepareNavMeshTileData(const RecastMesh& recastMesh, - const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings); + const TilePosition& tilePosition, const AgentBounds& agentBounds, const RecastSettings& settings); NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data, - const std::vector& offMeshConnections, const osg::Vec3f& agentHalfExtents, + const std::vector& offMeshConnections, const AgentBounds& agentBounds, const TilePosition& tile, const RecastSettings& settings); NavMeshPtr makeEmptyNavMesh(const Settings& settings); diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 65f7c43fc1..df2b202cdd 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -26,6 +26,7 @@ namespace Loading namespace DetourNavigator { struct Settings; + struct AgentBounds; struct ObjectShapes { @@ -66,16 +67,16 @@ namespace DetourNavigator /** * @brief addAgent should be called for each agent even if all of them has same half extents. - * @param agentHalfExtents allows to setup bounding cylinder for each agent, for each different half extents + * @param agentBounds allows to setup bounding cylinder for each agent, for each different half extents * there is different navmesh. */ - virtual void addAgent(const osg::Vec3f& agentHalfExtents) = 0; + virtual void addAgent(const AgentBounds& agentBounds) = 0; /** * @brief removeAgent should be called for each agent even if all of them has same half extents - * @param agentHalfExtents allows determine which agent to remove + * @param agentBounds allows determine which agent to remove */ - virtual void removeAgent(const osg::Vec3f& agentHalfExtents) = 0; + virtual void removeAgent(const AgentBounds& agentBounds) = 0; /** * @brief setWorldspace should be called before adding object from new worldspace @@ -185,13 +186,13 @@ namespace DetourNavigator * @brief getNavMesh returns navmesh for specific agent half extents * @return navmesh */ - virtual SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const = 0; + virtual SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const = 0; /** * @brief getNavMeshes returns all current navmeshes * @return map of agent half extents to navmesh */ - virtual std::map getNavMeshes() const = 0; + virtual std::map getNavMeshes() const = 0; virtual const Settings& getSettings() const = 0; diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 42cd8bd9d1..e1b2df55ed 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -16,17 +16,17 @@ namespace DetourNavigator { } - void NavigatorImpl::addAgent(const osg::Vec3f& agentHalfExtents) + void NavigatorImpl::addAgent(const AgentBounds& agentBounds) { - if(agentHalfExtents.length2() <= 0) + if(agentBounds.mHalfExtents.length2() <= 0) return; - ++mAgents[agentHalfExtents]; - mNavMeshManager.addAgent(agentHalfExtents); + ++mAgents[agentBounds]; + mNavMeshManager.addAgent(agentBounds); } - void NavigatorImpl::removeAgent(const osg::Vec3f& agentHalfExtents) + void NavigatorImpl::removeAgent(const AgentBounds& agentBounds) { - const auto it = mAgents.find(agentHalfExtents); + const auto it = mAgents.find(agentBounds); if (it == mAgents.end()) return; if (it->second > 0) @@ -178,12 +178,12 @@ namespace DetourNavigator mNavMeshManager.wait(listener, waitConditionType); } - SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const + SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const AgentBounds& agentBounds) const { - return mNavMeshManager.getNavMesh(agentHalfExtents); + return mNavMeshManager.getNavMesh(agentBounds); } - std::map NavigatorImpl::getNavMeshes() const + std::map NavigatorImpl::getNavMeshes() const { return mNavMeshManager.getNavMeshes(); } diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index 58c4c6c05d..f7b2d6d8c8 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -18,9 +18,9 @@ namespace DetourNavigator */ explicit NavigatorImpl(const Settings& settings, std::unique_ptr&& db); - void addAgent(const osg::Vec3f& agentHalfExtents) override; + void addAgent(const AgentBounds& agentBounds) override; - void removeAgent(const osg::Vec3f& agentHalfExtents) override; + void removeAgent(const AgentBounds& agentBounds) override; void setWorldspace(std::string_view worldspace) override; @@ -56,9 +56,9 @@ namespace DetourNavigator void wait(Loading::Listener& listener, WaitConditionType waitConditionType) override; - SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const override; + SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const override; - std::map getNavMeshes() const override; + std::map getNavMeshes() const override; const Settings& getSettings() const override; @@ -73,7 +73,7 @@ namespace DetourNavigator NavMeshManager mNavMeshManager; bool mUpdatesEnabled; std::optional mLastPlayerPosition; - std::map mAgents; + std::map mAgents; std::unordered_map mAvoidIds; std::unordered_map mWaterIds; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 466ff5c912..1eb1860217 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORSTUB_H #include "navigator.hpp" +#include "settings.hpp" namespace Loading { @@ -15,9 +16,9 @@ namespace DetourNavigator public: NavigatorStub() = default; - void addAgent(const osg::Vec3f& /*agentHalfExtents*/) override {} + void addAgent(const AgentBounds& /*agentBounds*/) override {} - void removeAgent(const osg::Vec3f& /*agentHalfExtents*/) override {} + void removeAgent(const AgentBounds& /*agentBounds*/) override {} void setWorldspace(std::string_view /*worldspace*/) override {} @@ -80,14 +81,14 @@ namespace DetourNavigator void wait(Loading::Listener& /*listener*/, WaitConditionType /*waitConditionType*/) override {} - SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override + SharedNavMeshCacheItem getNavMesh(const AgentBounds& /*agentBounds*/) const override { return mEmptyNavMeshCacheItem; } - std::map getNavMeshes() const override + std::map getNavMeshes() const override { - return std::map(); + return {}; } const Settings& getSettings() const override diff --git a/components/detournavigator/navigatorutils.cpp b/components/detournavigator/navigatorutils.cpp index a64343905d..450fab6a6d 100644 --- a/components/detournavigator/navigatorutils.cpp +++ b/components/detournavigator/navigatorutils.cpp @@ -5,30 +5,30 @@ namespace DetourNavigator { - std::optional findRandomPointAroundCircle(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, + std::optional findRandomPointAroundCircle(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, float(*prng)()) { - const auto navMesh = navigator.getNavMesh(agentHalfExtents); + const auto navMesh = navigator.getNavMesh(agentBounds); if (!navMesh) return std::nullopt; const auto& settings = navigator.getSettings(); const auto result = DetourNavigator::findRandomPointAroundCircle(navMesh->lockConst()->getImpl(), - toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start), + toNavMeshCoordinates(settings.mRecast, agentBounds.mHalfExtents), toNavMeshCoordinates(settings.mRecast, start), toNavMeshCoordinates(settings.mRecast, maxRadius), includeFlags, settings.mDetour, prng); if (!result) return std::nullopt; return std::optional(fromNavMeshCoordinates(settings.mRecast, *result)); } - std::optional raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start, + std::optional raycast(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags) { - const auto navMesh = navigator.getNavMesh(agentHalfExtents); + const auto navMesh = navigator.getNavMesh(agentBounds); if (navMesh == nullptr) return std::nullopt; const auto& settings = navigator.getSettings(); const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(), - toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start), + toNavMeshCoordinates(settings.mRecast, agentBounds.mHalfExtents), toNavMeshCoordinates(settings.mRecast, start), toNavMeshCoordinates(settings.mRecast, end), includeFlags, settings.mDetour); if (!result) return std::nullopt; diff --git a/components/detournavigator/navigatorutils.hpp b/components/detournavigator/navigatorutils.hpp index 8bd1499897..44db7b40fe 100644 --- a/components/detournavigator/navigatorutils.hpp +++ b/components/detournavigator/navigatorutils.hpp @@ -12,7 +12,7 @@ namespace DetourNavigator { /** * @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through. - * @param agentHalfExtents allows to find navmesh for given actor. + * @param agentBounds allows to find navmesh for given actor. * @param start path from given point. * @param end path at given point. * @param includeFlags setup allowed surfaces for actor to walk. @@ -22,8 +22,8 @@ namespace DetourNavigator * Equal to out if no path is found. */ template - inline Status findPath(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const float stepSize, const osg::Vec3f& start, - const osg::Vec3f& end, const Flags includeFlags, const DetourNavigator::AreaCosts& areaCosts, + inline Status findPath(const Navigator& navigator, const AgentBounds& agentBounds, const float stepSize, + const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const AreaCosts& areaCosts, float endTolerance, OutputIterator& out) { static_assert( @@ -33,35 +33,35 @@ namespace DetourNavigator >::value, "out is not an OutputIterator" ); - const auto navMesh = navigator.getNavMesh(agentHalfExtents); + const auto navMesh = navigator.getNavMesh(agentBounds); if (navMesh == nullptr) return Status::NavMeshNotFound; const auto settings = navigator.getSettings(); - return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings.mRecast, agentHalfExtents), + return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings.mRecast, agentBounds.mHalfExtents), toNavMeshCoordinates(settings.mRecast, stepSize), toNavMeshCoordinates(settings.mRecast, start), toNavMeshCoordinates(settings.mRecast, end), includeFlags, areaCosts, settings, endTolerance, out); } /** * @brief findRandomPointAroundCircle returns random location on navmesh within the reach of specified location. - * @param agentHalfExtents allows to find navmesh for given actor. + * @param agentBounds allows to find navmesh for given actor. * @param start path from given point. * @param maxRadius limit maximum distance from start. * @param includeFlags setup allowed surfaces for actor to walk. * @return not empty optional with position if point is found and empty optional if point is not found. */ - std::optional findRandomPointAroundCircle(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, + std::optional findRandomPointAroundCircle(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, float(*prng)()); /** * @brief raycast finds farest navmesh point from start on a line from start to end that has path from start. - * @param agentHalfExtents allows to find navmesh for given actor. + * @param agentBounds allows to find navmesh for given actor. * @param start of the line * @param end of the line * @param includeFlags setup allowed surfaces for actor to walk. * @return not empty optional with position if point is found and empty optional if point is not found. */ - std::optional raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start, + std::optional raycast(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags); } diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index bbaf010807..ccab20a5aa 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -151,27 +151,27 @@ namespace DetourNavigator return true; } - void NavMeshManager::addAgent(const osg::Vec3f& agentHalfExtents) + void NavMeshManager::addAgent(const AgentBounds& agentBounds) { - auto cached = mCache.find(agentHalfExtents); + auto cached = mCache.find(agentBounds); if (cached != mCache.end()) return; - mCache.insert(std::make_pair(agentHalfExtents, + mCache.insert(std::make_pair(agentBounds, std::make_shared(makeEmptyNavMesh(mSettings), ++mGenerationCounter))); - Log(Debug::Debug) << "cache add for agent=" << agentHalfExtents; + Log(Debug::Debug) << "cache add for agent=" << agentBounds; } - bool NavMeshManager::reset(const osg::Vec3f& agentHalfExtents) + bool NavMeshManager::reset(const AgentBounds& agentBounds) { - const auto it = mCache.find(agentHalfExtents); + const auto it = mCache.find(agentBounds); if (it == mCache.end()) return true; if (!resetIfUnique(it->second)) return false; - mCache.erase(agentHalfExtents); - mChangedTiles.erase(agentHalfExtents); - mPlayerTile.erase(agentHalfExtents); - mLastRecastMeshManagerRevision.erase(agentHalfExtents); + mCache.erase(agentBounds); + mChangedTiles.erase(agentBounds); + mPlayerTile.erase(agentBounds); + mLastRecastMeshManagerRevision.erase(agentBounds); return true; } @@ -195,28 +195,28 @@ namespace DetourNavigator addChangedTile(tile, ChangeType::update); } - void NavMeshManager::update(const osg::Vec3f& playerPosition, const osg::Vec3f& agentHalfExtents) + void NavMeshManager::update(const osg::Vec3f& playerPosition, const AgentBounds& agentBounds) { const auto playerTile = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition)); - auto& lastRevision = mLastRecastMeshManagerRevision[agentHalfExtents]; - auto lastPlayerTile = mPlayerTile.find(agentHalfExtents); + auto& lastRevision = mLastRecastMeshManagerRevision[agentBounds]; + auto lastPlayerTile = mPlayerTile.find(agentBounds); if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end() && lastPlayerTile->second == playerTile) return; lastRevision = mRecastMeshManager.getRevision(); if (lastPlayerTile == mPlayerTile.end()) - lastPlayerTile = mPlayerTile.insert(std::make_pair(agentHalfExtents, playerTile)).first; + lastPlayerTile = mPlayerTile.insert(std::make_pair(agentBounds, playerTile)).first; else lastPlayerTile->second = playerTile; std::map tilesToPost; - const auto cached = getCached(agentHalfExtents); + const auto cached = getCached(agentBounds); if (!cached) { std::ostringstream stream; - stream << "Agent with half extents is not found: " << agentHalfExtents; + stream << "Agent with half extents is not found: " << agentBounds; throw InvalidArgument(stream.str()); } - const auto changedTiles = mChangedTiles.find(agentHalfExtents); + const auto changedTiles = mChangedTiles.find(agentBounds); { const auto locked = cached->lockConst(); const auto& navMesh = locked->getImpl(); @@ -247,10 +247,10 @@ namespace DetourNavigator recastMeshManager.reportNavMeshChange(recastMeshManager.getVersion(), Version {0, 0}); }); } - mAsyncNavMeshUpdater.post(agentHalfExtents, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost); + mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost); if (changedTiles != mChangedTiles.end()) changedTiles->second.clear(); - Log(Debug::Debug) << "Cache update posted for agent=" << agentHalfExtents << + Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds << " playerTile=" << lastPlayerTile->second << " recastMeshManagerRevision=" << lastRevision; } @@ -260,12 +260,12 @@ namespace DetourNavigator mAsyncNavMeshUpdater.wait(listener, waitConditionType); } - SharedNavMeshCacheItem NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const + SharedNavMeshCacheItem NavMeshManager::getNavMesh(const AgentBounds& agentBounds) const { - return getCached(agentHalfExtents); + return getCached(agentBounds); } - std::map NavMeshManager::getNavMeshes() const + std::map NavMeshManager::getNavMeshes() const { return mCache; } @@ -319,9 +319,9 @@ namespace DetourNavigator } } - SharedNavMeshCacheItem NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const + SharedNavMeshCacheItem NavMeshManager::getCached(const AgentBounds& agentBounds) const { - const auto cached = mCache.find(agentHalfExtents); + const auto cached = mCache.find(agentBounds); if (cached != mCache.end()) return cached->second; return SharedNavMeshCacheItem(); diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index dbe45b684f..d4a5a58122 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -7,7 +7,7 @@ #include "recastmeshtiles.hpp" #include "waitconditiontype.hpp" #include "heightfieldshape.hpp" - +#include "agentbounds.hpp" #include @@ -35,7 +35,7 @@ namespace DetourNavigator bool removeObject(const ObjectId id); - void addAgent(const osg::Vec3f& agentHalfExtents); + void addAgent(const AgentBounds& agentBounds); bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level); @@ -45,19 +45,19 @@ namespace DetourNavigator bool removeHeightfield(const osg::Vec2i& cellPosition); - bool reset(const osg::Vec3f& agentHalfExtents); + bool reset(const AgentBounds& agentBounds); void addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType); void removeOffMeshConnections(const ObjectId id); - void update(const osg::Vec3f& playerPosition, const osg::Vec3f& agentHalfExtents); + void update(const osg::Vec3f& playerPosition, const AgentBounds& agentBounds); void wait(Loading::Listener& listener, WaitConditionType waitConditionType); - SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const; + SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const; - std::map getNavMeshes() const; + std::map getNavMeshes() const; void reportStats(unsigned int frameNumber, osg::Stats& stats) const; @@ -69,11 +69,11 @@ namespace DetourNavigator TileCachedRecastMeshManager mRecastMeshManager; OffMeshConnectionsManager mOffMeshConnectionsManager; AsyncNavMeshUpdater mAsyncNavMeshUpdater; - std::map mCache; - std::map> mChangedTiles; + std::map mCache; + std::map> mChangedTiles; std::size_t mGenerationCounter = 0; - std::map mPlayerTile; - std::map mLastRecastMeshManagerRevision; + std::map mPlayerTile; + std::map mLastRecastMeshManagerRevision; void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType); @@ -81,7 +81,7 @@ namespace DetourNavigator void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType); - SharedNavMeshCacheItem getCached(const osg::Vec3f& agentHalfExtents) const; + SharedNavMeshCacheItem getCached(const AgentBounds& agentBounds) const; }; } diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index bbda8a3179..6938ff3650 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -10,14 +10,14 @@ namespace DetourNavigator : mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0), mHitCount(0), mGetCount(0) {} - NavMeshTilesCache::Value NavMeshTilesCache::get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, + NavMeshTilesCache::Value NavMeshTilesCache::get(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh) { const std::lock_guard lock(mMutex); ++mGetCount; - const auto tile = mValues.find(std::make_tuple(agentHalfExtents, changedTile, recastMesh)); + const auto tile = mValues.find(std::make_tuple(agentBounds, changedTile, recastMesh)); if (tile == mValues.end()) return Value(); @@ -28,7 +28,7 @@ namespace DetourNavigator return Value(*this, tile->second); } - NavMeshTilesCache::Value NavMeshTilesCache::set(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, + NavMeshTilesCache::Value NavMeshTilesCache::set(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh, std::unique_ptr&& value) { const auto itemSize = sizeof(RecastMesh) + getSize(recastMesh) @@ -45,8 +45,8 @@ namespace DetourNavigator RecastMeshData key {recastMesh.getMesh(), recastMesh.getWater(), recastMesh.getHeightfields(), recastMesh.getFlatHeightfields()}; - const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(key), itemSize); - const auto emplaced = mValues.emplace(std::make_tuple(agentHalfExtents, changedTile, std::cref(iterator->mRecastMeshData)), iterator); + const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentBounds, changedTile, std::move(key), itemSize); + const auto emplaced = mValues.emplace(std::make_tuple(agentBounds, changedTile, std::cref(iterator->mRecastMeshData)), iterator); if (!emplaced.second) { @@ -92,7 +92,7 @@ namespace DetourNavigator { const auto& item = mFreeItems.back(); - const auto value = mValues.find(std::make_tuple(item.mAgentHalfExtents, item.mChangedTile, std::cref(item.mRecastMeshData))); + const auto value = mValues.find(std::make_tuple(item.mAgentBounds, item.mChangedTile, std::cref(item.mRecastMeshData))); if (value == mValues.end()) return; diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index e7e0b6c7a8..572f7fdb4b 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -4,6 +4,7 @@ #include "preparednavmeshdata.hpp" #include "recastmesh.hpp" #include "tileposition.hpp" +#include "agentbounds.hpp" #include #include @@ -52,16 +53,16 @@ namespace DetourNavigator struct Item { std::atomic mUseCount; - osg::Vec3f mAgentHalfExtents; + AgentBounds mAgentBounds; TilePosition mChangedTile; RecastMeshData mRecastMeshData; std::unique_ptr mPreparedNavMeshData; std::size_t mSize; - Item(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, + Item(const AgentBounds& agentBounds, const TilePosition& changedTile, RecastMeshData&& recastMeshData, std::size_t size) : mUseCount(0) - , mAgentHalfExtents(agentHalfExtents) + , mAgentBounds(agentBounds) , mChangedTile(changedTile) , mRecastMeshData(std::move(recastMeshData)) , mSize(size) @@ -136,10 +137,10 @@ namespace DetourNavigator NavMeshTilesCache(const std::size_t maxNavMeshDataSize); - Value get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, + Value get(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh); - Value set(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile, + Value set(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh, std::unique_ptr&& value); Stats getStats() const; @@ -153,7 +154,7 @@ namespace DetourNavigator std::size_t mGetCount; std::list mBusyItems; std::list mFreeItems; - std::map>, ItemIterator, std::less<>> mValues; + std::map>, ItemIterator, std::less<>> mValues; void removeLeastRecentlyUsed(); diff --git a/components/detournavigator/recastparams.hpp b/components/detournavigator/recastparams.hpp index 7e07d2c085..e765623431 100644 --- a/components/detournavigator/recastparams.hpp +++ b/components/detournavigator/recastparams.hpp @@ -1,20 +1,32 @@ #ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H +#include "agentbounds.hpp" + #include +#include #include +#include namespace DetourNavigator { - inline float getAgentHeight(const osg::Vec3f& agentHalfExtents) + inline float getAgentHeight(const AgentBounds& agentBounds) { - return 2.0f * agentHalfExtents.z(); + return 2.0f * agentBounds.mHalfExtents.z(); } - inline float getAgentRadius(const osg::Vec3f& agentHalfExtents) + inline float getAgentRadius(const AgentBounds& agentBounds) { - return std::max(agentHalfExtents.x(), agentHalfExtents.y()) * std::sqrt(2); + switch (agentBounds.mShapeType) + { + case CollisionShapeType::Aabb: + return std::max(agentBounds.mHalfExtents.x(), agentBounds.mHalfExtents.y()) * std::sqrt(2); + case CollisionShapeType::RotatingBox: + return agentBounds.mHalfExtents.x(); + } + assert(false && "Unsupported agent shape type"); + return 0; } } diff --git a/components/detournavigator/serialization.cpp b/components/detournavigator/serialization.cpp index 50b014acb1..a0a097ab0b 100644 --- a/components/detournavigator/serialization.cpp +++ b/components/detournavigator/serialization.cpp @@ -5,6 +5,7 @@ #include "recast.hpp" #include "recastmesh.hpp" #include "settings.hpp" +#include "agentbounds.hpp" #include #include @@ -136,12 +137,13 @@ namespace } template - void operator()(Visitor&& visitor, const RecastSettings& settings, const RecastMesh& recastMesh, - const std::vector& dbRefGeometryObjects) const + void operator()(Visitor&& visitor, const RecastSettings& settings, const AgentBounds& agentBounds, + const RecastMesh& recastMesh, const std::vector& dbRefGeometryObjects) const { visitor(*this, DetourNavigator::recastMeshMagic); visitor(*this, DetourNavigator::recastMeshVersion); visitor(*this, settings); + visitor(*this, agentBounds); visitor(*this, recastMesh); visitor(*this, dbRefGeometryObjects); } @@ -228,21 +230,28 @@ namespace visitor(*this, value.mPolyMesh); visitor(*this, value.mPolyMeshDetail); } + + template + void operator()(Visitor&& visitor, const AgentBounds& value) const + { + visitor(*this, value.mShapeType); + visitor(*this, value.mHalfExtents); + } }; } } // namespace DetourNavigator namespace DetourNavigator { - std::vector serialize(const RecastSettings& settings, const RecastMesh& recastMesh, - const std::vector& dbRefGeometryObjects) + std::vector serialize(const RecastSettings& settings, const AgentBounds& agentBounds, + const RecastMesh& recastMesh, const std::vector& dbRefGeometryObjects) { constexpr Format format; Serialization::SizeAccumulator sizeAccumulator; - format(sizeAccumulator, settings, recastMesh, dbRefGeometryObjects); + format(sizeAccumulator, settings, agentBounds, recastMesh, dbRefGeometryObjects); std::vector result(sizeAccumulator.value()); format(Serialization::BinaryWriter(result.data(), result.data() + result.size()), - settings, recastMesh, dbRefGeometryObjects); + settings, agentBounds, recastMesh, dbRefGeometryObjects); return result; } diff --git a/components/detournavigator/serialization.hpp b/components/detournavigator/serialization.hpp index 194e50a994..93022df97e 100644 --- a/components/detournavigator/serialization.hpp +++ b/components/detournavigator/serialization.hpp @@ -11,15 +11,16 @@ namespace DetourNavigator struct DbRefGeometryObject; struct PreparedNavMeshData; struct RecastSettings; + struct AgentBounds; constexpr char recastMeshMagic[] = {'r', 'c', 's', 't'}; - constexpr std::uint32_t recastMeshVersion = 1; + constexpr std::uint32_t recastMeshVersion = 2; constexpr char preparedNavMeshDataMagic[] = {'p', 'n', 'a', 'v'}; constexpr std::uint32_t preparedNavMeshDataVersion = 1; - std::vector serialize(const RecastSettings& settings, const RecastMesh& value, - const std::vector& dbRefGeometryObjects); + std::vector serialize(const RecastSettings& settings, const AgentBounds& agentBounds, + const RecastMesh& recastMesh, const std::vector& dbRefGeometryObjects); std::vector serialize(const PreparedNavMeshData& value); diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index 040a0a7b29..178a1215a5 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -61,7 +61,6 @@ namespace DetourNavigator result.mEnableRecastMeshFileNameRevision = ::Settings::Manager::getBool("enable recast mesh file name revision", "Navigator"); result.mEnableNavMeshFileNameRevision = ::Settings::Manager::getBool("enable nav mesh file name revision", "Navigator"); result.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator")); - result.mNavMeshVersion = ::Settings::Manager::getInt("nav mesh version", "Navigator"); result.mEnableNavMeshDiskCache = ::Settings::Manager::getBool("enable nav mesh disk cache", "Navigator"); result.mWriteToNavMeshDb = ::Settings::Manager::getBool("write to navmeshdb", "Navigator"); result.mMaxDbFileSize = static_cast(::Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index b107a6eb85..67e0a5a958 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -50,10 +50,11 @@ namespace DetourNavigator std::string mRecastMeshPathPrefix; std::string mNavMeshPathPrefix; std::chrono::milliseconds mMinUpdateInterval; - std::int64_t mNavMeshVersion = 0; std::uint64_t mMaxDbFileSize = 0; }; + inline constexpr std::int64_t navMeshVersion = 2; + RecastSettings makeRecastSettingsFromSettingsManager(); DetourSettings makeDetourSettingsFromSettingsManager(); diff --git a/components/sceneutil/agentpath.cpp b/components/sceneutil/agentpath.cpp index 8d90475a82..e1fa9fe3c8 100644 --- a/components/sceneutil/agentpath.cpp +++ b/components/sceneutil/agentpath.cpp @@ -37,7 +37,7 @@ namespace namespace SceneUtil { osg::ref_ptr createAgentPathGroup(const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end, + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end, const DetourNavigator::RecastSettings& settings) { using namespace DetourNavigator; @@ -46,8 +46,8 @@ namespace SceneUtil DebugDraw debugDraw(*group, DebugDraw::makeStateSet(), osg::Vec3f(0, 0, 0), 1); - const auto agentRadius = DetourNavigator::getAgentRadius(halfExtents); - const auto agentHeight = DetourNavigator::getAgentHeight(halfExtents); + const auto agentRadius = DetourNavigator::getAgentRadius(agentBounds); + const auto agentHeight = DetourNavigator::getAgentHeight(agentBounds); const auto agentClimb = settings.mMaxClimb; const auto startColor = duRGBA(128, 25, 0, 192); const auto endColor = duRGBA(51, 102, 0, 129); diff --git a/components/sceneutil/agentpath.hpp b/components/sceneutil/agentpath.hpp index 1194fa512a..53a41e02d8 100644 --- a/components/sceneutil/agentpath.hpp +++ b/components/sceneutil/agentpath.hpp @@ -14,12 +14,13 @@ namespace osg namespace DetourNavigator { struct RecastSettings; + struct AgentBounds; } namespace SceneUtil { osg::ref_ptr createAgentPathGroup(const std::deque& path, - const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end, + const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end, const DetourNavigator::RecastSettings& settings); } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 807f00b41f..2675004907 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -943,10 +943,6 @@ min update interval ms = 250 # Distance is measured in the number of tiles and can be only an integer value. wait until min distance to player = 5 -# Version of navigation mesh generation algorithm. -# Should be increased each time there is a difference between output of makeNavMeshTileData function for the same input. -nav mesh version = 1 - # Use navigation mesh cache stored on disk (true, false) enable nav mesh disk cache = true