mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 20:09:40 +00:00
Support animated objects
This commit is contained in:
parent
4aba0fa85f
commit
144e1a063b
20 changed files with 460 additions and 23 deletions
|
@ -4,6 +4,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <osg/Quat>
|
#include <osg/Quat>
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
@ -174,6 +175,13 @@ namespace MWPhysics
|
||||||
void markAsNonSolid (const MWWorld::ConstPtr& ptr);
|
void markAsNonSolid (const MWWorld::ConstPtr& ptr);
|
||||||
|
|
||||||
bool isOnSolidGround (const MWWorld::Ptr& actor) const;
|
bool isOnSolidGround (const MWWorld::Ptr& actor) const;
|
||||||
|
|
||||||
|
template <class Function>
|
||||||
|
void forEachAnimatedObject(Function&& function) const
|
||||||
|
{
|
||||||
|
std::for_each(mAnimatedObjects.begin(), mAnimatedObjects.end(), function);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void updateWater();
|
void updateWater();
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
#include <osg/ComputeBoundsVisitor>
|
#include <osg/ComputeBoundsVisitor>
|
||||||
|
|
||||||
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
@ -51,6 +53,7 @@
|
||||||
#include "../mwphysics/physicssystem.hpp"
|
#include "../mwphysics/physicssystem.hpp"
|
||||||
#include "../mwphysics/actor.hpp"
|
#include "../mwphysics/actor.hpp"
|
||||||
#include "../mwphysics/collisiontype.hpp"
|
#include "../mwphysics/collisiontype.hpp"
|
||||||
|
#include "../mwphysics/object.hpp"
|
||||||
|
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "manualref.hpp"
|
#include "manualref.hpp"
|
||||||
|
@ -1535,6 +1538,16 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
if(player != results.end())
|
if(player != results.end())
|
||||||
moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false);
|
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)
|
bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2, bool ignoreDoors)
|
||||||
|
|
|
@ -22,6 +22,7 @@ if (GTEST_FOUND AND GMOCK_FOUND)
|
||||||
detournavigator/settingsutils.cpp
|
detournavigator/settingsutils.cpp
|
||||||
detournavigator/recastmeshbuilder.cpp
|
detournavigator/recastmeshbuilder.cpp
|
||||||
detournavigator/gettilespositions.cpp
|
detournavigator/gettilespositions.cpp
|
||||||
|
detournavigator/recastmeshobject.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
|
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <components/detournavigator/exceptions.hpp>
|
#include <components/detournavigator/exceptions.hpp>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||||
|
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||||
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
@ -131,6 +133,175 @@ namespace
|
||||||
})) << mPath;
|
})) << mPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorNavigatorTest, add_object_should_change_navmesh)
|
||||||
|
{
|
||||||
|
const std::array<btScalar, 5 * 5> 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>({
|
||||||
|
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>({
|
||||||
|
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<btScalar, 5 * 5> 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>({
|
||||||
|
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>({
|
||||||
|
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)
|
TEST_F(DetourNavigatorNavigatorTest, for_overlapping_heightfields_should_use_higher)
|
||||||
{
|
{
|
||||||
const std::array<btScalar, 5 * 5> heightfieldData {{
|
const std::array<btScalar, 5 * 5> heightfieldData {{
|
||||||
|
|
66
apps/openmw_test_suite/detournavigator/recastmeshobject.cpp
Normal file
66
apps/openmw_test_suite/detournavigator/recastmeshobject.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include "operators.hpp"
|
||||||
|
|
||||||
|
#include <components/detournavigator/recastmeshobject.hpp>
|
||||||
|
|
||||||
|
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||||
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -169,6 +169,7 @@ add_component_dir(detournavigator
|
||||||
chunkytrimesh
|
chunkytrimesh
|
||||||
recastmesh
|
recastmesh
|
||||||
tilecachedrecastmeshmanager
|
tilecachedrecastmeshmanager
|
||||||
|
recastmeshobject
|
||||||
)
|
)
|
||||||
|
|
||||||
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
||||||
|
|
|
@ -78,6 +78,8 @@ namespace DetourNavigator
|
||||||
makePriority(changedTile, playerTile)});
|
makePriority(changedTile, playerTile)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log("posted ", mJobs.size(), " jobs");
|
||||||
|
|
||||||
mHasJob.notify_all();
|
mHasJob.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +171,8 @@ namespace DetourNavigator
|
||||||
navMeshRevision = revision;
|
navMeshRevision = revision;
|
||||||
}
|
}
|
||||||
if (recastMesh && mSettings.get().mEnableWriteRecastMeshToFile)
|
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)
|
if (mSettings.get().mEnableWriteNavMeshToFile)
|
||||||
writeToFile(*job.mNavMeshCacheItem->mValue.lock(), mSettings.get().mNavMeshPathPrefix, navMeshRevision);
|
writeToFile(*job.mNavMeshCacheItem->mValue.lock(), mSettings.get().mNavMeshPathPrefix, navMeshRevision);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,15 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<RecastMeshManager::Object> 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<RemovedRecastMeshObject> CachedRecastMeshManager::removeObject(std::size_t id)
|
||||||
{
|
{
|
||||||
const auto object = mImpl.removeObject(id);
|
const auto object = mImpl.removeObject(id);
|
||||||
if (object)
|
if (object)
|
||||||
|
|
|
@ -14,7 +14,9 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
||||||
|
|
||||||
boost::optional<RecastMeshManager::Object> removeObject(std::size_t id);
|
bool updateObject(std::size_t id, const btTransform& transform);
|
||||||
|
|
||||||
|
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh();
|
std::shared_ptr<RecastMesh> getMesh();
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <components/osghelpers/operators.hpp>
|
#include <components/osghelpers/operators.hpp>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -25,6 +26,13 @@ namespace DetourNavigator
|
||||||
|
|
||||||
class RecastMesh;
|
class RecastMesh;
|
||||||
|
|
||||||
|
inline std::ostream& operator <<(std::ostream& stream, const std::chrono::steady_clock::time_point& value)
|
||||||
|
{
|
||||||
|
using float_s = std::chrono::duration<float, std::ratio<1>>;
|
||||||
|
return stream << std::fixed << std::setprecision(4)
|
||||||
|
<< std::chrono::duration_cast<float_s>(value.time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
class Log
|
class Log
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -88,6 +96,7 @@ namespace DetourNavigator
|
||||||
if (!log.isEnabled())
|
if (!log.isEnabled())
|
||||||
return;
|
return;
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
stream << '[' << std::chrono::steady_clock::now() << "] ";
|
||||||
write(stream, std::forward<Ts>(values) ...);
|
write(stream, std::forward<Ts>(values) ...);
|
||||||
log.write(stream.str());
|
log.write(stream.str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@ namespace DetourNavigator
|
||||||
return mNavMeshManager.addObject(id, shape, transform);
|
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)
|
bool Navigator::removeObject(std::size_t id)
|
||||||
{
|
{
|
||||||
return mNavMeshManager.removeObject(id);
|
return mNavMeshManager.removeObject(id);
|
||||||
|
|
|
@ -19,6 +19,8 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
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);
|
bool removeObject(std::size_t id);
|
||||||
|
|
||||||
void update(const osg::Vec3f& playerPosition);
|
void update(const osg::Vec3f& playerPosition);
|
||||||
|
|
|
@ -30,12 +30,20 @@ namespace DetourNavigator
|
||||||
return true;
|
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)
|
bool NavMeshManager::removeObject(std::size_t id)
|
||||||
{
|
{
|
||||||
const auto object = mRecastMeshManager.removeObject(id);
|
const auto object = mRecastMeshManager.removeObject(id);
|
||||||
if (!object)
|
if (!object)
|
||||||
return false;
|
return false;
|
||||||
addChangedTiles(*object->mShape, object->mTransform);
|
addChangedTiles(object->mShape, object->mTransform);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
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);
|
bool removeObject(std::size_t id);
|
||||||
|
|
||||||
void addAgent(const osg::Vec3f& agentHalfExtents);
|
void addAgent(const osg::Vec3f& agentHalfExtents);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "recastmeshmanager.hpp"
|
#include "recastmeshmanager.hpp"
|
||||||
|
|
||||||
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
|
@ -12,18 +13,29 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool RecastMeshManager::addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform)
|
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;
|
return false;
|
||||||
mShouldRebuild = true;
|
mShouldRebuild = true;
|
||||||
return true;
|
return mShouldRebuild;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<RecastMeshManager::Object> 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<RemovedRecastMeshObject> RecastMeshManager::removeObject(std::size_t id)
|
||||||
{
|
{
|
||||||
const auto object = mObjects.find(id);
|
const auto object = mObjects.find(id);
|
||||||
if (object == mObjects.end())
|
if (object == mObjects.end())
|
||||||
return boost::none;
|
return boost::none;
|
||||||
const auto result = object->second;
|
const RemovedRecastMeshObject result {object->second.getShape(), object->second.getTransform()};
|
||||||
mObjects.erase(object);
|
mObjects.erase(object);
|
||||||
mShouldRebuild = true;
|
mShouldRebuild = true;
|
||||||
return result;
|
return result;
|
||||||
|
@ -46,7 +58,7 @@ namespace DetourNavigator
|
||||||
return;
|
return;
|
||||||
mMeshBuilder.reset();
|
mMeshBuilder.reset();
|
||||||
for (const auto& v : mObjects)
|
for (const auto& v : mObjects)
|
||||||
mMeshBuilder.addObject(*v.second.mShape, v.second.mTransform);
|
mMeshBuilder.addObject(v.second.getShape(), v.second.getTransform());
|
||||||
mShouldRebuild = false;
|
mShouldRebuild = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H
|
||||||
|
|
||||||
#include "recastmeshbuilder.hpp"
|
#include "recastmeshbuilder.hpp"
|
||||||
|
#include "recastmeshobject.hpp"
|
||||||
|
|
||||||
#include <LinearMath/btTransform.h>
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
|
@ -13,20 +14,22 @@ class btCollisionShape;
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
|
struct RemovedRecastMeshObject
|
||||||
|
{
|
||||||
|
std::reference_wrapper<const btCollisionShape> mShape;
|
||||||
|
btTransform mTransform;
|
||||||
|
};
|
||||||
|
|
||||||
class RecastMeshManager
|
class RecastMeshManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Object
|
|
||||||
{
|
|
||||||
const btCollisionShape* mShape;
|
|
||||||
btTransform mTransform;
|
|
||||||
};
|
|
||||||
|
|
||||||
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
|
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
|
||||||
|
|
||||||
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
||||||
|
|
||||||
boost::optional<Object> removeObject(std::size_t id);
|
bool updateObject(std::size_t id, const btTransform& transform);
|
||||||
|
|
||||||
|
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh();
|
std::shared_ptr<RecastMesh> getMesh();
|
||||||
|
|
||||||
|
@ -35,7 +38,7 @@ namespace DetourNavigator
|
||||||
private:
|
private:
|
||||||
bool mShouldRebuild;
|
bool mShouldRebuild;
|
||||||
RecastMeshBuilder mMeshBuilder;
|
RecastMeshBuilder mMeshBuilder;
|
||||||
std::unordered_map<std::size_t, Object> mObjects;
|
std::unordered_map<std::size_t, RecastMeshObject> mObjects;
|
||||||
|
|
||||||
void rebuild();
|
void rebuild();
|
||||||
};
|
};
|
||||||
|
|
58
components/detournavigator/recastmeshobject.cpp
Normal file
58
components/detournavigator/recastmeshobject.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "recastmeshobject.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
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<const btCompoundShape&>(mShape.get()), mChildren) || result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RecastMeshObject::updateCompoundObject(const btCompoundShape& shape, std::vector<RecastMeshObject>& children)
|
||||||
|
{
|
||||||
|
assert(static_cast<std::size_t>(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<std::size_t>(i)].mShape.get()));
|
||||||
|
result = children[static_cast<std::size_t>(i)].update(shape.getChildTransform(i)) || result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape)
|
||||||
|
{
|
||||||
|
if (shape.isCompound())
|
||||||
|
return makeChildrenObjects(static_cast<const btCompoundShape&>(shape));
|
||||||
|
else
|
||||||
|
return std::vector<RecastMeshObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RecastMeshObject> makeChildrenObjects(const btCompoundShape& shape)
|
||||||
|
{
|
||||||
|
std::vector<RecastMeshObject> result;
|
||||||
|
for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i)
|
||||||
|
result.emplace_back(*shape.getChildShape(i), shape.getChildTransform(i));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
44
components/detournavigator/recastmeshobject.hpp
Normal file
44
components/detournavigator/recastmeshobject.hpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHOBJECT_H
|
||||||
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHOBJECT_H
|
||||||
|
|
||||||
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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<const btCollisionShape> mShape;
|
||||||
|
btTransform mTransform;
|
||||||
|
std::vector<RecastMeshObject> mChildren;
|
||||||
|
|
||||||
|
static bool updateCompoundObject(const btCompoundShape& shape, std::vector<RecastMeshObject>& children);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape);
|
||||||
|
|
||||||
|
std::vector<RecastMeshObject> makeChildrenObjects(const btCompoundShape& shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -40,12 +40,31 @@ namespace DetourNavigator
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<RecastMeshManager::Object> 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<std::mutex> 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<RemovedRecastMeshObject> TileCachedRecastMeshManager::removeObject(std::size_t id)
|
||||||
{
|
{
|
||||||
const auto object = mObjectsTilesPositions.find(id);
|
const auto object = mObjectsTilesPositions.find(id);
|
||||||
if (object == mObjectsTilesPositions.end())
|
if (object == mObjectsTilesPositions.end())
|
||||||
return boost::none;
|
return boost::none;
|
||||||
boost::optional<RecastMeshManager::Object> result;
|
boost::optional<RemovedRecastMeshObject> result;
|
||||||
for (const auto& tilePosition : object->second)
|
for (const auto& tilePosition : object->second)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mTilesMutex);
|
std::unique_lock<std::mutex> lock(mTilesMutex);
|
||||||
|
|
|
@ -16,7 +16,9 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
|
||||||
|
|
||||||
boost::optional<RecastMeshManager::Object> removeObject(std::size_t id);
|
bool updateObject(std::size_t id, const btTransform& transform);
|
||||||
|
|
||||||
|
boost::optional<RemovedRecastMeshObject> removeObject(std::size_t id);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition);
|
std::shared_ptr<RecastMesh> getMesh(const TilePosition& tilePosition);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue