1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 14:09:39 +00:00

Support animated objects

This commit is contained in:
elsid 2018-05-26 17:44:25 +03:00
parent 4aba0fa85f
commit 144e1a063b
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
20 changed files with 460 additions and 23 deletions

View file

@ -4,6 +4,7 @@
#include <memory>
#include <map>
#include <set>
#include <algorithm>
#include <osg/Quat>
#include <osg/ref_ptr>
@ -174,6 +175,13 @@ namespace MWPhysics
void markAsNonSolid (const MWWorld::ConstPtr& ptr);
bool isOnSolidGround (const MWWorld::Ptr& actor) const;
template <class Function>
void forEachAnimatedObject(Function&& function) const
{
std::for_each(mAnimatedObjects.begin(), mAnimatedObjects.end(), function);
}
private:
void updateWater();

View file

@ -3,6 +3,8 @@
#include <osg/Group>
#include <osg/ComputeBoundsVisitor>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <components/debug/debuglog.hpp>
#include <components/esm/esmreader.hpp>
@ -51,6 +53,7 @@
#include "../mwphysics/physicssystem.hpp"
#include "../mwphysics/actor.hpp"
#include "../mwphysics/collisiontype.hpp"
#include "../mwphysics/object.hpp"
#include "player.hpp"
#include "manualref.hpp"
@ -1535,6 +1538,16 @@ namespace MWWorld
}
if(player != results.end())
moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false);
bool navigatorObjectsUpdated = false;
mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object)
{
navigatorObjectsUpdated = mNavigator->updateObject(std::size_t(object),
*object->getCollisionObject()->getCollisionShape(),
object->getCollisionObject()->getWorldTransform()) || navigatorObjectsUpdated;
});
if (navigatorObjectsUpdated)
mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3());
}
bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2, bool ignoreDoors)

View file

@ -22,6 +22,7 @@ if (GTEST_FOUND AND GMOCK_FOUND)
detournavigator/settingsutils.cpp
detournavigator/recastmeshbuilder.cpp
detournavigator/gettilespositions.cpp
detournavigator/recastmeshobject.cpp
)
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})

View file

@ -4,6 +4,8 @@
#include <components/detournavigator/exceptions.hpp>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
#include <BulletCollision/CollisionShapes/btBoxShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <gtest/gtest.h>
@ -131,6 +133,175 @@ namespace
})) << 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)
{
const std::array<btScalar, 5 * 5> heightfieldData {{

View 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));
}
}

View file

@ -169,6 +169,7 @@ add_component_dir(detournavigator
chunkytrimesh
recastmesh
tilecachedrecastmeshmanager
recastmeshobject
)
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui

View file

@ -78,6 +78,8 @@ namespace DetourNavigator
makePriority(changedTile, playerTile)});
}
log("posted ", mJobs.size(), " jobs");
mHasJob.notify_all();
}
@ -169,7 +171,8 @@ namespace DetourNavigator
navMeshRevision = revision;
}
if (recastMesh && mSettings.get().mEnableWriteRecastMeshToFile)
writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix, recastMeshRevision);
writeToFile(*recastMesh, mSettings.get().mRecastMeshPathPrefix + std::to_string(job.mChangedTile.x())
+ "_" + std::to_string(job.mChangedTile.y()) + "_", recastMeshRevision);
if (mSettings.get().mEnableWriteNavMeshToFile)
writeToFile(*job.mNavMeshCacheItem->mValue.lock(), mSettings.get().mNavMeshPathPrefix, navMeshRevision);
}

View file

@ -16,7 +16,15 @@ namespace DetourNavigator
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);
if (object)

View file

@ -14,7 +14,9 @@ namespace DetourNavigator
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();

View file

@ -7,6 +7,7 @@
#include <components/osghelpers/operators.hpp>
#include <atomic>
#include <chrono>
#include <fstream>
#include <iomanip>
#include <iostream>
@ -25,6 +26,13 @@ namespace DetourNavigator
class RecastMesh;
inline std::ostream& operator <<(std::ostream& stream, const std::chrono::steady_clock::time_point& value)
{
using float_s = std::chrono::duration<float, std::ratio<1>>;
return stream << std::fixed << std::setprecision(4)
<< std::chrono::duration_cast<float_s>(value.time_since_epoch()).count();
}
class Log
{
public:
@ -88,6 +96,7 @@ namespace DetourNavigator
if (!log.isEnabled())
return;
std::ostringstream stream;
stream << '[' << std::chrono::steady_clock::now() << "] ";
write(stream, std::forward<Ts>(values) ...);
log.write(stream.str());
}

View file

@ -30,6 +30,11 @@ namespace DetourNavigator
return mNavMeshManager.addObject(id, shape, transform);
}
bool Navigator::updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform)
{
return mNavMeshManager.updateObject(id, shape, transform);
}
bool Navigator::removeObject(std::size_t id)
{
return mNavMeshManager.removeObject(id);

View file

@ -19,6 +19,8 @@ namespace DetourNavigator
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
bool updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
bool removeObject(std::size_t id);
void update(const osg::Vec3f& playerPosition);

View file

@ -30,12 +30,20 @@ namespace DetourNavigator
return true;
}
bool NavMeshManager::updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform)
{
if (!mRecastMeshManager.updateObject(id, transform))
return false;
addChangedTiles(shape, transform);
return true;
}
bool NavMeshManager::removeObject(std::size_t id)
{
const auto object = mRecastMeshManager.removeObject(id);
if (!object)
return false;
addChangedTiles(*object->mShape, object->mTransform);
addChangedTiles(object->mShape, object->mTransform);
return true;
}

View file

@ -25,6 +25,8 @@ namespace DetourNavigator
bool addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
bool updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
bool removeObject(std::size_t id);
void addAgent(const osg::Vec3f& agentHalfExtents);

View file

@ -1,5 +1,6 @@
#include "recastmeshmanager.hpp"
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
namespace DetourNavigator
@ -12,18 +13,29 @@ namespace DetourNavigator
bool RecastMeshManager::addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform)
{
if (!mObjects.insert(std::make_pair(id, Object {&shape, transform})).second)
if (!mObjects.emplace(id, RecastMeshObject(shape, transform)).second)
return false;
mShouldRebuild = true;
return true;
return mShouldRebuild;
}
boost::optional<RecastMeshManager::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);
if (object == mObjects.end())
return boost::none;
const auto result = object->second;
const RemovedRecastMeshObject result {object->second.getShape(), object->second.getTransform()};
mObjects.erase(object);
mShouldRebuild = true;
return result;
@ -46,7 +58,7 @@ namespace DetourNavigator
return;
mMeshBuilder.reset();
for (const auto& v : mObjects)
mMeshBuilder.addObject(*v.second.mShape, v.second.mTransform);
mMeshBuilder.addObject(v.second.getShape(), v.second.getTransform());
mShouldRebuild = false;
}
}

View file

@ -2,6 +2,7 @@
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H
#include "recastmeshbuilder.hpp"
#include "recastmeshobject.hpp"
#include <LinearMath/btTransform.h>
@ -13,20 +14,22 @@ class btCollisionShape;
namespace DetourNavigator
{
class RecastMeshManager
struct RemovedRecastMeshObject
{
public:
struct Object
{
const btCollisionShape* mShape;
std::reference_wrapper<const btCollisionShape> mShape;
btTransform mTransform;
};
class RecastMeshManager
{
public:
RecastMeshManager(const Settings& settings, const TileBounds& bounds);
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();
@ -35,7 +38,7 @@ namespace DetourNavigator
private:
bool mShouldRebuild;
RecastMeshBuilder mMeshBuilder;
std::unordered_map<std::size_t, Object> mObjects;
std::unordered_map<std::size_t, RecastMeshObject> mObjects;
void rebuild();
};

View 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;
}
}

View 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

View file

@ -40,12 +40,31 @@ namespace DetourNavigator
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);
if (object == mObjectsTilesPositions.end())
return boost::none;
boost::optional<RecastMeshManager::Object> result;
boost::optional<RemovedRecastMeshObject> result;
for (const auto& tilePosition : object->second)
{
std::unique_lock<std::mutex> lock(mTilesMutex);

View file

@ -16,7 +16,9 @@ namespace DetourNavigator
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);