diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index 8d456fd7ed..8e8d04d93d 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -415,7 +415,7 @@ namespace TestBulletNifLoader, for_root_nif_node_with_bounding_box_should_return_shape_with_compound_shape_and_box_inside) { mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision; - mNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode.mBounds.mBox.mExtents = osg::Vec3f(1, 2, 3); mNode.mBounds.mBox.mCenter = osg::Vec3f(-1, -2, -3); @@ -439,7 +439,7 @@ namespace TEST_F(TestBulletNifLoader, for_child_nif_node_with_bounding_box) { mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision; - mNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode.mBounds.mBox.mExtents = osg::Vec3f(1, 2, 3); mNode.mBounds.mBox.mCenter = osg::Vec3f(-1, -2, -3); mNode.mParents.push_back(&mNiNode); @@ -466,12 +466,12 @@ namespace for_root_and_child_nif_node_with_bounding_box_but_root_without_flag_should_use_child_bounds) { mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision; - mNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode.mBounds.mBox.mExtents = osg::Vec3f(1, 2, 3); mNode.mBounds.mBox.mCenter = osg::Vec3f(-1, -2, -3); mNode.mParents.push_back(&mNiNode); - mNiNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNiNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNiNode.mBounds.mBox.mExtents = osg::Vec3f(4, 5, 6); mNiNode.mBounds.mBox.mCenter = osg::Vec3f(-4, -5, -6); mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNode) }; @@ -497,17 +497,17 @@ namespace for_root_and_two_children_where_both_with_bounds_but_only_first_with_flag_should_use_first_bounds) { mNode.mFlags |= Nif::NiAVObject::Flag_BBoxCollision; - mNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode.mBounds.mBox.mExtents = osg::Vec3f(1, 2, 3); mNode.mBounds.mBox.mCenter = osg::Vec3f(-1, -2, -3); mNode.mParents.push_back(&mNiNode); - mNode2.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode2.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode2.mBounds.mBox.mExtents = osg::Vec3f(4, 5, 6); mNode2.mBounds.mBox.mCenter = osg::Vec3f(-4, -5, -6); mNode2.mParents.push_back(&mNiNode); - mNiNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNiNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNiNode.mBounds.mBox.mExtents = osg::Vec3f(7, 8, 9); mNiNode.mBounds.mBox.mCenter = osg::Vec3f(-7, -8, -9); mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNode), Nif::NiAVObjectPtr(&mNode2) }; @@ -532,18 +532,18 @@ namespace TEST_F(TestBulletNifLoader, for_root_and_two_children_where_both_with_bounds_but_only_second_with_flag_should_use_second_bounds) { - mNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode.mBounds.mBox.mExtents = osg::Vec3f(1, 2, 3); mNode.mBounds.mBox.mCenter = osg::Vec3f(-1, -2, -3); mNode.mParents.push_back(&mNiNode); mNode2.mFlags |= Nif::NiAVObject::Flag_BBoxCollision; - mNode2.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode2.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode2.mBounds.mBox.mExtents = osg::Vec3f(4, 5, 6); mNode2.mBounds.mBox.mCenter = osg::Vec3f(-4, -5, -6); mNode2.mParents.push_back(&mNiNode); - mNiNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNiNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNiNode.mBounds.mBox.mExtents = osg::Vec3f(7, 8, 9); mNiNode.mBounds.mBox.mCenter = osg::Vec3f(-7, -8, -9); mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNode), Nif::NiAVObjectPtr(&mNode2) }; @@ -568,7 +568,7 @@ namespace TEST_F(TestBulletNifLoader, for_root_nif_node_with_bounds_but_without_flag_should_return_shape_with_bounds_but_with_null_collision_shape) { - mNode.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNode.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNode.mBounds.mBox.mExtents = osg::Vec3f(1, 2, 3); mNode.mBounds.mBox.mCenter = osg::Vec3f(-1, -2, -3); @@ -608,7 +608,7 @@ namespace TEST_F(TestBulletNifLoader, for_tri_shape_root_node_with_bounds_should_return_static_shape_with_bounds_but_with_null_collision_shape) { - mNiTriShape.mBounds.mType = Nif::NiBoundingVolume::Type::BOX_BV; + mNiTriShape.mBounds.mType = Nif::BoundingVolume::Type::BOX_BV; mNiTriShape.mBounds.mBox.mExtents = osg::Vec3f(1, 2, 3); mNiTriShape.mBounds.mBox.mCenter = osg::Vec3f(-1, -2, -3); diff --git a/components/nif/node.cpp b/components/nif/node.cpp index 18742f1ea1..328546b7c6 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -12,7 +12,7 @@ namespace Nif { - void NiBoundingVolume::read(NIFStream* nif) + void BoundingVolume::read(NIFStream* nif) { nif->read(mType); switch (mType) @@ -55,7 +55,7 @@ namespace Nif case UNION_BV: { mChildren.resize(nif->get()); - for (NiBoundingVolume& child : mChildren) + for (BoundingVolume& child : mChildren) child.read(nif); break; } @@ -69,7 +69,7 @@ namespace Nif default: { throw Nif::Exception( - "Unhandled NiBoundingVolume type: " + std::to_string(mType), nif->getFile().getFilename()); + "Unhandled BoundingVolume type: " + std::to_string(mType), nif->getFile().getFilename()); } } } @@ -168,7 +168,8 @@ namespace Nif NiAVObject::read(nif); mData.read(nif); - mSkin.read(nif); + if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13)) + mSkin.read(nif); mMaterial.read(nif); if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3) @@ -218,7 +219,7 @@ namespace Nif void BSLODTriShape::read(NIFStream* nif) { - NiTriShape::read(nif); + NiTriBasedGeom::read(nif); nif->readArray(mLOD); } @@ -356,7 +357,7 @@ namespace Nif mMultiBound.read(nif); if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SKY) - nif->read(mType); + mCullingType = static_cast(nif->get()); } void BSMultiBoundNode::post(Reader& nif) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 6e28f3b647..7d851051e0 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -13,7 +13,7 @@ namespace Nif struct NiNode; - struct NiBoundingVolume + struct BoundingVolume { enum Type : uint32_t { @@ -56,7 +56,7 @@ namespace Nif NiBoxBV mBox; NiCapsuleBV mCapsule; NiLozengeBV mLozenge; - std::vector mChildren; + std::vector mChildren; NiHalfSpaceBV mHalfSpace; void read(NIFStream* nif); @@ -83,7 +83,7 @@ namespace Nif NiTransform mTransform; osg::Vec3f mVelocity; PropertyList mProperties; - NiBoundingVolume mBounds; + BoundingVolume mBounds; NiCollisionObjectPtr mCollision; // Parent nodes for the node. Only types derived from NiNode can be parents. std::vector mParents; @@ -152,15 +152,20 @@ namespace Nif void post(Reader& nif) override; }; - struct NiTriShape : NiGeometry + // Abstract triangle-based geometry + struct NiTriBasedGeom : NiGeometry { }; - struct NiTriStrips : NiGeometry + struct NiTriShape : NiTriBasedGeom { }; - struct NiLines : NiGeometry + struct NiTriStrips : NiTriBasedGeom + { + }; + + struct NiLines : NiTriBasedGeom { }; @@ -168,7 +173,7 @@ namespace Nif { }; - struct BSLODTriShape : NiTriShape + struct BSLODTriShape : NiTriBasedGeom { std::array mLOD; void read(NIFStream* nif) override; @@ -283,8 +288,17 @@ namespace Nif struct BSMultiBoundNode : NiNode { + enum class BSCPCullingType : uint32_t + { + Normal, + AllPass, + AllFail, + IgnoreMultiBounds, + ForceMultiBoundsNoUpdate, + }; + BSMultiBoundPtr mMultiBound; - uint32_t mType{ 0 }; + BSCPCullingType mCullingType; void read(NIFStream* nif) override; void post(Reader& nif) override; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 1349c1dc97..df4155db7d 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -175,7 +175,7 @@ namespace NifBullet bool hasCollisionShape = false; if (colNode != nullptr) { - if (colNode->mBounds.mType == Nif::NiBoundingVolume::Type::BASE_BV && !colNode->mChildren.empty()) + if (colNode->mBounds.mType == Nif::BoundingVolume::Type::BASE_BV && !colNode->mChildren.empty()) hasCollisionShape = true; else mShape->mVisualCollisionType = Resource::VisualCollisionType::Camera; @@ -202,22 +202,22 @@ namespace NifBullet unsigned int type = node.mBounds.mType; switch (type) { - case Nif::NiBoundingVolume::Type::BASE_BV: + case Nif::BoundingVolume::Type::BASE_BV: break; - case Nif::NiBoundingVolume::Type::BOX_BV: + case Nif::BoundingVolume::Type::BOX_BV: mShape->mCollisionBox.mExtents = node.mBounds.mBox.mExtents; mShape->mCollisionBox.mCenter = node.mBounds.mBox.mCenter; break; default: { std::stringstream warning; - warning << "Unsupported NiBoundingVolume type " << type << " in node " << node.recIndex; + warning << "Unsupported BoundingVolume type " << type << " in node " << node.recIndex; warning << " in file " << filename; warn(warning.str()); } } - if (type != Nif::NiBoundingVolume::Type::BASE_BV && node.hasBBoxCollision()) + if (type != Nif::BoundingVolume::Type::BASE_BV && node.hasBBoxCollision()) return true; if (const Nif::NiNode* ninode = dynamic_cast(&node)) @@ -329,7 +329,7 @@ namespace NifBullet // NOTE: a trishape with bounds, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. // (occurs in tr_ex_imp_wall_arch_04.nif) - if (node.mBounds.mType == Nif::NiBoundingVolume::Type::BASE_BV + if (node.mBounds.mType == Nif::BoundingVolume::Type::BASE_BV && (node.recType == Nif::RC_NiTriShape || node.recType == Nif::RC_NiTriStrips || node.recType == Nif::RC_BSLODTriShape)) {