mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
Update NavMesh one by one tile in order from nearest to player
This commit is contained in:
parent
41caca24ee
commit
d1d034a1ec
13 changed files with 227 additions and 181 deletions
|
@ -363,7 +363,8 @@ namespace MWWorld
|
|||
else
|
||||
mPhysics->disableWater();
|
||||
|
||||
navigator->update();
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
navigator->update(player.getRefData().getPosition().asVec3());
|
||||
|
||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||
mRendering.configureAmbient(cell->getCell());
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
#include <components/detournavigator/debug.hpp>
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
#include <components/detournavigator/debug.hpp>
|
||||
|
||||
|
|
|
@ -56,6 +56,32 @@ namespace
|
|||
}
|
||||
};
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_throw_exception)
|
||||
{
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut), InvalidArgument);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut), NavigatorException);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_removed_agent_should_throw_exception)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->removeAgent(mAgentHalfExtents);
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut), InvalidArgument);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->removeAgent(mAgentHalfExtents);
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut), NavigatorException);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, update_then_find_path_should_return_path)
|
||||
{
|
||||
const std::array<btScalar, 5 * 5> heightfieldData {{
|
||||
|
@ -70,7 +96,7 @@ namespace
|
|||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||
mNavigator->update();
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||
|
@ -127,7 +153,7 @@ namespace
|
|||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||
mNavigator->addObject(2, shape2, btTransform::getIdentity());
|
||||
mNavigator->update();
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||
|
|
|
@ -7,6 +7,21 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
using DetourNavigator::TilePosition;
|
||||
|
||||
int getDistance(const TilePosition& lhs, const TilePosition& rhs)
|
||||
{
|
||||
return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y());
|
||||
}
|
||||
|
||||
std::pair<int, int> makePriority(const TilePosition& changedTile, const TilePosition& playerTile)
|
||||
{
|
||||
return std::make_pair(getDistance(changedTile, playerTile), getDistance(changedTile, TilePosition {0, 0}));
|
||||
}
|
||||
}
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings)
|
||||
|
@ -20,25 +35,21 @@ namespace DetourNavigator
|
|||
{
|
||||
mShouldStop = true;
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mJobs.clear();
|
||||
mJobs = decltype(mJobs)();
|
||||
mHasJob.notify_all();
|
||||
lock.unlock();
|
||||
mThread.join();
|
||||
}
|
||||
|
||||
void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr<RecastMesh>& recastMesh,
|
||||
const std::shared_ptr<NavMeshCacheItem>& navMeshCacheItem, std::set<TilePosition>&& changedTiles)
|
||||
const std::shared_ptr<NavMeshCacheItem>& navMeshCacheItem, const TilePosition& playerTile,
|
||||
const std::set<TilePosition>& changedTiles)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(mMutex);
|
||||
const auto job = mJobs.find(agentHalfExtents);
|
||||
if (job == mJobs.end() || job->second.mChangedTiles.empty())
|
||||
for (const auto& changedTile : changedTiles)
|
||||
{
|
||||
mJobs[agentHalfExtents] = Job {agentHalfExtents, recastMesh, navMeshCacheItem, std::move(changedTiles)};
|
||||
}
|
||||
else
|
||||
{
|
||||
job->second.mRecastMesh = recastMesh;
|
||||
job->second.mChangedTiles.insert(changedTiles.begin(), changedTiles.end());
|
||||
mJobs.push(Job {agentHalfExtents, recastMesh, navMeshCacheItem, changedTile,
|
||||
makePriority(changedTile, playerTile)});
|
||||
}
|
||||
mHasJob.notify_all();
|
||||
}
|
||||
|
@ -74,11 +85,8 @@ namespace DetourNavigator
|
|||
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
|
||||
if (job.mNavMeshCacheItem->mValue && !job.mChangedTiles.empty())
|
||||
updateNavMesh(job.mAgentHalfExtents, *job.mRecastMesh, job.mChangedTiles, mSettings,
|
||||
*job.mNavMeshCacheItem->mValue);
|
||||
else
|
||||
job.mNavMeshCacheItem->mValue = makeNavMesh(job.mAgentHalfExtents, *job.mRecastMesh, mSettings);
|
||||
updateNavMesh(job.mAgentHalfExtents, *job.mRecastMesh, job.mChangedTile, mSettings,
|
||||
job.mNavMeshCacheItem->mValue);
|
||||
|
||||
const auto finish = std::chrono::steady_clock::now();
|
||||
|
||||
|
@ -101,8 +109,8 @@ namespace DetourNavigator
|
|||
return boost::none;
|
||||
}
|
||||
log("got ", mJobs.size(), " jobs");
|
||||
const auto job = mJobs.begin()->second;
|
||||
mJobs.erase(mJobs.begin());
|
||||
const auto job = mJobs.top();
|
||||
mJobs.pop();
|
||||
return job;
|
||||
}
|
||||
|
||||
|
@ -115,6 +123,6 @@ namespace DetourNavigator
|
|||
if (mSettings.get().mEnableWriteRecastMeshToFile)
|
||||
writeToFile(*job.mRecastMesh, mSettings.get().mRecastMeshPathPrefix, revision);
|
||||
if (mSettings.get().mEnableWriteNavMeshToFile)
|
||||
writeToFile(*job.mNavMeshCacheItem->mValue, mSettings.get().mNavMeshPathPrefix, revision);
|
||||
writeToFile(*job.mNavMeshCacheItem->mValue.lock(), mSettings.get().mNavMeshPathPrefix, revision);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_ASYNCNAVMESHUPDATER_H
|
||||
|
||||
#include "recastmesh.hpp"
|
||||
#include "sharednavmesh.hpp"
|
||||
#include "tileposition.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
|
||||
|
@ -20,11 +22,9 @@ class dtNavMesh;
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
using NavMeshPtr = std::shared_ptr<dtNavMesh>;
|
||||
|
||||
struct NavMeshCacheItem
|
||||
{
|
||||
NavMeshPtr mValue;
|
||||
SharedNavMesh mValue;
|
||||
std::size_t mRevision;
|
||||
};
|
||||
|
||||
|
@ -35,7 +35,8 @@ namespace DetourNavigator
|
|||
~AsyncNavMeshUpdater();
|
||||
|
||||
void post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr<RecastMesh>& recastMesh,
|
||||
const std::shared_ptr<NavMeshCacheItem>& mNavMeshCacheItem, std::set<TilePosition>&& changedTiles);
|
||||
const std::shared_ptr<NavMeshCacheItem>& navMeshCacheItem, const TilePosition& playerTile,
|
||||
const std::set<TilePosition>& changedTiles);
|
||||
|
||||
void wait();
|
||||
|
||||
|
@ -45,10 +46,16 @@ namespace DetourNavigator
|
|||
osg::Vec3f mAgentHalfExtents;
|
||||
std::shared_ptr<RecastMesh> mRecastMesh;
|
||||
std::shared_ptr<NavMeshCacheItem> mNavMeshCacheItem;
|
||||
std::set<TilePosition> mChangedTiles;
|
||||
TilePosition mChangedTile;
|
||||
std::pair<int, int> mPriority;
|
||||
|
||||
friend inline bool operator <(const Job& lhs, const Job& rhs)
|
||||
{
|
||||
return lhs.mPriority > rhs.mPriority;
|
||||
}
|
||||
};
|
||||
|
||||
using Jobs = std::map<osg::Vec3f, Job>;
|
||||
using Jobs = std::priority_queue<Job, std::deque<Job>>;
|
||||
|
||||
std::reference_wrapper<const Settings> mSettings;
|
||||
std::atomic_bool mShouldStop;
|
||||
|
|
|
@ -10,6 +10,12 @@ namespace DetourNavigator
|
|||
NavigatorException(const std::string& message) : std::runtime_error(message) {}
|
||||
NavigatorException(const char* message) : std::runtime_error(message) {}
|
||||
};
|
||||
|
||||
struct InvalidArgument : std::invalid_argument
|
||||
{
|
||||
InvalidArgument(const std::string& message) : std::invalid_argument(message) {}
|
||||
InvalidArgument(const char* message) : std::invalid_argument(message) {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "recastmesh.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "settingsutils.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "sharednavmesh.hpp"
|
||||
|
||||
#include <DetourNavMesh.h>
|
||||
#include <DetourNavMeshBuilder.h>
|
||||
|
@ -218,22 +218,8 @@ namespace
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
NavMeshPtr makeEmptyNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const Settings& settings)
|
||||
NavMeshPtr makeEmptyNavMesh(const Settings& settings)
|
||||
{
|
||||
log("build empty NavMesh:",
|
||||
" agentHeight=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
getHeight(settings, agentHalfExtents),
|
||||
" agentMaxClimb=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
getMaxClimb(settings),
|
||||
" agentRadius=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
getRadius(settings, agentHalfExtents));
|
||||
|
||||
osg::Vec3f boundsMin;
|
||||
osg::Vec3f boundsMax;
|
||||
rcCalcBounds(recastMesh.getVertices().data(), static_cast<int>(recastMesh.getVerticesCount()),
|
||||
boundsMin.ptr(), boundsMax.ptr());
|
||||
|
||||
// Max tiles and max polys affect how the tile IDs are caculated.
|
||||
// There are 22 bits available for identifying a tile and a polygon.
|
||||
const auto tileBits = 10;
|
||||
|
@ -242,7 +228,7 @@ namespace DetourNavigator
|
|||
const auto maxPolysPerTile = 1 << polyBits;
|
||||
|
||||
dtNavMeshParams params;
|
||||
rcVcopy(params.orig, boundsMin.ptr());
|
||||
std::fill_n(params.orig, 3, 0.0f);
|
||||
params.tileWidth = settings.mTileSize * settings.mCellSize;
|
||||
params.tileHeight = settings.mTileSize * settings.mCellSize;
|
||||
params.maxTiles = maxTiles;
|
||||
|
@ -254,67 +240,8 @@ namespace DetourNavigator
|
|||
return navMesh;
|
||||
}
|
||||
|
||||
NavMeshPtr makeNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const Settings& settings)
|
||||
{
|
||||
log("build NavMesh with mutiple tiles:",
|
||||
" agentHeight=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
getHeight(settings, agentHalfExtents),
|
||||
" agentMaxClimb=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
getMaxClimb(settings),
|
||||
" agentRadius=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
getRadius(settings, agentHalfExtents));
|
||||
|
||||
osg::Vec3f boundsMin;
|
||||
osg::Vec3f boundsMax;
|
||||
rcCalcBounds(recastMesh.getVertices().data(), static_cast<int>(recastMesh.getVerticesCount()),
|
||||
boundsMin.ptr(), boundsMax.ptr());
|
||||
|
||||
const auto minTilePosition = getTilePosition(settings, boundsMin);
|
||||
const auto maxTilePosition = getTilePosition(settings, boundsMax);
|
||||
|
||||
// Max tiles and max polys affect how the tile IDs are caculated.
|
||||
// There are 22 bits available for identifying a tile and a polygon.
|
||||
const auto tileBits = 10;
|
||||
const auto polyBits = 22 - tileBits;
|
||||
const auto maxTiles = 1 << tileBits;
|
||||
const auto maxPolysPerTile = 1 << polyBits;
|
||||
|
||||
dtNavMeshParams params;
|
||||
std::fill_n(params.orig, 3, 0.0f);
|
||||
params.tileWidth = getTileSize(settings);
|
||||
params.tileHeight = getTileSize(settings);
|
||||
params.maxTiles = maxTiles;
|
||||
params.maxPolys = maxPolysPerTile;
|
||||
|
||||
NavMeshPtr navMesh(dtAllocNavMesh(), &dtFreeNavMesh);
|
||||
OPENMW_CHECK_DT_STATUS(navMesh->init(¶ms));
|
||||
|
||||
for (int y = minTilePosition.y(); y <= maxTilePosition.y(); ++y)
|
||||
{
|
||||
for (int x = minTilePosition.x(); x <= maxTilePosition.x(); ++x)
|
||||
{
|
||||
const auto tileBounds = makeTileBounds(settings, TilePosition(x, y));
|
||||
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), boundsMin.y() - 1, tileBounds.mMin.y());
|
||||
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), boundsMax.y() + 1, tileBounds.mMax.y());
|
||||
|
||||
auto navMeshData = makeNavMeshTileData(agentHalfExtents, recastMesh, x, y,
|
||||
tileBorderMin, tileBorderMax, settings);
|
||||
|
||||
if (!navMeshData.mValue)
|
||||
continue;
|
||||
|
||||
OPENMW_CHECK_DT_STATUS(navMesh->addTile(navMeshData.mValue.get(), navMeshData.mSize,
|
||||
DT_TILE_FREE_DATA, 0, 0));
|
||||
navMeshData.mValue.release();
|
||||
}
|
||||
}
|
||||
|
||||
return navMesh;
|
||||
}
|
||||
|
||||
void updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const std::set<TilePosition>& changedTiles, const Settings& settings, dtNavMesh& navMesh)
|
||||
const TilePosition& changedTile, const Settings& settings, SharedNavMesh& navMesh)
|
||||
{
|
||||
log("update NavMesh with mutiple tiles:",
|
||||
" agentHeight=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
|
@ -323,36 +250,36 @@ namespace DetourNavigator
|
|||
getMaxClimb(settings),
|
||||
" agentRadius=", std::setprecision(std::numeric_limits<float>::max_exponent10),
|
||||
getRadius(settings, agentHalfExtents),
|
||||
" changedTiles.size()=", changedTiles.size());
|
||||
" changedTile=", changedTile);
|
||||
|
||||
osg::Vec3f boundsMin;
|
||||
osg::Vec3f boundsMax;
|
||||
rcCalcBounds(recastMesh.getVertices().data(), int(recastMesh.getVerticesCount()),
|
||||
boundsMin.ptr(), boundsMax.ptr());
|
||||
|
||||
const auto& params = *navMesh.getParams();
|
||||
const auto& params = *navMesh.lock()->getParams();
|
||||
const osg::Vec3f origin(params.orig[0], params.orig[1], params.orig[2]);
|
||||
|
||||
for (const auto& tilePosition : changedTiles)
|
||||
const auto x = changedTile.x();
|
||||
const auto y = changedTile.y();
|
||||
|
||||
{
|
||||
const auto x = tilePosition.x();
|
||||
const auto y = tilePosition.y();
|
||||
|
||||
navMesh.removeTile(navMesh.getTileRefAt(x, y, 0), nullptr, nullptr);
|
||||
|
||||
const auto tileBounds = makeTileBounds(settings, tilePosition);
|
||||
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), boundsMin.y() - 1, tileBounds.mMin.y());
|
||||
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), boundsMax.y() + 1, tileBounds.mMax.y());
|
||||
|
||||
auto navMeshData = makeNavMeshTileData(agentHalfExtents, recastMesh, x, y,
|
||||
tileBorderMin, tileBorderMax, settings);
|
||||
|
||||
if (!navMeshData.mValue)
|
||||
continue;
|
||||
|
||||
OPENMW_CHECK_DT_STATUS(navMesh.addTile(navMeshData.mValue.get(), navMeshData.mSize,
|
||||
DT_TILE_FREE_DATA, 0, 0));
|
||||
navMeshData.mValue.release();
|
||||
const auto locked = navMesh.lock();
|
||||
locked->removeTile(locked->getTileRefAt(x, y, 0), nullptr, nullptr);
|
||||
}
|
||||
|
||||
const auto tileBounds = makeTileBounds(settings, changedTile);
|
||||
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), boundsMin.y() - 1, tileBounds.mMin.y());
|
||||
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), boundsMax.y() + 1, tileBounds.mMax.y());
|
||||
|
||||
auto navMeshData = makeNavMeshTileData(agentHalfExtents, recastMesh, x, y,
|
||||
tileBorderMin, tileBorderMax, settings);
|
||||
|
||||
if (!navMeshData.mValue)
|
||||
return;
|
||||
|
||||
OPENMW_CHECK_DT_STATUS(navMesh.lock()->addTile(navMeshData.mValue.get(), navMeshData.mSize,
|
||||
DT_TILE_FREE_DATA, 0, 0));
|
||||
navMeshData.mValue.release();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,18 +13,15 @@ class dtNavMesh;
|
|||
namespace DetourNavigator
|
||||
{
|
||||
class RecastMesh;
|
||||
class SharedNavMesh;
|
||||
struct Settings;
|
||||
|
||||
using NavMeshPtr = std::shared_ptr<dtNavMesh>;
|
||||
|
||||
NavMeshPtr makeEmptyNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const Settings& settings);
|
||||
|
||||
NavMeshPtr makeNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const Settings& settings);
|
||||
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
|
||||
|
||||
void updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||
const std::set<TilePosition>& changedTiles, const Settings& settings, dtNavMesh& navMesh);
|
||||
const TilePosition& changedTile, const Settings& settings, SharedNavMesh& navMesh);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace DetourNavigator
|
|||
void Navigator::addAgent(const osg::Vec3f& agentHalfExtents)
|
||||
{
|
||||
++mAgents[agentHalfExtents];
|
||||
mNavMeshManager.addAgent(agentHalfExtents);
|
||||
}
|
||||
|
||||
void Navigator::removeAgent(const osg::Vec3f& agentHalfExtents)
|
||||
|
@ -29,10 +30,10 @@ namespace DetourNavigator
|
|||
return mNavMeshManager.removeObject(id);
|
||||
}
|
||||
|
||||
void Navigator::update()
|
||||
void Navigator::update(const osg::Vec3f& playerPosition)
|
||||
{
|
||||
for (const auto& v : mAgents)
|
||||
mNavMeshManager.update(v.first);
|
||||
mNavMeshManager.update(playerPosition, v.first);
|
||||
}
|
||||
|
||||
void Navigator::wait()
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace DetourNavigator
|
|||
|
||||
bool removeObject(std::size_t id);
|
||||
|
||||
void update();
|
||||
void update(const osg::Vec3f& playerPosition);
|
||||
|
||||
void wait();
|
||||
|
||||
|
@ -34,9 +34,7 @@ namespace DetourNavigator
|
|||
const osg::Vec3f& end, OutputIterator out) const
|
||||
{
|
||||
const auto navMesh = mNavMeshManager.getNavMesh(agentHalfExtents);
|
||||
if (!navMesh)
|
||||
return out;
|
||||
return findSmoothPath(*navMesh, toNavMeshCoordinates(mSettings, agentHalfExtents),
|
||||
return findSmoothPath(*navMesh.lock(), toNavMeshCoordinates(mSettings, agentHalfExtents),
|
||||
toNavMeshCoordinates(mSettings, start), toNavMeshCoordinates(mSettings, end), mSettings, out);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "navmeshmanager.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "makenavmesh.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "sharednavmesh.hpp"
|
||||
|
||||
#include <DetourNavMesh.h>
|
||||
|
||||
|
@ -27,34 +29,39 @@ namespace DetourNavigator
|
|||
return true;
|
||||
}
|
||||
|
||||
void NavMeshManager::addAgent(const osg::Vec3f& agentHalfExtents)
|
||||
{
|
||||
auto cached = mCache.find(agentHalfExtents);
|
||||
if (cached != mCache.end())
|
||||
return;
|
||||
mCache.insert(std::make_pair(agentHalfExtents,
|
||||
std::make_shared<NavMeshCacheItem>(NavMeshCacheItem {makeEmptyNavMesh(mSettings), mRevision}))
|
||||
);
|
||||
log("cache add for agent=", agentHalfExtents);
|
||||
}
|
||||
|
||||
void NavMeshManager::reset(const osg::Vec3f& agentHalfExtents)
|
||||
{
|
||||
mCache.erase(agentHalfExtents);
|
||||
}
|
||||
|
||||
void NavMeshManager::update(const osg::Vec3f& agentHalfExtents)
|
||||
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)
|
||||
{
|
||||
auto cached = mCache.find(agentHalfExtents);
|
||||
if (cached == mCache.end())
|
||||
cached = mCache.insert(std::make_pair(agentHalfExtents,
|
||||
std::make_shared<NavMeshCacheItem>(NavMeshCacheItem {
|
||||
makeEmptyNavMesh(agentHalfExtents, *mRecastMeshManager.getMesh(), mSettings),
|
||||
mRevision
|
||||
}))).first;
|
||||
else if (cached->second->mRevision >= mRevision)
|
||||
const auto& cached = getCached(agentHalfExtents);
|
||||
if (cached->mRevision >= mRevision)
|
||||
return;
|
||||
cached->second->mRevision = mRevision;
|
||||
cached->mRevision = mRevision;
|
||||
const auto changedTiles = mChangedTiles.find(agentHalfExtents);
|
||||
if (changedTiles == mChangedTiles.end())
|
||||
if (changedTiles != mChangedTiles.end())
|
||||
{
|
||||
mAsyncNavMeshUpdater.post(agentHalfExtents, mRecastMeshManager.getMesh(), cached->second,
|
||||
std::set<TilePosition>());
|
||||
}
|
||||
else
|
||||
{
|
||||
mAsyncNavMeshUpdater.post(agentHalfExtents, mRecastMeshManager.getMesh(), cached->second,
|
||||
std::move(changedTiles->second));
|
||||
TilePosition playerTile;
|
||||
playerPosition *= mSettings.mRecastScaleFactor;
|
||||
std::swap(playerPosition.y(), playerPosition.z());
|
||||
cached->mValue.raw()->calcTileLoc(playerPosition.ptr(), &playerTile.x(), &playerTile.y());
|
||||
mAsyncNavMeshUpdater.post(agentHalfExtents, mRecastMeshManager.getMesh(), cached, playerTile,
|
||||
changedTiles->second);
|
||||
mChangedTiles.erase(changedTiles);
|
||||
log("cache update posted for agent=", agentHalfExtents);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,12 +70,9 @@ namespace DetourNavigator
|
|||
mAsyncNavMeshUpdater.wait();
|
||||
}
|
||||
|
||||
NavMeshConstPtr NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const
|
||||
SharedNavMesh NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const
|
||||
{
|
||||
const auto it = mCache.find(agentHalfExtents);
|
||||
if (it == mCache.end())
|
||||
return nullptr;
|
||||
return it->second->mValue;
|
||||
return getCached(agentHalfExtents)->mValue;
|
||||
}
|
||||
|
||||
void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform)
|
||||
|
@ -85,29 +89,36 @@ namespace DetourNavigator
|
|||
{
|
||||
if (const auto& item = v.second)
|
||||
{
|
||||
if (const auto& navMesh = item->mValue)
|
||||
{
|
||||
auto& changedTiles = mChangedTiles[v.first];
|
||||
auto& changedTiles = mChangedTiles[v.first];
|
||||
|
||||
int minTileX;
|
||||
int minTileY;
|
||||
navMesh->calcTileLoc(min.ptr(), &minTileX, &minTileY);
|
||||
int minTileX;
|
||||
int minTileY;
|
||||
item->mValue.raw()->calcTileLoc(min.ptr(), &minTileX, &minTileY);
|
||||
|
||||
int maxTileX;
|
||||
int maxTileY;
|
||||
navMesh->calcTileLoc(max.ptr(), &maxTileX, &maxTileY);
|
||||
int maxTileX;
|
||||
int maxTileY;
|
||||
item->mValue.raw()->calcTileLoc(max.ptr(), &maxTileX, &maxTileY);
|
||||
|
||||
if (minTileX > maxTileX)
|
||||
std::swap(minTileX, maxTileX);
|
||||
if (minTileX > maxTileX)
|
||||
std::swap(minTileX, maxTileX);
|
||||
|
||||
if (minTileY > maxTileY)
|
||||
std::swap(minTileY, maxTileY);
|
||||
if (minTileY > maxTileY)
|
||||
std::swap(minTileY, maxTileY);
|
||||
|
||||
for (int tileX = minTileX; tileX <= maxTileX; ++tileX)
|
||||
for (int tileY = minTileY; tileY <= maxTileY; ++tileY)
|
||||
changedTiles.insert(TilePosition {tileX, tileY});
|
||||
}
|
||||
for (int tileX = minTileX; tileX <= maxTileX; ++tileX)
|
||||
for (int tileY = minTileY; tileY <= maxTileY; ++tileY)
|
||||
changedTiles.insert(TilePosition {tileX, tileY});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<NavMeshCacheItem>& NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const
|
||||
{
|
||||
const auto cached = mCache.find(agentHalfExtents);
|
||||
if (cached != mCache.end())
|
||||
return cached->second;
|
||||
std::ostringstream stream;
|
||||
stream << "Agent with half extents is not found: " << agentHalfExtents;
|
||||
throw InvalidArgument(stream.str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include "asyncnavmeshupdater.hpp"
|
||||
#include "cachedrecastmeshmanager.hpp"
|
||||
#include "sharednavmesh.hpp"
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
|
||||
|
@ -15,8 +18,6 @@ class dtNavMesh;
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
using NavMeshConstPtr = std::shared_ptr<const dtNavMesh>;
|
||||
|
||||
class NavMeshManager
|
||||
{
|
||||
public:
|
||||
|
@ -34,13 +35,15 @@ namespace DetourNavigator
|
|||
|
||||
bool removeObject(std::size_t id);
|
||||
|
||||
void addAgent(const osg::Vec3f& agentHalfExtents);
|
||||
|
||||
void reset(const osg::Vec3f& agentHalfExtents);
|
||||
|
||||
void update(const osg::Vec3f& agentHalfExtents);
|
||||
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);
|
||||
|
||||
void wait();
|
||||
|
||||
NavMeshConstPtr getNavMesh(const osg::Vec3f& agentHalfExtents) const;
|
||||
SharedNavMesh getNavMesh(const osg::Vec3f& agentHalfExtents) const;
|
||||
|
||||
private:
|
||||
std::size_t mRevision = 0;
|
||||
|
@ -51,6 +54,8 @@ namespace DetourNavigator
|
|||
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
|
||||
|
||||
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform);
|
||||
|
||||
const std::shared_ptr<NavMeshCacheItem>& getCached(const osg::Vec3f& agentHalfExtents) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
58
components/detournavigator/sharednavmesh.hpp
Normal file
58
components/detournavigator/sharednavmesh.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_SHAREDNAVMESH_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_SHAREDNAVMESH_H
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
class dtNavMesh;
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
using NavMeshPtr = std::shared_ptr<dtNavMesh>;
|
||||
|
||||
class LockedSharedNavMesh
|
||||
{
|
||||
public:
|
||||
LockedSharedNavMesh(std::mutex& mutex, const NavMeshPtr& value)
|
||||
: mLock(new std::lock_guard<std::mutex>(mutex)), mValue(value)
|
||||
{}
|
||||
|
||||
dtNavMesh* operator ->() const
|
||||
{
|
||||
return mValue.get();
|
||||
}
|
||||
|
||||
dtNavMesh& operator *() const
|
||||
{
|
||||
return *mValue;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<const std::lock_guard<std::mutex>> mLock;
|
||||
NavMeshPtr mValue;
|
||||
};
|
||||
|
||||
class SharedNavMesh
|
||||
{
|
||||
public:
|
||||
SharedNavMesh(const NavMeshPtr& value)
|
||||
: mMutex(std::make_shared<std::mutex>()), mValue(value)
|
||||
{}
|
||||
|
||||
LockedSharedNavMesh lock() const
|
||||
{
|
||||
return LockedSharedNavMesh(*mMutex, mValue);
|
||||
}
|
||||
|
||||
NavMeshPtr raw() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::mutex> mMutex;
|
||||
NavMeshPtr mValue;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue