Create collision shape for all avoided nodes

pull/1633/head
elsid 7 years ago
parent e24d4d7052
commit f6a60790f8
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -142,6 +142,7 @@ namespace Resource
static bool operator ==(const Resource::BulletShape& lhs, const Resource::BulletShape& rhs) static bool operator ==(const Resource::BulletShape& lhs, const Resource::BulletShape& rhs)
{ {
return compareObjects(lhs.mCollisionShape, rhs.mCollisionShape) return compareObjects(lhs.mCollisionShape, rhs.mCollisionShape)
&& compareObjects(lhs.mAvoidCollisionShape, rhs.mAvoidCollisionShape)
&& lhs.mCollisionBoxHalfExtents == rhs.mCollisionBoxHalfExtents && lhs.mCollisionBoxHalfExtents == rhs.mCollisionBoxHalfExtents
&& lhs.mCollisionBoxTranslate == rhs.mCollisionBoxTranslate && lhs.mCollisionBoxTranslate == rhs.mCollisionBoxTranslate
&& lhs.mAnimatedShapes == rhs.mAnimatedShapes; && lhs.mAnimatedShapes == rhs.mAnimatedShapes;
@ -151,6 +152,7 @@ namespace Resource
{ {
return stream << "Resource::BulletShape {" return stream << "Resource::BulletShape {"
<< value.mCollisionShape << ", " << value.mCollisionShape << ", "
<< value.mAvoidCollisionShape << ", "
<< value.mCollisionBoxHalfExtents << ", " << value.mCollisionBoxHalfExtents << ", "
<< value.mAnimatedShapes << value.mAnimatedShapes
<< "}"; << "}";
@ -837,7 +839,10 @@ namespace
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
const auto result = mLoader.load(mNifFile); const auto result = mLoader.load(mNifFile);
std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
Resource::BulletShape expected; Resource::BulletShape expected;
expected.mAvoidCollisionShape = new Resource::TriangleMeshShape(triangles.release(), false);
EXPECT_EQ(*result, expected); EXPECT_EQ(*result, expected);
} }

@ -8,7 +8,6 @@
#include <BulletCollision/CollisionShapes/btBoxShape.h> #include <BulletCollision/CollisionShapes/btBoxShape.h>
#include <BulletCollision/CollisionShapes/btTriangleMesh.h> #include <BulletCollision/CollisionShapes/btTriangleMesh.h>
#include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h> #include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
@ -42,27 +41,41 @@ bool pathFileNameStartsWithX(const std::string& path)
return letterPos < path.size() && (path[letterPos] == 'x' || path[letterPos] == 'X'); return letterPos < path.size() && (path[letterPos] == 'x' || path[letterPos] == 'X');
} }
void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriShapeData& data, const osg::Matrixf &transform)
{
mesh.preallocateVertices(static_cast<int>(data.vertices.size()));
mesh.preallocateIndices(static_cast<int>(data.triangles.size()));
const std::vector<osg::Vec3f> &vertices = data.vertices;
const std::vector<unsigned short> &triangles = data.triangles;
for (std::size_t i = 0; i < triangles.size(); i += 3)
{
mesh.addTriangle(
getbtVector(vertices[triangles[i + 0]] * transform),
getbtVector(vertices[triangles[i + 1]] * transform),
getbtVector(vertices[triangles[i + 2]] * transform)
);
}
} }
namespace NifBullet void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data)
{ {
fillTriangleMeshWithTransform(mesh, data, osg::Matrixf());
}
BulletNifLoader::BulletNifLoader()
: mCompoundShape()
, mStaticMesh()
{
} }
BulletNifLoader::~BulletNifLoader() namespace NifBullet
{ {
}
osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif) osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif)
{ {
mShape = new Resource::BulletShape; mShape = new Resource::BulletShape;
mCompoundShape = nullptr; mCompoundShape.reset();
mStaticMesh = nullptr; mStaticMesh.reset();
mAvoidStaticMesh.reset();
if (nif.numRoots() < 1) if (nif.numRoots() < 1)
{ {
@ -125,6 +138,9 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif)
mStaticMesh.release(); mStaticMesh.release();
} }
if (mAvoidStaticMesh)
mShape->mAvoidCollisionShape = new Resource::TriangleMeshShape(mAvoidStaticMesh.release(), false);
return mShape; return mShape;
} }
} }
@ -189,7 +205,7 @@ const Nif::Node* BulletNifLoader::getCollisionNode(const Nif::Node* rootNode)
} }
void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *node, int flags, void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *node, int flags,
bool isCollisionNode, bool isAnimated, bool autogenerated) bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid)
{ {
// Accumulate the flags from all the child nodes. This works for all // Accumulate the flags from all the child nodes. This works for all
// the flags we currently use, at least. // the flags we currently use, at least.
@ -205,8 +221,7 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n
Log(Debug::Info) << "Found RootCollisionNode attached to non-root node in " << fileName << ". Treat it as a common NiTriShape."; Log(Debug::Info) << "Found RootCollisionNode attached to non-root node in " << fileName << ". Treat it as a common NiTriShape.";
// Don't collide with AvoidNode shapes // Don't collide with AvoidNode shapes
if(node->recType == Nif::RC_AvoidNode) avoid = avoid || (node->recType == Nif::RC_AvoidNode);
flags |= 0x800;
// Check for extra data // Check for extra data
Nif::Extra const *e = node; Nif::Extra const *e = node;
@ -242,7 +257,7 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n
// (occurs in tr_ex_imp_wall_arch_04.nif) // (occurs in tr_ex_imp_wall_arch_04.nif)
if(!node->hasBounds && node->recType == Nif::RC_NiTriShape) if(!node->hasBounds && node->recType == Nif::RC_NiTriShape)
{ {
handleNiTriShape(static_cast<const Nif::NiTriShape*>(node), flags, getWorldTransform(node), isAnimated); handleNiTriShape(static_cast<const Nif::NiTriShape*>(node), flags, getWorldTransform(node), isAnimated, avoid);
} }
} }
@ -254,12 +269,13 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n
for(size_t i = 0;i < list.length();i++) for(size_t i = 0;i < list.length();i++)
{ {
if(!list[i].empty()) if(!list[i].empty())
handleNode(fileName, list[i].getPtr(), flags, isCollisionNode, isAnimated, autogenerated); handleNode(fileName, list[i].getPtr(), flags, isCollisionNode, isAnimated, autogenerated, avoid);
} }
} }
} }
void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, bool isAnimated) void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform,
bool isAnimated, bool avoid)
{ {
assert(shape != nullptr); assert(shape != nullptr);
@ -285,21 +301,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
std::unique_ptr<btTriangleMesh> childMesh(new btTriangleMesh); std::unique_ptr<btTriangleMesh> childMesh(new btTriangleMesh);
const Nif::NiTriShapeData *data = shape->data.getPtr(); fillTriangleMesh(*childMesh, shape->data.get());
childMesh->preallocateVertices(data->vertices.size());
childMesh->preallocateIndices(data->triangles.size());
const std::vector<osg::Vec3f> &vertices = data->vertices;
const std::vector<unsigned short> &triangles = data->triangles;
for(size_t i = 0;i < data->triangles.size();i+=3)
{
osg::Vec3f b1 = vertices[triangles[i+0]];
osg::Vec3f b2 = vertices[triangles[i+1]];
osg::Vec3f b3 = vertices[triangles[i+2]];
childMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3));
}
std::unique_ptr<Resource::TriangleMeshShape> childShape(new Resource::TriangleMeshShape(childMesh.get(), true)); std::unique_ptr<Resource::TriangleMeshShape> childShape(new Resource::TriangleMeshShape(childMesh.get(), true));
childMesh.release(); childMesh.release();
@ -322,27 +324,20 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
mCompoundShape->addChildShape(trans, childShape.get()); mCompoundShape->addChildShape(trans, childShape.get());
childShape.release(); childShape.release();
} }
else if (avoid)
{
if (!mAvoidStaticMesh)
mAvoidStaticMesh.reset(new btTriangleMesh(false));
fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform);
}
else else
{ {
if (!mStaticMesh) if (!mStaticMesh)
mStaticMesh.reset(new btTriangleMesh(false)); mStaticMesh.reset(new btTriangleMesh(false));
// Static shape, just transform all vertices into position // Static shape, just transform all vertices into position
const Nif::NiTriShapeData *data = shape->data.getPtr(); fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform);
const std::vector<osg::Vec3f> &vertices = data->vertices;
const std::vector<unsigned short> &triangles = data->triangles;
mStaticMesh->preallocateVertices(data->vertices.size());
mStaticMesh->preallocateIndices(data->triangles.size());
size_t numtris = data->triangles.size();
for(size_t i = 0;i < numtris;i+=3)
{
osg::Vec3f b1 = vertices[triangles[i+0]]*transform;
osg::Vec3f b2 = vertices[triangles[i+1]]*transform;
osg::Vec3f b3 = vertices[triangles[i+2]]*transform;
mStaticMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3));
}
} }
} }

@ -11,6 +11,8 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Referenced> #include <osg/Referenced>
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/nif/niffile.hpp> #include <components/nif/niffile.hpp>
#include <components/resource/bulletshape.hpp> #include <components/resource/bulletshape.hpp>
@ -35,10 +37,6 @@ namespace NifBullet
class BulletNifLoader class BulletNifLoader
{ {
public: public:
BulletNifLoader();
virtual ~BulletNifLoader();
void warn(const std::string &msg) void warn(const std::string &msg)
{ {
Log(Debug::Warning) << "NIFLoader: Warn:" << msg; Log(Debug::Warning) << "NIFLoader: Warn:" << msg;
@ -55,16 +53,19 @@ public:
private: private:
bool findBoundingBox(const Nif::Node* node); bool findBoundingBox(const Nif::Node* node);
void handleNode(const std::string& fileName, Nif::Node const *node, int flags, bool isCollisionNode, bool isAnimated=false, bool autogenerated=false); void handleNode(const std::string& fileName, Nif::Node const *node, int flags, bool isCollisionNode,
bool isAnimated=false, bool autogenerated=false, bool avoid=false);
const Nif::Node* getCollisionNode(const Nif::Node* rootNode); const Nif::Node* getCollisionNode(const Nif::Node* rootNode);
void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated); void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated, bool avoid);
std::unique_ptr<btCompoundShape> mCompoundShape; std::unique_ptr<btCompoundShape> mCompoundShape;
std::unique_ptr<btTriangleMesh> mStaticMesh; std::unique_ptr<btTriangleMesh> mStaticMesh;
std::unique_ptr<btTriangleMesh> mAvoidStaticMesh;
osg::ref_ptr<Resource::BulletShape> mShape; osg::ref_ptr<Resource::BulletShape> mShape;
}; };

@ -13,12 +13,14 @@ namespace Resource
BulletShape::BulletShape() BulletShape::BulletShape()
: mCollisionShape(nullptr) : mCollisionShape(nullptr)
, mAvoidCollisionShape(nullptr)
{ {
} }
BulletShape::BulletShape(const BulletShape &copy, const osg::CopyOp &copyop) BulletShape::BulletShape(const BulletShape &copy, const osg::CopyOp &copyop)
: mCollisionShape(duplicateCollisionShape(copy.mCollisionShape)) : mCollisionShape(duplicateCollisionShape(copy.mCollisionShape))
, mAvoidCollisionShape(duplicateCollisionShape(copy.mAvoidCollisionShape))
, mCollisionBoxHalfExtents(copy.mCollisionBoxHalfExtents) , mCollisionBoxHalfExtents(copy.mCollisionBoxHalfExtents)
, mCollisionBoxTranslate(copy.mCollisionBoxTranslate) , mCollisionBoxTranslate(copy.mCollisionBoxTranslate)
, mAnimatedShapes(copy.mAnimatedShapes) , mAnimatedShapes(copy.mAnimatedShapes)
@ -27,6 +29,7 @@ BulletShape::BulletShape(const BulletShape &copy, const osg::CopyOp &copyop)
BulletShape::~BulletShape() BulletShape::~BulletShape()
{ {
deleteShape(mAvoidCollisionShape);
deleteShape(mCollisionShape); deleteShape(mCollisionShape);
} }
@ -82,6 +85,11 @@ btCollisionShape *BulletShape::getCollisionShape()
return mCollisionShape; return mCollisionShape;
} }
btCollisionShape *BulletShape::getAvoidCollisionShape()
{
return mAvoidCollisionShape;
}
osg::ref_ptr<BulletShapeInstance> BulletShape::makeInstance() const osg::ref_ptr<BulletShapeInstance> BulletShape::makeInstance() const
{ {
osg::ref_ptr<BulletShapeInstance> instance (new BulletShapeInstance(this)); osg::ref_ptr<BulletShapeInstance> instance (new BulletShapeInstance(this));
@ -99,6 +107,9 @@ BulletShapeInstance::BulletShapeInstance(osg::ref_ptr<const BulletShape> source)
if (source->mCollisionShape) if (source->mCollisionShape)
mCollisionShape = duplicateCollisionShape(source->mCollisionShape); mCollisionShape = duplicateCollisionShape(source->mCollisionShape);
if (source->mAvoidCollisionShape)
mAvoidCollisionShape = duplicateCollisionShape(source->mAvoidCollisionShape);
} }
} }

@ -25,6 +25,7 @@ namespace Resource
META_Object(Resource, BulletShape) META_Object(Resource, BulletShape)
btCollisionShape* mCollisionShape; btCollisionShape* mCollisionShape;
btCollisionShape* mAvoidCollisionShape;
// Used for actors. Note, ideally actors would use a separate loader - as it is // Used for actors. Note, ideally actors would use a separate loader - as it is
// we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used. // we have to keep a redundant copy of the actor model around in mCollisionShape, which isn't used.
@ -44,6 +45,8 @@ namespace Resource
btCollisionShape* getCollisionShape(); btCollisionShape* getCollisionShape();
btCollisionShape* getAvoidCollisionShape();
private: private:
void deleteShape(btCollisionShape* shape); void deleteShape(btCollisionShape* shape);

Loading…
Cancel
Save