From 6c2a79184d6c3510b134d1ffbb2ee9a7cd71753e Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 27 Sep 2023 12:17:44 +0300 Subject: [PATCH] Read FO4 skinning data --- components/nif/data.cpp | 37 ++++++++++++++++++++++++++++++++++++ components/nif/data.hpp | 24 +++++++++++++++++++++++ components/nif/niffile.cpp | 2 ++ components/nif/record.hpp | 2 ++ components/nif/recordptr.hpp | 2 ++ 5 files changed, 67 insertions(+) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 62a2a9cce3..8b459d015a 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -302,6 +302,33 @@ namespace Nif } } + void BSSkinInstance::read(NIFStream* nif) + { + mRoot.read(nif); + mData.read(nif); + readRecordList(nif, mBones); + nif->readVector(mScales, nif->get()); + } + + void BSSkinInstance::post(Reader& nif) + { + mRoot.post(nif); + mData.post(nif); + postRecordList(nif, mBones); + if (mData.empty() || mRoot.empty()) + throw Nif::Exception("BSSkin::Instance missing root or data", nif.getFilename()); + + if (mBones.size() != mData->mBones.size()) + throw Nif::Exception("Mismatch in BSSkin::BoneData bone count", nif.getFilename()); + + for (auto& bone : mBones) + { + if (bone.empty()) + throw Nif::Exception("Oops: Missing bone! Don't know how to handle this.", nif.getFilename()); + bone->setBone(); + } + } + void NiSkinData::read(NIFStream* nif) { nif->read(mTransform); @@ -344,6 +371,16 @@ namespace Nif mPartitions.post(nif); } + void BSSkinBoneData::read(NIFStream* nif) + { + mBones.resize(nif->get()); + for (BoneInfo& bone : mBones) + { + nif->read(bone.mBoundSphere); + nif->read(bone.mTransform); + } + } + void NiSkinPartition::read(NIFStream* nif) { mPartitions.resize(nif->get()); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index efab514223..75c18d657a 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -223,6 +223,17 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSSkinInstance : Record + { + NiAVObjectPtr mRoot; + BSSkinBoneDataPtr mData; + NiAVObjectList mBones; + std::vector mScales; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct NiSkinData : public Record { using VertWeight = std::pair; @@ -242,6 +253,19 @@ namespace Nif void post(Reader& nif) override; }; + struct BSSkinBoneData : Record + { + struct BoneInfo + { + osg::BoundingSpheref mBoundSphere; + NiTransform mTransform; + }; + + std::vector mBones; + + void read(NIFStream* nif) override; + }; + struct NiSkinPartition : public Record { struct Partition diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index d5faebb55f..2e3cc8f9aa 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -268,6 +268,8 @@ namespace Nif // Bethesda { "BSDismemberSkinInstance", &construct }, + { "BSSkin::Instance", &construct }, + { "BSSkin::BoneData", &construct }, { "BSTriShape", &construct }, { "BSDynamicTriShape", &construct }, { "BSLODTriShape", &construct }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 00eec64b24..eeafc7abd5 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -125,6 +125,8 @@ namespace Nif RC_BSShaderPPLightingProperty, RC_BSShaderProperty, RC_BSShaderTextureSet, + RC_BSSkinBoneData, + RC_BSSkinInstance, RC_BSSkyShaderProperty, RC_BSTriShape, RC_BSWArray, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index b847f609a4..7056abe6a3 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -162,6 +162,7 @@ namespace Nif struct bhkCompressedMeshShapeData; struct BSMultiBound; struct BSMultiBoundData; + struct BSSkinBoneData; using NiAVObjectPtr = RecordPtrT; using ExtraPtr = RecordPtrT; @@ -211,6 +212,7 @@ namespace Nif using bhkCompressedMeshShapeDataPtr = RecordPtrT; using BSMultiBoundPtr = RecordPtrT; using BSMultiBoundDataPtr = RecordPtrT; + using BSSkinBoneDataPtr = RecordPtrT; using NiAVObjectList = RecordListT; using NiPropertyList = RecordListT;