mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-20 15:40:32 +00:00
Treat empty RootCollisionNode
in NIF as NCC flag and generate CameraOnly collision shape
This commit is contained in:
parent
f1fd0d2e4a
commit
8b8c304953
@ -187,6 +187,7 @@ namespace Resource
|
||||
return compareObjects(lhs.mCollisionShape.get(), rhs.mCollisionShape.get())
|
||||
&& compareObjects(lhs.mAvoidCollisionShape.get(), rhs.mAvoidCollisionShape.get())
|
||||
&& lhs.mCollisionBox == rhs.mCollisionBox
|
||||
&& lhs.mCollisionType == rhs.mCollisionType
|
||||
&& lhs.mAnimatedShapes == rhs.mAnimatedShapes;
|
||||
}
|
||||
|
||||
@ -197,6 +198,7 @@ namespace Resource
|
||||
<< value.mAvoidCollisionShape.get() << ", "
|
||||
<< value.mCollisionBox << ", "
|
||||
<< value.mAnimatedShapes
|
||||
<< ", collisionType=" << value.mCollisionType
|
||||
<< "}";
|
||||
}
|
||||
}
|
||||
@ -1034,7 +1036,7 @@ namespace
|
||||
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_not_first_extra_data_string_equal_ncc_should_return_shape_with_cameraonly_collision)
|
||||
{
|
||||
mNiStringExtraData.next = Nif::ExtraPtr(&mNiStringExtraData2);
|
||||
mNiStringExtraData2.string = "NC___";
|
||||
mNiStringExtraData2.string = "NCC__";
|
||||
mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
|
||||
mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
|
||||
mNiTriShape.parents.push_back(&mNiNode);
|
||||
@ -1054,7 +1056,6 @@ namespace
|
||||
EXPECT_EQ(*result, expected);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_starting_with_nc_should_return_shape_with_nocollision)
|
||||
{
|
||||
mNiStringExtraData.string = "NC___";
|
||||
@ -1100,6 +1101,36 @@ namespace
|
||||
EXPECT_EQ(*result, expected);
|
||||
}
|
||||
|
||||
TEST_F(TestBulletNifLoader, for_empty_root_collision_node_without_nc_should_return_shape_with_cameraonly_collision)
|
||||
{
|
||||
Nif::NiTriShape niTriShape;
|
||||
Nif::NiNode emptyCollisionNode;
|
||||
init(niTriShape);
|
||||
init(emptyCollisionNode);
|
||||
|
||||
niTriShape.data = Nif::NiGeometryDataPtr(&mNiTriShapeData);
|
||||
niTriShape.parents.push_back(&mNiNode);
|
||||
|
||||
emptyCollisionNode.recType = Nif::RC_RootCollisionNode;
|
||||
emptyCollisionNode.parents.push_back(&mNiNode);
|
||||
|
||||
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>(
|
||||
{Nif::NodePtr(&niTriShape), Nif::NodePtr(&emptyCollisionNode)}));
|
||||
|
||||
EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
|
||||
EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
|
||||
EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
|
||||
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;
|
||||
expected.mCollisionShape.reset(new Resource::TriangleMeshShape(triangles.release(), true));
|
||||
expected.mCollisionType = Resource::BulletShape::CollisionType::Camera;
|
||||
|
||||
EXPECT_EQ(*result, expected);
|
||||
}
|
||||
|
||||
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_mrk_should_return_shape_with_null_collision_shape)
|
||||
{
|
||||
mNiStringExtraData.string = "MRK";
|
||||
|
@ -220,8 +220,12 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif)
|
||||
// from the collision data present in every root node.
|
||||
for (const Nif::Node* node : roots)
|
||||
{
|
||||
bool autogenerated = hasAutoGeneratedCollision(*node);
|
||||
handleNode(filename, *node, nullptr, 0, autogenerated, isAnimated, autogenerated, false, mShape->mCollisionType);
|
||||
bool hasCollisionNode = hasRootCollisionNode(*node);
|
||||
bool hasCollisionShape = hasCollisionNode && !collisionShapeIsEmpty(*node);
|
||||
if (hasCollisionNode && !hasCollisionShape)
|
||||
mShape->mCollisionType = Resource::BulletShape::CollisionType::Camera;
|
||||
bool generateCollisionShape = !hasCollisionShape;
|
||||
handleNode(filename, *node, nullptr, 0, generateCollisionShape, isAnimated, generateCollisionShape, false, mShape->mCollisionType);
|
||||
}
|
||||
|
||||
if (mCompoundShape)
|
||||
@ -295,18 +299,37 @@ bool BulletNifLoader::findBoundingBox(const Nif::Node& node, const std::string&
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BulletNifLoader::hasAutoGeneratedCollision(const Nif::Node& rootNode)
|
||||
bool BulletNifLoader::hasRootCollisionNode(const Nif::Node& rootNode) const
|
||||
{
|
||||
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&rootNode))
|
||||
{
|
||||
const Nif::NodeList &list = ninode->children;
|
||||
for(size_t i = 0;i < list.length();i++)
|
||||
{
|
||||
if(!list[i].empty())
|
||||
{
|
||||
if(list[i].getPtr()->recType == Nif::RC_RootCollisionNode)
|
||||
return false;
|
||||
}
|
||||
if(list[i].empty())
|
||||
continue;
|
||||
if (list[i].getPtr()->recType == Nif::RC_RootCollisionNode)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BulletNifLoader::collisionShapeIsEmpty(const Nif::Node& rootNode) const
|
||||
{
|
||||
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&rootNode))
|
||||
{
|
||||
const Nif::NodeList &list = ninode->children;
|
||||
for(size_t i = 0;i < list.length();i++)
|
||||
{
|
||||
if(list[i].empty())
|
||||
continue;
|
||||
const Nif::Node* childNode = list[i].getPtr();
|
||||
if (childNode->recType != Nif::RC_RootCollisionNode)
|
||||
continue;
|
||||
const Nif::NiNode* niChildnode = static_cast<const Nif::NiNode*>(childNode); // RootCollisionNode is always a NiNode
|
||||
if (childNode->hasBounds || niChildnode->children.length() > 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -319,6 +342,11 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node& n
|
||||
if (node.recType == Nif::RC_NiCollisionSwitch && !node.collisionActive())
|
||||
return;
|
||||
|
||||
// If RootCollisionNode is empty we treat it as NCC flag and autogenerate collision shape as there was no RootCollisionNode.
|
||||
// So ignoring it here if `autogenerated` is true and collisionType was set to `Camera`.
|
||||
if (node.recType == Nif::RC_RootCollisionNode && autogenerated && collisionType == Resource::BulletShape::CollisionType::Camera)
|
||||
return;
|
||||
|
||||
// Accumulate the flags from all the child nodes. This works for all
|
||||
// the flags we currently use, at least.
|
||||
flags |= node.flags;
|
||||
|
@ -59,7 +59,8 @@ private:
|
||||
void handleNode(const std::string& fileName, const Nif::Node& node,const Nif::Parent* parent, int flags,
|
||||
bool isCollisionNode, bool isAnimated, bool autogenerated, bool avoid, unsigned int& cameraOnlyCollision);
|
||||
|
||||
bool hasAutoGeneratedCollision(const Nif::Node& rootNode);
|
||||
bool hasRootCollisionNode(const Nif::Node& rootNode) const;
|
||||
bool collisionShapeIsEmpty(const Nif::Node& rootNode) const;
|
||||
|
||||
void handleNiTriShape(const Nif::NiGeometry& nifNode, const Nif::Parent* parent, const osg::Matrixf& transform,
|
||||
bool isAnimated, bool avoid);
|
||||
|
Loading…
x
Reference in New Issue
Block a user