diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index dbe455fbd4..82dab3bcee 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -143,6 +143,15 @@ static std::map makeFactory() factory["bhkCollisionObject"] = {&construct , RC_bhkCollisionObject }; factory["BSDismemberSkinInstance"] = {&construct , RC_BSDismemberSkinInstance }; factory["NiControllerManager"] = {&construct , RC_NiControllerManager }; + factory["bhkMoppBvTreeShape"] = {&construct , RC_bhkMoppBvTreeShape }; + factory["bhkNiTriStripsShape"] = {&construct , RC_bhkNiTriStripsShape }; + factory["bhkPackedNiTriStripsShape"] = {&construct , RC_bhkPackedNiTriStripsShape }; + factory["hkPackedNiTriStripsData"] = {&construct , RC_hkPackedNiTriStripsData }; + factory["bhkConvexVerticesShape"] = {&construct , RC_bhkConvexVerticesShape }; + factory["bhkBoxShape"] = {&construct , RC_bhkBoxShape }; + factory["bhkListShape"] = {&construct , RC_bhkListShape }; + factory["bhkRigidBody"] = {&construct , RC_bhkRigidBody }; + factory["bhkRigidBodyT"] = {&construct , RC_bhkRigidBodyT }; return factory; } diff --git a/components/nif/physics.cpp b/components/nif/physics.cpp index 992a56c9b7..9bbeb148dd 100644 --- a/components/nif/physics.cpp +++ b/components/nif/physics.cpp @@ -3,6 +3,150 @@ namespace Nif { + + /// Non-record data types + + void bhkWorldObjCInfoProperty::read(NIFStream *nif) + { + mData = nif->getUInt(); + mSize = nif->getUInt(); + mCapacityAndFlags = nif->getUInt(); + } + + void bhkWorldObjectCInfo::read(NIFStream *nif) + { + nif->skip(4); // Unused + mPhaseType = static_cast(nif->getChar()); + nif->skip(3); // Unused + mProperty.read(nif); + } + + void HavokMaterial::read(NIFStream *nif) + { + if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD) + nif->skip(4); // Unknown + mMaterial = nif->getUInt(); + } + + void HavokFilter::read(NIFStream *nif) + { + mLayer = nif->getChar(); + mFlags = nif->getChar(); + mGroup = nif->getUShort(); + } + + void hkSubPartData::read(NIFStream *nif) + { + mHavokFilter.read(nif); + mNumVertices = nif->getUInt(); + mHavokMaterial.read(nif); + } + + void hkpMoppCode::read(NIFStream *nif) + { + unsigned int size = nif->getUInt(); + if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0)) + mOffset = nif->getVector4(); + if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3) + nif->getChar(); // MOPP data build type + if (size) + nif->getChars(mData, size); + } + + void bhkEntityCInfo::read(NIFStream *nif) + { + mResponseType = static_cast(nif->getChar()); + nif->skip(1); // Unused + mProcessContactDelay = nif->getUShort(); + } + + void TriangleData::read(NIFStream *nif) + { + for (int i = 0; i < 3; i++) + mTriangle[i] = nif->getUShort(); + mWeldingInfo = nif->getUShort(); + if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB) + mNormal = nif->getVector3(); + } + + void bhkRigidBodyCInfo::read(NIFStream *nif) + { + if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0)) + { + nif->skip(4); // Unused + mHavokFilter.read(nif); + nif->skip(4); // Unused + if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_FO4) + { + if (nif->getBethVersion() >= 83) + nif->skip(4); // Unused + mResponseType = static_cast(nif->getChar()); + nif->skip(1); // Unused + mProcessContactDelay = nif->getUShort(); + } + } + if (nif->getBethVersion() < 83) + nif->skip(4); // Unused + mTranslation = nif->getVector4(); + mRotation = nif->getQuaternion(); + mLinearVelocity = nif->getVector4(); + mAngularVelocity = nif->getVector4(); + for (int i = 0; i < 3; i++) + for (int j = 0; j < 4; j++) + mInertiaTensor[i][j] = nif->getFloat(); + mCenter = nif->getVector4(); + mMass = nif->getFloat(); + mLinearDamping = nif->getFloat(); + mAngularDamping = nif->getFloat(); + if (nif->getBethVersion() >= 83) + { + if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_FO4) + mTimeFactor = nif->getFloat(); + mGravityFactor = nif->getFloat(); + } + mFriction = nif->getFloat(); + if (nif->getBethVersion() >= 83) + mRollingFrictionMult = nif->getFloat(); + mRestitution = nif->getFloat(); + if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0)) + { + mMaxLinearVelocity = nif->getFloat(); + mMaxAngularVelocity = nif->getFloat(); + if (nif->getBethVersion() != NIFFile::BethVersion::BETHVER_FO4) + mPenetrationDepth = nif->getFloat(); + } + mMotionType = static_cast(nif->getChar()); + if (nif->getBethVersion() < 83) + mDeactivatorType = static_cast(nif->getChar()); + else + mEnableDeactivation = nif->getBoolean(); + mSolverDeactivation = static_cast(nif->getChar()); + if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_FO4) + { + nif->skip(1); + mPenetrationDepth = nif->getFloat(); + mTimeFactor = nif->getFloat(); + nif->skip(4); + mResponseType = static_cast(nif->getChar()); + nif->skip(1); // Unused + mProcessContactDelay = nif->getUShort(); + } + mQualityType = static_cast(nif->getChar()); + if (nif->getBethVersion() >= 83) + { + mAutoRemoveLevel = nif->getChar(); + mResponseModifierFlags = nif->getChar(); + mNumContactPointShapeKeys = nif->getChar(); + mForceCollidedOntoPPU = nif->getBoolean(); + } + if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_FO4) + nif->skip(3); // Unused + else + nif->skip(12); // Unused + } + + /// Record types + void bhkCollisionObject::read(NIFStream *nif) { NiCollisionObject::read(nif); @@ -15,13 +159,8 @@ namespace Nif mShape.read(nif); if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD) nif->skip(4); // Unknown - mFlags = nif->getUInt(); - nif->skip(4); // Unused - mWorldObjectInfo.mPhaseType = nif->getChar(); - nif->skip(3); // Unused - mWorldObjectInfo.mData = nif->getUInt(); - mWorldObjectInfo.mSize = nif->getUInt(); - mWorldObjectInfo.mCapacityAndFlags = nif->getUInt(); + mHavokFilter.read(nif); + mWorldObjectInfo.read(nif); } void bhkWorldObject::post(NIFFile *nif) @@ -32,23 +171,143 @@ namespace Nif void bhkEntity::read(NIFStream *nif) { bhkWorldObject::read(nif); - mResponseType = static_cast(nif->getChar()); - nif->skip(1); // Unused - mProcessContactDelay = nif->getUShort(); + mInfo.read(nif); } - void HavokMaterial::read(NIFStream *nif) + void bhkBvTreeShape::read(NIFStream *nif) { - if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB_OLD) - nif->skip(4); // Unknown - mMaterial = nif->getUInt(); + mShape.read(nif); } - void hkSubPartData::read(NIFStream *nif) + void bhkBvTreeShape::post(NIFFile *nif) { - mHavokFilter = nif->getUInt(); - mNumVertices = nif->getUInt(); + mShape.post(nif); + } + + void bhkMoppBvTreeShape::read(NIFStream *nif) + { + bhkBvTreeShape::read(nif); + nif->skip(12); // Unused + mScale = nif->getFloat(); + mMopp.read(nif); + } + + void bhkNiTriStripsShape::read(NIFStream *nif) + { + mHavokMaterial.read(nif); + mRadius = nif->getFloat(); + nif->skip(20); // Unused + mGrowBy = nif->getUInt(); + if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0)) + mScale = nif->getVector4(); + mData.read(nif); + unsigned int numFilters = nif->getUInt(); + nif->getUInts(mFilters, numFilters); + } + + void bhkNiTriStripsShape::post(NIFFile *nif) + { + mData.post(nif); + } + + void bhkPackedNiTriStripsShape::read(NIFStream *nif) + { + if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB) + { + mSubshapes.resize(nif->getUShort()); + for (hkSubPartData& subshape : mSubshapes) + subshape.read(nif); + } + mUserData = nif->getUInt(); + nif->skip(4); // Unused + mRadius = nif->getFloat(); + nif->skip(4); // Unused + mScale = nif->getVector4(); + nif->skip(20); // Duplicates of the two previous fields + mData.read(nif); + } + + void bhkPackedNiTriStripsShape::post(NIFFile *nif) + { + mData.post(nif); + } + + void hkPackedNiTriStripsData::read(NIFStream *nif) + { + unsigned int numTriangles = nif->getUInt(); + mTriangles.resize(numTriangles); + for (unsigned int i = 0; i < numTriangles; i++) + mTriangles[i].read(nif); + + unsigned int numVertices = nif->getUInt(); + bool compressed = false; + if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS) + compressed = nif->getBoolean(); + if (!compressed) + nif->getVector3s(mVertices, numVertices); + else + nif->skip(6 * numVertices); // Half-precision vectors are not currently supported + if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS) + { + mSubshapes.resize(nif->getUShort()); + for (hkSubPartData& subshape : mSubshapes) + subshape.read(nif); + } + } + + void bhkSphereRepShape::read(NIFStream *nif) + { + mHavokMaterial.read(nif); + } + + void bhkConvexShape::read(NIFStream *nif) + { + bhkSphereRepShape::read(nif); + mRadius = nif->getFloat(); + } + + void bhkConvexVerticesShape::read(NIFStream *nif) + { + bhkConvexShape::read(nif); + mVerticesProperty.read(nif); + mNormalsProperty.read(nif); + unsigned int numVertices = nif->getUInt(); + if (numVertices) + nif->getVector4s(mVertices, numVertices); + unsigned int numNormals = nif->getUInt(); + if (numNormals) + nif->getVector4s(mNormals, numNormals); + } + + void bhkBoxShape::read(NIFStream *nif) + { + bhkConvexShape::read(nif); + nif->skip(8); // Unused + mExtents = nif->getVector3(); + nif->skip(4); // Unused + } + + void bhkListShape::read(NIFStream *nif) + { + mSubshapes.read(nif); mHavokMaterial.read(nif); + mChildShapeProperty.read(nif); + mChildFilterProperty.read(nif); + unsigned int numFilters = nif->getUInt(); + mHavokFilters.resize(numFilters); + for (HavokFilter& filter : mHavokFilters) + filter.read(nif); + } + + void bhkRigidBody::read(NIFStream *nif) + { + bhkEntity::read(nif); + mInfo.read(nif); + mConstraints.read(nif); + if (nif->getBethVersion() < 76) + mBodyFlags = nif->getUInt(); + else + mBodyFlags = nif->getUShort(); } } // Namespace \ No newline at end of file diff --git a/components/nif/physics.hpp b/components/nif/physics.hpp index ca31512c71..613ec0ba43 100644 --- a/components/nif/physics.hpp +++ b/components/nif/physics.hpp @@ -8,6 +8,176 @@ namespace Nif { +/// Non-record data types + +struct bhkWorldObjCInfoProperty +{ + unsigned int mData; + unsigned int mSize; + unsigned int mCapacityAndFlags; + void read(NIFStream *nif); +}; + +enum class BroadPhaseType : uint8_t +{ + BroadPhase_Invalid = 0, + BroadPhase_Entity = 1, + BroadPhase_Phantom = 2, + BroadPhase_Border = 3 +}; + +struct bhkWorldObjectCInfo +{ + BroadPhaseType mPhaseType; + bhkWorldObjCInfoProperty mProperty; + void read(NIFStream *nif); +}; + +struct HavokMaterial +{ + unsigned int mMaterial; + void read(NIFStream *nif); +}; + +struct HavokFilter +{ + unsigned char mLayer; + unsigned char mFlags; + unsigned short mGroup; + void read(NIFStream *nif); +}; + +struct hkSubPartData +{ + HavokMaterial mHavokMaterial; + unsigned int mNumVertices; + HavokFilter mHavokFilter; + void read(NIFStream *nif); +}; + +enum class hkResponseType : uint8_t +{ + Response_Invalid = 0, + Response_SimpleContact = 1, + Response_Reporting = 2, + Response_None = 3 +}; + +struct bhkEntityCInfo +{ + hkResponseType mResponseType; + unsigned short mProcessContactDelay; + void read(NIFStream *nif); +}; + +struct hkpMoppCode +{ + osg::Vec4f mOffset; + std::vector mData; + void read(NIFStream *nif); +}; + +struct TriangleData +{ + unsigned short mTriangle[3]; + unsigned short mWeldingInfo; + osg::Vec3f mNormal; + void read(NIFStream *nif); +}; + +enum class hkMotionType : uint8_t +{ + Motion_Invalid = 0, + Motion_Dynamic = 1, + Motion_SphereInertia = 2, + Motion_SphereStabilized = 3, + Motion_BoxInertia = 4, + Motion_BoxStabilized = 5, + Motion_Keyframed = 6, + Motion_Fixed = 7, + Motion_ThinBox = 8, + Motion_Character = 9 +}; + +enum class hkDeactivatorType : uint8_t +{ + Deactivator_Invalid = 0, + Deactivator_Never = 1, + Deactivator_Spatial = 2 +}; + +enum class hkSolverDeactivation : uint8_t +{ + SolverDeactivation_Invalid = 0, + SolverDeactivation_Off = 1, + SolverDeactivation_Low = 2, + SolverDeactivation_Medium = 3, + SolverDeactivation_High = 4, + SolverDeactivation_Max = 5 +}; + +enum class hkQualityType : uint8_t +{ + Quality_Invalid = 0, + Quality_Fixed = 1, + Quality_Keyframed = 2, + Quality_Debris = 3, + Quality_Moving = 4, + Quality_Critical = 5, + Quality_Bullet = 6, + Quality_User = 7, + Quality_Character = 8, + Quality_KeyframedReport = 9 +}; + +struct bhkRigidBodyCInfo +{ + HavokFilter mHavokFilter; + hkResponseType mResponseType; + unsigned short mProcessContactDelay; + osg::Vec4f mTranslation; + osg::Quat mRotation; + osg::Vec4f mLinearVelocity; + osg::Vec4f mAngularVelocity; + float mInertiaTensor[3][4]; + osg::Vec4f mCenter; + float mMass; + float mLinearDamping; + float mAngularDamping; + float mTimeFactor{1.f}; + float mGravityFactor{1.f}; + float mFriction; + float mRollingFrictionMult; + float mRestitution; + float mMaxLinearVelocity; + float mMaxAngularVelocity; + float mPenetrationDepth; + hkMotionType mMotionType; + hkDeactivatorType mDeactivatorType; + bool mEnableDeactivation{true}; + hkSolverDeactivation mSolverDeactivation; + hkQualityType mQualityType; + unsigned char mAutoRemoveLevel; + unsigned char mResponseModifierFlags; + unsigned char mNumContactPointShapeKeys; + bool mForceCollidedOntoPPU; + void read(NIFStream *nif); +}; + +/// Record types + +// Abstract Bethesda Havok object +struct bhkRefObject : public Record {}; + +// Abstract serializable Bethesda Havok object +struct bhkSerializable : public bhkRefObject {}; + +// Abstract narrowphase collision detection object +struct bhkShape : public bhkSerializable {}; + +// Abstract bhkShape collection +struct bhkShapeCollection : public bhkShape {}; + // Generic collision object struct NiCollisionObject : public Record { @@ -28,7 +198,7 @@ struct NiCollisionObject : public Record struct bhkCollisionObject : public NiCollisionObject { unsigned short mFlags; - CollisionBodyPtr mBody; + bhkWorldObjectPtr mBody; void read(NIFStream *nif) override; void post(NIFFile *nif) override @@ -39,51 +209,123 @@ struct bhkCollisionObject : public NiCollisionObject }; // Abstract Havok shape info record -struct bhkWorldObject : public Record +struct bhkWorldObject : public bhkSerializable { bhkShapePtr mShape; - unsigned int mFlags; // Havok layer type, collision filter flags and group - struct WorldObjectInfo - { - unsigned char mPhaseType; - unsigned int mData; - unsigned int mSize; - unsigned int mCapacityAndFlags; - }; - WorldObjectInfo mWorldObjectInfo; + HavokFilter mHavokFilter; + bhkWorldObjectCInfo mWorldObjectInfo; void read(NIFStream *nif) override; void post(NIFFile *nif) override; }; -struct bhkShape : public Record {}; +// Abstract +struct bhkEntity : public bhkWorldObject +{ + bhkEntityCInfo mInfo; + void read(NIFStream *nif) override; +}; -enum class hkResponseType : uint8_t +// Bethesda extension of hkpBvTreeShape +// hkpBvTreeShape adds a bounding volume tree to an hkpShapeCollection +struct bhkBvTreeShape : public bhkShape { - Response_Invalid = 0, - Response_SimpleContact = 1, - Response_Reporting = 2, - Response_None = 3 + bhkShapePtr mShape; + void read(NIFStream *nif) override; + void post(NIFFile *nif) override; }; -struct bhkEntity : public bhkWorldObject +// bhkBvTreeShape with Havok MOPP code +struct bhkMoppBvTreeShape : public bhkBvTreeShape { - hkResponseType mResponseType; - unsigned short mProcessContactDelay; + float mScale; + hkpMoppCode mMopp; void read(NIFStream *nif) override; }; -struct HavokMaterial +// Bethesda triangle strip-based Havok shape collection +struct bhkNiTriStripsShape : public bhkShape { - unsigned int mMaterial; - void read(NIFStream *nif); + HavokMaterial mHavokMaterial; + float mRadius; + unsigned int mGrowBy; + osg::Vec4f mScale{1.f, 1.f, 1.f, 0.f}; + NiTriStripsDataList mData; + std::vector mFilters; + void read(NIFStream *nif) override; + void post(NIFFile *nif) override; }; -struct hkSubPartData +// Bethesda packed triangle strip-based Havok shape collection +struct bhkPackedNiTriStripsShape : public bhkShapeCollection +{ + std::vector mSubshapes; + unsigned int mUserData; + float mRadius; + osg::Vec4f mScale; + hkPackedNiTriStripsDataPtr mData; + + void read(NIFStream *nif) override; + void post(NIFFile *nif) override; +}; + +// bhkPackedNiTriStripsShape data block +struct hkPackedNiTriStripsData : public bhkShapeCollection +{ + std::vector mTriangles; + std::vector mVertices; + std::vector mSubshapes; + void read(NIFStream *nif) override; +}; + +// Abstract +struct bhkSphereRepShape : public bhkShape { HavokMaterial mHavokMaterial; - unsigned int mNumVertices; - unsigned int mHavokFilter; - void read(NIFStream *nif); + void read(NIFStream *nif) override; +}; + +// Abstract +struct bhkConvexShape : public bhkSphereRepShape +{ + float mRadius; + void read(NIFStream *nif) override; +}; + +// A convex shape built from vertices +struct bhkConvexVerticesShape : public bhkConvexShape +{ + bhkWorldObjCInfoProperty mVerticesProperty; + bhkWorldObjCInfoProperty mNormalsProperty; + std::vector mVertices; + std::vector mNormals; + void read(NIFStream *nif) override; +}; + +// A box +struct bhkBoxShape : public bhkConvexShape +{ + osg::Vec3f mExtents; + void read(NIFStream *nif) override; +}; + +// A list of shapes +struct bhkListShape : public bhkShapeCollection +{ + bhkShapeList mSubshapes; + HavokMaterial mHavokMaterial; + bhkWorldObjCInfoProperty mChildShapeProperty; + bhkWorldObjCInfoProperty mChildFilterProperty; + std::vector mHavokFilters; + void read(NIFStream *nif) override; +}; + +struct bhkRigidBody : public bhkEntity +{ + bhkRigidBodyCInfo mInfo; + bhkSerializableList mConstraints; + unsigned int mBodyFlags; + + void read(NIFStream *nif) override; }; } // Namespace diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 0b9b2dc998..5fb50a05e5 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -130,7 +130,16 @@ enum RecordType RC_NiCollisionObject, RC_bhkCollisionObject, RC_BSDismemberSkinInstance, - RC_NiControllerManager + RC_NiControllerManager, + RC_bhkMoppBvTreeShape, + RC_bhkNiTriStripsShape, + RC_bhkPackedNiTriStripsShape, + RC_hkPackedNiTriStripsData, + RC_bhkConvexVerticesShape, + RC_bhkBoxShape, + RC_bhkListShape, + RC_bhkRigidBody, + RC_bhkRigidBodyT }; /// Base class for all records diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index a25480fe43..cc62d7b2e0 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -151,6 +151,8 @@ struct NiAlphaProperty; struct NiCollisionObject; struct bhkWorldObject; struct bhkShape; +struct bhkSerializable; +struct hkPackedNiTriStripsData; using NodePtr = RecordPtrT; using ExtraPtr = RecordPtrT; @@ -179,8 +181,9 @@ using NiGeometryDataPtr = RecordPtrT; using BSShaderPropertyPtr = RecordPtrT; using NiAlphaPropertyPtr = RecordPtrT; using NiCollisionObjectPtr = RecordPtrT; -using CollisionBodyPtr = RecordPtrT; +using bhkWorldObjectPtr = RecordPtrT; using bhkShapePtr = RecordPtrT; +using hkPackedNiTriStripsDataPtr = RecordPtrT; using NodeList = RecordListT; using PropertyList = RecordListT; @@ -188,6 +191,8 @@ using ExtraList = RecordListT; using NiSourceTextureList = RecordListT; using NiFloatInterpolatorList = RecordListT; using NiTriStripsDataList = RecordListT; +using bhkShapeList = RecordListT; +using bhkSerializableList = RecordListT; } // Namespace #endif