mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 02:23:51 +00:00
Support water for NavMesh
This commit is contained in:
parent
72f211ef28
commit
c95cea414c
27 changed files with 633 additions and 79 deletions
|
@ -282,6 +282,9 @@ namespace MWWorld
|
||||||
mPhysics->remove(ptr);
|
mPhysics->remove(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto cellX = (*iter)->getCell()->getGridX();
|
||||||
|
const auto cellY = (*iter)->getCell()->getGridY();
|
||||||
|
|
||||||
if ((*iter)->getCell()->isExterior())
|
if ((*iter)->getCell()->isExterior())
|
||||||
{
|
{
|
||||||
const ESM::Land* land =
|
const ESM::Land* land =
|
||||||
|
@ -291,14 +294,15 @@ namespace MWWorld
|
||||||
);
|
);
|
||||||
if (land && land->mDataTypes&ESM::Land::DATA_VHGT)
|
if (land && land->mDataTypes&ESM::Land::DATA_VHGT)
|
||||||
{
|
{
|
||||||
const auto cellX = (*iter)->getCell()->getGridX();
|
|
||||||
const auto cellY = (*iter)->getCell()->getGridY();
|
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||||
navigator->removeObject(reinterpret_cast<std::size_t>(heightField));
|
navigator->removeObject(reinterpret_cast<std::size_t>(heightField));
|
||||||
mPhysics->removeHeightField(cellX, cellY);
|
mPhysics->removeHeightField(cellX, cellY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((*iter)->getCell()->hasWater())
|
||||||
|
navigator->removeWater(osg::Vec2i(cellX, cellY));
|
||||||
|
|
||||||
navigator->update(player.getRefData().getPosition().asVec3());
|
navigator->update(player.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
||||||
|
@ -326,11 +330,12 @@ namespace MWWorld
|
||||||
|
|
||||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||||
|
|
||||||
|
const int cellX = cell->getCell()->getGridX();
|
||||||
|
const int cellY = cell->getCell()->getGridY();
|
||||||
|
|
||||||
// Load terrain physics first...
|
// Load terrain physics first...
|
||||||
if (cell->getCell()->isExterior())
|
if (cell->getCell()->isExterior())
|
||||||
{
|
{
|
||||||
int cellX = cell->getCell()->getGridX();
|
|
||||||
int cellY = cell->getCell()->getGridY();
|
|
||||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : 0;
|
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : 0;
|
||||||
if (data)
|
if (data)
|
||||||
|
@ -368,6 +373,18 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
mPhysics->enableWater(waterLevel);
|
mPhysics->enableWater(waterLevel);
|
||||||
mRendering.setWaterHeight(waterLevel);
|
mRendering.setWaterHeight(waterLevel);
|
||||||
|
|
||||||
|
if (cell->getCell()->isExterior())
|
||||||
|
{
|
||||||
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||||
|
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
|
||||||
|
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
|
||||||
|
cell->getWaterLevel(), btTransform::getIdentity());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mPhysics->disableWater();
|
mPhysics->disableWater();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
|
@ -27,6 +28,11 @@ namespace Loading
|
||||||
class Listener;
|
class Listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace DetourNavigator
|
||||||
|
{
|
||||||
|
class Water;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
class SkyManager;
|
class SkyManager;
|
||||||
|
|
|
@ -168,42 +168,6 @@ namespace MWWorld
|
||||||
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0),
|
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0),
|
||||||
mPlayerTraveling(false), mPlayerInJail(false), mSpellPreloadTimer(0.f)
|
mPlayerTraveling(false), mPlayerInJail(false), mSpellPreloadTimer(0.f)
|
||||||
{
|
{
|
||||||
mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode));
|
|
||||||
|
|
||||||
DetourNavigator::Settings navigatorSettings;
|
|
||||||
navigatorSettings.mBorderSize = Settings::Manager::getInt("border size", "Navigator");
|
|
||||||
navigatorSettings.mCellHeight = Settings::Manager::getFloat("cell height", "Navigator");
|
|
||||||
navigatorSettings.mCellSize = Settings::Manager::getFloat("cell size", "Navigator");
|
|
||||||
navigatorSettings.mDetailSampleDist = Settings::Manager::getFloat("detail sample dist", "Navigator");
|
|
||||||
navigatorSettings.mDetailSampleMaxError = Settings::Manager::getFloat("detail sample max error", "Navigator");
|
|
||||||
navigatorSettings.mMaxClimb = MWPhysics::sStepSizeUp;
|
|
||||||
navigatorSettings.mMaxSimplificationError = Settings::Manager::getFloat("max simplification error", "Navigator");
|
|
||||||
navigatorSettings.mMaxSlope = MWPhysics::sMaxSlope;
|
|
||||||
navigatorSettings.mRecastScaleFactor = Settings::Manager::getFloat("recast scale factor", "Navigator");
|
|
||||||
navigatorSettings.mMaxEdgeLen = Settings::Manager::getInt("max edge len", "Navigator");
|
|
||||||
navigatorSettings.mMaxNavMeshQueryNodes = Settings::Manager::getInt("max nav mesh query nodes", "Navigator");
|
|
||||||
navigatorSettings.mMaxVertsPerPoly = Settings::Manager::getInt("max verts per poly", "Navigator");
|
|
||||||
navigatorSettings.mRegionMergeSize = Settings::Manager::getInt("region merge size", "Navigator");
|
|
||||||
navigatorSettings.mRegionMinSize = Settings::Manager::getInt("region min size", "Navigator");
|
|
||||||
navigatorSettings.mTileSize = Settings::Manager::getInt("tile size", "Navigator");
|
|
||||||
navigatorSettings.mMaxPolygonPathSize = static_cast<std::size_t>(Settings::Manager::getInt("max polygon path size", "Navigator"));
|
|
||||||
navigatorSettings.mMaxSmoothPathSize = static_cast<std::size_t>(Settings::Manager::getInt("max smooth path size", "Navigator"));
|
|
||||||
navigatorSettings.mTrianglesPerChunk = static_cast<std::size_t>(Settings::Manager::getInt("triangles per chunk", "Navigator"));
|
|
||||||
navigatorSettings.mEnableWriteRecastMeshToFile = Settings::Manager::getBool("enable write recast mesh to file", "Navigator");
|
|
||||||
navigatorSettings.mEnableWriteNavMeshToFile = Settings::Manager::getBool("enable write nav mesh to file", "Navigator");
|
|
||||||
navigatorSettings.mRecastMeshPathPrefix = Settings::Manager::getString("recast mesh path prefix", "Navigator");
|
|
||||||
navigatorSettings.mNavMeshPathPrefix = Settings::Manager::getString("nav mesh path prefix", "Navigator");
|
|
||||||
navigatorSettings.mEnableRecastMeshFileNameRevision = Settings::Manager::getBool("enable recast mesh file name revision", "Navigator");
|
|
||||||
navigatorSettings.mEnableNavMeshFileNameRevision = Settings::Manager::getBool("enable nav mesh file name revision", "Navigator");
|
|
||||||
if (Settings::Manager::getBool("enable log", "Navigator"))
|
|
||||||
DetourNavigator::Log::instance().setSink(std::unique_ptr<DetourNavigator::FileSink>(
|
|
||||||
new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator"))));
|
|
||||||
mNavigator.reset(new DetourNavigator::Navigator(navigatorSettings));
|
|
||||||
|
|
||||||
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath, *mNavigator));
|
|
||||||
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get()));
|
|
||||||
mRendering->preloadCommonAssets();
|
|
||||||
|
|
||||||
mEsm.resize(contentFiles.size());
|
mEsm.resize(contentFiles.size());
|
||||||
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
listener->loadingOn();
|
listener->loadingOn();
|
||||||
|
@ -232,6 +196,43 @@ namespace MWWorld
|
||||||
|
|
||||||
mSwimHeightScale = mStore.get<ESM::GameSetting>().find("fSwimHeightScale")->mValue.getFloat();
|
mSwimHeightScale = mStore.get<ESM::GameSetting>().find("fSwimHeightScale")->mValue.getFloat();
|
||||||
|
|
||||||
|
mPhysics.reset(new MWPhysics::PhysicsSystem(resourceSystem, rootNode));
|
||||||
|
|
||||||
|
DetourNavigator::Settings navigatorSettings;
|
||||||
|
navigatorSettings.mBorderSize = Settings::Manager::getInt("border size", "Navigator");
|
||||||
|
navigatorSettings.mCellHeight = Settings::Manager::getFloat("cell height", "Navigator");
|
||||||
|
navigatorSettings.mCellSize = Settings::Manager::getFloat("cell size", "Navigator");
|
||||||
|
navigatorSettings.mDetailSampleDist = Settings::Manager::getFloat("detail sample dist", "Navigator");
|
||||||
|
navigatorSettings.mDetailSampleMaxError = Settings::Manager::getFloat("detail sample max error", "Navigator");
|
||||||
|
navigatorSettings.mMaxClimb = MWPhysics::sStepSizeUp;
|
||||||
|
navigatorSettings.mMaxSimplificationError = Settings::Manager::getFloat("max simplification error", "Navigator");
|
||||||
|
navigatorSettings.mMaxSlope = MWPhysics::sMaxSlope;
|
||||||
|
navigatorSettings.mRecastScaleFactor = Settings::Manager::getFloat("recast scale factor", "Navigator");
|
||||||
|
navigatorSettings.mSwimHeightScale = mSwimHeightScale;
|
||||||
|
navigatorSettings.mMaxEdgeLen = Settings::Manager::getInt("max edge len", "Navigator");
|
||||||
|
navigatorSettings.mMaxNavMeshQueryNodes = Settings::Manager::getInt("max nav mesh query nodes", "Navigator");
|
||||||
|
navigatorSettings.mMaxVertsPerPoly = Settings::Manager::getInt("max verts per poly", "Navigator");
|
||||||
|
navigatorSettings.mRegionMergeSize = Settings::Manager::getInt("region merge size", "Navigator");
|
||||||
|
navigatorSettings.mRegionMinSize = Settings::Manager::getInt("region min size", "Navigator");
|
||||||
|
navigatorSettings.mTileSize = Settings::Manager::getInt("tile size", "Navigator");
|
||||||
|
navigatorSettings.mMaxPolygonPathSize = static_cast<std::size_t>(Settings::Manager::getInt("max polygon path size", "Navigator"));
|
||||||
|
navigatorSettings.mMaxSmoothPathSize = static_cast<std::size_t>(Settings::Manager::getInt("max smooth path size", "Navigator"));
|
||||||
|
navigatorSettings.mTrianglesPerChunk = static_cast<std::size_t>(Settings::Manager::getInt("triangles per chunk", "Navigator"));
|
||||||
|
navigatorSettings.mEnableWriteRecastMeshToFile = Settings::Manager::getBool("enable write recast mesh to file", "Navigator");
|
||||||
|
navigatorSettings.mEnableWriteNavMeshToFile = Settings::Manager::getBool("enable write nav mesh to file", "Navigator");
|
||||||
|
navigatorSettings.mRecastMeshPathPrefix = Settings::Manager::getString("recast mesh path prefix", "Navigator");
|
||||||
|
navigatorSettings.mNavMeshPathPrefix = Settings::Manager::getString("nav mesh path prefix", "Navigator");
|
||||||
|
navigatorSettings.mEnableRecastMeshFileNameRevision = Settings::Manager::getBool("enable recast mesh file name revision", "Navigator");
|
||||||
|
navigatorSettings.mEnableNavMeshFileNameRevision = Settings::Manager::getBool("enable nav mesh file name revision", "Navigator");
|
||||||
|
if (Settings::Manager::getBool("enable log", "Navigator"))
|
||||||
|
DetourNavigator::Log::instance().setSink(std::unique_ptr<DetourNavigator::FileSink>(
|
||||||
|
new DetourNavigator::FileSink(Settings::Manager::getString("log path", "Navigator"))));
|
||||||
|
mNavigator.reset(new DetourNavigator::Navigator(navigatorSettings));
|
||||||
|
|
||||||
|
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath, *mNavigator));
|
||||||
|
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get()));
|
||||||
|
mRendering->preloadCommonAssets();
|
||||||
|
|
||||||
mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering, mFallback, mStore));
|
mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering, mFallback, mStore));
|
||||||
|
|
||||||
mWorldScene.reset(new Scene(*mRendering.get(), mPhysics.get()));
|
mWorldScene.reset(new Scene(*mRendering.get(), mPhysics.get()));
|
||||||
|
|
|
@ -48,6 +48,7 @@ namespace
|
||||||
mSettings.mMaxSimplificationError = 1.3f;
|
mSettings.mMaxSimplificationError = 1.3f;
|
||||||
mSettings.mMaxSlope = 49;
|
mSettings.mMaxSlope = 49;
|
||||||
mSettings.mRecastScaleFactor = 0.017647058823529415f;
|
mSettings.mRecastScaleFactor = 0.017647058823529415f;
|
||||||
|
mSettings.mSwimHeightScale = 0.89999997615814208984375f;
|
||||||
mSettings.mMaxEdgeLen = 12;
|
mSettings.mMaxEdgeLen = 12;
|
||||||
mSettings.mMaxNavMeshQueryNodes = 2048;
|
mSettings.mMaxNavMeshQueryNodes = 2048;
|
||||||
mSettings.mMaxVertsPerPoly = 6;
|
mSettings.mMaxVertsPerPoly = 6;
|
||||||
|
@ -415,4 +416,142 @@ namespace
|
||||||
osg::Vec3f(215, -215, 1.93937528133392333984375),
|
osg::Vec3f(215, -215, 1.93937528133392333984375),
|
||||||
})) << mPath;
|
})) << mPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_ground_lower_than_water)
|
||||||
|
{
|
||||||
|
std::array<btScalar, 5 * 5> heightfieldData {{
|
||||||
|
-50, -50, -50, -50, 0,
|
||||||
|
-50, -100, -150, -100, -50,
|
||||||
|
-50, -150, -200, -150, -100,
|
||||||
|
-50, -100, -150, -100, -100,
|
||||||
|
0, -50, -100, -100, -100,
|
||||||
|
}};
|
||||||
|
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||||
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity());
|
||||||
|
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||||
|
mNavigator->update(mPlayerPosition);
|
||||||
|
mNavigator->wait();
|
||||||
|
|
||||||
|
mStart.x() = 0;
|
||||||
|
mStart.z() = 300;
|
||||||
|
mEnd.x() = 0;
|
||||||
|
mEnd.z() = 300;
|
||||||
|
|
||||||
|
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||||
|
|
||||||
|
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||||
|
osg::Vec3f(0, 215, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, 186.6666717529296875, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, 158.333343505859375, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, 130.0000152587890625, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, 101.66667938232421875, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, 73.333343505859375, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, 45.0000152587890625, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, 16.6666812896728515625, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -11.66664981842041015625, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -39.999980926513671875, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -68.33331298828125, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -96.66664886474609375, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -124.99997711181640625, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -153.33331298828125, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -181.6666412353515625, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -209.999969482421875, 185.33331298828125),
|
||||||
|
osg::Vec3f(0, -215, 185.33331298828125),
|
||||||
|
})) << mPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water)
|
||||||
|
{
|
||||||
|
std::array<btScalar, 7 * 7> heightfieldData {{
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, -100, -100, -100, -100, -100, 0,
|
||||||
|
0, -100, -150, -150, -150, -100, 0,
|
||||||
|
0, -100, -150, -200, -150, -100, 0,
|
||||||
|
0, -100, -150, -150, -150, -100, 0,
|
||||||
|
0, -100, -100, -100, -100, -100, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
}};
|
||||||
|
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||||
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity());
|
||||||
|
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||||
|
mNavigator->update(mPlayerPosition);
|
||||||
|
mNavigator->wait();
|
||||||
|
|
||||||
|
mStart.x() = 0;
|
||||||
|
mEnd.x() = 0;
|
||||||
|
|
||||||
|
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||||
|
|
||||||
|
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||||
|
osg::Vec3f(0, 215, -94.75363922119140625),
|
||||||
|
osg::Vec3f(0, 186.6666717529296875, -106.0000152587890625),
|
||||||
|
osg::Vec3f(0, 158.333343505859375, -115.85507965087890625),
|
||||||
|
osg::Vec3f(0, 130.0000152587890625, -125.71016693115234375),
|
||||||
|
osg::Vec3f(0, 101.66667938232421875, -135.5652313232421875),
|
||||||
|
osg::Vec3f(0, 73.333343505859375, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, 45.0000152587890625, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, 16.6666812896728515625, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -11.66664981842041015625, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -39.999980926513671875, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -68.33331298828125, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875),
|
||||||
|
osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375),
|
||||||
|
osg::Vec3f(0, -153.33331298828125, -117.5942230224609375),
|
||||||
|
osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625),
|
||||||
|
osg::Vec3f(0, -209.999969482421875, -97.79712677001953125),
|
||||||
|
osg::Vec3f(0, -215, -94.753631591796875),
|
||||||
|
})) << mPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water_with_max_int_cells_size)
|
||||||
|
{
|
||||||
|
std::array<btScalar, 7 * 7> heightfieldData {{
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, -100, -100, -100, -100, -100, 0,
|
||||||
|
0, -100, -150, -150, -150, -100, 0,
|
||||||
|
0, -100, -150, -200, -150, -100, 0,
|
||||||
|
0, -100, -150, -150, -150, -100, 0,
|
||||||
|
0, -100, -100, -100, -100, -100, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
}};
|
||||||
|
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||||
|
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
|
mNavigator->addAgent(mAgentHalfExtents);
|
||||||
|
mNavigator->addObject(1, shape, btTransform::getIdentity());
|
||||||
|
mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits<int>::max(), -25, btTransform::getIdentity());
|
||||||
|
mNavigator->update(mPlayerPosition);
|
||||||
|
mNavigator->wait();
|
||||||
|
|
||||||
|
mStart.x() = 0;
|
||||||
|
mEnd.x() = 0;
|
||||||
|
|
||||||
|
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut);
|
||||||
|
|
||||||
|
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||||
|
osg::Vec3f(0, 215, -94.75363922119140625),
|
||||||
|
osg::Vec3f(0, 186.6666717529296875, -106.0000152587890625),
|
||||||
|
osg::Vec3f(0, 158.333343505859375, -115.85507965087890625),
|
||||||
|
osg::Vec3f(0, 130.0000152587890625, -125.71016693115234375),
|
||||||
|
osg::Vec3f(0, 101.66667938232421875, -135.5652313232421875),
|
||||||
|
osg::Vec3f(0, 73.333343505859375, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, 45.0000152587890625, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, 16.6666812896728515625, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -11.66664981842041015625, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -39.999980926513671875, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -68.33331298828125, -143.3333587646484375),
|
||||||
|
osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875),
|
||||||
|
osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375),
|
||||||
|
osg::Vec3f(0, -153.33331298828125, -117.5942230224609375),
|
||||||
|
osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625),
|
||||||
|
osg::Vec3f(0, -209.999969482421875, -97.79712677001953125),
|
||||||
|
osg::Vec3f(0, -215, -94.753631591796875),
|
||||||
|
})) << mPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,14 @@
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace DetourNavigator
|
||||||
|
{
|
||||||
|
static inline bool operator ==(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs)
|
||||||
|
{
|
||||||
|
return lhs.mCellSize == rhs.mCellSize && lhs.mTransform == rhs.mTransform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using namespace testing;
|
using namespace testing;
|
||||||
|
@ -391,4 +399,14 @@ namespace
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_null}));
|
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_null}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it)
|
||||||
|
{
|
||||||
|
RecastMeshBuilder builder(mSettings, mBounds);
|
||||||
|
builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300)));
|
||||||
|
const auto recastMesh = builder.create();
|
||||||
|
EXPECT_EQ(recastMesh->getWater(), std::vector<RecastMesh::Water>({
|
||||||
|
RecastMesh::Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))}
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace DetourNavigator
|
||||||
enum AreaType : unsigned char
|
enum AreaType : unsigned char
|
||||||
{
|
{
|
||||||
AreaType_null = RC_NULL_AREA,
|
AreaType_null = RC_NULL_AREA,
|
||||||
|
AreaType_water,
|
||||||
AreaType_ground = RC_WALKABLE_AREA,
|
AreaType_ground = RC_WALKABLE_AREA,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,23 @@ namespace DetourNavigator
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
||||||
|
const btTransform& transform)
|
||||||
|
{
|
||||||
|
if (!mImpl.addWater(cellPosition, cellSize, transform))
|
||||||
|
return false;
|
||||||
|
mCached.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<RecastMeshManager::Water> CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
|
{
|
||||||
|
const auto water = mImpl.removeWater(cellPosition);
|
||||||
|
if (water)
|
||||||
|
mCached.reset();
|
||||||
|
return water;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> CachedRecastMeshManager::getMesh()
|
std::shared_ptr<RecastMesh> CachedRecastMeshManager::getMesh()
|
||||||
{
|
{
|
||||||
if (!mCached)
|
if (!mCached)
|
||||||
|
|
|
@ -17,6 +17,10 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool updateObject(std::size_t id, const btTransform& transform, const AreaType areaType);
|
bool updateObject(std::size_t id, const btTransform& transform, const AreaType areaType);
|
||||||
|
|
||||||
|
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||||
|
|
||||||
|
boost::optional<RecastMeshManager::Water> removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh();
|
std::shared_ptr<RecastMesh> getMesh();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "dtstatus.hpp"
|
#include "dtstatus.hpp"
|
||||||
#include "exceptions.hpp"
|
#include "exceptions.hpp"
|
||||||
|
#include "flags.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
#include "settingsutils.hpp"
|
#include "settingsutils.hpp"
|
||||||
|
|
||||||
|
@ -10,6 +11,8 @@
|
||||||
#include <DetourNavMesh.h>
|
#include <DetourNavMesh.h>
|
||||||
#include <DetourNavMeshQuery.h>
|
#include <DetourNavMeshQuery.h>
|
||||||
|
|
||||||
|
#include <LinearMath/btVector3.h>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
@ -27,6 +30,11 @@ namespace DetourNavigator
|
||||||
return osg::Vec3f(values[0], values[1], values[2]);
|
return osg::Vec3f(values[0], values[1], values[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline osg::Vec3f makeOsgVec3f(const btVector3& value)
|
||||||
|
{
|
||||||
|
return osg::Vec3f(value.x(), value.y(), value.z());
|
||||||
|
}
|
||||||
|
|
||||||
inline bool inRange(const osg::Vec3f& v1, const osg::Vec3f& v2, const float r, const float h)
|
inline bool inRange(const osg::Vec3f& v1, const osg::Vec3f& v2, const float r, const float h)
|
||||||
{
|
{
|
||||||
const auto d = v2 - v1;
|
const auto d = v2 - v1;
|
||||||
|
@ -217,6 +225,7 @@ namespace DetourNavigator
|
||||||
OPENMW_CHECK_DT_STATUS(navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes));
|
OPENMW_CHECK_DT_STATUS(navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes));
|
||||||
|
|
||||||
dtQueryFilter queryFilter;
|
dtQueryFilter queryFilter;
|
||||||
|
queryFilter.setIncludeFlags(Flag_swim | Flag_walk);
|
||||||
|
|
||||||
dtPolyRef startRef = 0;
|
dtPolyRef startRef = 0;
|
||||||
osg::Vec3f startPolygonPosition;
|
osg::Vec3f startPolygonPosition;
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
Flag_none = 0,
|
Flag_none = 0,
|
||||||
Flag_walk = 1 << 0,
|
Flag_walk = 1 << 0,
|
||||||
|
Flag_swim = 1 << 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,23 @@ namespace DetourNavigator
|
||||||
|
|
||||||
getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward<Callback>(callback));
|
getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward<Callback>(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Callback>
|
||||||
|
void getTilesPositions(const int cellSize, const btTransform& transform,
|
||||||
|
const Settings& settings, Callback&& callback)
|
||||||
|
{
|
||||||
|
const auto halfCellSize = cellSize / 2;
|
||||||
|
auto aabbMin = transform(btVector3(-halfCellSize, -halfCellSize, 0));
|
||||||
|
auto aabbMax = transform(btVector3(halfCellSize, halfCellSize, 0));
|
||||||
|
|
||||||
|
aabbMin.setX(std::min(aabbMin.x(), aabbMax.x()));
|
||||||
|
aabbMin.setY(std::min(aabbMin.y(), aabbMax.y()));
|
||||||
|
|
||||||
|
aabbMax.setX(std::max(aabbMin.x(), aabbMax.x()));
|
||||||
|
aabbMax.setY(std::max(aabbMin.y(), aabbMax.y()));
|
||||||
|
|
||||||
|
getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward<Callback>(callback));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <Recast.h>
|
#include <Recast.h>
|
||||||
#include <RecastAlloc.h>
|
#include <RecastAlloc.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
@ -64,6 +65,41 @@ namespace
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
osg::Vec3f makeOsgVec3f(const btVector3& value)
|
||||||
|
{
|
||||||
|
return osg::Vec3f(value.x(), value.y(), value.z());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WaterBounds
|
||||||
|
{
|
||||||
|
osg::Vec3f mMin;
|
||||||
|
osg::Vec3f mMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
WaterBounds getWaterBounds(const RecastMesh::Water& water, const Settings& settings,
|
||||||
|
const osg::Vec3f& agentHalfExtents)
|
||||||
|
{
|
||||||
|
if (water.mCellSize == std::numeric_limits<int>::max())
|
||||||
|
{
|
||||||
|
const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z());
|
||||||
|
const auto min = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-1, -1, 0))));
|
||||||
|
const auto max = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(1, 1, 0))));
|
||||||
|
return WaterBounds {
|
||||||
|
osg::Vec3f(-std::numeric_limits<float>::max(), min.y(), -std::numeric_limits<float>::max()),
|
||||||
|
osg::Vec3f(std::numeric_limits<float>::max(), max.y(), std::numeric_limits<float>::max())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z());
|
||||||
|
const auto halfCellSize = water.mCellSize / 2.0f;
|
||||||
|
return WaterBounds {
|
||||||
|
toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))),
|
||||||
|
toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0))))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||||
const int tileX, const int tileY, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
|
const int tileX, const int tileY, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
|
@ -156,6 +192,56 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::array<unsigned char, 2> areas {{AreaType_water, AreaType_water}};
|
||||||
|
|
||||||
|
for (const auto& water : recastMesh.getWater())
|
||||||
|
{
|
||||||
|
const auto bounds = getWaterBounds(water, settings, agentHalfExtents);
|
||||||
|
|
||||||
|
const osg::Vec2f tileBoundsMin(
|
||||||
|
std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMin.x())),
|
||||||
|
std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMin.z()))
|
||||||
|
);
|
||||||
|
const osg::Vec2f tileBoundsMax(
|
||||||
|
std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMax.x())),
|
||||||
|
std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMax.z()))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tileBoundsMax == tileBoundsMin)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::array<osg::Vec3f, 4> vertices {{
|
||||||
|
osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMin.y()),
|
||||||
|
osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMax.y()),
|
||||||
|
osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMax.y()),
|
||||||
|
osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMin.y()),
|
||||||
|
}};
|
||||||
|
|
||||||
|
std::array<float, 4 * 3> convertedVertices;
|
||||||
|
auto convertedVerticesIt = convertedVertices.begin();
|
||||||
|
|
||||||
|
for (const auto& vertex : vertices)
|
||||||
|
convertedVerticesIt = std::copy(vertex.ptr(), vertex.ptr() + 3, convertedVerticesIt);
|
||||||
|
|
||||||
|
const std::array<int, 6> indices {{
|
||||||
|
0, 1, 2,
|
||||||
|
0, 2, 3,
|
||||||
|
}};
|
||||||
|
|
||||||
|
OPENMW_CHECK_DT_RESULT(rcRasterizeTriangles(
|
||||||
|
&context,
|
||||||
|
convertedVertices.data(),
|
||||||
|
static_cast<int>(convertedVertices.size() / 3),
|
||||||
|
indices.data(),
|
||||||
|
areas.data(),
|
||||||
|
static_cast<int>(areas.size()),
|
||||||
|
solid,
|
||||||
|
config.walkableClimb
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
|
rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid);
|
||||||
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
|
rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid);
|
||||||
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
|
rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid);
|
||||||
|
@ -187,8 +273,12 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < polyMesh.npolys; ++i)
|
for (int i = 0; i < polyMesh.npolys; ++i)
|
||||||
|
{
|
||||||
if (polyMesh.areas[i] == AreaType_ground)
|
if (polyMesh.areas[i] == AreaType_ground)
|
||||||
polyMesh.flags[i] = Flag_walk;
|
polyMesh.flags[i] = Flag_walk;
|
||||||
|
else if (polyMesh.areas[i] == AreaType_water)
|
||||||
|
polyMesh.flags[i] = Flag_swim;
|
||||||
|
}
|
||||||
|
|
||||||
dtNavMeshCreateParams params;
|
dtNavMeshCreateParams params;
|
||||||
params.verts = polyMesh.verts;
|
params.verts = polyMesh.verts;
|
||||||
|
@ -302,8 +392,15 @@ namespace DetourNavigator
|
||||||
return removeTile();
|
return removeTile();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& boundsMin = recastMesh->getBoundsMin();
|
auto boundsMin = recastMesh->getBoundsMin();
|
||||||
const auto& boundsMax = recastMesh->getBoundsMax();
|
auto boundsMax = recastMesh->getBoundsMax();
|
||||||
|
|
||||||
|
for (const auto& water : recastMesh->getWater())
|
||||||
|
{
|
||||||
|
const auto bounds = getWaterBounds(water, settings, agentHalfExtents);
|
||||||
|
boundsMin.y() = std::min(boundsMin.y(), bounds.mMin.y());
|
||||||
|
boundsMax.y() = std::max(boundsMax.y(), bounds.mMax.y());
|
||||||
|
}
|
||||||
|
|
||||||
if (boundsMin == boundsMax)
|
if (boundsMin == boundsMax)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
|
||||||
|
|
||||||
class dtNavMesh;
|
class dtNavMesh;
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,24 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
bool result = mNavMeshManager.removeObject(id);
|
bool result = mNavMeshManager.removeObject(id);
|
||||||
const auto avoid = mAvoidIds.find(id);
|
const auto avoid = mAvoidIds.find(id);
|
||||||
if (avoid == mAvoidIds.end())
|
if (avoid != mAvoidIds.end())
|
||||||
return result;
|
result = mNavMeshManager.removeObject(avoid->second) || result;
|
||||||
return mNavMeshManager.removeObject(avoid->second) || result;
|
const auto water = mWaterIds.find(id);
|
||||||
|
if (water != mWaterIds.end())
|
||||||
|
result = mNavMeshManager.removeObject(water->second) || result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigator::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level,
|
||||||
|
const btTransform& transform)
|
||||||
|
{
|
||||||
|
return mNavMeshManager.addWater(cellPosition, cellSize,
|
||||||
|
btTransform(transform.getBasis(), btVector3(transform.getOrigin().x(), transform.getOrigin().y(), level)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Navigator::removeWater(const osg::Vec2i& cellPosition)
|
||||||
|
{
|
||||||
|
return mNavMeshManager.removeWater(cellPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Navigator::update(const osg::Vec3f& playerPosition)
|
void Navigator::update(const osg::Vec3f& playerPosition)
|
||||||
|
@ -97,13 +112,23 @@ namespace DetourNavigator
|
||||||
return mSettings;
|
return mSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Navigator::updateAvoidShapeId(std::size_t id, std::size_t avoidId)
|
void Navigator::updateAvoidShapeId(const std::size_t id, const std::size_t avoidId)
|
||||||
{
|
{
|
||||||
auto inserted = mAvoidIds.insert(std::make_pair(id, avoidId));
|
updateId(id, avoidId, mWaterIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Navigator::updateWaterShapeId(const std::size_t id, const std::size_t waterId)
|
||||||
|
{
|
||||||
|
updateId(id, waterId, mWaterIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Navigator::updateId(const std::size_t id, const std::size_t updateId, std::unordered_map<std::size_t, std::size_t>& ids)
|
||||||
|
{
|
||||||
|
auto inserted = ids.insert(std::make_pair(id, updateId));
|
||||||
if (!inserted.second)
|
if (!inserted.second)
|
||||||
{
|
{
|
||||||
mNavMeshManager.removeObject(inserted.first->second);
|
mNavMeshManager.removeObject(inserted.first->second);
|
||||||
inserted.second = avoidId;
|
inserted.second = updateId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,11 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool removeObject(std::size_t id);
|
bool removeObject(std::size_t id);
|
||||||
|
|
||||||
|
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level,
|
||||||
|
const btTransform& transform);
|
||||||
|
|
||||||
|
bool removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
void update(const osg::Vec3f& playerPosition);
|
void update(const osg::Vec3f& playerPosition);
|
||||||
|
|
||||||
void wait();
|
void wait();
|
||||||
|
@ -59,8 +64,11 @@ namespace DetourNavigator
|
||||||
NavMeshManager mNavMeshManager;
|
NavMeshManager mNavMeshManager;
|
||||||
std::map<osg::Vec3f, std::size_t> mAgents;
|
std::map<osg::Vec3f, std::size_t> mAgents;
|
||||||
std::unordered_map<std::size_t, std::size_t> mAvoidIds;
|
std::unordered_map<std::size_t, std::size_t> mAvoidIds;
|
||||||
|
std::unordered_map<std::size_t, std::size_t> mWaterIds;
|
||||||
|
|
||||||
void updateAvoidShapeId(std::size_t id, std::size_t avoidId);
|
void updateAvoidShapeId(const std::size_t id, const std::size_t avoidId);
|
||||||
|
void updateWaterShapeId(const std::size_t id, const std::size_t waterId);
|
||||||
|
void updateId(const std::size_t id, const std::size_t waterId, std::unordered_map<std::size_t, std::size_t>& ids);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,23 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NavMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform)
|
||||||
|
{
|
||||||
|
if (!mRecastMeshManager.addWater(cellPosition, cellSize, transform))
|
||||||
|
return false;
|
||||||
|
addChangedTiles(cellSize, transform, ChangeType::add);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NavMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
|
{
|
||||||
|
const auto water = mRecastMeshManager.removeWater(cellPosition);
|
||||||
|
if (!water)
|
||||||
|
return false;
|
||||||
|
addChangedTiles(water->mCellSize, water->mTransform, ChangeType::remove);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void NavMeshManager::addAgent(const osg::Vec3f& agentHalfExtents)
|
void NavMeshManager::addAgent(const osg::Vec3f& agentHalfExtents)
|
||||||
{
|
{
|
||||||
auto cached = mCache.find(agentHalfExtents);
|
auto cached = mCache.find(agentHalfExtents);
|
||||||
|
@ -75,9 +92,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)
|
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)
|
||||||
{
|
{
|
||||||
playerPosition *= mSettings.mRecastScaleFactor;
|
const auto playerTile = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition));
|
||||||
std::swap(playerPosition.y(), playerPosition.z());
|
|
||||||
const auto playerTile = getTilePosition(mSettings, playerPosition);
|
|
||||||
if (mLastRecastMeshManagerRevision >= mRecastMeshManager.getRevision() && mPlayerTile
|
if (mLastRecastMeshManagerRevision >= mRecastMeshManager.getRevision() && mPlayerTile
|
||||||
&& *mPlayerTile == playerTile)
|
&& *mPlayerTile == playerTile)
|
||||||
return;
|
return;
|
||||||
|
@ -140,20 +155,36 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform,
|
void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform,
|
||||||
const ChangeType changeType)
|
const ChangeType changeType)
|
||||||
{
|
{
|
||||||
getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& v) {
|
getTilesPositions(shape, transform, mSettings,
|
||||||
for (const auto& cached : mCache)
|
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
|
||||||
if (cached.second)
|
}
|
||||||
{
|
|
||||||
auto& tiles = mChangedTiles[cached.first];
|
void NavMeshManager::addChangedTiles(const int cellSize, const btTransform& transform,
|
||||||
auto tile = tiles.find(v);
|
const ChangeType changeType)
|
||||||
if (tile == tiles.end())
|
{
|
||||||
tiles.insert(std::make_pair(v, changeType));
|
if (cellSize == std::numeric_limits<int>::max())
|
||||||
else
|
return;
|
||||||
tile->second = addChangeType(tile->second, changeType);
|
|
||||||
}
|
getTilesPositions(cellSize, transform, mSettings,
|
||||||
});
|
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavMeshManager::addChangedTile(const TilePosition& tilePosition, const ChangeType changeType)
|
||||||
|
{
|
||||||
|
for (const auto& cached : mCache)
|
||||||
|
{
|
||||||
|
if (cached.second)
|
||||||
|
{
|
||||||
|
auto& tiles = mChangedTiles[cached.first];
|
||||||
|
auto tile = tiles.find(tilePosition);
|
||||||
|
if (tile == tiles.end())
|
||||||
|
tiles.insert(std::make_pair(tilePosition, changeType));
|
||||||
|
else
|
||||||
|
tile->second = addChangeType(tile->second, changeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<NavMeshCacheItem>& NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const
|
const std::shared_ptr<NavMeshCacheItem>& NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -33,6 +31,10 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void addAgent(const osg::Vec3f& agentHalfExtents);
|
void addAgent(const osg::Vec3f& agentHalfExtents);
|
||||||
|
|
||||||
|
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||||
|
|
||||||
|
bool removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
void reset(const osg::Vec3f& agentHalfExtents);
|
void reset(const osg::Vec3f& agentHalfExtents);
|
||||||
|
|
||||||
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);
|
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);
|
||||||
|
@ -55,6 +57,10 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType);
|
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType);
|
||||||
|
|
||||||
|
void addChangedTiles(const int cellSize, const btTransform& transform, const ChangeType changeType);
|
||||||
|
|
||||||
|
void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType);
|
||||||
|
|
||||||
const std::shared_ptr<NavMeshCacheItem>& getCached(const osg::Vec3f& agentHalfExtents) const;
|
const std::shared_ptr<NavMeshCacheItem>& getCached(const osg::Vec3f& agentHalfExtents) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,11 @@
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
RecastMesh::RecastMesh(std::vector<int> indices, std::vector<float> vertices,
|
RecastMesh::RecastMesh(std::vector<int> indices, std::vector<float> vertices,
|
||||||
std::vector<AreaType> areaTypes, const Settings& settings)
|
std::vector<AreaType> areaTypes, std::vector<Water> water, const Settings& settings)
|
||||||
: mIndices(std::move(indices))
|
: mIndices(std::move(indices))
|
||||||
, mVertices(std::move(vertices))
|
, mVertices(std::move(vertices))
|
||||||
, mAreaTypes(std::move(areaTypes))
|
, mAreaTypes(std::move(areaTypes))
|
||||||
|
, mWater(std::move(water))
|
||||||
, mChunkyTriMesh(mVertices, mIndices, mAreaTypes, settings.mTrianglesPerChunk)
|
, mChunkyTriMesh(mVertices, mIndices, mAreaTypes, settings.mTrianglesPerChunk)
|
||||||
{
|
{
|
||||||
if (getTrianglesCount() != mAreaTypes.size())
|
if (getTrianglesCount() != mAreaTypes.size())
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct Settings;
|
struct Settings;
|
||||||
|
@ -16,8 +18,14 @@ namespace DetourNavigator
|
||||||
class RecastMesh
|
class RecastMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct Water
|
||||||
|
{
|
||||||
|
int mCellSize;
|
||||||
|
btTransform mTransform;
|
||||||
|
};
|
||||||
|
|
||||||
RecastMesh(std::vector<int> indices, std::vector<float> vertices,
|
RecastMesh(std::vector<int> indices, std::vector<float> vertices,
|
||||||
std::vector<AreaType> areaTypes, const Settings& settings);
|
std::vector<AreaType> areaTypes, std::vector<Water> water, const Settings& settings);
|
||||||
|
|
||||||
const std::vector<int>& getIndices() const
|
const std::vector<int>& getIndices() const
|
||||||
{
|
{
|
||||||
|
@ -34,6 +42,11 @@ namespace DetourNavigator
|
||||||
return mAreaTypes;
|
return mAreaTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<Water>& getWater() const
|
||||||
|
{
|
||||||
|
return mWater;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t getVerticesCount() const
|
std::size_t getVerticesCount() const
|
||||||
{
|
{
|
||||||
return mVertices.size() / 3;
|
return mVertices.size() / 3;
|
||||||
|
@ -63,6 +76,7 @@ namespace DetourNavigator
|
||||||
std::vector<int> mIndices;
|
std::vector<int> mIndices;
|
||||||
std::vector<float> mVertices;
|
std::vector<float> mVertices;
|
||||||
std::vector<AreaType> mAreaTypes;
|
std::vector<AreaType> mAreaTypes;
|
||||||
|
std::vector<Water> mWater;
|
||||||
ChunkyTriMesh mChunkyTriMesh;
|
ChunkyTriMesh mChunkyTriMesh;
|
||||||
osg::Vec3f mBoundsMin;
|
osg::Vec3f mBoundsMin;
|
||||||
osg::Vec3f mBoundsMax;
|
osg::Vec3f mBoundsMax;
|
||||||
|
|
|
@ -82,19 +82,16 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
|
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
|
||||||
{
|
{
|
||||||
const auto indexOffset = int(mVertices.size() / 3);
|
const auto indexOffset = static_cast<int>(mVertices.size() / 3);
|
||||||
|
|
||||||
for (int vertex = 0; vertex < shape.getNumVertices(); ++vertex)
|
for (int vertex = 0, count = shape.getNumVertices(); vertex < count; ++vertex)
|
||||||
{
|
{
|
||||||
btVector3 position;
|
btVector3 position;
|
||||||
shape.getVertex(vertex, position);
|
shape.getVertex(vertex, position);
|
||||||
addVertex(transform(position));
|
addVertex(transform(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int vertex = 0; vertex < 12; ++vertex)
|
const std::array<int, 36> indices {{
|
||||||
mAreaTypes.push_back(areaType);
|
|
||||||
|
|
||||||
static const std::array<int, 36> indices {{
|
|
||||||
0, 2, 3,
|
0, 2, 3,
|
||||||
3, 1, 0,
|
3, 1, 0,
|
||||||
0, 4, 6,
|
0, 4, 6,
|
||||||
|
@ -111,11 +108,18 @@ namespace DetourNavigator
|
||||||
|
|
||||||
std::transform(indices.begin(), indices.end(), std::back_inserter(mIndices),
|
std::transform(indices.begin(), indices.end(), std::back_inserter(mIndices),
|
||||||
[&] (int index) { return index + indexOffset; });
|
[&] (int index) { return index + indexOffset; });
|
||||||
|
|
||||||
|
std::generate_n(std::back_inserter(mAreaTypes), 12, [=] { return areaType; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecastMeshBuilder::addWater(const int cellSize, const btTransform& transform)
|
||||||
|
{
|
||||||
|
mWater.push_back(RecastMesh::Water {cellSize, transform});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> RecastMeshBuilder::create() const
|
std::shared_ptr<RecastMesh> RecastMeshBuilder::create() const
|
||||||
{
|
{
|
||||||
return std::make_shared<RecastMesh>(mIndices, mVertices, mAreaTypes, mSettings);
|
return std::make_shared<RecastMesh>(mIndices, mVertices, mAreaTypes, mWater, mSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecastMeshBuilder::reset()
|
void RecastMeshBuilder::reset()
|
||||||
|
@ -123,6 +127,7 @@ namespace DetourNavigator
|
||||||
mIndices.clear();
|
mIndices.clear();
|
||||||
mVertices.clear();
|
mVertices.clear();
|
||||||
mAreaTypes.clear();
|
mAreaTypes.clear();
|
||||||
|
mWater.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
||||||
|
|
|
@ -4,14 +4,17 @@
|
||||||
#include "recastmesh.hpp"
|
#include "recastmesh.hpp"
|
||||||
#include "tilebounds.hpp"
|
#include "tilebounds.hpp"
|
||||||
|
|
||||||
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
|
#include <osg/Vec2f>
|
||||||
|
#include <osg/Vec2i>
|
||||||
|
|
||||||
class btBoxShape;
|
class btBoxShape;
|
||||||
class btCollisionShape;
|
class btCollisionShape;
|
||||||
class btCompoundShape;
|
class btCompoundShape;
|
||||||
class btConcaveShape;
|
class btConcaveShape;
|
||||||
class btHeightfieldTerrainShape;
|
class btHeightfieldTerrainShape;
|
||||||
class btTransform;
|
|
||||||
class btTriangleCallback;
|
class btTriangleCallback;
|
||||||
class btVector3;
|
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
|
@ -30,6 +33,8 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType);
|
void addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType);
|
||||||
|
|
||||||
|
void addWater(const int mCellSize, const btTransform& transform);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> create() const;
|
std::shared_ptr<RecastMesh> create() const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -40,6 +45,7 @@ namespace DetourNavigator
|
||||||
std::vector<int> mIndices;
|
std::vector<int> mIndices;
|
||||||
std::vector<float> mVertices;
|
std::vector<float> mVertices;
|
||||||
std::vector<AreaType> mAreaTypes;
|
std::vector<AreaType> mAreaTypes;
|
||||||
|
std::vector<RecastMesh::Water> mWater;
|
||||||
|
|
||||||
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,26 @@ namespace DetourNavigator
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
||||||
|
const btTransform& transform)
|
||||||
|
{
|
||||||
|
if (!mWater.insert(std::make_pair(cellPosition, Water {cellSize, transform})).second)
|
||||||
|
return false;
|
||||||
|
mShouldRebuild = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<RecastMeshManager::Water> RecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
|
{
|
||||||
|
const auto water = mWater.find(cellPosition);
|
||||||
|
if (water == mWater.end())
|
||||||
|
return boost::none;
|
||||||
|
mShouldRebuild = true;
|
||||||
|
const auto result = water->second;
|
||||||
|
mWater.erase(water);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
|
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
|
||||||
{
|
{
|
||||||
rebuild();
|
rebuild();
|
||||||
|
@ -58,6 +78,8 @@ namespace DetourNavigator
|
||||||
if (!mShouldRebuild)
|
if (!mShouldRebuild)
|
||||||
return;
|
return;
|
||||||
mMeshBuilder.reset();
|
mMeshBuilder.reset();
|
||||||
|
for (const auto& v : mWater)
|
||||||
|
mMeshBuilder.addWater(v.second.mCellSize, v.second.mTransform);
|
||||||
for (const auto& v : mObjects)
|
for (const auto& v : mObjects)
|
||||||
mMeshBuilder.addObject(v.second.getShape(), v.second.getTransform(), v.second.getAreaType());
|
mMeshBuilder.addObject(v.second.getShape(), v.second.getTransform(), v.second.getAreaType());
|
||||||
mShouldRebuild = false;
|
mShouldRebuild = false;
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
|
|
||||||
#include <LinearMath/btTransform.h>
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
|
#include <osg/Vec2i>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
class btCollisionShape;
|
class btCollisionShape;
|
||||||
|
@ -23,6 +26,12 @@ namespace DetourNavigator
|
||||||
class RecastMeshManager
|
class RecastMeshManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct Water
|
||||||
|
{
|
||||||
|
int mCellSize;
|
||||||
|
btTransform mTransform;
|
||||||
|
};
|
||||||
|
|
||||||
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
|
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
|
||||||
|
|
||||||
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform,
|
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform,
|
||||||
|
@ -30,6 +39,10 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool updateObject(std::size_t id, const btTransform& transform, const AreaType areaType);
|
bool updateObject(std::size_t id, const btTransform& transform, const AreaType areaType);
|
||||||
|
|
||||||
|
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||||
|
|
||||||
|
boost::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh();
|
std::shared_ptr<RecastMesh> getMesh();
|
||||||
|
@ -40,6 +53,7 @@ namespace DetourNavigator
|
||||||
bool mShouldRebuild;
|
bool mShouldRebuild;
|
||||||
RecastMeshBuilder mMeshBuilder;
|
RecastMeshBuilder mMeshBuilder;
|
||||||
std::unordered_map<std::size_t, RecastMeshObject> mObjects;
|
std::unordered_map<std::size_t, RecastMeshObject> mObjects;
|
||||||
|
std::map<osg::Vec2i, Water> mWater;
|
||||||
|
|
||||||
void rebuild();
|
void rebuild();
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace DetourNavigator
|
||||||
float mMaxSimplificationError;
|
float mMaxSimplificationError;
|
||||||
float mMaxSlope;
|
float mMaxSlope;
|
||||||
float mRecastScaleFactor;
|
float mRecastScaleFactor;
|
||||||
|
float mSwimHeightScale;
|
||||||
int mBorderSize;
|
int mBorderSize;
|
||||||
int mMaxEdgeLen;
|
int mMaxEdgeLen;
|
||||||
int mMaxNavMeshQueryNodes;
|
int mMaxNavMeshQueryNodes;
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include "tileposition.hpp"
|
#include "tileposition.hpp"
|
||||||
#include "tilebounds.hpp"
|
#include "tilebounds.hpp"
|
||||||
|
|
||||||
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
#include <osg/Vec2f>
|
#include <osg/Vec2f>
|
||||||
#include <osg/Vec2i>
|
#include <osg/Vec2i>
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
@ -68,6 +70,20 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
return settings.mBorderSize * settings.mCellSize;
|
return settings.mBorderSize * settings.mCellSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline float getSwimLevel(const Settings& settings, const float agentHalfExtentsZ)
|
||||||
|
{
|
||||||
|
return - settings.mSwimHeightScale * agentHalfExtentsZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline btTransform getSwimLevelTransform(const Settings& settings, const btTransform& transform,
|
||||||
|
const float agentHalfExtentsZ)
|
||||||
|
{
|
||||||
|
return btTransform(
|
||||||
|
transform.getBasis(),
|
||||||
|
transform.getOrigin() + btVector3(0, 0, getSwimLevel(settings, agentHalfExtentsZ) - agentHalfExtentsZ)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -83,6 +83,80 @@ namespace DetourNavigator
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
||||||
|
const btTransform& transform)
|
||||||
|
{
|
||||||
|
const auto border = getBorderSize(mSettings);
|
||||||
|
|
||||||
|
auto& tilesPositions = mWaterTilesPositions[cellPosition];
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (cellSize == std::numeric_limits<int>::max())
|
||||||
|
{
|
||||||
|
const std::lock_guard<std::mutex> lock(mTilesMutex);
|
||||||
|
for (auto& tile : mTiles)
|
||||||
|
{
|
||||||
|
if (tile.second.addWater(cellPosition, cellSize, transform))
|
||||||
|
{
|
||||||
|
tilesPositions.push_back(tile.first);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getTilesPositions(cellSize, transform, mSettings, [&] (const TilePosition& tilePosition)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mTilesMutex);
|
||||||
|
auto tile = mTiles.find(tilePosition);
|
||||||
|
if (tile == mTiles.end())
|
||||||
|
{
|
||||||
|
auto tileBounds = makeTileBounds(mSettings, tilePosition);
|
||||||
|
tileBounds.mMin -= osg::Vec2f(border, border);
|
||||||
|
tileBounds.mMax += osg::Vec2f(border, border);
|
||||||
|
tile = mTiles.insert(std::make_pair(tilePosition,
|
||||||
|
CachedRecastMeshManager(mSettings, tileBounds))).first;
|
||||||
|
}
|
||||||
|
if (tile->second.addWater(cellPosition, cellSize, transform))
|
||||||
|
{
|
||||||
|
lock.unlock();
|
||||||
|
tilesPositions.push_back(tilePosition);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
++mRevision;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<RecastMeshManager::Water> TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
|
{
|
||||||
|
const auto object = mWaterTilesPositions.find(cellPosition);
|
||||||
|
if (object == mWaterTilesPositions.end())
|
||||||
|
return boost::none;
|
||||||
|
boost::optional<RecastMeshManager::Water> result;
|
||||||
|
for (const auto& tilePosition : object->second)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mTilesMutex);
|
||||||
|
const auto tile = mTiles.find(tilePosition);
|
||||||
|
if (tile == mTiles.end())
|
||||||
|
continue;
|
||||||
|
const auto tileResult = tile->second.removeWater(cellPosition);
|
||||||
|
if (tile->second.isEmpty())
|
||||||
|
mTiles.erase(tile);
|
||||||
|
lock.unlock();
|
||||||
|
if (tileResult && !result)
|
||||||
|
result = tileResult;
|
||||||
|
}
|
||||||
|
if (result)
|
||||||
|
++mRevision;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition)
|
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition)
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> lock(mTilesMutex);
|
const std::lock_guard<std::mutex> lock(mTilesMutex);
|
||||||
|
|
|
@ -21,6 +21,10 @@ namespace DetourNavigator
|
||||||
|
|
||||||
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||||
|
|
||||||
|
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform);
|
||||||
|
|
||||||
|
boost::optional<RecastMeshManager::Water> removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition);
|
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition);
|
||||||
|
|
||||||
bool hasTile(const TilePosition& tilePosition);
|
bool hasTile(const TilePosition& tilePosition);
|
||||||
|
@ -40,6 +44,7 @@ namespace DetourNavigator
|
||||||
std::mutex mTilesMutex;
|
std::mutex mTilesMutex;
|
||||||
std::map<TilePosition, CachedRecastMeshManager> mTiles;
|
std::map<TilePosition, CachedRecastMeshManager> mTiles;
|
||||||
std::unordered_map<std::size_t, std::vector<TilePosition>> mObjectsTilesPositions;
|
std::unordered_map<std::size_t, std::vector<TilePosition>> mObjectsTilesPositions;
|
||||||
|
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;
|
||||||
std::size_t mRevision = 0;
|
std::size_t mRevision = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue