From 4574e5f565cec7c60aa7e962fc8ea776ed47d9fb Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 1 Aug 2021 01:27:41 +0200 Subject: [PATCH 1/3] Remove redundant Navigator API functions --- .../detournavigator/navigator.cpp | 30 +++++++++---------- components/detournavigator/navigator.hpp | 18 ----------- components/detournavigator/navigatorimpl.cpp | 14 ++------- components/detournavigator/navigatorimpl.hpp | 4 --- components/detournavigator/navigatorstub.hpp | 10 ------- 5 files changed, 17 insertions(+), 59 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index a75275079b..05d8b4b663 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -221,7 +221,7 @@ namespace Vec3fEq(204, -204, 1.99998295307159423828125) )) << mPath; - mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&compoundShape), ObjectShapes(compoundShape, nullptr), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -273,7 +273,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); - mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&compoundShape), ObjectShapes(compoundShape, nullptr), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -307,7 +307,7 @@ namespace compoundShape.updateChildTransform(0, btTransform(btMatrix3x3::getIdentity(), btVector3(1000, 0, 0))); - mNavigator->updateObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); + mNavigator->updateObject(ObjectId(&compoundShape), ObjectShapes(compoundShape, nullptr), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -364,8 +364,8 @@ namespace shape2.setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); - mNavigator->addObject(ObjectId(&shape2), shape2, btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&shape), ObjectShapes(shape, nullptr), btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&shape2), ObjectShapes(shape2, nullptr), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -670,7 +670,7 @@ namespace shape.setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&shape), ObjectShapes(shape, nullptr), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -678,7 +678,7 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&shape), ObjectShapes(shape, nullptr), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -813,7 +813,7 @@ namespace for (std::size_t i = 0; i < boxShapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 10, i * 10, i * 10)); - mNavigator->addObject(ObjectId(&boxShapes[i]), boxShapes[i], transform); + mNavigator->addObject(ObjectId(&boxShapes[i]), ObjectShapes(boxShapes[i], nullptr), transform); } std::this_thread::sleep_for(std::chrono::microseconds(1)); @@ -821,7 +821,7 @@ namespace for (std::size_t i = 0; i < boxShapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 10 + 1, i * 10 + 1, i * 10 + 1)); - mNavigator->updateObject(ObjectId(&boxShapes[i]), boxShapes[i], transform); + mNavigator->updateObject(ObjectId(&boxShapes[i]), ObjectShapes(boxShapes[i], nullptr), transform); } mNavigator->update(mPlayerPosition); @@ -865,7 +865,7 @@ namespace for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32, i * 32, i * 32)); - mNavigator->addObject(ObjectId(&shapes[i]), shapes[i], transform); + mNavigator->addObject(ObjectId(&shapes[i]), ObjectShapes(shapes[i], nullptr), transform); } mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -874,7 +874,7 @@ namespace for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32 + 1, i * 32 + 1, i * 32 + 1)); - mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); + mNavigator->updateObject(ObjectId(&shapes[i]), ObjectShapes(shapes[i], nullptr), transform); } mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -882,7 +882,7 @@ namespace for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32 + 2, i * 32 + 2, i * 32 + 2)); - mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); + mNavigator->updateObject(ObjectId(&shapes[i]), ObjectShapes(shapes[i], nullptr), transform); } mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -932,10 +932,10 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); - mNavigator->addObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, + mNavigator->addObject(ObjectId(&oscillatingBoxShape), ObjectShapes(oscillatingBoxShape, nullptr), btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition)); // add this box to make navmesh bound box independent from oscillatingBoxShape rotations - mNavigator->addObject(ObjectId(&boderBoxShape), boderBoxShape, + mNavigator->addObject(ObjectId(&boderBoxShape), ObjectShapes(boderBoxShape, nullptr), btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200))); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -952,7 +952,7 @@ namespace { const btTransform transform(btQuaternion(btVector3(0, 0, 1), n * 2 * osg::PI / 10), oscillatingBoxShapePosition); - mNavigator->updateObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, transform); + mNavigator->updateObject(ObjectId(&oscillatingBoxShape), ObjectShapes(oscillatingBoxShape, nullptr), transform); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); } diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 6e0f773fb6..e1c4694642 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -72,15 +72,6 @@ namespace DetourNavigator */ virtual void removeAgent(const osg::Vec3f& agentHalfExtents) = 0; - /** - * @brief addObject is used to add object represented by single btCollisionShape and btTransform. - * @param id is used to distinguish different objects. - * @param shape must live until object is updated by another shape removed from Navigator. - * @param transform allows to setup object geometry according to its world state. - * @return true if object is added, false if there is already object with given id. - */ - virtual bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) = 0; - /** * @brief addObject is used to add complex object with allowed to walk and avoided to walk shapes * @param id is used to distinguish different objects @@ -99,15 +90,6 @@ namespace DetourNavigator */ virtual bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; - /** - * @brief updateObject replace object geometry by given data. - * @param id is used to find object. - * @param shape must live until object is updated by another shape removed from Navigator. - * @param transform allows to setup objects geometry according to its world state. - * @return true if object is updated, false if there is no object with given id. - */ - virtual bool updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) = 0; - /** * @brief updateObject replace object geometry by given data. * @param id is used to find object. diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index e256d8f76f..2168497cc3 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -32,14 +32,9 @@ namespace DetourNavigator --it->second; } - bool NavigatorImpl::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) - { - return mNavMeshManager.addObject(id, shape, transform, AreaType_ground); - } - bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { - bool result = addObject(id, shapes.mShape, transform); + bool result = mNavMeshManager.addObject(id, shapes.mShape, transform, AreaType_ground); if (shapes.mAvoid) { const ObjectId avoidId(shapes.mAvoid); @@ -65,14 +60,9 @@ namespace DetourNavigator return false; } - bool NavigatorImpl::updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) - { - return mNavMeshManager.updateObject(id, shape, transform, AreaType_ground); - } - bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { - bool result = updateObject(id, shapes.mShape, transform); + bool result = mNavMeshManager.updateObject(id, shapes.mShape, transform, AreaType_ground); if (shapes.mAvoid) { const ObjectId avoidId(shapes.mAvoid); diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index 35a6888551..cda6158958 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -21,14 +21,10 @@ namespace DetourNavigator void removeAgent(const osg::Vec3f& agentHalfExtents) override; - bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) override; - bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; - bool updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform) override; - bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 2d2fc936ca..40de90f256 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -19,11 +19,6 @@ namespace DetourNavigator void removeAgent(const osg::Vec3f& /*agentHalfExtents*/) override {} - bool addObject(const ObjectId /*id*/, const btCollisionShape& /*shape*/, const btTransform& /*transform*/) override - { - return false; - } - bool addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override { return false; @@ -34,11 +29,6 @@ namespace DetourNavigator return false; } - bool updateObject(const ObjectId /*id*/, const btCollisionShape& /*shape*/, const btTransform& /*transform*/) override - { - return false; - } - bool updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override { return false; From c8987bda2f1c19fe877c90ae20f9e4ca5904e806 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 1 Aug 2021 02:13:55 +0200 Subject: [PATCH 2/3] Store reference to BulletShapeInstance for btCollisionShape To keep btCollisionShape lifetime. --- apps/openmw/mwworld/scene.cpp | 16 +-- apps/openmw/mwworld/worldimp.cpp | 5 +- .../detournavigator/navigator.cpp | 116 +++++++++++------- .../detournavigator/recastmeshobject.cpp | 16 +-- .../tilecachedrecastmeshmanager.cpp | 75 ++++++----- .../cachedrecastmeshmanager.cpp | 2 +- .../cachedrecastmeshmanager.hpp | 2 +- components/detournavigator/navigator.hpp | 13 +- components/detournavigator/navigatorimpl.cpp | 20 +-- components/detournavigator/navmeshmanager.cpp | 7 +- components/detournavigator/navmeshmanager.hpp | 4 +- .../detournavigator/recastmeshmanager.cpp | 2 +- .../detournavigator/recastmeshmanager.hpp | 2 +- .../detournavigator/recastmeshobject.cpp | 45 ++++--- .../detournavigator/recastmeshobject.hpp | 27 +++- .../tilecachedrecastmeshmanager.cpp | 6 +- .../tilecachedrecastmeshmanager.hpp | 8 +- components/resource/bulletshape.cpp | 4 + 18 files changed, 221 insertions(+), 149 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8c401dcf12..3de4940a37 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -151,11 +151,9 @@ namespace { if (ptr.getClass().isDoor() && !ptr.getCellRef().getTeleport()) { - const auto shape = object->getShapeInstance()->getCollisionShape(); - btVector3 aabbMin; btVector3 aabbMax; - shape->getAabb(btTransform::getIdentity(), aabbMin, aabbMax); + object->getShapeInstance()->getCollisionShape()->getAabb(btTransform::getIdentity(), aabbMin, aabbMax); const auto center = (aabbMax + aabbMin) * 0.5f; @@ -182,12 +180,7 @@ namespace navigator.addObject( DetourNavigator::ObjectId(object), - DetourNavigator::DoorShapes( - *shape, - object->getShapeInstance()->getAvoidCollisionShape(), - connectionStart, - connectionEnd - ), + DetourNavigator::DoorShapes(object->getShapeInstance(), connectionStart, connectionEnd), transform ); } @@ -195,10 +188,7 @@ namespace { navigator.addObject( DetourNavigator::ObjectId(object), - DetourNavigator::ObjectShapes { - *object->getShapeInstance()->getCollisionShape(), - object->getShapeInstance()->getAvoidCollisionShape() - }, + DetourNavigator::ObjectShapes(object->getShapeInstance()), object->getTransform() ); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5fcab477cf..54b15e4412 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1533,10 +1533,7 @@ namespace MWWorld void World::updateNavigatorObject(const MWPhysics::Object& object) { - const DetourNavigator::ObjectShapes shapes { - *object.getShapeInstance()->getCollisionShape(), - object.getShapeInstance()->getAvoidCollisionShape() - }; + const DetourNavigator::ObjectShapes shapes(object.getShapeInstance()); mShouldUpdateNavigator = mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform()) || mShouldUpdateNavigator; } diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 05d8b4b663..35fde5b657 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -5,6 +5,9 @@ #include #include #include +#include + +#include #include #include @@ -15,6 +18,7 @@ #include #include +#include MATCHER_P3(Vec3fEq, x, y, z, "") { @@ -84,14 +88,15 @@ namespace }; template - btHeightfieldTerrainShape makeSquareHeightfieldTerrainShape(const std::array& values, + std::unique_ptr makeSquareHeightfieldTerrainShape(const std::array& values, btScalar heightScale = 1, int upAxis = 2, PHY_ScalarType heightDataType = PHY_FLOAT, bool flipQuadEdges = false) { const int width = static_cast(std::sqrt(size)); const btScalar min = *std::min_element(values.begin(), values.end()); const btScalar max = *std::max_element(values.begin(), values.end()); const btScalar greater = std::max(std::abs(min), std::abs(max)); - return btHeightfieldTerrainShape(width, width, values.data(), heightScale, -greater, greater, upAxis, heightDataType, flipQuadEdges); + return std::make_unique(width, width, values.data(), heightScale, -greater, greater, + upAxis, heightDataType, flipQuadEdges); } template @@ -107,6 +112,27 @@ namespace return surface; } + template + osg::ref_ptr makeBulletShapeInstance(std::unique_ptr&& shape) + { + osg::ref_ptr bulletShape(new Resource::BulletShape); + bulletShape->mCollisionShape = std::move(shape).release(); + return new Resource::BulletShapeInstance(bulletShape); + } + + template + class CollisionShapeInstance + { + public: + CollisionShapeInstance(std::unique_ptr&& shape) : mInstance(makeBulletShapeInstance(std::move(shape))) {} + + T& shape() { return static_cast(*mInstance->mCollisionShape); } + const osg::ref_ptr& instance() const { return mInstance; } + + private: + osg::ref_ptr mInstance; + }; + TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty) { EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), @@ -185,9 +211,8 @@ namespace }}; const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); - btBoxShape boxShape(btVector3(20, 20, 100)); - btCompoundShape compoundShape; - compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape); + CollisionShapeInstance compound(std::make_unique()); + compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); mNavigator->addAgent(mAgentHalfExtents); mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); @@ -221,7 +246,7 @@ namespace Vec3fEq(204, -204, 1.99998295307159423828125) )) << mPath; - mNavigator->addObject(ObjectId(&compoundShape), ObjectShapes(compoundShape, nullptr), btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance()), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -267,13 +292,12 @@ namespace }}; const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); - btBoxShape boxShape(btVector3(20, 20, 100)); - btCompoundShape compoundShape; - compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape); + CollisionShapeInstance compound(std::make_unique()); + compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); mNavigator->addAgent(mAgentHalfExtents); mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); - mNavigator->addObject(ObjectId(&compoundShape), ObjectShapes(compoundShape, nullptr), btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance()), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -305,9 +329,9 @@ namespace Vec3fEq(204, -204, 1.99998295307159423828125) )) << mPath; - compoundShape.updateChildTransform(0, btTransform(btMatrix3x3::getIdentity(), btVector3(1000, 0, 0))); + compound.shape().updateChildTransform(0, btTransform(btMatrix3x3::getIdentity(), btVector3(1000, 0, 0))); - mNavigator->updateObject(ObjectId(&compoundShape), ObjectShapes(compoundShape, nullptr), btTransform::getIdentity()); + mNavigator->updateObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance()), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -350,8 +374,8 @@ namespace 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData1); - shape.setLocalScaling(btVector3(128, 128, 1)); + CollisionShapeInstance heightfield1(makeSquareHeightfieldTerrainShape(heightfieldData1)); + heightfield1.shape().setLocalScaling(btVector3(128, 128, 1)); const std::array heightfieldData2 {{ -25, -25, -25, -25, -25, @@ -360,12 +384,12 @@ namespace -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, }}; - btHeightfieldTerrainShape shape2 = makeSquareHeightfieldTerrainShape(heightfieldData2); - shape2.setLocalScaling(btVector3(128, 128, 1)); + CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2)); + heightfield2.shape().setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), ObjectShapes(shape, nullptr), btTransform::getIdentity()); - mNavigator->addObject(ObjectId(&shape2), ObjectShapes(shape2, nullptr), btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance()), btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance()), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -424,6 +448,8 @@ namespace TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape) { + osg::ref_ptr bulletShape(new Resource::BulletShape); + std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, @@ -431,8 +457,9 @@ namespace 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + std::unique_ptr shapePtr = makeSquareHeightfieldTerrainShape(heightfieldData); + shapePtr->setLocalScaling(btVector3(128, 128, 1)); + bulletShape->mCollisionShape = shapePtr.release(); std::array heightfieldDataAvoid {{ -25, -25, -25, -25, -25, @@ -441,11 +468,14 @@ namespace -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, }}; - btHeightfieldTerrainShape shapeAvoid = makeSquareHeightfieldTerrainShape(heightfieldDataAvoid); - shapeAvoid.setLocalScaling(btVector3(128, 128, 1)); + std::unique_ptr shapeAvoidPtr = makeSquareHeightfieldTerrainShape(heightfieldDataAvoid); + shapeAvoidPtr->setLocalScaling(btVector3(128, 128, 1)); + bulletShape->mAvoidCollisionShape = shapeAvoidPtr.release(); + + osg::ref_ptr instance(new Resource::BulletShapeInstance(bulletShape)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), ObjectShapes {shape, &shapeAvoid}, btTransform::getIdentity()); + mNavigator->addObject(ObjectId(instance->getCollisionShape()), ObjectShapes(instance), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -666,19 +696,19 @@ namespace 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData)); + heightfield.shape().setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), ObjectShapes(shape, nullptr), btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance()), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - mNavigator->removeObject(ObjectId(&shape)); + mNavigator->removeObject(ObjectId(&heightfield.shape())); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); - mNavigator->addObject(ObjectId(&shape), ObjectShapes(shape, nullptr), btTransform::getIdentity()); + mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance()), btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -804,24 +834,25 @@ namespace }}; const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); - const std::vector boxShapes(100, btVector3(20, 20, 100)); + std::vector> boxes; + std::generate_n(std::back_inserter(boxes), 100, [] { return std::make_unique(btVector3(20, 20, 100)); }); mNavigator->addAgent(mAgentHalfExtents); mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); - for (std::size_t i = 0; i < boxShapes.size(); ++i) + for (std::size_t i = 0; i < boxes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 10, i * 10, i * 10)); - mNavigator->addObject(ObjectId(&boxShapes[i]), ObjectShapes(boxShapes[i], nullptr), transform); + mNavigator->addObject(ObjectId(&boxes[i].shape()), ObjectShapes(boxes[i].instance()), transform); } std::this_thread::sleep_for(std::chrono::microseconds(1)); - for (std::size_t i = 0; i < boxShapes.size(); ++i) + for (std::size_t i = 0; i < boxes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 10 + 1, i * 10 + 1, i * 10 + 1)); - mNavigator->updateObject(ObjectId(&boxShapes[i]), ObjectShapes(boxShapes[i], nullptr), transform); + mNavigator->updateObject(ObjectId(&boxes[i].shape()), ObjectShapes(boxes[i].instance()), transform); } mNavigator->update(mPlayerPosition); @@ -858,14 +889,15 @@ namespace TEST_F(DetourNavigatorNavigatorTest, update_changed_multiple_times_object_should_delay_navmesh_change) { - const std::vector shapes(100, btVector3(64, 64, 64)); + std::vector> shapes; + std::generate_n(std::back_inserter(shapes), 100, [] { return std::make_unique(btVector3(64, 64, 64)); }); mNavigator->addAgent(mAgentHalfExtents); for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32, i * 32, i * 32)); - mNavigator->addObject(ObjectId(&shapes[i]), ObjectShapes(shapes[i], nullptr), transform); + mNavigator->addObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance()), transform); } mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -874,7 +906,7 @@ namespace for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32 + 1, i * 32 + 1, i * 32 + 1)); - mNavigator->updateObject(ObjectId(&shapes[i]), ObjectShapes(shapes[i], nullptr), transform); + mNavigator->updateObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance()), transform); } mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -882,7 +914,7 @@ namespace for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32 + 2, i * 32 + 2, i * 32 + 2)); - mNavigator->updateObject(ObjectId(&shapes[i]), ObjectShapes(shapes[i], nullptr), transform); + mNavigator->updateObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance()), transform); } mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -926,16 +958,16 @@ namespace }}; const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); - const btBoxShape oscillatingBoxShape(btVector3(20, 20, 20)); + CollisionShapeInstance oscillatingBox(std::make_unique(btVector3(20, 20, 20))); const btVector3 oscillatingBoxShapePosition(32, 32, 400); - const btBoxShape boderBoxShape(btVector3(50, 50, 50)); + CollisionShapeInstance boderBox(std::make_unique(btVector3(50, 50, 50))); mNavigator->addAgent(mAgentHalfExtents); mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); - mNavigator->addObject(ObjectId(&oscillatingBoxShape), ObjectShapes(oscillatingBoxShape, nullptr), + mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance()), btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition)); // add this box to make navmesh bound box independent from oscillatingBoxShape rotations - mNavigator->addObject(ObjectId(&boderBoxShape), ObjectShapes(boderBoxShape, nullptr), + mNavigator->addObject(ObjectId(&boderBox.shape()), ObjectShapes(boderBox.instance()), btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200))); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -952,7 +984,7 @@ namespace { const btTransform transform(btQuaternion(btVector3(0, 0, 1), n * 2 * osg::PI / 10), oscillatingBoxShapePosition); - mNavigator->updateObject(ObjectId(&oscillatingBoxShape), ObjectShapes(oscillatingBoxShape, nullptr), transform); + mNavigator->updateObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance()), transform); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); } diff --git a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp index 621db51a89..7751d5220c 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp @@ -14,20 +14,22 @@ namespace struct DetourNavigatorRecastMeshObjectTest : Test { - btBoxShape mBoxShape {btVector3(1, 2, 3)}; - btCompoundShape mCompoundShape {true}; + btBoxShape mBoxShapeImpl {btVector3(1, 2, 3)}; + CollisionShape mBoxShape {nullptr, mBoxShapeImpl}; + btCompoundShape mCompoundShapeImpl {true}; + CollisionShape mCompoundShape {nullptr, mCompoundShapeImpl}; btTransform mTransform {btQuaternion(btVector3(1, 2, 3), 1), btVector3(1, 2, 3)}; DetourNavigatorRecastMeshObjectTest() { - mCompoundShape.addChildShape(mTransform, std::addressof(mBoxShape)); + mCompoundShapeImpl.addChildShape(mTransform, std::addressof(mBoxShapeImpl)); } }; TEST_F(DetourNavigatorRecastMeshObjectTest, constructed_object_should_have_shape_and_transform) { const RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); - EXPECT_EQ(std::addressof(object.getShape()), std::addressof(mBoxShape)); + EXPECT_EQ(std::addressof(object.getShape()), std::addressof(mBoxShapeImpl)); EXPECT_EQ(object.getTransform(), mTransform); } @@ -58,14 +60,14 @@ namespace TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_compound_shape_with_same_transform_and_changed_child_transform_should_return_true) { RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground); - mCompoundShape.updateChildTransform(0, btTransform::getIdentity()); + mCompoundShapeImpl.updateChildTransform(0, btTransform::getIdentity()); EXPECT_TRUE(object.update(mTransform, AreaType_ground)); } TEST_F(DetourNavigatorRecastMeshObjectTest, repeated_update_for_compound_shape_without_changes_should_return_false) { RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground); - mCompoundShape.updateChildTransform(0, btTransform::getIdentity()); + mCompoundShapeImpl.updateChildTransform(0, btTransform::getIdentity()); object.update(mTransform, AreaType_ground); EXPECT_FALSE(object.update(mTransform, AreaType_ground)); } @@ -73,7 +75,7 @@ namespace TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_changed_local_scaling_should_return_true) { RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); - mBoxShape.setLocalScaling(btVector3(2, 2, 2)); + mBoxShapeImpl.setLocalScaling(btVector3(2, 2, 2)); EXPECT_TRUE(object.update(mTransform, AreaType_ground)); } } diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index 4c49e75dc9..51580906ce 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -62,22 +62,25 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - EXPECT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + const CollisionShape shape(nullptr, boxShape); + EXPECT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_existing_object_should_return_false) { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); - EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_add_tiles) { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + const CollisionShape shape(nullptr, boxShape); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); for (int x = -1; x < 1; ++x) for (int y = -1; y < 1; ++y) ASSERT_TRUE(manager.hasTile(TilePosition(x, y))); @@ -88,8 +91,9 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); - manager.addObject(ObjectId(&boxShape), boxShape, transform, AreaType::AreaType_ground); - EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); + EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [&] (const auto& v) { onChangedTile(v); })); EXPECT_THAT( mChangedTiles, @@ -102,8 +106,9 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); - EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [&] (const auto& v) { onChangedTile(v); })); EXPECT_EQ(mChangedTiles, std::vector()); } @@ -112,7 +117,8 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); @@ -123,7 +129,8 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_EQ(manager.getMesh(TilePosition(1, 0)), nullptr); } @@ -132,14 +139,15 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); + const CollisionShape shape(nullptr, boxShape); - manager.addObject(ObjectId(&boxShape), boxShape, transform, AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(1, -1)), nullptr); - manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); + manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); @@ -151,12 +159,13 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); + const CollisionShape shape(nullptr, boxShape); - manager.addObject(ObjectId(&boxShape), boxShape, transform, AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr); EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr); - manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); + manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); EXPECT_EQ(manager.getMesh(TilePosition(1, 0)), nullptr); EXPECT_EQ(manager.getMesh(TilePosition(1, -1)), nullptr); } @@ -165,7 +174,8 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); manager.removeObject(ObjectId(&boxShape)); EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr); EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr); @@ -177,14 +187,15 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); + const CollisionShape shape(nullptr, boxShape); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); - manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); + manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); EXPECT_NE(manager.getMesh(TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); @@ -196,7 +207,8 @@ namespace TileCachedRecastMeshManager manager(mSettings); const auto initialRevision = manager.getRevision(); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_EQ(manager.getRevision(), initialRevision + 1); } @@ -204,9 +216,10 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); const auto beforeAddRevision = manager.getRevision(); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_EQ(manager.getRevision(), beforeAddRevision); } @@ -215,9 +228,10 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); - manager.addObject(ObjectId(&boxShape), boxShape, transform, AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); const auto beforeUpdateRevision = manager.getRevision(); - manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); + manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision + 1); } @@ -225,9 +239,10 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); const auto beforeUpdateRevision = manager.getRevision(); - manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); + manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision); } @@ -235,7 +250,8 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); + const CollisionShape shape(nullptr, boxShape); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); const auto beforeRemoveRevision = manager.getRevision(); manager.removeObject(ObjectId(&boxShape)); EXPECT_EQ(manager.getRevision(), beforeRemoveRevision + 1); @@ -272,7 +288,8 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + const CollisionShape shape(nullptr, boxShape); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); const osg::Vec2i cellPosition(0, 0); const int cellSize = std::numeric_limits::max(); ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); @@ -314,7 +331,8 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + const CollisionShape shape(nullptr, boxShape); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); @@ -330,7 +348,8 @@ namespace const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; const btBoxShape boxShape(btVector3(20, 20, 100)); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + const CollisionShape shape(nullptr, boxShape); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); ASSERT_TRUE(manager.removeObject(ObjectId(&boxShape))); for (int x = -6; x < 6; ++x) diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 154da806d7..36f5e9e03a 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -8,7 +8,7 @@ namespace DetourNavigator : mImpl(settings, bounds, generation) {} - bool CachedRecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, + bool CachedRecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType) { if (!mImpl.addObject(id, shape, transform, areaType)) diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index ab7bb9e7cb..1af249404b 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -12,7 +12,7 @@ namespace DetourNavigator public: CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation); - bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index e1c4694642..1a78b602cd 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -10,6 +10,8 @@ #include "waitconditiontype.hpp" #include "heightfieldshape.hpp" +#include + #include namespace ESM @@ -27,11 +29,10 @@ namespace DetourNavigator { struct ObjectShapes { - const btCollisionShape& mShape; - const btCollisionShape* mAvoid; + osg::ref_ptr mShapeInstance; - ObjectShapes(const btCollisionShape& shape, const btCollisionShape* avoid) - : mShape(shape), mAvoid(avoid) + ObjectShapes(const osg::ref_ptr& shapeInstance) + : mShapeInstance(shapeInstance) {} }; @@ -40,9 +41,9 @@ namespace DetourNavigator osg::Vec3f mConnectionStart; osg::Vec3f mConnectionEnd; - DoorShapes(const btCollisionShape& shape, const btCollisionShape* avoid, + DoorShapes(const osg::ref_ptr& shapeInstance, const osg::Vec3f& connectionStart,const osg::Vec3f& connectionEnd) - : ObjectShapes(shape, avoid) + : ObjectShapes(shapeInstance) , mConnectionStart(connectionStart) , mConnectionEnd(connectionEnd) {} diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 2168497cc3..5a8488c8d0 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -34,11 +34,13 @@ namespace DetourNavigator bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { - bool result = mNavMeshManager.addObject(id, shapes.mShape, transform, AreaType_ground); - if (shapes.mAvoid) + CollisionShape collisionShape {shapes.mShapeInstance, *shapes.mShapeInstance->getCollisionShape()}; + bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground); + if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->getAvoidCollisionShape()) { - const ObjectId avoidId(shapes.mAvoid); - if (mNavMeshManager.addObject(avoidId, *shapes.mAvoid, transform, AreaType_null)) + const ObjectId avoidId(avoidShape); + CollisionShape collisionShape {shapes.mShapeInstance, *avoidShape}; + if (mNavMeshManager.addObject(avoidId, collisionShape, transform, AreaType_null)) { updateAvoidShapeId(id, avoidId); result = true; @@ -62,11 +64,13 @@ namespace DetourNavigator bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { - bool result = mNavMeshManager.updateObject(id, shapes.mShape, transform, AreaType_ground); - if (shapes.mAvoid) + const CollisionShape collisionShape {shapes.mShapeInstance, *shapes.mShapeInstance->getCollisionShape()}; + bool result = mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground); + if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->getAvoidCollisionShape()) { - const ObjectId avoidId(shapes.mAvoid); - if (mNavMeshManager.updateObject(avoidId, *shapes.mAvoid, transform, AreaType_null)) + const ObjectId avoidId(avoidShape); + const CollisionShape collisionShape {shapes.mShapeInstance, *avoidShape}; + if (mNavMeshManager.updateObject(avoidId, collisionShape, transform, AreaType_null)) { updateAvoidShapeId(id, avoidId); result = true; diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 287a3c8ef9..c378230845 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -47,16 +47,17 @@ namespace DetourNavigator , mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager) {} - bool NavMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType) { + const btCollisionShape& collisionShape = shape.getShape(); if (!mRecastMeshManager.addObject(id, shape, transform, areaType)) return false; - addChangedTiles(shape, transform, ChangeType::add); + addChangedTiles(collisionShape, transform, ChangeType::add); return true; } - bool NavMeshManager::updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool NavMeshManager::updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType) { return mRecastMeshManager.updateObject(id, shape, transform, areaType, diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index 390ba41ec8..76c9b1e0b9 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -24,10 +24,10 @@ namespace DetourNavigator public: NavMeshManager(const Settings& settings); - bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); - bool updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); bool removeObject(const ObjectId id); diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 151b3161c1..872996d9e6 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -35,7 +35,7 @@ namespace DetourNavigator { } - bool RecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool RecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType) { const auto object = mObjects.lower_bound(id); diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index 88124c44cf..fb7018d922 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -35,7 +35,7 @@ namespace DetourNavigator public: RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation); - bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp index 3f35462781..862460b34b 100644 --- a/components/detournavigator/recastmeshobject.cpp +++ b/components/detournavigator/recastmeshobject.cpp @@ -22,15 +22,36 @@ namespace DetourNavigator } return result; } + + std::vector makeChildrenObjects(const osg::ref_ptr& instance, + const btCompoundShape& shape, const AreaType areaType) + { + std::vector result; + for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i) + { + const CollisionShape collisionShape {instance, *shape.getChildShape(i)}; + result.emplace_back(collisionShape, shape.getChildTransform(i), areaType); + } + return result; + } + + std::vector makeChildrenObjects(const osg::ref_ptr& instance, + const btCollisionShape& shape, const AreaType areaType) + { + if (shape.isCompound()) + return makeChildrenObjects(std::move(instance), static_cast(shape), areaType); + return std::vector(); + } } - RecastMeshObject::RecastMeshObject(const btCollisionShape& shape, const btTransform& transform, + RecastMeshObject::RecastMeshObject(const CollisionShape& shape, const btTransform& transform, const AreaType areaType) - : mShape(shape) + : mShapeInstance(shape.getShapeInstance()) + , mShape(shape.getShape()) , mTransform(transform) , mAreaType(areaType) - , mLocalScaling(shape.getLocalScaling()) - , mChildren(makeChildrenObjects(shape, mAreaType)) + , mLocalScaling(mShape.get().getLocalScaling()) + , mChildren(makeChildrenObjects(mShapeInstance, mShape.get(), mAreaType)) { } @@ -57,20 +78,4 @@ namespace DetourNavigator || result; return result; } - - std::vector makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType) - { - if (shape.isCompound()) - return makeChildrenObjects(static_cast(shape), areaType); - else - return std::vector(); - } - - std::vector makeChildrenObjects(const btCompoundShape& shape, const AreaType areaType) - { - std::vector result; - for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i) - result.emplace_back(*shape.getChildShape(i), shape.getChildTransform(i), areaType); - return result; - } } diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp index e659300e68..81199c5bad 100644 --- a/components/detournavigator/recastmeshobject.hpp +++ b/components/detournavigator/recastmeshobject.hpp @@ -3,8 +3,12 @@ #include "areatype.hpp" +#include + #include +#include + #include #include @@ -13,10 +17,26 @@ class btCompoundShape; namespace DetourNavigator { + class CollisionShape + { + public: + CollisionShape(osg::ref_ptr instance, const btCollisionShape& shape) + : mShapeInstance(std::move(instance)) + , mShape(shape) + {} + + const osg::ref_ptr& getShapeInstance() const { return mShapeInstance; } + const btCollisionShape& getShape() const { return mShape; } + + private: + osg::ref_ptr mShapeInstance; + std::reference_wrapper mShape; + }; + class RecastMeshObject { public: - RecastMeshObject(const btCollisionShape& shape, const btTransform& transform, const AreaType areaType); + RecastMeshObject(const CollisionShape& shape, const btTransform& transform, const AreaType areaType); bool update(const btTransform& transform, const AreaType areaType); @@ -36,16 +56,13 @@ namespace DetourNavigator } private: + osg::ref_ptr mShapeInstance; std::reference_wrapper mShape; btTransform mTransform; AreaType mAreaType; btVector3 mLocalScaling; std::vector mChildren; }; - - std::vector makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType); - - std::vector makeChildrenObjects(const btCompoundShape& shape, const AreaType areaType); } #endif diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index a37d24399d..61bd973cbf 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -14,14 +14,14 @@ namespace DetourNavigator : mSettings(settings) {} - bool TileCachedRecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, + bool TileCachedRecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType) { std::vector tilesPositions; const auto border = getBorderSize(mSettings); { auto tiles = mTiles.lock(); - getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& tilePosition) + getTilesPositions(shape.getShape(), transform, mSettings, [&] (const TilePosition& tilePosition) { if (addTile(id, shape, transform, areaType, tilePosition, border, tiles.get())) tilesPositions.push_back(tilePosition); @@ -218,7 +218,7 @@ namespace DetourNavigator it->second.reportNavMeshChange(recastMeshVersion, navMeshVersion); } - bool TileCachedRecastMeshManager::addTile(const ObjectId id, const btCollisionShape& shape, + bool TileCachedRecastMeshManager::addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, std::map& tiles) { diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index f3292cbf9b..38d004ccca 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -22,11 +22,11 @@ namespace DetourNavigator public: TileCachedRecastMeshManager(const Settings& settings); - bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); template - bool updateObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType, OnChangedTile&& onChangedTile) { const auto object = mObjectsTilesPositions.find(id); @@ -56,7 +56,7 @@ namespace DetourNavigator changed = true; } }; - getTilesPositions(shape, transform, mSettings, onTilePosition); + getTilesPositions(shape.getShape(), transform, mSettings, onTilePosition); std::sort(newTiles.begin(), newTiles.end()); for (const auto& tile : currentTiles) { @@ -110,7 +110,7 @@ namespace DetourNavigator std::size_t mRevision = 0; std::size_t mTilesGeneration = 0; - bool addTile(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, + bool addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, std::map& tiles); diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index c6f6369dba..ce896610a9 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace Resource { @@ -75,6 +76,9 @@ btCollisionShape* BulletShape::duplicateCollisionShape(const btCollisionShape *s return new btBoxShape(*boxshape); } + if (shape->getShapeType() == TERRAIN_SHAPE_PROXYTYPE) + return new btHeightfieldTerrainShape(static_cast(*shape)); + throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); } From 050b7d31aac95b97a69fa9b122e75297327cbfba Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 1 Aug 2021 02:43:36 +0200 Subject: [PATCH 3/3] Create RecastMesh outside critical section To not lock main thread when it tries to update objects. --- .../cachedrecastmeshmanager.cpp | 23 +++++---- .../cachedrecastmeshmanager.hpp | 4 +- .../detournavigator/recastmeshmanager.cpp | 32 +++++++++--- .../detournavigator/recastmeshmanager.hpp | 6 ++- .../tilecachedrecastmeshmanager.cpp | 50 +++++++++++-------- .../tilecachedrecastmeshmanager.hpp | 13 ++--- 6 files changed, 79 insertions(+), 49 deletions(-) diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 36f5e9e03a..e7e5886589 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -13,7 +13,7 @@ namespace DetourNavigator { if (!mImpl.addObject(id, shape, transform, areaType)) return false; - mCached.reset(); + mCached.lock()->reset(); return true; } @@ -21,7 +21,7 @@ namespace DetourNavigator { if (!mImpl.updateObject(id, transform, areaType)) return false; - mCached.reset(); + mCached.lock()->reset(); return true; } @@ -29,7 +29,7 @@ namespace DetourNavigator { const auto object = mImpl.removeObject(id); if (object) - mCached.reset(); + mCached.lock()->reset(); return object; } @@ -38,7 +38,7 @@ namespace DetourNavigator { if (!mImpl.addWater(cellPosition, cellSize, shift)) return false; - mCached.reset(); + mCached.lock()->reset(); return true; } @@ -46,7 +46,7 @@ namespace DetourNavigator { const auto water = mImpl.removeWater(cellPosition); if (water) - mCached.reset(); + mCached.lock()->reset(); return water; } @@ -55,7 +55,7 @@ namespace DetourNavigator { if (!mImpl.addHeightfield(cellPosition, cellSize, shift, shape)) return false; - mCached.reset(); + mCached.lock()->reset(); return true; } @@ -63,15 +63,18 @@ namespace DetourNavigator { const auto cell = mImpl.removeHeightfield(cellPosition); if (cell) - mCached.reset(); + mCached.lock()->reset(); return cell; } std::shared_ptr CachedRecastMeshManager::getMesh() { - if (!mCached) - mCached = mImpl.getMesh(); - return mCached; + std::shared_ptr cached = *mCached.lock(); + if (cached != nullptr) + return cached; + cached = mImpl.getMesh(); + *mCached.lock() = cached; + return cached; } bool CachedRecastMeshManager::isEmpty() const diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index 1af249404b..b506f807fa 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -5,6 +5,8 @@ #include "version.hpp" #include "heightfieldshape.hpp" +#include + namespace DetourNavigator { class CachedRecastMeshManager @@ -38,7 +40,7 @@ namespace DetourNavigator private: RecastMeshManager mImpl; - std::shared_ptr mCached; + Misc::ScopeGuarded> mCached; }; } diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 872996d9e6..5bbbbe4dea 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -38,6 +38,7 @@ namespace DetourNavigator bool RecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType) { + const std::lock_guard lock(mMutex); const auto object = mObjects.lower_bound(id); if (object != mObjects.end() && object->first == id) return false; @@ -49,6 +50,7 @@ namespace DetourNavigator bool RecastMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType) { + const std::lock_guard lock(mMutex); const auto object = mObjects.find(id); if (object == mObjects.end()) return false; @@ -62,6 +64,7 @@ namespace DetourNavigator std::optional RecastMeshManager::removeObject(const ObjectId id) { + const std::lock_guard lock(mMutex); const auto object = mObjects.find(id); if (object == mObjects.end()) return std::nullopt; @@ -73,6 +76,7 @@ namespace DetourNavigator bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift) { + const std::lock_guard lock(mMutex); if (!mWater.emplace(cellPosition, Cell {cellSize, shift}).second) return false; ++mRevision; @@ -81,6 +85,7 @@ namespace DetourNavigator std::optional RecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { + const std::lock_guard lock(mMutex); const auto water = mWater.find(cellPosition); if (water == mWater.end()) return std::nullopt; @@ -93,6 +98,7 @@ namespace DetourNavigator bool RecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, const HeightfieldShape& shape) { + const std::lock_guard lock(mMutex); if (!mHeightfields.emplace(cellPosition, Heightfield {Cell {cellSize, shift}, shape}).second) return false; ++mRevision; @@ -101,6 +107,7 @@ namespace DetourNavigator std::optional RecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) { + const std::lock_guard lock(mMutex); const auto it = mHeightfields.find(cellPosition); if (it == mHeightfields.end()) return std::nullopt; @@ -116,20 +123,27 @@ namespace DetourNavigator tileBounds.mMin /= mSettings.mRecastScaleFactor; tileBounds.mMax /= mSettings.mRecastScaleFactor; RecastMeshBuilder builder(tileBounds); - for (const auto& [k, v] : mWater) - builder.addWater(v.mSize, v.mShift); - for (const auto& [k, object] : mObjects) + std::vector objects; + std::size_t revision; { - const RecastMeshObject& v = object.getImpl(); - builder.addObject(v.getShape(), v.getTransform(), v.getAreaType()); + const std::lock_guard lock(mMutex); + for (const auto& [k, v] : mWater) + builder.addWater(v.mSize, v.mShift); + for (const auto& [cellPosition, v] : mHeightfields) + std::visit(AddHeightfield {v.mCell, builder}, v.mShape); + objects.reserve(mObjects.size()); + for (const auto& [k, object] : mObjects) + objects.push_back(object.getImpl()); + revision = mRevision; } - for (const auto& [cellPosition, v] : mHeightfields) - std::visit(AddHeightfield {v.mCell, builder}, v.mShape); - return std::move(builder).create(mGeneration, mRevision); + for (const auto& v : objects) + builder.addObject(v.getShape(), v.getTransform(), v.getAreaType()); + return std::move(builder).create(mGeneration, revision); } bool RecastMeshManager::isEmpty() const { + const std::lock_guard lock(mMutex); return mObjects.empty() && mWater.empty() && mHeightfields.empty(); } @@ -137,6 +151,7 @@ namespace DetourNavigator { if (recastMeshVersion.mGeneration != mGeneration) return; + const std::lock_guard lock(mMutex); if (mLastNavMeshReport.has_value() && navMeshVersion < mLastNavMeshReport->mNavMeshVersion) return; mLastNavMeshReport = {recastMeshVersion.mRevision, navMeshVersion}; @@ -147,6 +162,7 @@ namespace DetourNavigator Version RecastMeshManager::getVersion() const { + const std::lock_guard lock(mMutex); return Version {mGeneration, mRevision}; } } diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index fb7018d922..1cd35ca467 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -16,6 +16,7 @@ #include #include #include +#include class btCollisionShape; @@ -73,9 +74,10 @@ namespace DetourNavigator }; const Settings& mSettings; + const std::size_t mGeneration; + const TileBounds mTileBounds; + mutable std::mutex mMutex; std::size_t mRevision = 0; - std::size_t mGeneration; - TileBounds mTileBounds; std::map mObjects; std::map mWater; std::map mHeightfields; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 61bd973cbf..2b8c85b8a3 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -69,7 +69,7 @@ namespace DetourNavigator const auto tiles = mTiles.lock(); for (auto& tile : *tiles) { - if (tile.second.addWater(cellPosition, cellSize, shift)) + if (tile.second->addWater(cellPosition, cellSize, shift)) { tilesPositions.push_back(tile.first); result = true; @@ -88,9 +88,9 @@ namespace DetourNavigator tileBounds.mMin -= osg::Vec2f(border, border); tileBounds.mMax += osg::Vec2f(border, border); tile = tiles->insert(std::make_pair(tilePosition, - CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; + std::make_shared(mSettings, tileBounds, mTilesGeneration))).first; } - if (tile->second.addWater(cellPosition, cellSize, shift)) + if (tile->second->addWater(cellPosition, cellSize, shift)) { tilesPositions.push_back(tilePosition); result = true; @@ -116,8 +116,8 @@ namespace DetourNavigator const auto tile = tiles->find(tilePosition); if (tile == tiles->end()) continue; - const auto tileResult = tile->second.removeWater(cellPosition); - if (tile->second.isEmpty()) + const auto tileResult = tile->second->removeWater(cellPosition); + if (tile->second->isEmpty()) { tiles->erase(tile); ++mTilesGeneration; @@ -149,9 +149,9 @@ namespace DetourNavigator tileBounds.mMin -= osg::Vec2f(border, border); tileBounds.mMax += osg::Vec2f(border, border); tile = tiles->insert(std::make_pair(tilePosition, - CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; + std::make_shared(mSettings, tileBounds, mTilesGeneration))).first; } - if (tile->second.addHeightfield(cellPosition, cellSize, shift, shape)) + if (tile->second->addHeightfield(cellPosition, cellSize, shift, shape)) { tilesPositions.push_back(tilePosition); result = true; @@ -176,8 +176,8 @@ namespace DetourNavigator const auto tile = tiles->find(tilePosition); if (tile == tiles->end()) continue; - const auto tileResult = tile->second.removeHeightfield(cellPosition); - if (tile->second.isEmpty()) + const auto tileResult = tile->second->removeHeightfield(cellPosition); + if (tile->second->isEmpty()) { tiles->erase(tile); ++mTilesGeneration; @@ -192,11 +192,17 @@ namespace DetourNavigator std::shared_ptr TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition) { - const auto tiles = mTiles.lock(); - const auto it = tiles->find(tilePosition); - if (it == tiles->end()) + const auto manager = [&] () -> std::shared_ptr + { + const auto tiles = mTiles.lock(); + const auto it = tiles->find(tilePosition); + if (it == tiles->end()) + return nullptr; + return it->second; + } (); + if (manager == nullptr) return nullptr; - return it->second.getMesh(); + return manager->getMesh(); } bool TileCachedRecastMeshManager::hasTile(const TilePosition& tilePosition) @@ -215,12 +221,12 @@ namespace DetourNavigator const auto it = tiles->find(tilePosition); if (it == tiles->end()) return; - it->second.reportNavMeshChange(recastMeshVersion, navMeshVersion); + it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion); } bool TileCachedRecastMeshManager::addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, - std::map& tiles) + TilesMap& tiles) { auto tile = tiles.find(tilePosition); if (tile == tiles.end()) @@ -229,26 +235,26 @@ namespace DetourNavigator tileBounds.mMin -= osg::Vec2f(border, border); tileBounds.mMax += osg::Vec2f(border, border); tile = tiles.insert(std::make_pair( - tilePosition, CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; + tilePosition, std::make_shared(mSettings, tileBounds, mTilesGeneration))).first; } - return tile->second.addObject(id, shape, transform, areaType); + return tile->second->addObject(id, shape, transform, areaType); } bool TileCachedRecastMeshManager::updateTile(const ObjectId id, const btTransform& transform, - const AreaType areaType, const TilePosition& tilePosition, std::map& tiles) + const AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles) { const auto tile = tiles.find(tilePosition); - return tile != tiles.end() && tile->second.updateObject(id, transform, areaType); + return tile != tiles.end() && tile->second->updateObject(id, transform, areaType); } std::optional TileCachedRecastMeshManager::removeTile(const ObjectId id, - const TilePosition& tilePosition, std::map& tiles) + const TilePosition& tilePosition, TilesMap& tiles) { const auto tile = tiles.find(tilePosition); if (tile == tiles.end()) return std::optional(); - const auto tileResult = tile->second.removeObject(id); - if (tile->second.isEmpty()) + const auto tileResult = tile->second->removeObject(id); + if (tile->second->isEmpty()) { tiles.erase(tile); ++mTilesGeneration; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 38d004ccca..f8cb5a8b0e 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -94,7 +94,7 @@ namespace DetourNavigator void forEachTile(Function&& function) { for (auto& [tilePosition, recastMeshManager] : *mTiles.lock()) - function(tilePosition, recastMeshManager); + function(tilePosition, *recastMeshManager); } std::size_t getRevision() const; @@ -102,8 +102,10 @@ namespace DetourNavigator void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion); private: + using TilesMap = std::map>; + const Settings& mSettings; - Misc::ScopeGuarded> mTiles; + Misc::ScopeGuarded mTiles; std::unordered_map> mObjectsTilesPositions; std::map> mWaterTilesPositions; std::map> mHeightfieldTilesPositions; @@ -111,14 +113,13 @@ namespace DetourNavigator std::size_t mTilesGeneration = 0; bool addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType, const TilePosition& tilePosition, float border, - std::map& tiles); + const AreaType areaType, const TilePosition& tilePosition, float border, TilesMap& tiles); bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType, - const TilePosition& tilePosition, std::map& tiles); + const TilePosition& tilePosition, TilesMap& tiles); std::optional removeTile(const ObjectId id, const TilePosition& tilePosition, - std::map& tiles); + TilesMap& tiles); }; }