diff --git a/apps/openmw/mwrender/actorspaths.cpp b/apps/openmw/mwrender/actorspaths.cpp index 941f37df75..c8c5f56d8f 100644 --- a/apps/openmw/mwrender/actorspaths.cpp +++ b/apps/openmw/mwrender/actorspaths.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -47,7 +48,7 @@ namespace MWRender if (group != mGroups.end()) mRootNode->removeChild(group->second); - const auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings); + const auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings.mRecast); if (newGroup) { MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug"); diff --git a/apps/openmw/mwrender/recastmesh.cpp b/apps/openmw/mwrender/recastmesh.cpp index f108536242..5f202720b2 100644 --- a/apps/openmw/mwrender/recastmesh.cpp +++ b/apps/openmw/mwrender/recastmesh.cpp @@ -54,7 +54,7 @@ namespace MWRender if (it->second.mGeneration != tile->second->getGeneration() || it->second.mRevision != tile->second->getRevision()) { - const auto group = SceneUtil::createRecastMeshGroup(*tile->second, settings); + const auto group = SceneUtil::createRecastMeshGroup(*tile->second, settings.mRecast); MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(group, "debug"); group->setNodeMask(Mask_Debug); mRootNode->removeChild(it->second.mValue); @@ -71,7 +71,7 @@ namespace MWRender { if (mGroups.count(tile.first)) continue; - const auto group = SceneUtil::createRecastMeshGroup(*tile.second, settings); + const auto group = SceneUtil::createRecastMeshGroup(*tile.second, settings.mRecast); MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(group, "debug"); group->setNodeMask(Mask_Debug); mGroups.emplace(tile.first, Group {tile.second->getGeneration(), tile.second->getRevision(), group}); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d08eef2904..5a937d1a78 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -186,7 +186,7 @@ namespace MWWorld if (Settings::Manager::getBool("enable", "Navigator")) { auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager(); - navigatorSettings.mSwimHeightScale = mSwimHeightScale; + navigatorSettings.mRecast.mSwimHeightScale = mSwimHeightScale; mNavigator = DetourNavigator::makeNavigator(navigatorSettings); } else diff --git a/apps/openmw_test_suite/detournavigator/gettilespositions.cpp b/apps/openmw_test_suite/detournavigator/gettilespositions.cpp index 1ad5c063d0..ced33a99f0 100644 --- a/apps/openmw_test_suite/detournavigator/gettilespositions.cpp +++ b/apps/openmw_test_suite/detournavigator/gettilespositions.cpp @@ -21,7 +21,7 @@ namespace struct DetourNavigatorGetTilesPositionsTest : Test { - Settings mSettings; + RecastSettings mSettings; std::vector mTilesPositions; CollectTilesPositions mCollect {mTilesPositions}; diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 07dcbb2002..b630c261ef 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -63,28 +63,28 @@ namespace mSettings.mEnableWriteNavMeshToFile = false; mSettings.mEnableRecastMeshFileNameRevision = false; mSettings.mEnableNavMeshFileNameRevision = false; - mSettings.mBorderSize = 16; - mSettings.mCellHeight = 0.2f; - mSettings.mCellSize = 0.2f; - mSettings.mDetailSampleDist = 6; - mSettings.mDetailSampleMaxError = 1; - mSettings.mMaxClimb = 34; - mSettings.mMaxSimplificationError = 1.3f; - mSettings.mMaxSlope = 49; - mSettings.mRecastScaleFactor = 0.017647058823529415f; - mSettings.mSwimHeightScale = 0.89999997615814208984375f; - mSettings.mMaxEdgeLen = 12; - mSettings.mMaxNavMeshQueryNodes = 2048; - mSettings.mMaxVertsPerPoly = 6; - mSettings.mRegionMergeSize = 20; - mSettings.mRegionMinSize = 8; - mSettings.mTileSize = 64; + mSettings.mRecast.mBorderSize = 16; + mSettings.mRecast.mCellHeight = 0.2f; + mSettings.mRecast.mCellSize = 0.2f; + mSettings.mRecast.mDetailSampleDist = 6; + mSettings.mRecast.mDetailSampleMaxError = 1; + mSettings.mRecast.mMaxClimb = 34; + mSettings.mRecast.mMaxSimplificationError = 1.3f; + mSettings.mRecast.mMaxSlope = 49; + mSettings.mRecast.mRecastScaleFactor = 0.017647058823529415f; + mSettings.mRecast.mSwimHeightScale = 0.89999997615814208984375f; + mSettings.mRecast.mMaxEdgeLen = 12; + mSettings.mDetour.mMaxNavMeshQueryNodes = 2048; + mSettings.mRecast.mMaxVertsPerPoly = 6; + mSettings.mRecast.mRegionMergeArea = 400; + mSettings.mRecast.mRegionMinArea = 64; + mSettings.mRecast.mTileSize = 64; mSettings.mWaitUntilMinDistanceToPlayer = std::numeric_limits::max(); mSettings.mAsyncNavMeshUpdaterThreads = 1; mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024; - mSettings.mMaxPolygonPathSize = 1024; - mSettings.mMaxSmoothPathSize = 1024; - mSettings.mMaxPolys = 4096; + mSettings.mDetour.mMaxPolygonPathSize = 1024; + mSettings.mDetour.mMaxSmoothPathSize = 1024; + mSettings.mDetour.mMaxPolys = 4096; mSettings.mMaxTilesNumber = 512; mSettings.mMinUpdateInterval = std::chrono::milliseconds(50); mNavigator.reset(new NavigatorImpl(mSettings)); diff --git a/apps/openmw_test_suite/detournavigator/settingsutils.cpp b/apps/openmw_test_suite/detournavigator/settingsutils.cpp index ffed64ab81..f06f3b3e32 100644 --- a/apps/openmw_test_suite/detournavigator/settingsutils.cpp +++ b/apps/openmw_test_suite/detournavigator/settingsutils.cpp @@ -11,7 +11,7 @@ namespace struct DetourNavigatorGetTilePositionTest : Test { - Settings mSettings; + RecastSettings mSettings; DetourNavigatorGetTilePositionTest() { @@ -47,7 +47,7 @@ namespace struct DetourNavigatorMakeTileBoundsTest : Test { - Settings mSettings; + RecastSettings mSettings; DetourNavigatorMakeTileBoundsTest() { diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index eac7f4abbd..9426a3968f 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -15,7 +15,7 @@ namespace struct DetourNavigatorTileCachedRecastMeshManagerTest : Test { - Settings mSettings; + RecastSettings mSettings; std::vector mChangedTiles; const ObjectTransform mObjectTransform {ESM::Position {{0, 0, 0}, {0, 0, 0}}, 0.0f}; const osg::ref_ptr mShape = new Resource::BulletShape; diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 583fd1162a..c2c79a840e 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -404,7 +404,7 @@ namespace DetourNavigator } if (recastMesh && mSettings.get().mEnableWriteRecastMeshToFile) writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix + std::to_string(job.mChangedTile.x()) - + "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision, mSettings); + + "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision, mSettings.get().mRecast); if (mSettings.get().mEnableWriteNavMeshToFile) if (const auto shared = job.mNavMeshCacheItem.lock()) writeToFile(shared->lockConst()->getImpl(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); diff --git a/components/detournavigator/debug.cpp b/components/detournavigator/debug.cpp index 07832d748f..8394c6696d 100644 --- a/components/detournavigator/debug.cpp +++ b/components/detournavigator/debug.cpp @@ -11,7 +11,8 @@ namespace DetourNavigator { - void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, const std::string& revision, const Settings& settings) + void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, + const std::string& revision, const RecastSettings& settings) { const auto path = pathPrefix + "recastmesh" + revision + ".obj"; boost::filesystem::ofstream file(boost::filesystem::path(path), std::ios::out); diff --git a/components/detournavigator/debug.hpp b/components/detournavigator/debug.hpp index 7c86603348..ce1e2d2023 100644 --- a/components/detournavigator/debug.hpp +++ b/components/detournavigator/debug.hpp @@ -70,9 +70,10 @@ namespace DetourNavigator } class RecastMesh; - struct Settings; + struct RecastSettings; - void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, const std::string& revision, const Settings& settings); + void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, + const std::string& revision, const RecastSettings& settings); void writeToFile(const dtNavMesh& navMesh, const std::string& pathPrefix, const std::string& revision); } diff --git a/components/detournavigator/findrandompointaroundcircle.cpp b/components/detournavigator/findrandompointaroundcircle.cpp index a3407a61c3..1e1e2401c5 100644 --- a/components/detournavigator/findrandompointaroundcircle.cpp +++ b/components/detournavigator/findrandompointaroundcircle.cpp @@ -10,7 +10,7 @@ namespace DetourNavigator { std::optional findRandomPointAroundCircle(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, - const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const Settings& settings) + const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const DetourSettings& settings) { dtNavMeshQuery navMeshQuery; if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes)) diff --git a/components/detournavigator/findrandompointaroundcircle.hpp b/components/detournavigator/findrandompointaroundcircle.hpp index d0dc2bbbc0..89a3c0964c 100644 --- a/components/detournavigator/findrandompointaroundcircle.hpp +++ b/components/detournavigator/findrandompointaroundcircle.hpp @@ -10,10 +10,10 @@ class dtNavMesh; namespace DetourNavigator { - struct Settings; + struct DetourSettings; std::optional findRandomPointAroundCircle(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, - const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const Settings& settings); + const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, const DetourSettings& settings); } #endif diff --git a/components/detournavigator/findsmoothpath.hpp b/components/detournavigator/findsmoothpath.hpp index 2e63340578..fa35470c42 100644 --- a/components/detournavigator/findsmoothpath.hpp +++ b/components/detournavigator/findsmoothpath.hpp @@ -60,7 +60,7 @@ namespace DetourNavigator class OutputTransformIterator { public: - OutputTransformIterator(OutputIterator& impl, const Settings& settings) + explicit OutputTransformIterator(OutputIterator& impl, const RecastSettings& settings) : mImpl(impl), mSettings(settings) { } @@ -91,7 +91,7 @@ namespace DetourNavigator private: std::reference_wrapper mImpl; - std::reference_wrapper mSettings; + std::reference_wrapper mSettings; }; inline bool initNavMeshQuery(dtNavMeshQuery& value, const dtNavMesh& navMesh, const int maxNodes) @@ -261,7 +261,7 @@ namespace DetourNavigator const Settings& settings, float endTolerance, OutputIterator& out) { dtNavMeshQuery navMeshQuery; - if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes)) + if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mDetour.mMaxNavMeshQueryNodes)) return Status::InitNavMeshQueryFailed; dtQueryFilter queryFilter; @@ -283,7 +283,7 @@ namespace DetourNavigator if (endRef == 0) return Status::EndPolygonNotFound; - std::vector polygonPath(settings.mMaxPolygonPathSize); + std::vector polygonPath(settings.mDetour.mMaxPolygonPathSize); const auto polygonPathSize = findPath(navMeshQuery, startRef, endRef, start, end, queryFilter, polygonPath.data(), polygonPath.size()); @@ -294,9 +294,9 @@ namespace DetourNavigator return Status::Success; const bool partialPath = polygonPath[*polygonPathSize - 1] != endRef; - auto outTransform = OutputTransformIterator(out, settings); + auto outTransform = OutputTransformIterator(out, settings.mRecast); const Status smoothStatus = makeSmoothPath(navMesh, navMeshQuery, queryFilter, start, end, stepSize, - polygonPath, *polygonPathSize, settings.mMaxSmoothPathSize, outTransform); + polygonPath, *polygonPathSize, settings.mDetour.mMaxSmoothPathSize, outTransform); if (smoothStatus != Status::Success) return smoothStatus; diff --git a/components/detournavigator/gettilespositions.hpp b/components/detournavigator/gettilespositions.hpp index abfce06464..707db0b512 100644 --- a/components/detournavigator/gettilespositions.hpp +++ b/components/detournavigator/gettilespositions.hpp @@ -15,7 +15,7 @@ namespace DetourNavigator { template void getTilesPositions(const osg::Vec3f& aabbMin, const osg::Vec3f& aabbMax, - const Settings& settings, Callback&& callback) + const RecastSettings& settings, Callback&& callback) { auto min = toNavMeshCoordinates(settings, aabbMin); auto max = toNavMeshCoordinates(settings, aabbMax); @@ -40,7 +40,7 @@ namespace DetourNavigator template void getTilesPositions(const btCollisionShape& shape, const btTransform& transform, - const Settings& settings, Callback&& callback) + const RecastSettings& settings, Callback&& callback) { btVector3 aabbMin; btVector3 aabbMax; @@ -51,7 +51,7 @@ namespace DetourNavigator template void getTilesPositions(const int cellSize, const btVector3& shift, - const Settings& settings, Callback&& callback) + const RecastSettings& settings, Callback&& callback) { using Misc::Convert::toOsg; diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 7d478b9c1b..217e2b565e 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -36,32 +36,6 @@ namespace float mHeight; }; - Rectangle getSwimRectangle(const CellWater& water, const Settings& settings, const osg::Vec3f& agentHalfExtents) - { - if (water.mWater.mCellSize == std::numeric_limits::max()) - { - return Rectangle { - TileBounds { - osg::Vec2f(-std::numeric_limits::max(), -std::numeric_limits::max()), - osg::Vec2f(std::numeric_limits::max(), std::numeric_limits::max()) - }, - toNavMeshCoordinates(settings, getSwimLevel(settings, water.mWater.mLevel, agentHalfExtents.z())) - }; - } - else - { - const osg::Vec2f shift = getWaterShift2d(water.mCellPosition, water.mWater.mCellSize); - const float halfCellSize = water.mWater.mCellSize / 2.0f; - return Rectangle { - TileBounds{ - toNavMeshCoordinates(settings, shift + osg::Vec2f(-halfCellSize, -halfCellSize)), - toNavMeshCoordinates(settings, shift + osg::Vec2f(halfCellSize, halfCellSize)) - }, - toNavMeshCoordinates(settings, getSwimLevel(settings, water.mWater.mLevel, agentHalfExtents.z())) - }; - } - } - std::vector getOffMeshVerts(const std::vector& connections) { std::vector result; @@ -120,52 +94,46 @@ namespace return result; } - rcConfig makeConfig(const osg::Vec3f& agentHalfExtents, const TilePosition& tile, float minZ, float maxZ, - const Settings& settings) + float getHeight(const RecastSettings& settings,const osg::Vec3f& agentHalfExtents) { - rcConfig config; - - config.cs = settings.mCellSize; - config.ch = settings.mCellHeight; - config.walkableSlopeAngle = settings.mMaxSlope; - config.walkableHeight = static_cast(std::ceil(getHeight(settings, agentHalfExtents) / config.ch)); - config.walkableClimb = static_cast(std::floor(getMaxClimb(settings) / config.ch)); - config.walkableRadius = static_cast(std::ceil(getRadius(settings, agentHalfExtents) / config.cs)); - config.maxEdgeLen = static_cast(std::round(settings.mMaxEdgeLen / config.cs)); - config.maxSimplificationError = settings.mMaxSimplificationError; - config.minRegionArea = settings.mRegionMinSize * settings.mRegionMinSize; - config.mergeRegionArea = settings.mRegionMergeSize * settings.mRegionMergeSize; - config.maxVertsPerPoly = settings.mMaxVertsPerPoly; - config.detailSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : config.cs * settings.mDetailSampleDist; - config.detailSampleMaxError = config.ch * settings.mDetailSampleMaxError; - config.borderSize = settings.mBorderSize; - config.tileSize = settings.mTileSize; - const int size = config.tileSize + config.borderSize * 2; - config.width = size; - config.height = size; - const float halfBoundsSize = size * config.cs * 0.5f; - const osg::Vec2f shift = osg::Vec2f(tile.x() + 0.5f, tile.y() + 0.5f) * getTileSize(settings); - config.bmin[0] = shift.x() - halfBoundsSize; - config.bmin[1] = minZ; - config.bmin[2] = shift.y() - halfBoundsSize; - config.bmax[0] = shift.x() + halfBoundsSize; - config.bmax[1] = maxZ; - config.bmax[2] = shift.y() + halfBoundsSize; - - return config; + return 2.0f * agentHalfExtents.z() * settings.mRecastScaleFactor; } - void createHeightfield(rcContext& context, rcHeightfield& solid, int width, int height, const float* bmin, - const float* bmax, const float cs, const float ch) + float getMaxClimb(const RecastSettings& settings) { - const auto result = rcCreateHeightfield(&context, solid, width, height, bmin, bmax, cs, ch); + return settings.mMaxClimb * settings.mRecastScaleFactor; + } + + float getRadius(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents) + { + return std::max(agentHalfExtents.x(), agentHalfExtents.y()) * std::sqrt(2) * settings.mRecastScaleFactor; + } + + float getSwimLevel(const RecastSettings& settings, const float waterLevel, const float agentHalfExtentsZ) + { + return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;; + } + + void initHeightfield(rcContext& context, const TilePosition& tilePosition, float minZ, float maxZ, + const RecastSettings& settings, rcHeightfield& solid) + { + const int size = settings.mTileSize + settings.mBorderSize * 2; + const int width = size; + const int height = size; + const float halfBoundsSize = size * settings.mCellSize * 0.5f; + const osg::Vec2f shift = osg::Vec2f(tilePosition.x() + 0.5f, tilePosition.y() + 0.5f) * getTileSize(settings); + const osg::Vec3f bmin(shift.x() - halfBoundsSize, minZ, shift.y() - halfBoundsSize); + const osg::Vec3f bmax(shift.x() + halfBoundsSize, maxZ, shift.y() + halfBoundsSize); + + const auto result = rcCreateHeightfield(&context, solid, width, height, bmin.ptr(), bmax.ptr(), + settings.mCellSize, settings.mCellHeight); if (!result) throw NavigatorException("Failed to create heightfield for navmesh"); } - bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const Settings& settings, const rcConfig& config, - rcHeightfield& solid) + bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const RecastSettings& settings, + const RecastParams& params, rcHeightfield& solid) { std::vector areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end()); std::vector vertices = mesh.getVertices(); @@ -179,7 +147,7 @@ namespace rcClearUnwalkableTriangles( &context, - config.walkableSlopeAngle, + settings.mMaxSlope, vertices.data(), static_cast(mesh.getVerticesCount()), mesh.getIndices().data(), @@ -195,30 +163,18 @@ namespace areas.data(), static_cast(areas.size()), solid, - config.walkableClimb + params.mWalkableClimb ); } - bool rasterizeTriangles(rcContext& context, const Rectangle& rectangle, const rcConfig& config, - AreaType areaType, rcHeightfield& solid) + bool rasterizeTriangles(rcContext& context, const Rectangle& rectangle, AreaType areaType, + const RecastParams& params, rcHeightfield& solid) { - const osg::Vec2f tileBoundsMin( - std::clamp(rectangle.mBounds.mMin.x(), config.bmin[0], config.bmax[0]), - std::clamp(rectangle.mBounds.mMin.y(), config.bmin[2], config.bmax[2]) - ); - const osg::Vec2f tileBoundsMax( - std::clamp(rectangle.mBounds.mMax.x(), config.bmin[0], config.bmax[0]), - std::clamp(rectangle.mBounds.mMax.y(), config.bmin[2], config.bmax[2]) - ); - - if (tileBoundsMax == tileBoundsMin) - return true; - const std::array vertices { - tileBoundsMin.x(), rectangle.mHeight, tileBoundsMin.y(), - tileBoundsMin.x(), rectangle.mHeight, tileBoundsMax.y(), - tileBoundsMax.x(), rectangle.mHeight, tileBoundsMax.y(), - tileBoundsMax.x(), rectangle.mHeight, tileBoundsMin.y(), + rectangle.mBounds.mMin.x(), rectangle.mHeight, rectangle.mBounds.mMin.y(), + rectangle.mBounds.mMin.x(), rectangle.mHeight, rectangle.mBounds.mMax.y(), + rectangle.mBounds.mMax.x(), rectangle.mHeight, rectangle.mBounds.mMax.y(), + rectangle.mBounds.mMax.x(), rectangle.mHeight, rectangle.mBounds.mMin.y(), }; const std::array indices { @@ -236,31 +192,42 @@ namespace areas.data(), static_cast(areas.size()), solid, - config.walkableClimb + params.mWalkableClimb ); } bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector& water, - const Settings& settings, const rcConfig& config, rcHeightfield& solid) + const RecastSettings& settings, const RecastParams& params, const TileBounds& realTileBounds, rcHeightfield& solid) { for (const CellWater& cellWater : water) { - const Rectangle rectangle = getSwimRectangle(cellWater, settings, agentHalfExtents); - if (!rasterizeTriangles(context, rectangle, config, AreaType_water, solid)) - return false; + const TileBounds cellTileBounds = maxCellTileBounds(cellWater.mCellPosition, cellWater.mWater.mCellSize); + if (auto intersection = getIntersection(realTileBounds, cellTileBounds)) + { + const Rectangle rectangle { + toNavMeshCoordinates(settings, *intersection), + toNavMeshCoordinates(settings, getSwimLevel(settings, cellWater.mWater.mLevel, agentHalfExtents.z())) + }; + if (!rasterizeTriangles(context, rectangle, AreaType_water, params, solid)) + return false; + } } return true; } - bool rasterizeTriangles(rcContext& context, const TileBounds& tileBounds, const std::vector& heightfields, - const Settings& settings, const rcConfig& config, rcHeightfield& solid) + bool rasterizeTriangles(rcContext& context, const TileBounds& realTileBounds, const std::vector& heightfields, + const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid) { for (const FlatHeightfield& heightfield : heightfields) { - if (auto intersection = getIntersection(tileBounds, maxCellTileBounds(heightfield.mCellPosition, heightfield.mCellSize))) + const TileBounds cellTileBounds = maxCellTileBounds(heightfield.mCellPosition, heightfield.mCellSize); + if (auto intersection = getIntersection(realTileBounds, cellTileBounds)) { - const Rectangle rectangle {*intersection, toNavMeshCoordinates(settings, heightfield.mHeight)}; - if (!rasterizeTriangles(context, rectangle, config, AreaType_ground, solid)) + const Rectangle rectangle { + toNavMeshCoordinates(settings, *intersection), + toNavMeshCoordinates(settings, heightfield.mHeight) + }; + if (!rasterizeTriangles(context, rectangle, AreaType_ground, params, solid)) return false; } } @@ -268,27 +235,25 @@ namespace } bool rasterizeTriangles(rcContext& context, const std::vector& heightfields, - const Settings& settings, const rcConfig& config, rcHeightfield& solid) + const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid) { - using BulletHelpers::makeProcessTriangleCallback; - for (const Heightfield& heightfield : heightfields) { const Mesh mesh = makeMesh(heightfield); - if (!rasterizeTriangles(context, mesh, settings, config, solid)) + if (!rasterizeTriangles(context, mesh, settings, params, solid)) return false; } return true; } bool rasterizeTriangles(rcContext& context, const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, - const RecastMesh& recastMesh, const rcConfig& config, const Settings& settings, rcHeightfield& solid) + const RecastMesh& recastMesh, const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid) { - return rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid) - && rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, config, solid) - && rasterizeTriangles(context, recastMesh.getHeightfields(), settings, config, solid) - && rasterizeTriangles(context, makeRealTileBoundsWithBorder(settings, tilePosition), - recastMesh.getFlatHeightfields(), settings, config, solid); + const TileBounds realTileBounds = makeRealTileBoundsWithBorder(settings, tilePosition); + return rasterizeTriangles(context, recastMesh.getMesh(), settings, params, solid) + && rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, params, realTileBounds, solid) + && rasterizeTriangles(context, recastMesh.getHeightfields(), settings, params, solid) + && rasterizeTriangles(context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid); } void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb, @@ -359,27 +324,25 @@ namespace polyMesh.flags[i] = getFlag(static_cast(polyMesh.areas[i])); } - bool fillPolyMesh(rcContext& context, const rcConfig& config, rcHeightfield& solid, rcPolyMesh& polyMesh, - rcPolyMeshDetail& polyMeshDetail) + bool fillPolyMesh(rcContext& context, const RecastSettings& settings, const RecastParams& params, + rcHeightfield& solid, rcPolyMesh& polyMesh, rcPolyMeshDetail& polyMeshDetail) { rcCompactHeightfield compact; - compact.dist = nullptr; - buildCompactHeightfield(context, config.walkableHeight, config.walkableClimb, solid, compact); + buildCompactHeightfield(context, params.mWalkableHeight, params.mWalkableClimb, solid, compact); - erodeWalkableArea(context, config.walkableRadius, compact); + erodeWalkableArea(context, params.mWalkableRadius, compact); buildDistanceField(context, compact); - buildRegions(context, compact, config.borderSize, config.minRegionArea, config.mergeRegionArea); + buildRegions(context, compact, settings.mBorderSize, settings.mRegionMinArea, settings.mRegionMergeArea); rcContourSet contourSet; - buildContours(context, compact, config.maxSimplificationError, config.maxEdgeLen, contourSet); + buildContours(context, compact, settings.mMaxSimplificationError, params.mMaxEdgeLen, contourSet); if (contourSet.nconts == 0) return false; - buildPolyMesh(context, contourSet, config.maxVertsPerPoly, polyMesh); + buildPolyMesh(context, contourSet, settings.mMaxVertsPerPoly, polyMesh); - buildPolyMeshDetail(context, polyMesh, compact, config.detailSampleDist, config.detailSampleMaxError, - polyMeshDetail); + buildPolyMeshDetail(context, polyMesh, compact, params.mSampleDist, params.mSampleMaxError, polyMeshDetail); setPolyMeshFlags(polyMesh); @@ -395,7 +358,7 @@ namespace return power; } - std::pair getBoundsByZ(const RecastMesh& recastMesh, const osg::Vec3f& agentHalfExtents, const Settings& settings) + std::pair getBoundsByZ(const RecastMesh& recastMesh, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings) { float minZ = 0; float maxZ = 0; @@ -436,39 +399,54 @@ namespace namespace DetourNavigator { + RecastParams makeRecastParams(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents) + { + RecastParams result; + + result.mWalkableHeight = static_cast(std::ceil(getHeight(settings, agentHalfExtents) / settings.mCellHeight)); + result.mWalkableClimb = static_cast(std::floor(getMaxClimb(settings) / settings.mCellHeight)); + result.mWalkableRadius = static_cast(std::ceil(getRadius(settings, agentHalfExtents) / settings.mCellSize)); + result.mMaxEdgeLen = static_cast(std::round(static_cast(settings.mMaxEdgeLen) / settings.mCellSize)); + result.mSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : settings.mCellSize * settings.mDetailSampleDist; + result.mSampleMaxError = settings.mCellHeight * settings.mDetailSampleMaxError; + + return result; + } + std::unique_ptr prepareNavMeshTileData(const RecastMesh& recastMesh, - const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const Settings& settings) + const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings) { const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentHalfExtents, settings); rcContext context; - const auto config = makeConfig(agentHalfExtents, tilePosition, toNavMeshCoordinates(settings, minZ), - toNavMeshCoordinates(settings, maxZ), settings); rcHeightfield solid; - createHeightfield(context, solid, config.width, config.height, config.bmin, config.bmax, config.cs, config.ch); + initHeightfield(context, tilePosition, toNavMeshCoordinates(settings, minZ), + toNavMeshCoordinates(settings, maxZ), settings, solid); - if (!rasterizeTriangles(context, tilePosition, agentHalfExtents, recastMesh, config, settings, solid)) + const RecastParams params = makeRecastParams(settings, agentHalfExtents); + + if (!rasterizeTriangles(context, tilePosition, agentHalfExtents, recastMesh, settings, params, solid)) return nullptr; - rcFilterLowHangingWalkableObstacles(&context, config.walkableClimb, solid); - rcFilterLedgeSpans(&context, config.walkableHeight, config.walkableClimb, solid); - rcFilterWalkableLowHeightSpans(&context, config.walkableHeight, solid); + rcFilterLowHangingWalkableObstacles(&context, params.mWalkableClimb, solid); + rcFilterLedgeSpans(&context, params.mWalkableHeight, params.mWalkableClimb, solid); + rcFilterWalkableLowHeightSpans(&context, params.mWalkableHeight, solid); std::unique_ptr result = std::make_unique(); - if (!fillPolyMesh(context, config, solid, result->mPolyMesh, result->mPolyMeshDetail)) + if (!fillPolyMesh(context, settings, params, solid, result->mPolyMesh, result->mPolyMeshDetail)) return nullptr; - result->mCellSize = config.cs; - result->mCellHeight = config.ch; + result->mCellSize = settings.mCellSize; + result->mCellHeight = settings.mCellHeight; return result; } NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data, const std::vector& offMeshConnections, const osg::Vec3f& agentHalfExtents, - const TilePosition& tile, const Settings& settings) + const TilePosition& tile, const RecastSettings& settings) { const auto offMeshConVerts = getOffMeshVerts(offMeshConnections); const std::vector offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents)); @@ -524,7 +502,7 @@ namespace DetourNavigator // 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 int polysAndTilesBits = 22; - const auto polysBits = getMinValuableBitsNumber(settings.mMaxPolys); + const auto polysBits = getMinValuableBitsNumber(settings.mDetour.mMaxPolys); if (polysBits >= polysAndTilesBits) throw InvalidArgument("Too many polygons per tile"); @@ -533,8 +511,8 @@ namespace DetourNavigator dtNavMeshParams params; std::fill_n(params.orig, 3, 0.0f); - params.tileWidth = settings.mTileSize * settings.mCellSize; - params.tileHeight = settings.mTileSize * settings.mCellSize; + params.tileWidth = settings.mRecast.mTileSize * settings.mRecast.mCellSize; + params.tileHeight = settings.mRecast.mTileSize * settings.mRecast.mCellSize; params.maxTiles = 1 << tilesBits; params.maxPolys = 1 << polysBits; @@ -558,9 +536,9 @@ namespace DetourNavigator { Log(Debug::Debug) << std::fixed << std::setprecision(2) << "Update NavMesh with multiple tiles:" << - " agentHeight=" << getHeight(settings, agentHalfExtents) << - " agentMaxClimb=" << getMaxClimb(settings) << - " agentRadius=" << getRadius(settings, agentHalfExtents) << + " agentHeight=" << getHeight(settings.mRecast, agentHalfExtents) << + " agentMaxClimb=" << getMaxClimb(settings.mRecast) << + " agentRadius=" << getRadius(settings.mRecast, agentHalfExtents) << " changedTile=(" << changedTile << ")" << " playerTile=(" << playerTile << ")" << " changedTileDistance=" << getDistance(changedTile, playerTile); @@ -591,7 +569,7 @@ namespace DetourNavigator if (!cachedNavMeshData) { - auto prepared = prepareNavMeshTileData(*recastMesh, changedTile, agentHalfExtents, settings); + auto prepared = prepareNavMeshTileData(*recastMesh, changedTile, agentHalfExtents, settings.mRecast); if (prepared == nullptr) { @@ -601,7 +579,7 @@ namespace DetourNavigator if (updateType == UpdateType::Temporary) return navMeshCacheItem->lock()->updateTile(changedTile, NavMeshTilesCache::Value(), - makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings)); + makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings.mRecast)); cachedNavMeshData = navMeshTilesCache.set(agentHalfExtents, changedTile, *recastMesh, std::move(prepared)); @@ -609,12 +587,12 @@ namespace DetourNavigator { Log(Debug::Debug) << "Navigator cache overflow"; return navMeshCacheItem->lock()->updateTile(changedTile, NavMeshTilesCache::Value(), - makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings)); + makeNavMeshTileData(*prepared, offMeshConnections, agentHalfExtents, changedTile, settings.mRecast)); } } const auto updateStatus = navMeshCacheItem->lock()->updateTile(changedTile, std::move(cachedNavMeshData), - makeNavMeshTileData(cachedNavMeshData.get(), offMeshConnections, agentHalfExtents, changedTile, settings)); + makeNavMeshTileData(cachedNavMeshData.get(), offMeshConnections, agentHalfExtents, changedTile, settings.mRecast)); return UpdateNavMeshStatusBuilder(updateStatus).cached(cached).getResult(); } diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 5b4169374b..989565d4bf 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -22,6 +22,16 @@ namespace DetourNavigator struct PreparedNavMeshData; struct NavMeshData; + struct RecastParams + { + float mSampleDist = 0; + float mSampleMaxError = 0; + int mMaxEdgeLen = 0; + int mWalkableClimb = 0; + int mWalkableHeight = 0; + int mWalkableRadius = 0; + }; + inline float getLength(const osg::Vec2i& value) { return std::sqrt(float(osg::square(value.x()) + osg::square(value.y()))); @@ -38,12 +48,14 @@ namespace DetourNavigator return expectedTilesCount <= maxTiles; } + RecastParams makeRecastParams(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents); + std::unique_ptr prepareNavMeshTileData(const RecastMesh& recastMesh, const TilePosition& tile, const Bounds& bounds, const osg::Vec3f& agentHalfExtents, const Settings& settings); NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data, const std::vector& offMeshConnections, const osg::Vec3f& agentHalfExtents, - const TilePosition& tile, const Settings& settings); + const TilePosition& tile, const RecastSettings& settings); NavMeshPtr makeEmptyNavMesh(const Settings& settings); diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 9092624ca3..541e1f791c 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -53,8 +53,8 @@ namespace DetourNavigator { if (addObject(id, static_cast(shapes), transform)) { - const osg::Vec3f start = toNavMeshCoordinates(mSettings, shapes.mConnectionStart); - const osg::Vec3f end = toNavMeshCoordinates(mSettings, shapes.mConnectionEnd); + const osg::Vec3f start = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionStart); + const osg::Vec3f end = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionEnd); mNavMeshManager.addOffMeshConnection(id, start, end, AreaType_door); mNavMeshManager.addOffMeshConnection(id, end, start, AreaType_door); return true; @@ -126,8 +126,8 @@ namespace DetourNavigator const auto dst = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV1])); mNavMeshManager.addOffMeshConnection( ObjectId(&pathgrid), - toNavMeshCoordinates(mSettings, src), - toNavMeshCoordinates(mSettings, dst), + toNavMeshCoordinates(mSettings.mRecast, src), + toNavMeshCoordinates(mSettings.mRecast, dst), AreaType_pathgrid ); } @@ -149,7 +149,7 @@ namespace DetourNavigator void NavigatorImpl::updatePlayerPosition(const osg::Vec3f& playerPosition) { - const TilePosition tilePosition = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition)); + const TilePosition tilePosition = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition)); if (mLastPlayerPosition.has_value() && *mLastPlayerPosition == tilePosition) return; update(playerPosition); @@ -225,6 +225,6 @@ namespace DetourNavigator float NavigatorImpl::getMaxNavmeshAreaRealRadius() const { const auto& settings = getSettings(); - return getRealTileSize(settings) * getMaxNavmeshAreaRadius(settings); + return getRealTileSize(settings.mRecast) * getMaxNavmeshAreaRadius(settings); } } diff --git a/components/detournavigator/navigatorutils.cpp b/components/detournavigator/navigatorutils.cpp index 82a108db6f..bc94e3f991 100644 --- a/components/detournavigator/navigatorutils.cpp +++ b/components/detournavigator/navigatorutils.cpp @@ -13,11 +13,11 @@ namespace DetourNavigator return std::nullopt; const auto settings = navigator.getSettings(); const auto result = DetourNavigator::findRandomPointAroundCircle(navMesh->lockConst()->getImpl(), - toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start), - toNavMeshCoordinates(settings, maxRadius), includeFlags, settings); + toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start), + toNavMeshCoordinates(settings.mRecast, maxRadius), includeFlags, settings.mDetour); if (!result) return std::nullopt; - return std::optional(fromNavMeshCoordinates(settings, *result)); + return std::optional(fromNavMeshCoordinates(settings.mRecast, *result)); } std::optional raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start, @@ -28,10 +28,10 @@ namespace DetourNavigator return std::nullopt; const auto settings = navigator.getSettings(); const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(), - toNavMeshCoordinates(settings, agentHalfExtents), toNavMeshCoordinates(settings, start), - toNavMeshCoordinates(settings, end), includeFlags, settings); + toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start), + toNavMeshCoordinates(settings.mRecast, end), includeFlags, settings.mDetour); if (!result) return std::nullopt; - return fromNavMeshCoordinates(settings, *result); + return fromNavMeshCoordinates(settings.mRecast, *result); } } diff --git a/components/detournavigator/navigatorutils.hpp b/components/detournavigator/navigatorutils.hpp index 4ccc238f97..8f3b6161f9 100644 --- a/components/detournavigator/navigatorutils.hpp +++ b/components/detournavigator/navigatorutils.hpp @@ -37,9 +37,9 @@ namespace DetourNavigator if (navMesh == nullptr) return Status::NavMeshNotFound; const auto settings = navigator.getSettings(); - return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings, agentHalfExtents), - toNavMeshCoordinates(settings, stepSize), toNavMeshCoordinates(settings, start), - toNavMeshCoordinates(settings, end), includeFlags, areaCosts, settings, endTolerance, out); + return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings.mRecast, agentHalfExtents), + toNavMeshCoordinates(settings.mRecast, stepSize), toNavMeshCoordinates(settings.mRecast, start), + toNavMeshCoordinates(settings.mRecast, end), includeFlags, areaCosts, settings, endTolerance, out); } /** diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index fff7d8d7cc..452fba93ad 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -43,8 +43,8 @@ namespace DetourNavigator { NavMeshManager::NavMeshManager(const Settings& settings) : mSettings(settings) - , mRecastMeshManager(settings) - , mOffMeshConnectionsManager(settings) + , mRecastMeshManager(mSettings.mRecast) + , mOffMeshConnectionsManager(mSettings.mRecast) , mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager) {} @@ -140,8 +140,8 @@ namespace DetourNavigator { mOffMeshConnectionsManager.add(id, OffMeshConnection {start, end, areaType}); - const auto startTilePosition = getTilePosition(mSettings, start); - const auto endTilePosition = getTilePosition(mSettings, end); + const auto startTilePosition = getTilePosition(mSettings.mRecast, start); + const auto endTilePosition = getTilePosition(mSettings.mRecast, end); addChangedTile(startTilePosition, ChangeType::add); @@ -158,7 +158,7 @@ namespace DetourNavigator void NavMeshManager::update(const osg::Vec3f& playerPosition, const osg::Vec3f& agentHalfExtents) { - const auto playerTile = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition)); + const auto playerTile = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition)); auto& lastRevision = mLastRecastMeshManagerRevision[agentHalfExtents]; auto lastPlayerTile = mPlayerTile.find(agentHalfExtents); if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end() @@ -251,7 +251,7 @@ namespace DetourNavigator void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType) { - getTilesPositions(shape, transform, mSettings, + getTilesPositions(shape, transform, mSettings.mRecast, [&] (const TilePosition& v) { addChangedTile(v, changeType); }); } @@ -261,7 +261,7 @@ namespace DetourNavigator if (cellSize == std::numeric_limits::max()) return; - getTilesPositions(cellSize, shift, mSettings, + getTilesPositions(cellSize, shift, mSettings.mRecast, [&] (const TilePosition& v) { addChangedTile(v, changeType); }); } diff --git a/components/detournavigator/offmeshconnectionsmanager.cpp b/components/detournavigator/offmeshconnectionsmanager.cpp index a673ae3e68..2306e50da9 100644 --- a/components/detournavigator/offmeshconnectionsmanager.cpp +++ b/components/detournavigator/offmeshconnectionsmanager.cpp @@ -11,7 +11,7 @@ namespace DetourNavigator { - OffMeshConnectionsManager::OffMeshConnectionsManager(const Settings& settings) + OffMeshConnectionsManager::OffMeshConnectionsManager(const RecastSettings& settings) : mSettings(settings) {} diff --git a/components/detournavigator/offmeshconnectionsmanager.hpp b/components/detournavigator/offmeshconnectionsmanager.hpp index 20a6427cd5..a0a1231bc4 100644 --- a/components/detournavigator/offmeshconnectionsmanager.hpp +++ b/components/detournavigator/offmeshconnectionsmanager.hpp @@ -18,7 +18,7 @@ namespace DetourNavigator class OffMeshConnectionsManager { public: - OffMeshConnectionsManager(const Settings& settings); + explicit OffMeshConnectionsManager(const RecastSettings& settings); void add(const ObjectId id, const OffMeshConnection& value); @@ -33,7 +33,7 @@ namespace DetourNavigator std::map> mByTilePosition; }; - const Settings& mSettings; + const RecastSettings& mSettings; Misc::ScopeGuarded mValues; }; } diff --git a/components/detournavigator/raycast.cpp b/components/detournavigator/raycast.cpp index 271da22496..be3217ba40 100644 --- a/components/detournavigator/raycast.cpp +++ b/components/detournavigator/raycast.cpp @@ -10,7 +10,7 @@ namespace DetourNavigator { std::optional raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, - const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings) + const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const DetourSettings& settings) { dtNavMeshQuery navMeshQuery; if (!initNavMeshQuery(navMeshQuery, navMesh, settings.mMaxNavMeshQueryNodes)) diff --git a/components/detournavigator/raycast.hpp b/components/detournavigator/raycast.hpp index ddf61b49f4..60cdf0a157 100644 --- a/components/detournavigator/raycast.hpp +++ b/components/detournavigator/raycast.hpp @@ -10,10 +10,10 @@ class dtNavMesh; namespace DetourNavigator { - struct Settings; + struct DetourSettings; std::optional raycast(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, - const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings); + const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const DetourSettings& settings); } #endif diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index e428f3695a..5ad45d699b 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -3,43 +3,65 @@ #include #include +#include + namespace DetourNavigator { + RecastSettings makeRecastSettingsFromSettingsManager() + { + constexpr float epsilon = std::numeric_limits::epsilon(); + + RecastSettings result; + + result.mBorderSize = std::max(0, ::Settings::Manager::getInt("border size", "Navigator")); + result.mCellHeight = std::max(epsilon, ::Settings::Manager::getFloat("cell height", "Navigator")); + result.mCellSize = std::max(epsilon, ::Settings::Manager::getFloat("cell size", "Navigator")); + result.mDetailSampleDist = std::max(0.0f, ::Settings::Manager::getFloat("detail sample dist", "Navigator")); + result.mDetailSampleMaxError = std::max(0.0f, ::Settings::Manager::getFloat("detail sample max error", "Navigator")); + result.mMaxClimb = Constants::sStepSizeUp; + result.mMaxSimplificationError = std::max(0.0f, ::Settings::Manager::getFloat("max simplification error", "Navigator")); + result.mMaxSlope = Constants::sMaxSlope; + result.mRecastScaleFactor = std::max(epsilon, ::Settings::Manager::getFloat("recast scale factor", "Navigator")); + result.mSwimHeightScale = 0; + result.mMaxEdgeLen = std::max(0, ::Settings::Manager::getInt("max edge len", "Navigator")); + result.mMaxVertsPerPoly = std::max(3, ::Settings::Manager::getInt("max verts per poly", "Navigator")); + result.mRegionMergeArea = std::max(0, ::Settings::Manager::getInt("region merge area", "Navigator")); + result.mRegionMinArea = std::max(0, ::Settings::Manager::getInt("region min area", "Navigator")); + result.mTileSize = std::max(1, ::Settings::Manager::getInt("tile size", "Navigator")); + + return result; + } + + DetourSettings makeDetourSettingsFromSettingsManager() + { + DetourSettings result; + + result.mMaxNavMeshQueryNodes = std::clamp(::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"), 1, 65535); + result.mMaxPolys = std::clamp(::Settings::Manager::getInt("max polygons per tile", "Navigator"), 1, (1 << 22) - 1); + result.mMaxPolygonPathSize = static_cast(std::max(0, ::Settings::Manager::getInt("max polygon path size", "Navigator"))); + result.mMaxSmoothPathSize = static_cast(std::max(0, ::Settings::Manager::getInt("max smooth path size", "Navigator"))); + + return result; + } + Settings makeSettingsFromSettingsManager() { - Settings navigatorSettings; + Settings result; - 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 = Constants::sStepSizeUp; - navigatorSettings.mMaxSimplificationError = ::Settings::Manager::getFloat("max simplification error", "Navigator"); - navigatorSettings.mMaxSlope = Constants::sMaxSlope; - navigatorSettings.mRecastScaleFactor = ::Settings::Manager::getFloat("recast scale factor", "Navigator"); - navigatorSettings.mSwimHeightScale = 0; - navigatorSettings.mMaxEdgeLen = ::Settings::Manager::getInt("max edge len", "Navigator"); - navigatorSettings.mMaxNavMeshQueryNodes = ::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"); - navigatorSettings.mMaxPolys = ::Settings::Manager::getInt("max polygons per tile", "Navigator"); - navigatorSettings.mMaxTilesNumber = ::Settings::Manager::getInt("max tiles number", "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.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "Navigator"); - navigatorSettings.mAsyncNavMeshUpdaterThreads = static_cast(::Settings::Manager::getInt("async nav mesh updater threads", "Navigator")); - navigatorSettings.mMaxNavMeshTilesCacheSize = static_cast(::Settings::Manager::getInt("max nav mesh tiles cache size", "Navigator")); - navigatorSettings.mMaxPolygonPathSize = static_cast(::Settings::Manager::getInt("max polygon path size", "Navigator")); - navigatorSettings.mMaxSmoothPathSize = static_cast(::Settings::Manager::getInt("max smooth path size", "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"); - navigatorSettings.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator")); + result.mRecast = makeRecastSettingsFromSettingsManager(); + result.mDetour = makeDetourSettingsFromSettingsManager(); + result.mMaxTilesNumber = std::max(0, ::Settings::Manager::getInt("max tiles number", "Navigator")); + result.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "Navigator"); + result.mAsyncNavMeshUpdaterThreads = static_cast(std::max(0, ::Settings::Manager::getInt("async nav mesh updater threads", "Navigator"))); + result.mMaxNavMeshTilesCacheSize = static_cast(std::max(std::int64_t {0}, ::Settings::Manager::getInt64("max nav mesh tiles cache size", "Navigator"))); + result.mEnableWriteRecastMeshToFile = ::Settings::Manager::getBool("enable write recast mesh to file", "Navigator"); + result.mEnableWriteNavMeshToFile = ::Settings::Manager::getBool("enable write nav mesh to file", "Navigator"); + result.mRecastMeshPathPrefix = ::Settings::Manager::getString("recast mesh path prefix", "Navigator"); + result.mNavMeshPathPrefix = ::Settings::Manager::getString("nav mesh path prefix", "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.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator")); - return navigatorSettings; + return result; } } diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index 0ea35d9b49..fbd44dfcfc 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -6,12 +6,8 @@ namespace DetourNavigator { - struct Settings + struct RecastSettings { - bool mEnableWriteRecastMeshToFile = false; - bool mEnableWriteNavMeshToFile = false; - bool mEnableRecastMeshFileNameRevision = false; - bool mEnableNavMeshFileNameRevision = false; float mCellHeight = 0; float mCellSize = 0; float mDetailSampleDist = 0; @@ -23,23 +19,41 @@ namespace DetourNavigator float mSwimHeightScale = 0; int mBorderSize = 0; int mMaxEdgeLen = 0; - int mMaxNavMeshQueryNodes = 0; - int mMaxPolys = 0; - int mMaxTilesNumber = 0; int mMaxVertsPerPoly = 0; - int mRegionMergeSize = 0; - int mRegionMinSize = 0; + int mRegionMergeArea = 0; + int mRegionMinArea = 0; int mTileSize = 0; - int mWaitUntilMinDistanceToPlayer = 0; - std::size_t mAsyncNavMeshUpdaterThreads = 0; - std::size_t mMaxNavMeshTilesCacheSize = 0; + }; + + struct DetourSettings + { + int mMaxPolys = 0; + int mMaxNavMeshQueryNodes = 0; std::size_t mMaxPolygonPathSize = 0; std::size_t mMaxSmoothPathSize = 0; + }; + + struct Settings + { + bool mEnableWriteRecastMeshToFile = false; + bool mEnableWriteNavMeshToFile = false; + bool mEnableRecastMeshFileNameRevision = false; + bool mEnableNavMeshFileNameRevision = false; + RecastSettings mRecast; + DetourSettings mDetour; + int mWaitUntilMinDistanceToPlayer = 0; + int mMaxTilesNumber = 0; + std::size_t mAsyncNavMeshUpdaterThreads = 0; + std::size_t mMaxNavMeshTilesCacheSize = 0; std::string mRecastMeshPathPrefix; std::string mNavMeshPathPrefix; std::chrono::milliseconds mMinUpdateInterval; }; + RecastSettings makeRecastSettingsFromSettingsManager(); + + DetourSettings makeDetourSettingsFromSettingsManager(); + Settings makeSettingsFromSettingsManager(); } diff --git a/components/detournavigator/settingsutils.hpp b/components/detournavigator/settingsutils.hpp index 6f15faaa3e..285920e5a0 100644 --- a/components/detournavigator/settingsutils.hpp +++ b/components/detournavigator/settingsutils.hpp @@ -4,12 +4,8 @@ #include "settings.hpp" #include "tilebounds.hpp" #include "tileposition.hpp" -#include "tilebounds.hpp" - -#include #include -#include #include #include @@ -17,38 +13,31 @@ namespace DetourNavigator { - inline float getHeight(const Settings& settings,const osg::Vec3f& agentHalfExtents) - { - return 2.0f * agentHalfExtents.z() * settings.mRecastScaleFactor; - } - - inline float getMaxClimb(const Settings& settings) - { - return settings.mMaxClimb * settings.mRecastScaleFactor; - } - - inline float getRadius(const Settings& settings, const osg::Vec3f& agentHalfExtents) - { - return std::max(agentHalfExtents.x(), agentHalfExtents.y()) * std::sqrt(2) * settings.mRecastScaleFactor; - } - - inline float toNavMeshCoordinates(const Settings& settings, float value) + inline float toNavMeshCoordinates(const RecastSettings& settings, float value) { return value * settings.mRecastScaleFactor; } - inline osg::Vec2f toNavMeshCoordinates(const Settings& settings, osg::Vec2f position) + inline osg::Vec2f toNavMeshCoordinates(const RecastSettings& settings, osg::Vec2f position) { return position * settings.mRecastScaleFactor; } - inline osg::Vec3f toNavMeshCoordinates(const Settings& settings, osg::Vec3f position) + inline osg::Vec3f toNavMeshCoordinates(const RecastSettings& settings, osg::Vec3f position) { std::swap(position.y(), position.z()); return position * settings.mRecastScaleFactor; } - inline osg::Vec3f fromNavMeshCoordinates(const Settings& settings, osg::Vec3f position) + inline TileBounds toNavMeshCoordinates(const RecastSettings& settings, const TileBounds& value) + { + return TileBounds { + toNavMeshCoordinates(settings, value.mMin), + toNavMeshCoordinates(settings, value.mMax) + }; + } + + inline osg::Vec3f fromNavMeshCoordinates(const RecastSettings& settings, osg::Vec3f position) { const auto factor = 1.0f / settings.mRecastScaleFactor; position *= factor; @@ -56,12 +45,12 @@ namespace DetourNavigator return position; } - inline float getTileSize(const Settings& settings) + inline float getTileSize(const RecastSettings& settings) { return static_cast(settings.mTileSize) * settings.mCellSize; } - inline TilePosition getTilePosition(const Settings& settings, const osg::Vec3f& position) + inline TilePosition getTilePosition(const RecastSettings& settings, const osg::Vec3f& position) { return TilePosition( static_cast(std::floor(position.x() / getTileSize(settings))), @@ -69,7 +58,7 @@ namespace DetourNavigator ); } - inline TileBounds makeTileBounds(const Settings& settings, const TilePosition& tilePosition) + inline TileBounds makeTileBounds(const RecastSettings& settings, const TilePosition& tilePosition) { return TileBounds { osg::Vec2f(tilePosition.x(), tilePosition.y()) * getTileSize(settings), @@ -77,17 +66,12 @@ namespace DetourNavigator }; } - inline float getBorderSize(const Settings& settings) + inline float getBorderSize(const RecastSettings& settings) { return static_cast(settings.mBorderSize) * settings.mCellSize; } - inline float getSwimLevel(const Settings& settings, const float waterLevel, const float agentHalfExtentsZ) - { - return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;; - } - - inline float getRealTileSize(const Settings& settings) + inline float getRealTileSize(const RecastSettings& settings) { return settings.mTileSize * settings.mCellSize / settings.mRecastScaleFactor; } @@ -97,7 +81,7 @@ namespace DetourNavigator return std::floor(std::sqrt(settings.mMaxTilesNumber / osg::PI)) - 1; } - inline TileBounds makeRealTileBoundsWithBorder(const Settings& settings, const TilePosition& tilePosition) + inline TileBounds makeRealTileBoundsWithBorder(const RecastSettings& settings, const TilePosition& tilePosition) { TileBounds result = makeTileBounds(settings, tilePosition); const float border = getBorderSize(settings); diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 20fbe30667..ebd64180aa 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -10,7 +10,7 @@ namespace DetourNavigator { - TileCachedRecastMeshManager::TileCachedRecastMeshManager(const Settings& settings) + TileCachedRecastMeshManager::TileCachedRecastMeshManager(const RecastSettings& settings) : mSettings(settings) {} diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index bb08a4227e..96183a51be 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -20,7 +20,7 @@ namespace DetourNavigator class TileCachedRecastMeshManager { public: - TileCachedRecastMeshManager(const Settings& settings); + explicit TileCachedRecastMeshManager(const RecastSettings& settings); bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); @@ -102,7 +102,7 @@ namespace DetourNavigator private: using TilesMap = std::map>; - const Settings& mSettings; + const RecastSettings& mSettings; Misc::ScopeGuarded mTiles; std::unordered_map> mObjectsTilesPositions; std::map> mWaterTilesPositions; diff --git a/components/sceneutil/agentpath.cpp b/components/sceneutil/agentpath.cpp index 5721110f77..db026a3332 100644 --- a/components/sceneutil/agentpath.cpp +++ b/components/sceneutil/agentpath.cpp @@ -37,7 +37,7 @@ namespace SceneUtil { osg::ref_ptr createAgentPathGroup(const std::deque& path, const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end, - const DetourNavigator::Settings& settings) + const DetourNavigator::RecastSettings& settings) { using namespace DetourNavigator; diff --git a/components/sceneutil/agentpath.hpp b/components/sceneutil/agentpath.hpp index a8965d852e..1194fa512a 100644 --- a/components/sceneutil/agentpath.hpp +++ b/components/sceneutil/agentpath.hpp @@ -13,14 +13,14 @@ namespace osg namespace DetourNavigator { - struct Settings; + struct RecastSettings; } namespace SceneUtil { osg::ref_ptr createAgentPathGroup(const std::deque& path, const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end, - const DetourNavigator::Settings& settings); + const DetourNavigator::RecastSettings& settings); } #endif diff --git a/components/sceneutil/navmesh.cpp b/components/sceneutil/navmesh.cpp index d66f95381c..eac3d17156 100644 --- a/components/sceneutil/navmesh.cpp +++ b/components/sceneutil/navmesh.cpp @@ -254,9 +254,9 @@ namespace SceneUtil osg::ref_ptr group(new osg::Group); group->setStateSet(groupStateSet); constexpr float shift = 10.0f; - DebugDraw debugDraw(*group, debugDrawStateSet, osg::Vec3f(0, 0, shift), 1.0f / settings.mRecastScaleFactor); + DebugDraw debugDraw(*group, debugDrawStateSet, osg::Vec3f(0, 0, shift), 1.0f / settings.mRecast.mRecastScaleFactor); dtNavMeshQuery navMeshQuery; - navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes); + navMeshQuery.init(&navMesh, settings.mDetour.mMaxNavMeshQueryNodes); drawMeshTile(&debugDraw, navMesh, &navMeshQuery, &meshTile, DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST); return group; diff --git a/components/sceneutil/recastmesh.cpp b/components/sceneutil/recastmesh.cpp index 9614673a64..d320624682 100644 --- a/components/sceneutil/recastmesh.cpp +++ b/components/sceneutil/recastmesh.cpp @@ -42,7 +42,7 @@ namespace namespace SceneUtil { osg::ref_ptr createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh, - const DetourNavigator::Settings& settings) + const DetourNavigator::RecastSettings& settings) { using namespace DetourNavigator; diff --git a/components/sceneutil/recastmesh.hpp b/components/sceneutil/recastmesh.hpp index ee5d9865e5..674b5b1d2a 100644 --- a/components/sceneutil/recastmesh.hpp +++ b/components/sceneutil/recastmesh.hpp @@ -11,13 +11,13 @@ namespace osg namespace DetourNavigator { class RecastMesh; - struct Settings; + struct RecastSettings; } namespace SceneUtil { osg::ref_ptr createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh, - const DetourNavigator::Settings& settings); + const DetourNavigator::RecastSettings& settings); } #endif diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index cef627acd4..7fa625e4ab 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -79,6 +79,15 @@ int Manager::getInt (const std::string& setting, const std::string& category) return number; } +std::int64_t Manager::getInt64 (const std::string& setting, const std::string& category) +{ + const std::string& value = getString(setting, category); + std::stringstream stream(value); + std::size_t number = 0; + stream >> number; + return number; +} + bool Manager::getBool (const std::string& setting, const std::string& category) { const std::string& string = getString(setting, category); diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index 21d5aff770..a4b1cf3a54 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -51,6 +51,7 @@ namespace Settings ///< returns the list of changed settings intersecting with the filter static int getInt (const std::string& setting, const std::string& category); + static std::int64_t getInt64 (const std::string& setting, const std::string& category); static float getFloat (const std::string& setting, const std::string& category); static double getDouble (const std::string& setting, const std::string& category); static std::string getString (const std::string& setting, const std::string& category); diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index aea817530e..f8ab4522d6 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -365,20 +365,20 @@ max verts per poly The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process. -region merge size +region merge area ----------------- :Type: integer :Range: >= 0 -:Default: 20 +:Default: 400 Any regions with a span count smaller than this value will, if possible, be merged with larger regions. -region min size +region min area --------------- :Type: integer :Range: >= 0 -:Default: 8 +:Default: 64 The minimum number of cells allowed to form isolated island areas. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 9715e3793e..084aad4fe3 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -876,10 +876,10 @@ max polygons per tile = 4096 max verts per poly = 6 # Any regions with a span count smaller than this value will, if possible, be merged with larger regions. (value >= 0) -region merge size = 20 +region merge area = 400 # The minimum number of cells allowed to form isolated island areas. (value >= 0) -region min size = 8 +region min area = 64 # Number of background threads to update nav mesh (value >= 1) async nav mesh updater threads = 1