mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 21:09:41 +00:00
Support different agent collision shape type for pathfinding
Actors may have different collision shapes. Currently there are axis-aligned bounding boxes and rotating bounding boxes. With AABB it's required to use bounding cylinder for navmesh agent to avoid providing paths where actor can't pass. But for rotating bounding boxes cylinder with diameter equal to the front face width should be used to not reduce of available paths. For example rats have rotating bounding box as collision shape because of the difference between front and side faces width. * Add agent bounds to navmesh tile db cache key. This is required to distinguish tiles for agents with different bounds. * Increase navmesh version because navmesh tile db cache key and data has changed. * Move navmesh version to the code to avoid misconfiguration by users. * Fix all places where wrong half extents were used for pathfinding.
This commit is contained in:
parent
15c7ed774c
commit
1a12c453d6
51 changed files with 515 additions and 389 deletions
|
@ -13,7 +13,7 @@ namespace
|
||||||
|
|
||||||
struct Key
|
struct Key
|
||||||
{
|
{
|
||||||
osg::Vec3f mAgentHalfExtents;
|
AgentBounds mAgentBounds;
|
||||||
TilePosition mTilePosition;
|
TilePosition mTilePosition;
|
||||||
RecastMesh mRecastMesh;
|
RecastMesh mRecastMesh;
|
||||||
};
|
};
|
||||||
|
@ -137,6 +137,7 @@ namespace
|
||||||
template <class Random>
|
template <class Random>
|
||||||
Key generateKey(std::size_t triangles, Random& random)
|
Key generateKey(std::size_t triangles, Random& random)
|
||||||
{
|
{
|
||||||
|
const CollisionShapeType agentShapeType = CollisionShapeType::Aabb;
|
||||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
||||||
const TilePosition tilePosition = generateVec2i(10000, random);
|
const TilePosition tilePosition = generateVec2i(10000, random);
|
||||||
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
|
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
|
||||||
|
@ -146,7 +147,7 @@ namespace
|
||||||
generateWater(std::back_inserter(water), 1, random);
|
generateWater(std::back_inserter(water), 1, random);
|
||||||
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water),
|
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water),
|
||||||
{generateHeightfield(random)}, {generateFlatHeightfield(random)}, {});
|
{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;
|
constexpr std::size_t trianglesPerTile = 239;
|
||||||
|
@ -165,7 +166,7 @@ namespace
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Key key = generateKey(trianglesPerTile, random);
|
Key key = generateKey(trianglesPerTile, random);
|
||||||
cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh,
|
cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh,
|
||||||
std::make_unique<PreparedNavMeshData>());
|
std::make_unique<PreparedNavMeshData>());
|
||||||
*out++ = std::move(key);
|
*out++ = std::move(key);
|
||||||
const std::size_t newSize = cache.getStats().mNavMeshCacheSize;
|
const std::size_t newSize = cache.getStats().mNavMeshCacheSize;
|
||||||
|
@ -188,7 +189,7 @@ namespace
|
||||||
while (state.KeepRunning())
|
while (state.KeepRunning())
|
||||||
{
|
{
|
||||||
const auto& key = keys[n++ % keys.size()];
|
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);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +217,7 @@ namespace
|
||||||
while (state.KeepRunning())
|
while (state.KeepRunning())
|
||||||
{
|
{
|
||||||
const auto& key = keys[n++ % keys.size()];
|
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<PreparedNavMeshData>());
|
std::make_unique<PreparedNavMeshData>());
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <components/vfs/registerarchives.hpp>
|
#include <components/vfs/registerarchives.hpp>
|
||||||
#include <components/esm3/readerscache.hpp>
|
#include <components/esm3/readerscache.hpp>
|
||||||
#include <components/platform/platform.hpp>
|
#include <components/platform/platform.hpp>
|
||||||
|
#include <components/detournavigator/agentbounds.hpp>
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
@ -173,7 +174,9 @@ namespace NavMeshTool
|
||||||
Settings::Manager settings;
|
Settings::Manager settings;
|
||||||
settings.load(config);
|
settings.load(config);
|
||||||
|
|
||||||
|
const DetourNavigator::CollisionShapeType agentCollisionShape = DetourNavigator::defaultCollisionShapeType;
|
||||||
const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game");
|
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<std::uint64_t>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
const std::uint64_t maxDbFileSize = static_cast<std::uint64_t>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
||||||
const std::string dbPath = (config.getUserDataPath() / "navmesh.db").string();
|
const std::string dbPath = (config.getUserDataPath() / "navmesh.db").string();
|
||||||
|
|
||||||
|
@ -201,7 +204,7 @@ namespace NavMeshTool
|
||||||
WorldspaceData cellsData = gatherWorldspaceData(navigatorSettings, readers, vfs, bulletShapeManager,
|
WorldspaceData cellsData = gatherWorldspaceData(navigatorSettings, readers, vfs, bulletShapeManager,
|
||||||
esmData, processInteriorCells, writeBinaryLog);
|
esmData, processInteriorCells, writeBinaryLog);
|
||||||
|
|
||||||
const Status status = generateAllNavMeshTiles(agentHalfExtents, navigatorSettings, threadsNumber,
|
const Status status = generateAllNavMeshTiles(agentBounds, navigatorSettings, threadsNumber,
|
||||||
removeUnusedTiles, writeBinaryLog, cellsData, std::move(db));
|
removeUnusedTiles, writeBinaryLog, cellsData, std::move(db));
|
||||||
|
|
||||||
switch (status)
|
switch (status)
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace NavMeshTool
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
using DetourNavigator::AgentBounds;
|
||||||
using DetourNavigator::GenerateNavMeshTile;
|
using DetourNavigator::GenerateNavMeshTile;
|
||||||
using DetourNavigator::NavMeshDb;
|
using DetourNavigator::NavMeshDb;
|
||||||
using DetourNavigator::NavMeshTileInfo;
|
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,
|
std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& data,
|
||||||
NavMeshDb&& db)
|
NavMeshDb&& db)
|
||||||
{
|
{
|
||||||
|
@ -291,7 +292,7 @@ namespace NavMeshTool
|
||||||
input->mWorldspace,
|
input->mWorldspace,
|
||||||
tilePosition,
|
tilePosition,
|
||||||
RecastMeshProvider(input->mTileCachedRecastMeshManager),
|
RecastMeshProvider(input->mTileCachedRecastMeshManager),
|
||||||
agentHalfExtents,
|
agentBounds,
|
||||||
settings,
|
settings,
|
||||||
navMeshTileConsumer
|
navMeshTileConsumer
|
||||||
));
|
));
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
class NavMeshDb;
|
class NavMeshDb;
|
||||||
struct Settings;
|
struct Settings;
|
||||||
|
struct AgentBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NavMeshTool
|
namespace NavMeshTool
|
||||||
|
@ -22,7 +23,7 @@ namespace NavMeshTool
|
||||||
NotEnoughSpace,
|
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,
|
std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& cellsData,
|
||||||
DetourNavigator::NavMeshDb&& db);
|
DetourNavigator::NavMeshDb&& db);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace MWMechanics
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct Navigator;
|
struct Navigator;
|
||||||
|
struct AgentBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -644,14 +645,13 @@ namespace MWBase
|
||||||
virtual DetourNavigator::Navigator* getNavigator() const = 0;
|
virtual DetourNavigator::Navigator* getNavigator() const = 0;
|
||||||
|
|
||||||
virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& 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 removeActorPath(const MWWorld::ConstPtr& actor) const = 0;
|
||||||
|
|
||||||
virtual void setNavMeshNumberToRender(const std::size_t value) = 0;
|
virtual void setNavMeshNumberToRender(const std::size_t value) = 0;
|
||||||
|
|
||||||
/// Return physical half extents of the given actor to be used in pathfinding
|
virtual DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const = 0;
|
||||||
virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0;
|
|
||||||
|
|
||||||
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
|
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -268,11 +268,11 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
// Try to build path to the target.
|
// 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 navigatorFlags = getNavigatorFlags(actor);
|
||||||
const auto areaCosts = getAreaCosts(actor);
|
const auto areaCosts = getAreaCosts(actor);
|
||||||
const auto pathGridGraph = getPathGridGraph(actor.getCell());
|
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);
|
navigatorFlags, areaCosts, storage.mAttackRange, PathType::Full);
|
||||||
|
|
||||||
if (!mPathFinder.isPathConstructed())
|
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
|
// 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.
|
// on navmesh to attack the target from there.
|
||||||
const auto navigator = world->getNavigator();
|
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 (hit.has_value() && (*hit - vTargetPos).length() <= rangeAttack)
|
||||||
{
|
{
|
||||||
// If the point is close enough, try to find a path to that point.
|
// 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);
|
navigatorFlags, areaCosts, storage.mAttackRange, PathType::Full);
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
const osg::Vec3f position = actor.getRefData().getPosition().asVec3(); //position of the actor
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
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
|
/// 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
|
//... 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[0] = 0;
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 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;
|
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
|
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()),
|
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;
|
mRotateOnTheRunChecks = 3;
|
||||||
|
|
||||||
// give priority to go directly on target if there is minimal opportunity
|
// 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,
|
||||||
const float pointTolerance = getPointTolerance(actor.getClass().getMaxSpeed(actor), duration, halfExtents);
|
world->getHalfExtents(actor));
|
||||||
|
|
||||||
static const bool smoothMovement = Settings::Manager::getBool("smooth movement", "Game");
|
static const bool smoothMovement = Settings::Manager::getBool("smooth movement", "Game");
|
||||||
mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE,
|
mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE,
|
||||||
/*shortenIfAlmostStraight=*/smoothMovement, actorCanMoveByZ,
|
/*shortenIfAlmostStraight=*/smoothMovement, actorCanMoveByZ,
|
||||||
halfExtents, getNavigatorFlags(actor));
|
agentBounds, getNavigatorFlags(actor));
|
||||||
|
|
||||||
if (isDestReached || mPathFinder.checkPathCompleted()) // if path is finished
|
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())
|
else if (mPathFinder.getPath().empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
world->updateActorPath(actor, mPathFinder.getPath(), world->getPathfindingHalfExtents(actor), position, dest);
|
world->updateActorPath(actor, mPathFinder.getPath(), agentBounds, position, dest);
|
||||||
|
|
||||||
if (mRotateOnTheRunChecks == 0
|
if (mRotateOnTheRunChecks == 0
|
||||||
|| isReachableRotatingOnTheRun(actor, *mPathFinder.getPath().begin())) // to prevent circling around a path point
|
|| isReachableRotatingOnTheRun(actor, *mPathFinder.getPath().begin())) // to prevent circling around a path point
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <components/esm3/aisequence.hpp>
|
#include <components/esm3/aisequence.hpp>
|
||||||
|
#include <components/detournavigator/agentbounds.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace MWMechanics
|
||||||
const auto position = actor.getRefData().getPosition().asVec3();
|
const auto position = actor.getRefData().getPosition().asVec3();
|
||||||
const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
|
const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
|
||||||
const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(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;
|
osg::Vec3f direction = destination - position;
|
||||||
direction.normalize();
|
direction.normalize();
|
||||||
const auto visibleDestination = (
|
const auto visibleDestination = (
|
||||||
|
@ -210,10 +210,10 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
|
const auto agentBounds = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor);
|
||||||
constexpr float endTolerance = 0;
|
constexpr float endTolerance = 0;
|
||||||
mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(),
|
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);
|
endTolerance, PathType::Full);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ namespace MWMechanics
|
||||||
const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
|
const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
|
||||||
const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor);
|
const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor);
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
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 navigator = world->getNavigator();
|
||||||
const auto navigatorFlags = getNavigatorFlags(actor);
|
const auto navigatorFlags = getNavigatorFlags(actor);
|
||||||
const auto areaCosts = getAreaCosts(actor);
|
const auto areaCosts = getAreaCosts(actor);
|
||||||
|
@ -358,7 +358,7 @@ namespace MWMechanics
|
||||||
if (!isWaterCreature && !isFlyingCreature)
|
if (!isWaterCreature && !isFlyingCreature)
|
||||||
{
|
{
|
||||||
// findRandomPointAroundCircle uses wanderDistance as limit for random and not as exact distance
|
// 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, []() {
|
mInitialActorPosition, wanderDistance, navigatorFlags, []() {
|
||||||
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
||||||
return Misc::Rng::rollProbability(prng);
|
return Misc::Rng::rollProbability(prng);
|
||||||
|
@ -385,7 +385,7 @@ namespace MWMechanics
|
||||||
if (isWaterCreature || isFlyingCreature)
|
if (isWaterCreature || isFlyingCreature)
|
||||||
mPathFinder.buildStraightPath(mDestination);
|
mPathFinder.buildStraightPath(mDestination);
|
||||||
else
|
else
|
||||||
mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, halfExtents, navigatorFlags,
|
mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, agentBounds, navigatorFlags,
|
||||||
areaCosts, endTolerance, PathType::Full);
|
areaCosts, endTolerance, PathType::Full);
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
|
@ -532,8 +532,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if (mUsePathgrid)
|
if (mUsePathgrid)
|
||||||
{
|
{
|
||||||
const auto halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
|
const auto agentBounds = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor);
|
||||||
mPathFinder.buildPathByNavMeshToNextPoint(actor, halfExtents, getNavigatorFlags(actor),
|
mPathFinder.buildPathByNavMeshToNextPoint(actor, agentBounds, getNavigatorFlags(actor),
|
||||||
getAreaCosts(actor));
|
getAreaCosts(actor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
#include <components/detournavigator/agentbounds.hpp>
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
@ -80,7 +81,7 @@ namespace MWMechanics
|
||||||
std::vector<MWWorld::Ptr>* occupyingActors)
|
std::vector<MWWorld::Ptr>* occupyingActors)
|
||||||
{
|
{
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
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()));
|
const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
|
||||||
if (ignorePlayer)
|
if (ignorePlayer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,12 +109,12 @@ namespace
|
||||||
struct IsValidShortcut
|
struct IsValidShortcut
|
||||||
{
|
{
|
||||||
const DetourNavigator::Navigator* mNavigator;
|
const DetourNavigator::Navigator* mNavigator;
|
||||||
const osg::Vec3f mHalfExtents;
|
const DetourNavigator::AgentBounds mAgentBounds;
|
||||||
const DetourNavigator::Flags mFlags;
|
const DetourNavigator::Flags mFlags;
|
||||||
|
|
||||||
bool operator()(const osg::Vec3f& start, const osg::Vec3f& end) const
|
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;
|
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,
|
void PathFinder::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)
|
const DetourNavigator::Flags flags)
|
||||||
{
|
{
|
||||||
if (mPath.empty())
|
if (mPath.empty())
|
||||||
return;
|
return;
|
||||||
|
@ -318,7 +318,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
const IsValidShortcut isValidShortcut {
|
const IsValidShortcut isValidShortcut {
|
||||||
MWBase::Environment::get().getWorld()->getNavigator(),
|
MWBase::Environment::get().getWorld()->getNavigator(),
|
||||||
halfExtents, flags
|
agentBounds, flags
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shortenIfAlmostStraight)
|
if (shortenIfAlmostStraight)
|
||||||
|
@ -375,13 +375,13 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathFinder::buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
|
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)
|
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType)
|
||||||
{
|
{
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
|
|
||||||
// If it's not possible to build path over navmesh due to disabled navmesh generation fallback to straight path
|
// 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));
|
areaCosts, endTolerance, pathType, std::back_inserter(mPath));
|
||||||
|
|
||||||
if (status != DetourNavigator::Status::Success)
|
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,
|
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,
|
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
||||||
PathType pathType)
|
PathType pathType)
|
||||||
{
|
{
|
||||||
|
@ -405,7 +405,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (!actor.getClass().isPureWaterCreature(actor) && !actor.getClass().isPureFlyingCreature(actor))
|
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));
|
endTolerance, pathType, std::back_inserter(mPath));
|
||||||
if (status != DetourNavigator::Status::Success)
|
if (status != DetourNavigator::Status::Success)
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
|
@ -413,7 +413,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (status != DetourNavigator::Status::NavMeshNotFound && mPath.empty() && (flags & DetourNavigator::Flag_usePathgrid) == 0)
|
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));
|
flags | DetourNavigator::Flag_usePathgrid, areaCosts, endTolerance, pathType, std::back_inserter(mPath));
|
||||||
if (status != DetourNavigator::Status::Success)
|
if (status != DetourNavigator::Status::Success)
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
|
@ -429,14 +429,14 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
DetourNavigator::Status PathFinder::buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
|
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,
|
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType,
|
||||||
std::back_insert_iterator<std::deque<osg::Vec3f>> out)
|
std::back_insert_iterator<std::deque<osg::Vec3f>> out)
|
||||||
{
|
{
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
const auto world = MWBase::Environment::get().getWorld();
|
||||||
const auto stepSize = getPathStepSize(actor);
|
const auto stepSize = getPathStepSize(actor);
|
||||||
const auto navigator = world->getNavigator();
|
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);
|
startPoint, endPoint, flags, areaCosts, endTolerance, out);
|
||||||
|
|
||||||
if (pathType == PathType::Partial && status == DetourNavigator::Status::PartialPath)
|
if (pathType == PathType::Partial && status == DetourNavigator::Status::PartialPath)
|
||||||
|
@ -453,8 +453,9 @@ namespace MWMechanics
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents,
|
void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor,
|
||||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts)
|
const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags,
|
||||||
|
const DetourNavigator::AreaCosts& areaCosts)
|
||||||
{
|
{
|
||||||
if (mPath.empty())
|
if (mPath.empty())
|
||||||
return;
|
return;
|
||||||
|
@ -469,7 +470,7 @@ namespace MWMechanics
|
||||||
std::deque<osg::Vec3f> prePath;
|
std::deque<osg::Vec3f> prePath;
|
||||||
auto prePathInserter = std::back_inserter(prePath);
|
auto prePathInserter = std::back_inserter(prePath);
|
||||||
const float endTolerance = 0;
|
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);
|
startPoint, mPath.front(), flags, areaCosts, endTolerance, prePathInserter);
|
||||||
|
|
||||||
if (status == DetourNavigator::Status::NavMeshNotFound)
|
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,
|
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 MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph,
|
||||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags,
|
||||||
PathType pathType)
|
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType)
|
||||||
{
|
{
|
||||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||||
const auto maxDistance = std::min(
|
const auto maxDistance = std::min(
|
||||||
|
@ -506,9 +507,9 @@ namespace MWMechanics
|
||||||
const auto startToEnd = endPoint - startPoint;
|
const auto startToEnd = endPoint - startPoint;
|
||||||
const auto distance = startToEnd.length();
|
const auto distance = startToEnd.length();
|
||||||
if (distance <= maxDistance)
|
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);
|
endTolerance, pathType);
|
||||||
const auto end = startPoint + startToEnd * maxDistance / distance;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,11 @@ namespace MWWorld
|
||||||
class Ptr;
|
class Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace DetourNavigator
|
||||||
|
{
|
||||||
|
struct AgentBounds;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
class PathgridGraph;
|
class PathgridGraph;
|
||||||
|
@ -98,25 +103,26 @@ namespace MWMechanics
|
||||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
|
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
|
||||||
|
|
||||||
void buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
|
void 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::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 DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
||||||
PathType pathType);
|
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);
|
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts);
|
||||||
|
|
||||||
void buildLimitedPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
|
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,
|
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
||||||
PathType pathType);
|
PathType pathType);
|
||||||
|
|
||||||
/// Remove front point if exist and within tolerance
|
/// Remove front point if exist and within tolerance
|
||||||
void update(const osg::Vec3f& position, float pointTolerance, float destinationTolerance,
|
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);
|
const DetourNavigator::Flags flags);
|
||||||
|
|
||||||
bool checkPathCompleted() const
|
bool checkPathCompleted() const
|
||||||
|
@ -219,7 +225,7 @@ namespace MWMechanics
|
||||||
const PathgridGraph& pathgridGraph, std::back_insert_iterator<std::deque<osg::Vec3f>> out);
|
const PathgridGraph& pathgridGraph, std::back_insert_iterator<std::deque<osg::Vec3f>> out);
|
||||||
|
|
||||||
[[nodiscard]] DetourNavigator::Status buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor,
|
[[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,
|
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType,
|
||||||
std::back_insert_iterator<std::deque<osg::Vec3f>> out);
|
std::back_insert_iterator<std::deque<osg::Vec3f>> out);
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,7 +57,18 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
|
||||||
}
|
}
|
||||||
|
|
||||||
mShape = std::make_unique<btBoxShape>(Misc::Convert::toBullet(mOriginalHalfExtents));
|
mShape = std::make_unique<btBoxShape>(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<btConvexShape*>(mShape.get());
|
mConvexShape = static_cast<btConvexShape*>(mShape.get());
|
||||||
mConvexShape->setMargin(0.001); // make sure bullet isn't using the huge default convex shape margin of 0.04
|
mConvexShape->setMargin(0.001); // make sure bullet isn't using the huge default convex shape margin of 0.04
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include "ptrholder.hpp"
|
#include "ptrholder.hpp"
|
||||||
|
|
||||||
|
#include <components/detournavigator/collisionshapetype.hpp>
|
||||||
|
|
||||||
#include <LinearMath/btTransform.h>
|
#include <LinearMath/btTransform.h>
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
#include <osg/Quat>
|
#include <osg/Quat>
|
||||||
|
@ -156,6 +158,8 @@ namespace MWPhysics
|
||||||
|
|
||||||
void setActive(bool value) { mActive = value; }
|
void setActive(bool value) { mActive = value; }
|
||||||
|
|
||||||
|
DetourNavigator::CollisionShapeType getCollisionShapeType() const { return mCollisionShapeType; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MWWorld::Ptr mStandingOnPtr;
|
MWWorld::Ptr mStandingOnPtr;
|
||||||
/// Removes then re-adds the collision object to the dynamics world
|
/// Removes then re-adds the collision object to the dynamics world
|
||||||
|
@ -171,6 +175,8 @@ namespace MWPhysics
|
||||||
|
|
||||||
bool mRotationallyInvariant;
|
bool mRotationallyInvariant;
|
||||||
|
|
||||||
|
DetourNavigator::CollisionShapeType mCollisionShapeType;
|
||||||
|
|
||||||
std::unique_ptr<btCollisionShape> mShape;
|
std::unique_ptr<btCollisionShape> mShape;
|
||||||
btConvexShape* mConvexShape;
|
btConvexShape* mConvexShape;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActorsPaths::update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
void ActorsPaths::update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& 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)
|
const DetourNavigator::Settings& settings)
|
||||||
{
|
{
|
||||||
if (!mEnabled)
|
if (!mEnabled)
|
||||||
|
@ -48,7 +48,7 @@ namespace MWRender
|
||||||
if (group != mGroups.end())
|
if (group != mGroups.end())
|
||||||
mRootNode->removeChild(group->second.mNode);
|
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)
|
if (newGroup)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug");
|
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug");
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace osg
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct Settings;
|
struct Settings;
|
||||||
|
struct AgentBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -30,7 +31,7 @@ namespace MWRender
|
||||||
bool toggle();
|
bool toggle();
|
||||||
|
|
||||||
void update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
void update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& 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);
|
const DetourNavigator::Settings& settings);
|
||||||
|
|
||||||
void remove(const MWWorld::ConstPtr& actor);
|
void remove(const MWWorld::ConstPtr& actor);
|
||||||
|
|
|
@ -1518,9 +1518,9 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
void RenderingManager::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& 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
|
void RenderingManager::removeActorPath(const MWWorld::ConstPtr& actor) const
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct Navigator;
|
struct Navigator;
|
||||||
struct Settings;
|
struct Settings;
|
||||||
|
struct AgentBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -236,7 +237,7 @@ namespace MWRender
|
||||||
bool toggleBorders();
|
bool toggleBorders();
|
||||||
|
|
||||||
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& 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;
|
void removeActorPath(const MWWorld::ConstPtr& actor) const;
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ namespace
|
||||||
}
|
}
|
||||||
else if (physics.getActor(ptr))
|
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))
|
else if (mPhysics->getActor(ptr))
|
||||||
{
|
{
|
||||||
mNavigator.removeAgent(mWorld.getPathfindingHalfExtents(ptr));
|
mNavigator.removeAgent(mWorld.getPathfindingAgentBounds(ptr));
|
||||||
mRendering.removeActorPath(ptr);
|
mRendering.removeActorPath(ptr);
|
||||||
mPhysics->remove(ptr);
|
mPhysics->remove(ptr);
|
||||||
}
|
}
|
||||||
|
@ -940,7 +940,7 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
else if (mPhysics->getActor(ptr))
|
else if (mPhysics->getActor(ptr))
|
||||||
{
|
{
|
||||||
mNavigator.removeAgent(mWorld.getPathfindingHalfExtents(ptr));
|
mNavigator.removeAgent(mWorld.getPathfindingAgentBounds(ptr));
|
||||||
}
|
}
|
||||||
mPhysics->remove(ptr);
|
mPhysics->remove(ptr);
|
||||||
mRendering.removeObject (ptr);
|
mRendering.removeObject (ptr);
|
||||||
|
|
|
@ -1275,7 +1275,7 @@ namespace MWWorld
|
||||||
if (!force && scale == ptr.getCellRef().getScale())
|
if (!force && scale == ptr.getCellRef().getScale())
|
||||||
return;
|
return;
|
||||||
if (mPhysics->getActor(ptr))
|
if (mPhysics->getActor(ptr))
|
||||||
mNavigator->removeAgent(getPathfindingHalfExtents(ptr));
|
mNavigator->removeAgent(getPathfindingAgentBounds(ptr));
|
||||||
|
|
||||||
ptr.getCellRef().setScale(scale);
|
ptr.getCellRef().setScale(scale);
|
||||||
mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr);
|
mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr);
|
||||||
|
@ -1285,7 +1285,7 @@ namespace MWWorld
|
||||||
mWorldScene->updateObjectScale(ptr);
|
mWorldScene->updateObjectScale(ptr);
|
||||||
|
|
||||||
if (mPhysics->getActor(ptr))
|
if (mPhysics->getActor(ptr))
|
||||||
mNavigator->addAgent(getPathfindingHalfExtents(ptr));
|
mNavigator->addAgent(getPathfindingAgentBounds(ptr));
|
||||||
else if (const auto object = mPhysics->getObject(ptr))
|
else if (const auto object = mPhysics->getObject(ptr))
|
||||||
updateNavigatorObject(*object);
|
updateNavigatorObject(*object);
|
||||||
}
|
}
|
||||||
|
@ -2416,7 +2416,7 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
// Remove the old CharacterController
|
// Remove the old CharacterController
|
||||||
MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr(), true);
|
MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr(), true);
|
||||||
mNavigator->removeAgent(getPathfindingHalfExtents(getPlayerConstPtr()));
|
mNavigator->removeAgent(getPathfindingAgentBounds(getPlayerConstPtr()));
|
||||||
mPhysics->remove(getPlayerPtr());
|
mPhysics->remove(getPlayerPtr());
|
||||||
mRendering->removePlayer(getPlayerPtr());
|
mRendering->removePlayer(getPlayerPtr());
|
||||||
MWBase::Environment::get().getLuaManager()->objectRemovedFromScene(getPlayerPtr());
|
MWBase::Environment::get().getLuaManager()->objectRemovedFromScene(getPlayerPtr());
|
||||||
|
@ -2453,7 +2453,7 @@ namespace MWWorld
|
||||||
|
|
||||||
applyLoopingParticles(player);
|
applyLoopingParticles(player);
|
||||||
|
|
||||||
mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr()));
|
mNavigator->addAgent(getPathfindingAgentBounds(getPlayerConstPtr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
World::RestPermitted World::canRest () const
|
World::RestPermitted World::canRest () const
|
||||||
|
@ -3898,9 +3898,9 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
void World::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& 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
|
void World::removeActorPath(const MWWorld::ConstPtr& actor) const
|
||||||
|
@ -3913,12 +3913,13 @@ namespace MWWorld
|
||||||
mRendering->setNavMeshNumber(value);
|
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())
|
const MWPhysics::Actor* physicsActor = mPhysics->getActor(actor);
|
||||||
return mDefaultHalfExtents; // Using default half extents for better performance
|
if (physicsActor == nullptr || (actor.isInCell() && actor.getCell()->isExterior()))
|
||||||
|
return DetourNavigator::AgentBounds {DetourNavigator::defaultCollisionShapeType, mDefaultHalfExtents};
|
||||||
else
|
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
|
bool World::hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const
|
||||||
|
|
|
@ -727,14 +727,13 @@ namespace MWWorld
|
||||||
DetourNavigator::Navigator* getNavigator() const override;
|
DetourNavigator::Navigator* getNavigator() const override;
|
||||||
|
|
||||||
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& 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 removeActorPath(const MWWorld::ConstPtr& actor) const override;
|
||||||
|
|
||||||
void setNavMeshNumberToRender(const std::size_t value) override;
|
void setNavMeshNumberToRender(const std::size_t value) override;
|
||||||
|
|
||||||
/// Return physical half extents of the given actor to be used in pathfinding
|
DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const override;
|
||||||
osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override;
|
|
||||||
|
|
||||||
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
|
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace
|
||||||
Settings mSettings = makeSettings();
|
Settings mSettings = makeSettings();
|
||||||
TileCachedRecastMeshManager mRecastMeshManager {mSettings.mRecast};
|
TileCachedRecastMeshManager mRecastMeshManager {mSettings.mRecast};
|
||||||
OffMeshConnectionsManager mOffMeshConnectionsManager {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 TilePosition mPlayerTile {0, 0};
|
||||||
const std::string mWorldspace = "sys::default";
|
const std::string mWorldspace = "sys::default";
|
||||||
const btBoxShape mBox {btVector3(100, 100, 20)};
|
const btBoxShape mBox {btVector3(100, 100, 20)};
|
||||||
|
@ -76,7 +76,7 @@ namespace
|
||||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::add}};
|
const std::map<TilePosition, ChangeType> 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);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
EXPECT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
EXPECT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
||||||
}
|
}
|
||||||
|
@ -88,14 +88,14 @@ namespace
|
||||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::add}};
|
const std::map<TilePosition, ChangeType> 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);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
{
|
{
|
||||||
const auto stats = updater.getStats();
|
const auto stats = updater.getStats();
|
||||||
ASSERT_EQ(stats.mCache.mGetCount, 1);
|
ASSERT_EQ(stats.mCache.mGetCount, 1);
|
||||||
ASSERT_EQ(stats.mCache.mHitCount, 0);
|
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);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
{
|
{
|
||||||
const auto stats = updater.getStats();
|
const auto stats = updater.getStats();
|
||||||
|
@ -111,14 +111,14 @@ namespace
|
||||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::update}};
|
const std::map<TilePosition, ChangeType> 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);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
{
|
{
|
||||||
const auto stats = updater.getStats();
|
const auto stats = updater.getStats();
|
||||||
ASSERT_EQ(stats.mCache.mGetCount, 1);
|
ASSERT_EQ(stats.mCache.mGetCount, 1);
|
||||||
ASSERT_EQ(stats.mCache.mHitCount, 0);
|
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);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
{
|
{
|
||||||
const auto stats = updater.getStats();
|
const auto stats = updater.getStats();
|
||||||
|
@ -138,7 +138,7 @@ namespace
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const TilePosition tilePosition {0, 0};
|
const TilePosition tilePosition {0, 0};
|
||||||
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
||||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
updater.stop();
|
updater.stop();
|
||||||
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
||||||
|
@ -146,10 +146,11 @@ namespace
|
||||||
ShapeId nextShapeId {1};
|
ShapeId nextShapeId {1};
|
||||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||||
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v, nextShapeId); });
|
[&] (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());
|
ASSERT_TRUE(tile.has_value());
|
||||||
EXPECT_EQ(tile->mTileId, 1);
|
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)
|
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write_tiles)
|
||||||
|
@ -164,7 +165,7 @@ namespace
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const TilePosition tilePosition {0, 0};
|
const TilePosition tilePosition {0, 0};
|
||||||
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
||||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
updater.stop();
|
updater.stop();
|
||||||
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
||||||
|
@ -172,7 +173,8 @@ namespace
|
||||||
ShapeId nextShapeId {1};
|
ShapeId nextShapeId {1};
|
||||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||||
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v, nextShapeId); });
|
[&] (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());
|
ASSERT_FALSE(tile.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +190,7 @@ namespace
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const TilePosition tilePosition {0, 0};
|
const TilePosition tilePosition {0, 0};
|
||||||
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
||||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
updater.stop();
|
updater.stop();
|
||||||
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
||||||
|
@ -207,7 +209,7 @@ namespace
|
||||||
std::make_unique<NavMeshDb>(":memory:", std::numeric_limits<std::uint64_t>::max()));
|
std::make_unique<NavMeshDb>(":memory:", std::numeric_limits<std::uint64_t>::max()));
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::add}};
|
const std::map<TilePosition, ChangeType> 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);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
{
|
{
|
||||||
const auto stats = updater.getStats();
|
const auto stats = updater.getStats();
|
||||||
|
@ -217,7 +219,7 @@ namespace
|
||||||
ASSERT_EQ(stats.mDb->mGetTileCount, 1);
|
ASSERT_EQ(stats.mDb->mGetTileCount, 1);
|
||||||
ASSERT_EQ(stats.mDbGetTileHits, 0);
|
ASSERT_EQ(stats.mDbGetTileHits, 0);
|
||||||
}
|
}
|
||||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
{
|
{
|
||||||
const auto stats = updater.getStats();
|
const auto stats = updater.getStats();
|
||||||
|
@ -236,12 +238,12 @@ namespace
|
||||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||||
const std::map<TilePosition, ChangeType> changedTilesAdd {{TilePosition {0, 0}, ChangeType::add}};
|
const std::map<TilePosition, ChangeType> 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);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
ASSERT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
ASSERT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
||||||
const std::map<TilePosition, ChangeType> changedTilesRemove {{TilePosition {0, 0}, ChangeType::remove}};
|
const std::map<TilePosition, ChangeType> changedTilesRemove {{TilePosition {0, 0}, ChangeType::remove}};
|
||||||
const TilePosition playerTile(100, 100);
|
const TilePosition playerTile(100, 100);
|
||||||
updater.post(mAgentHalfExtents, navMeshCacheItem, playerTile, mWorldspace, changedTilesRemove);
|
updater.post(mAgentBounds, navMeshCacheItem, playerTile, mWorldspace, changedTilesRemove);
|
||||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
EXPECT_EQ(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
EXPECT_EQ(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +263,7 @@ namespace
|
||||||
for (int x = -5; x <= 5; ++x)
|
for (int x = -5; x <= 5; ++x)
|
||||||
for (int y = -5; y <= 5; ++y)
|
for (int y = -5; y <= 5; ++y)
|
||||||
changedTiles.emplace(TilePosition {x, y}, ChangeType::add);
|
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.wait(mListener, WaitConditionType::allJobsDone);
|
||||||
updater.stop();
|
updater.stop();
|
||||||
const std::set<TilePosition> present {
|
const std::set<TilePosition> present {
|
||||||
|
@ -276,7 +278,6 @@ namespace
|
||||||
TilePosition(0, 2),
|
TilePosition(0, 2),
|
||||||
TilePosition(1, -1),
|
TilePosition(1, -1),
|
||||||
TilePosition(1, 0),
|
TilePosition(1, 0),
|
||||||
TilePosition(1, 1),
|
|
||||||
};
|
};
|
||||||
for (int x = -5; x <= 5; ++x)
|
for (int x = -5; x <= 5; ++x)
|
||||||
for (int y = -5; y <= 5; ++y)
|
for (int y = -5; y <= 5; ++y)
|
||||||
|
@ -288,7 +289,8 @@ namespace
|
||||||
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v); });
|
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v); });
|
||||||
if (!objects.has_value())
|
if (!objects.has_value())
|
||||||
continue;
|
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())
|
present.find(tilePosition) != present.end())
|
||||||
<< tilePosition.x() << " " << tilePosition.y() << " present=" << (present.find(tilePosition) != present.end());
|
<< tilePosition.x() << " " << tilePosition.y() << " present=" << (present.find(tilePosition) != present.end());
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace
|
||||||
std::unique_ptr<Navigator> mNavigator;
|
std::unique_ptr<Navigator> mNavigator;
|
||||||
const osg::Vec3f mPlayerPosition;
|
const osg::Vec3f mPlayerPosition;
|
||||||
const std::string mWorldspace;
|
const std::string mWorldspace;
|
||||||
const osg::Vec3f mAgentHalfExtents;
|
const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {29, 29, 66}};
|
||||||
osg::Vec3f mStart;
|
osg::Vec3f mStart;
|
||||||
osg::Vec3f mEnd;
|
osg::Vec3f mEnd;
|
||||||
std::deque<osg::Vec3f> mPath;
|
std::deque<osg::Vec3f> mPath;
|
||||||
|
@ -59,7 +59,6 @@ namespace
|
||||||
DetourNavigatorNavigatorTest()
|
DetourNavigatorNavigatorTest()
|
||||||
: mPlayerPosition(256, 256, 0)
|
: mPlayerPosition(256, 256, 0)
|
||||||
, mWorldspace("sys::default")
|
, mWorldspace("sys::default")
|
||||||
, mAgentHalfExtents(29, 29, 66)
|
|
||||||
, mStart(52, 460, 1)
|
, mStart(52, 460, 1)
|
||||||
, mEnd(460, 52, 1)
|
, mEnd(460, 52, 1)
|
||||||
, mOut(mPath)
|
, mOut(mPath)
|
||||||
|
@ -122,24 +121,24 @@ namespace
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty)
|
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);
|
Status::NavMeshNotFound);
|
||||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>());
|
EXPECT_EQ(mPath, std::deque<osg::Vec3f>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception)
|
TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception)
|
||||||
{
|
{
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
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::StartPolygonNotFound);
|
Status::StartPolygonNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent)
|
TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent)
|
||||||
{
|
{
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->removeAgent(mAgentHalfExtents);
|
mNavigator->removeAgent(mAgentBounds);
|
||||||
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::StartPolygonNotFound);
|
Status::StartPolygonNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,12 +154,12 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -204,12 +203,12 @@ namespace
|
||||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
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->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -243,7 +242,7 @@ namespace
|
||||||
|
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
mOut = std::back_inserter(mPath);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -288,13 +287,13 @@ namespace
|
||||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
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->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -331,7 +330,7 @@ namespace
|
||||||
|
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
mOut = std::back_inserter(mPath);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -382,13 +381,13 @@ namespace
|
||||||
CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2));
|
CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2));
|
||||||
heightfield2.shape().setLocalScaling(btVector3(128, 128, 1));
|
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(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform), mTransform);
|
||||||
mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform), mTransform);
|
mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform), mTransform);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -439,7 +438,7 @@ namespace
|
||||||
const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2);
|
const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2);
|
||||||
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, surface1));
|
EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, surface1));
|
||||||
EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, surface2));
|
EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, surface2));
|
||||||
}
|
}
|
||||||
|
@ -472,12 +471,12 @@ namespace
|
||||||
|
|
||||||
osg::ref_ptr<const Resource::BulletShapeInstance> instance(new Resource::BulletShapeInstance(bulletShape));
|
osg::ref_ptr<const Resource::BulletShapeInstance> instance(new Resource::BulletShapeInstance(bulletShape));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addObject(ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform);
|
mNavigator->addObject(ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -519,7 +518,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addWater(mCellPosition, cellSize, 300);
|
mNavigator->addWater(mCellPosition, cellSize, 300);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
|
@ -530,7 +529,7 @@ namespace
|
||||||
mEnd.x() = 256;
|
mEnd.x() = 256;
|
||||||
mEnd.z() = 300;
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -567,7 +566,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addWater(mCellPosition, cellSize, -25);
|
mNavigator->addWater(mCellPosition, cellSize, -25);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
|
@ -576,7 +575,7 @@ namespace
|
||||||
mStart.x() = 256;
|
mStart.x() = 256;
|
||||||
mEnd.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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -613,7 +612,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->addWater(mCellPosition, std::numeric_limits<int>::max(), -25);
|
mNavigator->addWater(mCellPosition, std::numeric_limits<int>::max(), -25);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
|
@ -622,7 +621,7 @@ namespace
|
||||||
mStart.x() = 256;
|
mStart.x() = 256;
|
||||||
mEnd.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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -659,7 +658,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addWater(mCellPosition, cellSize, -25);
|
mNavigator->addWater(mCellPosition, cellSize, -25);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
|
@ -668,7 +667,7 @@ namespace
|
||||||
mStart.x() = 256;
|
mStart.x() = 256;
|
||||||
mEnd.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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -703,7 +702,7 @@ namespace
|
||||||
CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData));
|
CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData));
|
||||||
heightfield.shape().setLocalScaling(btVector3(128, 128, 1));
|
heightfield.shape().setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform);
|
mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||||
|
@ -716,7 +715,7 @@ namespace
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -757,7 +756,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||||
|
@ -770,7 +769,7 @@ namespace
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -812,14 +811,14 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||||
|
|
||||||
Misc::Rng::init(42);
|
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(); });
|
[]() { return Misc::Rng::rollClosedProbability(); });
|
||||||
|
|
||||||
ASSERT_THAT(result, Optional(Vec3fEq(70.35845947265625, 335.592041015625, -2.6667339801788330078125)))
|
ASSERT_THAT(result, Optional(Vec3fEq(70.35845947265625, 335.592041015625, -2.6667339801788330078125)))
|
||||||
|
@ -849,7 +848,7 @@ namespace
|
||||||
std::vector<CollisionShapeInstance<btBoxShape>> boxes;
|
std::vector<CollisionShapeInstance<btBoxShape>> boxes;
|
||||||
std::generate_n(std::back_inserter(boxes), 100, [] { return std::make_unique<btBoxShape>(btVector3(20, 20, 100)); });
|
std::generate_n(std::back_inserter(boxes), 100, [] { return std::make_unique<btBoxShape>(btVector3(20, 20, 100)); });
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
|
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
|
|
||||||
|
@ -870,7 +869,7 @@ namespace
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -905,7 +904,7 @@ namespace
|
||||||
std::vector<CollisionShapeInstance<btBoxShape>> shapes;
|
std::vector<CollisionShapeInstance<btBoxShape>> shapes;
|
||||||
std::generate_n(std::back_inserter(shapes), 100, [] { return std::make_unique<btBoxShape>(btVector3(64, 64, 64)); });
|
std::generate_n(std::back_inserter(shapes), 100, [] { return std::make_unique<btBoxShape>(btVector3(64, 64, 64)); });
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
|
|
||||||
for (std::size_t i = 0; i < shapes.size(); ++i)
|
for (std::size_t i = 0; i < shapes.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -950,14 +949,14 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||||
|
|
||||||
const osg::Vec3f start(57, 460, 1);
|
const osg::Vec3f start(57, 460, 1);
|
||||||
const osg::Vec3f end(460, 57, 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)))
|
ASSERT_THAT(result, Optional(Vec3fEq(end.x(), end.y(), 1.95257937908172607421875)))
|
||||||
<< (result ? *result : osg::Vec3f());
|
<< (result ? *result : osg::Vec3f());
|
||||||
|
@ -979,7 +978,7 @@ namespace
|
||||||
const btVector3 oscillatingBoxShapePosition(288, 288, 400);
|
const btVector3 oscillatingBoxShapePosition(288, 288, 400);
|
||||||
CollisionShapeInstance borderBox(std::make_unique<btBoxShape>(btVector3(50, 50, 50)));
|
CollisionShapeInstance borderBox(std::make_unique<btBoxShape>(btVector3(50, 50, 50)));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform),
|
mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform),
|
||||||
btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition));
|
btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition));
|
||||||
|
@ -1013,12 +1012,12 @@ namespace
|
||||||
const HeightfieldPlane plane {100};
|
const HeightfieldPlane plane {100};
|
||||||
const int cellSize = mHeightfieldTileSize * 4;
|
const int cellSize = mHeightfieldTileSize * 4;
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, plane);
|
mNavigator->addHeightfield(mCellPosition, cellSize, plane);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent);
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -1063,13 +1062,13 @@ namespace
|
||||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||||
new btBoxShape(btVector3(200, 200, 1000)));
|
new btBoxShape(btVector3(200, 200, 1000)));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
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);
|
Status::PartialPath);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -1102,7 +1101,7 @@ namespace
|
||||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||||
new btBoxShape(btVector3(100, 100, 1000)));
|
new btBoxShape(btVector3(100, 100, 1000)));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
||||||
mNavigator->update(mPlayerPosition);
|
mNavigator->update(mPlayerPosition);
|
||||||
|
@ -1110,7 +1109,7 @@ namespace
|
||||||
|
|
||||||
const float endTolerance = 1000.0f;
|
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);
|
Status::Success);
|
||||||
|
|
||||||
EXPECT_THAT(mPath, ElementsAre(
|
EXPECT_THAT(mPath, ElementsAre(
|
||||||
|
@ -1142,7 +1141,7 @@ namespace
|
||||||
const int cellSize2 = 200;
|
const int cellSize2 = 200;
|
||||||
const float level2 = 2;
|
const float level2 = 2;
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentHalfExtents);
|
mNavigator->addAgent(mAgentBounds);
|
||||||
EXPECT_TRUE(mNavigator->addWater(mCellPosition, cellSize1, level1));
|
EXPECT_TRUE(mNavigator->addWater(mCellPosition, cellSize1, level1));
|
||||||
EXPECT_FALSE(mNavigator->addWater(mCellPosition, cellSize2, level2));
|
EXPECT_FALSE(mNavigator->addWater(mCellPosition, cellSize2, level2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ namespace
|
||||||
|
|
||||||
struct DetourNavigatorNavMeshTilesCacheTest : Test
|
struct DetourNavigatorNavMeshTilesCacheTest : Test
|
||||||
{
|
{
|
||||||
const osg::Vec3f mAgentHalfExtents {1, 2, 3};
|
const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {1, 2, 3}};
|
||||||
const TilePosition mTilePosition {0, 0};
|
const TilePosition mTilePosition {0, 0};
|
||||||
const std::size_t mGeneration = 0;
|
const std::size_t mGeneration = 0;
|
||||||
const std::size_t mRevision = 0;
|
const std::size_t mRevision = 0;
|
||||||
|
@ -117,7 +117,7 @@ namespace
|
||||||
const std::size_t maxSize = 0;
|
const std::size_t maxSize = 0;
|
||||||
NavMeshTilesCache cache(maxSize);
|
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)
|
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_for_not_enought_cache_size_should_return_empty_value)
|
||||||
|
@ -125,7 +125,7 @@ namespace
|
||||||
const std::size_t maxSize = 0;
|
const std::size_t maxSize = 0;
|
||||||
NavMeshTilesCache cache(maxSize);
|
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);
|
EXPECT_NE(mPreparedNavMeshData, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ namespace
|
||||||
const auto copy = clone(*mPreparedNavMeshData);
|
const auto copy = clone(*mPreparedNavMeshData);
|
||||||
ASSERT_EQ(*mPreparedNavMeshData, *copy);
|
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);
|
ASSERT_TRUE(result);
|
||||||
EXPECT_EQ(result.get(), *copy);
|
EXPECT_EQ(result.get(), *copy);
|
||||||
}
|
}
|
||||||
|
@ -148,9 +148,9 @@ namespace
|
||||||
auto copy = clone(*mPreparedNavMeshData);
|
auto copy = clone(*mPreparedNavMeshData);
|
||||||
const auto sameCopy = 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);
|
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);
|
ASSERT_TRUE(result);
|
||||||
EXPECT_EQ(result.get(), *sameCopy);
|
EXPECT_EQ(result.get(), *sameCopy);
|
||||||
}
|
}
|
||||||
|
@ -161,8 +161,8 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
const auto copy = clone(*mPreparedNavMeshData);
|
const auto copy = clone(*mPreparedNavMeshData);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
const auto result = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
const auto result = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||||
ASSERT_TRUE(result);
|
ASSERT_TRUE(result);
|
||||||
EXPECT_EQ(result.get(), *copy);
|
EXPECT_EQ(result.get(), *copy);
|
||||||
}
|
}
|
||||||
|
@ -171,10 +171,10 @@ namespace
|
||||||
{
|
{
|
||||||
const std::size_t maxSize = 1;
|
const std::size_t maxSize = 1;
|
||||||
NavMeshTilesCache cache(maxSize);
|
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));
|
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
EXPECT_FALSE(cache.get(unexsistentAgentHalfExtents, mTilePosition, mRecastMesh));
|
EXPECT_FALSE(cache.get(absentAgentBounds, mTilePosition, mRecastMesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_tile_position_should_return_empty_value)
|
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_tile_position_should_return_empty_value)
|
||||||
|
@ -183,8 +183,8 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
const TilePosition unexistentTilePosition {1, 1};
|
const TilePosition unexistentTilePosition {1, 1};
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, unexistentTilePosition, mRecastMesh));
|
EXPECT_FALSE(cache.get(mAgentBounds, unexistentTilePosition, mRecastMesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_recast_mesh_should_return_empty_value)
|
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_recast_mesh_should_return_empty_value)
|
||||||
|
@ -194,8 +194,8 @@ namespace
|
||||||
const std::vector<CellWater> water(1, CellWater {osg::Vec2i(), Water {1, 0.0f}});
|
const std::vector<CellWater> water(1, CellWater {osg::Vec2i(), Water {1, 0.0f}});
|
||||||
const RecastMesh unexistentRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
const RecastMesh unexistentRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh));
|
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, unexistentRecastMesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_value)
|
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_value)
|
||||||
|
@ -208,12 +208,12 @@ namespace
|
||||||
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
||||||
const auto copy = clone(*anotherPreparedNavMeshData);
|
const auto copy = clone(*anotherPreparedNavMeshData);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh,
|
const auto result = cache.set(mAgentBounds, mTilePosition, anotherRecastMesh,
|
||||||
std::move(anotherPreparedNavMeshData));
|
std::move(anotherPreparedNavMeshData));
|
||||||
ASSERT_TRUE(result);
|
ASSERT_TRUE(result);
|
||||||
EXPECT_EQ(result.get(), *copy);
|
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)
|
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_used_value)
|
||||||
|
@ -225,9 +225,9 @@ namespace
|
||||||
const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||||
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
const auto value = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||||
std::move(mPreparedNavMeshData));
|
std::move(mPreparedNavMeshData));
|
||||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh,
|
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh,
|
||||||
std::move(anotherPreparedNavMeshData)));
|
std::move(anotherPreparedNavMeshData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,17 +247,17 @@ namespace
|
||||||
mHeightfields, mFlatHeightfields, mSources);
|
mHeightfields, mFlatHeightfields, mSources);
|
||||||
auto mostRecentlySetData = makePeparedNavMeshData(3);
|
auto mostRecentlySetData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh,
|
ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, leastRecentlySetRecastMesh,
|
||||||
std::move(leastRecentlySetData)));
|
std::move(leastRecentlySetData)));
|
||||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh,
|
ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, mostRecentlySetRecastMesh,
|
||||||
std::move(mostRecentlySetData)));
|
std::move(mostRecentlySetData)));
|
||||||
|
|
||||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||||
std::move(mPreparedNavMeshData));
|
std::move(mPreparedNavMeshData));
|
||||||
EXPECT_EQ(result.get(), *copy);
|
EXPECT_EQ(result.get(), *copy);
|
||||||
|
|
||||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh));
|
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, leastRecentlySetRecastMesh));
|
||||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh));
|
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mostRecentlySetRecastMesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_used_value)
|
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_used_value)
|
||||||
|
@ -277,28 +277,28 @@ namespace
|
||||||
auto mostRecentlyUsedData = makePeparedNavMeshData(3);
|
auto mostRecentlyUsedData = makePeparedNavMeshData(3);
|
||||||
const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData);
|
const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh, std::move(leastRecentlyUsedData));
|
cache.set(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh, std::move(leastRecentlyUsedData));
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh, std::move(mostRecentlyUsedData));
|
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_TRUE(value);
|
||||||
ASSERT_EQ(value.get(), *leastRecentlyUsedCopy);
|
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_TRUE(value);
|
||||||
ASSERT_EQ(value.get(), *mostRecentlyUsedCopy);
|
ASSERT_EQ(value.get(), *mostRecentlyUsedCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto copy = clone(*mPreparedNavMeshData);
|
const auto copy = clone(*mPreparedNavMeshData);
|
||||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||||
std::move(mPreparedNavMeshData));
|
std::move(mPreparedNavMeshData));
|
||||||
EXPECT_EQ(result.get(), *copy);
|
EXPECT_EQ(result.get(), *copy);
|
||||||
|
|
||||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh));
|
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh));
|
||||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh));
|
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)
|
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);
|
mHeightfields, mFlatHeightfields, mSources);
|
||||||
auto tooLargeData = makePeparedNavMeshData(10);
|
auto tooLargeData = makePeparedNavMeshData(10);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh, std::move(tooLargeData)));
|
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, tooLargeRecastMesh, std::move(tooLargeData)));
|
||||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
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)
|
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);
|
mHeightfields, mFlatHeightfields, mSources);
|
||||||
auto tooLargeData = makePeparedNavMeshData(10);
|
auto tooLargeData = makePeparedNavMeshData(10);
|
||||||
|
|
||||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
const auto value = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||||
std::move(mPreparedNavMeshData));
|
std::move(mPreparedNavMeshData));
|
||||||
ASSERT_TRUE(value);
|
ASSERT_TRUE(value);
|
||||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh,
|
ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh,
|
||||||
std::move(anotherData)));
|
std::move(anotherData)));
|
||||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh,
|
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, tooLargeRecastMesh,
|
||||||
std::move(tooLargeData)));
|
std::move(tooLargeData)));
|
||||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, anotherRecastMesh));
|
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, anotherRecastMesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_used_after_set_then_used_by_get_item_should_left_this_item_available)
|
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);
|
const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||||
auto anotherData = makePeparedNavMeshData(3);
|
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);
|
ASSERT_TRUE(firstCopy);
|
||||||
{
|
{
|
||||||
const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
const auto secondCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||||
ASSERT_TRUE(secondCopy);
|
ASSERT_TRUE(secondCopy);
|
||||||
}
|
}
|
||||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
||||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_twice_used_item_should_left_this_item_available)
|
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);
|
const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||||
auto anotherData = makePeparedNavMeshData(3);
|
auto anotherData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
const auto firstCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
const auto firstCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||||
ASSERT_TRUE(firstCopy);
|
ASSERT_TRUE(firstCopy);
|
||||||
{
|
{
|
||||||
const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
const auto secondCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||||
ASSERT_TRUE(secondCopy);
|
ASSERT_TRUE(secondCopy);
|
||||||
}
|
}
|
||||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
||||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
34
components/detournavigator/agentbounds.hpp
Normal file
34
components/detournavigator/agentbounds.hpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_AGENTBOUNDS_H
|
||||||
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_AGENTBOUNDS_H
|
||||||
|
|
||||||
|
#include "collisionshapetype.hpp"
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
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
|
|
@ -32,12 +32,12 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
|
|
||||||
int getMinDistanceTo(const TilePosition& position, int maxDistance,
|
int getMinDistanceTo(const TilePosition& position, int maxDistance,
|
||||||
const std::set<std::tuple<osg::Vec3f, TilePosition>>& pushedTiles,
|
const std::set<std::tuple<AgentBounds, TilePosition>>& pushedTiles,
|
||||||
const std::set<std::tuple<osg::Vec3f, TilePosition>>& presentTiles)
|
const std::set<std::tuple<AgentBounds, TilePosition>>& presentTiles)
|
||||||
{
|
{
|
||||||
int result = maxDistance;
|
int result = maxDistance;
|
||||||
for (const auto& [halfExtents, tile] : pushedTiles)
|
for (const auto& [agentBounds, tile] : pushedTiles)
|
||||||
if (presentTiles.find(std::tie(halfExtents, tile)) == presentTiles.end())
|
if (presentTiles.find(std::tie(agentBounds, tile)) == presentTiles.end())
|
||||||
result = std::min(result, getManhattanDistance(position, tile));
|
result = std::min(result, getManhattanDistance(position, tile));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -84,14 +84,14 @@ namespace DetourNavigator
|
||||||
|
|
||||||
auto getAgentAndTile(const Job& job) noexcept
|
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<DbWorker> makeDbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db, const Settings& settings)
|
std::unique_ptr<DbWorker> makeDbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db, const Settings& settings)
|
||||||
{
|
{
|
||||||
if (db == nullptr)
|
if (db == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return std::make_unique<DbWorker>(updater, std::move(db), TileVersion(settings.mNavMeshVersion),
|
return std::make_unique<DbWorker>(updater, std::move(db), TileVersion(navMeshVersion),
|
||||||
settings.mRecast, settings.mWriteToNavMeshDb);
|
settings.mRecast, settings.mWriteToNavMeshDb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,11 +112,11 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Job::Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
Job::Job(const AgentBounds& agentBounds, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||||
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||||
std::chrono::steady_clock::time_point processTime)
|
std::chrono::steady_clock::time_point processTime)
|
||||||
: mId(getNextJobId())
|
: mId(getNextJobId())
|
||||||
, mAgentHalfExtents(agentHalfExtents)
|
, mAgentBounds(agentBounds)
|
||||||
, mNavMeshCacheItem(std::move(navMeshCacheItem))
|
, mNavMeshCacheItem(std::move(navMeshCacheItem))
|
||||||
, mWorldspace(worldspace)
|
, mWorldspace(worldspace)
|
||||||
, mChangedTile(changedTile)
|
, mChangedTile(changedTile)
|
||||||
|
@ -145,7 +145,7 @@ namespace DetourNavigator
|
||||||
stop();
|
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 TilePosition& playerTile, std::string_view worldspace,
|
||||||
const std::map<TilePosition, ChangeType>& changedTiles)
|
const std::map<TilePosition, ChangeType>& changedTiles)
|
||||||
{
|
{
|
||||||
|
@ -169,16 +169,16 @@ namespace DetourNavigator
|
||||||
|
|
||||||
for (const auto& [changedTile, changeType] : changedTiles)
|
for (const auto& [changedTile, changeType] : changedTiles)
|
||||||
{
|
{
|
||||||
if (mPushed.emplace(agentHalfExtents, changedTile).second)
|
if (mPushed.emplace(agentBounds, changedTile).second)
|
||||||
{
|
{
|
||||||
const auto processTime = changeType == ChangeType::update
|
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();
|
: 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);
|
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 << ")";
|
<< " changedTile=(" << it->mChangedTile << ")";
|
||||||
|
|
||||||
if (playerTileChanged)
|
if (playerTileChanged)
|
||||||
|
@ -342,7 +342,7 @@ namespace DetourNavigator
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case JobStatus::Done:
|
case JobStatus::Done:
|
||||||
unlockTile(job->mAgentHalfExtents, job->mChangedTile);
|
unlockTile(job->mAgentBounds, job->mChangedTile);
|
||||||
if (job->mGeneratedNavMeshData != nullptr)
|
if (job->mGeneratedNavMeshData != nullptr)
|
||||||
mDbWorker->enqueueJob(job);
|
mDbWorker->enqueueJob(job);
|
||||||
else
|
else
|
||||||
|
@ -419,7 +419,7 @@ namespace DetourNavigator
|
||||||
return JobStatus::Done;
|
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> preparedNavMeshData;
|
std::unique_ptr<PreparedNavMeshData> preparedNavMeshData;
|
||||||
const PreparedNavMeshData* preparedNavMeshDataPtr = nullptr;
|
const PreparedNavMeshData* preparedNavMeshDataPtr = nullptr;
|
||||||
|
|
||||||
|
@ -435,7 +435,7 @@ namespace DetourNavigator
|
||||||
return JobStatus::MemoryCacheMiss;
|
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)
|
if (preparedNavMeshData == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -450,7 +450,7 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentHalfExtents, job.mChangedTile,
|
cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentBounds, job.mChangedTile,
|
||||||
*recastMesh, std::move(preparedNavMeshData));
|
*recastMesh, std::move(preparedNavMeshData));
|
||||||
preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get();
|
preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get();
|
||||||
}
|
}
|
||||||
|
@ -459,7 +459,7 @@ namespace DetourNavigator
|
||||||
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
|
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
|
||||||
|
|
||||||
const UpdateNavMeshStatus status = navMeshCacheItem.lock()->updateTile(job.mChangedTile, std::move(cachedNavMeshData),
|
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);
|
return handleUpdateNavMeshStatus(status, job, navMeshCacheItem, *recastMesh);
|
||||||
}
|
}
|
||||||
|
@ -471,7 +471,7 @@ namespace DetourNavigator
|
||||||
std::unique_ptr<PreparedNavMeshData> preparedNavMeshData;
|
std::unique_ptr<PreparedNavMeshData> preparedNavMeshData;
|
||||||
bool generatedNavMeshData = false;
|
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<PreparedNavMeshData>();
|
preparedNavMeshData = std::make_unique<PreparedNavMeshData>();
|
||||||
if (deserialize(job.mCachedTileData->mData, *preparedNavMeshData))
|
if (deserialize(job.mCachedTileData->mData, *preparedNavMeshData))
|
||||||
|
@ -482,7 +482,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
if (preparedNavMeshData == nullptr)
|
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;
|
generatedNavMeshData = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,14 +493,14 @@ namespace DetourNavigator
|
||||||
return JobStatus::Done;
|
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));
|
std::move(preparedNavMeshData));
|
||||||
|
|
||||||
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
|
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
|
||||||
|
|
||||||
const PreparedNavMeshData* preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get();
|
const PreparedNavMeshData* preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get();
|
||||||
const UpdateNavMeshStatus status = navMeshCacheItem.lock()->updateTile(job.mChangedTile, std::move(cachedNavMeshData),
|
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);
|
const JobStatus result = handleUpdateNavMeshStatus(status, job, navMeshCacheItem, *job.mRecastMesh);
|
||||||
|
|
||||||
|
@ -522,12 +522,12 @@ namespace DetourNavigator
|
||||||
if (status == UpdateNavMeshStatus::removed || status == UpdateNavMeshStatus::lost)
|
if (status == UpdateNavMeshStatus::removed || status == UpdateNavMeshStatus::lost)
|
||||||
{
|
{
|
||||||
const std::scoped_lock lock(mMutex);
|
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)
|
else if (isSuccess(status) && status != UpdateNavMeshStatus::ignored)
|
||||||
{
|
{
|
||||||
const std::scoped_lock lock(mMutex);
|
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);
|
writeDebugFiles(job, &recastMesh);
|
||||||
|
@ -564,7 +564,7 @@ namespace DetourNavigator
|
||||||
if (job->mRecastMesh != nullptr)
|
if (job->mRecastMesh != nullptr)
|
||||||
return job;
|
return job;
|
||||||
|
|
||||||
if (!lockTile(job->mAgentHalfExtents, job->mChangedTile))
|
if (!lockTile(job->mAgentBounds, job->mChangedTile))
|
||||||
{
|
{
|
||||||
Log(Debug::Debug) << "Failed to lock tile by " << job->mId;
|
Log(Debug::Debug) << "Failed to lock tile by " << job->mId;
|
||||||
++job->mTryNumber;
|
++job->mTryNumber;
|
||||||
|
@ -604,14 +604,14 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void AsyncNavMeshUpdater::repost(JobIt job)
|
void AsyncNavMeshUpdater::repost(JobIt job)
|
||||||
{
|
{
|
||||||
unlockTile(job->mAgentHalfExtents, job->mChangedTile);
|
unlockTile(job->mAgentBounds, job->mChangedTile);
|
||||||
|
|
||||||
if (mShouldStop || job->mTryNumber > 2)
|
if (mShouldStop || job->mTryNumber > 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::lock_guard<std::mutex> lock(mMutex);
|
const std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
if (mPushed.emplace(job->mAgentHalfExtents, job->mChangedTile).second)
|
if (mPushed.emplace(job->mAgentBounds, job->mChangedTile).second)
|
||||||
{
|
{
|
||||||
++job->mTryNumber;
|
++job->mTryNumber;
|
||||||
insertPrioritizedJob(job, mWaiting);
|
insertPrioritizedJob(job, mWaiting);
|
||||||
|
@ -622,17 +622,17 @@ namespace DetourNavigator
|
||||||
mJobs.erase(job);
|
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 << ")";
|
Log(Debug::Debug) << "Locking tile agent=" << agentBounds << " changedTile=(" << changedTile << ")";
|
||||||
return mProcessingTiles.lock()->emplace(agentHalfExtents, changedTile).second;
|
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();
|
auto locked = mProcessingTiles.lock();
|
||||||
locked->erase(std::tie(agentHalfExtents, changedTile));
|
locked->erase(std::tie(agentBounds, changedTile));
|
||||||
Log(Debug::Debug) << "Unlocked tile agent=(" << agentHalfExtents << ") changedTile=(" << changedTile << ")";
|
Log(Debug::Debug) << "Unlocked tile agent=" << agentBounds << " changedTile=(" << changedTile << ")";
|
||||||
if (locked->empty())
|
if (locked->empty())
|
||||||
mProcessed.notify_all();
|
mProcessed.notify_all();
|
||||||
}
|
}
|
||||||
|
@ -819,7 +819,7 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
||||||
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
|
[&] (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
|
else
|
||||||
{
|
{
|
||||||
|
@ -827,7 +827,7 @@ namespace DetourNavigator
|
||||||
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v); });
|
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v); });
|
||||||
if (!objects.has_value())
|
if (!objects.has_value())
|
||||||
return;
|
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;
|
Log(Debug::Debug) << "Serializing input for job " << job->mId;
|
||||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
||||||
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
|
[&] (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)
|
if (const auto& cachedTileData = job->mCachedTileData)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "waitconditiontype.hpp"
|
#include "waitconditiontype.hpp"
|
||||||
#include "navmeshdb.hpp"
|
#include "navmeshdb.hpp"
|
||||||
#include "changetype.hpp"
|
#include "changetype.hpp"
|
||||||
|
#include "agentbounds.hpp"
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ namespace DetourNavigator
|
||||||
struct Job
|
struct Job
|
||||||
{
|
{
|
||||||
const std::size_t mId;
|
const std::size_t mId;
|
||||||
const osg::Vec3f mAgentHalfExtents;
|
const AgentBounds mAgentBounds;
|
||||||
const std::weak_ptr<GuardedNavMeshCacheItem> mNavMeshCacheItem;
|
const std::weak_ptr<GuardedNavMeshCacheItem> mNavMeshCacheItem;
|
||||||
const std::string mWorldspace;
|
const std::string mWorldspace;
|
||||||
const TilePosition mChangedTile;
|
const TilePosition mChangedTile;
|
||||||
|
@ -57,7 +58,7 @@ namespace DetourNavigator
|
||||||
std::optional<TileData> mCachedTileData;
|
std::optional<TileData> mCachedTileData;
|
||||||
std::unique_ptr<PreparedNavMeshData> mGeneratedNavMeshData;
|
std::unique_ptr<PreparedNavMeshData> mGeneratedNavMeshData;
|
||||||
|
|
||||||
Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
Job(const AgentBounds& agentBounds, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||||
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||||
std::chrono::steady_clock::time_point processTime);
|
std::chrono::steady_clock::time_point processTime);
|
||||||
};
|
};
|
||||||
|
@ -166,7 +167,7 @@ namespace DetourNavigator
|
||||||
OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr<NavMeshDb>&& db);
|
OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr<NavMeshDb>&& db);
|
||||||
~AsyncNavMeshUpdater();
|
~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 TilePosition& playerTile, std::string_view worldspace,
|
||||||
const std::map<TilePosition, ChangeType>& changedTiles);
|
const std::map<TilePosition, ChangeType>& changedTiles);
|
||||||
|
|
||||||
|
@ -191,12 +192,12 @@ namespace DetourNavigator
|
||||||
std::condition_variable mProcessed;
|
std::condition_variable mProcessed;
|
||||||
std::list<Job> mJobs;
|
std::list<Job> mJobs;
|
||||||
std::deque<JobIt> mWaiting;
|
std::deque<JobIt> mWaiting;
|
||||||
std::set<std::tuple<osg::Vec3f, TilePosition>> mPushed;
|
std::set<std::tuple<AgentBounds, TilePosition>> mPushed;
|
||||||
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
||||||
NavMeshTilesCache mNavMeshTilesCache;
|
NavMeshTilesCache mNavMeshTilesCache;
|
||||||
Misc::ScopeGuarded<std::set<std::tuple<osg::Vec3f, TilePosition>>> mProcessingTiles;
|
Misc::ScopeGuarded<std::set<std::tuple<AgentBounds, TilePosition>>> mProcessingTiles;
|
||||||
std::map<std::tuple<osg::Vec3f, TilePosition>, std::chrono::steady_clock::time_point> mLastUpdates;
|
std::map<std::tuple<AgentBounds, TilePosition>, std::chrono::steady_clock::time_point> mLastUpdates;
|
||||||
std::set<std::tuple<osg::Vec3f, TilePosition>> mPresentTiles;
|
std::set<std::tuple<AgentBounds, TilePosition>> mPresentTiles;
|
||||||
std::vector<std::thread> mThreads;
|
std::vector<std::thread> mThreads;
|
||||||
std::unique_ptr<DbWorker> mDbWorker;
|
std::unique_ptr<DbWorker> mDbWorker;
|
||||||
std::atomic_size_t mDbGetTileHits {0};
|
std::atomic_size_t mDbGetTileHits {0};
|
||||||
|
@ -220,9 +221,9 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void repost(JobIt job);
|
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;
|
inline std::size_t getTotalJobs() const;
|
||||||
|
|
||||||
|
|
17
components/detournavigator/collisionshapetype.hpp
Normal file
17
components/detournavigator/collisionshapetype.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_COLLISIONSHAPETYPE_H
|
||||||
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_COLLISIONSHAPETYPE_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace DetourNavigator
|
||||||
|
{
|
||||||
|
enum class CollisionShapeType : std::uint8_t
|
||||||
|
{
|
||||||
|
Aabb = 0,
|
||||||
|
RotatingBox = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr CollisionShapeType defaultCollisionShapeType = CollisionShapeType::Aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,6 +4,7 @@
|
||||||
#include "tilebounds.hpp"
|
#include "tilebounds.hpp"
|
||||||
#include "status.hpp"
|
#include "status.hpp"
|
||||||
#include "recastmesh.hpp"
|
#include "recastmesh.hpp"
|
||||||
|
#include "agentbounds.hpp"
|
||||||
|
|
||||||
#include <osg/io_utils>
|
#include <osg/io_utils>
|
||||||
|
|
||||||
|
@ -69,6 +70,21 @@ namespace DetourNavigator
|
||||||
return s << ", .mOriginalSize=" << v.mOriginalSize << "}";
|
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<std::underlying_type_t<CollisionShapeType>>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& s, const AgentBounds& v)
|
||||||
|
{
|
||||||
|
return s << "AgentBounds {" << v.mShapeType << ", " << v.mHalfExtents << "}";
|
||||||
|
}
|
||||||
|
|
||||||
class RecastMesh;
|
class RecastMesh;
|
||||||
struct RecastSettings;
|
struct RecastSettings;
|
||||||
|
|
||||||
|
|
|
@ -38,12 +38,12 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateNavMeshTile::GenerateNavMeshTile(std::string worldspace, const TilePosition& tilePosition,
|
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<NavMeshTileConsumer> consumer)
|
const DetourNavigator::Settings& settings, std::weak_ptr<NavMeshTileConsumer> consumer)
|
||||||
: mWorldspace(std::move(worldspace))
|
: mWorldspace(std::move(worldspace))
|
||||||
, mTilePosition(tilePosition)
|
, mTilePosition(tilePosition)
|
||||||
, mRecastMeshProvider(recastMeshProvider)
|
, mRecastMeshProvider(recastMeshProvider)
|
||||||
, mAgentHalfExtents(agentHalfExtents)
|
, mAgentBounds(agentBounds)
|
||||||
, mSettings(settings)
|
, mSettings(settings)
|
||||||
, mConsumer(std::move(consumer)) {}
|
, mConsumer(std::move(consumer)) {}
|
||||||
|
|
||||||
|
@ -70,25 +70,25 @@ namespace DetourNavigator
|
||||||
|
|
||||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||||
[&] (const MeshSource& v) { return consumer->resolveMeshSource(v); });
|
[&] (const MeshSource& v) { return consumer->resolveMeshSource(v); });
|
||||||
std::vector<std::byte> input = serialize(mSettings.mRecast, *recastMesh, objects);
|
std::vector<std::byte> input = serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects);
|
||||||
const std::optional<NavMeshTileInfo> info = consumer->find(mWorldspace, mTilePosition, input);
|
const std::optional<NavMeshTileInfo> 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);
|
consumer->identity(mWorldspace, mTilePosition, info->mTileId);
|
||||||
ignore.mConsumer = nullptr;
|
ignore.mConsumer = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto data = prepareNavMeshTileData(*recastMesh, mTilePosition, mAgentHalfExtents, mSettings.mRecast);
|
const auto data = prepareNavMeshTileData(*recastMesh, mTilePosition, mAgentBounds, mSettings.mRecast);
|
||||||
|
|
||||||
if (data == nullptr)
|
if (data == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (info.has_value())
|
if (info.has_value())
|
||||||
consumer->update(mWorldspace, mTilePosition, info->mTileId, mSettings.mNavMeshVersion, *data);
|
consumer->update(mWorldspace, mTilePosition, info->mTileId, navMeshVersion, *data);
|
||||||
else
|
else
|
||||||
consumer->insert(mWorldspace, mTilePosition, mSettings.mNavMeshVersion, input, *data);
|
consumer->insert(mWorldspace, mTilePosition, navMeshVersion, input, *data);
|
||||||
|
|
||||||
ignore.mConsumer = nullptr;
|
ignore.mConsumer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "recastmeshprovider.hpp"
|
#include "recastmeshprovider.hpp"
|
||||||
#include "tileposition.hpp"
|
#include "tileposition.hpp"
|
||||||
|
#include "agentbounds.hpp"
|
||||||
|
|
||||||
#include <components/sceneutil/workqueue.hpp>
|
#include <components/sceneutil/workqueue.hpp>
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GenerateNavMeshTile(std::string worldspace, const TilePosition& tilePosition,
|
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<NavMeshTileConsumer> consumer);
|
std::weak_ptr<NavMeshTileConsumer> consumer);
|
||||||
|
|
||||||
void doWork() final;
|
void doWork() final;
|
||||||
|
@ -66,7 +67,7 @@ namespace DetourNavigator
|
||||||
const std::string mWorldspace;
|
const std::string mWorldspace;
|
||||||
const TilePosition mTilePosition;
|
const TilePosition mTilePosition;
|
||||||
const RecastMeshProvider mRecastMeshProvider;
|
const RecastMeshProvider mRecastMeshProvider;
|
||||||
const osg::Vec3f mAgentHalfExtents;
|
const AgentBounds mAgentBounds;
|
||||||
const Settings& mSettings;
|
const Settings& mSettings;
|
||||||
std::weak_ptr<NavMeshTileConsumer> mConsumer;
|
std::weak_ptr<NavMeshTileConsumer> mConsumer;
|
||||||
|
|
||||||
|
|
|
@ -101,9 +101,9 @@ namespace
|
||||||
return result;
|
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)
|
float getMaxClimb(const RecastSettings& settings)
|
||||||
|
@ -111,14 +111,14 @@ namespace
|
||||||
return settings.mMaxClimb * settings.mRecastScaleFactor;
|
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)
|
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
|
struct RecastParams
|
||||||
|
@ -131,13 +131,13 @@ namespace
|
||||||
int mWalkableRadius = 0;
|
int mWalkableRadius = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
RecastParams makeRecastParams(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents)
|
RecastParams makeRecastParams(const RecastSettings& settings, const AgentBounds& agentBounds)
|
||||||
{
|
{
|
||||||
RecastParams result;
|
RecastParams result;
|
||||||
|
|
||||||
result.mWalkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentHalfExtents) / settings.mCellHeight));
|
result.mWalkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentBounds) / settings.mCellHeight));
|
||||||
result.mWalkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / settings.mCellHeight));
|
result.mWalkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / settings.mCellHeight));
|
||||||
result.mWalkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentHalfExtents) / settings.mCellSize));
|
result.mWalkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentBounds) / settings.mCellSize));
|
||||||
result.mMaxEdgeLen = static_cast<int>(std::round(static_cast<float>(settings.mMaxEdgeLen) / settings.mCellSize));
|
result.mMaxEdgeLen = static_cast<int>(std::round(static_cast<float>(settings.mMaxEdgeLen) / settings.mCellSize));
|
||||||
result.mSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : settings.mCellSize * settings.mDetailSampleDist;
|
result.mSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : settings.mCellSize * settings.mDetailSampleDist;
|
||||||
result.mSampleMaxError = settings.mCellHeight * settings.mDetailSampleMaxError;
|
result.mSampleMaxError = settings.mCellHeight * settings.mDetailSampleMaxError;
|
||||||
|
@ -227,7 +227,7 @@ namespace
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector<CellWater>& water,
|
bool rasterizeTriangles(rcContext& context, float agentHalfExtentsZ, const std::vector<CellWater>& water,
|
||||||
const RecastSettings& settings, const RecastParams& params, const TileBounds& realTileBounds, rcHeightfield& solid)
|
const RecastSettings& settings, const RecastParams& params, const TileBounds& realTileBounds, rcHeightfield& solid)
|
||||||
{
|
{
|
||||||
for (const CellWater& cellWater : water)
|
for (const CellWater& cellWater : water)
|
||||||
|
@ -237,7 +237,7 @@ namespace
|
||||||
{
|
{
|
||||||
const Rectangle rectangle {
|
const Rectangle rectangle {
|
||||||
toNavMeshCoordinates(settings, *intersection),
|
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))
|
if (!rasterizeTriangles(context, rectangle, AreaType_water, params, solid))
|
||||||
return false;
|
return false;
|
||||||
|
@ -277,12 +277,12 @@ namespace
|
||||||
return true;
|
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 RecastMesh& recastMesh, const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid)
|
||||||
{
|
{
|
||||||
const TileBounds realTileBounds = makeRealTileBoundsWithBorder(settings, tilePosition);
|
const TileBounds realTileBounds = makeRealTileBoundsWithBorder(settings, tilePosition);
|
||||||
return rasterizeTriangles(context, recastMesh.getMesh(), settings, params, solid)
|
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, recastMesh.getHeightfields(), settings, params, solid)
|
||||||
&& rasterizeTriangles(context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid);
|
&& rasterizeTriangles(context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid);
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ namespace
|
||||||
return power;
|
return power;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<float, float> getBoundsByZ(const RecastMesh& recastMesh, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings)
|
std::pair<float, float> getBoundsByZ(const RecastMesh& recastMesh, float agentHalfExtentsZ, const RecastSettings& settings)
|
||||||
{
|
{
|
||||||
float minZ = 0;
|
float minZ = 0;
|
||||||
float maxZ = 0;
|
float maxZ = 0;
|
||||||
|
@ -403,7 +403,7 @@ namespace
|
||||||
|
|
||||||
for (const CellWater& water : recastMesh.getWater())
|
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);
|
minZ = std::min(minZ, swimLevel);
|
||||||
maxZ = std::max(maxZ, swimLevel);
|
maxZ = std::max(maxZ, swimLevel);
|
||||||
}
|
}
|
||||||
|
@ -431,19 +431,19 @@ namespace
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
std::unique_ptr<PreparedNavMeshData> prepareNavMeshTileData(const RecastMesh& recastMesh,
|
std::unique_ptr<PreparedNavMeshData> 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;
|
rcContext context;
|
||||||
|
|
||||||
const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentHalfExtents, settings);
|
const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentBounds.mHalfExtents.z(), settings);
|
||||||
|
|
||||||
rcHeightfield solid;
|
rcHeightfield solid;
|
||||||
initHeightfield(context, tilePosition, toNavMeshCoordinates(settings, minZ),
|
initHeightfield(context, tilePosition, toNavMeshCoordinates(settings, minZ),
|
||||||
toNavMeshCoordinates(settings, maxZ), settings, solid);
|
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;
|
return nullptr;
|
||||||
|
|
||||||
rcFilterLowHangingWalkableObstacles(&context, params.mWalkableClimb, solid);
|
rcFilterLowHangingWalkableObstacles(&context, params.mWalkableClimb, solid);
|
||||||
|
@ -462,11 +462,11 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
|
|
||||||
NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data,
|
NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data,
|
||||||
const std::vector<OffMeshConnection>& offMeshConnections, const osg::Vec3f& agentHalfExtents,
|
const std::vector<OffMeshConnection>& offMeshConnections, const AgentBounds& agentBounds,
|
||||||
const TilePosition& tile, const RecastSettings& settings)
|
const TilePosition& tile, const RecastSettings& settings)
|
||||||
{
|
{
|
||||||
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
|
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
|
||||||
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
|
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentBounds));
|
||||||
const std::vector<unsigned char> offMeshConDir(offMeshConnections.size(), 0);
|
const std::vector<unsigned char> offMeshConDir(offMeshConnections.size(), 0);
|
||||||
const std::vector<unsigned char> offMeshConAreas = getOffMeshConAreas(offMeshConnections);
|
const std::vector<unsigned char> offMeshConAreas = getOffMeshConAreas(offMeshConnections);
|
||||||
const std::vector<unsigned short> offMeshConFlags = getOffMeshFlags(offMeshConnections);
|
const std::vector<unsigned short> offMeshConFlags = getOffMeshFlags(offMeshConnections);
|
||||||
|
@ -491,8 +491,8 @@ namespace DetourNavigator
|
||||||
params.offMeshConFlags = offMeshConFlags.data();
|
params.offMeshConFlags = offMeshConFlags.data();
|
||||||
params.offMeshConUserID = nullptr;
|
params.offMeshConUserID = nullptr;
|
||||||
params.offMeshConCount = static_cast<int>(offMeshConnections.size());
|
params.offMeshConCount = static_cast<int>(offMeshConnections.size());
|
||||||
params.walkableHeight = getHeight(settings, agentHalfExtents);
|
params.walkableHeight = getHeight(settings, agentBounds);
|
||||||
params.walkableRadius = getRadius(settings, agentHalfExtents);
|
params.walkableRadius = getRadius(settings, agentBounds);
|
||||||
params.walkableClimb = getMaxClimb(settings);
|
params.walkableClimb = getMaxClimb(settings);
|
||||||
rcVcopy(params.bmin, data.mPolyMesh.bmin);
|
rcVcopy(params.bmin, data.mPolyMesh.bmin);
|
||||||
rcVcopy(params.bmax, data.mPolyMesh.bmax);
|
rcVcopy(params.bmax, data.mPolyMesh.bmax);
|
||||||
|
|
|
@ -51,10 +51,10 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PreparedNavMeshData> prepareNavMeshTileData(const RecastMesh& recastMesh,
|
std::unique_ptr<PreparedNavMeshData> 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,
|
NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data,
|
||||||
const std::vector<OffMeshConnection>& offMeshConnections, const osg::Vec3f& agentHalfExtents,
|
const std::vector<OffMeshConnection>& offMeshConnections, const AgentBounds& agentBounds,
|
||||||
const TilePosition& tile, const RecastSettings& settings);
|
const TilePosition& tile, const RecastSettings& settings);
|
||||||
|
|
||||||
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
|
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace Loading
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct Settings;
|
struct Settings;
|
||||||
|
struct AgentBounds;
|
||||||
|
|
||||||
struct ObjectShapes
|
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.
|
* @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.
|
* 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
|
* @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
|
* @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
|
* @brief getNavMesh returns navmesh for specific agent half extents
|
||||||
* @return navmesh
|
* @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
|
* @brief getNavMeshes returns all current navmeshes
|
||||||
* @return map of agent half extents to navmesh
|
* @return map of agent half extents to navmesh
|
||||||
*/
|
*/
|
||||||
virtual std::map<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const = 0;
|
virtual std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const = 0;
|
||||||
|
|
||||||
virtual const Settings& getSettings() const = 0;
|
virtual const Settings& getSettings() const = 0;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
return;
|
||||||
++mAgents[agentHalfExtents];
|
++mAgents[agentBounds];
|
||||||
mNavMeshManager.addAgent(agentHalfExtents);
|
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())
|
if (it == mAgents.end())
|
||||||
return;
|
return;
|
||||||
if (it->second > 0)
|
if (it->second > 0)
|
||||||
|
@ -178,12 +178,12 @@ namespace DetourNavigator
|
||||||
mNavMeshManager.wait(listener, waitConditionType);
|
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<osg::Vec3f, SharedNavMeshCacheItem> NavigatorImpl::getNavMeshes() const
|
std::map<AgentBounds, SharedNavMeshCacheItem> NavigatorImpl::getNavMeshes() const
|
||||||
{
|
{
|
||||||
return mNavMeshManager.getNavMeshes();
|
return mNavMeshManager.getNavMeshes();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,9 @@ namespace DetourNavigator
|
||||||
*/
|
*/
|
||||||
explicit NavigatorImpl(const Settings& settings, std::unique_ptr<NavMeshDb>&& db);
|
explicit NavigatorImpl(const Settings& settings, std::unique_ptr<NavMeshDb>&& 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;
|
void setWorldspace(std::string_view worldspace) override;
|
||||||
|
|
||||||
|
@ -56,9 +56,9 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void wait(Loading::Listener& listener, WaitConditionType waitConditionType) override;
|
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<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const override;
|
std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const override;
|
||||||
|
|
||||||
const Settings& getSettings() const override;
|
const Settings& getSettings() const override;
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ namespace DetourNavigator
|
||||||
NavMeshManager mNavMeshManager;
|
NavMeshManager mNavMeshManager;
|
||||||
bool mUpdatesEnabled;
|
bool mUpdatesEnabled;
|
||||||
std::optional<TilePosition> mLastPlayerPosition;
|
std::optional<TilePosition> mLastPlayerPosition;
|
||||||
std::map<osg::Vec3f, std::size_t> mAgents;
|
std::map<AgentBounds, std::size_t> mAgents;
|
||||||
std::unordered_map<ObjectId, ObjectId> mAvoidIds;
|
std::unordered_map<ObjectId, ObjectId> mAvoidIds;
|
||||||
std::unordered_map<ObjectId, ObjectId> mWaterIds;
|
std::unordered_map<ObjectId, ObjectId> mWaterIds;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORSTUB_H
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORSTUB_H
|
||||||
|
|
||||||
#include "navigator.hpp"
|
#include "navigator.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
namespace Loading
|
namespace Loading
|
||||||
{
|
{
|
||||||
|
@ -15,9 +16,9 @@ namespace DetourNavigator
|
||||||
public:
|
public:
|
||||||
NavigatorStub() = default;
|
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 {}
|
void setWorldspace(std::string_view /*worldspace*/) override {}
|
||||||
|
|
||||||
|
@ -80,14 +81,14 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void wait(Loading::Listener& /*listener*/, WaitConditionType /*waitConditionType*/) override {}
|
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;
|
return mEmptyNavMeshCacheItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const override
|
std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const override
|
||||||
{
|
{
|
||||||
return std::map<osg::Vec3f, SharedNavMeshCacheItem>();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Settings& getSettings() const override
|
const Settings& getSettings() const override
|
||||||
|
|
|
@ -5,30 +5,30 @@
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const osg::Vec3f& agentHalfExtents,
|
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const AgentBounds& agentBounds,
|
||||||
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, float(*prng)())
|
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)
|
if (!navMesh)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
const auto& settings = navigator.getSettings();
|
const auto& settings = navigator.getSettings();
|
||||||
const auto result = DetourNavigator::findRandomPointAroundCircle(navMesh->lockConst()->getImpl(),
|
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);
|
toNavMeshCoordinates(settings.mRecast, maxRadius), includeFlags, settings.mDetour, prng);
|
||||||
if (!result)
|
if (!result)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return std::optional<osg::Vec3f>(fromNavMeshCoordinates(settings.mRecast, *result));
|
return std::optional<osg::Vec3f>(fromNavMeshCoordinates(settings.mRecast, *result));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start,
|
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start,
|
||||||
const osg::Vec3f& end, const Flags includeFlags)
|
const osg::Vec3f& end, const Flags includeFlags)
|
||||||
{
|
{
|
||||||
const auto navMesh = navigator.getNavMesh(agentHalfExtents);
|
const auto navMesh = navigator.getNavMesh(agentBounds);
|
||||||
if (navMesh == nullptr)
|
if (navMesh == nullptr)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
const auto& settings = navigator.getSettings();
|
const auto& settings = navigator.getSettings();
|
||||||
const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(),
|
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);
|
toNavMeshCoordinates(settings.mRecast, end), includeFlags, settings.mDetour);
|
||||||
if (!result)
|
if (!result)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through.
|
* @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 start path from given point.
|
||||||
* @param end path at given point.
|
* @param end path at given point.
|
||||||
* @param includeFlags setup allowed surfaces for actor to walk.
|
* @param includeFlags setup allowed surfaces for actor to walk.
|
||||||
|
@ -22,8 +22,8 @@ namespace DetourNavigator
|
||||||
* Equal to out if no path is found.
|
* Equal to out if no path is found.
|
||||||
*/
|
*/
|
||||||
template <class OutputIterator>
|
template <class OutputIterator>
|
||||||
inline Status findPath(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const float stepSize, const osg::Vec3f& start,
|
inline Status findPath(const Navigator& navigator, const AgentBounds& agentBounds, const float stepSize,
|
||||||
const osg::Vec3f& end, const Flags includeFlags, const DetourNavigator::AreaCosts& areaCosts,
|
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const AreaCosts& areaCosts,
|
||||||
float endTolerance, OutputIterator& out)
|
float endTolerance, OutputIterator& out)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
|
@ -33,35 +33,35 @@ namespace DetourNavigator
|
||||||
>::value,
|
>::value,
|
||||||
"out is not an OutputIterator"
|
"out is not an OutputIterator"
|
||||||
);
|
);
|
||||||
const auto navMesh = navigator.getNavMesh(agentHalfExtents);
|
const auto navMesh = navigator.getNavMesh(agentBounds);
|
||||||
if (navMesh == nullptr)
|
if (navMesh == nullptr)
|
||||||
return Status::NavMeshNotFound;
|
return Status::NavMeshNotFound;
|
||||||
const auto settings = navigator.getSettings();
|
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, stepSize), toNavMeshCoordinates(settings.mRecast, start),
|
||||||
toNavMeshCoordinates(settings.mRecast, end), includeFlags, areaCosts, settings, endTolerance, out);
|
toNavMeshCoordinates(settings.mRecast, end), includeFlags, areaCosts, settings, endTolerance, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief findRandomPointAroundCircle returns random location on navmesh within the reach of specified location.
|
* @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 start path from given point.
|
||||||
* @param maxRadius limit maximum distance from start.
|
* @param maxRadius limit maximum distance from start.
|
||||||
* @param includeFlags setup allowed surfaces for actor to walk.
|
* @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.
|
* @return not empty optional with position if point is found and empty optional if point is not found.
|
||||||
*/
|
*/
|
||||||
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const osg::Vec3f& agentHalfExtents,
|
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const AgentBounds& agentBounds,
|
||||||
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, float(*prng)());
|
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.
|
* @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 start of the line
|
||||||
* @param end of the line
|
* @param end of the line
|
||||||
* @param includeFlags setup allowed surfaces for actor to walk.
|
* @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.
|
* @return not empty optional with position if point is found and empty optional if point is not found.
|
||||||
*/
|
*/
|
||||||
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start,
|
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start,
|
||||||
const osg::Vec3f& end, const Flags includeFlags);
|
const osg::Vec3f& end, const Flags includeFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,27 +151,27 @@ namespace DetourNavigator
|
||||||
return true;
|
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())
|
if (cached != mCache.end())
|
||||||
return;
|
return;
|
||||||
mCache.insert(std::make_pair(agentHalfExtents,
|
mCache.insert(std::make_pair(agentBounds,
|
||||||
std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), ++mGenerationCounter)));
|
std::make_shared<GuardedNavMeshCacheItem>(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())
|
if (it == mCache.end())
|
||||||
return true;
|
return true;
|
||||||
if (!resetIfUnique(it->second))
|
if (!resetIfUnique(it->second))
|
||||||
return false;
|
return false;
|
||||||
mCache.erase(agentHalfExtents);
|
mCache.erase(agentBounds);
|
||||||
mChangedTiles.erase(agentHalfExtents);
|
mChangedTiles.erase(agentBounds);
|
||||||
mPlayerTile.erase(agentHalfExtents);
|
mPlayerTile.erase(agentBounds);
|
||||||
mLastRecastMeshManagerRevision.erase(agentHalfExtents);
|
mLastRecastMeshManagerRevision.erase(agentBounds);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,28 +195,28 @@ namespace DetourNavigator
|
||||||
addChangedTile(tile, ChangeType::update);
|
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));
|
const auto playerTile = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition));
|
||||||
auto& lastRevision = mLastRecastMeshManagerRevision[agentHalfExtents];
|
auto& lastRevision = mLastRecastMeshManagerRevision[agentBounds];
|
||||||
auto lastPlayerTile = mPlayerTile.find(agentHalfExtents);
|
auto lastPlayerTile = mPlayerTile.find(agentBounds);
|
||||||
if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end()
|
if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end()
|
||||||
&& lastPlayerTile->second == playerTile)
|
&& lastPlayerTile->second == playerTile)
|
||||||
return;
|
return;
|
||||||
lastRevision = mRecastMeshManager.getRevision();
|
lastRevision = mRecastMeshManager.getRevision();
|
||||||
if (lastPlayerTile == mPlayerTile.end())
|
if (lastPlayerTile == mPlayerTile.end())
|
||||||
lastPlayerTile = mPlayerTile.insert(std::make_pair(agentHalfExtents, playerTile)).first;
|
lastPlayerTile = mPlayerTile.insert(std::make_pair(agentBounds, playerTile)).first;
|
||||||
else
|
else
|
||||||
lastPlayerTile->second = playerTile;
|
lastPlayerTile->second = playerTile;
|
||||||
std::map<TilePosition, ChangeType> tilesToPost;
|
std::map<TilePosition, ChangeType> tilesToPost;
|
||||||
const auto cached = getCached(agentHalfExtents);
|
const auto cached = getCached(agentBounds);
|
||||||
if (!cached)
|
if (!cached)
|
||||||
{
|
{
|
||||||
std::ostringstream stream;
|
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());
|
throw InvalidArgument(stream.str());
|
||||||
}
|
}
|
||||||
const auto changedTiles = mChangedTiles.find(agentHalfExtents);
|
const auto changedTiles = mChangedTiles.find(agentBounds);
|
||||||
{
|
{
|
||||||
const auto locked = cached->lockConst();
|
const auto locked = cached->lockConst();
|
||||||
const auto& navMesh = locked->getImpl();
|
const auto& navMesh = locked->getImpl();
|
||||||
|
@ -247,10 +247,10 @@ namespace DetourNavigator
|
||||||
recastMeshManager.reportNavMeshChange(recastMeshManager.getVersion(), Version {0, 0});
|
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())
|
if (changedTiles != mChangedTiles.end())
|
||||||
changedTiles->second.clear();
|
changedTiles->second.clear();
|
||||||
Log(Debug::Debug) << "Cache update posted for agent=" << agentHalfExtents <<
|
Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds <<
|
||||||
" playerTile=" << lastPlayerTile->second <<
|
" playerTile=" << lastPlayerTile->second <<
|
||||||
" recastMeshManagerRevision=" << lastRevision;
|
" recastMeshManagerRevision=" << lastRevision;
|
||||||
}
|
}
|
||||||
|
@ -260,12 +260,12 @@ namespace DetourNavigator
|
||||||
mAsyncNavMeshUpdater.wait(listener, waitConditionType);
|
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<osg::Vec3f, SharedNavMeshCacheItem> NavMeshManager::getNavMeshes() const
|
std::map<AgentBounds, SharedNavMeshCacheItem> NavMeshManager::getNavMeshes() const
|
||||||
{
|
{
|
||||||
return mCache;
|
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())
|
if (cached != mCache.end())
|
||||||
return cached->second;
|
return cached->second;
|
||||||
return SharedNavMeshCacheItem();
|
return SharedNavMeshCacheItem();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "recastmeshtiles.hpp"
|
#include "recastmeshtiles.hpp"
|
||||||
#include "waitconditiontype.hpp"
|
#include "waitconditiontype.hpp"
|
||||||
#include "heightfieldshape.hpp"
|
#include "heightfieldshape.hpp"
|
||||||
|
#include "agentbounds.hpp"
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool removeObject(const ObjectId id);
|
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);
|
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
||||||
|
|
||||||
|
@ -45,19 +45,19 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool removeHeightfield(const osg::Vec2i& cellPosition);
|
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 addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType);
|
||||||
|
|
||||||
void removeOffMeshConnections(const ObjectId id);
|
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);
|
void wait(Loading::Listener& listener, WaitConditionType waitConditionType);
|
||||||
|
|
||||||
SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const;
|
SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const;
|
||||||
|
|
||||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const;
|
std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const;
|
||||||
|
|
||||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
||||||
|
|
||||||
|
@ -69,11 +69,11 @@ namespace DetourNavigator
|
||||||
TileCachedRecastMeshManager mRecastMeshManager;
|
TileCachedRecastMeshManager mRecastMeshManager;
|
||||||
OffMeshConnectionsManager mOffMeshConnectionsManager;
|
OffMeshConnectionsManager mOffMeshConnectionsManager;
|
||||||
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
|
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
|
||||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> mCache;
|
std::map<AgentBounds, SharedNavMeshCacheItem> mCache;
|
||||||
std::map<osg::Vec3f, std::map<TilePosition, ChangeType>> mChangedTiles;
|
std::map<AgentBounds, std::map<TilePosition, ChangeType>> mChangedTiles;
|
||||||
std::size_t mGenerationCounter = 0;
|
std::size_t mGenerationCounter = 0;
|
||||||
std::map<osg::Vec3f, TilePosition> mPlayerTile;
|
std::map<AgentBounds, TilePosition> mPlayerTile;
|
||||||
std::map<osg::Vec3f, std::size_t> mLastRecastMeshManagerRevision;
|
std::map<AgentBounds, std::size_t> mLastRecastMeshManagerRevision;
|
||||||
|
|
||||||
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType);
|
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);
|
void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType);
|
||||||
|
|
||||||
SharedNavMeshCacheItem getCached(const osg::Vec3f& agentHalfExtents) const;
|
SharedNavMeshCacheItem getCached(const AgentBounds& agentBounds) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,14 @@ namespace DetourNavigator
|
||||||
: mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0),
|
: mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0),
|
||||||
mHitCount(0), mGetCount(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 RecastMesh& recastMesh)
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> lock(mMutex);
|
const std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
++mGetCount;
|
++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())
|
if (tile == mValues.end())
|
||||||
return Value();
|
return Value();
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace DetourNavigator
|
||||||
return Value(*this, tile->second);
|
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<PreparedNavMeshData>&& value)
|
const RecastMesh& recastMesh, std::unique_ptr<PreparedNavMeshData>&& value)
|
||||||
{
|
{
|
||||||
const auto itemSize = sizeof(RecastMesh) + getSize(recastMesh)
|
const auto itemSize = sizeof(RecastMesh) + getSize(recastMesh)
|
||||||
|
@ -45,8 +45,8 @@ namespace DetourNavigator
|
||||||
RecastMeshData key {recastMesh.getMesh(), recastMesh.getWater(),
|
RecastMeshData key {recastMesh.getMesh(), recastMesh.getWater(),
|
||||||
recastMesh.getHeightfields(), recastMesh.getFlatHeightfields()};
|
recastMesh.getHeightfields(), recastMesh.getFlatHeightfields()};
|
||||||
|
|
||||||
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(key), itemSize);
|
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentBounds, changedTile, std::move(key), itemSize);
|
||||||
const auto emplaced = mValues.emplace(std::make_tuple(agentHalfExtents, changedTile, std::cref(iterator->mRecastMeshData)), iterator);
|
const auto emplaced = mValues.emplace(std::make_tuple(agentBounds, changedTile, std::cref(iterator->mRecastMeshData)), iterator);
|
||||||
|
|
||||||
if (!emplaced.second)
|
if (!emplaced.second)
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
const auto& item = mFreeItems.back();
|
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())
|
if (value == mValues.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "preparednavmeshdata.hpp"
|
#include "preparednavmeshdata.hpp"
|
||||||
#include "recastmesh.hpp"
|
#include "recastmesh.hpp"
|
||||||
#include "tileposition.hpp"
|
#include "tileposition.hpp"
|
||||||
|
#include "agentbounds.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -52,16 +53,16 @@ namespace DetourNavigator
|
||||||
struct Item
|
struct Item
|
||||||
{
|
{
|
||||||
std::atomic<std::int64_t> mUseCount;
|
std::atomic<std::int64_t> mUseCount;
|
||||||
osg::Vec3f mAgentHalfExtents;
|
AgentBounds mAgentBounds;
|
||||||
TilePosition mChangedTile;
|
TilePosition mChangedTile;
|
||||||
RecastMeshData mRecastMeshData;
|
RecastMeshData mRecastMeshData;
|
||||||
std::unique_ptr<PreparedNavMeshData> mPreparedNavMeshData;
|
std::unique_ptr<PreparedNavMeshData> mPreparedNavMeshData;
|
||||||
std::size_t mSize;
|
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)
|
RecastMeshData&& recastMeshData, std::size_t size)
|
||||||
: mUseCount(0)
|
: mUseCount(0)
|
||||||
, mAgentHalfExtents(agentHalfExtents)
|
, mAgentBounds(agentBounds)
|
||||||
, mChangedTile(changedTile)
|
, mChangedTile(changedTile)
|
||||||
, mRecastMeshData(std::move(recastMeshData))
|
, mRecastMeshData(std::move(recastMeshData))
|
||||||
, mSize(size)
|
, mSize(size)
|
||||||
|
@ -136,10 +137,10 @@ namespace DetourNavigator
|
||||||
|
|
||||||
NavMeshTilesCache(const std::size_t maxNavMeshDataSize);
|
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);
|
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<PreparedNavMeshData>&& value);
|
const RecastMesh& recastMesh, std::unique_ptr<PreparedNavMeshData>&& value);
|
||||||
|
|
||||||
Stats getStats() const;
|
Stats getStats() const;
|
||||||
|
@ -153,7 +154,7 @@ namespace DetourNavigator
|
||||||
std::size_t mGetCount;
|
std::size_t mGetCount;
|
||||||
std::list<Item> mBusyItems;
|
std::list<Item> mBusyItems;
|
||||||
std::list<Item> mFreeItems;
|
std::list<Item> mFreeItems;
|
||||||
std::map<std::tuple<osg::Vec3f, TilePosition, std::reference_wrapper<const RecastMeshData>>, ItemIterator, std::less<>> mValues;
|
std::map<std::tuple<AgentBounds, TilePosition, std::reference_wrapper<const RecastMeshData>>, ItemIterator, std::less<>> mValues;
|
||||||
|
|
||||||
void removeLeastRecentlyUsed();
|
void removeLeastRecentlyUsed();
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H
|
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H
|
||||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H
|
||||||
|
|
||||||
|
#include "agentbounds.hpp"
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace DetourNavigator
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "recast.hpp"
|
#include "recast.hpp"
|
||||||
#include "recastmesh.hpp"
|
#include "recastmesh.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
#include "agentbounds.hpp"
|
||||||
|
|
||||||
#include <components/serialization/binaryreader.hpp>
|
#include <components/serialization/binaryreader.hpp>
|
||||||
#include <components/serialization/binarywriter.hpp>
|
#include <components/serialization/binarywriter.hpp>
|
||||||
|
@ -136,12 +137,13 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Visitor>
|
template <class Visitor>
|
||||||
void operator()(Visitor&& visitor, const RecastSettings& settings, const RecastMesh& recastMesh,
|
void operator()(Visitor&& visitor, const RecastSettings& settings, const AgentBounds& agentBounds,
|
||||||
const std::vector<DbRefGeometryObject>& dbRefGeometryObjects) const
|
const RecastMesh& recastMesh, const std::vector<DbRefGeometryObject>& dbRefGeometryObjects) const
|
||||||
{
|
{
|
||||||
visitor(*this, DetourNavigator::recastMeshMagic);
|
visitor(*this, DetourNavigator::recastMeshMagic);
|
||||||
visitor(*this, DetourNavigator::recastMeshVersion);
|
visitor(*this, DetourNavigator::recastMeshVersion);
|
||||||
visitor(*this, settings);
|
visitor(*this, settings);
|
||||||
|
visitor(*this, agentBounds);
|
||||||
visitor(*this, recastMesh);
|
visitor(*this, recastMesh);
|
||||||
visitor(*this, dbRefGeometryObjects);
|
visitor(*this, dbRefGeometryObjects);
|
||||||
}
|
}
|
||||||
|
@ -228,21 +230,28 @@ namespace
|
||||||
visitor(*this, value.mPolyMesh);
|
visitor(*this, value.mPolyMesh);
|
||||||
visitor(*this, value.mPolyMeshDetail);
|
visitor(*this, value.mPolyMeshDetail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Visitor>
|
||||||
|
void operator()(Visitor&& visitor, const AgentBounds& value) const
|
||||||
|
{
|
||||||
|
visitor(*this, value.mShapeType);
|
||||||
|
visitor(*this, value.mHalfExtents);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} // namespace DetourNavigator
|
} // namespace DetourNavigator
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
std::vector<std::byte> serialize(const RecastSettings& settings, const RecastMesh& recastMesh,
|
std::vector<std::byte> serialize(const RecastSettings& settings, const AgentBounds& agentBounds,
|
||||||
const std::vector<DbRefGeometryObject>& dbRefGeometryObjects)
|
const RecastMesh& recastMesh, const std::vector<DbRefGeometryObject>& dbRefGeometryObjects)
|
||||||
{
|
{
|
||||||
constexpr Format<Serialization::Mode::Write> format;
|
constexpr Format<Serialization::Mode::Write> format;
|
||||||
Serialization::SizeAccumulator sizeAccumulator;
|
Serialization::SizeAccumulator sizeAccumulator;
|
||||||
format(sizeAccumulator, settings, recastMesh, dbRefGeometryObjects);
|
format(sizeAccumulator, settings, agentBounds, recastMesh, dbRefGeometryObjects);
|
||||||
std::vector<std::byte> result(sizeAccumulator.value());
|
std::vector<std::byte> result(sizeAccumulator.value());
|
||||||
format(Serialization::BinaryWriter(result.data(), result.data() + result.size()),
|
format(Serialization::BinaryWriter(result.data(), result.data() + result.size()),
|
||||||
settings, recastMesh, dbRefGeometryObjects);
|
settings, agentBounds, recastMesh, dbRefGeometryObjects);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,16 @@ namespace DetourNavigator
|
||||||
struct DbRefGeometryObject;
|
struct DbRefGeometryObject;
|
||||||
struct PreparedNavMeshData;
|
struct PreparedNavMeshData;
|
||||||
struct RecastSettings;
|
struct RecastSettings;
|
||||||
|
struct AgentBounds;
|
||||||
|
|
||||||
constexpr char recastMeshMagic[] = {'r', 'c', 's', 't'};
|
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 char preparedNavMeshDataMagic[] = {'p', 'n', 'a', 'v'};
|
||||||
constexpr std::uint32_t preparedNavMeshDataVersion = 1;
|
constexpr std::uint32_t preparedNavMeshDataVersion = 1;
|
||||||
|
|
||||||
std::vector<std::byte> serialize(const RecastSettings& settings, const RecastMesh& value,
|
std::vector<std::byte> serialize(const RecastSettings& settings, const AgentBounds& agentBounds,
|
||||||
const std::vector<DbRefGeometryObject>& dbRefGeometryObjects);
|
const RecastMesh& recastMesh, const std::vector<DbRefGeometryObject>& dbRefGeometryObjects);
|
||||||
|
|
||||||
std::vector<std::byte> serialize(const PreparedNavMeshData& value);
|
std::vector<std::byte> serialize(const PreparedNavMeshData& value);
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ namespace DetourNavigator
|
||||||
result.mEnableRecastMeshFileNameRevision = ::Settings::Manager::getBool("enable recast mesh file name revision", "Navigator");
|
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.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.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.mEnableNavMeshDiskCache = ::Settings::Manager::getBool("enable nav mesh disk cache", "Navigator");
|
||||||
result.mWriteToNavMeshDb = ::Settings::Manager::getBool("write to navmeshdb", "Navigator");
|
result.mWriteToNavMeshDb = ::Settings::Manager::getBool("write to navmeshdb", "Navigator");
|
||||||
result.mMaxDbFileSize = static_cast<std::uint64_t>(::Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
result.mMaxDbFileSize = static_cast<std::uint64_t>(::Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
||||||
|
|
|
@ -50,10 +50,11 @@ namespace DetourNavigator
|
||||||
std::string mRecastMeshPathPrefix;
|
std::string mRecastMeshPathPrefix;
|
||||||
std::string mNavMeshPathPrefix;
|
std::string mNavMeshPathPrefix;
|
||||||
std::chrono::milliseconds mMinUpdateInterval;
|
std::chrono::milliseconds mMinUpdateInterval;
|
||||||
std::int64_t mNavMeshVersion = 0;
|
|
||||||
std::uint64_t mMaxDbFileSize = 0;
|
std::uint64_t mMaxDbFileSize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline constexpr std::int64_t navMeshVersion = 2;
|
||||||
|
|
||||||
RecastSettings makeRecastSettingsFromSettingsManager();
|
RecastSettings makeRecastSettingsFromSettingsManager();
|
||||||
|
|
||||||
DetourSettings makeDetourSettingsFromSettingsManager();
|
DetourSettings makeDetourSettingsFromSettingsManager();
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
|
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& 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)
|
const DetourNavigator::RecastSettings& settings)
|
||||||
{
|
{
|
||||||
using namespace DetourNavigator;
|
using namespace DetourNavigator;
|
||||||
|
@ -46,8 +46,8 @@ namespace SceneUtil
|
||||||
|
|
||||||
DebugDraw debugDraw(*group, DebugDraw::makeStateSet(), osg::Vec3f(0, 0, 0), 1);
|
DebugDraw debugDraw(*group, DebugDraw::makeStateSet(), osg::Vec3f(0, 0, 0), 1);
|
||||||
|
|
||||||
const auto agentRadius = DetourNavigator::getAgentRadius(halfExtents);
|
const auto agentRadius = DetourNavigator::getAgentRadius(agentBounds);
|
||||||
const auto agentHeight = DetourNavigator::getAgentHeight(halfExtents);
|
const auto agentHeight = DetourNavigator::getAgentHeight(agentBounds);
|
||||||
const auto agentClimb = settings.mMaxClimb;
|
const auto agentClimb = settings.mMaxClimb;
|
||||||
const auto startColor = duRGBA(128, 25, 0, 192);
|
const auto startColor = duRGBA(128, 25, 0, 192);
|
||||||
const auto endColor = duRGBA(51, 102, 0, 129);
|
const auto endColor = duRGBA(51, 102, 0, 129);
|
||||||
|
|
|
@ -14,12 +14,13 @@ namespace osg
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct RecastSettings;
|
struct RecastSettings;
|
||||||
|
struct AgentBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
|
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& 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);
|
const DetourNavigator::RecastSettings& settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -943,10 +943,6 @@ min update interval ms = 250
|
||||||
# Distance is measured in the number of tiles and can be only an integer value.
|
# Distance is measured in the number of tiles and can be only an integer value.
|
||||||
wait until min distance to player = 5
|
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)
|
# Use navigation mesh cache stored on disk (true, false)
|
||||||
enable nav mesh disk cache = true
|
enable nav mesh disk cache = true
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue