From 7ae7cb181d5623235f1f7edb483ac5c58d6934a3 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 27 Nov 2019 23:45:01 +0100 Subject: [PATCH 1/2] Support recast mesh rendering --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/recastmesh.cpp | 92 +++++++++++++++++++ apps/openmw/mwrender/recastmesh.hpp | 53 +++++++++++ apps/openmw/mwrender/renderingmanager.cpp | 15 +++ apps/openmw/mwrender/renderingmanager.hpp | 4 + apps/openmw/mwrender/rendermode.hpp | 1 + apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/miscextensions.cpp | 15 +++ .../detournavigator/navmeshtilescache.cpp | 42 +++++---- .../detournavigator/recastmeshbuilder.cpp | 32 ++++--- components/CMakeLists.txt | 2 +- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + .../cachedrecastmeshmanager.cpp | 5 +- .../cachedrecastmeshmanager.hpp | 2 +- components/detournavigator/navigator.hpp | 4 + components/detournavigator/navigatorimpl.cpp | 5 + components/detournavigator/navigatorimpl.hpp | 2 + components/detournavigator/navigatorstub.hpp | 5 + components/detournavigator/navmeshmanager.cpp | 11 +++ components/detournavigator/navmeshmanager.hpp | 3 + components/detournavigator/recastmesh.cpp | 8 +- components/detournavigator/recastmesh.hpp | 16 +++- .../detournavigator/recastmeshbuilder.cpp | 5 +- .../detournavigator/recastmeshbuilder.hpp | 2 +- .../detournavigator/recastmeshmanager.cpp | 24 ++--- .../detournavigator/recastmeshmanager.hpp | 6 +- .../detournavigator/recastmeshtiles.hpp | 15 +++ .../tilecachedrecastmeshmanager.cpp | 11 ++- .../tilecachedrecastmeshmanager.hpp | 1 + components/sceneutil/detourdebugdraw.cpp | 9 +- components/sceneutil/recastmesh.cpp | 48 ++++++++++ components/sceneutil/recastmesh.hpp | 23 +++++ .../reference/modding/settings/navigator.rst | 14 +++ files/settings-default.cfg | 3 + 35 files changed, 418 insertions(+), 67 deletions(-) create mode 100644 apps/openmw/mwrender/recastmesh.cpp create mode 100644 apps/openmw/mwrender/recastmesh.hpp create mode 100644 components/detournavigator/recastmeshtiles.hpp create mode 100644 components/sceneutil/recastmesh.cpp create mode 100644 components/sceneutil/recastmesh.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 14c271b66..2bc85e062 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -21,7 +21,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation - renderbin actoranimation landmanager navmesh actorspaths + renderbin actoranimation landmanager navmesh actorspaths recastmesh ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/recastmesh.cpp b/apps/openmw/mwrender/recastmesh.cpp new file mode 100644 index 000000000..5aec174df --- /dev/null +++ b/apps/openmw/mwrender/recastmesh.cpp @@ -0,0 +1,92 @@ +#include "recastmesh.hpp" + +#include +#include +#include + +#include + +namespace MWRender +{ + RecastMesh::RecastMesh(const osg::ref_ptr& root, bool enabled) + : mRootNode(root) + , mEnabled(enabled) + { + } + + RecastMesh::~RecastMesh() + { + if (mEnabled) + disable(); + } + + bool RecastMesh::toggle() + { + if (mEnabled) + disable(); + else + enable(); + + return mEnabled; + } + + void RecastMesh::update(const DetourNavigator::RecastMeshTiles& tiles, const DetourNavigator::Settings& settings) + { + if (!mEnabled) + return; + + for (auto it = mGroups.begin(); it != mGroups.end();) + { + const auto tile = tiles.find(it->first); + if (tile == tiles.end()) + { + mRootNode->removeChild(it->second.mValue); + it = mGroups.erase(it); + continue; + } + + if (it->second.mGeneration != tile->second->getGeneration() + || it->second.mRevision != tile->second->getRevision()) + { + const auto group = SceneUtil::createRecastMeshGroup(*tile->second, settings); + group->setNodeMask(SceneUtil::Mask_Debug); + mRootNode->removeChild(it->second.mValue); + mRootNode->addChild(group); + it->second.mValue = group; + it->second.mGeneration = tile->second->getGeneration(); + it->second.mRevision = tile->second->getRevision(); + continue; + } + + ++it; + } + + for (const auto& tile : tiles) + { + if (mGroups.count(tile.first)) + continue; + const auto group = SceneUtil::createRecastMeshGroup(*tile.second, settings); + group->setNodeMask(SceneUtil::Mask_Debug); + mGroups.emplace(tile.first, Group {tile.second->getGeneration(), tile.second->getRevision(), group}); + mRootNode->addChild(group); + } + } + + void RecastMesh::reset() + { + std::for_each(mGroups.begin(), mGroups.end(), [&] (const auto& v) { mRootNode->removeChild(v.second.mValue); }); + mGroups.clear(); + } + + void RecastMesh::enable() + { + std::for_each(mGroups.begin(), mGroups.end(), [&] (const auto& v) { mRootNode->addChild(v.second.mValue); }); + mEnabled = true; + } + + void RecastMesh::disable() + { + std::for_each(mGroups.begin(), mGroups.end(), [&] (const auto& v) { mRootNode->removeChild(v.second.mValue); }); + mEnabled = false; + } +} diff --git a/apps/openmw/mwrender/recastmesh.hpp b/apps/openmw/mwrender/recastmesh.hpp new file mode 100644 index 000000000..729438dbe --- /dev/null +++ b/apps/openmw/mwrender/recastmesh.hpp @@ -0,0 +1,53 @@ +#ifndef OPENMW_MWRENDER_RECASTMESH_H +#define OPENMW_MWRENDER_RECASTMESH_H + +#include + +#include + +#include + +namespace osg +{ + class Group; + class Geometry; +} + +namespace MWRender +{ + class RecastMesh + { + public: + RecastMesh(const osg::ref_ptr& root, bool enabled); + ~RecastMesh(); + + bool toggle(); + + void update(const DetourNavigator::RecastMeshTiles& recastMeshTiles, const DetourNavigator::Settings& settings); + + void reset(); + + void enable(); + + void disable(); + + bool isEnabled() const + { + return mEnabled; + } + + private: + struct Group + { + std::size_t mGeneration; + std::size_t mRevision; + osg::ref_ptr mValue; + }; + + osg::ref_ptr mRootNode; + bool mEnabled; + std::map mGroups; + }; +} + +#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index dd570f558..4d8db6cc4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -66,6 +66,7 @@ #include "util.hpp" #include "navmesh.hpp" #include "actorspaths.hpp" +#include "recastmesh.hpp" namespace { @@ -260,6 +261,7 @@ namespace MWRender mNavMesh.reset(new NavMesh(mRootNode, Settings::Manager::getBool("enable nav mesh render", "Navigator"))); mActorsPaths.reset(new ActorsPaths(mRootNode, Settings::Manager::getBool("enable agents paths render", "Navigator"))); + mRecastMesh.reset(new RecastMesh(mRootNode, Settings::Manager::getBool("enable recast mesh render", "Navigator"))); mPathgrid.reset(new Pathgrid(mRootNode)); mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get())); @@ -585,6 +587,10 @@ namespace MWRender { return mActorsPaths->toggle(); } + else if (mode == Render_RecastMesh) + { + return mRecastMesh->toggle(); + } return false; } @@ -651,6 +657,7 @@ namespace MWRender } updateNavMesh(); + updateRecastMesh(); mCamera->update(dt, paused); @@ -1463,4 +1470,12 @@ namespace MWRender } } } + + void RenderingManager::updateRecastMesh() + { + if (!mRecastMesh->isEnabled()) + return; + + mRecastMesh->update(mNavigator.getRecastMeshTiles(), mNavigator.getSettings()); + } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 22d2cf28c..d4b0b1840 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -82,6 +82,7 @@ namespace MWRender class LandManager; class NavMesh; class ActorsPaths; + class RecastMesh; class RenderingManager : public MWRender::RenderingInterface { @@ -246,6 +247,8 @@ namespace MWRender void updateNavMesh(); + void updateRecastMesh(); + osg::ref_ptr getIntersectionVisitor(osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors); osg::ref_ptr mIntersectionVisitor; @@ -264,6 +267,7 @@ namespace MWRender std::unique_ptr mNavMesh; std::size_t mNavMeshNumber = 0; std::unique_ptr mActorsPaths; + std::unique_ptr mRecastMesh; std::unique_ptr mPathgrid; std::unique_ptr mObjects; std::unique_ptr mWater; diff --git a/apps/openmw/mwrender/rendermode.hpp b/apps/openmw/mwrender/rendermode.hpp index 077710f4f..3ba2f9596 100644 --- a/apps/openmw/mwrender/rendermode.hpp +++ b/apps/openmw/mwrender/rendermode.hpp @@ -13,6 +13,7 @@ namespace MWRender Render_Scene, Render_NavMesh, Render_ActorsPaths, + Render_RecastMesh, }; } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 6795a058f..5a333a5b7 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -463,5 +463,6 @@ op 0x200030c: RepairedOnMe op 0x200030d: RepairedOnMe, explicit op 0x200030e: TestCells op 0x200030f: TestInteriorCells +op 0x2000310: ToggleRecastMesh -opcodes 0x2000310-0x3ffffff unused +opcodes 0x2000311-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 7d779e62f..b7b91cf5c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1440,6 +1440,20 @@ namespace MWScript } }; + class OpToggleRecastMesh : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + bool enabled = + MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_RecastMesh); + + runtime.getContext().report (enabled ? + "Recast Mesh Rendering -> On" : "Recast Mesh Rendering -> Off"); + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); @@ -1545,6 +1559,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeSetNavMeshNumberToRender, new OpSetNavMeshNumberToRender); interpreter.installSegment5 (Compiler::Misc::opcodeRepairedOnMe, new OpRepairedOnMe); interpreter.installSegment5 (Compiler::Misc::opcodeRepairedOnMeExplicit, new OpRepairedOnMe); + interpreter.installSegment5 (Compiler::Misc::opcodeToggleRecastMesh, new OpToggleRecastMesh); } } } diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index a3a1816ad..e8e7820d9 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -25,12 +25,15 @@ namespace { const osg::Vec3f mAgentHalfExtents {1, 2, 3}; const TilePosition mTilePosition {0, 0}; + const std::size_t mGeneration = 0; + const std::size_t mRevision = 0; const std::vector mIndices {{0, 1, 2}}; const std::vector mVertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}}; const std::vector mAreaTypes {1, AreaType_ground}; const std::vector mWater {}; const std::size_t mTrianglesPerChunk {1}; - const RecastMesh mRecastMesh {mIndices, mVertices, mAreaTypes, mWater, mTrianglesPerChunk}; + const RecastMesh mRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, mWater, mTrianglesPerChunk}; const std::vector mOffMeshConnections {}; unsigned char* const mData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData mNavMeshData {mData, 1}; @@ -128,7 +131,8 @@ namespace const std::size_t maxSize = 1; NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh unexistentRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; + const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, water, mTrianglesPerChunk}; cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData)); EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh, mOffMeshConnections)); @@ -142,7 +146,8 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, water, mTrianglesPerChunk}; const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData anotherNavMeshData {anotherData, 1}; @@ -162,7 +167,8 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, water, mTrianglesPerChunk}; const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData anotherNavMeshData {anotherData, 1}; @@ -180,14 +186,14 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh leastRecentlySetRecastMesh {mIndices, mVertices, mAreaTypes, leastRecentlySetWater, - mTrianglesPerChunk}; + const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, leastRecentlySetWater, mTrianglesPerChunk}; const auto leastRecentlySetData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData leastRecentlySetNavMeshData {leastRecentlySetData, 1}; const std::vector mostRecentlySetWater {1, RecastMesh::Water {2, btTransform::getIdentity()}}; - const RecastMesh mostRecentlySetRecastMesh {mIndices, mVertices, mAreaTypes, mostRecentlySetWater, - mTrianglesPerChunk}; + const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, mostRecentlySetWater, mTrianglesPerChunk}; const auto mostRecentlySetData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData mostRecentlySetNavMeshData {mostRecentlySetData, 1}; @@ -212,14 +218,14 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh leastRecentlyUsedRecastMesh {mIndices, mVertices, mAreaTypes, leastRecentlyUsedWater, - mTrianglesPerChunk}; + const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, leastRecentlyUsedWater, mTrianglesPerChunk}; const auto leastRecentlyUsedData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData leastRecentlyUsedNavMeshData {leastRecentlyUsedData, 1}; const std::vector mostRecentlyUsedWater {1, RecastMesh::Water {2, btTransform::getIdentity()}}; - const RecastMesh mostRecentlyUsedRecastMesh {mIndices, mVertices, mAreaTypes, mostRecentlyUsedWater, - mTrianglesPerChunk}; + const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, mostRecentlyUsedWater, mTrianglesPerChunk}; const auto mostRecentlyUsedData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData mostRecentlyUsedNavMeshData {mostRecentlyUsedData, 1}; @@ -256,7 +262,7 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh tooLargeRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; + const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; const auto tooLargeData = reinterpret_cast(dtAlloc(2, DT_ALLOC_PERM)); NavMeshData tooLargeNavMeshData {tooLargeData, 2}; @@ -275,12 +281,13 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, anotherWater, mTrianglesPerChunk}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, anotherWater, mTrianglesPerChunk}; const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData anotherNavMeshData {anotherData, 1}; const std::vector tooLargeWater {1, RecastMesh::Water {2, btTransform::getIdentity()}}; - const RecastMesh tooLargeRecastMesh {mIndices, mVertices, mAreaTypes, tooLargeWater, mTrianglesPerChunk}; + const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, tooLargeWater, mTrianglesPerChunk}; const auto tooLargeData = reinterpret_cast(dtAlloc(2, DT_ALLOC_PERM)); NavMeshData tooLargeNavMeshData {tooLargeData, 2}; @@ -303,7 +310,8 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, + mAreaTypes, water, mTrianglesPerChunk}; const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData anotherNavMeshData {anotherData, 1}; @@ -326,7 +334,7 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; - const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk}; const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData anotherNavMeshData {anotherData, 1}; diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index 60b754915..af6797cf0 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -30,6 +30,8 @@ namespace { Settings mSettings; TileBounds mBounds; + const std::size_t mGeneration = 0; + const std::size_t mRevision = 0; DetourNavigatorRecastMeshBuilderTest() { @@ -45,7 +47,7 @@ namespace TEST_F(DetourNavigatorRecastMeshBuilderTest, create_for_empty_should_return_empty) { RecastMeshBuilder builder(mSettings, mBounds); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector()); EXPECT_EQ(recastMesh->getIndices(), std::vector()); EXPECT_EQ(recastMesh->getAreaTypes(), std::vector()); @@ -59,7 +61,7 @@ namespace RecastMeshBuilder builder(mSettings, mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 1, 0, -1, -1, 0, 1, @@ -80,7 +82,7 @@ namespace btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 2, 3, 0, 0, 3, 4, @@ -96,7 +98,7 @@ namespace btHeightfieldTerrainShape shape(2, 2, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false); RecastMeshBuilder builder(mSettings, mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ -0.5, 0, -0.5, -0.5, 0, 0.5, @@ -114,7 +116,7 @@ namespace btBoxShape shape(btVector3(1, 1, 2)); RecastMeshBuilder builder(mSettings, mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 1, 2, 1, -1, 2, 1, @@ -161,7 +163,7 @@ namespace btTransform::getIdentity(), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 1, 0, -1, -1, 0, 1, @@ -210,7 +212,7 @@ namespace btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 2, 3, 0, 0, 3, 4, @@ -234,7 +236,7 @@ namespace btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 3, 12, 2, 1, 12, 10, @@ -256,7 +258,7 @@ namespace btTransform::getIdentity(), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 1, 0, -1, -1, 0, 1, @@ -284,7 +286,7 @@ namespace btTransform::getIdentity(), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ -0.2f, 0, -0.3f, -0.3f, 0, -0.2f, @@ -309,7 +311,7 @@ namespace static_cast(-osg::PI_4))), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 0, -0.70710659027099609375, -3.535533905029296875, 0, 0.707107067108154296875, -3.535533905029296875, @@ -334,7 +336,7 @@ namespace static_cast(osg::PI_4))), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ -3.535533905029296875, -0.70710659027099609375, 0, -3.535533905029296875, 0.707107067108154296875, 0, @@ -359,7 +361,7 @@ namespace static_cast(osg::PI_4))), AreaType_ground ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 1.41421353816986083984375, 0, 1.1920928955078125e-07, -1.41421353816986083984375, 0, -1.1920928955078125e-07, @@ -388,7 +390,7 @@ namespace btTransform::getIdentity(), AreaType_null ); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getVertices(), std::vector({ 1, 0, -1, -1, 0, 1, @@ -405,7 +407,7 @@ namespace { RecastMeshBuilder builder(mSettings, mBounds); builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))); - const auto recastMesh = builder.create(); + const auto recastMesh = builder.create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getWater(), std::vector({ RecastMesh::Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))} })); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 2f6266dff..8d644c6de 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -51,7 +51,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer - actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique vismask + actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique vismask recastmesh ) add_component_dir (nif diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index cfa8c4667..24578b238 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -327,6 +327,7 @@ namespace Compiler extensions.registerInstruction ("toggleactorspaths", "", opcodeToggleActorsPaths); extensions.registerInstruction ("setnavmeshnumber", "l", opcodeSetNavMeshNumberToRender); extensions.registerFunction ("repairedonme", 'l', "S", opcodeRepairedOnMe, opcodeRepairedOnMeExplicit); + extensions.registerInstruction ("togglerecastmesh", "", opcodeToggleRecastMesh); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 5fa8cc170..d3446e688 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -304,6 +304,7 @@ namespace Compiler const int opcodeSetNavMeshNumberToRender = 0x200030a; const int opcodeRepairedOnMe = 0x200030c; const int opcodeRepairedOnMeExplicit = 0x200030d; + const int opcodeToggleRecastMesh = 0x2000310; } namespace Sky diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 5e145486b..da0f6c874 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -3,8 +3,9 @@ namespace DetourNavigator { - CachedRecastMeshManager::CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds) - : mImpl(settings, bounds) + CachedRecastMeshManager::CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds, + std::size_t generation) + : mImpl(settings, bounds, generation) {} bool CachedRecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index 528e8dabc..5efb315e8 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -10,7 +10,7 @@ namespace DetourNavigator class CachedRecastMeshManager { public: - CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds); + CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation); bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, const AreaType areaType); diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 2265b1d39..99f1e258d 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -6,6 +6,8 @@ #include "settings.hpp" #include "objectid.hpp" #include "navmeshcacheitem.hpp" +#include "recastmesh.hpp" +#include "recastmeshtiles.hpp" namespace DetourNavigator { @@ -204,6 +206,8 @@ namespace DetourNavigator */ boost::optional findRandomPointAroundCircle(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start, const float maxRadius, const Flags includeFlags) const; + + virtual RecastMeshTiles getRecastMeshTiles() = 0; }; } diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index b743f26b2..3ecfd8b51 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -143,6 +143,11 @@ namespace DetourNavigator mNavMeshManager.reportStats(frameNumber, stats); } + RecastMeshTiles NavigatorImpl::getRecastMeshTiles() + { + return mNavMeshManager.getRecastMeshTiles(); + } + void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId) { updateId(id, avoidId, mWaterIds); diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index b6b3b1b7f..be291f501 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -50,6 +50,8 @@ namespace DetourNavigator void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; + RecastMeshTiles getRecastMeshTiles() override; + private: Settings mSettings; NavMeshManager mNavMeshManager; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 885482a45..ee23e67be 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -81,6 +81,11 @@ namespace DetourNavigator void reportStats(unsigned int /*frameNumber*/, osg::Stats& /*stats*/) const override {} + RecastMeshTiles getRecastMeshTiles() override + { + return {}; + } + private: Settings mDefaultSettings {}; SharedNavMeshCacheItem mEmptyNavMeshCacheItem; diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 4bd797326..9e8619469 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -220,6 +220,17 @@ namespace DetourNavigator mAsyncNavMeshUpdater.reportStats(frameNumber, stats); } + RecastMeshTiles NavMeshManager::getRecastMeshTiles() + { + std::vector tiles; + mRecastMeshManager.forEachTilePosition( + [&tiles] (const TilePosition& tile) { tiles.push_back(tile); }); + RecastMeshTiles result; + std::transform(tiles.begin(), tiles.end(), std::inserter(result, result.end()), + [this] (const TilePosition& tile) { return std::make_pair(tile, mRecastMeshManager.getMesh(tile)); }); + return result; + } + void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType) { diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index 3ef898b05..a6bdca09b 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -5,6 +5,7 @@ #include "cachedrecastmeshmanager.hpp" #include "offmeshconnectionsmanager.hpp" #include "sharednavmesh.hpp" +#include "recastmeshtiles.hpp" #include @@ -52,6 +53,8 @@ namespace DetourNavigator void reportStats(unsigned int frameNumber, osg::Stats& stats) const; + RecastMeshTiles getRecastMeshTiles(); + private: const Settings& mSettings; TileCachedRecastMeshManager mRecastMeshManager; diff --git a/components/detournavigator/recastmesh.cpp b/components/detournavigator/recastmesh.cpp index 476799c1f..dc56f7b93 100644 --- a/components/detournavigator/recastmesh.cpp +++ b/components/detournavigator/recastmesh.cpp @@ -5,9 +5,11 @@ namespace DetourNavigator { - RecastMesh::RecastMesh(std::vector indices, std::vector vertices, std::vector areaTypes, - std::vector water, const std::size_t trianglesPerChunk) - : mIndices(std::move(indices)) + RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, std::vector indices, std::vector vertices, + std::vector areaTypes, std::vector water, const std::size_t trianglesPerChunk) + : mGeneration(generation) + , mRevision(revision) + , mIndices(std::move(indices)) , mVertices(std::move(vertices)) , mAreaTypes(std::move(areaTypes)) , mWater(std::move(water)) diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index 47d5f7963..f3259903f 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -24,8 +24,18 @@ namespace DetourNavigator btTransform mTransform; }; - RecastMesh(std::vector indices, std::vector vertices, std::vector areaTypes, - std::vector water, const std::size_t trianglesPerChunk); + RecastMesh(std::size_t generation, std::size_t revision, std::vector indices, std::vector vertices, + std::vector areaTypes, std::vector water, const std::size_t trianglesPerChunk); + + std::size_t getGeneration() const + { + return mGeneration; + } + + std::size_t getRevision() const + { + return mRevision; + } const std::vector& getIndices() const { @@ -68,6 +78,8 @@ namespace DetourNavigator } private: + std::size_t mGeneration; + std::size_t mRevision; std::vector mIndices; std::vector mVertices; std::vector mAreaTypes; diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index 5d8a07055..d96ba2f29 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -112,9 +112,10 @@ namespace DetourNavigator mWater.push_back(RecastMesh::Water {cellSize, transform}); } - std::shared_ptr RecastMeshBuilder::create() const + std::shared_ptr RecastMeshBuilder::create(std::size_t generation, std::size_t revision) const { - return std::make_shared(mIndices, mVertices, mAreaTypes, mWater, mSettings.get().mTrianglesPerChunk); + return std::make_shared(generation, revision, mIndices, mVertices, mAreaTypes, + mWater, mSettings.get().mTrianglesPerChunk); } void RecastMeshBuilder::reset() diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index 070b9c67d..d28558d0f 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -34,7 +34,7 @@ namespace DetourNavigator void addWater(const int mCellSize, const btTransform& transform); - std::shared_ptr create() const; + std::shared_ptr create(std::size_t generation, std::size_t revision) const; void reset(); diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 39afdf56e..05f250596 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -4,8 +4,8 @@ namespace DetourNavigator { - RecastMeshManager::RecastMeshManager(const Settings& settings, const TileBounds& bounds) - : mShouldRebuild(false) + RecastMeshManager::RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation) + : mGeneration(generation) , mMeshBuilder(settings, bounds) { } @@ -19,8 +19,8 @@ namespace DetourNavigator mObjectsOrder.erase(iterator); return false; } - mShouldRebuild = true; - return mShouldRebuild; + ++mRevision; + return true; } bool RecastMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType) @@ -30,8 +30,8 @@ namespace DetourNavigator return false; if (!object->second->update(transform, areaType)) return false; - mShouldRebuild = true; - return mShouldRebuild; + ++mRevision; + return true; } boost::optional RecastMeshManager::removeObject(const ObjectId id) @@ -42,7 +42,7 @@ namespace DetourNavigator const RemovedRecastMeshObject result {object->second->getShape(), object->second->getTransform()}; mObjectsOrder.erase(object->second); mObjects.erase(object); - mShouldRebuild = true; + ++mRevision; return result; } @@ -55,7 +55,7 @@ namespace DetourNavigator mWaterOrder.erase(iterator); return false; } - mShouldRebuild = true; + ++mRevision; return true; } @@ -64,7 +64,7 @@ namespace DetourNavigator const auto water = mWater.find(cellPosition); if (water == mWater.end()) return boost::none; - mShouldRebuild = true; + ++mRevision; const auto result = *water->second; mWaterOrder.erase(water->second); mWater.erase(water); @@ -74,7 +74,7 @@ namespace DetourNavigator std::shared_ptr RecastMeshManager::getMesh() { rebuild(); - return mMeshBuilder.create(); + return mMeshBuilder.create(mGeneration, mLastBuildRevision); } bool RecastMeshManager::isEmpty() const @@ -84,13 +84,13 @@ namespace DetourNavigator void RecastMeshManager::rebuild() { - if (!mShouldRebuild) + if (mLastBuildRevision == mRevision) return; mMeshBuilder.reset(); for (const auto& v : mWaterOrder) mMeshBuilder.addWater(v.mCellSize, v.mTransform); for (const auto& v : mObjectsOrder) mMeshBuilder.addObject(v.getShape(), v.getTransform(), v.getAreaType()); - mShouldRebuild = false; + mLastBuildRevision = mRevision; } } diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index a6f86bfcf..f1870ec6b 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -34,7 +34,7 @@ namespace DetourNavigator btTransform mTransform; }; - RecastMeshManager(const Settings& settings, const TileBounds& bounds); + RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation); bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, const AreaType areaType); @@ -52,7 +52,9 @@ namespace DetourNavigator bool isEmpty() const; private: - bool mShouldRebuild; + std::size_t mRevision = 0; + std::size_t mLastBuildRevision = 0; + std::size_t mGeneration; RecastMeshBuilder mMeshBuilder; std::list mObjectsOrder; std::unordered_map::iterator> mObjects; diff --git a/components/detournavigator/recastmeshtiles.hpp b/components/detournavigator/recastmeshtiles.hpp new file mode 100644 index 000000000..68e30ba63 --- /dev/null +++ b/components/detournavigator/recastmeshtiles.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHTILE_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHTILE_H + +#include "tileposition.hpp" +#include "recastmesh.hpp" + +#include +#include + +namespace DetourNavigator +{ + using RecastMeshTiles = std::map>; +} + +#endif diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 0cb1cfb80..bbdbd410a 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -121,7 +121,7 @@ namespace DetourNavigator tileBounds.mMin -= osg::Vec2f(border, border); tileBounds.mMax += osg::Vec2f(border, border); tile = tiles->insert(std::make_pair(tilePosition, - CachedRecastMeshManager(mSettings, tileBounds))).first; + CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; } if (tile->second.addWater(cellPosition, cellSize, transform)) { @@ -151,7 +151,10 @@ namespace DetourNavigator continue; const auto tileResult = tile->second.removeWater(cellPosition); if (tile->second.isEmpty()) + { tiles->erase(tile); + ++mTilesGeneration; + } if (tileResult && !result) result = tileResult; } @@ -189,7 +192,8 @@ namespace DetourNavigator auto tileBounds = makeTileBounds(mSettings, tilePosition); tileBounds.mMin -= osg::Vec2f(border, border); tileBounds.mMax += osg::Vec2f(border, border); - tile = tiles.insert(std::make_pair(tilePosition, CachedRecastMeshManager(mSettings, tileBounds))).first; + tile = tiles.insert(std::make_pair( + tilePosition, CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; } return tile->second.addObject(id, shape, transform, areaType); } @@ -209,7 +213,10 @@ namespace DetourNavigator return boost::optional(); const auto tileResult = tile->second.removeObject(id); if (tile->second.isEmpty()) + { tiles.erase(tile); + ++mTilesGeneration; + } return tileResult; } } diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index a3d0ae1e5..4351c86bb 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -48,6 +48,7 @@ namespace DetourNavigator std::unordered_map> mObjectsTilesPositions; std::map> mWaterTilesPositions; std::size_t mRevision = 0; + std::size_t mTilesGeneration = 0; bool addTile(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, diff --git a/components/sceneutil/detourdebugdraw.cpp b/components/sceneutil/detourdebugdraw.cpp index ea8a4c2f6..b9c2fecef 100644 --- a/components/sceneutil/detourdebugdraw.cpp +++ b/components/sceneutil/detourdebugdraw.cpp @@ -50,10 +50,8 @@ namespace SceneUtil mDepthMask = state; } - void DebugDraw::texture(bool state) + void DebugDraw::texture(bool) { - if (state) - throw std::logic_error("DebugDraw does not support textures (at " __FILE__ ":" OPENMW_LINE_STRING ")"); } void DebugDraw::begin(osg::PrimitiveSet::Mode mode, float size) @@ -85,9 +83,10 @@ namespace SceneUtil vertex(pos[0], pos[1], pos[2], color, uv[0], uv[1]); } - void DebugDraw::vertex(const float, const float, const float, unsigned, const float, const float) + void DebugDraw::vertex(const float x, const float y, const float z, unsigned color, const float, const float) { - throw std::logic_error("Not implemented (at " __FILE__ ":" OPENMW_LINE_STRING ")"); + addVertex(osg::Vec3f(x, y, z)); + addColor(SceneUtil::colourFromRGBA(color)); } void DebugDraw::end() diff --git a/components/sceneutil/recastmesh.cpp b/components/sceneutil/recastmesh.cpp new file mode 100644 index 000000000..2716f4683 --- /dev/null +++ b/components/sceneutil/recastmesh.cpp @@ -0,0 +1,48 @@ +#include "navmesh.hpp" +#include "detourdebugdraw.hpp" + +#include +#include + +#include + +#include + +namespace +{ + std::vector calculateNormals(const std::vector& vertices, const std::vector& indices) + { + std::vector result(indices.size()); + for (std::size_t i = 0, n = indices.size(); i < n; i += 3) + { + const float* v0_ptr = &vertices[indices[i] * 3]; + const float* v1_ptr = &vertices[indices[i + 1] * 3]; + const float* v2_ptr = &vertices[indices[i + 2] * 3]; + const osg::Vec3f v0(v0_ptr[0], v0_ptr[1], v0_ptr[2]); + const osg::Vec3f v1(v1_ptr[0], v1_ptr[1], v1_ptr[2]); + const osg::Vec3f v2(v2_ptr[0], v2_ptr[1], v2_ptr[2]); + const osg::Vec3f e0 = v1 - v0; + const osg::Vec3f e1 = v2 - v0; + osg::Vec3f normal = e0 ^ e1; + normal.normalize(); + for (std::size_t j = 0; j < 3; ++j) + result[i + j] = normal[j]; + } + return result; + } +} + +namespace SceneUtil +{ + osg::ref_ptr createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh, + const DetourNavigator::Settings& settings) + { + const osg::ref_ptr group(new osg::Group); + DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f / settings.mRecastScaleFactor); + const auto normals = calculateNormals(recastMesh.getVertices(), recastMesh.getIndices()); + const auto texScale = 1.0f / (settings.mCellSize * 10.0f); + duDebugDrawTriMesh(&debugDraw, recastMesh.getVertices().data(), recastMesh.getVerticesCount(), + recastMesh.getIndices().data(), normals.data(), recastMesh.getTrianglesCount(), nullptr, texScale); + return group; + } +} diff --git a/components/sceneutil/recastmesh.hpp b/components/sceneutil/recastmesh.hpp new file mode 100644 index 000000000..ee5d9865e --- /dev/null +++ b/components/sceneutil/recastmesh.hpp @@ -0,0 +1,23 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_RECASTMESH_H +#define OPENMW_COMPONENTS_SCENEUTIL_RECASTMESH_H + +#include + +namespace osg +{ + class Group; +} + +namespace DetourNavigator +{ + class RecastMesh; + struct Settings; +} + +namespace SceneUtil +{ + osg::ref_ptr createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh, + const DetourNavigator::Settings& settings); +} + +#endif diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index 083048332..c7817b6e8 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -166,6 +166,20 @@ Make visible all NPC's and creaure's plans where they are going. Works even if Navigator is disabled. Potentially decreases performance. +enable recast mesh render +---------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Render recast mesh that is built as set of culled tiles from physical mesh. +Should show similar mesh to physical one. +Little difference can be a result of floating point error. +Absent pieces usually mean a bug in recast mesh tiles building. +Allows to do in-game debug. +Potentially decreases performance. + Expert settings *************** diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c6f7abfba..293f8ffaf 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -748,6 +748,9 @@ enable nav mesh render = false # Render agents paths (true, false) enable agents paths render = false +# Render recast mesh (true, false) +enable recast mesh render = false + # Max number of navmesh tiles (value >= 0) max tiles number = 512 From 5168f2059f892baa6cefc1c26b1c896a1d4f8f29 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 30 Nov 2019 13:52:17 +0100 Subject: [PATCH 2/2] Compare revisions by equality to support overflow --- apps/openmw/mwrender/navmesh.cpp | 2 +- components/detournavigator/navmeshmanager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/navmesh.cpp b/apps/openmw/mwrender/navmesh.cpp index 3a80ac8ca..7aade0c23 100644 --- a/apps/openmw/mwrender/navmesh.cpp +++ b/apps/openmw/mwrender/navmesh.cpp @@ -34,7 +34,7 @@ namespace MWRender void NavMesh::update(const dtNavMesh& navMesh, const std::size_t id, const std::size_t generation, const std::size_t revision, const DetourNavigator::Settings& settings) { - if (!mEnabled || (mGroup && mId == id && mGeneration >= generation && mRevision >= revision)) + if (!mEnabled || (mGroup && mId == id && mGeneration == generation && mRevision == revision)) return; mId = id; diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 9e8619469..a769981d3 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -147,7 +147,7 @@ namespace DetourNavigator const auto playerTile = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition)); auto& lastRevision = mLastRecastMeshManagerRevision[agentHalfExtents]; auto lastPlayerTile = mPlayerTile.find(agentHalfExtents); - if (lastRevision >= mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end() + if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end() && lastPlayerTile->second == playerTile) return; lastRevision = mRecastMeshManager.getRevision();