diff --git a/apps/openmw_test_suite/nif/node.hpp b/apps/openmw_test_suite/nif/node.hpp index b39729c876..e05a056b79 100644 --- a/apps/openmw_test_suite/nif/node.hpp +++ b/apps/openmw_test_suite/nif/node.hpp @@ -20,7 +20,7 @@ namespace Nif::Testing { value.mExtra = ExtraPtr(nullptr); value.mExtraList = ExtraList(); - value.mController = ControllerPtr(nullptr); + value.mController = NiTimeControllerPtr(nullptr); } inline void init(NiAVObject& value) @@ -55,15 +55,15 @@ namespace Nif::Testing value.mRoot = NiAVObjectPtr(nullptr); } - inline void init(Controller& value) + inline void init(NiTimeController& value) { - value.next = ControllerPtr(nullptr); - value.flags = 0; - value.frequency = 0; - value.phase = 0; - value.timeStart = 0; - value.timeStop = 0; - value.target = NiObjectNETPtr(nullptr); + value.mNext = NiTimeControllerPtr(nullptr); + value.mFlags = 0; + value.mFrequency = 0; + value.mPhase = 0; + value.mTimeStart = 0; + value.mTimeStop = 0; + value.mTarget = NiObjectNETPtr(nullptr); } } diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index fc6a21f62c..1971895936 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -300,7 +300,7 @@ namespace Nif::NiStringExtraData mNiStringExtraData; Nif::NiStringExtraData mNiStringExtraData2; Nif::NiIntegerExtraData mNiIntegerExtraData; - Nif::Controller mController; + Nif::NiTimeController mController; btTransform mTransform{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(1, 2, 3) }; btTransform mTransformScale2{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(2, 4, 6) }; btTransform mTransformScale3{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(3, 6, 9) }; @@ -817,11 +817,11 @@ namespace TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_controller_should_return_animated_shape) { mController.recType = Nif::RC_NiKeyframeController; - mController.flags |= Nif::Controller::Flag_Active; + mController.mFlags |= Nif::NiTimeController::Flag_Active; copy(mTransform, mNiTriShape.mTransform); mNiTriShape.mTransform.mScale = 3; mNiTriShape.mParents.push_back(&mNiNode); - mNiTriShape.mController = Nif::ControllerPtr(&mController); + mNiTriShape.mController = Nif::NiTimeControllerPtr(&mController); mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) }; mNiNode.mTransform.mScale = 4; @@ -847,14 +847,14 @@ namespace TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_where_one_with_controller_should_return_animated_shape) { mController.recType = Nif::RC_NiKeyframeController; - mController.flags |= Nif::Controller::Flag_Active; + mController.mFlags |= Nif::NiTimeController::Flag_Active; copy(mTransform, mNiTriShape.mTransform); mNiTriShape.mTransform.mScale = 3; mNiTriShape.mParents.push_back(&mNiNode); copy(mTransform, mNiTriShape2.mTransform); mNiTriShape2.mTransform.mScale = 3; mNiTriShape2.mParents.push_back(&mNiNode); - mNiTriShape2.mController = Nif::ControllerPtr(&mController); + mNiTriShape2.mController = Nif::NiTimeControllerPtr(&mController); mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape), Nif::NiAVObjectPtr(&mNiTriShape2), diff --git a/components/nif/base.hpp b/components/nif/base.hpp index 6b4d5710b4..ae4bda7753 100644 --- a/components/nif/base.hpp +++ b/components/nif/base.hpp @@ -21,7 +21,7 @@ namespace Nif void post(Reader& nif) override { mNext.post(nif); } }; - struct Controller : public Record + struct NiTimeController : public Record { enum Flags { @@ -36,17 +36,17 @@ namespace Nif Mask = 6 }; - ControllerPtr next; - int flags; - float frequency, phase; - float timeStart, timeStop; - NiObjectNETPtr target; + NiTimeControllerPtr mNext; + uint16_t mFlags; + float mFrequency, mPhase; + float mTimeStart, mTimeStop; + NiObjectNETPtr mTarget; void read(NIFStream* nif) override; void post(Reader& nif) override; - bool isActive() const { return flags & Flag_Active; } - ExtrapolationMode extrapolationMode() const { return static_cast(flags & Mask); } + bool isActive() const { return mFlags & Flag_Active; } + ExtrapolationMode extrapolationMode() const { return static_cast(mFlags & Mask); } }; /// Abstract object that has a name, extra data and controllers @@ -55,7 +55,7 @@ namespace Nif std::string mName; ExtraPtr mExtra; ExtraList mExtraList; - ControllerPtr mController; + NiTimeControllerPtr mController; void read(NIFStream* nif) override; void post(Reader& nif) override; diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index a3d7f33e45..99317cda57 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -1,6 +1,7 @@ #include "controller.hpp" #include "data.hpp" +#include "exception.hpp" #include "node.hpp" #include "particle.hpp" #include "texture.hpp" @@ -8,25 +9,22 @@ namespace Nif { - void Controller::read(NIFStream* nif) + void NiTimeController::read(NIFStream* nif) { - next.read(nif); - - flags = nif->getUShort(); - - frequency = nif->getFloat(); - phase = nif->getFloat(); - timeStart = nif->getFloat(); - timeStop = nif->getFloat(); - - target.read(nif); + mNext.read(nif); + nif->read(mFlags); + nif->read(mFrequency); + nif->read(mPhase); + nif->read(mTimeStart); + nif->read(mTimeStop); + if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13)) + mTarget.read(nif); } - void Controller::post(Reader& nif) + void NiTimeController::post(Reader& nif) { - Record::post(nif); - next.post(nif); - target.post(nif); + mNext.post(nif); + mTarget.post(nif); } void ControlledBlock::read(NIFStream* nif) @@ -44,28 +42,28 @@ namespace Nif if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 110)) { mBlendInterpolator.read(nif); - mBlendIndex = nif->getUShort(); + nif->read(mBlendIndex); } if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106) && nif->getBethVersion() > 0) - mPriority = nif->getChar(); + nif->read(mPriority); 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(); + nif->read(mNodeNameOffset); + nif->read(mPropertyTypeOffset); + nif->read(mControllerTypeOffset); + nif->read(mControllerIdOffset); + nif->read(mInterpolatorIdOffset); } else { - mNodeName = nif->getString(); - mPropertyType = nif->getString(); - mControllerType = nif->getString(); - mControllerId = nif->getString(); - mInterpolatorId = nif->getString(); + nif->read(mNodeName); + nif->read(mPropertyType); + nif->read(mControllerType); + nif->read(mControllerId); + nif->read(mInterpolatorId); } } @@ -80,16 +78,15 @@ namespace Nif void NiSequence::read(NIFStream* nif) { - mName = nif->getString(); + nif->read(mName); if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) { - mAccumRootName = nif->getString(); + nif->read(mAccumRootName); mTextKeys.read(nif); } - size_t numControlledBlocks = nif->getUInt(); + mControlledBlocks.resize(nif->get()); if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106)) - mArrayGrowBy = nif->getUInt(); - mControlledBlocks.resize(numControlledBlocks); + nif->read(mArrayGrowBy); for (ControlledBlock& block : mControlledBlocks) block.read(nif); } @@ -104,28 +101,30 @@ namespace Nif void NiControllerSequence::read(NIFStream* nif) { NiSequence::read(nif); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) return; - mWeight = nif->getFloat(); + nif->read(mWeight); mTextKeys.read(nif); - mExtrapolationMode = static_cast(nif->getUInt()); - mFrequency = nif->getFloat(); + mExtrapolationMode = static_cast(nif->get()); + nif->read(mFrequency); 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(); + nif->read(mPhase); + nif->read(mStartTime); + nif->read(mStopTime); + if (nif->getVersion() == NIFStream::generateVersion(10, 1, 0, 106)) + nif->read(mPlayBackwards); mManager.read(nif); - mAccumRootName = nif->getString(); + nif->read(mAccumRootName); 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; + uint16_t numAnimNotes = 1; if (nif->getBethVersion() >= 29) - numAnimNotes = nif->getUShort(); + nif->read(numAnimNotes); nif->skip(4 * numAnimNotes); // BSAnimNotes links } @@ -134,21 +133,24 @@ namespace Nif void NiControllerSequence::post(Reader& nif) { NiSequence::post(nif); + mManager.post(nif); mStringPalette.post(nif); } void NiInterpController::read(NIFStream* nif) { - Controller::read(nif); + NiTimeController::read(nif); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 104) && nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 108)) - mManagerControlled = nif->getBoolean(); + nif->read(mManagerControlled); } void NiSingleInterpController::read(NIFStream* nif) { NiInterpController::read(nif); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 104)) mInterpolator.read(nif); } @@ -156,83 +158,86 @@ namespace Nif void NiSingleInterpController::post(Reader& nif) { NiInterpController::post(nif); + mInterpolator.post(nif); } + void NiParticleInfo::read(NIFStream* nif) + { + nif->read(mVelocity); + if (nif->getVersion() <= NIFStream::generateVersion(10, 4, 0, 1)) + nif->read(mRotationAxis); + nif->read(mAge); + nif->read(mLifespan); + nif->read(mLastUpdate); + nif->read(mSpawnGeneration); + nif->read(mCode); + } + void NiParticleSystemController::read(NIFStream* nif) { - Controller::read(nif); - - velocity = nif->getFloat(); - velocityRandom = nif->getFloat(); - verticalDir = nif->getFloat(); - verticalAngle = nif->getFloat(); - horizontalDir = nif->getFloat(); - horizontalAngle = nif->getFloat(); - /*normal?*/ nif->getVector3(); - color = nif->getVector4(); - size = nif->getFloat(); - startTime = nif->getFloat(); - stopTime = nif->getFloat(); - nif->getChar(); - emitRate = nif->getFloat(); - lifetime = nif->getFloat(); - lifetimeRandom = nif->getFloat(); - - emitFlags = nif->getUShort(); - offsetRandom = nif->getVector3(); - - emitter.read(nif); - - /* Unknown Short, 0? - * Unknown Float, 1.0? - * Unknown Int, 1? - * Unknown Int, 0? - * Unknown Short, 0? - */ - nif->skip(16); - - numParticles = nif->getUShort(); - activeCount = nif->getUShort(); - - particles.resize(numParticles); - for (size_t i = 0; i < particles.size(); i++) + NiTimeController::read(nif); + + if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13)) + nif->read(mSpeed); + nif->read(mSpeedVariation); + nif->read(mDeclination); + nif->read(mDeclinationVariation); + nif->read(mPlanarAngle); + nif->read(mPlanarAngleVariation); + nif->read(mInitialNormal); + nif->read(mInitialColor); + nif->read(mInitialSize); + nif->read(mEmitStartTime); + nif->read(mEmitStopTime); + if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13)) { - particles[i].velocity = nif->getVector3(); - nif->getVector3(); /* unknown */ - particles[i].lifetime = nif->getFloat(); - particles[i].lifespan = nif->getFloat(); - particles[i].timestamp = nif->getFloat(); - nif->getUShort(); /* unknown */ - particles[i].vertex = nif->getUShort(); + mResetParticleSystem = nif->get() != 0; + nif->read(mBirthRate); } - - nif->getUInt(); /* -1? */ - affectors.read(nif); - colliders.read(nif); - nif->getChar(); + nif->read(mLifetime); + nif->read(mLifetimeVariation); + if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13)) + nif->read(mEmitFlags); + nif->read(mEmitterDimensions); + mEmitter.read(nif); + if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13)) + { + nif->read(mNumSpawnGenerations); + nif->read(mPercentageSpawned); + nif->read(mSpawnMultiplier); + nif->read(mSpawnSpeedChaos); + nif->read(mSpawnDirChaos); + mParticles.resize(nif->get()); + nif->read(mNumValid); + for (NiParticleInfo& particle : mParticles) + particle.read(nif); + nif->skip(4); // NiEmitterModifier link + } + mModifier.read(nif); + mCollider.read(nif); + if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 15)) + nif->read(mStaticTargetBound); } void NiParticleSystemController::post(Reader& nif) { - Controller::post(nif); - emitter.post(nif); - affectors.post(nif); - colliders.post(nif); + NiTimeController::post(nif); + + mEmitter.post(nif); + mModifier.post(nif); + mCollider.post(nif); } void NiMaterialColorController::read(NIFStream* nif) { NiPoint3InterpController::read(nif); - // Two bits that correspond to the controlled material color. - // 00: Ambient - // 01: Diffuse - // 10: Specular - // 11: Emissive + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) - mTargetColor = nif->getUShort() & 3; + mTargetColor = static_cast(nif->get() & 3); else - mTargetColor = (flags >> 4) & 3; + mTargetColor = static_cast((mFlags >> 4) & 3); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) mData.read(nif); } @@ -240,60 +245,70 @@ namespace Nif void NiMaterialColorController::post(Reader& nif) { NiPoint3InterpController::post(nif); + mData.post(nif); } void NiLookAtController::read(NIFStream* nif) { - Controller::read(nif); + NiTimeController::read(nif); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) - lookAtFlags = nif->getUShort(); - target.read(nif); + nif->read(mLookAtFlags); + mLookAt.read(nif); } void NiLookAtController::post(Reader& nif) { - Controller::post(nif); - target.post(nif); + NiTimeController::post(nif); + + mLookAt.post(nif); } void NiPathController::read(NIFStream* nif) { - Controller::read(nif); + NiTimeController::read(nif); + + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) + nif->read(mPathFlags); + else + mPathFlags = (mFlags >> 4); - bankDir = nif->getInt(); - maxBankAngle = nif->getFloat(); - smoothing = nif->getFloat(); - followAxis = nif->getShort(); - posData.read(nif); - floatData.read(nif); + nif->read(mBankDirection); + nif->read(mMaxBankAngle); + nif->read(mSmoothing); + nif->read(mFollowAxis); + mPathData.read(nif); + mPercentData.read(nif); } void NiPathController::post(Reader& nif) { - Controller::post(nif); + NiTimeController::post(nif); - posData.post(nif); - floatData.post(nif); + mPathData.post(nif); + mPercentData.post(nif); } void NiUVController::read(NIFStream* nif) { - Controller::read(nif); + NiTimeController::read(nif); - uvSet = nif->getUShort(); - data.read(nif); + nif->read(mUvSet); + mData.read(nif); } void NiUVController::post(Reader& nif) { - Controller::post(nif); - data.post(nif); + NiTimeController::post(nif); + + mData.post(nif); } void NiKeyframeController::read(NIFStream* nif) { NiSingleInterpController::read(nif); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) mData.read(nif); } @@ -301,29 +316,30 @@ namespace Nif void NiKeyframeController::post(Reader& nif) { NiSingleInterpController::post(nif); + mData.post(nif); } void NiMultiTargetTransformController::read(NIFStream* nif) { NiInterpController::read(nif); - size_t numTargets = nif->getUShort(); - std::vector targets; - targets.resize(numTargets); - for (size_t i = 0; i < targets.size(); i++) - targets[i].read(nif); - mExtraTargets = targets; + + mExtraTargets.resize(nif->get()); + for (NiAVObjectPtr& extraTarget : mExtraTargets) + extraTarget.read(nif); } void NiMultiTargetTransformController::post(Reader& nif) { NiInterpController::post(nif); + postRecordList(nif, mExtraTargets); } void NiAlphaController::read(NIFStream* nif) { NiFloatInterpController::read(nif); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) mData.read(nif); } @@ -331,12 +347,14 @@ namespace Nif void NiAlphaController::post(Reader& nif) { NiFloatInterpController::post(nif); + mData.post(nif); } void NiRollController::read(NIFStream* nif) { NiSingleInterpController::read(nif); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) mData.read(nif); } @@ -344,49 +362,47 @@ namespace Nif void NiRollController::post(Reader& nif) { NiSingleInterpController::post(nif); + mData.post(nif); } void NiGeomMorpherController::read(NIFStream* nif) { NiInterpController::read(nif); + if (nif->getVersion() >= NIFFile::NIFVersion::VER_OB_OLD) - mUpdateNormals = nif->getUShort() & 1; + mUpdateNormals = nif->get() & 1; mData.read(nif); - if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW) + + if (nif->getVersion() < NIFFile::NIFVersion::VER_MW) + return; + + mAlwaysActive = nif->get() != 0; + + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 105)) + return; + + if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB) { - mAlwaysActive = nif->getChar(); - if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106)) - { - if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB) - { - readRecordList(nif, mInterpolators); - if (nif->getVersion() >= NIFStream::generateVersion(10, 2, 0, 0) && nif->getBethVersion() > 9) - { - unsigned int numUnknown = nif->getUInt(); - nif->skip(4 * numUnknown); - } - } - else - { - std::vector interpolators; - size_t numInterps = nif->getUInt(); - interpolators.resize(numInterps); - mWeights.resize(numInterps); - for (size_t i = 0; i < numInterps; i++) - { - interpolators[i].read(nif); - mWeights[i] = nif->getFloat(); - } - mInterpolators = interpolators; - } - } + readRecordList(nif, mInterpolators); + if (nif->getVersion() >= NIFStream::generateVersion(10, 2, 0, 0) && nif->getBethVersion() >= 10) + nif->skip(4 * nif->get()); // Unknown + return; + } + + mInterpolators.resize(nif->get()); + mWeights.resize(mInterpolators.size()); + for (size_t i = 0; i < mInterpolators.size(); i++) + { + mInterpolators[i].read(nif); + nif->read(mWeights[i]); } } void NiGeomMorpherController::post(Reader& nif) { NiInterpController::post(nif); + mData.post(nif); postRecordList(nif, mInterpolators); } @@ -394,6 +410,7 @@ namespace Nif void NiVisController::read(NIFStream* nif) { NiBoolInterpController::read(nif); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) mData.read(nif); } @@ -401,17 +418,19 @@ namespace Nif void NiVisController::post(Reader& nif) { NiBoolInterpController::post(nif); + mData.post(nif); } void NiFlipController::read(NIFStream* nif) { NiFloatInterpController::read(nif); - mTexSlot = nif->getUInt(); + + mTexSlot = static_cast(nif->get()); if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) { - timeStart = nif->getFloat(); - mDelta = nif->getFloat(); + nif->read(mTimeStart); + nif->read(mDelta); } readRecordList(nif, mSources); } @@ -419,14 +438,16 @@ namespace Nif void NiFlipController::post(Reader& nif) { NiFloatInterpController::post(nif); + postRecordList(nif, mSources); } void NiTextureTransformController::read(NIFStream* nif) { NiFloatInterpController::read(nif); - mShaderMap = nif->getBoolean(); - nif->read(mTexSlot); + + nif->read(mShaderMap); + mTexSlot = static_cast(nif->get()); nif->read(mTransformMember); if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) mData.read(nif); @@ -435,176 +456,113 @@ namespace Nif void NiTextureTransformController::post(Reader& nif) { NiFloatInterpController::post(nif); + mData.post(nif); } void bhkBlendController::read(NIFStream* nif) { - Controller::read(nif); - nif->getUInt(); // Zero + NiTimeController::read(nif); + + uint32_t numKeys; + nif->read(numKeys); + // Is this possible? + if (numKeys != 0) + throw Nif::Exception( + "Unsupported keys in bhkBlendController " + std::to_string(recIndex), nif->getFile().getFilename()); } void BSEffectShaderPropertyFloatController::read(NIFStream* nif) { NiFloatInterpController::read(nif); + nif->read(mControlledVariable); } void BSEffectShaderPropertyColorController::read(NIFStream* nif) { NiPoint3InterpController::read(nif); + nif->read(mControlledColor); } void NiControllerManager::read(NIFStream* nif) { - Controller::read(nif); - mCumulative = nif->getBoolean(); + NiTimeController::read(nif); + + nif->read(mCumulative); readRecordList(nif, mSequences); mObjectPalette.read(nif); } void NiControllerManager::post(Reader& nif) { - Controller::post(nif); + NiTimeController::post(nif); + postRecordList(nif, mSequences); mObjectPalette.post(nif); } - void NiPoint3Interpolator::read(NIFStream* nif) - { - defaultVal = nif->getVector3(); - data.read(nif); - } - - void NiPoint3Interpolator::post(Reader& nif) - { - data.post(nif); - } - - void NiBoolInterpolator::read(NIFStream* nif) - { - defaultVal = nif->getBoolean(); - data.read(nif); - } - - void NiBoolInterpolator::post(Reader& nif) - { - data.post(nif); - } - - void NiFloatInterpolator::read(NIFStream* nif) - { - defaultVal = nif->getFloat(); - data.read(nif); - } - - void NiFloatInterpolator::post(Reader& nif) - { - data.post(nif); - } - - void NiTransformInterpolator::read(NIFStream* nif) - { - defaultPos = nif->getVector3(); - defaultRot = nif->getQuaternion(); - defaultScale = nif->getFloat(); - if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109)) - { - if (!nif->getBoolean()) - defaultPos = osg::Vec3f(); - if (!nif->getBoolean()) - defaultRot = osg::Quat(); - if (!nif->getBoolean()) - defaultScale = 1.f; - } - data.read(nif); - } - - void NiTransformInterpolator::post(Reader& nif) - { - data.post(nif); - } - - void NiColorInterpolator::read(NIFStream* nif) - { - defaultVal = nif->getVector4(); - data.read(nif); - } - - void NiColorInterpolator::post(Reader& nif) - { - data.post(nif); - } - void NiBlendInterpolator::read(NIFStream* nif) { if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 112)) - mManagerControlled = nif->getChar() & 1; - size_t numInterps = 0; - if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109)) - { - numInterps = nif->getUShort(); - mArrayGrowBy = nif->getUShort(); - } - else { - numInterps = nif->getChar(); - if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 112)) + nif->read(mFlags); + mItems.resize(nif->get()); + nif->read(mWeightThreshold); + if (!(mFlags & Flag_ManagerControlled)) { - mWeightThreshold = nif->getFloat(); - if (!mManagerControlled) - { - mInterpCount = nif->getChar(); - mSingleIndex = nif->getChar(); - mHighPriority = nif->getChar(); - mNextHighPriority = nif->getChar(); - mSingleTime = nif->getFloat(); - mHighWeightsSum = nif->getFloat(); - mNextHighWeightsSum = nif->getFloat(); - mHighEaseSpinner = nif->getFloat(); - } + mInterpCount = nif->get(); + mSingleIndex = nif->get(); + mHighPriority = nif->get(); + mNextHighPriority = nif->get(); + nif->read(mSingleTime); + nif->read(mHighWeightsSum); + nif->read(mNextHighWeightsSum); + nif->read(mHighEaseSpinner); + for (Item& item : mItems) + item.read(nif); } + return; } - if (!mManagerControlled) + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 110)) { - mItems.resize(numInterps); + mItems.resize(nif->get()); for (Item& item : mItems) item.read(nif); + if (nif->get()) + mFlags |= Flag_ManagerControlled; + nif->read(mWeightThreshold); + if (nif->get()) + mFlags |= Flag_OnlyUseHighestWeight; + mInterpCount = nif->get(); + mSingleIndex = nif->get(); + mSingleInterpolator.read(nif); + nif->read(mSingleTime); + mHighPriority = nif->get(); + mNextHighPriority = nif->get(); + return; } - if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 111)) + mItems.resize(nif->get()); + nif->read(mArrayGrowBy); + for (Item& item : mItems) + item.read(nif); + if (nif->get()) + mFlags |= Flag_ManagerControlled; + nif->read(mWeightThreshold); + if (nif->get()) + mFlags |= Flag_OnlyUseHighestWeight; + nif->read(mInterpCount); + nif->read(mSingleIndex); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 108)) { - mManagerControlled = nif->getBoolean(); - mWeightThreshold = nif->getFloat(); - mOnlyUseHighestWeight = nif->getBoolean(); - if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109)) - { - mInterpCount = nif->getUShort(); - mSingleIndex = nif->getUShort(); - } - else - { - mInterpCount = nif->getChar(); - mSingleIndex = nif->getChar(); - } - if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 108)) - { - mSingleInterpolator.read(nif); - mSingleTime = nif->getFloat(); - } - if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109)) - { - mHighPriority = nif->getInt(); - mNextHighPriority = nif->getInt(); - } - else - { - mHighPriority = nif->getChar(); - mNextHighPriority = nif->getChar(); - } + mSingleInterpolator.read(nif); + nif->read(mSingleTime); } + nif->read(mHighPriority); + nif->read(mNextHighPriority); } void NiBlendInterpolator::post(Reader& nif) @@ -617,13 +575,13 @@ namespace Nif void NiBlendInterpolator::Item::read(NIFStream* nif) { mInterpolator.read(nif); - mWeight = nif->getFloat(); - mNormalizedWeight = nif->getFloat(); - if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109)) - mPriority = nif->getInt(); + nif->read(mWeight); + nif->read(mNormalizedWeight); + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 110)) + mPriority = nif->get(); else - mPriority = nif->getChar(); - mEaseSpinner = nif->getFloat(); + nif->read(mPriority); + nif->read(mEaseSpinner); } void NiBlendInterpolator::Item::post(Reader& nif) @@ -631,38 +589,4 @@ namespace Nif mInterpolator.post(nif); } - void NiBlendBoolInterpolator::read(NIFStream* nif) - { - NiBlendInterpolator::read(nif); - mValue = nif->getChar() != 0; - } - - void NiBlendFloatInterpolator::read(NIFStream* nif) - { - NiBlendInterpolator::read(nif); - mValue = nif->getFloat(); - } - - void NiBlendPoint3Interpolator::read(NIFStream* nif) - { - NiBlendInterpolator::read(nif); - mValue = nif->getVector3(); - } - - void NiBlendTransformInterpolator::read(NIFStream* nif) - { - NiBlendInterpolator::read(nif); - if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109)) - { - mPosValue = nif->getVector3(); - mRotValue = nif->getQuaternion(); - mScaleValue = nif->getFloat(); - if (!nif->getBoolean()) - mPosValue = osg::Vec3f(); - if (!nif->getBoolean()) - mRotValue = osg::Quat(); - if (!nif->getBoolean()) - mScaleValue = 1.f; - } - } } diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 68e795e7fc..afca97d885 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -1,30 +1,8 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: https://openmw.org/ - - This file (controller.h) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - https://www.gnu.org/licenses/ . - - */ - #ifndef OPENMW_COMPONENTS_NIF_CONTROLLER_HPP #define OPENMW_COMPONENTS_NIF_CONTROLLER_HPP #include "base.hpp" +#include "niftypes.hpp" #include "property.hpp" namespace Nif @@ -34,16 +12,16 @@ namespace Nif { std::string mTargetName; NiInterpolatorPtr mInterpolator; - ControllerPtr mController; + NiTimeControllerPtr mController; NiBlendInterpolatorPtr mBlendInterpolator; - unsigned short mBlendIndex; - unsigned char mPriority; + uint16_t mBlendIndex; + uint8_t mPriority; NiStringPalettePtr mStringPalette; - size_t mNodeNameOffset; - size_t mPropertyTypeOffset; - size_t mControllerTypeOffset; - size_t mControllerIdOffset; - size_t mInterpolatorIdOffset; + uint32_t mNodeNameOffset; + uint32_t mPropertyTypeOffset; + uint32_t mControllerTypeOffset; + uint32_t mControllerIdOffset; + uint32_t mInterpolatorIdOffset; std::string mNodeName; std::string mPropertyType; std::string mControllerType; @@ -60,7 +38,7 @@ namespace Nif std::string mName; std::string mAccumRootName; ExtraPtr mTextKeys; - unsigned int mArrayGrowBy; + uint32_t mArrayGrowBy; std::vector mControlledBlocks; void read(NIFStream* nif) override; @@ -71,7 +49,7 @@ namespace Nif struct NiControllerSequence : public NiSequence { float mWeight{ 1.f }; - Controller::ExtrapolationMode mExtrapolationMode{ Controller::ExtrapolationMode::Constant }; + NiTimeController::ExtrapolationMode mExtrapolationMode{ NiTimeController::ExtrapolationMode::Constant }; float mFrequency{ 1.f }; float mPhase{ 1.f }; float mStartTime, mStopTime; @@ -84,7 +62,7 @@ namespace Nif }; // Base class for controllers that use NiInterpolators to animate objects. - struct NiInterpController : public Controller + struct NiInterpController : public NiTimeController { // Usually one of the flags. bool mManagerControlled{ false }; @@ -116,7 +94,20 @@ namespace Nif { }; - struct NiParticleSystemController : public Controller + struct NiParticleInfo + { + osg::Vec3f mVelocity; + osg::Vec3f mRotationAxis; + float mAge; + float mLifespan; + float mLastUpdate; + uint16_t mSpawnGeneration; + uint16_t mCode; + + void read(NIFStream* nif); + }; + + struct NiParticleSystemController : public NiTimeController { enum BSPArrayController { @@ -124,104 +115,113 @@ namespace Nif BSPArrayController_AtVertex = 0x10 }; - struct Particle - { - osg::Vec3f velocity; - float lifetime; - float lifespan; - float timestamp; - unsigned short vertex; - }; - - float velocity; - float velocityRandom; - - float verticalDir; // 0=up, pi/2=horizontal, pi=down - float verticalAngle; - float horizontalDir; - float horizontalAngle; - - osg::Vec4f color; - float size; - float startTime; - float stopTime; - - float emitRate; - float lifetime; - float lifetimeRandom; - enum EmitFlags { EmitFlag_NoAutoAdjust = 0x1 // If this flag is set, we use the emitRate value. Otherwise, // we calculate an emit rate so that the maximum number of particles // in the system (numParticles) is never exceeded. }; - int emitFlags; - osg::Vec3f offsetRandom; - - NiAVObjectPtr emitter; - - int numParticles; - int activeCount; - std::vector particles; - - NiParticleModifierPtr affectors; - NiParticleModifierPtr colliders; + float mSpeed; + float mSpeedVariation; + float mDeclination; + float mDeclinationVariation; + float mPlanarAngle; + float mPlanarAngleVariation; + osg::Vec3f mInitialNormal; + osg::Vec4f mInitialColor; + float mInitialSize; + float mEmitStartTime; + float mEmitStopTime; + bool mResetParticleSystem{ false }; + float mBirthRate; + float mLifetime; + float mLifetimeVariation; + uint16_t mEmitFlags{ 0 }; + osg::Vec3f mEmitterDimensions; + NiAVObjectPtr mEmitter; + uint16_t mNumSpawnGenerations; + float mPercentageSpawned; + uint16_t mSpawnMultiplier; + float mSpawnSpeedChaos; + float mSpawnDirChaos; + uint16_t mNumParticles; + uint16_t mNumValid; + std::vector mParticles; + NiParticleModifierPtr mModifier; + NiParticleModifierPtr mCollider; + uint8_t mStaticTargetBound; void read(NIFStream* nif) override; void post(Reader& nif) override; - bool noAutoAdjust() const { return emitFlags & EmitFlag_NoAutoAdjust; } - bool emitAtVertex() const { return flags & BSPArrayController_AtVertex; } + bool noAutoAdjust() const { return mEmitFlags & EmitFlag_NoAutoAdjust; } + bool emitAtVertex() const { return mFlags & BSPArrayController_AtVertex; } }; using NiBSPArrayController = NiParticleSystemController; struct NiMaterialColorController : public NiPoint3InterpController { + enum class TargetColor + { + Ambient = 0, + Diffuse = 1, + Specular = 2, + Emissive = 3, + }; + NiPosDataPtr mData; - unsigned int mTargetColor; + TargetColor mTargetColor; void read(NIFStream* nif) override; void post(Reader& nif) override; }; - struct NiPathController : public Controller + struct NiPathController : public NiTimeController { - NiPosDataPtr posData; - NiFloatDataPtr floatData; - enum Flags { - Flag_OpenCurve = 0x020, - Flag_AllowFlip = 0x040, - Flag_Bank = 0x080, - Flag_ConstVelocity = 0x100, - Flag_Follow = 0x200, - Flag_FlipFollowAxis = 0x400 + Flag_CVDataNeedsUpdate = 0x01, + Flag_OpenCurve = 0x02, + Flag_AllowFlip = 0x04, + Flag_Bank = 0x08, + Flag_ConstVelocity = 0x10, + Flag_Follow = 0x20, + Flag_FlipFollowAxis = 0x40, }; - int bankDir; - float maxBankAngle, smoothing; - short followAxis; + uint16_t mPathFlags; + int32_t mBankDirection; + float mMaxBankAngle; + float mSmoothing; + uint16_t mFollowAxis; + NiPosDataPtr mPathData; + NiFloatDataPtr mPercentData; void read(NIFStream* nif) override; void post(Reader& nif) override; }; - struct NiLookAtController : public Controller + struct NiLookAtController : public NiTimeController { - NiAVObjectPtr target; - unsigned short lookAtFlags{ 0 }; + enum Flags + { + Flag_Flip = 0x1, + Flag_LookYAxis = 0x2, + Flag_LookZAxis = 0x4, + }; + + uint16_t mLookAtFlags{ 0 }; + NiAVObjectPtr mLookAt; void read(NIFStream* nif) override; void post(Reader& nif) override; }; - struct NiUVController : public Controller + struct NiUVController : public NiTimeController { - NiUVDataPtr data; - unsigned int uvSet; + NiUVDataPtr mData; + uint16_t mUvSet; void read(NIFStream* nif) override; void post(Reader& nif) override; @@ -281,7 +281,7 @@ namespace Nif struct NiFlipController : public NiFloatInterpController { - int mTexSlot; // NiTexturingProperty::TextureType + NiTexturingProperty::TextureType mTexSlot; float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources NiSourceTextureList mSources; @@ -292,110 +292,95 @@ namespace Nif struct NiTextureTransformController : public NiFloatInterpController { bool mShaderMap; - int mTexSlot; // NiTexturingProperty::TextureType - unsigned int mTransformMember; + NiTexturingProperty::TextureType mTexSlot; + uint32_t mTransformMember; NiFloatDataPtr mData; void read(NIFStream* nif) override; void post(Reader& nif) override; }; - struct bhkBlendController : public Controller + struct bhkBlendController : public NiTimeController { void read(NIFStream* nif) override; }; struct BSEffectShaderPropertyFloatController : public NiFloatInterpController { - unsigned int mControlledVariable; + uint32_t mControlledVariable; void read(NIFStream* nif) override; }; struct BSEffectShaderPropertyColorController : public NiPoint3InterpController { - unsigned int mControlledColor; + uint32_t mControlledColor; void read(NIFStream* nif) override; }; - struct NiControllerManager : public Controller + struct NiControllerManager : public NiTimeController { bool mCumulative; NiControllerSequenceList mSequences; NiDefaultAVObjectPalettePtr mObjectPalette; - void read(NIFStream* nif) override; - void post(Reader& nif) override; - }; - - struct NiInterpolator : public Record - { - }; - struct NiPoint3Interpolator : public NiInterpolator - { - osg::Vec3f defaultVal; - NiPosDataPtr data; void read(NIFStream* nif) override; void post(Reader& nif) override; }; - struct NiBoolInterpolator : public NiInterpolator + // Abstract + struct NiInterpolator : public Record { - char defaultVal; - NiBoolDataPtr data; - void read(NIFStream* nif) override; - void post(Reader& nif) override; }; - struct NiFloatInterpolator : public NiInterpolator + template + struct TypedNiInterpolator : public NiInterpolator { - float defaultVal; - NiFloatDataPtr data; - void read(NIFStream* nif) override; - void post(Reader& nif) override; - }; + T mDefaultValue; + DataPtr mData; - struct NiTransformInterpolator : public NiInterpolator - { - osg::Vec3f defaultPos; - osg::Quat defaultRot; - float defaultScale; - NiKeyframeDataPtr data; + void read(NIFStream* nif) override + { + nif->read(mDefaultValue); + mData.read(nif); + } - void read(NIFStream* nif) override; - void post(Reader& nif) override; + void post(Reader& nif) override { mData.post(nif); } }; - struct NiColorInterpolator : public NiInterpolator - { - osg::Vec4f defaultVal; - NiColorDataPtr data; - void read(NIFStream* nif) override; - void post(Reader& nif) override; - }; + using NiPoint3Interpolator = TypedNiInterpolator; + using NiBoolInterpolator = TypedNiInterpolator; + using NiFloatInterpolator = TypedNiInterpolator; + using NiTransformInterpolator = TypedNiInterpolator; + using NiColorInterpolator = TypedNiInterpolator; // Abstract struct NiBlendInterpolator : public NiInterpolator { + enum Flags + { + Flag_ManagerControlled = 0x1, + Flag_OnlyUseHighestWeight = 0x2, + }; + struct Item { NiInterpolatorPtr mInterpolator; float mWeight, mNormalizedWeight; - int mPriority; + int32_t mPriority; float mEaseSpinner; void read(NIFStream* nif); void post(Reader& nif); }; - bool mManagerControlled{ false }; - bool mOnlyUseHighestWeight{ false }; - unsigned short mArrayGrowBy{ 0 }; + uint8_t mFlags{ 0 }; + uint16_t mArrayGrowBy{ 0 }; float mWeightThreshold; - unsigned short mInterpCount; - unsigned short mSingleIndex; - int mHighPriority, mNextHighPriority; + uint16_t mInterpCount; + uint16_t mSingleIndex; + int32_t mHighPriority, mNextHighPriority; float mSingleTime; float mHighWeightsSum, mNextHighWeightsSum; float mHighEaseSpinner; @@ -406,31 +391,37 @@ namespace Nif void post(Reader& nif) override; }; - struct NiBlendBoolInterpolator : public NiBlendInterpolator + template + struct TypedNiBlendInterpolator : public NiBlendInterpolator { - char mValue; - void read(NIFStream* nif) override; - }; + T mValue; - struct NiBlendFloatInterpolator : public NiBlendInterpolator - { - float mValue; - void read(NIFStream* nif) override; - }; + void read(NIFStream* nif) override + { + NiBlendInterpolator::read(nif); - struct NiBlendPoint3Interpolator : public NiBlendInterpolator - { - osg::Vec3f mValue; - void read(NIFStream* nif) override; + nif->read(mValue); + } }; - struct NiBlendTransformInterpolator : public NiBlendInterpolator + template <> + struct TypedNiBlendInterpolator : public NiBlendInterpolator { - osg::Vec3f mPosValue; - osg::Quat mRotValue; - float mScaleValue; - void read(NIFStream* nif) override; + NiQuatTransform mValue; + + void read(NIFStream* nif) override + { + NiBlendInterpolator::read(nif); + + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109)) + nif->read(mValue); + } }; -} // Namespace + using NiBlendBoolInterpolator = TypedNiBlendInterpolator; + using NiBlendFloatInterpolator = TypedNiBlendInterpolator; + using NiBlendPoint3Interpolator = TypedNiBlendInterpolator; + using NiBlendTransformInterpolator = TypedNiBlendInterpolator; + +} #endif diff --git a/components/nif/data.cpp b/components/nif/data.cpp index a07f66d43f..528256c49b 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -528,7 +528,7 @@ namespace Nif void NiBoolData::read(NIFStream* nif) { - mKeyList = std::make_shared(); + mKeyList = std::make_shared(); mKeyList->read(nif); } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 849cbde7bd..6ec09c2f42 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -219,7 +219,7 @@ namespace Nif struct NiVisData : public Record { - // TODO: investigate possible use of ByteKeyMap + // TODO: investigate possible use of BoolKeyMap std::shared_ptr> mKeys; void read(NIFStream* nif) override; @@ -357,7 +357,8 @@ namespace Nif struct NiBoolData : public Record { - ByteKeyMapPtr mKeyList; + BoolKeyMapPtr mKeyList; + void read(NIFStream* nif) override; }; diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index bbd06cb048..604cf92c33 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -152,13 +152,13 @@ namespace Nif using Vector3KeyMap = KeyMapT>; using Vector4KeyMap = KeyMapT>; using QuaternionKeyMap = KeyMapT>; - using ByteKeyMap = KeyMapT>; + using BoolKeyMap = KeyMapT>; using FloatKeyMapPtr = std::shared_ptr; using Vector3KeyMapPtr = std::shared_ptr; using Vector4KeyMapPtr = std::shared_ptr; using QuaternionKeyMapPtr = std::shared_ptr; - using ByteKeyMapPtr = std::shared_ptr; + using BoolKeyMapPtr = std::shared_ptr; } // Namespace #endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index e33dc4f7b1..2eba746ccf 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -137,6 +137,22 @@ namespace Nif read(transform.mScale); } + template <> + void NIFStream::read(NiQuatTransform& transform) + { + read(transform.mTranslation); + read(transform.mRotation); + read(transform.mScale); + if (getVersion() >= generateVersion(10, 1, 0, 110)) + return; + if (!get()) + transform.mTranslation = osg::Vec3f(); + if (!get()) + transform.mRotation = osg::Quat(); + if (!get()) + transform.mScale = 1.f; + } + template <> void NIFStream::read(bool& data) { @@ -197,6 +213,12 @@ namespace Nif readRange(*this, dest, size); } + template <> + void NIFStream::read(NiQuatTransform* dest, size_t size) + { + readRange(*this, dest, size); + } + template <> void NIFStream::read(bool* dest, size_t size) { diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index f4c35e6625..8a4ec847fc 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -149,7 +149,6 @@ namespace Nif /// DEPRECATED: Use read() or get() char getChar() { return get(); } - short getShort() { return get(); } unsigned short getUShort() { return get(); } int getInt() { return get(); } unsigned int getUInt() { return get(); } @@ -157,10 +156,6 @@ namespace Nif osg::Vec2f getVector2() { return get(); } osg::Vec3f getVector3() { return get(); } osg::Vec4f getVector4() { return get(); } - Matrix3 getMatrix3() { return get(); } - osg::Quat getQuaternion() { return get(); } - bool getBoolean() { return get(); } - std::string getString() { return get(); } }; template <> @@ -178,6 +173,8 @@ namespace Nif template <> void NIFStream::read(NiTransform& transform); template <> + void NIFStream::read(NiQuatTransform& transform); + template <> void NIFStream::read(bool& data); template <> void NIFStream::read(std::string& str); @@ -197,6 +194,8 @@ namespace Nif template <> void NIFStream::read(NiTransform* dest, size_t size); template <> + void NIFStream::read(NiQuatTransform* dest, size_t size); + template <> void NIFStream::read(bool* dest, size_t size); template <> void NIFStream::read(std::string* dest, size_t size); diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 3b2a4c1578..b294756f69 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -25,6 +25,7 @@ #define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP #include +#include #include // Common types used in NIF files @@ -80,5 +81,30 @@ namespace Nif } }; + struct NiQuatTransform + { + osg::Vec3f mTranslation; + osg::Quat mRotation; + float mScale; + + osg::Matrixf toMatrix() const + { + osg::Matrixf transform(mRotation); + transform.setTrans(mTranslation); + for (int i = 0; i < 3; i++) + transform(i, i) *= mScale; + + return transform; + } + + bool isIdentity() const { return mTranslation == osg::Vec3f() && mRotation == osg::Quat() && mScale == 1.f; } + + static const NiQuatTransform& getIdentity() + { + static const NiQuatTransform identity = { osg::Vec3f(), osg::Quat(), 1.f }; + return identity; + } + }; + } // Namespace #endif diff --git a/components/nif/node.cpp b/components/nif/node.cpp index d7b6c3945b..a9e4f183b2 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -25,7 +25,7 @@ namespace Nif case BOX_BV: { box.center = nif->getVector3(); - box.axes = nif->getMatrix3(); + nif->read(box.axes); box.extents = nif->getVector3(); break; } @@ -153,8 +153,8 @@ namespace Nif if (nif->getVersion() < NIFStream::generateVersion(10, 0, 1, 0)) return; unsigned int num = 0; - if (nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 3)) - num = nif->getBoolean(); // Has Shader + if (nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 3) && nif->get()) + num = 1; else if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5)) num = nif->getUInt(); @@ -163,7 +163,7 @@ namespace Nif if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5)) active = nif->getUInt(); if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS) - needsUpdate = nif->getBoolean(); + nif->read(needsUpdate); } void NiGeometry::read(NIFStream* nif) @@ -210,7 +210,7 @@ namespace Nif nearDist = nif->getFloat(); farDist = nif->getFloat(); if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) - orthographic = nif->getBoolean(); + nif->read(orthographic); vleft = nif->getFloat(); vright = nif->getFloat(); vtop = nif->getFloat(); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 5590877294..328498210a 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -9,7 +9,7 @@ namespace Nif struct NiParticleModifier : public Record { NiParticleModifierPtr mNext; - ControllerPtr mController; + NiTimeControllerPtr mController; void read(NIFStream* nif) override; void post(Reader& nif) override; diff --git a/components/nif/property.cpp b/components/nif/property.cpp index 39a7cbff23..3569fd55cc 100644 --- a/components/nif/property.cpp +++ b/components/nif/property.cpp @@ -8,7 +8,7 @@ namespace Nif void NiTexturingProperty::Texture::read(NIFStream* nif) { - inUse = nif->getBoolean(); + nif->read(inUse); if (!inUse) return; @@ -36,7 +36,7 @@ namespace Nif nif->skip(2); // Unknown short else if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) { - if (nif->getBoolean()) // Has texture transform + if (nif->get()) // Has texture transform { nif->getVector2(); // UV translation nif->getVector2(); // UV scale diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 90f1e9ffb5..d9574f31d6 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -79,7 +79,7 @@ namespace Nif * 5 - Bump map texture * 6 - Decal texture */ - enum TextureType + enum TextureType : uint32_t { BaseTexture = 0, DarkTexture = 1, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 9f75b31d74..627e59cf0d 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -116,7 +116,7 @@ namespace Nif struct NiUVData; struct NiPosData; struct NiVisData; - struct Controller; + struct NiTimeController; struct NiObjectNET; struct NiSkinData; struct NiFloatData; @@ -157,7 +157,7 @@ namespace Nif using NiUVDataPtr = RecordPtrT; using NiPosDataPtr = RecordPtrT; using NiVisDataPtr = RecordPtrT; - using ControllerPtr = RecordPtrT; + using NiTimeControllerPtr = RecordPtrT; using NiObjectNETPtr = RecordPtrT; using NiSkinDataPtr = RecordPtrT; using NiMorphDataPtr = RecordPtrT; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index bc207e52bf..59d5cd61d8 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -255,7 +255,7 @@ namespace NifBullet if (node.recType == Nif::RC_NiCollisionSwitch && !node.collisionActive()) return; - for (Nif::ControllerPtr ctrl = node.mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = node.mController; !ctrl.empty(); ctrl = ctrl->mNext) { if (args.mAnimated) break; diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 20a3ee92e4..54e9e2bb16 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -15,11 +15,11 @@ namespace NifOsg { - ControllerFunction::ControllerFunction(const Nif::Controller* ctrl) - : mFrequency(ctrl->frequency) - , mPhase(ctrl->phase) - , mStartTime(ctrl->timeStart) - , mStopTime(ctrl->timeStop) + ControllerFunction::ControllerFunction(const Nif::NiTimeController* ctrl) + : mFrequency(ctrl->mFrequency) + , mPhase(ctrl->mPhase) + , mStartTime(ctrl->mTimeStart) + , mStopTime(ctrl->mTimeStop) , mExtrapolationMode(ctrl->extrapolationMode()) { } @@ -31,7 +31,7 @@ namespace NifOsg return time; switch (mExtrapolationMode) { - case Nif::Controller::ExtrapolationMode::Cycle: + case Nif::NiTimeController::ExtrapolationMode::Cycle: { float delta = mStopTime - mStartTime; if (delta <= 0) @@ -40,7 +40,7 @@ namespace NifOsg float remainder = (cycles - std::floor(cycles)) * delta; return mStartTime + remainder; } - case Nif::Controller::ExtrapolationMode::Reverse: + case Nif::NiTimeController::ExtrapolationMode::Reverse: { float delta = mStopTime - mStartTime; if (delta <= 0) @@ -55,7 +55,7 @@ namespace NifOsg return mStopTime - remainder; } - case Nif::Controller::ExtrapolationMode::Constant: + case Nif::NiTimeController::ExtrapolationMode::Constant: default: return std::clamp(time, mStartTime, mStopTime); } @@ -90,21 +90,23 @@ namespace NifOsg { const Nif::NiTransformInterpolator* interp = static_cast(keyctrl->mInterpolator.getPtr()); - if (!interp->data.empty()) + const Nif::NiQuatTransform& defaultTransform = interp->mDefaultValue; + if (!interp->mData.empty()) { - mRotations = QuaternionInterpolator(interp->data->mRotations, interp->defaultRot); - mXRotations = FloatInterpolator(interp->data->mXRotations); - mYRotations = FloatInterpolator(interp->data->mYRotations); - mZRotations = FloatInterpolator(interp->data->mZRotations); - mTranslations = Vec3Interpolator(interp->data->mTranslations, interp->defaultPos); - mScales = FloatInterpolator(interp->data->mScales, interp->defaultScale); - mAxisOrder = interp->data->mAxisOrder; + mRotations = QuaternionInterpolator(interp->mData->mRotations, defaultTransform.mRotation); + mXRotations = FloatInterpolator(interp->mData->mXRotations); + mYRotations = FloatInterpolator(interp->mData->mYRotations); + mZRotations = FloatInterpolator(interp->mData->mZRotations); + mTranslations = Vec3Interpolator(interp->mData->mTranslations, defaultTransform.mTranslation); + mScales = FloatInterpolator(interp->mData->mScales, defaultTransform.mScale); + + mAxisOrder = interp->mData->mAxisOrder; } else { - mRotations = QuaternionInterpolator(Nif::QuaternionKeyMapPtr(), interp->defaultRot); - mTranslations = Vec3Interpolator(Nif::Vector3KeyMapPtr(), interp->defaultPos); - mScales = FloatInterpolator(Nif::FloatKeyMapPtr(), interp->defaultScale); + mRotations = QuaternionInterpolator(Nif::QuaternionKeyMapPtr(), defaultTransform.mRotation); + mTranslations = Vec3Interpolator(Nif::Vector3KeyMapPtr(), defaultTransform.mTranslation); + mScales = FloatInterpolator(Nif::FloatKeyMapPtr(), defaultTransform.mScale); } } } @@ -117,6 +119,7 @@ namespace NifOsg mZRotations = FloatInterpolator(keydata->mZRotations); mTranslations = Vec3Interpolator(keydata->mTranslations); mScales = FloatInterpolator(keydata->mScales, 1.f); + mAxisOrder = keydata->mAxisOrder; } } @@ -177,11 +180,11 @@ namespace NifOsg else node->setRotation(node->mRotationScale); - if (!mScales.empty()) - node->setScale(mScales.interpKey(time)); - if (!mTranslations.empty()) node->setTranslation(mTranslations.interpKey(time)); + + if (!mScales.empty()) + node->setScale(mScales.interpKey(time)); } traverse(node, nv); @@ -251,9 +254,7 @@ namespace NifOsg } } - UVController::UVController() {} - - UVController::UVController(const Nif::NiUVData* data, const std::set& textureUnits) + UVController::UVController(const Nif::NiUVData* data, const std::set& textureUnits) : mUTrans(data->mKeyList[0], 0.f) , mVTrans(data->mKeyList[1], 0.f) , mUScale(data->mKeyList[2], 1.f) @@ -277,8 +278,8 @@ namespace NifOsg void UVController::setDefaults(osg::StateSet* stateset) { osg::ref_ptr texMat(new osg::TexMat); - for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) - stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + for (unsigned int unit : mTextureUnits) + stateset->setTextureAttributeAndModes(unit, texMat, osg::StateAttribute::ON); } void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv) @@ -314,9 +315,10 @@ namespace NifOsg { if (!ctrl->mInterpolator.empty()) { - if (ctrl->mInterpolator->recType == Nif::RC_NiBoolInterpolator) - mInterpolator - = ByteInterpolator(static_cast(ctrl->mInterpolator.getPtr())); + if (ctrl->mInterpolator->recType != Nif::RC_NiBoolInterpolator) + return; + + mInterpolator = { static_cast(ctrl->mInterpolator.getPtr()) }; } else if (!ctrl->mData.empty()) mData = ctrl->mData->mKeys; @@ -444,7 +446,7 @@ namespace NifOsg MaterialColorController::MaterialColorController( const Nif::NiMaterialColorController* ctrl, const osg::Material* baseMaterial) - : mTargetColor(static_cast(ctrl->mTargetColor)) + : mTargetColor(ctrl->mTargetColor) , mBaseMaterial(baseMaterial) { if (!ctrl->mInterpolator.empty()) @@ -477,30 +479,31 @@ namespace NifOsg { osg::Vec3f value = mData.interpKey(getInputValue(nv)); osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + using TargetColor = Nif::NiMaterialColorController::TargetColor; switch (mTargetColor) { - case Diffuse: + case TargetColor::Diffuse: { osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); break; } - case Specular: + case TargetColor::Specular: { osg::Vec4f specular = mat->getSpecular(osg::Material::FRONT_AND_BACK); specular.set(value.x(), value.y(), value.z(), specular.a()); mat->setSpecular(osg::Material::FRONT_AND_BACK, specular); break; } - case Emissive: + case TargetColor::Emissive: { osg::Vec4f emissive = mat->getEmission(osg::Material::FRONT_AND_BACK); emissive.set(value.x(), value.y(), value.z(), emissive.a()); mat->setEmission(osg::Material::FRONT_AND_BACK, emissive); break; } - case Ambient: + case TargetColor::Ambient: default: { osg::Vec4f ambient = mat->getAmbient(osg::Material::FRONT_AND_BACK); @@ -552,14 +555,8 @@ namespace NifOsg } ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController* ctrl) - : mEmitStart(ctrl->startTime) - , mEmitStop(ctrl->stopTime) - { - } - - ParticleSystemController::ParticleSystemController() - : mEmitStart(0.f) - , mEmitStop(0.f) + : mEmitStart(ctrl->mEmitStartTime) + , mEmitStop(ctrl->mEmitStopTime) { } @@ -594,9 +591,9 @@ namespace NifOsg } PathController::PathController(const Nif::NiPathController* ctrl) - : mPath(ctrl->posData->mKeyList, osg::Vec3f()) - , mPercent(ctrl->floatData->mKeyList, 1.f) - , mFlags(ctrl->flags) + : mPath(ctrl->mPathData->mKeyList, osg::Vec3f()) + , mPercent(ctrl->mPercentData->mKeyList, 1.f) + , mFlags(ctrl->mPathFlags) { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 90e87366e1..df6fdb2a24 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -63,18 +63,17 @@ namespace NifOsg ValueInterpolator() = default; template , - std::is_same, std::is_same, - std::is_same, std::is_same>, - std::is_same>, + typename = std::enable_if_t< + std::conjunction_v, std::is_same, + std::is_same, std::is_same>, + std::is_same>, T>> ValueInterpolator(const T* interpolator) - : mDefaultVal(interpolator->defaultVal) + : mDefaultVal(interpolator->mDefaultValue) { - if (interpolator->data.empty()) + if (interpolator->mData.empty()) return; - mKeys = interpolator->data->mKeyList; + mKeys = interpolator->mData->mKeyList; if (mKeys) { mLastLowKey = mKeys->mKeys.end(); @@ -182,7 +181,7 @@ namespace NifOsg using FloatInterpolator = ValueInterpolator; using Vec3Interpolator = ValueInterpolator; using Vec4Interpolator = ValueInterpolator; - using ByteInterpolator = ValueInterpolator; + using BoolInterpolator = ValueInterpolator; class ControllerFunction : public SceneUtil::ControllerFunction { @@ -191,10 +190,10 @@ namespace NifOsg float mPhase; float mStartTime; float mStopTime; - Nif::Controller::ExtrapolationMode mExtrapolationMode; + Nif::NiTimeController::ExtrapolationMode mExtrapolationMode; public: - ControllerFunction(const Nif::Controller* ctrl); + ControllerFunction(const Nif::NiTimeController* ctrl); float calculate(float value) const override; @@ -262,9 +261,9 @@ namespace NifOsg class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { public: - UVController(); + UVController() = default; UVController(const UVController&, const osg::CopyOp&); - UVController(const Nif::NiUVData* data, const std::set& textureUnits); + UVController(const Nif::NiUVData* data, const std::set& textureUnits); META_Object(NifOsg, UVController) @@ -276,14 +275,14 @@ namespace NifOsg FloatInterpolator mVTrans; FloatInterpolator mUScale; FloatInterpolator mVScale; - std::set mTextureUnits; + std::set mTextureUnits; }; class VisController : public SceneUtil::NodeCallback, public SceneUtil::Controller { private: std::shared_ptr> mData; - ByteInterpolator mInterpolator; + BoolInterpolator mInterpolator; unsigned int mMask{ 0u }; bool calculate(float time) const; @@ -336,13 +335,6 @@ namespace NifOsg class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { public: - enum TargetColor - { - Ambient = 0, - Diffuse = 1, - Specular = 2, - Emissive = 3 - }; MaterialColorController(const Nif::NiMaterialColorController* ctrl, const osg::Material* baseMaterial); MaterialColorController(); MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop); @@ -355,7 +347,7 @@ namespace NifOsg private: Vec3Interpolator mData; - TargetColor mTargetColor = Ambient; + Nif::NiMaterialColorController::TargetColor mTargetColor; osg::ref_ptr mBaseMaterial; }; @@ -386,7 +378,7 @@ namespace NifOsg { public: ParticleSystemController(const Nif::NiParticleSystemController* ctrl); - ParticleSystemController(); + ParticleSystemController() = default; ParticleSystemController(const ParticleSystemController& copy, const osg::CopyOp& copyop); META_Object(NifOsg, ParticleSystemController) @@ -394,8 +386,8 @@ namespace NifOsg void operator()(osgParticle::ParticleProcessor* node, osg::NodeVisitor* nv); private: - float mEmitStart; - float mEmitStop; + float mEmitStart{ 0.f }; + float mEmitStop{ 0.f }; }; class PathController : public SceneUtil::NodeCallback, diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9683de9a23..fc8da57dbd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -293,8 +293,8 @@ namespace NifOsg auto textKeyExtraData = static_cast(extraList[0].getPtr()); extractTextKeys(textKeyExtraData, target.mTextKeys); - Nif::ControllerPtr ctrl = seq->mController; - for (size_t i = 1; i < extraList.size() && !ctrl.empty(); i++, (ctrl = ctrl->next)) + Nif::NiTimeControllerPtr ctrl = seq->mController; + for (size_t i = 1; i < extraList.size() && !ctrl.empty(); i++, (ctrl = ctrl->mNext)) { Nif::ExtraPtr extra = extraList[i]; if (extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController) @@ -449,7 +449,7 @@ namespace NifOsg animflags, hasStencilProperty); } - static void setupController(const Nif::Controller* ctrl, SceneUtil::Controller* toSetup, int animflags) + static void setupController(const Nif::NiTimeController* ctrl, SceneUtil::Controller* toSetup, int animflags) { bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; if (autoPlay) @@ -725,7 +725,7 @@ namespace NifOsg if (nifNode->isHidden()) { bool hasVisController = false; - for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext) { hasVisController |= (ctrl->recType == Nif::RC_NiVisController); if (hasVisController) @@ -858,25 +858,24 @@ namespace NifOsg SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext) { if (!ctrl->isActive()) continue; if (ctrl->recType == Nif::RC_NiUVController) { const Nif::NiUVController* niuvctrl = static_cast(ctrl.getPtr()); - if (niuvctrl->data.empty()) + if (niuvctrl->mData.empty()) continue; - const unsigned int uvSet = niuvctrl->uvSet; - std::set texUnits; - // UVController should work only for textures which use a given UV Set, usually 0. + std::set texUnits; + // UVController should only work for textures which use the given UV Set. for (unsigned int i = 0; i < boundTextures.size(); ++i) { - if (boundTextures[i] == uvSet) + if (boundTextures[i] == niuvctrl->mUvSet) texUnits.insert(i); } - osg::ref_ptr uvctrl = new UVController(niuvctrl->data.getPtr(), texUnits); + osg::ref_ptr uvctrl = new UVController(niuvctrl->mData.getPtr(), texUnits); setupController(niuvctrl, uvctrl, animflags); composite->addController(uvctrl); } @@ -885,7 +884,7 @@ namespace NifOsg void handleNodeControllers(const Nif::NiAVObject* nifNode, osg::Node* node, int animflags, bool& isAnimated) { - for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext) { if (!ctrl->isActive()) continue; @@ -908,7 +907,7 @@ namespace NifOsg else if (ctrl->recType == Nif::RC_NiPathController) { const Nif::NiPathController* path = static_cast(ctrl.getPtr()); - if (path->posData.empty() || path->floatData.empty()) + if (path->mPathData.empty() || path->mPercentData.empty()) continue; osg::ref_ptr callback(new PathController(path)); setupController(path, callback, animflags); @@ -963,7 +962,7 @@ namespace NifOsg void handleMaterialControllers(const Nif::Property* materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags, const osg::Material* baseMaterial) { - for (Nif::ControllerPtr ctrl = materialProperty->mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = materialProperty->mController; !ctrl.empty(); ctrl = ctrl->mNext) { if (!ctrl->isActive()) continue; @@ -988,18 +987,16 @@ namespace NifOsg { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); - if (matctrl->mData.empty() && matctrl->mInterpolator.empty()) + Nif::NiInterpolatorPtr interp = matctrl->mInterpolator; + if (matctrl->mData.empty() && interp.empty()) continue; - auto targetColor = static_cast(matctrl->mTargetColor); if (mVersion <= Nif::NIFFile::VER_MW - && targetColor == MaterialColorController::TargetColor::Specular) + && matctrl->mTargetColor == Nif::NiMaterialColorController::TargetColor::Specular) continue; - if (!matctrl->mInterpolator.empty() - && matctrl->mInterpolator->recType != Nif::RC_NiPoint3Interpolator) + if (!interp.empty() && interp->recType != Nif::RC_NiPoint3Interpolator) { - Log(Debug::Error) - << "Unsupported interpolator type for NiMaterialColorController " << matctrl->recIndex - << " in " << mFilename << ": " << matctrl->mInterpolator->recName; + Log(Debug::Error) << "Unsupported interpolator type for NiMaterialColorController " + << matctrl->recIndex << " in " << mFilename << ": " << interp->recName; continue; } osg::ref_ptr osgctrl = new MaterialColorController(matctrl, baseMaterial); @@ -1014,7 +1011,7 @@ namespace NifOsg void handleTextureControllers(const Nif::Property* texProperty, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, osg::StateSet* stateset, int animflags) { - for (Nif::ControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->mNext) { if (!ctrl->isActive()) continue; @@ -1063,7 +1060,7 @@ namespace NifOsg } } - void handleParticlePrograms(Nif::NiParticleModifierPtr affectors, Nif::NiParticleModifierPtr colliders, + void handleParticlePrograms(Nif::NiParticleModifierPtr modifier, Nif::NiParticleModifierPtr collider, osg::Group* attachTo, osgParticle::ParticleSystem* partsys, osgParticle::ParticleProcessor::ReferenceFrame rf) { @@ -1071,50 +1068,50 @@ namespace NifOsg attachTo->addChild(program); program->setParticleSystem(partsys); program->setReferenceFrame(rf); - for (; !affectors.empty(); affectors = affectors->mNext) + for (; !modifier.empty(); modifier = modifier->mNext) { - if (affectors->recType == Nif::RC_NiParticleGrowFade) + if (modifier->recType == Nif::RC_NiParticleGrowFade) { - const Nif::NiParticleGrowFade* gf = static_cast(affectors.getPtr()); + const Nif::NiParticleGrowFade* gf = static_cast(modifier.getPtr()); program->addOperator(new GrowFadeAffector(gf->mGrowTime, gf->mFadeTime)); } - else if (affectors->recType == Nif::RC_NiGravity) + else if (modifier->recType == Nif::RC_NiGravity) { - const Nif::NiGravity* gr = static_cast(affectors.getPtr()); + const Nif::NiGravity* gr = static_cast(modifier.getPtr()); program->addOperator(new GravityAffector(gr)); } - else if (affectors->recType == Nif::RC_NiParticleColorModifier) + else if (modifier->recType == Nif::RC_NiParticleColorModifier) { const Nif::NiParticleColorModifier* cl - = static_cast(affectors.getPtr()); + = static_cast(modifier.getPtr()); if (cl->mData.empty()) continue; const Nif::NiColorData* clrdata = cl->mData.getPtr(); program->addOperator(new ParticleColorAffector(clrdata)); } - else if (affectors->recType == Nif::RC_NiParticleRotation) + else if (modifier->recType == Nif::RC_NiParticleRotation) { // unused } else - Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename; + Log(Debug::Info) << "Unhandled particle modifier " << modifier->recName << " in " << mFilename; } - for (; !colliders.empty(); colliders = colliders->mNext) + for (; !collider.empty(); collider = collider->mNext) { - if (colliders->recType == Nif::RC_NiPlanarCollider) + if (collider->recType == Nif::RC_NiPlanarCollider) { const Nif::NiPlanarCollider* planarcollider - = static_cast(colliders.getPtr()); + = static_cast(collider.getPtr()); program->addOperator(new PlanarCollider(planarcollider)); } - else if (colliders->recType == Nif::RC_NiSphericalCollider) + else if (collider->recType == Nif::RC_NiSphericalCollider) { const Nif::NiSphericalCollider* sphericalcollider - = static_cast(colliders.getPtr()); + = static_cast(collider.getPtr()); program->addOperator(new SphericalCollider(sphericalcollider)); } else - Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename; + Log(Debug::Info) << "Unhandled particle collider " << collider->recName << " in " << mFilename; } } @@ -1126,7 +1123,7 @@ namespace NifOsg auto particleNode = static_cast(nifNode); if (particleNode->data.empty() || particleNode->data->recType != Nif::RC_NiParticlesData) { - partsys->setQuota(partctrl->numParticles); + partsys->setQuota(partctrl->mParticles.size()); return; } @@ -1136,35 +1133,35 @@ namespace NifOsg osg::BoundingBox box; int i = 0; - for (const auto& particle : partctrl->particles) + for (const auto& particle : partctrl->mParticles) { if (i++ >= particledata->mActiveCount) break; - if (particle.lifespan <= 0) + if (particle.mLifespan <= 0) continue; - if (particle.vertex >= particledata->mVertices.size()) + if (particle.mCode >= particledata->mVertices.size()) continue; - ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime)); + ParticleAgeSetter particletemplate(std::max(0.f, particle.mAge)); osgParticle::Particle* created = partsys->createParticle(&particletemplate); - created->setLifeTime(particle.lifespan); + created->setLifeTime(particle.mLifespan); // Note this position and velocity is not correct for a particle system with absolute reference frame, // which can not be done in this loader since we are not attached to the scene yet. Will be fixed up // post-load in the SceneManager. - created->setVelocity(particle.velocity); - const osg::Vec3f& position = particledata->mVertices[particle.vertex]; + created->setVelocity(particle.mVelocity); + const osg::Vec3f& position = particledata->mVertices[particle.mCode]; created->setPosition(position); - created->setColorRange(osgParticle::rangev4(partctrl->color, partctrl->color)); + created->setColorRange(osgParticle::rangev4(partctrl->mInitialColor, partctrl->mInitialColor)); created->setAlphaRange(osgParticle::rangef(1.f, 1.f)); - float size = partctrl->size; - if (particle.vertex < particledata->mSizes.size()) - size *= particledata->mSizes[particle.vertex]; + float size = partctrl->mInitialSize; + if (particle.mCode < particledata->mSizes.size()) + size *= particledata->mSizes[particle.mCode]; created->setSizeRange(osgParticle::rangef(size, size)); box.expandBy(osg::BoundingSphere(position, size)); @@ -1181,39 +1178,39 @@ namespace NifOsg std::vector targets; if (partctrl->recType == Nif::RC_NiBSPArrayController && !partctrl->emitAtVertex()) { - getAllNiNodes(partctrl->emitter.getPtr(), targets); + getAllNiNodes(partctrl->mEmitter.getPtr(), targets); } osg::ref_ptr emitter = new Emitter(targets); osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter; if (partctrl->noAutoAdjust()) - counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate); - else if (partctrl->lifetime == 0 && partctrl->lifetimeRandom == 0) + counter->setNumberOfParticlesPerSecondToCreate(partctrl->mBirthRate); + else if (partctrl->mLifetime == 0 && partctrl->mLifetimeVariation == 0) counter->setNumberOfParticlesPerSecondToCreate(0); else counter->setNumberOfParticlesPerSecondToCreate( - partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom / 2)); + partctrl->mParticles.size() / (partctrl->mLifetime + partctrl->mLifetimeVariation / 2)); emitter->setCounter(counter); - ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom * 0.5f, - partctrl->velocity + partctrl->velocityRandom * 0.5f, partctrl->horizontalDir, - partctrl->horizontalAngle, partctrl->verticalDir, partctrl->verticalAngle, partctrl->lifetime, - partctrl->lifetimeRandom); + ParticleShooter* shooter = new ParticleShooter(partctrl->mSpeed - partctrl->mSpeedVariation * 0.5f, + partctrl->mSpeed + partctrl->mSpeedVariation * 0.5f, partctrl->mPlanarAngle, + partctrl->mPlanarAngleVariation, partctrl->mDeclination, partctrl->mDeclinationVariation, + partctrl->mLifetime, partctrl->mLifetimeVariation); emitter->setShooter(shooter); - emitter->setFlags(partctrl->flags); + emitter->setFlags(partctrl->mFlags); if (partctrl->recType == Nif::RC_NiBSPArrayController && partctrl->emitAtVertex()) { - emitter->setGeometryEmitterTarget(partctrl->emitter->recIndex); + emitter->setGeometryEmitterTarget(partctrl->mEmitter->recIndex); } else { osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer; - placer->setXRange(-partctrl->offsetRandom.x() / 2.f, partctrl->offsetRandom.x() / 2.f); - placer->setYRange(-partctrl->offsetRandom.y() / 2.f, partctrl->offsetRandom.y() / 2.f); - placer->setZRange(-partctrl->offsetRandom.z() / 2.f, partctrl->offsetRandom.z() / 2.f); + placer->setXRange(-partctrl->mEmitterDimensions.x() / 2.f, partctrl->mEmitterDimensions.x() / 2.f); + placer->setYRange(-partctrl->mEmitterDimensions.y() / 2.f, partctrl->mEmitterDimensions.y() / 2.f); + placer->setZRange(-partctrl->mEmitterDimensions.z() / 2.f, partctrl->mEmitterDimensions.z() / 2.f); emitter->setPlacer(placer); } @@ -1254,7 +1251,7 @@ namespace NifOsg partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT); const Nif::NiParticleSystemController* partctrl = nullptr; - for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext) { if (!ctrl->isActive()) continue; @@ -1282,11 +1279,13 @@ namespace NifOsg handleParticleInitialState(nifNode, partsys, partctrl); - partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size)); - partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(partctrl->color, partctrl->color)); + partsys->getDefaultParticleTemplate().setSizeRange( + osgParticle::rangef(partctrl->mInitialSize, partctrl->mInitialSize)); + partsys->getDefaultParticleTemplate().setColorRange( + osgParticle::rangev4(partctrl->mInitialColor, partctrl->mInitialColor)); partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f)); - if (!partctrl->emitter.empty()) + if (!partctrl->mEmitter.empty()) { osg::ref_ptr emitter = handleParticleEmitter(partctrl); emitter->setParticleSystem(partsys); @@ -1295,7 +1294,7 @@ namespace NifOsg // The emitter node may not actually be handled yet, so let's delay attaching the emitter to a later // moment. If the emitter node is placed later than the particle node, it'll have a single frame delay // in particle processing. But that shouldn't be a game-breaking issue. - mEmitterQueue.emplace_back(partctrl->emitter->recIndex, emitter); + mEmitterQueue.emplace_back(partctrl->mEmitter->recIndex, emitter); osg::ref_ptr callback(new ParticleSystemController(partctrl)); setupController(partctrl, callback, animflags); @@ -1312,16 +1311,16 @@ namespace NifOsg partsys->update(0.0, nv); } - // affectors should be attached *after* the emitter in the scene graph for correct update order + // modifiers should be attached *after* the emitter in the scene graph for correct update order // attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct // localToWorldMatrix for transforming to particle space - handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf); + handleParticlePrograms(partctrl->mModifier, partctrl->mCollider, parentNode, partsys.get(), rf); std::vector drawableProps; collectDrawableProperties(nifNode, parent, drawableProps); applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); - // particle system updater (after the emitters and affectors in the scene graph) + // particle system updater (after the emitters and modifiers in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other // way osg::ref_ptr updater = new osgParticle::ParticleSystemUpdater; @@ -1485,7 +1484,7 @@ namespace NifOsg if (geom->empty()) return; osg::ref_ptr drawable; - for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext) { if (!ctrl->isActive()) continue;