Merge upstream/master
commit
3785ba6aa0
@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
#!/bin/sh -e
|
||||
sudo ln -s /usr/bin/clang-3.6 /usr/local/bin/clang
|
||||
sudo ln -s /usr/bin/clang++-3.6 /usr/local/bin/clang++
|
||||
|
@ -0,0 +1,17 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
git clone https://github.com/recastnavigation/recastnavigation.git
|
||||
cd recastnavigation
|
||||
mkdir build
|
||||
cd build
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE="${CONFIGURATION}" \
|
||||
-DRECASTNAVIGATION_DEMO=OFF \
|
||||
-DRECASTNAVIGATION_TESTS=OFF \
|
||||
-DRECASTNAVIGATION_EXAMPLES=OFF \
|
||||
-DRECASTNAVIGATION_STATIC=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=. \
|
||||
-G "${GENERATOR}" \
|
||||
..
|
||||
cmake --build . --config "${CONFIGURATION}"
|
||||
cmake --build . --target install --config "${CONFIGURATION}"
|
@ -0,0 +1,54 @@
|
||||
#include "heightfield.hpp"
|
||||
|
||||
#include <osg/Object>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
|
||||
namespace MWPhysics
|
||||
{
|
||||
HeightField::HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject)
|
||||
{
|
||||
mShape = new btHeightfieldTerrainShape(
|
||||
sqrtVerts, sqrtVerts, heights, 1,
|
||||
minH, maxH, 2,
|
||||
PHY_FLOAT, false
|
||||
);
|
||||
mShape->setUseDiamondSubdivision(true);
|
||||
mShape->setLocalScaling(btVector3(triSize, triSize, 1));
|
||||
|
||||
btTransform transform(btQuaternion::getIdentity(),
|
||||
btVector3((x+0.5f) * triSize * (sqrtVerts-1),
|
||||
(y+0.5f) * triSize * (sqrtVerts-1),
|
||||
(maxH+minH)*0.5f));
|
||||
|
||||
mCollisionObject = new btCollisionObject;
|
||||
mCollisionObject->setCollisionShape(mShape);
|
||||
mCollisionObject->setWorldTransform(transform);
|
||||
|
||||
mHoldObject = holdObject;
|
||||
}
|
||||
|
||||
HeightField::~HeightField()
|
||||
{
|
||||
delete mCollisionObject;
|
||||
delete mShape;
|
||||
}
|
||||
|
||||
btCollisionObject* HeightField::getCollisionObject()
|
||||
{
|
||||
return mCollisionObject;
|
||||
}
|
||||
|
||||
const btCollisionObject* HeightField::getCollisionObject() const
|
||||
{
|
||||
return mCollisionObject;
|
||||
}
|
||||
|
||||
const btHeightfieldTerrainShape* HeightField::getShape() const
|
||||
{
|
||||
return mShape;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#ifndef OPENMW_MWPHYSICS_HEIGHTFIELD_H
|
||||
#define OPENMW_MWPHYSICS_HEIGHTFIELD_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
class btCollisionObject;
|
||||
class btHeightfieldTerrainShape;
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Object;
|
||||
}
|
||||
|
||||
namespace MWPhysics
|
||||
{
|
||||
class HeightField
|
||||
{
|
||||
public:
|
||||
HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject);
|
||||
~HeightField();
|
||||
|
||||
btCollisionObject* getCollisionObject();
|
||||
const btCollisionObject* getCollisionObject() const;
|
||||
const btHeightfieldTerrainShape* getShape() const;
|
||||
|
||||
private:
|
||||
btHeightfieldTerrainShape* mShape;
|
||||
btCollisionObject* mCollisionObject;
|
||||
osg::ref_ptr<const osg::Object> mHoldObject;
|
||||
|
||||
void operator=(const HeightField&);
|
||||
HeightField(const HeightField&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,130 @@
|
||||
#include "object.hpp"
|
||||
#include "convert.hpp"
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/nifosg/particle.hpp>
|
||||
#include <components/resource/bulletshape.hpp>
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
#include <osg/Object>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
|
||||
namespace MWPhysics
|
||||
{
|
||||
Object::Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance)
|
||||
: mShapeInstance(shapeInstance)
|
||||
, mSolid(true)
|
||||
{
|
||||
mPtr = ptr;
|
||||
|
||||
mCollisionObject.reset(new btCollisionObject);
|
||||
mCollisionObject->setCollisionShape(shapeInstance->getCollisionShape());
|
||||
|
||||
mCollisionObject->setUserPointer(static_cast<PtrHolder*>(this));
|
||||
|
||||
setScale(ptr.getCellRef().getScale());
|
||||
setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude()));
|
||||
const float* pos = ptr.getRefData().getPosition().pos;
|
||||
setOrigin(btVector3(pos[0], pos[1], pos[2]));
|
||||
}
|
||||
|
||||
const Resource::BulletShapeInstance* Object::getShapeInstance() const
|
||||
{
|
||||
return mShapeInstance.get();
|
||||
}
|
||||
|
||||
void Object::setScale(float scale)
|
||||
{
|
||||
mShapeInstance->setLocalScaling(btVector3(scale, scale, scale));
|
||||
}
|
||||
|
||||
void Object::setRotation(const btQuaternion& quat)
|
||||
{
|
||||
mCollisionObject->getWorldTransform().setRotation(quat);
|
||||
}
|
||||
|
||||
void Object::setOrigin(const btVector3& vec)
|
||||
{
|
||||
mCollisionObject->getWorldTransform().setOrigin(vec);
|
||||
}
|
||||
|
||||
btCollisionObject* Object::getCollisionObject()
|
||||
{
|
||||
return mCollisionObject.get();
|
||||
}
|
||||
|
||||
const btCollisionObject* Object::getCollisionObject() const
|
||||
{
|
||||
return mCollisionObject.get();
|
||||
}
|
||||
|
||||
bool Object::isSolid() const
|
||||
{
|
||||
return mSolid;
|
||||
}
|
||||
|
||||
void Object::setSolid(bool solid)
|
||||
{
|
||||
mSolid = solid;
|
||||
}
|
||||
|
||||
bool Object::isAnimated() const
|
||||
{
|
||||
return !mShapeInstance->mAnimatedShapes.empty();
|
||||
}
|
||||
|
||||
void Object::animateCollisionShapes(btCollisionWorld* collisionWorld)
|
||||
{
|
||||
if (mShapeInstance->mAnimatedShapes.empty())
|
||||
return;
|
||||
|
||||
assert (mShapeInstance->getCollisionShape()->isCompound());
|
||||
|
||||
btCompoundShape* compound = static_cast<btCompoundShape*>(mShapeInstance->getCollisionShape());
|
||||
for (std::map<int, int>::const_iterator it = mShapeInstance->mAnimatedShapes.begin(); it != mShapeInstance->mAnimatedShapes.end(); ++it)
|
||||
{
|
||||
int recIndex = it->first;
|
||||
int shapeIndex = it->second;
|
||||
|
||||
std::map<int, osg::NodePath>::iterator nodePathFound = mRecIndexToNodePath.find(recIndex);
|
||||
if (nodePathFound == mRecIndexToNodePath.end())
|
||||
{
|
||||
NifOsg::FindGroupByRecIndex visitor(recIndex);
|
||||
mPtr.getRefData().getBaseNode()->accept(visitor);
|
||||
if (!visitor.mFound)
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: animateCollisionShapes can't find node " << recIndex << " for " << mPtr.getCellRef().getRefId();
|
||||
|
||||
// Remove nonexistent nodes from animated shapes map and early out
|
||||
mShapeInstance->mAnimatedShapes.erase(recIndex);
|
||||
return;
|
||||
}
|
||||
osg::NodePath nodePath = visitor.mFoundPath;
|
||||
nodePath.erase(nodePath.begin());
|
||||
nodePathFound = mRecIndexToNodePath.insert(std::make_pair(recIndex, nodePath)).first;
|
||||
}
|
||||
|
||||
osg::NodePath& nodePath = nodePathFound->second;
|
||||
osg::Matrixf matrix = osg::computeLocalToWorld(nodePath);
|
||||
matrix.orthoNormalize(matrix);
|
||||
|
||||
btTransform transform;
|
||||
transform.setOrigin(toBullet(matrix.getTrans()) * compound->getLocalScaling());
|
||||
for (int i=0; i<3; ++i)
|
||||
for (int j=0; j<3; ++j)
|
||||
transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference
|
||||
|
||||
// Note: we can not apply scaling here for now since we treat scaled shapes
|
||||
// as new shapes (btScaledBvhTriangleMeshShape) with 1.0 scale for now
|
||||
if (!(transform == compound->getChildTransform(shapeIndex)))
|
||||
compound->updateChildTransform(shapeIndex, transform);
|
||||
}
|
||||
|
||||
collisionWorld->updateSingleAabb(mCollisionObject.get());
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
#ifndef OPENMW_MWPHYSICS_OBJECT_H
|
||||
#define OPENMW_MWPHYSICS_OBJECT_H
|
||||
|
||||
#include "ptrholder.hpp"
|
||||
|
||||
#include <osg/Node>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
class BulletShapeInstance;
|
||||
}
|
||||
|
||||
class btCollisionObject;
|
||||
class btCollisionWorld;
|
||||
class btQuaternion;
|
||||
class btVector3;
|
||||
|
||||
namespace MWPhysics
|
||||
{
|
||||
class Object : public PtrHolder
|
||||
{
|
||||
public:
|
||||
Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance);
|
||||
|
||||
const Resource::BulletShapeInstance* getShapeInstance() const;
|
||||
void setScale(float scale);
|
||||
void setRotation(const btQuaternion& quat);
|
||||
void setOrigin(const btVector3& vec);
|
||||
btCollisionObject* getCollisionObject();
|
||||
const btCollisionObject* getCollisionObject() const;
|
||||
/// Return solid flag. Not used by the object itself, true by default.
|
||||
bool isSolid() const;
|
||||
void setSolid(bool solid);
|
||||
bool isAnimated() const;
|
||||
void animateCollisionShapes(btCollisionWorld* collisionWorld);
|
||||
|
||||
private:
|
||||
std::unique_ptr<btCollisionObject> mCollisionObject;
|
||||
osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance;
|
||||
std::map<int, osg::NodePath> mRecIndexToNodePath;
|
||||
bool mSolid;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,33 @@
|
||||
#ifndef OPENMW_MWPHYSICS_PTRHOLDER_H
|
||||
#define OPENMW_MWPHYSICS_PTRHOLDER_H
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace MWPhysics
|
||||
{
|
||||
class PtrHolder
|
||||
{
|
||||
public:
|
||||
virtual ~PtrHolder() {}
|
||||
|
||||
void updatePtr(const MWWorld::Ptr& updated)
|
||||
{
|
||||
mPtr = updated;
|
||||
}
|
||||
|
||||
MWWorld::Ptr getPtr()
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
MWWorld::ConstPtr getPtr() const
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
protected:
|
||||
MWWorld::Ptr mPtr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,99 @@
|
||||
#include "actorspaths.hpp"
|
||||
#include "vismask.hpp"
|
||||
|
||||
#include <components/sceneutil/agentpath.hpp>
|
||||
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
ActorsPaths::ActorsPaths(const osg::ref_ptr<osg::Group>& root, bool enabled)
|
||||
: mRootNode(root)
|
||||
, mEnabled(enabled)
|
||||
{
|
||||
}
|
||||
|
||||
ActorsPaths::~ActorsPaths()
|
||||
{
|
||||
if (mEnabled)
|
||||
disable();
|
||||
}
|
||||
|
||||
bool ActorsPaths::toggle()
|
||||
{
|
||||
if (mEnabled)
|
||||
disable();
|
||||
else
|
||||
enable();
|
||||
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
void ActorsPaths::update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::Settings& settings)
|
||||
{
|
||||
if (!mEnabled)
|
||||
return;
|
||||
|
||||
const auto group = mGroups.find(actor);
|
||||
if (group != mGroups.end())
|
||||
mRootNode->removeChild(group->second);
|
||||
|
||||
const auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings);
|
||||
if (newGroup)
|
||||
{
|
||||
newGroup->setNodeMask(Mask_Debug);
|
||||
mRootNode->addChild(newGroup);
|
||||
mGroups[actor] = newGroup;
|
||||
}
|
||||
}
|
||||
|
||||
void ActorsPaths::remove(const MWWorld::ConstPtr& actor)
|
||||
{
|
||||
const auto group = mGroups.find(actor);
|
||||
if (group != mGroups.end())
|
||||
{
|
||||
mRootNode->removeChild(group->second);
|
||||
mGroups.erase(group);
|
||||
}
|
||||
}
|
||||
|
||||
void ActorsPaths::removeCell(const MWWorld::CellStore* const store)
|
||||
{
|
||||
for (auto it = mGroups.begin(); it != mGroups.end(); )
|
||||
{
|
||||
if (it->first.getCell() == store)
|
||||
{
|
||||
mRootNode->removeChild(it->second);
|
||||
it = mGroups.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void ActorsPaths::updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated)
|
||||
{
|
||||
const auto it = mGroups.find(old);
|
||||
if (it == mGroups.end())
|
||||
return;
|
||||
auto group = std::move(it->second);
|
||||
mGroups.erase(it);
|
||||
mGroups.insert(std::make_pair(updated, std::move(group)));
|
||||
}
|
||||
|
||||
void ActorsPaths::enable()
|
||||
{
|
||||
std::for_each(mGroups.begin(), mGroups.end(),
|
||||
[&] (const Groups::value_type& v) { mRootNode->addChild(v.second); });
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
void ActorsPaths::disable()
|
||||
{
|
||||
std::for_each(mGroups.begin(), mGroups.end(),
|
||||
[&] (const Groups::value_type& v) { mRootNode->removeChild(v.second); });
|
||||
mEnabled = false;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
#ifndef OPENMW_MWRENDER_AGENTSPATHS_H
|
||||
#define OPENMW_MWRENDER_AGENTSPATHS_H
|
||||
|
||||
#include <apps/openmw/mwworld/ptr.hpp>
|
||||
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <deque>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class ActorsPaths
|
||||
{
|
||||
public:
|
||||
ActorsPaths(const osg::ref_ptr<osg::Group>& root, bool enabled);
|
||||
~ActorsPaths();
|
||||
|
||||
bool toggle();
|
||||
|
||||
void update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::Settings& settings);
|
||||
|
||||
void remove(const MWWorld::ConstPtr& actor);
|
||||
|
||||
void removeCell(const MWWorld::CellStore* const store);
|
||||
|
||||
void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated);
|
||||
|
||||
void enable();
|
||||
|
||||
void disable();
|
||||
|
||||
private:
|
||||
using Groups = std::map<MWWorld::ConstPtr, osg::ref_ptr<osg::Group>>;
|
||||
|
||||
osg::ref_ptr<osg::Group> mRootNode;
|
||||
Groups mGroups;
|
||||
bool mEnabled;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,71 @@
|
||||
#include "navmesh.hpp"
|
||||
#include "vismask.hpp"
|
||||
|
||||
#include <components/sceneutil/navmesh.hpp>
|
||||
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
NavMesh::NavMesh(const osg::ref_ptr<osg::Group>& root, bool enabled)
|
||||
: mRootNode(root)
|
||||
, mEnabled(enabled)
|
||||
, mGeneration(0)
|
||||
, mRevision(0)
|
||||
{
|
||||
}
|
||||
|
||||
NavMesh::~NavMesh()
|
||||
{
|
||||
if (mEnabled)
|
||||
disable();
|
||||
}
|
||||
|
||||
bool NavMesh::toggle()
|
||||
{
|
||||
if (mEnabled)
|
||||
disable();
|
||||
else
|
||||
enable();
|
||||
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
void NavMesh::update(const dtNavMesh& navMesh, const std::size_t id,
|
||||
const std::size_t generation, const std::size_t revision, const DetourNavigator::Settings& settings)
|
||||
{
|
||||
if (!mEnabled || (mId == id && mGeneration >= generation && mRevision >= revision))
|
||||
return;
|
||||
|
||||
mId = id;
|
||||
mGeneration = generation;
|
||||
mRevision = revision;
|
||||
if (mGroup)
|
||||
mRootNode->removeChild(mGroup);
|
||||
mGroup = SceneUtil::createNavMeshGroup(navMesh, settings);
|
||||
if (mGroup)
|
||||
{
|
||||
mGroup->setNodeMask(Mask_Debug);
|
||||
mRootNode->addChild(mGroup);
|
||||
}
|
||||
}
|
||||
|
||||
void NavMesh::reset()
|
||||
{
|
||||
if (mGroup)
|
||||
mRootNode->removeChild(mGroup);
|
||||
}
|
||||
|
||||
void NavMesh::enable()
|
||||
{
|
||||
if (mGroup)
|
||||
mRootNode->addChild(mGroup);
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
void NavMesh::disable()
|
||||
{
|
||||
reset();
|
||||
mEnabled = false;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
#ifndef OPENMW_MWRENDER_NAVMESH_H
|
||||
#define OPENMW_MWRENDER_NAVMESH_H
|
||||
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
class Geometry;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class NavMesh
|
||||
{
|
||||
public:
|
||||
NavMesh(const osg::ref_ptr<osg::Group>& root, bool enabled);
|
||||
~NavMesh();
|
||||
|
||||
bool toggle();
|
||||
|
||||
void update(const dtNavMesh& navMesh, const std::size_t number, const std::size_t generation,
|
||||
const std::size_t revision, const DetourNavigator::Settings& settings);
|
||||
|
||||
void reset();
|
||||
|
||||
void enable();
|
||||
|
||||
void disable();
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::Group> mRootNode;
|
||||
bool mEnabled;
|
||||
std::size_t mId = std::numeric_limits<std::size_t>::max();
|
||||
std::size_t mGeneration;
|
||||
std::size_t mRevision;
|
||||
osg::ref_ptr<osg::Group> mGroup;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,104 @@
|
||||
#include <components/detournavigator/gettilespositions.hpp>
|
||||
#include <components/detournavigator/debug.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
using namespace DetourNavigator;
|
||||
|
||||
struct CollectTilesPositions
|
||||
{
|
||||
std::vector<TilePosition>& mTilesPositions;
|
||||
|
||||
void operator ()(const TilePosition& value)
|
||||
{
|
||||
mTilesPositions.push_back(value);
|
||||
}
|
||||
};
|
||||
|
||||
struct DetourNavigatorGetTilesPositionsTest : Test
|
||||
{
|
||||
Settings mSettings;
|
||||
std::vector<TilePosition> mTilesPositions;
|
||||
CollectTilesPositions mCollect {mTilesPositions};
|
||||
|
||||
DetourNavigatorGetTilesPositionsTest()
|
||||
{
|
||||
mSettings.mBorderSize = 0;
|
||||
mSettings.mCellSize = 0.5;
|
||||
mSettings.mRecastScaleFactor = 1;
|
||||
mSettings.mTileSize = 64;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DetourNavigatorGetTilesPositionsTest, for_object_in_single_tile_should_return_one_tile)
|
||||
{
|
||||
getTilesPositions(osg::Vec3f(2, 2, 0), osg::Vec3f(31, 31, 1), mSettings, mCollect);
|
||||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(TilePosition(0, 0)));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilesPositionsTest, for_object_with_x_bounds_in_two_tiles_should_return_two_tiles)
|
||||
{
|
||||
getTilesPositions(osg::Vec3f(0, 0, 0), osg::Vec3f(32, 31, 1), mSettings, mCollect);
|
||||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(TilePosition(0, 0), TilePosition(1, 0)));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilesPositionsTest, for_object_with_y_bounds_in_two_tiles_should_return_two_tiles)
|
||||
{
|
||||
getTilesPositions(osg::Vec3f(0, 0, 0), osg::Vec3f(31, 32, 1), mSettings, mCollect);
|
||||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(TilePosition(0, 0), TilePosition(0, 1)));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilesPositionsTest, tiling_works_only_for_x_and_y_coordinates)
|
||||
{
|
||||
getTilesPositions(osg::Vec3f(0, 0, 0), osg::Vec3f(31, 31, 32), mSettings, mCollect);
|
||||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(TilePosition(0, 0)));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilesPositionsTest, tiling_should_work_with_negative_coordinates)
|
||||
{
|
||||
getTilesPositions(osg::Vec3f(-31, -31, 0), osg::Vec3f(31, 31, 1), mSettings, mCollect);
|
||||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(
|
||||
TilePosition(-1, -1),
|
||||
TilePosition(-1, 0),
|
||||
TilePosition(0, -1),
|
||||
TilePosition(0, 0)
|
||||
));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilesPositionsTest, border_size_should_extend_tile_bounds)
|
||||
{
|
||||
mSettings.mBorderSize = 1;
|
||||
|
||||
getTilesPositions(osg::Vec3f(0, 0, 0), osg::Vec3f(31.5, 31.5, 1), mSettings, mCollect);
|
||||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(
|
||||
TilePosition(-1, -1),
|
||||
TilePosition(-1, 0),
|
||||
TilePosition(-1, 1),
|
||||
TilePosition(0, -1),
|
||||
TilePosition(0, 0),
|
||||
TilePosition(0, 1),
|
||||
TilePosition(1, -1),
|
||||
TilePosition(1, 0),
|
||||
TilePosition(1, 1)
|
||||
));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilesPositionsTest, should_apply_recast_scale_factor)
|
||||
{
|
||||
mSettings.mRecastScaleFactor = 0.5;
|
||||
|
||||
getTilesPositions(osg::Vec3f(0, 0, 0), osg::Vec3f(32, 32, 1), mSettings, mCollect);
|
||||
|
||||
EXPECT_THAT(mTilesPositions, ElementsAre(TilePosition(0, 0)));
|
||||
}
|
||||
}
|
@ -0,0 +1,661 @@
|
||||
#include "operators.hpp"
|
||||
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
#include <components/detournavigator/exceptions.hpp>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <deque>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
using namespace DetourNavigator;
|
||||
|
||||
struct DetourNavigatorNavigatorTest : Test
|
||||
{
|
||||
Settings mSettings;
|
||||
std::unique_ptr<Navigator> mNavigator;
|
||||
osg::Vec3f mPlayerPosition;
|
||||
osg::Vec3f mAgentHalfExtents;
|
||||
osg::Vec3f mStart;
|
||||
osg::Vec3f mEnd;
|
||||
std::deque<osg::Vec3f> mPath;
|
||||
std::back_insert_iterator<std::deque<osg::Vec3f>> mOut;
|
||||
|
||||
DetourNavigatorNavigatorTest()
|
||||
: mPlayerPosition(0, 0, 0)
|
||||
, mAgentHalfExtents(29, 29, 66)
|
||||
, mStart(-215, 215, 1)
|
||||
, mEnd(215, -215, 1)
|
||||
, mOut(mPath)
|
||||
{
|
||||
mSettings.mEnableWriteRecastMeshToFile = false;
|
||||
mSettings.mEnableWriteNavMeshToFile = false;
|
||||
mSettings.mEnableRecastMeshFileNameRevision = false;
|
||||
mSettings.mEnableNavMeshFileNameRevision = false;
|
||||
mSettings.mBorderSize = 16;
|
||||
mSettings.mCellHeight = 0.2f;
|
||||
mSettings.mCellSize = 0.2f;
|
||||
mSettings.mDetailSampleDist = 6;
|
||||
mSettings.mDetailSampleMaxError = 1;
|
||||
mSettings.mMaxClimb = 34;
|
||||
mSettings.mMaxSimplificationError = 1.3f;
|
||||
mSettings.mMaxSlope = 49;
|
||||
mSettings.mRecastScaleFactor = 0.017647058823529415f;
|
||||
mSettings.mSwimHeightScale = 0.89999997615814208984375f;
|
||||
mSettings.mMaxEdgeLen = 12;
|
||||
mSettings.mMaxNavMeshQueryNodes = 2048;
|
||||
mSettings.mMaxVertsPerPoly = 6;
|
||||
mSettings.mRegionMergeSize = 20;
|
||||
mSettings.mRegionMinSize = 8;
|
||||
mSettings.mTileSize = 64;
|
||||
mSettings.mAsyncNavMeshUpdaterThreads = 1;
|
||||
mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024;
|
||||
mSettings.mMaxPolygonPathSize = 1024;
|
||||
mSettings.mMaxSmoothPathSize = 1024;
|
||||
mSettings.mTrianglesPerChunk = 256;
|
||||
mSettings.mMaxPolys = 4096;
|
||||
mNavigator.reset(new Navigator(mSettings));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_throw_exception)
|
||||
{
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), InvalidArgument);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), NavigatorException);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_removed_agent_should_throw_exception)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->removeAgent(mAgentHalfExtents);
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), InvalidArgument);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->removeAgent(mAgentHalfExtents);
|
||||
EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), NavigatorException);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, update_then_find_path_should_return_path)
|
||||
{
|
||||
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 shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, 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, 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(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, 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(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mPath.clear();
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, 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(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity());
|
||||
mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, 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(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mPath.clear();
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, 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 {{
|
||||
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 shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
const std::array<btScalar, 5 * 5> heightfieldData2 {{
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape2(5, 5, heightfieldData2.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape2.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->addObject(ObjectId(&shape2), shape2, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(-215, 215, 1.96328866481781005859375),
|
||||
osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -0.2422157227993011474609375),
|
||||
osg::Vec3f(-174.930633544921875, 174.930633544921875, -2.44772052764892578125),
|
||||
osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -4.653223514556884765625),
|
||||
osg::Vec3f(-134.86126708984375, 134.86126708984375, -6.858728885650634765625),
|
||||
osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -9.0642337799072265625),
|
||||
osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -11.26973724365234375),
|
||||
osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -13.26497173309326171875),
|
||||
osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -15.24860286712646484375),
|
||||
osg::Vec3f(-34.68780517578125, 34.68780517578125, -17.2322368621826171875),
|
||||
osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -19.2158660888671875),
|
||||
osg::Vec3f(5.3815765380859375, -5.3815765380859375, -20.1338443756103515625),
|
||||
osg::Vec3f(25.41626739501953125, -25.41626739501953125, -18.150211334228515625),
|
||||
osg::Vec3f(45.450958251953125, -45.450958251953125, -16.1665802001953125),
|
||||
osg::Vec3f(65.48564910888671875, -65.48564910888671875, -14.18294811248779296875),
|
||||
osg::Vec3f(85.5203399658203125, -85.5203399658203125, -12.19931507110595703125),
|
||||
osg::Vec3f(105.55503082275390625, -105.55503082275390625, -10.08488559722900390625),
|
||||
osg::Vec3f(125.5897216796875, -125.5897216796875, -7.879383563995361328125),
|
||||
osg::Vec3f(145.6244049072265625, -145.6244049072265625, -5.673877239227294921875),
|
||||
osg::Vec3f(165.659088134765625, -165.659088134765625, -3.4683735370635986328125),
|
||||
osg::Vec3f(185.6937713623046875, -185.6937713623046875, -1.2628715038299560546875),
|
||||
osg::Vec3f(205.7284698486328125, -205.7284698486328125, 0.9426348209381103515625),
|
||||
osg::Vec3f(215, -215, 1.96328866481781005859375),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape)
|
||||
{
|
||||
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 shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
std::array<btScalar, 5 * 5> heightfieldDataAvoid {{
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
-25, -25, -25, -25, -25,
|
||||
}};
|
||||
btHeightfieldTerrainShape shapeAvoid(5, 5, heightfieldDataAvoid.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shapeAvoid.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(ObjectId(&shape), ObjectShapes {shape, &shapeAvoid}, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(-215, 215, 1.9393787384033203125),
|
||||
osg::Vec3f(-200.8159637451171875, 190.47265625, -0.639537751674652099609375),
|
||||
osg::Vec3f(-186.6319427490234375, 165.9453125, -3.2184507846832275390625),
|
||||
osg::Vec3f(-172.447906494140625, 141.41796875, -5.797363758087158203125),
|
||||
osg::Vec3f(-158.263885498046875, 116.8906097412109375, -8.37627887725830078125),
|
||||
osg::Vec3f(-144.079864501953125, 92.3632659912109375, -10.95519161224365234375),
|
||||
osg::Vec3f(-129.89581298828125, 67.83591461181640625, -13.534107208251953125),
|
||||
osg::Vec3f(-115.7117919921875, 43.308563232421875, -16.1130199432373046875),
|
||||
osg::Vec3f(-101.5277557373046875, 18.7812137603759765625, -18.6919345855712890625),
|
||||
osg::Vec3f(-87.34372711181640625, -5.7461376190185546875, -20.4680538177490234375),
|
||||
osg::Vec3f(-67.02922821044921875, -25.4970550537109375, -20.514247894287109375),
|
||||
osg::Vec3f(-46.714717864990234375, -45.2479705810546875, -20.5604457855224609375),
|
||||
osg::Vec3f(-26.40021514892578125, -64.99889373779296875, -20.6066417694091796875),
|
||||
osg::Vec3f(-6.085712432861328125, -84.74980926513671875, -20.652835845947265625),
|
||||
osg::Vec3f(14.22879505157470703125, -104.50072479248046875, -18.151393890380859375),
|
||||
osg::Vec3f(39.05098724365234375, -118.16222381591796875, -15.6674861907958984375),
|
||||
osg::Vec3f(63.87317657470703125, -131.82373046875, -13.18357944488525390625),
|
||||
osg::Vec3f(88.69537353515625, -145.4852142333984375, -10.69967365264892578125),
|
||||
osg::Vec3f(113.51757049560546875, -159.146697998046875, -8.21576690673828125),
|
||||
osg::Vec3f(138.3397674560546875, -172.808197021484375, -5.731858730316162109375),
|
||||
osg::Vec3f(163.1619720458984375, -186.469696044921875, -3.2479503154754638671875),
|
||||
osg::Vec3f(187.984161376953125, -200.1311798095703125, -0.764044582843780517578125),
|
||||
osg::Vec3f(212.8063507080078125, -213.7926788330078125, 1.7198636531829833984375),
|
||||
osg::Vec3f(215, -215, 1.93937528133392333984375),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_ground_lower_than_water_with_only_swim_flag)
|
||||
{
|
||||
std::array<btScalar, 5 * 5> heightfieldData {{
|
||||
-50, -50, -50, -50, 0,
|
||||
-50, -100, -150, -100, -50,
|
||||
-50, -150, -200, -150, -100,
|
||||
-50, -100, -150, -100, -100,
|
||||
0, -50, -100, -100, -100,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity());
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mStart.x() = 0;
|
||||
mStart.z() = 300;
|
||||
mEnd.x() = 0;
|
||||
mEnd.z() = 300;
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(0, 215, 185.33331298828125),
|
||||
osg::Vec3f(0, 186.6666717529296875, 185.33331298828125),
|
||||
osg::Vec3f(0, 158.333343505859375, 185.33331298828125),
|
||||
osg::Vec3f(0, 130.0000152587890625, 185.33331298828125),
|
||||
osg::Vec3f(0, 101.66667938232421875, 185.33331298828125),
|
||||
osg::Vec3f(0, 73.333343505859375, 185.33331298828125),
|
||||
osg::Vec3f(0, 45.0000152587890625, 185.33331298828125),
|
||||
osg::Vec3f(0, 16.6666812896728515625, 185.33331298828125),
|
||||
osg::Vec3f(0, -11.66664981842041015625, 185.33331298828125),
|
||||
osg::Vec3f(0, -39.999980926513671875, 185.33331298828125),
|
||||
osg::Vec3f(0, -68.33331298828125, 185.33331298828125),
|
||||
osg::Vec3f(0, -96.66664886474609375, 185.33331298828125),
|
||||
osg::Vec3f(0, -124.99997711181640625, 185.33331298828125),
|
||||
osg::Vec3f(0, -153.33331298828125, 185.33331298828125),
|
||||
osg::Vec3f(0, -181.6666412353515625, 185.33331298828125),
|
||||
osg::Vec3f(0, -209.999969482421875, 185.33331298828125),
|
||||
osg::Vec3f(0, -215, 185.33331298828125),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water_with_swim_and_walk_flags)
|
||||
{
|
||||
std::array<btScalar, 7 * 7> heightfieldData {{
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -150, -200, -150, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity());
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mStart.x() = 0;
|
||||
mEnd.x() = 0;
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim | Flag_walk, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(0, 215, -94.75363922119140625),
|
||||
osg::Vec3f(0, 186.6666717529296875, -106.0000152587890625),
|
||||
osg::Vec3f(0, 158.333343505859375, -115.85507965087890625),
|
||||
osg::Vec3f(0, 130.0000152587890625, -125.71016693115234375),
|
||||
osg::Vec3f(0, 101.66667938232421875, -135.5652313232421875),
|
||||
osg::Vec3f(0, 73.333343505859375, -143.3333587646484375),
|
||||
osg::Vec3f(0, 45.0000152587890625, -143.3333587646484375),
|
||||
osg::Vec3f(0, 16.6666812896728515625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -11.66664981842041015625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -39.999980926513671875, -143.3333587646484375),
|
||||
osg::Vec3f(0, -68.33331298828125, -143.3333587646484375),
|
||||
osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875),
|
||||
osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375),
|
||||
osg::Vec3f(0, -153.33331298828125, -117.5942230224609375),
|
||||
osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625),
|
||||
osg::Vec3f(0, -209.999969482421875, -97.79712677001953125),
|
||||
osg::Vec3f(0, -215, -94.753631591796875),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water_with_max_int_cells_size_and_swim_and_walk_flags)
|
||||
{
|
||||
std::array<btScalar, 7 * 7> heightfieldData {{
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -150, -200, -150, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits<int>::max(), -25, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mStart.x() = 0;
|
||||
mEnd.x() = 0;
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim | Flag_walk, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(0, 215, -94.75363922119140625),
|
||||
osg::Vec3f(0, 186.6666717529296875, -106.0000152587890625),
|
||||
osg::Vec3f(0, 158.333343505859375, -115.85507965087890625),
|
||||
osg::Vec3f(0, 130.0000152587890625, -125.71016693115234375),
|
||||
osg::Vec3f(0, 101.66667938232421875, -135.5652313232421875),
|
||||
osg::Vec3f(0, 73.333343505859375, -143.3333587646484375),
|
||||
osg::Vec3f(0, 45.0000152587890625, -143.3333587646484375),
|
||||
osg::Vec3f(0, 16.6666812896728515625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -11.66664981842041015625, -143.3333587646484375),
|
||||
osg::Vec3f(0, -39.999980926513671875, -143.3333587646484375),
|
||||
osg::Vec3f(0, -68.33331298828125, -143.3333587646484375),
|
||||
osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875),
|
||||
osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375),
|
||||
osg::Vec3f(0, -153.33331298828125, -117.5942230224609375),
|
||||
osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625),
|
||||
osg::Vec3f(0, -209.999969482421875, -97.79712677001953125),
|
||||
osg::Vec3f(0, -215, -94.753631591796875),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_ground_when_ground_cross_water_with_only_walk_flag)
|
||||
{
|
||||
std::array<btScalar, 7 * 7> heightfieldData {{
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -150, -200, -150, -100, 0,
|
||||
0, -100, -150, -150, -150, -100, 0,
|
||||
0, -100, -100, -100, -100, -100, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
}};
|
||||
btHeightfieldTerrainShape shape(7, 7, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity());
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mStart.x() = 0;
|
||||
mEnd.x() = 0;
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut);
|
||||
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>({
|
||||
osg::Vec3f(0, 215, -94.75363922119140625),
|
||||
osg::Vec3f(9.8083515167236328125, 188.4185333251953125, -105.19994354248046875),
|
||||
osg::Vec3f(19.6167049407958984375, 161.837066650390625, -114.25496673583984375),
|
||||
osg::Vec3f(29.42505645751953125, 135.255615234375, -123.309967041015625),
|
||||
osg::Vec3f(39.23340606689453125, 108.674163818359375, -132.3649749755859375),
|
||||
osg::Vec3f(49.04175567626953125, 82.09270477294921875, -137.2874755859375),
|
||||
osg::Vec3f(58.8501129150390625, 55.5112457275390625, -139.2451171875),
|
||||
osg::Vec3f(68.6584625244140625, 28.9297885894775390625, -141.2027740478515625),
|
||||
osg::Vec3f(78.4668121337890625, 2.3483295440673828125, -143.1604156494140625),
|
||||
osg::Vec3f(88.27516937255859375, -24.233127593994140625, -141.3894805908203125),
|
||||
osg::Vec3f(83.73651885986328125, -52.2005767822265625, -142.3761444091796875),
|
||||
osg::Vec3f(79.19786834716796875, -80.16802978515625, -143.114837646484375),
|
||||
osg::Vec3f(64.8477935791015625, -104.598602294921875, -137.840911865234375),
|
||||
osg::Vec3f(50.497714996337890625, -129.0291748046875, -131.45831298828125),
|
||||
osg::Vec3f(36.147632598876953125, -153.459747314453125, -121.42321014404296875),
|
||||
osg::Vec3f(21.7975559234619140625, -177.8903350830078125, -111.38809967041015625),
|
||||
osg::Vec3f(7.44747829437255859375, -202.3209075927734375, -101.1938323974609375),
|
||||
osg::Vec3f(0, -215, -94.753631591796875),
|
||||
})) << mPath;
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, update_remove_and_update_then_find_path_should_return_path)
|
||||
{
|
||||
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 shape(5, 5, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
shape.setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->removeObject(ObjectId(&shape));
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait();
|
||||
|
||||
mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,312 @@
|
||||
#include "operators.hpp"
|
||||
|
||||
#include <components/detournavigator/navmeshtilescache.hpp>
|
||||
#include <components/detournavigator/exceptions.hpp>
|
||||
#include <components/detournavigator/recastmesh.hpp>
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
static inline bool operator ==(const NavMeshDataRef& lhs, const NavMeshDataRef& rhs)
|
||||
{
|
||||
return std::make_pair(lhs.mValue, lhs.mSize) == std::make_pair(rhs.mValue, rhs.mSize);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
using namespace DetourNavigator;
|
||||
|
||||
struct DetourNavigatorNavMeshTilesCacheTest : Test
|
||||
{
|
||||
const osg::Vec3f mAgentHalfExtents {1, 2, 3};
|
||||
const TilePosition mTilePosition {0, 0};
|
||||
const std::vector<int> mIndices {{0, 1, 2}};
|
||||
const std::vector<float> mVertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}};
|
||||
const std::vector<AreaType> mAreaTypes {1, AreaType_ground};
|
||||
const std::vector<RecastMesh::Water> mWater {};
|
||||
const std::size_t mTrianglesPerChunk {1};
|
||||
const RecastMesh mRecastMesh {mIndices, mVertices, mAreaTypes, mWater, mTrianglesPerChunk};
|
||||
const std::vector<OffMeshConnection> mOffMeshConnections {};
|
||||
unsigned char* const mData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mNavMeshData {mData, 1};
|
||||
};
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_empty_cache_should_return_empty_value)
|
||||
{
|
||||
const std::size_t maxSize = 0;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_for_not_enought_cache_size_should_return_empty_value)
|
||||
{
|
||||
const std::size_t maxSize = 0;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections,
|
||||
std::move(mNavMeshData)));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_return_cached_value)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections,
|
||||
std::move(mNavMeshData));
|
||||
EXPECT_EQ(result.get(), (NavMeshDataRef {mData, 1}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_existing_element_should_throw_exception)
|
||||
{
|
||||
const std::size_t maxSize = 2;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
EXPECT_THROW(
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(anotherNavMeshData)),
|
||||
InvalidArgument
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_should_return_cached_value)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
const auto result = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections);
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_EQ(result.get(), (NavMeshDataRef {mData, 1}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_agent_half_extents_should_return_empty_value)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const osg::Vec3f unexsistentAgentHalfExtents {1, 1, 1};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
EXPECT_FALSE(cache.get(unexsistentAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_tile_position_should_return_empty_value)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const TilePosition unexistentTilePosition {1, 1};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, unexistentTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_recast_mesh_should_return_empty_value)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh unexistentRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_value)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, mOffMeshConnections,
|
||||
std::move(anotherNavMeshData));
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_EQ(result.get(), (NavMeshDataRef {anotherData, 1}));
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_used_value)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections,
|
||||
std::move(mNavMeshData));
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, mOffMeshConnections,
|
||||
std::move(anotherNavMeshData)));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_set_value)
|
||||
{
|
||||
const std::size_t maxSize = 2;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh leastRecentlySetRecastMesh {mIndices, mVertices, mAreaTypes, leastRecentlySetWater,
|
||||
mTrianglesPerChunk};
|
||||
const auto leastRecentlySetData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData leastRecentlySetNavMeshData {leastRecentlySetData, 1};
|
||||
|
||||
const std::vector<RecastMesh::Water> mostRecentlySetWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||
const RecastMesh mostRecentlySetRecastMesh {mIndices, mVertices, mAreaTypes, mostRecentlySetWater,
|
||||
mTrianglesPerChunk};
|
||||
const auto mostRecentlySetData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mostRecentlySetNavMeshData {mostRecentlySetData, 1};
|
||||
|
||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh, mOffMeshConnections,
|
||||
std::move(leastRecentlySetNavMeshData)));
|
||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh, mOffMeshConnections,
|
||||
std::move(mostRecentlySetNavMeshData)));
|
||||
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections,
|
||||
std::move(mNavMeshData));
|
||||
EXPECT_EQ(result.get(), (NavMeshDataRef {mData, 1}));
|
||||
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh, mOffMeshConnections));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_used_value)
|
||||
{
|
||||
const std::size_t maxSize = 2;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh leastRecentlyUsedRecastMesh {mIndices, mVertices, mAreaTypes, leastRecentlyUsedWater,
|
||||
mTrianglesPerChunk};
|
||||
const auto leastRecentlyUsedData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData leastRecentlyUsedNavMeshData {leastRecentlyUsedData, 1};
|
||||
|
||||
const std::vector<RecastMesh::Water> mostRecentlyUsedWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||
const RecastMesh mostRecentlyUsedRecastMesh {mIndices, mVertices, mAreaTypes, mostRecentlyUsedWater,
|
||||
mTrianglesPerChunk};
|
||||
const auto mostRecentlyUsedData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData mostRecentlyUsedNavMeshData {mostRecentlyUsedData, 1};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh, mOffMeshConnections,
|
||||
std::move(leastRecentlyUsedNavMeshData));
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh, mOffMeshConnections,
|
||||
std::move(mostRecentlyUsedNavMeshData));
|
||||
|
||||
{
|
||||
const auto value = cache.get(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh, mOffMeshConnections);
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_EQ(value.get(), (NavMeshDataRef {leastRecentlyUsedData, 1}));
|
||||
}
|
||||
|
||||
{
|
||||
const auto value = cache.get(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh, mOffMeshConnections);
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_EQ(value.get(), (NavMeshDataRef {mostRecentlyUsedData, 1}));
|
||||
}
|
||||
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections,
|
||||
std::move(mNavMeshData));
|
||||
EXPECT_EQ(result.get(), (NavMeshDataRef {mData, 1}));
|
||||
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh, mOffMeshConnections));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_cache_max_size)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh tooLargeRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto tooLargeData = reinterpret_cast<unsigned char*>(dtAlloc(2, DT_ALLOC_PERM));
|
||||
NavMeshData tooLargeNavMeshData {tooLargeData, 2};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh, mOffMeshConnections,
|
||||
std::move(tooLargeNavMeshData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_size_of_unused_items)
|
||||
{
|
||||
const std::size_t maxSize = 2;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, anotherWater, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
const std::vector<RecastMesh::Water> tooLargeWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||
const RecastMesh tooLargeRecastMesh {mIndices, mVertices, mAreaTypes, tooLargeWater, mTrianglesPerChunk};
|
||||
const auto tooLargeData = reinterpret_cast<unsigned char*>(dtAlloc(2, DT_ALLOC_PERM));
|
||||
NavMeshData tooLargeNavMeshData {tooLargeData, 2};
|
||||
|
||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections,
|
||||
std::move(mNavMeshData));
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, mOffMeshConnections,
|
||||
std::move(anotherNavMeshData)));
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh, mOffMeshConnections,
|
||||
std::move(tooLargeNavMeshData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, anotherRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_used_after_set_then_used_by_get_item_should_left_this_item_available)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
const auto firstCopy = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
ASSERT_TRUE(firstCopy);
|
||||
{
|
||||
const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections);
|
||||
ASSERT_TRUE(secondCopy);
|
||||
}
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, mOffMeshConnections,
|
||||
std::move(anotherNavMeshData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_twice_used_item_should_left_this_item_available)
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||
const RecastMesh anotherRecastMesh {mIndices, mVertices, mAreaTypes, water, mTrianglesPerChunk};
|
||||
const auto anotherData = reinterpret_cast<unsigned char*>(dtAlloc(1, DT_ALLOC_PERM));
|
||||
NavMeshData anotherNavMeshData {anotherData, 1};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections, std::move(mNavMeshData));
|
||||
const auto firstCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections);
|
||||
ASSERT_TRUE(firstCopy);
|
||||
{
|
||||
const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections);
|
||||
ASSERT_TRUE(secondCopy);
|
||||
}
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, mOffMeshConnections,
|
||||
std::move(anotherNavMeshData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh, mOffMeshConnections));
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
#ifndef OPENMW_TEST_SUITE_DETOURNAVIGATOR_OPERATORS_H
|
||||
#define OPENMW_TEST_SUITE_DETOURNAVIGATOR_OPERATORS_H
|
||||
|
||||
#include <components/bullethelpers/operators.hpp>
|
||||
#include <components/detournavigator/debug.hpp>
|
||||
#include <components/osghelpers/operators.hpp>
|
||||
|
||||
#include <deque>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
static inline bool operator ==(const TileBounds& lhs, const TileBounds& rhs)
|
||||
{
|
||||
return lhs.mMin == rhs.mMin && lhs.mMax == rhs.mMax;
|
||||
}
|
||||
}
|
||||
|
||||
namespace testing
|
||||
{
|
||||
template <>
|
||||
inline testing::Message& Message::operator <<(const std::deque<osg::Vec3f>& value)
|
||||
{
|
||||
(*this) << "{\n";
|
||||
for (const auto& v : value)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << v;
|
||||
(*this) << stream.str() << ",\n";
|
||||
}
|
||||
return (*this) << "}";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,413 @@
|
||||
#include "operators.hpp"
|
||||
|
||||
#include <components/detournavigator/recastmeshbuilder.hpp>
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
#include <components/detournavigator/recastmesh.hpp>
|
||||
#include <components/detournavigator/exceptions.hpp>
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
static inline bool operator ==(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs)
|
||||
{
|
||||
return lhs.mCellSize == rhs.mCellSize && lhs.mTransform == rhs.mTransform;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
using namespace DetourNavigator;
|
||||
|
||||
struct DetourNavigatorRecastMeshBuilderTest : Test
|
||||
{
|
||||
Settings mSettings;
|
||||
TileBounds mBounds;
|
||||
|
||||
DetourNavigatorRecastMeshBuilderTest()
|
||||
{
|
||||
mSettings.mRecastScaleFactor = 1.0f;
|
||||
mSettings.mTrianglesPerChunk = 256;
|
||||
mBounds.mMin = osg::Vec2f(-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
|
||||
-std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon());
|
||||
mBounds.mMax = osg::Vec2f(std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon(),
|
||||
std::numeric_limits<float>::max() * std::numeric_limits<float>::epsilon());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, create_for_empty_should_return_empty)
|
||||
{
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>());
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>());
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>());
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_bhv_triangle_mesh_shape)
|
||||
{
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
-1, 0, -1,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_bhv_triangle_mesh_shape)
|
||||
{
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
2, 3, 0,
|
||||
0, 3, 4,
|
||||
0, 3, 0,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_terrian_shape)
|
||||
{
|
||||
const std::array<btScalar, 4> heightfieldData {{0, 0, 0, 0}};
|
||||
btHeightfieldTerrainShape shape(2, 2, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
-0.5, 0, -0.5,
|
||||
-0.5, 0, 0.5,
|
||||
0.5, 0, -0.5,
|
||||
0.5, 0, -0.5,
|
||||
-0.5, 0, 0.5,
|
||||
0.5, 0, 0.5,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles)
|
||||
{
|
||||
btBoxShape shape(btVector3(1, 1, 2));
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 2, 1,
|
||||
-1, 2, 1,
|
||||
1, 2, -1,
|
||||
-1, 2, -1,
|
||||
1, -2, 1,
|
||||
-1, -2, 1,
|
||||
1, -2, -1,
|
||||
-1, -2, -1,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
|
||||
0, 2, 3,
|
||||
3, 1, 0,
|
||||
0, 4, 6,
|
||||
6, 2, 0,
|
||||
0, 1, 5,
|
||||
5, 4, 0,
|
||||
7, 5, 1,
|
||||
1, 3, 7,
|
||||
7, 3, 2,
|
||||
2, 6, 7,
|
||||
7, 6, 4,
|
||||
4, 5, 7,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(12, AreaType_ground));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_compound_shape)
|
||||
{
|
||||
btTriangleMesh mesh1;
|
||||
mesh1.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape triangle1(&mesh1, true);
|
||||
btBoxShape box(btVector3(1, 1, 2));
|
||||
btTriangleMesh mesh2;
|
||||
mesh2.addTriangle(btVector3(1, 1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape triangle2(&mesh2, true);
|
||||
btCompoundShape shape;
|
||||
shape.addChildShape(btTransform::getIdentity(), &triangle1);
|
||||
shape.addChildShape(btTransform::getIdentity(), &box);
|
||||
shape.addChildShape(btTransform::getIdentity(), &triangle2);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform::getIdentity(),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
-1, 0, -1,
|
||||
1, 2, 1,
|
||||
-1, 2, 1,
|
||||
1, 2, -1,
|
||||
-1, 2, -1,
|
||||
1, -2, 1,
|
||||
-1, -2, 1,
|
||||
1, -2, -1,
|
||||
-1, -2, -1,
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
1, 0, 1,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
|
||||
0, 1, 2,
|
||||
3, 5, 6,
|
||||
6, 4, 3,
|
||||
3, 7, 9,
|
||||
9, 5, 3,
|
||||
3, 4, 8,
|
||||
8, 7, 3,
|
||||
10, 8, 4,
|
||||
4, 6, 10,
|
||||
10, 6, 5,
|
||||
5, 9, 10,
|
||||
10, 9, 7,
|
||||
7, 8, 10,
|
||||
11, 12, 13,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(14, AreaType_ground));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_compound_shape)
|
||||
{
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape triangle(&mesh, true);
|
||||
btCompoundShape shape;
|
||||
shape.addChildShape(btTransform::getIdentity(), &triangle);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
2, 3, 0,
|
||||
0, 3, 4,
|
||||
0, 3, 0,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_compound_shape_with_transformed_bhv_triangle_shape)
|
||||
{
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape triangle(&mesh, true);
|
||||
btCompoundShape shape;
|
||||
shape.addChildShape(btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
|
||||
&triangle);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
3, 12, 2,
|
||||
1, 12, 10,
|
||||
1, 12, 2,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, without_bounds_add_bhv_triangle_shape_should_not_filter_by_bounds)
|
||||
{
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform::getIdentity(),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
-1, 0, -1,
|
||||
-2, 0, -3,
|
||||
-3, 0, -2,
|
||||
-3, 0, -3,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(2, AreaType_ground));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_bhv_triangle_shape_should_filter_by_bounds)
|
||||
{
|
||||
mSettings.mRecastScaleFactor = 0.1f;
|
||||
mBounds.mMin = osg::Vec2f(-3, -3) * mSettings.mRecastScaleFactor;
|
||||
mBounds.mMax = osg::Vec2f(-2, -2) * mSettings.mRecastScaleFactor;
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform::getIdentity(),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
-0.2f, 0, -0.3f,
|
||||
-0.3f, 0, -0.2f,
|
||||
-0.3f, 0, -0.3f,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_x_bhv_triangle_shape_should_filter_by_bounds)
|
||||
{
|
||||
mBounds.mMin = osg::Vec2f(-5, -5);
|
||||
mBounds.mMax = osg::Vec2f(5, -2);
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(0, -1, -1), btVector3(0, -1, -1), btVector3(0, 1, -1));
|
||||
mesh.addTriangle(btVector3(0, -3, -3), btVector3(0, -3, -2), btVector3(0, -2, -3));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform(btQuaternion(btVector3(1, 0, 0),
|
||||
static_cast<btScalar>(-osg::PI_4))),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
0, -0.70710659027099609375, -3.535533905029296875,
|
||||
0, 0.707107067108154296875, -3.535533905029296875,
|
||||
0, 2.384185791015625e-07, -4.24264049530029296875,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_y_bhv_triangle_shape_should_filter_by_bounds)
|
||||
{
|
||||
mBounds.mMin = osg::Vec2f(-5, -5);
|
||||
mBounds.mMax = osg::Vec2f(-3, 5);
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, 0, -1), btVector3(-1, 0, 1), btVector3(1, 0, -1));
|
||||
mesh.addTriangle(btVector3(-3, 0, -3), btVector3(-3, 0, -2), btVector3(-2, 0, -3));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform(btQuaternion(btVector3(0, 1, 0),
|
||||
static_cast<btScalar>(osg::PI_4))),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
-3.535533905029296875, -0.70710659027099609375, 0,
|
||||
-3.535533905029296875, 0.707107067108154296875, 0,
|
||||
-4.24264049530029296875, 2.384185791015625e-07, 0,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_z_bhv_triangle_shape_should_filter_by_bounds)
|
||||
{
|
||||
mBounds.mMin = osg::Vec2f(-5, -5);
|
||||
mBounds.mMax = osg::Vec2f(-1, -1);
|
||||
btTriangleMesh mesh;
|
||||
mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
|
||||
btBvhTriangleMeshShape shape(&mesh, true);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape),
|
||||
btTransform(btQuaternion(btVector3(0, 0, 1),
|
||||
static_cast<btScalar>(osg::PI_4))),
|
||||
AreaType_ground
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
0.707107067108154296875, 0, -3.535533905029296875,
|
||||
-0.70710659027099609375, 0, -3.535533905029296875,
|
||||
2.384185791015625e-07, 0, -4.24264049530029296875,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, flags_values_should_be_corresponding_to_added_objects)
|
||||
{
|
||||
btTriangleMesh mesh1;
|
||||
mesh1.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0));
|
||||
btBvhTriangleMeshShape shape1(&mesh1, true);
|
||||
btTriangleMesh mesh2;
|
||||
mesh2.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0));
|
||||
btBvhTriangleMeshShape shape2(&mesh2, true);
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape1),
|
||||
btTransform::getIdentity(),
|
||||
AreaType_ground
|
||||
);
|
||||
builder.addObject(
|
||||
static_cast<const btCollisionShape&>(shape2),
|
||||
btTransform::getIdentity(),
|
||||
AreaType_null
|
||||
);
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||
1, 0, -1,
|
||||
-1, 0, 1,
|
||||
-1, 0, -1,
|
||||
-2, 0, -3,
|
||||
-3, 0, -2,
|
||||
-3, 0, -3,
|
||||
}));
|
||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_null}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it)
|
||||
{
|
||||
RecastMeshBuilder builder(mSettings, mBounds);
|
||||
builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300)));
|
||||
const auto recastMesh = builder.create();
|
||||
EXPECT_EQ(recastMesh->getWater(), std::vector<RecastMesh::Water>({
|
||||
RecastMesh::Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))}
|
||||
}));
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
#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, AreaType_ground);
|
||||
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, AreaType_ground);
|
||||
EXPECT_FALSE(object.update(mTransform, AreaType_ground));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshObjectTest, update_with_different_transform_should_return_true)
|
||||
{
|
||||
RecastMeshObject object(mBoxShape, mTransform, AreaType_ground);
|
||||
EXPECT_TRUE(object.update(btTransform::getIdentity(), AreaType_ground));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshObjectTest, update_with_different_flags_should_return_true)
|
||||
{
|
||||
RecastMeshObject object(mBoxShape, mTransform, AreaType_ground);
|
||||
EXPECT_TRUE(object.update(mTransform, AreaType_null));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_compound_shape_with_same_transform_and_not_changed_child_transform_should_return_false)
|
||||
{
|
||||
RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground);
|
||||
EXPECT_FALSE(object.update(mTransform, AreaType_ground));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_compound_shape_with_same_transform_and_changed_child_transform_should_return_true)
|
||||
{
|
||||
RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground);
|
||||
mCompoundShape.updateChildTransform(0, btTransform::getIdentity());
|
||||
EXPECT_TRUE(object.update(mTransform, AreaType_ground));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorRecastMeshObjectTest, repeated_update_for_compound_shape_without_changes_should_return_false)
|
||||
{
|
||||
RecastMeshObject object(mCompoundShape, mTransform, AreaType_ground);
|
||||
mCompoundShape.updateChildTransform(0, btTransform::getIdentity());
|
||||
object.update(mTransform, AreaType_ground);
|
||||
EXPECT_FALSE(object.update(mTransform, AreaType_ground));
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
#include "operators.hpp"
|
||||
|
||||
#include <components/detournavigator/settingsutils.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
using namespace DetourNavigator;
|
||||
|
||||
struct DetourNavigatorGetTilePositionTest : Test
|
||||
{
|
||||
Settings mSettings;
|
||||
|
||||
DetourNavigatorGetTilePositionTest()
|
||||
{
|
||||
mSettings.mCellSize = 0.5;
|
||||
mSettings.mTileSize = 64;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DetourNavigatorGetTilePositionTest, for_zero_coordinates_should_return_zero_tile_position)
|
||||
{
|
||||
EXPECT_EQ(getTilePosition(mSettings, osg::Vec3f(0, 0, 0)), TilePosition(0, 0));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilePositionTest, tile_size_should_be_multiplied_by_cell_size)
|
||||
{
|
||||
EXPECT_EQ(getTilePosition(mSettings, osg::Vec3f(32, 0, 0)), TilePosition(1, 0));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilePositionTest, tile_position_calculates_by_floor)
|
||||
{
|
||||
EXPECT_EQ(getTilePosition(mSettings, osg::Vec3f(31, 0, 0)), TilePosition(0, 0));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilePositionTest, tile_position_depends_on_x_and_z_coordinates)
|
||||
{
|
||||
EXPECT_EQ(getTilePosition(mSettings, osg::Vec3f(32, 64, 128)), TilePosition(1, 4));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorGetTilePositionTest, tile_position_works_for_negative_coordinates)
|
||||
{
|
||||
EXPECT_EQ(getTilePosition(mSettings, osg::Vec3f(-31, 0, -32)), TilePosition(-1, -1));
|
||||
}
|
||||
|
||||
struct DetourNavigatorMakeTileBoundsTest : Test
|
||||
{
|
||||
Settings mSettings;
|
||||
|
||||
DetourNavigatorMakeTileBoundsTest()
|
||||
{
|
||||
mSettings.mCellSize = 0.5;
|
||||
mSettings.mTileSize = 64;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DetourNavigatorMakeTileBoundsTest, tile_bounds_depend_on_tile_size_and_cell_size)
|
||||
{
|
||||
EXPECT_EQ(makeTileBounds(mSettings, TilePosition(0, 0)), (TileBounds {osg::Vec2f(0, 0), osg::Vec2f(32, 32)}));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorMakeTileBoundsTest, tile_bounds_are_multiplied_by_tile_position)
|
||||
{
|
||||
EXPECT_EQ(makeTileBounds(mSettings, TilePosition(1, 2)), (TileBounds {osg::Vec2f(32, 64), osg::Vec2f(64, 96)}));
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
find_path(RecastNavigation_INCLUDE_DIR
|
||||
NAMES Recast.h
|
||||
HINTS $ENV{RecastNavigation_ROOT}
|
||||
${RecastNavigation_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
mark_as_advanced(RecastNavigation_INCLUDE_DIR)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
set(RecastNavigation_LIBRARIES "")
|
||||
|
||||
foreach(COMPONENT ${RecastNavigation_FIND_COMPONENTS})
|
||||
if(NOT RecastNavigation_${COMPONENT}_FOUND)
|
||||
find_library(RecastNavigation_${COMPONENT}_LIBRARY
|
||||
HINTS $ENV{RecastNavigation_ROOT}
|
||||
${RecastNavigation_ROOT}
|
||||
NAMES ${COMPONENT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
find_package_handle_standard_args(RecastNavigation_${COMPONENT} DEFAULT_MSG
|
||||
RecastNavigation_${COMPONENT}_LIBRARY
|
||||
RecastNavigation_INCLUDE_DIR
|
||||
)
|
||||
mark_as_advanced(RecastNavigation_${COMPONENT}_LIBRARY)
|
||||
if(RecastNavigation_${COMPONENT}_FOUND)
|
||||
list(APPEND RecastNavigation_LIBRARIES ${RecastNavigation_${COMPONENT}_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
mark_as_advanced(RecastNavigation_LIBRARIES)
|
||||
|
||||
find_package_handle_standard_args(RecastNavigation DEFAULT_MSG
|
||||
RecastNavigation_LIBRARIES
|
||||
RecastNavigation_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(RecastNavigation_FOUND)
|
||||
set(RecastNavigation_INCLUDE_DIRS ${RecastNavigation_INCLUDE_DIR})
|
||||
endif()
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue