diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index f05c6bcd7e..16d553cec8 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -29,6 +29,114 @@ namespace Nif target.post(nif); } + void ControlledBlock::read(NIFStream* nif) + { + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) + mTargetName = nif->getSizedString(); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106)) + mInterpolator.read(nif); + if (nif->getVersion() <= NIFStream::generateVersion(20, 5, 0, 0)) + mController.read(nif); + + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) + return; + + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 110)) + { + nif->skip(4); // NiBlendInterpolator link + mBlendIndex = nif->getUShort(); + } + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106) && nif->getBethVersion() > 0) + mPriority = nif->getChar(); + + if (nif->getVersion() >= NIFStream::generateVersion(10, 2, 0, 0) + && nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 0)) + { + mStringPalette.read(nif); + mNodeNameOffset = nif->getUInt(); + mPropertyTypeOffset = nif->getUInt(); + mControllerTypeOffset = nif->getUInt(); + mControllerIdOffset = nif->getUInt(); + mInterpolatorIdOffset = nif->getUInt(); + } + else + { + mNodeName = nif->getString(); + mPropertyType = nif->getString(); + mControllerType = nif->getString(); + mControllerId = nif->getString(); + mInterpolatorId = nif->getString(); + } + } + + void ControlledBlock::post(Reader& nif) + { + mInterpolator.post(nif); + mController.post(nif); + mStringPalette.post(nif); + // TODO: probably should fill the strings with string palette contents here + } + + void NiSequence::read(NIFStream* nif) + { + mName = nif->getString(); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) + { + mAccumRootName = nif->getString(); + mTextKeys.read(nif); + } + size_t numControlledBlocks = nif->getUInt(); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106)) + mArrayGrowBy = nif->getUInt(); + mControlledBlocks.resize(numControlledBlocks); + for (ControlledBlock& block : mControlledBlocks) + block.read(nif); + } + + void NiSequence::post(Reader& nif) + { + mTextKeys.post(nif); + for (ControlledBlock& block : mControlledBlocks) + block.post(nif); + } + + void NiControllerSequence::read(NIFStream* nif) + { + NiSequence::read(nif); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) + return; + + mWeight = nif->getFloat(); + mTextKeys.read(nif); + mExtrapolationMode = static_cast(nif->getUInt()); + mFrequency = nif->getFloat(); + if (nif->getVersion() <= NIFStream::generateVersion(10, 4, 0, 1)) + mPhase = nif->getFloat(); + mStartTime = nif->getFloat(); + mStopTime = nif->getFloat(); + mPlayBackwards = nif->getVersion() == NIFStream::generateVersion(10, 1, 0, 106) && nif->getBoolean(); + mManager.read(nif); + mAccumRootName = nif->getString(); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 113) + && nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 0)) + mStringPalette.read(nif); + else if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() >= 24) + { + size_t numAnimNotes = 1; + if (nif->getBethVersion() >= 29) + numAnimNotes = nif->getUShort(); + + nif->skip(4 * numAnimNotes); // BSAnimNotes links + } + } + + void NiControllerSequence::post(Reader& nif) + { + NiSequence::post(nif); + mManager.post(nif); + mStringPalette.post(nif); + } + void NiInterpController::read(NIFStream* nif) { Controller::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 762033da24..a5213a9be7 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -29,6 +29,58 @@ namespace Nif { + struct ControlledBlock + { + std::string mTargetName; + NiInterpolatorPtr mInterpolator; + ControllerPtr mController; + unsigned short mBlendIndex; + unsigned char mPriority; + NiStringPalettePtr mStringPalette; + size_t mNodeNameOffset; + size_t mPropertyTypeOffset; + size_t mControllerTypeOffset; + size_t mControllerIdOffset; + size_t mInterpolatorIdOffset; + std::string mNodeName; + std::string mPropertyType; + std::string mControllerType; + std::string mControllerId; + std::string mInterpolatorId; + + void read(NIFStream* nif); + void post(Reader& nif); + }; + + // Gamebryo KF root node record type (pre-10.0) + struct NiSequence : public Record + { + std::string mName; + std::string mAccumRootName; + ExtraPtr mTextKeys; + unsigned int mArrayGrowBy; + std::vector mControlledBlocks; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + // Gamebryo KF root node record type (10.0+) + struct NiControllerSequence : public NiSequence + { + float mWeight{ 1.f }; + Controller::ExtrapolationMode mExtrapolationMode{ Controller::ExtrapolationMode::Constant }; + float mFrequency{ 1.f }; + float mPhase{ 1.f }; + float mStartTime, mStopTime; + bool mPlayBackwards{ false }; + NiControllerManagerPtr mManager; + NiStringPalettePtr mStringPalette; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + // Base class for controllers that use NiInterpolators to animate objects. struct NiInterpController : public Controller { diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 052608a6c6..2f4d471227 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -171,6 +171,8 @@ namespace Nif { "NiSortAdjustNode", &construct }, { "NiClusterAccumulator", &construct }, { "NiAlphaAccumulator", &construct }, + { "NiSequence", &construct }, + { "NiControllerSequence", &construct }, }; } diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 8584ab8419..7a7fd5f5c8 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -147,7 +147,9 @@ namespace Nif RC_NiClusterAccumulator, RC_NiAlphaAccumulator, RC_NiSortAdjustNode, - RC_NiMultiTargetTransformController + RC_NiMultiTargetTransformController, + RC_NiSequence, + RC_NiControllerSequence, }; /// Base class for all records diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index a23ada3eba..cb85763a22 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -140,6 +140,8 @@ namespace Nif struct hkPackedNiTriStripsData; struct NiAccumulator; struct NiInterpolator; + struct NiStringPalette; + struct NiControllerManager; using NodePtr = RecordPtrT; using ExtraPtr = RecordPtrT; @@ -170,6 +172,8 @@ namespace Nif using hkPackedNiTriStripsDataPtr = RecordPtrT; using NiAccumulatorPtr = RecordPtrT; using NiInterpolatorPtr = RecordPtrT; + using NiStringPalettePtr = RecordPtrT; + using NiControllerManagerPtr = RecordPtrT; using NodeList = RecordListT; using PropertyList = RecordListT;