diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index a2311be490..ceb035db8b 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -142,6 +142,7 @@ namespace Resource static bool operator ==(const Resource::BulletShape& lhs, const Resource::BulletShape& rhs) { return compareObjects(lhs.mCollisionShape, rhs.mCollisionShape) + && compareObjects(lhs.mAvoidCollisionShape, rhs.mAvoidCollisionShape) && lhs.mCollisionBoxHalfExtents == rhs.mCollisionBoxHalfExtents && lhs.mCollisionBoxTranslate == rhs.mCollisionBoxTranslate && lhs.mAnimatedShapes == rhs.mAnimatedShapes; @@ -151,6 +152,7 @@ namespace Resource { return stream << "Resource::BulletShape {" << value.mCollisionShape << ", " + << value.mAvoidCollisionShape << ", " << value.mCollisionBoxHalfExtents << ", " << value.mAnimatedShapes << "}"; @@ -837,7 +839,10 @@ namespace EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); const auto result = mLoader.load(mNifFile); + std::unique_ptr triangles(new btTriangleMesh(false)); + triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); Resource::BulletShape expected; + expected.mAvoidCollisionShape = new Resource::TriangleMeshShape(triangles.release(), false); EXPECT_EQ(*result, expected); } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 0554db08fc..991e9fff5e 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include @@ -42,27 +41,41 @@ bool pathFileNameStartsWithX(const std::string& path) 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(data.vertices.size())); + mesh.preallocateIndices(static_cast(data.triangles.size())); + + const std::vector &vertices = data.vertices; + const std::vector &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 BulletNifLoader::load(const Nif::File& nif) { mShape = new Resource::BulletShape; - mCompoundShape = nullptr; - mStaticMesh = nullptr; + mCompoundShape.reset(); + mStaticMesh.reset(); + mAvoidStaticMesh.reset(); if (nif.numRoots() < 1) { @@ -125,6 +138,9 @@ osg::ref_ptr BulletNifLoader::load(const Nif::File& nif) mStaticMesh.release(); } + if (mAvoidStaticMesh) + mShape->mAvoidCollisionShape = new Resource::TriangleMeshShape(mAvoidStaticMesh.release(), false); + 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, - 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 // 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."; // Don't collide with AvoidNode shapes - if(node->recType == Nif::RC_AvoidNode) - flags |= 0x800; + avoid = avoid || (node->recType == Nif::RC_AvoidNode); // Check for extra data 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) if(!node->hasBounds && node->recType == Nif::RC_NiTriShape) { - handleNiTriShape(static_cast(node), flags, getWorldTransform(node), isAnimated); + handleNiTriShape(static_cast(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++) { 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); @@ -285,21 +301,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, std::unique_ptr childMesh(new btTriangleMesh); - const Nif::NiTriShapeData *data = shape->data.getPtr(); - - childMesh->preallocateVertices(data->vertices.size()); - childMesh->preallocateIndices(data->triangles.size()); - - const std::vector &vertices = data->vertices; - const std::vector &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)); - } + fillTriangleMesh(*childMesh, shape->data.get()); std::unique_ptr childShape(new Resource::TriangleMeshShape(childMesh.get(), true)); childMesh.release(); @@ -322,27 +324,20 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, mCompoundShape->addChildShape(trans, childShape.get()); childShape.release(); } + else if (avoid) + { + if (!mAvoidStaticMesh) + mAvoidStaticMesh.reset(new btTriangleMesh(false)); + + fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform); + } else { if (!mStaticMesh) mStaticMesh.reset(new btTriangleMesh(false)); // Static shape, just transform all vertices into position - const Nif::NiTriShapeData *data = shape->data.getPtr(); - const std::vector &vertices = data->vertices; - const std::vector &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)); - } + fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform); } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 26b5b329de..8d55e0ba0b 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include #include @@ -35,10 +37,6 @@ namespace NifBullet class BulletNifLoader { public: - BulletNifLoader(); - - virtual ~BulletNifLoader(); - void warn(const std::string &msg) { Log(Debug::Warning) << "NIFLoader: Warn:" << msg; @@ -55,16 +53,19 @@ public: private: 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); - 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 mCompoundShape; std::unique_ptr mStaticMesh; + std::unique_ptr mAvoidStaticMesh; + osg::ref_ptr mShape; }; diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index 15a747dd3a..645a5dd3b9 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -13,12 +13,14 @@ namespace Resource BulletShape::BulletShape() : mCollisionShape(nullptr) + , mAvoidCollisionShape(nullptr) { } BulletShape::BulletShape(const BulletShape ©, const osg::CopyOp ©op) : mCollisionShape(duplicateCollisionShape(copy.mCollisionShape)) + , mAvoidCollisionShape(duplicateCollisionShape(copy.mAvoidCollisionShape)) , mCollisionBoxHalfExtents(copy.mCollisionBoxHalfExtents) , mCollisionBoxTranslate(copy.mCollisionBoxTranslate) , mAnimatedShapes(copy.mAnimatedShapes) @@ -27,6 +29,7 @@ BulletShape::BulletShape(const BulletShape ©, const osg::CopyOp ©op) BulletShape::~BulletShape() { + deleteShape(mAvoidCollisionShape); deleteShape(mCollisionShape); } @@ -82,6 +85,11 @@ btCollisionShape *BulletShape::getCollisionShape() return mCollisionShape; } +btCollisionShape *BulletShape::getAvoidCollisionShape() +{ + return mAvoidCollisionShape; +} + osg::ref_ptr BulletShape::makeInstance() const { osg::ref_ptr instance (new BulletShapeInstance(this)); @@ -99,6 +107,9 @@ BulletShapeInstance::BulletShapeInstance(osg::ref_ptr source) if (source->mCollisionShape) mCollisionShape = duplicateCollisionShape(source->mCollisionShape); + + if (source->mAvoidCollisionShape) + mAvoidCollisionShape = duplicateCollisionShape(source->mAvoidCollisionShape); } } diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp index a418bb28ce..f2f45cac91 100644 --- a/components/resource/bulletshape.hpp +++ b/components/resource/bulletshape.hpp @@ -25,6 +25,7 @@ namespace Resource META_Object(Resource, BulletShape) btCollisionShape* mCollisionShape; + btCollisionShape* mAvoidCollisionShape; // 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. @@ -44,6 +45,8 @@ namespace Resource btCollisionShape* getCollisionShape(); + btCollisionShape* getAvoidCollisionShape(); + private: void deleteShape(btCollisionShape* shape);