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

Store reference to BulletShapeInstance for btCollisionShape

To keep btCollisionShape lifetime.
This commit is contained in:
elsid 2021-08-01 02:13:55 +02:00
parent 4574e5f565
commit c8987bda2f
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
18 changed files with 221 additions and 149 deletions

View file

@ -151,11 +151,9 @@ namespace
{ {
if (ptr.getClass().isDoor() && !ptr.getCellRef().getTeleport()) if (ptr.getClass().isDoor() && !ptr.getCellRef().getTeleport())
{ {
const auto shape = object->getShapeInstance()->getCollisionShape();
btVector3 aabbMin; btVector3 aabbMin;
btVector3 aabbMax; btVector3 aabbMax;
shape->getAabb(btTransform::getIdentity(), aabbMin, aabbMax); object->getShapeInstance()->getCollisionShape()->getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
const auto center = (aabbMax + aabbMin) * 0.5f; const auto center = (aabbMax + aabbMin) * 0.5f;
@ -182,12 +180,7 @@ namespace
navigator.addObject( navigator.addObject(
DetourNavigator::ObjectId(object), DetourNavigator::ObjectId(object),
DetourNavigator::DoorShapes( DetourNavigator::DoorShapes(object->getShapeInstance(), connectionStart, connectionEnd),
*shape,
object->getShapeInstance()->getAvoidCollisionShape(),
connectionStart,
connectionEnd
),
transform transform
); );
} }
@ -195,10 +188,7 @@ namespace
{ {
navigator.addObject( navigator.addObject(
DetourNavigator::ObjectId(object), DetourNavigator::ObjectId(object),
DetourNavigator::ObjectShapes { DetourNavigator::ObjectShapes(object->getShapeInstance()),
*object->getShapeInstance()->getCollisionShape(),
object->getShapeInstance()->getAvoidCollisionShape()
},
object->getTransform() object->getTransform()
); );
} }

View file

@ -1533,10 +1533,7 @@ namespace MWWorld
void World::updateNavigatorObject(const MWPhysics::Object& object) void World::updateNavigatorObject(const MWPhysics::Object& object)
{ {
const DetourNavigator::ObjectShapes shapes { const DetourNavigator::ObjectShapes shapes(object.getShapeInstance());
*object.getShapeInstance()->getCollisionShape(),
object.getShapeInstance()->getAvoidCollisionShape()
};
mShouldUpdateNavigator = mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform()) mShouldUpdateNavigator = mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform())
|| mShouldUpdateNavigator; || mShouldUpdateNavigator;
} }

View file

@ -5,6 +5,9 @@
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/loadinglistener/loadinglistener.hpp> #include <components/loadinglistener/loadinglistener.hpp>
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include <components/resource/bulletshape.hpp>
#include <osg/ref_ptr>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h> #include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
#include <BulletCollision/CollisionShapes/btBoxShape.h> #include <BulletCollision/CollisionShapes/btBoxShape.h>
@ -15,6 +18,7 @@
#include <array> #include <array>
#include <deque> #include <deque>
#include <memory>
MATCHER_P3(Vec3fEq, x, y, z, "") MATCHER_P3(Vec3fEq, x, y, z, "")
{ {
@ -84,14 +88,15 @@ namespace
}; };
template <std::size_t size> template <std::size_t size>
btHeightfieldTerrainShape makeSquareHeightfieldTerrainShape(const std::array<btScalar, size>& values, std::unique_ptr<btHeightfieldTerrainShape> makeSquareHeightfieldTerrainShape(const std::array<btScalar, size>& values,
btScalar heightScale = 1, int upAxis = 2, PHY_ScalarType heightDataType = PHY_FLOAT, bool flipQuadEdges = false) btScalar heightScale = 1, int upAxis = 2, PHY_ScalarType heightDataType = PHY_FLOAT, bool flipQuadEdges = false)
{ {
const int width = static_cast<int>(std::sqrt(size)); const int width = static_cast<int>(std::sqrt(size));
const btScalar min = *std::min_element(values.begin(), values.end()); const btScalar min = *std::min_element(values.begin(), values.end());
const btScalar max = *std::max_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)); 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<btHeightfieldTerrainShape>(width, width, values.data(), heightScale, -greater, greater,
upAxis, heightDataType, flipQuadEdges);
} }
template <std::size_t size> template <std::size_t size>
@ -107,6 +112,27 @@ namespace
return surface; return surface;
} }
template <class T>
osg::ref_ptr<const Resource::BulletShapeInstance> makeBulletShapeInstance(std::unique_ptr<T>&& shape)
{
osg::ref_ptr<Resource::BulletShape> bulletShape(new Resource::BulletShape);
bulletShape->mCollisionShape = std::move(shape).release();
return new Resource::BulletShapeInstance(bulletShape);
}
template <class T>
class CollisionShapeInstance
{
public:
CollisionShapeInstance(std::unique_ptr<T>&& shape) : mInstance(makeBulletShapeInstance(std::move(shape))) {}
T& shape() { return static_cast<T&>(*mInstance->mCollisionShape); }
const osg::ref_ptr<const Resource::BulletShapeInstance>& instance() const { return mInstance; }
private:
osg::ref_ptr<const Resource::BulletShapeInstance> mInstance;
};
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty) TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty)
{ {
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut),
@ -185,9 +211,8 @@ namespace
}}; }};
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
btBoxShape boxShape(btVector3(20, 20, 100)); CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
btCompoundShape compoundShape; compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape);
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface);
@ -221,7 +246,7 @@ namespace
Vec3fEq(204, -204, 1.99998295307159423828125) Vec3fEq(204, -204, 1.99998295307159423828125)
)) << mPath; )) << mPath;
mNavigator->addObject(ObjectId(&compoundShape), ObjectShapes(compoundShape, nullptr), btTransform::getIdentity()); mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance()), btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -267,13 +292,12 @@ namespace
}}; }};
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
btBoxShape boxShape(btVector3(20, 20, 100)); CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
btCompoundShape compoundShape; compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape);
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -305,9 +329,9 @@ namespace
Vec3fEq(204, -204, 1.99998295307159423828125) Vec3fEq(204, -204, 1.99998295307159423828125)
)) << mPath; )) << 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -350,8 +374,8 @@ namespace
0, -25, -100, -100, -100, 0, -25, -100, -100, -100,
0, -25, -100, -100, -100, 0, -25, -100, -100, -100,
}}; }};
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData1); CollisionShapeInstance heightfield1(makeSquareHeightfieldTerrainShape(heightfieldData1));
shape.setLocalScaling(btVector3(128, 128, 1)); heightfield1.shape().setLocalScaling(btVector3(128, 128, 1));
const std::array<btScalar, 5 * 5> heightfieldData2 {{ const std::array<btScalar, 5 * 5> heightfieldData2 {{
-25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
@ -360,12 +384,12 @@ namespace
-25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
}}; }};
btHeightfieldTerrainShape shape2 = makeSquareHeightfieldTerrainShape(heightfieldData2); CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2));
shape2.setLocalScaling(btVector3(128, 128, 1)); heightfield2.shape().setLocalScaling(btVector3(128, 128, 1));
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&shape), ObjectShapes(shape, nullptr), btTransform::getIdentity()); mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance()), btTransform::getIdentity());
mNavigator->addObject(ObjectId(&shape2), ObjectShapes(shape2, nullptr), btTransform::getIdentity()); mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance()), btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -424,6 +448,8 @@ namespace
TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape) TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape)
{ {
osg::ref_ptr<Resource::BulletShape> bulletShape(new Resource::BulletShape);
std::array<btScalar, 5 * 5> heightfieldData {{ std::array<btScalar, 5 * 5> heightfieldData {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, -25, -25, -25, -25, 0, -25, -25, -25, -25,
@ -431,8 +457,9 @@ namespace
0, -25, -100, -100, -100, 0, -25, -100, -100, -100,
0, -25, -100, -100, -100, 0, -25, -100, -100, -100,
}}; }};
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); std::unique_ptr<btHeightfieldTerrainShape> shapePtr = makeSquareHeightfieldTerrainShape(heightfieldData);
shape.setLocalScaling(btVector3(128, 128, 1)); shapePtr->setLocalScaling(btVector3(128, 128, 1));
bulletShape->mCollisionShape = shapePtr.release();
std::array<btScalar, 5 * 5> heightfieldDataAvoid {{ std::array<btScalar, 5 * 5> heightfieldDataAvoid {{
-25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
@ -441,11 +468,14 @@ namespace
-25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
}}; }};
btHeightfieldTerrainShape shapeAvoid = makeSquareHeightfieldTerrainShape(heightfieldDataAvoid); std::unique_ptr<btHeightfieldTerrainShape> shapeAvoidPtr = makeSquareHeightfieldTerrainShape(heightfieldDataAvoid);
shapeAvoid.setLocalScaling(btVector3(128, 128, 1)); shapeAvoidPtr->setLocalScaling(btVector3(128, 128, 1));
bulletShape->mAvoidCollisionShape = shapeAvoidPtr.release();
osg::ref_ptr<const Resource::BulletShapeInstance> instance(new Resource::BulletShapeInstance(bulletShape));
mNavigator->addAgent(mAgentHalfExtents); 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -666,19 +696,19 @@ namespace
0, -25, -100, -100, -100, 0, -25, -100, -100, -100,
0, -25, -100, -100, -100, 0, -25, -100, -100, -100,
}}; }};
btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData));
shape.setLocalScaling(btVector3(128, 128, 1)); heightfield.shape().setLocalScaling(btVector3(128, 128, 1));
mNavigator->addAgent(mAgentHalfExtents); 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
mNavigator->removeObject(ObjectId(&shape)); mNavigator->removeObject(ObjectId(&heightfield.shape()));
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -804,24 +834,25 @@ namespace
}}; }};
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
const std::vector<btBoxShape> boxShapes(100, btVector3(20, 20, 100)); std::vector<CollisionShapeInstance<btBoxShape>> boxes;
std::generate_n(std::back_inserter(boxes), 100, [] { return std::make_unique<btBoxShape>(btVector3(20, 20, 100)); });
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); 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)); 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)); 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)); 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); mNavigator->update(mPlayerPosition);
@ -858,14 +889,15 @@ namespace
TEST_F(DetourNavigatorNavigatorTest, update_changed_multiple_times_object_should_delay_navmesh_change) TEST_F(DetourNavigatorNavigatorTest, update_changed_multiple_times_object_should_delay_navmesh_change)
{ {
const std::vector<btBoxShape> shapes(100, btVector3(64, 64, 64)); std::vector<CollisionShapeInstance<btBoxShape>> shapes;
std::generate_n(std::back_inserter(shapes), 100, [] { return std::make_unique<btBoxShape>(btVector3(64, 64, 64)); });
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
for (std::size_t i = 0; i < shapes.size(); ++i) for (std::size_t i = 0; i < shapes.size(); ++i)
{ {
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32, i * 32, i * 32)); 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -874,7 +906,7 @@ namespace
for (std::size_t i = 0; i < shapes.size(); ++i) 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)); 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -882,7 +914,7 @@ namespace
for (std::size_t i = 0; i < shapes.size(); ++i) 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)); 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->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -926,16 +958,16 @@ namespace
}}; }};
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
const btBoxShape oscillatingBoxShape(btVector3(20, 20, 20)); CollisionShapeInstance oscillatingBox(std::make_unique<btBoxShape>(btVector3(20, 20, 20)));
const btVector3 oscillatingBoxShapePosition(32, 32, 400); const btVector3 oscillatingBoxShapePosition(32, 32, 400);
const btBoxShape boderBoxShape(btVector3(50, 50, 50)); CollisionShapeInstance boderBox(std::make_unique<btBoxShape>(btVector3(50, 50, 50)));
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); 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)); btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition));
// add this box to make navmesh bound box independent from oscillatingBoxShape rotations // 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))); btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200)));
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
@ -952,7 +984,7 @@ namespace
{ {
const btTransform transform(btQuaternion(btVector3(0, 0, 1), n * 2 * osg::PI / 10), const btTransform transform(btQuaternion(btVector3(0, 0, 1), n * 2 * osg::PI / 10),
oscillatingBoxShapePosition); oscillatingBoxShapePosition);
mNavigator->updateObject(ObjectId(&oscillatingBoxShape), ObjectShapes(oscillatingBoxShape, nullptr), transform); mNavigator->updateObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance()), transform);
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(mListener, WaitConditionType::allJobsDone); mNavigator->wait(mListener, WaitConditionType::allJobsDone);
} }

View file

@ -14,20 +14,22 @@ namespace
struct DetourNavigatorRecastMeshObjectTest : Test struct DetourNavigatorRecastMeshObjectTest : Test
{ {
btBoxShape mBoxShape {btVector3(1, 2, 3)}; btBoxShape mBoxShapeImpl {btVector3(1, 2, 3)};
btCompoundShape mCompoundShape {true}; CollisionShape mBoxShape {nullptr, mBoxShapeImpl};
btCompoundShape mCompoundShapeImpl {true};
CollisionShape mCompoundShape {nullptr, mCompoundShapeImpl};
btTransform mTransform {btQuaternion(btVector3(1, 2, 3), 1), btVector3(1, 2, 3)}; btTransform mTransform {btQuaternion(btVector3(1, 2, 3), 1), btVector3(1, 2, 3)};
DetourNavigatorRecastMeshObjectTest() DetourNavigatorRecastMeshObjectTest()
{ {
mCompoundShape.addChildShape(mTransform, std::addressof(mBoxShape)); mCompoundShapeImpl.addChildShape(mTransform, std::addressof(mBoxShapeImpl));
} }
}; };
TEST_F(DetourNavigatorRecastMeshObjectTest, constructed_object_should_have_shape_and_transform) TEST_F(DetourNavigatorRecastMeshObjectTest, constructed_object_should_have_shape_and_transform)
{ {
const RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); 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); 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) TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_compound_shape_with_same_transform_and_changed_child_transform_should_return_true)
{ {
RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground); RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground);
mCompoundShape.updateChildTransform(0, btTransform::getIdentity()); mCompoundShapeImpl.updateChildTransform(0, btTransform::getIdentity());
EXPECT_TRUE(object.update(mTransform, AreaType_ground)); EXPECT_TRUE(object.update(mTransform, AreaType_ground));
} }
TEST_F(DetourNavigatorRecastMeshObjectTest, repeated_update_for_compound_shape_without_changes_should_return_false) TEST_F(DetourNavigatorRecastMeshObjectTest, repeated_update_for_compound_shape_without_changes_should_return_false)
{ {
RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground); RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground);
mCompoundShape.updateChildTransform(0, btTransform::getIdentity()); mCompoundShapeImpl.updateChildTransform(0, btTransform::getIdentity());
object.update(mTransform, AreaType_ground); object.update(mTransform, AreaType_ground);
EXPECT_FALSE(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) TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_changed_local_scaling_should_return_true)
{ {
RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); 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)); EXPECT_TRUE(object.update(mTransform, AreaType_ground));
} }
} }

View file

@ -62,22 +62,25 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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) TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_existing_object_should_return_false)
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); const btBoxShape boxShape(btVector3(20, 20, 100));
manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); const CollisionShape shape(nullptr, boxShape);
EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); 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) TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_add_tiles)
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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 x = -1; x < 1; ++x)
for (int y = -1; y < 1; ++y) for (int y = -1; y < 1; ++y)
ASSERT_TRUE(manager.hasTile(TilePosition(x, y))); ASSERT_TRUE(manager.hasTile(TilePosition(x, y)));
@ -88,8 +91,9 @@ namespace
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); const btBoxShape boxShape(btVector3(20, 20, 100));
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); 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);
EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, 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); })); [&] (const auto& v) { onChangedTile(v); }));
EXPECT_THAT( EXPECT_THAT(
mChangedTiles, mChangedTiles,
@ -102,8 +106,9 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); const btBoxShape boxShape(btVector3(20, 20, 100));
manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground); const CollisionShape shape(nullptr, boxShape);
EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground, 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); })); [&] (const auto& v) { onChangedTile(v); }));
EXPECT_EQ(mChangedTiles, std::vector<TilePosition>()); EXPECT_EQ(mChangedTiles, std::vector<TilePosition>());
} }
@ -112,7 +117,8 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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, -1)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
@ -123,7 +129,8 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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); EXPECT_EQ(manager.getMesh(TilePosition(1, 0)), nullptr);
} }
@ -132,14 +139,15 @@ namespace
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); const btBoxShape boxShape(btVector3(20, 20, 100));
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); 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, -1)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, 0)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(1, 0)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(1, -1)), 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, -1)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
@ -151,12 +159,13 @@ namespace
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); const btBoxShape boxShape(btVector3(20, 20, 100));
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); 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, -1)), nullptr);
EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), 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, 0)), nullptr);
EXPECT_EQ(manager.getMesh(TilePosition(1, -1)), nullptr); EXPECT_EQ(manager.getMesh(TilePosition(1, -1)), nullptr);
} }
@ -165,7 +174,8 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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)); manager.removeObject(ObjectId(&boxShape));
EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr); EXPECT_EQ(manager.getMesh(TilePosition(-1, -1)), nullptr);
EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_EQ(manager.getMesh(TilePosition(-1, 0)), nullptr);
@ -177,14 +187,15 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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, -1)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(0, 0)), 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, -1)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(-1, 0)), nullptr);
EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh(TilePosition(0, -1)), nullptr);
@ -196,7 +207,8 @@ namespace
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const auto initialRevision = manager.getRevision(); const auto initialRevision = manager.getRevision();
const btBoxShape boxShape(btVector3(20, 20, 100)); 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); EXPECT_EQ(manager.getRevision(), initialRevision + 1);
} }
@ -204,9 +216,10 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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(); 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); EXPECT_EQ(manager.getRevision(), beforeAddRevision);
} }
@ -215,9 +228,10 @@ namespace
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); const btBoxShape boxShape(btVector3(20, 20, 100));
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); 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(); 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); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision + 1);
} }
@ -225,9 +239,10 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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(); 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); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision);
} }
@ -235,7 +250,8 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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(); const auto beforeRemoveRevision = manager.getRevision();
manager.removeObject(ObjectId(&boxShape)); manager.removeObject(ObjectId(&boxShape));
EXPECT_EQ(manager.getRevision(), beforeRemoveRevision + 1); EXPECT_EQ(manager.getRevision(), beforeRemoveRevision + 1);
@ -272,7 +288,8 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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 osg::Vec2i cellPosition(0, 0);
const int cellSize = std::numeric_limits<int>::max(); const int cellSize = std::numeric_limits<int>::max();
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f()));
@ -314,7 +331,8 @@ namespace
{ {
TileCachedRecastMeshManager manager(mSettings); TileCachedRecastMeshManager manager(mSettings);
const btBoxShape boxShape(btVector3(20, 20, 100)); 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 osg::Vec2i cellPosition(0, 0);
const int cellSize = 8192; const int cellSize = 8192;
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f()));
@ -330,7 +348,8 @@ namespace
const osg::Vec2i cellPosition(0, 0); const osg::Vec2i cellPosition(0, 0);
const int cellSize = 8192; const int cellSize = 8192;
const btBoxShape boxShape(btVector3(20, 20, 100)); 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.addWater(cellPosition, cellSize, osg::Vec3f()));
ASSERT_TRUE(manager.removeObject(ObjectId(&boxShape))); ASSERT_TRUE(manager.removeObject(ObjectId(&boxShape)));
for (int x = -6; x < 6; ++x) for (int x = -6; x < 6; ++x)

View file

@ -8,7 +8,7 @@ namespace DetourNavigator
: mImpl(settings, bounds, generation) : 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) const btTransform& transform, const AreaType areaType)
{ {
if (!mImpl.addObject(id, shape, transform, areaType)) if (!mImpl.addObject(id, shape, transform, areaType))

View file

@ -12,7 +12,7 @@ namespace DetourNavigator
public: public:
CachedRecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation); 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); const AreaType areaType);
bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType);

View file

@ -10,6 +10,8 @@
#include "waitconditiontype.hpp" #include "waitconditiontype.hpp"
#include "heightfieldshape.hpp" #include "heightfieldshape.hpp"
#include <components/resource/bulletshape.hpp>
#include <variant> #include <variant>
namespace ESM namespace ESM
@ -27,11 +29,10 @@ namespace DetourNavigator
{ {
struct ObjectShapes struct ObjectShapes
{ {
const btCollisionShape& mShape; osg::ref_ptr<const Resource::BulletShapeInstance> mShapeInstance;
const btCollisionShape* mAvoid;
ObjectShapes(const btCollisionShape& shape, const btCollisionShape* avoid) ObjectShapes(const osg::ref_ptr<const Resource::BulletShapeInstance>& shapeInstance)
: mShape(shape), mAvoid(avoid) : mShapeInstance(shapeInstance)
{} {}
}; };
@ -40,9 +41,9 @@ namespace DetourNavigator
osg::Vec3f mConnectionStart; osg::Vec3f mConnectionStart;
osg::Vec3f mConnectionEnd; osg::Vec3f mConnectionEnd;
DoorShapes(const btCollisionShape& shape, const btCollisionShape* avoid, DoorShapes(const osg::ref_ptr<const Resource::BulletShapeInstance>& shapeInstance,
const osg::Vec3f& connectionStart,const osg::Vec3f& connectionEnd) const osg::Vec3f& connectionStart,const osg::Vec3f& connectionEnd)
: ObjectShapes(shape, avoid) : ObjectShapes(shapeInstance)
, mConnectionStart(connectionStart) , mConnectionStart(connectionStart)
, mConnectionEnd(connectionEnd) , mConnectionEnd(connectionEnd)
{} {}

View file

@ -34,11 +34,13 @@ namespace DetourNavigator
bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
{ {
bool result = mNavMeshManager.addObject(id, shapes.mShape, transform, AreaType_ground); CollisionShape collisionShape {shapes.mShapeInstance, *shapes.mShapeInstance->getCollisionShape()};
if (shapes.mAvoid) bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground);
if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->getAvoidCollisionShape())
{ {
const ObjectId avoidId(shapes.mAvoid); const ObjectId avoidId(avoidShape);
if (mNavMeshManager.addObject(avoidId, *shapes.mAvoid, transform, AreaType_null)) CollisionShape collisionShape {shapes.mShapeInstance, *avoidShape};
if (mNavMeshManager.addObject(avoidId, collisionShape, transform, AreaType_null))
{ {
updateAvoidShapeId(id, avoidId); updateAvoidShapeId(id, avoidId);
result = true; result = true;
@ -62,11 +64,13 @@ namespace DetourNavigator
bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
{ {
bool result = mNavMeshManager.updateObject(id, shapes.mShape, transform, AreaType_ground); const CollisionShape collisionShape {shapes.mShapeInstance, *shapes.mShapeInstance->getCollisionShape()};
if (shapes.mAvoid) bool result = mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground);
if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->getAvoidCollisionShape())
{ {
const ObjectId avoidId(shapes.mAvoid); const ObjectId avoidId(avoidShape);
if (mNavMeshManager.updateObject(avoidId, *shapes.mAvoid, transform, AreaType_null)) const CollisionShape collisionShape {shapes.mShapeInstance, *avoidShape};
if (mNavMeshManager.updateObject(avoidId, collisionShape, transform, AreaType_null))
{ {
updateAvoidShapeId(id, avoidId); updateAvoidShapeId(id, avoidId);
result = true; result = true;

View file

@ -47,16 +47,17 @@ namespace DetourNavigator
, mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager) , 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 AreaType areaType)
{ {
const btCollisionShape& collisionShape = shape.getShape();
if (!mRecastMeshManager.addObject(id, shape, transform, areaType)) if (!mRecastMeshManager.addObject(id, shape, transform, areaType))
return false; return false;
addChangedTiles(shape, transform, ChangeType::add); addChangedTiles(collisionShape, transform, ChangeType::add);
return true; 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) const AreaType areaType)
{ {
return mRecastMeshManager.updateObject(id, shape, transform, areaType, return mRecastMeshManager.updateObject(id, shape, transform, areaType,

View file

@ -24,10 +24,10 @@ namespace DetourNavigator
public: public:
NavMeshManager(const Settings& settings); 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); 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); const AreaType areaType);
bool removeObject(const ObjectId id); bool removeObject(const ObjectId id);

View file

@ -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 AreaType areaType)
{ {
const auto object = mObjects.lower_bound(id); const auto object = mObjects.lower_bound(id);

View file

@ -35,7 +35,7 @@ namespace DetourNavigator
public: public:
RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation); 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); const AreaType areaType);
bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType);

View file

@ -22,15 +22,36 @@ namespace DetourNavigator
} }
return result; return result;
} }
std::vector<RecastMeshObject> makeChildrenObjects(const osg::ref_ptr<const Resource::BulletShapeInstance>& instance,
const btCompoundShape& shape, const AreaType areaType)
{
std::vector<RecastMeshObject> 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;
} }
RecastMeshObject::RecastMeshObject(const btCollisionShape& shape, const btTransform& transform, std::vector<RecastMeshObject> makeChildrenObjects(const osg::ref_ptr<const Resource::BulletShapeInstance>& instance,
const btCollisionShape& shape, const AreaType areaType)
{
if (shape.isCompound())
return makeChildrenObjects(std::move(instance), static_cast<const btCompoundShape&>(shape), areaType);
return std::vector<RecastMeshObject>();
}
}
RecastMeshObject::RecastMeshObject(const CollisionShape& shape, const btTransform& transform,
const AreaType areaType) const AreaType areaType)
: mShape(shape) : mShapeInstance(shape.getShapeInstance())
, mShape(shape.getShape())
, mTransform(transform) , mTransform(transform)
, mAreaType(areaType) , mAreaType(areaType)
, mLocalScaling(shape.getLocalScaling()) , mLocalScaling(mShape.get().getLocalScaling())
, mChildren(makeChildrenObjects(shape, mAreaType)) , mChildren(makeChildrenObjects(mShapeInstance, mShape.get(), mAreaType))
{ {
} }
@ -57,20 +78,4 @@ namespace DetourNavigator
|| result; || result;
return result; return result;
} }
std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType)
{
if (shape.isCompound())
return makeChildrenObjects(static_cast<const btCompoundShape&>(shape), areaType);
else
return std::vector<RecastMeshObject>();
}
std::vector<RecastMeshObject> makeChildrenObjects(const btCompoundShape& shape, const AreaType areaType)
{
std::vector<RecastMeshObject> result;
for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i)
result.emplace_back(*shape.getChildShape(i), shape.getChildTransform(i), areaType);
return result;
}
} }

View file

@ -3,8 +3,12 @@
#include "areatype.hpp" #include "areatype.hpp"
#include <components/resource/bulletshape.hpp>
#include <LinearMath/btTransform.h> #include <LinearMath/btTransform.h>
#include <osg/ref_ptr>
#include <functional> #include <functional>
#include <vector> #include <vector>
@ -13,10 +17,26 @@ class btCompoundShape;
namespace DetourNavigator namespace DetourNavigator
{ {
class CollisionShape
{
public:
CollisionShape(osg::ref_ptr<const Resource::BulletShapeInstance> instance, const btCollisionShape& shape)
: mShapeInstance(std::move(instance))
, mShape(shape)
{}
const osg::ref_ptr<const Resource::BulletShapeInstance>& getShapeInstance() const { return mShapeInstance; }
const btCollisionShape& getShape() const { return mShape; }
private:
osg::ref_ptr<const Resource::BulletShapeInstance> mShapeInstance;
std::reference_wrapper<const btCollisionShape> mShape;
};
class RecastMeshObject class RecastMeshObject
{ {
public: 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); bool update(const btTransform& transform, const AreaType areaType);
@ -36,16 +56,13 @@ namespace DetourNavigator
} }
private: private:
osg::ref_ptr<const Resource::BulletShapeInstance> mShapeInstance;
std::reference_wrapper<const btCollisionShape> mShape; std::reference_wrapper<const btCollisionShape> mShape;
btTransform mTransform; btTransform mTransform;
AreaType mAreaType; AreaType mAreaType;
btVector3 mLocalScaling; btVector3 mLocalScaling;
std::vector<RecastMeshObject> mChildren; std::vector<RecastMeshObject> mChildren;
}; };
std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType);
std::vector<RecastMeshObject> makeChildrenObjects(const btCompoundShape& shape, const AreaType areaType);
} }
#endif #endif

View file

@ -14,14 +14,14 @@ namespace DetourNavigator
: mSettings(settings) : 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) const btTransform& transform, const AreaType areaType)
{ {
std::vector<TilePosition> tilesPositions; std::vector<TilePosition> tilesPositions;
const auto border = getBorderSize(mSettings); const auto border = getBorderSize(mSettings);
{ {
auto tiles = mTiles.lock(); 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())) if (addTile(id, shape, transform, areaType, tilePosition, border, tiles.get()))
tilesPositions.push_back(tilePosition); tilesPositions.push_back(tilePosition);
@ -218,7 +218,7 @@ namespace DetourNavigator
it->second.reportNavMeshChange(recastMeshVersion, navMeshVersion); 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, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border,
std::map<TilePosition, CachedRecastMeshManager>& tiles) std::map<TilePosition, CachedRecastMeshManager>& tiles)
{ {

View file

@ -22,11 +22,11 @@ namespace DetourNavigator
public: public:
TileCachedRecastMeshManager(const Settings& settings); 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); const AreaType areaType);
template <class OnChangedTile> template <class OnChangedTile>
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 AreaType areaType, OnChangedTile&& onChangedTile)
{ {
const auto object = mObjectsTilesPositions.find(id); const auto object = mObjectsTilesPositions.find(id);
@ -56,7 +56,7 @@ namespace DetourNavigator
changed = true; changed = true;
} }
}; };
getTilesPositions(shape, transform, mSettings, onTilePosition); getTilesPositions(shape.getShape(), transform, mSettings, onTilePosition);
std::sort(newTiles.begin(), newTiles.end()); std::sort(newTiles.begin(), newTiles.end());
for (const auto& tile : currentTiles) for (const auto& tile : currentTiles)
{ {
@ -110,7 +110,7 @@ namespace DetourNavigator
std::size_t mRevision = 0; std::size_t mRevision = 0;
std::size_t mTilesGeneration = 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, const AreaType areaType, const TilePosition& tilePosition, float border,
std::map<TilePosition, CachedRecastMeshManager>& tiles); std::map<TilePosition, CachedRecastMeshManager>& tiles);

View file

@ -6,6 +6,7 @@
#include <BulletCollision/CollisionShapes/btBoxShape.h> #include <BulletCollision/CollisionShapes/btBoxShape.h>
#include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h> #include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h> #include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
namespace Resource namespace Resource
{ {
@ -75,6 +76,9 @@ btCollisionShape* BulletShape::duplicateCollisionShape(const btCollisionShape *s
return new btBoxShape(*boxshape); return new btBoxShape(*boxshape);
} }
if (shape->getShapeType() == TERRAIN_SHAPE_PROXYTYPE)
return new btHeightfieldTerrainShape(static_cast<const btHeightfieldTerrainShape&>(*shape));
throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName()); throw std::logic_error(std::string("Unhandled Bullet shape duplication: ")+shape->getName());
} }