mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:53:50 +00:00
Create collision shape for all avoided nodes
This commit is contained in:
parent
e24d4d7052
commit
f6a60790f8
5 changed files with 70 additions and 55 deletions
|
@ -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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data)
|
||||||
|
{
|
||||||
|
fillTriangleMeshWithTransform(mesh, data, osg::Matrixf());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NifBullet
|
namespace NifBullet
|
||||||
{
|
{
|
||||||
|
|
||||||
BulletNifLoader::BulletNifLoader()
|
|
||||||
: mCompoundShape()
|
|
||||||
, mStaticMesh()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BulletNifLoader::~BulletNifLoader()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ©, const osg::CopyOp ©op)
|
BulletShape::BulletShape(const BulletShape ©, const osg::CopyOp ©op)
|
||||||
: 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 ©, const osg::CopyOp ©op)
|
||||||
|
|
||||||
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…
Reference in a new issue