From 144e1a063b320e94ccb9d2458a6c139925191b64 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 26 May 2018 17:44:25 +0300 Subject: [PATCH] Support animated objects --- apps/openmw/mwphysics/physicssystem.hpp | 8 + apps/openmw/mwworld/worldimp.cpp | 19 +- apps/openmw_test_suite/CMakeLists.txt | 1 + .../detournavigator/navigator.cpp | 171 ++++++++++++++++++ .../detournavigator/recastmeshobject.cpp | 66 +++++++ components/CMakeLists.txt | 1 + .../detournavigator/asyncnavmeshupdater.cpp | 5 +- .../cachedrecastmeshmanager.cpp | 10 +- .../cachedrecastmeshmanager.hpp | 4 +- components/detournavigator/debug.hpp | 9 + components/detournavigator/navigator.cpp | 5 + components/detournavigator/navigator.hpp | 2 + components/detournavigator/navmeshmanager.cpp | 10 +- components/detournavigator/navmeshmanager.hpp | 2 + .../detournavigator/recastmeshmanager.cpp | 22 ++- .../detournavigator/recastmeshmanager.hpp | 19 +- .../detournavigator/recastmeshobject.cpp | 58 ++++++ .../detournavigator/recastmeshobject.hpp | 44 +++++ .../tilecachedrecastmeshmanager.cpp | 23 ++- .../tilecachedrecastmeshmanager.hpp | 4 +- 20 files changed, 460 insertions(+), 23 deletions(-) create mode 100644 apps/openmw_test_suite/detournavigator/recastmeshobject.cpp create mode 100644 components/detournavigator/recastmeshobject.cpp create mode 100644 components/detournavigator/recastmeshobject.hpp diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index b084cc4c9e..21fbe3f17a 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -174,6 +175,13 @@ namespace MWPhysics void markAsNonSolid (const MWWorld::ConstPtr& ptr); bool isOnSolidGround (const MWWorld::Ptr& actor) const; + + template + void forEachAnimatedObject(Function&& function) const + { + std::for_each(mAnimatedObjects.begin(), mAnimatedObjects.end(), function); + } + private: void updateWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce604580d0..9b8f97e8c7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include @@ -51,6 +53,7 @@ #include "../mwphysics/physicssystem.hpp" #include "../mwphysics/actor.hpp" #include "../mwphysics/collisiontype.hpp" +#include "../mwphysics/object.hpp" #include "player.hpp" #include "manualref.hpp" @@ -1535,6 +1538,16 @@ namespace MWWorld } if(player != results.end()) moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false); + + bool navigatorObjectsUpdated = false; + mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) + { + navigatorObjectsUpdated = mNavigator->updateObject(std::size_t(object), + *object->getCollisionObject()->getCollisionShape(), + object->getCollisionObject()->getWorldTransform()) || navigatorObjectsUpdated; + }); + if (navigatorObjectsUpdated) + mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3()); } bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2, bool ignoreDoors) @@ -2254,7 +2267,7 @@ namespace MWWorld float waterlevel = cell->getWaterLevel(); - // SwimHeightScale affects the upper z position an actor can swim to + // SwimHeightScale affects the upper z position an actor can swim to // while in water. Based on observation from the original engine, // the upper z position you get with a +1 SwimHeightScale is the depth // limit for being able to cast water walking on an underwater target. @@ -2400,7 +2413,7 @@ namespace MWWorld { mRendering->screenshot(image, w, h); } - + bool World::screenshot360(osg::Image* image, std::string settingStr) { return mRendering->screenshot360(image,settingStr); @@ -3573,7 +3586,7 @@ namespace MWWorld continue; } else - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, static_cast(effectIt->mArea * 2)); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, static_cast(effectIt->mArea * 2)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index fc04648e5a..b86f4b812c 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -22,6 +22,7 @@ if (GTEST_FOUND AND GMOCK_FOUND) detournavigator/settingsutils.cpp detournavigator/recastmeshbuilder.cpp detournavigator/gettilespositions.cpp + detournavigator/recastmeshobject.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 0e475ad9fc..de0636ca11 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include @@ -131,6 +133,175 @@ namespace })) << mPath; } + TEST_F(DetourNavigatorNavigatorTest, add_object_should_change_navmesh) + { + const std::array heightfieldData {{ + 0, 0, 0, 0, 0, + 0, -25, -25, -25, -25, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + }}; + btHeightfieldTerrainShape heightfieldShape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false); + heightfieldShape.setLocalScaling(btVector3(128, 128, 1)); + + btBoxShape boxShape(btVector3(20, 20, 100)); + btCompoundShape compoundShape; + compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape); + + mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addObject(1, heightfieldShape, btTransform::getIdentity()); + mNavigator->update(mPlayerPosition); + mNavigator->wait(); + + mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, std::back_inserter(mPath)); + + EXPECT_EQ(mPath, std::deque({ + osg::Vec3f(-215, 215, 1.85963428020477294921875), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), + osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), + osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), + osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), + osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), + osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(215, -215, 1.877177715301513671875), + })) << mPath; + + mNavigator->addObject(2, compoundShape, btTransform::getIdentity()); + mNavigator->update(mPlayerPosition); + mNavigator->wait(); + + mPath.clear(); + mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, std::back_inserter(mPath)); + + EXPECT_EQ(mPath, std::deque({ + osg::Vec3f(-215, 215, 1.87827122211456298828125), + osg::Vec3f(-199.7968292236328125, 191.09100341796875, -3.54876613616943359375), + osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847270965576171875), + osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.40817737579345703125), + osg::Vec3f(-154.1872711181640625, 119.36397552490234375, -19.837890625), + osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675952911376953125), + osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6972980499267578125), + osg::Vec3f(-108.57772064208984375, 47.636936187744140625, -36.12701416015625), + osg::Vec3f(-93.3745269775390625, 23.7279262542724609375, -40.754688262939453125), + osg::Vec3f(-78.17134857177734375, -0.18108306825160980224609375, -37.128787994384765625), + osg::Vec3f(-62.968158721923828125, -24.0900936126708984375, -33.50289154052734375), + osg::Vec3f(-47.764972686767578125, -47.999103546142578125, -30.797946929931640625), + osg::Vec3f(-23.852447509765625, -63.196765899658203125, -33.97112274169921875), + osg::Vec3f(0.0600789971649646759033203125, -78.39443206787109375, -37.14543914794921875), + osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.7740936279296875), + osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.051288604736328125), + osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.62355804443359375), + osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958160400390625), + osg::Vec3f(119.6226959228515625, -154.382720947265625, -19.7680912017822265625), + osg::Vec3f(143.53521728515625, -169.58038330078125, -14.3403491973876953125), + osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.91261768341064453125), + osg::Vec3f(191.360260009765625, -199.9757080078125, -3.484879016876220703125), + osg::Vec3f(215, -215, 1.87827455997467041015625), + })) << mPath; + } + + TEST_F(DetourNavigatorNavigatorTest, update_changed_object_should_change_navmesh) + { + const std::array heightfieldData {{ + 0, 0, 0, 0, 0, + 0, -25, -25, -25, -25, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + }}; + btHeightfieldTerrainShape heightfieldShape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false); + heightfieldShape.setLocalScaling(btVector3(128, 128, 1)); + + btBoxShape boxShape(btVector3(20, 20, 100)); + btCompoundShape compoundShape; + compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape); + + mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addObject(1, heightfieldShape, btTransform::getIdentity()); + mNavigator->addObject(2, compoundShape, btTransform::getIdentity()); + mNavigator->update(mPlayerPosition); + mNavigator->wait(); + + mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, std::back_inserter(mPath)); + + EXPECT_EQ(mPath, std::deque({ + osg::Vec3f(-215, 215, 1.87827122211456298828125), + osg::Vec3f(-199.7968292236328125, 191.09100341796875, -3.54876613616943359375), + osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847270965576171875), + osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.40817737579345703125), + osg::Vec3f(-154.1872711181640625, 119.36397552490234375, -19.837890625), + osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675952911376953125), + osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6972980499267578125), + osg::Vec3f(-108.57772064208984375, 47.636936187744140625, -36.12701416015625), + osg::Vec3f(-93.3745269775390625, 23.7279262542724609375, -40.754688262939453125), + osg::Vec3f(-78.17134857177734375, -0.18108306825160980224609375, -37.128787994384765625), + osg::Vec3f(-62.968158721923828125, -24.0900936126708984375, -33.50289154052734375), + osg::Vec3f(-47.764972686767578125, -47.999103546142578125, -30.797946929931640625), + osg::Vec3f(-23.852447509765625, -63.196765899658203125, -33.97112274169921875), + osg::Vec3f(0.0600789971649646759033203125, -78.39443206787109375, -37.14543914794921875), + osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.7740936279296875), + osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.051288604736328125), + osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.62355804443359375), + osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958160400390625), + osg::Vec3f(119.6226959228515625, -154.382720947265625, -19.7680912017822265625), + osg::Vec3f(143.53521728515625, -169.58038330078125, -14.3403491973876953125), + osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.91261768341064453125), + osg::Vec3f(191.360260009765625, -199.9757080078125, -3.484879016876220703125), + osg::Vec3f(215, -215, 1.87827455997467041015625), + })) << mPath; + + compoundShape.updateChildTransform(0, btTransform(btMatrix3x3::getIdentity(), btVector3(1000, 0, 0))); + + mNavigator->updateObject(2, compoundShape, btTransform::getIdentity()); + mNavigator->update(mPlayerPosition); + mNavigator->wait(); + + mPath.clear(); + mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, mOut); + + EXPECT_EQ(mPath, std::deque({ + osg::Vec3f(-215, 215, 1.85963428020477294921875), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), + osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), + osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), + osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), + osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), + osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(215, -215, 1.877177715301513671875), + })) << mPath; + } + TEST_F(DetourNavigatorNavigatorTest, for_overlapping_heightfields_should_use_higher) { const std::array heightfieldData {{ diff --git a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp new file mode 100644 index 0000000000..b0f03aa655 --- /dev/null +++ b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp @@ -0,0 +1,66 @@ +#include "operators.hpp" + +#include + +#include +#include + +#include + +namespace +{ + using namespace testing; + using namespace DetourNavigator; + + struct DetourNavigatorRecastMeshObjectTest : Test + { + btBoxShape mBoxShape {btVector3(1, 2, 3)}; + btCompoundShape mCompoundShape {btVector3(1, 2, 3)}; + btTransform mTransform {btQuaternion(btVector3(1, 2, 3), 1), btVector3(1, 2, 3)}; + + DetourNavigatorRecastMeshObjectTest() + { + mCompoundShape.addChildShape(mTransform, std::addressof(mBoxShape)); + } + }; + + TEST_F(DetourNavigatorRecastMeshObjectTest, constructed_object_should_have_shape_and_transform) + { + const RecastMeshObject object(mBoxShape, mTransform); + EXPECT_EQ(std::addressof(object.getShape()), std::addressof(mBoxShape)); + EXPECT_EQ(object.getTransform(), mTransform); + } + + TEST_F(DetourNavigatorRecastMeshObjectTest, update_with_same_transform_for_not_compound_shape_should_return_false) + { + RecastMeshObject object(mBoxShape, mTransform); + EXPECT_FALSE(object.update(mTransform)); + } + + TEST_F(DetourNavigatorRecastMeshObjectTest, update_with_different_transform_should_return_true) + { + RecastMeshObject object(mBoxShape, mTransform); + EXPECT_TRUE(object.update(btTransform::getIdentity())); + } + + TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_compound_shape_with_same_transform_and_not_changed_child_transform_should_return_false) + { + RecastMeshObject object(mCompoundShape, mTransform); + EXPECT_FALSE(object.update(mTransform)); + } + + TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_compound_shape_with_same_transform_and_changed_child_transform_should_return_true) + { + RecastMeshObject object(mCompoundShape, mTransform); + mCompoundShape.updateChildTransform(0, btTransform::getIdentity()); + EXPECT_TRUE(object.update(mTransform)); + } + + TEST_F(DetourNavigatorRecastMeshObjectTest, repeated_update_for_compound_shape_without_changes_should_return_false) + { + RecastMeshObject object(mCompoundShape, mTransform); + mCompoundShape.updateChildTransform(0, btTransform::getIdentity()); + object.update(mTransform); + EXPECT_FALSE(object.update(mTransform)); + } +} diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index fbb74a65a7..7ca7ce6734 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -169,6 +169,7 @@ add_component_dir(detournavigator chunkytrimesh recastmesh tilecachedrecastmeshmanager + recastmeshobject ) set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 20438674af..91af31e22e 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -78,6 +78,8 @@ namespace DetourNavigator makePriority(changedTile, playerTile)}); } + log("posted ", mJobs.size(), " jobs"); + mHasJob.notify_all(); } @@ -169,7 +171,8 @@ namespace DetourNavigator navMeshRevision = revision; } if (recastMesh && mSettings.get().mEnableWriteRecastMeshToFile) - writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix, recastMeshRevision); + writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix + std::to_string(job.mChangedTile.x()) + + "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision); if (mSettings.get().mEnableWriteNavMeshToFile) writeToFile(*job.mNavMeshCacheItem->mValue.lock(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); } diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 3699bc77d0..cba3946e00 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -16,7 +16,15 @@ namespace DetourNavigator return true; } - boost::optional CachedRecastMeshManager::removeObject(std::size_t id) + bool CachedRecastMeshManager::updateObject(std::size_t id, const btTransform& transform) + { + if (!mImpl.updateObject(id, transform)) + return false; + mCached.reset(); + return true; + } + + boost::optional CachedRecastMeshManager::removeObject(std::size_t id) { const auto object = mImpl.removeObject(id); if (object) diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index 5185c38169..71229ab2f4 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -14,7 +14,9 @@ namespace DetourNavigator bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform); - boost::optional removeObject(std::size_t id); + bool updateObject(std::size_t id, const btTransform& transform); + + boost::optional removeObject(std::size_t id); std::shared_ptr getMesh(); diff --git a/components/detournavigator/debug.hpp b/components/detournavigator/debug.hpp index 520851fbe6..bc52543221 100644 --- a/components/detournavigator/debug.hpp +++ b/components/detournavigator/debug.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,13 @@ namespace DetourNavigator class RecastMesh; + inline std::ostream& operator <<(std::ostream& stream, const std::chrono::steady_clock::time_point& value) + { + using float_s = std::chrono::duration>; + return stream << std::fixed << std::setprecision(4) + << std::chrono::duration_cast(value.time_since_epoch()).count(); + } + class Log { public: @@ -88,6 +96,7 @@ namespace DetourNavigator if (!log.isEnabled()) return; std::ostringstream stream; + stream << '[' << std::chrono::steady_clock::now() << "] "; write(stream, std::forward(values) ...); log.write(stream.str()); } diff --git a/components/detournavigator/navigator.cpp b/components/detournavigator/navigator.cpp index e2fc976a3a..913ba2e2ad 100644 --- a/components/detournavigator/navigator.cpp +++ b/components/detournavigator/navigator.cpp @@ -30,6 +30,11 @@ namespace DetourNavigator return mNavMeshManager.addObject(id, shape, transform); } + bool Navigator::updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform) + { + return mNavMeshManager.updateObject(id, shape, transform); + } + bool Navigator::removeObject(std::size_t id) { return mNavMeshManager.removeObject(id); diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index b8d77c705a..69529a9d45 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -19,6 +19,8 @@ namespace DetourNavigator bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform); + bool updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform); + bool removeObject(std::size_t id); void update(const osg::Vec3f& playerPosition); diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 5f6cdb93c3..c12351ee0a 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -30,12 +30,20 @@ namespace DetourNavigator return true; } + bool NavMeshManager::updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform) + { + if (!mRecastMeshManager.updateObject(id, transform)) + return false; + addChangedTiles(shape, transform); + return true; + } + bool NavMeshManager::removeObject(std::size_t id) { const auto object = mRecastMeshManager.removeObject(id); if (!object) return false; - addChangedTiles(*object->mShape, object->mTransform); + addChangedTiles(object->mShape, object->mTransform); return true; } diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index f0b273efd0..109aa2237f 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -25,6 +25,8 @@ namespace DetourNavigator bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform); + bool updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform); + bool removeObject(std::size_t id); void addAgent(const osg::Vec3f& agentHalfExtents); diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 919609190a..d4b905e7de 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -1,5 +1,6 @@ #include "recastmeshmanager.hpp" +#include #include namespace DetourNavigator @@ -12,18 +13,29 @@ namespace DetourNavigator bool RecastMeshManager::addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform) { - if (!mObjects.insert(std::make_pair(id, Object {&shape, transform})).second) + if (!mObjects.emplace(id, RecastMeshObject(shape, transform)).second) return false; mShouldRebuild = true; - return true; + return mShouldRebuild; } - boost::optional RecastMeshManager::removeObject(std::size_t id) + bool RecastMeshManager::updateObject(std::size_t id, const btTransform& transform) + { + const auto object = mObjects.find(id); + if (object == mObjects.end()) + return false; + if (!object->second.update(transform)) + return false; + mShouldRebuild = true; + return mShouldRebuild; + } + + boost::optional RecastMeshManager::removeObject(std::size_t id) { const auto object = mObjects.find(id); if (object == mObjects.end()) return boost::none; - const auto result = object->second; + const RemovedRecastMeshObject result {object->second.getShape(), object->second.getTransform()}; mObjects.erase(object); mShouldRebuild = true; return result; @@ -46,7 +58,7 @@ namespace DetourNavigator return; mMeshBuilder.reset(); for (const auto& v : mObjects) - mMeshBuilder.addObject(*v.second.mShape, v.second.mTransform); + mMeshBuilder.addObject(v.second.getShape(), v.second.getTransform()); mShouldRebuild = false; } } diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index f2aa7f871d..c8e32714e2 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H #include "recastmeshbuilder.hpp" +#include "recastmeshobject.hpp" #include @@ -13,20 +14,22 @@ class btCollisionShape; namespace DetourNavigator { + struct RemovedRecastMeshObject + { + std::reference_wrapper mShape; + btTransform mTransform; + }; + class RecastMeshManager { public: - struct Object - { - const btCollisionShape* mShape; - btTransform mTransform; - }; - RecastMeshManager(const Settings& settings, const TileBounds& bounds); bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform); - boost::optional removeObject(std::size_t id); + bool updateObject(std::size_t id, const btTransform& transform); + + boost::optional removeObject(std::size_t id); std::shared_ptr getMesh(); @@ -35,7 +38,7 @@ namespace DetourNavigator private: bool mShouldRebuild; RecastMeshBuilder mMeshBuilder; - std::unordered_map mObjects; + std::unordered_map mObjects; void rebuild(); }; diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp new file mode 100644 index 0000000000..b6727ba5e1 --- /dev/null +++ b/components/detournavigator/recastmeshobject.cpp @@ -0,0 +1,58 @@ +#include "recastmeshobject.hpp" + +#include + +#include + +#include + +namespace DetourNavigator +{ + RecastMeshObject::RecastMeshObject(const btCollisionShape& shape, const btTransform& transform) + : mShape(shape) + , mTransform(transform) + , mChildren(makeChildrenObjects(shape)) + { + } + + bool RecastMeshObject::update(const btTransform& transform) + { + bool result = false; + if (!(mTransform == transform)) + { + mTransform = transform; + result = true; + } + if (mShape.get().isCompound()) + result = updateCompoundObject(static_cast(mShape.get()), mChildren) || result; + return result; + } + + bool RecastMeshObject::updateCompoundObject(const btCompoundShape& shape, std::vector& children) + { + assert(static_cast(shape.getNumChildShapes()) == children.size()); + bool result = false; + for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i) + { + assert(shape.getChildShape(i) == std::addressof(children[static_cast(i)].mShape.get())); + result = children[static_cast(i)].update(shape.getChildTransform(i)) || result; + } + return result; + } + + std::vector makeChildrenObjects(const btCollisionShape& shape) + { + if (shape.isCompound()) + return makeChildrenObjects(static_cast(shape)); + else + return std::vector(); + } + + std::vector makeChildrenObjects(const btCompoundShape& shape) + { + std::vector result; + for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i) + result.emplace_back(*shape.getChildShape(i), shape.getChildTransform(i)); + return result; + } +} diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp new file mode 100644 index 0000000000..697acfa58e --- /dev/null +++ b/components/detournavigator/recastmeshobject.hpp @@ -0,0 +1,44 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHOBJECT_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHOBJECT_H + +#include + +#include +#include + +class btCollisionShape; +class btCompoundShape; + +namespace DetourNavigator +{ + class RecastMeshObject + { + public: + RecastMeshObject(const btCollisionShape& shape, const btTransform& transform); + + bool update(const btTransform& transform); + + const btCollisionShape& getShape() const + { + return mShape; + } + + const btTransform& getTransform() const + { + return mTransform; + } + + private: + std::reference_wrapper mShape; + btTransform mTransform; + std::vector mChildren; + + static bool updateCompoundObject(const btCompoundShape& shape, std::vector& children); + }; + + std::vector makeChildrenObjects(const btCollisionShape& shape); + + std::vector makeChildrenObjects(const btCompoundShape& shape); +} + +#endif diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index eb4dffcb6b..346ab9fd1c 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -40,12 +40,31 @@ namespace DetourNavigator return result; } - boost::optional TileCachedRecastMeshManager::removeObject(std::size_t id) + bool TileCachedRecastMeshManager::updateObject(std::size_t id, const btTransform& transform) + { + const auto object = mObjectsTilesPositions.find(id); + if (object == mObjectsTilesPositions.end()) + return false; + bool result = false; + std::unique_lock lock(mTilesMutex); + for (const auto& tilePosition : object->second) + { + const auto tile = mTiles.find(tilePosition); + if (tile != mTiles.end()) + result = tile->second.updateObject(id, transform) || result; + } + lock.unlock(); + if (result) + ++mRevision; + return result; + } + + boost::optional TileCachedRecastMeshManager::removeObject(std::size_t id) { const auto object = mObjectsTilesPositions.find(id); if (object == mObjectsTilesPositions.end()) return boost::none; - boost::optional result; + boost::optional result; for (const auto& tilePosition : object->second) { std::unique_lock lock(mTilesMutex); diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 1c685b2ec6..9e5c07e846 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -16,7 +16,9 @@ namespace DetourNavigator bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform); - boost::optional removeObject(std::size_t id); + bool updateObject(std::size_t id, const btTransform& transform); + + boost::optional removeObject(std::size_t id); std::shared_ptr getMesh(const TilePosition& tilePosition);