From dddfbf806b9913b24cc38a70fb6477428a5dec6c Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 12:07:48 +0300 Subject: [PATCH 01/22] Move particle geometry, add NiPSysData and NiPSysEmitterCtlrData These record types are currently unreachable, might get tweaks later --- components/nif/data.cpp | 81 ++++++-------------------------- components/nif/data.hpp | 26 ----------- components/nif/niffile.cpp | 20 +++++--- components/nif/particle.cpp | 93 +++++++++++++++++++++++++++++++++++++ components/nif/particle.hpp | 45 ++++++++++++++++++ components/nif/record.hpp | 2 + 6 files changed, 167 insertions(+), 100 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index c7f9e71fda..34ec3b2831 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -13,8 +13,8 @@ namespace Nif if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 114)) nif->read(mGroupId); - // Note: has special meaning for NiPSysData (unimplemented) nif->read(mNumVertices); + bool hasData = recType != RC_NiPSysData || nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO3; if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) { @@ -22,7 +22,7 @@ namespace Nif nif->read(mCompressFlags); } - if (nif->get()) + if (nif->get() && hasData) nif->readVector(mVertices, mNumVertices); if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0)) @@ -34,7 +34,7 @@ namespace Nif nif->read(mMaterialHash); } - if (nif->get()) + if (nif->get() && hasData) { nif->readVector(mNormals, mNumVertices); if (mDataFlags & DataFlag_HasTangents) @@ -46,7 +46,7 @@ namespace Nif nif->read(mBoundingSphere); - if (nif->get()) + if (nif->get() && hasData) nif->readVector(mColors, mNumVertices); if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0)) @@ -64,13 +64,16 @@ namespace Nif else if (!nif->get()) numUVs = 0; - mUVList.resize(numUVs); - for (std::vector& list : mUVList) + if (hasData) { - nif->readVector(list, mNumVertices); - // flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin - for (osg::Vec2f& uv : list) - uv.y() = 1.f - uv.y(); + mUVList.resize(numUVs); + for (std::vector& list : mUVList) + { + nif->readVector(list, mNumVertices); + // flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin + for (osg::Vec2f& uv : list) + uv.y() = 1.f - uv.y(); + } } if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0)) @@ -146,64 +149,6 @@ namespace Nif mLines.shrink_to_fit(); } - void NiParticlesData::read(NIFStream* nif) - { - NiGeometryData::read(nif); - - // Should always match the number of vertices in theory, but doesn't: - // see mist.nif in Mistify mod (https://www.nexusmods.com/morrowind/mods/48112). - if (nif->getVersion() <= NIFFile::NIFVersion::VER_MW) - nif->read(mNumParticles); - bool isBs202 = nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() != 0; - - bool numRadii = 1; - if (nif->getVersion() > NIFStream::generateVersion(10, 0, 1, 0)) - numRadii = (nif->get() && !isBs202) ? mNumVertices : 0; - nif->readVector(mRadii, numRadii); - nif->read(mActiveCount); - if (nif->get() && !isBs202) - nif->readVector(mSizes, mNumVertices); - - if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0)) - { - if (nif->get() && !isBs202) - nif->readVector(mRotations, mNumVertices); - if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 4)) - { - if (nif->get() && !isBs202) - nif->readVector(mRotationAngles, mNumVertices); - if (nif->get() && !isBs202) - nif->readVector(mRotationAxes, mNumVertices); - if (isBs202) - { - nif->read(mHasTextureIndices); - uint32_t numSubtextureOffsets; - if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3) - numSubtextureOffsets = nif->get(); - else - nif->read(numSubtextureOffsets); - nif->readVector(mSubtextureOffsets, numSubtextureOffsets); - if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3) - { - nif->read(mAspectRatio); - nif->read(mAspectFlags); - nif->read(mAspectRatio2); - nif->read(mAspectSpeed); - nif->read(mAspectSpeed2); - } - } - } - } - } - - void NiRotatingParticlesData::read(NIFStream* nif) - { - NiParticlesData::read(nif); - - if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0) && nif->get()) - nif->readVector(mRotations, mNumVertices); - } - void NiPosData::read(NIFStream* nif) { mKeyList = std::make_shared(); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 1596579fdd..efab514223 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -70,32 +70,6 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiParticlesData : public NiGeometryData - { - uint16_t mNumParticles{ 0 }; - uint16_t mActiveCount; - - std::vector mRadii; - std::vector mSizes; - std::vector mRotations; - std::vector mRotationAngles; - std::vector mRotationAxes; - - bool mHasTextureIndices{ false }; - std::vector mSubtextureOffsets; - float mAspectRatio{ 1.f }; - uint16_t mAspectFlags{ 0 }; - float mAspectRatio2; - float mAspectSpeed, mAspectSpeed2; - - void read(NIFStream* nif) override; - }; - - struct NiRotatingParticlesData : public NiParticlesData - { - void read(NIFStream* nif) override; - }; - struct NiPosData : public Record { Vector3KeyMapPtr mKeyList; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 66c4aaac7b..fe59bb8b9d 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -240,14 +240,8 @@ namespace Nif // GEOMETRY // 4.0.0.2 - { "NiAutoNormalParticles", &construct }, - { "NiAutoNormalParticlesData", &construct }, { "NiLines", &construct }, { "NiLinesData", &construct }, - { "NiParticles", &construct }, - { "NiParticlesData", &construct }, - { "NiRotatingParticles", &construct }, - { "NiRotatingParticlesData", &construct }, { "NiSkinData", &construct }, { "NiSkinInstance", &construct }, { "NiSkinPartition", &construct }, @@ -265,12 +259,26 @@ namespace Nif // PARTICLES + // Geometry, 4.0.0.2 + { "NiAutoNormalParticles", &construct }, + { "NiAutoNormalParticlesData", &construct }, + { "NiParticles", &construct }, + { "NiParticlesData", &construct }, + { "NiRotatingParticles", &construct }, + { "NiRotatingParticlesData", &construct }, + + // Geometry, Gamebryo + { "NiPSysData", &construct }, + // Modifiers, 4.0.0.2 { "NiGravity", &construct }, { "NiParticleColorModifier", &construct }, { "NiParticleGrowFade", &construct }, { "NiParticleRotation", &construct }, + // Modifier data, Gamebryo + { "NiPSysEmitterCtlrData", &construct }, + // Colliders, 4.0.0.2 { "NiPlanarCollider", &construct }, { "NiSphericalCollider", &construct }, diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index ae391c59e4..14898abf94 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -92,4 +92,97 @@ namespace Nif nif->read(mRotationSpeed); } + void NiParticlesData::read(NIFStream* nif) + { + NiGeometryData::read(nif); + + // Should always match the number of vertices in theory, but doesn't: + // see mist.nif in Mistify mod (https://www.nexusmods.com/morrowind/mods/48112). + if (nif->getVersion() <= NIFFile::NIFVersion::VER_MW) + nif->read(mNumParticles); + bool isBs202 = nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() != 0; + + bool numRadii = 1; + if (nif->getVersion() > NIFStream::generateVersion(10, 0, 1, 0)) + numRadii = (nif->get() && !isBs202) ? mNumVertices : 0; + nif->readVector(mRadii, numRadii); + nif->read(mActiveCount); + if (nif->get() && !isBs202) + nif->readVector(mSizes, mNumVertices); + + if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0)) + { + if (nif->get() && !isBs202) + nif->readVector(mRotations, mNumVertices); + if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 4)) + { + if (nif->get() && !isBs202) + nif->readVector(mRotationAngles, mNumVertices); + if (nif->get() && !isBs202) + nif->readVector(mRotationAxes, mNumVertices); + if (isBs202) + { + nif->read(mHasTextureIndices); + uint32_t numSubtextureOffsets; + if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3) + numSubtextureOffsets = nif->get(); + else + nif->read(numSubtextureOffsets); + nif->readVector(mSubtextureOffsets, numSubtextureOffsets); + if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3) + { + nif->read(mAspectRatio); + nif->read(mAspectFlags); + nif->read(mAspectRatio2); + nif->read(mAspectSpeed); + nif->read(mAspectSpeed2); + } + } + } + } + } + + void NiRotatingParticlesData::read(NIFStream* nif) + { + NiParticlesData::read(nif); + + if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0) && nif->get()) + nif->readVector(mRotations, mNumVertices); + } + + void NiPSysData::read(NIFStream* nif) + { + NiParticlesData::read(nif); + + bool hasData = nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO3; + if (hasData) + { + mParticles.resize(mNumVertices); + for (NiParticleInfo& info : mParticles) + info.read(nif); + } + + if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_F76) + nif->skip(12); // Unknown + + if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 2) && nif->get() && hasData) + nif->readVector(mRotationSpeeds, mNumVertices); + + if (nif->getVersion() != NIFStream::generateVersion(20, 2, 0, 7) || nif->getBethVersion() == 0) + { + nif->read(mNumAddedParticles); + nif->read(mAddedParticlesBase); + } + } + + void NiPSysEmitterCtlrData::read(NIFStream* nif) + { + mFloatKeyList = std::make_shared(); + mVisKeyList = std::make_shared(); + uint32_t numVisKeys; + nif->read(numVisKeys); + for (size_t i = 0; i < numVisKeys; i++) + mVisKeyList->mKeys[nif->get()].mValue = nif->get() != 0; + } + } diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 328498210a..084735a472 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_NIF_PARTICLE_HPP #include "base.hpp" +#include "data.hpp" namespace Nif { @@ -86,5 +87,49 @@ namespace Nif void read(NIFStream* nif) override; }; + struct NiParticlesData : NiGeometryData + { + uint16_t mNumParticles{ 0 }; + uint16_t mActiveCount; + + std::vector mRadii; + std::vector mSizes; + std::vector mRotations; + std::vector mRotationAngles; + std::vector mRotationAxes; + + bool mHasTextureIndices{ false }; + std::vector mSubtextureOffsets; + float mAspectRatio{ 1.f }; + uint16_t mAspectFlags{ 0 }; + float mAspectRatio2; + float mAspectSpeed, mAspectSpeed2; + + void read(NIFStream* nif) override; + }; + + struct NiRotatingParticlesData : NiParticlesData + { + void read(NIFStream* nif) override; + }; + + struct NiPSysData : NiParticlesData + { + std::vector mParticles; + std::vector mRotationSpeeds; + uint16_t mNumAddedParticles; + uint16_t mAddedParticlesBase; + + void read(NIFStream* nif) override; + }; + + struct NiPSysEmitterCtlrData : Record + { + FloatKeyMapPtr mFloatKeyList; + BoolKeyMapPtr mVisKeyList; + + void read(NIFStream* nif) override; + }; + } #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index cecb9631d6..3013bef8de 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -169,6 +169,8 @@ namespace Nif RC_NiPlanarCollider, RC_NiPoint3Interpolator, RC_NiPosData, + RC_NiPSysEmitterCtlrData, + RC_NiPSysData, RC_NiRollController, RC_NiSequence, RC_NiSequenceStreamHelper, From c8307ad397413b82f08cdad20ec42a656e773e81 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 13:09:33 +0300 Subject: [PATCH 02/22] Read particle system modifier controllers --- components/nif/niffile.cpp | 28 +++++++++++++++++++++++- components/nif/particle.cpp | 25 +++++++++++++++++++++ components/nif/particle.hpp | 42 ++++++++++++++++++++++++++++++++++++ components/nif/record.hpp | 22 ++++++++++++++++++- components/nif/recordptr.hpp | 2 ++ 5 files changed, 117 insertions(+), 2 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index fe59bb8b9d..62516c1df7 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -276,7 +276,33 @@ namespace Nif { "NiParticleGrowFade", &construct }, { "NiParticleRotation", &construct }, - // Modifier data, Gamebryo + // Modifier controllers, Gamebryo + { "NiPSysAirFieldAirFrictionCtlr", &construct }, + { "NiPSysAirFieldInheritVelocityCtlr", + &construct }, + { "NiPSysAirFieldSpreadCtlr", &construct }, + { "NiPSysEmitterCtlr", &construct }, + { "NiPSysEmitterDeclinationCtlr", &construct }, + { "NiPSysEmitterDeclinationVarCtlr", + &construct }, + { "NiPSysEmitterInitialRadiusCtlr", + &construct }, + { "NiPSysEmitterLifeSpanCtlr", &construct }, + { "NiPSysEmitterPlanarAngleCtlr", &construct }, + { "NiPSysEmitterPlanarAngleVarCtlr", + &construct }, + { "NiPSysEmitterSpeedCtlr", &construct }, + { "NiPSysFieldAttenuationCtlr", &construct }, + { "NiPSysFieldMagnitudeCtlr", &construct }, + { "NiPSysFieldMaxDistanceCtlr", &construct }, + { "NiPSysGravityStrengthCtlr", &construct }, + { "NiPSysInitialRotSpeedCtlr", &construct }, + { "NiPSysInitialRotSpeedVarCtlr", &construct }, + { "NiPSysInitialRotAngleCtlr", &construct }, + { "NiPSysInitialRotAngleVarCtlr", &construct }, + { "NiPSysModifierActiveCtlr", &construct }, + + // Modifier controller data, Gamebryo { "NiPSysEmitterCtlrData", &construct }, // Colliders, 4.0.0.2 diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 14898abf94..389449ed77 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -175,6 +175,31 @@ namespace Nif } } + void NiPSysModifierCtlr::read(NIFStream* nif) + { + NiSingleInterpController::read(nif); + + nif->read(mModifierName); + } + + void NiPSysEmitterCtlr::read(NIFStream* nif) + { + NiPSysModifierCtlr::read(nif); + + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) + mData.read(nif); + else + mVisInterpolator.read(nif); + } + + void NiPSysEmitterCtlr::post(Reader& nif) + { + NiPSysModifierCtlr::post(nif); + + mData.post(nif); + mVisInterpolator.post(nif); + } + void NiPSysEmitterCtlrData::read(NIFStream* nif) { mFloatKeyList = std::make_shared(); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 084735a472..ffdb307bab 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_NIF_PARTICLE_HPP #include "base.hpp" +#include "controller.hpp" #include "data.hpp" namespace Nif @@ -123,6 +124,47 @@ namespace Nif void read(NIFStream* nif) override; }; + // Abstract + struct NiPSysModifierCtlr : NiSingleInterpController + { + std::string mModifierName; + + void read(NIFStream* nif) override; + }; + + template + struct TypedNiPSysModifierCtlr : NiPSysModifierCtlr + { + DataPtr mData; + + void read(NIFStream* nif) override + { + NiPSysModifierCtlr::read(nif); + + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) + mData.read(nif); + } + + void post(Reader& nif) override + { + NiPSysModifierCtlr::post(nif); + + mData.post(nif); + } + }; + + using NiPSysModifierBoolCtlr = TypedNiPSysModifierCtlr; + using NiPSysModifierFloatCtlr = TypedNiPSysModifierCtlr; + + struct NiPSysEmitterCtlr : NiPSysModifierCtlr + { + NiPSysEmitterCtlrDataPtr mData; + NiInterpolatorPtr mVisInterpolator; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct NiPSysEmitterCtlrData : Record { FloatKeyMapPtr mFloatKeyList; diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 3013bef8de..aa0dbf9f37 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -169,8 +169,28 @@ namespace Nif RC_NiPlanarCollider, RC_NiPoint3Interpolator, RC_NiPosData, - RC_NiPSysEmitterCtlrData, + RC_NiPSysAirFieldAirFrictionCtlr, + RC_NiPSysAirFieldInheritVelocityCtlr, + RC_NiPSysAirFieldSpreadCtlr, RC_NiPSysData, + RC_NiPSysEmitterCtlr, + RC_NiPSysEmitterCtlrData, + RC_NiPSysEmitterDeclinationCtlr, + RC_NiPSysEmitterDeclinationVarCtlr, + RC_NiPSysEmitterInitialRadiusCtlr, + RC_NiPSysEmitterLifeSpanCtlr, + RC_NiPSysEmitterPlanarAngleCtlr, + RC_NiPSysEmitterPlanarAngleVarCtlr, + RC_NiPSysEmitterSpeedCtlr, + RC_NiPSysFieldAttenuationCtlr, + RC_NiPSysFieldMagnitudeCtlr, + RC_NiPSysFieldMaxDistanceCtlr, + RC_NiPSysGravityStrengthCtlr, + RC_NiPSysInitialRotSpeedCtlr, + RC_NiPSysInitialRotSpeedVarCtlr, + RC_NiPSysInitialRotAngleCtlr, + RC_NiPSysInitialRotAngleVarCtlr, + RC_NiPSysModifierActiveCtlr, RC_NiRollController, RC_NiSequence, RC_NiSequenceStreamHelper, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 8598a88f0e..53b9c02a95 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -129,6 +129,7 @@ namespace Nif struct NiSourceTexture; struct NiPalette; struct NiParticleModifier; + struct NiPSysEmitterCtlrData; struct NiBoolData; struct NiSkinPartition; struct BSShaderTextureSet; @@ -170,6 +171,7 @@ namespace Nif using NiSourceTexturePtr = RecordPtrT; using NiPalettePtr = RecordPtrT; using NiParticleModifierPtr = RecordPtrT; + using NiPSysEmitterCtlrDataPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; using NiSkinPartitionPtr = RecordPtrT; using BSShaderTextureSetPtr = RecordPtrT; From a90c848349a3586e248641e4246637d0454398d1 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 13:54:28 +0300 Subject: [PATCH 03/22] Reject files with non-zero preceding separators This sign is typically bad news on some 10.0.1.2 files used in Oblivion. Technically our fault, but NifTools research is incomplete, will need to check if cc9cii found anything --- components/nif/niffile.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 62516c1df7..d761d52b33 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -539,10 +539,8 @@ namespace Nif } // Record separator. Some Havok records in Oblivion do not have it. - if (hasRecordSeparators && !rec.starts_with("bhk")) - if (nif.get()) - Log(Debug::Warning) << "NIFFile Warning: Record of type " << rec << ", index " << i - << " is preceded by a non-zero separator. File: " << mFilename; + if (hasRecordSeparators && !rec.starts_with("bhk") && nif.get()) + throw Nif::Exception("Non-zero separator precedes " + rec + ", index " + std::to_string(i), mFilename); const auto entry = factories.find(rec); From c34faaf336e3f3ebe842c70fec5af7cc2580a9f1 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 14:01:43 +0300 Subject: [PATCH 04/22] Read NiPSysUpdateCtlr --- components/nif/niffile.cpp | 7 ++++++- components/nif/record.hpp | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index d761d52b33..85ec92f2fa 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -108,7 +108,6 @@ namespace Nif { "NiKeyframeController", &construct }, { "NiLookAtController", &construct }, { "NiMaterialColorController", &construct }, - { "NiParticleSystemController", &construct }, { "NiPathController", &construct }, { "NiRollController", &construct }, { "NiUVController", &construct }, @@ -309,6 +308,12 @@ namespace Nif { "NiPlanarCollider", &construct }, { "NiSphericalCollider", &construct }, + // Particle system controllers, 4.0.0.2 + { "NiParticleSystemController", &construct }, + + // Particle system controllers, Gamebryo + { "NiPSysUpdateCtlr", &construct }, + // PHYSICS // Collision objects, Gamebryo diff --git a/components/nif/record.hpp b/components/nif/record.hpp index aa0dbf9f37..b8cbbfe804 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -191,6 +191,7 @@ namespace Nif RC_NiPSysInitialRotAngleCtlr, RC_NiPSysInitialRotAngleVarCtlr, RC_NiPSysModifierActiveCtlr, + RC_NiPSysUpdateCtlr, RC_NiRollController, RC_NiSequence, RC_NiSequenceStreamHelper, From 812b0cf246aaf1f46e9e897f71d805edf5c35f45 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 14:59:14 +0300 Subject: [PATCH 05/22] Read NiFloatExtraDataController records --- components/nif/controller.cpp | 57 +++++++++++++++++++++++++++++++++++ components/nif/controller.hpp | 32 ++++++++++++++++++++ components/nif/niffile.cpp | 7 +++++ components/nif/record.hpp | 4 +++ 4 files changed, 100 insertions(+) diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 73644f1541..5dcf6ef80d 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -526,6 +526,63 @@ namespace Nif mObjectPalette.post(nif); } + void NiExtraDataController::read(NIFStream* nif) + { + NiSingleInterpController::read(nif); + + if (nif->getVersion() >= NIFStream::generateVersion(10, 2, 0, 0)) + nif->read(mExtraDataName); + } + + void NiFloatExtraDataController::read(NIFStream* nif) + { + NiExtraDataController::read(nif); + + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 104)) + return; + + // Unknown + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 0)) + { + uint8_t numExtraBytes; + nif->read(numExtraBytes); + nif->skip(7); + nif->skip(numExtraBytes); + } + + mData.read(nif); + } + + void NiFloatExtraDataController::post(Reader& nif) + { + NiExtraDataController::post(nif); + + mData.post(nif); + } + + void NiFloatsExtraDataController::read(NIFStream* nif) + { + NiExtraDataController::read(nif); + + nif->read(mFloatsExtraDataIndex); + if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103)) + mData.read(nif); + } + + void NiFloatsExtraDataController::post(Reader& nif) + { + NiExtraDataController::post(nif); + + mData.post(nif); + } + + void NiFloatsExtraDataPoint3Controller::read(NIFStream* nif) + { + NiExtraDataController::read(nif); + + nif->read(mFloatsExtraDataIndex); + } + void NiBlendInterpolator::read(NIFStream* nif) { if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 112)) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 3104c29f94..31f3d19f91 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -346,6 +346,38 @@ namespace Nif void post(Reader& nif) override; }; + // Abstract + struct NiExtraDataController : NiSingleInterpController + { + std::string mExtraDataName; + + void read(NIFStream* nif) override; + }; + + struct NiFloatExtraDataController : NiExtraDataController + { + NiFloatDataPtr mData; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiFloatsExtraDataController : NiExtraDataController + { + int32_t mFloatsExtraDataIndex; + NiFloatDataPtr mData; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiFloatsExtraDataPoint3Controller : NiExtraDataController + { + int32_t mFloatsExtraDataIndex; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiInterpolator : public Record { diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 85ec92f2fa..3609c42fe6 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -122,6 +122,13 @@ namespace Nif { "NiMultiTargetTransformController", &construct }, + // Extra data controllers, Gamebryo + { "NiColorExtraDataController", &construct }, + { "NiFloatExtraDataController", &construct }, + { "NiFloatsExtraDataController", &construct }, + { "NiFloatsExtraDataPoint3Controller", + &construct }, + // Bethesda { "BSFrustumFOVController", &construct }, { "BSKeyframeController", &construct }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index b8cbbfe804..0b7c239442 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -127,6 +127,7 @@ namespace Nif RC_NiCollisionSwitch, RC_NiColorData, RC_NiColorExtraData, + RC_NiColorExtraDataController, RC_NiColorInterpolator, RC_NiControllerManager, RC_NiControllerSequence, @@ -136,8 +137,11 @@ namespace Nif RC_NiFlipController, RC_NiFloatData, RC_NiFloatExtraData, + RC_NiFloatExtraDataController, RC_NiFloatInterpolator, RC_NiFloatsExtraData, + RC_NiFloatsExtraDataController, + RC_NiFloatsExtraDataPoint3Controller, RC_NiFltAnimationNode, RC_NiFogProperty, RC_NiGeomMorpherController, From 2d9c70053088c2337c3a56a024903f7a0a20f712 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 15:17:45 +0300 Subject: [PATCH 06/22] Read BSDebrisNode --- components/nif/niffile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 3609c42fe6..0e4ef39b60 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -69,6 +69,7 @@ namespace Nif // NiNode-like nodes, Bethesda { "BSBlastNode", &construct }, { "BSDamageStage", &construct }, + { "BSDebrisNode", &construct }, { "BSFadeNode", &construct }, { "BSLeafAnimNode", &construct }, { "BSMultiBoundNode", &construct }, From e2efc9dd2fe0fec375a3655b8a7657b92a899525 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 15:42:13 +0300 Subject: [PATCH 07/22] Read NiLightColorController and NiPathInterpolator --- components/nif/controller.cpp | 17 +++++++++++++++++ components/nif/controller.hpp | 15 +++++++++++++++ components/nif/niffile.cpp | 3 +++ components/nif/record.hpp | 2 ++ 4 files changed, 37 insertions(+) diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 5dcf6ef80d..a3033357ec 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -583,6 +583,23 @@ namespace Nif nif->read(mFloatsExtraDataIndex); } + void NiPathInterpolator::read(NIFStream* nif) + { + nif->read(mFlags); + nif->read(mBankDirection); + nif->read(mMaxBankAngle); + nif->read(mSmoothing); + nif->read(mFollowAxis); + mPathData.read(nif); + mPercentData.read(nif); + } + + void NiPathInterpolator::post(Reader& nif) + { + mPathData.post(nif); + mPercentData.post(nif); + } + void NiBlendInterpolator::read(NIFStream* nif) { if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 112)) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 31f3d19f91..8a7d306a85 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -404,6 +404,21 @@ namespace Nif using NiTransformInterpolator = TypedNiInterpolator; using NiColorInterpolator = TypedNiInterpolator; + struct NiPathInterpolator : public NiInterpolator + { + // Uses the same flags as NiPathController + uint16_t mFlags; + int32_t mBankDirection; + float mMaxBankAngle; + float mSmoothing; + uint16_t mFollowAxis; + NiPosDataPtr mPathData; + NiFloatDataPtr mPercentData; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + // Abstract struct NiBlendInterpolator : public NiInterpolator { diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 0e4ef39b60..bad2482432 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -108,6 +108,8 @@ namespace Nif { "NiGeomMorpherController", &construct }, { "NiKeyframeController", &construct }, { "NiLookAtController", &construct }, + // FIXME: NiLightColorController should have its own struct + { "NiLightColorController", &construct }, { "NiMaterialColorController", &construct }, { "NiPathController", &construct }, { "NiRollController", &construct }, @@ -162,6 +164,7 @@ namespace Nif { "NiBoolTimelineInterpolator", &construct }, { "NiColorInterpolator", &construct }, { "NiFloatInterpolator", &construct }, + { "NiPathInterpolator", &construct }, { "NiPoint3Interpolator", &construct }, { "NiTransformInterpolator", &construct }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 0b7c239442..b26233259a 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -151,6 +151,7 @@ namespace Nif RC_NiKeyframeController, RC_NiKeyframeData, RC_NiLight, + RC_NiLightColorController, RC_NiLightDimmerController, RC_NiLines, RC_NiLinesData, @@ -169,6 +170,7 @@ namespace Nif RC_NiParticlesData, RC_NiParticleSystemController, RC_NiPathController, + RC_NiPathInterpolator, RC_NiPixelData, RC_NiPlanarCollider, RC_NiPoint3Interpolator, From 6204a83a2b238cae3ee538b064e70291b81e5465 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 21 Sep 2023 22:59:55 +0300 Subject: [PATCH 08/22] Read bhkBallAndSocketConstraint and bhkStiffSpringConstraint --- components/nif/niffile.cpp | 2 ++ components/nif/physics.cpp | 27 +++++++++++++++++++++++++++ components/nif/physics.hpp | 29 +++++++++++++++++++++++++++++ components/nif/record.hpp | 2 ++ 4 files changed, 60 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index bad2482432..8f0925103a 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -338,9 +338,11 @@ namespace Nif { "bhkBlendCollisionObject", &construct }, // Constraint records, Bethesda + { "bhkBallAndSocketConstraint", &construct }, { "bhkHingeConstraint", &construct }, { "bhkLimitedHingeConstraint", &construct }, { "bhkRagdollConstraint", &construct }, + { "bhkStiffSpringConstraint", &construct }, // Physics body records, Bethesda { "bhkRigidBody", &construct }, diff --git a/components/nif/physics.cpp b/components/nif/physics.cpp index a359f86066..f97b4b6169 100644 --- a/components/nif/physics.cpp +++ b/components/nif/physics.cpp @@ -332,6 +332,19 @@ namespace Nif mMotor.read(nif); } + void bhkBallAndSocketConstraintCInfo::read(NIFStream* nif) + { + nif->read(mPivotA); + nif->read(mPivotB); + } + + void bhkStiffSpringConstraintCInfo::read(NIFStream* nif) + { + nif->read(mPivotA); + nif->read(mPivotB); + nif->read(mLength); + } + /// Record types void bhkCollisionObject::read(NIFStream* nif) @@ -719,4 +732,18 @@ namespace Nif mConstraint.read(nif); } + void bhkBallAndSocketConstraint::read(NIFStream* nif) + { + bhkConstraint::read(nif); + + mConstraint.read(nif); + } + + void bhkStiffSpringConstraint::read(NIFStream* nif) + { + bhkConstraint::read(nif); + + mConstraint.read(nif); + } + } // Namespace diff --git a/components/nif/physics.hpp b/components/nif/physics.hpp index 91d55c1f80..d9656510c3 100644 --- a/components/nif/physics.hpp +++ b/components/nif/physics.hpp @@ -348,6 +348,21 @@ namespace Nif void read(NIFStream* nif); }; + struct bhkBallAndSocketConstraintCInfo + { + osg::Vec4f mPivotA, mPivotB; + + void read(NIFStream* nif); + }; + + struct bhkStiffSpringConstraintCInfo + { + osg::Vec4f mPivotA, mPivotB; + float mLength; + + void read(NIFStream* nif); + }; + /// Record types // Abstract Bethesda Havok object @@ -684,5 +699,19 @@ namespace Nif void read(NIFStream* nif) override; }; + struct bhkBallAndSocketConstraint : bhkConstraint + { + bhkBallAndSocketConstraintCInfo mConstraint; + + void read(NIFStream* nif) override; + }; + + struct bhkStiffSpringConstraint : bhkConstraint + { + bhkStiffSpringConstraintCInfo mConstraint; + + void read(NIFStream* nif) override; + }; + } // Namespace #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index b26233259a..d399660432 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -36,6 +36,7 @@ namespace Nif { RC_MISSING = 0, RC_AvoidNode, + RC_bhkBallAndSocketConstraint, RC_bhkBlendCollisionObject, RC_bhkBlendController, RC_bhkBoxShape, @@ -61,6 +62,7 @@ namespace Nif RC_bhkRigidBodyT, RC_bhkSimpleShapePhantom, RC_bhkSphereShape, + RC_bhkStiffSpringConstraint, RC_BSBehaviorGraphExtraData, RC_BSBound, RC_BSBoneLODExtraData, From f507e17807d1b7e9f1546a99e10be10a4a18dd44 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 00:18:35 +0300 Subject: [PATCH 09/22] Read BSWaterShaderProperty and BSSkyShaderProperty --- components/nif/niffile.cpp | 2 ++ components/nif/property.cpp | 17 +++++++++++- components/nif/property.hpp | 55 +++++++++++++++++++++++++++++-------- components/nif/record.hpp | 2 ++ 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 8f0925103a..8dbf65d070 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -393,6 +393,8 @@ namespace Nif { "BSDistantTreeShaderProperty", &construct }, { "BSLightingShaderProperty", &construct }, { "BSEffectShaderProperty", &construct }, + { "BSSkyShaderProperty", &construct }, + { "BSWaterShaderProperty", &construct }, { "DistantLODShaderProperty", &construct }, { "HairShaderProperty", &construct }, { "Lighting30ShaderProperty", &construct }, diff --git a/components/nif/property.cpp b/components/nif/property.cpp index fa6fa1b4cf..bcc70540c8 100644 --- a/components/nif/property.cpp +++ b/components/nif/property.cpp @@ -232,7 +232,7 @@ namespace Nif BSShaderLightingProperty::read(nif); mFilename = nif->getSizedString(); - mSkyObjectType = static_cast(nif->get()); + mSkyObjectType = static_cast(nif->get()); } void TallGrassShaderProperty::read(NIFStream* nif) @@ -455,6 +455,21 @@ namespace Nif } } + void BSSkyShaderProperty::read(NIFStream* nif) + { + BSShaderProperty::read(nif); + + mFilename = nif->getSizedString(); + mSkyObjectType = static_cast(nif->get()); + } + + void BSWaterShaderProperty::read(NIFStream* nif) + { + BSShaderProperty::read(nif); + + nif->read(mFlags); + } + void NiAlphaProperty::read(NIFStream* nif) { NiProperty::read(nif); diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 37d17989b6..0d4a5b33c6 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -171,20 +171,20 @@ namespace Nif void read(NIFStream* nif) override; }; + enum class SkyObjectType : uint32_t + { + SkyTexture = 0, + SkySunglare = 1, + Sky = 2, + SkyClouds = 3, + SkyStars = 5, + SkyMoonStarsMask = 7, + }; + struct SkyShaderProperty : BSShaderLightingProperty { - enum class ObjectType : uint32_t - { - SkyTexture = 0, - SkySunglare = 1, - Sky = 2, - SkyClouds = 3, - SkyStars = 5, - SkyMoonStarsMask = 7, - }; - std::string mFilename; - ObjectType mSkyObjectType; + SkyObjectType mSkyObjectType; void read(NIFStream* nif) override; }; @@ -358,6 +358,39 @@ namespace Nif bool treeAnim() const { return mShaderFlags2 & BSLSFlag2_TreeAnim; } }; + struct BSSkyShaderProperty : BSShaderProperty + { + std::string mFilename; + SkyObjectType mSkyObjectType; + + void read(NIFStream* nif) override; + }; + + struct BSWaterShaderProperty : BSShaderProperty + { + enum Flags + { + Flag_Displacement = 0x0001, + Flag_LOD = 0x0002, + Flag_Depth = 0x0004, + Flag_ActorInWater = 0x0008, + Flag_ActorInWaterIsMoving = 0x0010, + Flag_Underwater = 0x0020, + Flag_Reflections = 0x0040, + Flag_Refractions = 0x0080, + Flag_VertexUV = 0x0100, + Flag_VertexAlphaDepth = 0x0200, + Flag_Procedural = 0x0400, + Flag_Fog = 0x0800, + Flag_UpdateConstants = 0x1000, + Flag_CubeMap = 0x2000, + }; + + uint32_t mFlags; + + void read(NIFStream* nif) override; + }; + struct NiAlphaProperty : NiProperty { enum Flags diff --git a/components/nif/record.hpp b/components/nif/record.hpp index d399660432..fd780e52eb 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -100,8 +100,10 @@ namespace Nif RC_BSShaderPPLightingProperty, RC_BSShaderProperty, RC_BSShaderTextureSet, + RC_BSSkyShaderProperty, RC_BSTriShape, RC_BSWArray, + RC_BSWaterShaderProperty, RC_BSXFlags, RC_DistantLODShaderProperty, RC_HairShaderProperty, From c800152ca25c2e6abed79f87f7f158b54b9a6781 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 01:00:32 +0300 Subject: [PATCH 10/22] Diminish error marker prominence Don't render ESM4 actors or SpeedTree objects --- apps/openmw/mwclass/esm4base.hpp | 7 ++----- components/resource/scenemanager.cpp | 5 +++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/esm4base.hpp b/apps/openmw/mwclass/esm4base.hpp index 3d2184e5fe..c59e8e1dc2 100644 --- a/apps/openmw/mwclass/esm4base.hpp +++ b/apps/openmw/mwclass/esm4base.hpp @@ -150,11 +150,8 @@ namespace MWClass std::string getModel(const MWWorld::ConstPtr& ptr) const override { - // TODO: Not clear where to get something renderable: - // ESM4::Npc::mModel is usually an empty string - // ESM4::Race::mModelMale is only a skeleton - // For now show error marker as a dummy model. - return "meshes/marker_error.nif"; + // TODO: Implement actor rendering. This function will typically return the skeleton. + return {}; } }; } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index dde39c5d65..66fee5256d 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -726,6 +726,11 @@ namespace Resource auto ext = Misc::getFileExtension(normalizedFilename); if (ext == "nif") return NifOsg::Loader::load(*nifFileManager->get(normalizedFilename), imageManager); + else if (ext == "spt") + { + Log(Debug::Warning) << "Ignoring SpeedTree data file " << normalizedFilename; + return new osg::Node(); + } else return loadNonNif(normalizedFilename, *vfs->get(normalizedFilename), imageManager); } From a8946e06f61814de0e3bbf986acf45dd7c5340e7 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 01:52:30 +0300 Subject: [PATCH 11/22] Read NiParticleSystem and its twins Looks like NiPSysData is loading correctly --- components/nif/niffile.cpp | 5 ++++ components/nif/particle.cpp | 53 ++++++++++++++++++++++++++++++++++++ components/nif/particle.hpp | 43 +++++++++++++++++++++++++++++ components/nif/record.hpp | 1 + components/nif/recordptr.hpp | 4 +++ 5 files changed, 106 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 8dbf65d070..f3a03b097f 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -278,8 +278,13 @@ namespace Nif { "NiRotatingParticlesData", &construct }, // Geometry, Gamebryo + { "NiParticleSystem", &construct }, + { "NiMeshParticleSystem", &construct }, { "NiPSysData", &construct }, + // Geometry, Bethesda + { "BSStripParticleSystem", &construct }, + // Modifiers, 4.0.0.2 { "NiGravity", &construct }, { "NiParticleColorModifier", &construct }, diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 389449ed77..8dee873c0b 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -150,6 +150,46 @@ namespace Nif nif->readVector(mRotations, mNumVertices); } + void NiParticleSystem::read(NIFStream* nif) + { + // Weird loading to account for inheritance differences starting from SSE + if (nif->getBethVersion() < NIFFile::BethVersion::BETHVER_SSE) + NiParticles::read(nif); + else + { + NiAVObject::read(nif); + + nif->read(mBoundingSphere); + if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_F76) + nif->readArray(mBoundMinMax); + + mSkin.read(nif); + mShaderProperty.read(nif); + mAlphaProperty.read(nif); + mVertDesc.read(nif); + } + + if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SKY) + { + nif->readArray(mNearFar); + if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SSE) + mData.read(nif); + } + + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) + { + nif->read(mWorldSpace); + readRecordList(nif, mModifiers); + } + } + + void NiParticleSystem::post(Reader& nif) + { + NiParticles::post(nif); + + postRecordList(nif, mModifiers); + } + void NiPSysData::read(NIFStream* nif) { NiParticlesData::read(nif); @@ -175,6 +215,19 @@ namespace Nif } } + void NiPSysModifier::read(NIFStream* nif) + { + nif->read(mName); + mOrder = static_cast(nif->get()); + mTarget.read(nif); + nif->read(mActive); + } + + void NiPSysModifier::post(Reader& nif) + { + mTarget.post(nif); + } + void NiPSysModifierCtlr::read(NIFStream* nif) { NiSingleInterpController::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index ffdb307bab..f800ddefb7 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -4,6 +4,7 @@ #include "base.hpp" #include "controller.hpp" #include "data.hpp" +#include "node.hpp" namespace Nif { @@ -114,6 +115,19 @@ namespace Nif void read(NIFStream* nif) override; }; + struct NiParticleSystem : NiParticles + { + osg::BoundingSpheref mBoundingSphere; + std::array mBoundMinMax; + BSVertexDesc mVertDesc; + std::array mNearFar; + bool mWorldSpace{ true }; + NiPSysModifierList mModifiers; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct NiPSysData : NiParticlesData { std::vector mParticles; @@ -124,6 +138,35 @@ namespace Nif void read(NIFStream* nif) override; }; + // Abstract + struct NiPSysModifier : Record + { + enum class NiPSysModifierOrder : uint32_t + { + KillOldParticles = 0, + BSLOD = 1, + Emitter = 1000, + Spawn = 2000, + BSStripUpdateFO3 = 2500, + General = 3000, + Force = 4000, + Collider = 5000, + PosUpdate = 6000, + PostPosUpdate = 6500, + WorldshiftPartspawn = 6600, + BoundUpdate = 7000, + BSStripUpdateSK = 8000, + }; + + std::string mName; + NiPSysModifierOrder mOrder; + NiParticleSystemPtr mTarget; + bool mActive; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + // Abstract struct NiPSysModifierCtlr : NiSingleInterpController { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index fd780e52eb..a4598ebe3c 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -172,6 +172,7 @@ namespace Nif RC_NiParticleRotation, RC_NiParticles, RC_NiParticlesData, + RC_NiParticleSystem, RC_NiParticleSystemController, RC_NiPathController, RC_NiPathInterpolator, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 53b9c02a95..2355879ac6 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -129,7 +129,9 @@ namespace Nif struct NiSourceTexture; struct NiPalette; struct NiParticleModifier; + struct NiParticleSystem; struct NiPSysEmitterCtlrData; + struct NiPSysModifier; struct NiBoolData; struct NiSkinPartition; struct BSShaderTextureSet; @@ -171,6 +173,7 @@ namespace Nif using NiSourceTexturePtr = RecordPtrT; using NiPalettePtr = RecordPtrT; using NiParticleModifierPtr = RecordPtrT; + using NiParticleSystemPtr = RecordPtrT; using NiPSysEmitterCtlrDataPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; using NiSkinPartitionPtr = RecordPtrT; @@ -204,6 +207,7 @@ namespace Nif using bhkSerializableList = RecordListT; using bhkEntityList = RecordListT; using NiControllerSequenceList = RecordListT; + using NiPSysModifierList = RecordListT; } // Namespace #endif From eaa82ba5c6f677ce1bcfebeb0e13ba9c0ed2c283 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 02:19:32 +0300 Subject: [PATCH 12/22] Read BSStripPSysData --- components/nif/data.cpp | 14 +++++++++++++- components/nif/niffile.cpp | 3 ++- components/nif/particle.cpp | 10 ++++++++++ components/nif/particle.hpp | 10 ++++++++++ components/nif/record.hpp | 2 ++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 34ec3b2831..9aa61b4db7 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -14,7 +14,19 @@ namespace Nif nif->read(mGroupId); nif->read(mNumVertices); - bool hasData = recType != RC_NiPSysData || nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO3; + + bool isPSysData = false; + switch (recType) + { + case RC_NiPSysData: + // case RC_NiMeshPSysData: + case RC_BSStripPSysData: + isPSysData = true; + break; + default: + break; + } + bool hasData = !isPSysData || nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO3; if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) { diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f3a03b097f..196fe780cc 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -283,7 +283,8 @@ namespace Nif { "NiPSysData", &construct }, // Geometry, Bethesda - { "BSStripParticleSystem", &construct }, + { "BSStripParticleSystem", &construct }, + { "BSStripPSysData", &construct }, // Modifiers, 4.0.0.2 { "NiGravity", &construct }, diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 8dee873c0b..bd3b4dcddb 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -215,6 +215,16 @@ namespace Nif } } + void BSStripPSysData::read(NIFStream* nif) + { + NiPSysData::read(nif); + + nif->read(mMaxPointCount); + nif->read(mStartCapSize); + nif->read(mEndCapSize); + nif->read(mDoZPrepass); + } + void NiPSysModifier::read(NIFStream* nif) { nif->read(mName); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index f800ddefb7..4428347105 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -138,6 +138,16 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSStripPSysData : NiPSysData + { + uint16_t mMaxPointCount; + float mStartCapSize; + float mEndCapSize; + bool mDoZPrepass; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiPSysModifier : Record { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index a4598ebe3c..2073723ece 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -94,6 +94,8 @@ namespace Nif RC_BSMultiBoundSphere, RC_BSNiAlphaPropertyTestRefController, RC_BSPackedAdditionalGeometryData, + RC_BSStripParticleSystem, + RC_BSStripPSysData, RC_BSRefractionFirePeriodController, RC_BSRefractionStrengthController, RC_BSShaderNoLightingProperty, From b45923ac39f5f921039365c36b35ff249aadfb60 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 02:54:03 +0300 Subject: [PATCH 13/22] Read NiPSysSpawnModifier, NiPSysAgeDeathModifier --- components/nif/niffile.cpp | 4 ++++ components/nif/particle.cpp | 29 +++++++++++++++++++++++++++++ components/nif/particle.hpp | 23 +++++++++++++++++++++++ components/nif/record.hpp | 2 ++ components/nif/recordptr.hpp | 2 ++ 5 files changed, 60 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 196fe780cc..a89540ac15 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -292,6 +292,10 @@ namespace Nif { "NiParticleGrowFade", &construct }, { "NiParticleRotation", &construct }, + // Modifiers, Gamebryo + { "NiPSysAgeDeathModifier", &construct }, + { "NiPSysSpawnModifier", &construct }, + // Modifier controllers, Gamebryo { "NiPSysAirFieldAirFrictionCtlr", &construct }, { "NiPSysAirFieldInheritVelocityCtlr", diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index bd3b4dcddb..04da656e9d 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -238,6 +238,35 @@ namespace Nif mTarget.post(nif); } + void NiPSysAgeDeathModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mSpawnOnDeath); + mSpawnModifier.read(nif); + } + + void NiPSysAgeDeathModifier::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mSpawnModifier.post(nif); + } + + void NiPSysSpawnModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mNumSpawnGenerations); + nif->read(mPercentageSpawned); + nif->read(mMinNumToSpawn); + nif->read(mMaxNumToSpawn); + nif->read(mSpawnSpeedVariation); + nif->read(mSpawnDirVariation); + nif->read(mLifespan); + nif->read(mLifespanVariation); + } + void NiPSysModifierCtlr::read(NIFStream* nif) { NiSingleInterpController::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 4428347105..b556b0b285 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -177,6 +177,29 @@ namespace Nif void post(Reader& nif) override; }; + struct NiPSysAgeDeathModifier : NiPSysModifier + { + bool mSpawnOnDeath; + NiPSysSpawnModifierPtr mSpawnModifier; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysSpawnModifier : NiPSysModifier + { + uint16_t mNumSpawnGenerations; + float mPercentageSpawned; + uint16_t mMinNumToSpawn; + uint16_t mMaxNumToSpawn; + float mSpawnSpeedVariation; + float mSpawnDirVariation; + float mLifespan; + float mLifespanVariation; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiPSysModifierCtlr : NiSingleInterpController { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 2073723ece..78bbb0f062 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -182,6 +182,7 @@ namespace Nif RC_NiPlanarCollider, RC_NiPoint3Interpolator, RC_NiPosData, + RC_NiPSysAgeDeathModifier, RC_NiPSysAirFieldAirFrictionCtlr, RC_NiPSysAirFieldInheritVelocityCtlr, RC_NiPSysAirFieldSpreadCtlr, @@ -204,6 +205,7 @@ namespace Nif RC_NiPSysInitialRotAngleCtlr, RC_NiPSysInitialRotAngleVarCtlr, RC_NiPSysModifierActiveCtlr, + RC_NiPSysSpawnModifier, RC_NiPSysUpdateCtlr, RC_NiRollController, RC_NiSequence, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 2355879ac6..6223740e31 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -132,6 +132,7 @@ namespace Nif struct NiParticleSystem; struct NiPSysEmitterCtlrData; struct NiPSysModifier; + struct NiPSysSpawnModifier; struct NiBoolData; struct NiSkinPartition; struct BSShaderTextureSet; @@ -175,6 +176,7 @@ namespace Nif using NiParticleModifierPtr = RecordPtrT; using NiParticleSystemPtr = RecordPtrT; using NiPSysEmitterCtlrDataPtr = RecordPtrT; + using NiPSysSpawnModifierPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; using NiSkinPartitionPtr = RecordPtrT; using BSShaderTextureSetPtr = RecordPtrT; From 717b93d61e9b2d7820c7fe3f86c2366cc6301657 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 03:04:36 +0300 Subject: [PATCH 14/22] Read BSPSysLODModifier --- components/nif/niffile.cpp | 3 +++ components/nif/particle.cpp | 10 ++++++++++ components/nif/particle.hpp | 10 ++++++++++ components/nif/record.hpp | 1 + 4 files changed, 24 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index a89540ac15..b3cc294d6e 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -296,6 +296,9 @@ namespace Nif { "NiPSysAgeDeathModifier", &construct }, { "NiPSysSpawnModifier", &construct }, + // Modifiers, Bethesda + { "BSPSysLODModifier", &construct }, + // Modifier controllers, Gamebryo { "NiPSysAirFieldAirFrictionCtlr", &construct }, { "NiPSysAirFieldInheritVelocityCtlr", diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 04da656e9d..26a22394d8 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -267,6 +267,16 @@ namespace Nif nif->read(mLifespanVariation); } + void BSPSysLODModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mLODStartDistance); + nif->read(mLODEndDistance); + nif->read(mEndEmitScale); + nif->read(mEndSize); + } + void NiPSysModifierCtlr::read(NIFStream* nif) { NiSingleInterpController::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index b556b0b285..a743834d98 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -200,6 +200,16 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSPSysLODModifier : NiPSysModifier + { + float mLODStartDistance; + float mLODEndDistance; + float mEndEmitScale; + float mEndSize; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiPSysModifierCtlr : NiSingleInterpController { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 78bbb0f062..70cb67e749 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -94,6 +94,7 @@ namespace Nif RC_BSMultiBoundSphere, RC_BSNiAlphaPropertyTestRefController, RC_BSPackedAdditionalGeometryData, + RC_BSPSysLODModifier, RC_BSStripParticleSystem, RC_BSStripPSysData, RC_BSRefractionFirePeriodController, From c6d0df432f9e677a49917bb7a50649f144f92b1c Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 03:26:01 +0300 Subject: [PATCH 15/22] Read a few Gamebryo particle emitters, NiPSysResetOnLoopCtlr, NiPSysPositionModifier --- components/nif/niffile.cpp | 7 +++++ components/nif/particle.cpp | 57 +++++++++++++++++++++++++++++++++++++ components/nif/particle.hpp | 51 +++++++++++++++++++++++++++++++++ components/nif/record.hpp | 5 ++++ 4 files changed, 120 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index b3cc294d6e..4f0ce46865 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -294,11 +294,17 @@ namespace Nif // Modifiers, Gamebryo { "NiPSysAgeDeathModifier", &construct }, + { "NiPSysPositionModifier", &construct }, { "NiPSysSpawnModifier", &construct }, // Modifiers, Bethesda { "BSPSysLODModifier", &construct }, + // Emitters + { "NiPSysBoxEmitter", &construct }, + { "NiPSysCylinderEmitter", &construct }, + { "NiPSysSphereEmitter", &construct }, + // Modifier controllers, Gamebryo { "NiPSysAirFieldAirFrictionCtlr", &construct }, { "NiPSysAirFieldInheritVelocityCtlr", @@ -336,6 +342,7 @@ namespace Nif { "NiParticleSystemController", &construct }, // Particle system controllers, Gamebryo + { "NiPSysResetOnLoopCtlr", &construct }, { "NiPSysUpdateCtlr", &construct }, // PHYSICS diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 26a22394d8..fa386e2b73 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -277,6 +277,63 @@ namespace Nif nif->read(mEndSize); } + void NiPSysEmitter::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mSpeed); + nif->read(mSpeedVariation); + nif->read(mDeclination); + nif->read(mDeclinationVariation); + nif->read(mPlanarAngle); + nif->read(mPlanarAngleVariation); + nif->read(mInitialColor); + nif->read(mInitialRadius); + if (nif->getVersion() >= NIFStream::generateVersion(10, 4, 0, 1)) + nif->read(mRadiusVariation); + nif->read(mLifespan); + nif->read(mLifespanVariation); + } + + void NiPSysVolumeEmitter::read(NIFStream* nif) + { + NiPSysEmitter::read(nif); + + if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) + mEmitterObject.read(nif); + } + + void NiPSysVolumeEmitter::post(Reader& nif) + { + NiPSysEmitter::post(nif); + + mEmitterObject.post(nif); + } + + void NiPSysBoxEmitter::read(NIFStream* nif) + { + NiPSysVolumeEmitter::read(nif); + + nif->read(mWidth); + nif->read(mHeight); + nif->read(mDepth); + } + + void NiPSysCylinderEmitter::read(NIFStream* nif) + { + NiPSysVolumeEmitter::read(nif); + + nif->read(mRadius); + nif->read(mHeight); + } + + void NiPSysSphereEmitter::read(NIFStream* nif) + { + NiPSysVolumeEmitter::read(nif); + + nif->read(mRadius); + } + void NiPSysModifierCtlr::read(NIFStream* nif) { NiSingleInterpController::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index a743834d98..55ed84b5ae 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -210,6 +210,57 @@ namespace Nif void read(NIFStream* nif) override; }; + // Abstract + struct NiPSysEmitter : public NiPSysModifier + { + float mSpeed; + float mSpeedVariation; + float mDeclination; + float mDeclinationVariation; + float mPlanarAngle; + float mPlanarAngleVariation; + osg::Vec4f mInitialColor; + float mInitialRadius; + float mRadiusVariation; + float mLifespan; + float mLifespanVariation; + + void read(NIFStream* nif) override; + }; + + // Abstract + struct NiPSysVolumeEmitter : public NiPSysEmitter + { + NiAVObjectPtr mEmitterObject; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysBoxEmitter : public NiPSysVolumeEmitter + { + float mWidth; + float mHeight; + float mDepth; + + void read(NIFStream* nif) override; + }; + + struct NiPSysCylinderEmitter : public NiPSysVolumeEmitter + { + float mRadius; + float mHeight; + + void read(NIFStream* nif) override; + }; + + struct NiPSysSphereEmitter : public NiPSysVolumeEmitter + { + float mRadius; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiPSysModifierCtlr : NiSingleInterpController { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 70cb67e749..e519a0bcc3 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -187,6 +187,8 @@ namespace Nif RC_NiPSysAirFieldAirFrictionCtlr, RC_NiPSysAirFieldInheritVelocityCtlr, RC_NiPSysAirFieldSpreadCtlr, + RC_NiPSysBoxEmitter, + RC_NiPSysCylinderEmitter, RC_NiPSysData, RC_NiPSysEmitterCtlr, RC_NiPSysEmitterCtlrData, @@ -206,7 +208,10 @@ namespace Nif RC_NiPSysInitialRotAngleCtlr, RC_NiPSysInitialRotAngleVarCtlr, RC_NiPSysModifierActiveCtlr, + RC_NiPSysPositionModifier, + RC_NiPSysResetOnLoopCtlr, RC_NiPSysSpawnModifier, + RC_NiPSysSphereEmitter, RC_NiPSysUpdateCtlr, RC_NiRollController, RC_NiSequence, From 8594875ccb85c309750d45c96877fec13649c33d Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 04:11:32 +0300 Subject: [PATCH 16/22] Read a few more Gamebryo/Bethesda modifiers --- components/nif/niffile.cpp | 5 ++++ components/nif/particle.cpp | 46 +++++++++++++++++++++++++++++++++++++ components/nif/particle.hpp | 38 ++++++++++++++++++++++++++++++ components/nif/record.hpp | 4 ++++ 4 files changed, 93 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 4f0ce46865..b60bb74594 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -294,11 +294,16 @@ namespace Nif // Modifiers, Gamebryo { "NiPSysAgeDeathModifier", &construct }, + { "NiPSysBoundUpdateModifier", &construct }, { "NiPSysPositionModifier", &construct }, { "NiPSysSpawnModifier", &construct }, // Modifiers, Bethesda + { "BSPSysInheritVelocityModifier", + &construct }, { "BSPSysLODModifier", &construct }, + { "BSPSysScaleModifier", &construct }, + { "BSPSysSimpleColorModifier", &construct }, // Emitters { "NiPSysBoxEmitter", &construct }, diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index fa386e2b73..f6e4ae9bc8 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -253,6 +253,13 @@ namespace Nif mSpawnModifier.post(nif); } + void NiPSysBoundUpdateModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mUpdateSkip); + } + void NiPSysSpawnModifier::read(NIFStream* nif) { NiPSysModifier::read(nif); @@ -267,6 +274,23 @@ namespace Nif nif->read(mLifespanVariation); } + void BSPSysInheritVelocityModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + mInheritObject.read(nif); + nif->read(mInheritChance); + nif->read(mVelocityMult); + nif->read(mVelcoityVariation); + } + + void BSPSysInheritVelocityModifier::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mInheritObject.post(nif); + } + void BSPSysLODModifier::read(NIFStream* nif) { NiPSysModifier::read(nif); @@ -277,6 +301,28 @@ namespace Nif nif->read(mEndSize); } + void BSPSysScaleModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->readVector(mScales, nif->get()); + } + + void BSPSysSimpleColorModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mFadeInPercent); + nif->read(mFadeOutPercent); + nif->read(mColor1EndPercent); + nif->read(mColor1StartPercent); + nif->read(mColor2EndPercent); + nif->read(mColor2StartPercent); + nif->readVector(mColors, 3); + if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_F76) + nif->skip(52); // Unknown + } + void NiPSysEmitter::read(NIFStream* nif) { NiPSysModifier::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 55ed84b5ae..e887009a13 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -186,6 +186,13 @@ namespace Nif void post(Reader& nif) override; }; + struct NiPSysBoundUpdateModifier : public NiPSysModifier + { + uint16_t mUpdateSkip; + + void read(NIFStream* nif) override; + }; + struct NiPSysSpawnModifier : NiPSysModifier { uint16_t mNumSpawnGenerations; @@ -200,6 +207,17 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSPSysInheritVelocityModifier : public NiPSysModifier + { + NiObjectNETPtr mInheritObject; + float mInheritChance; + float mVelocityMult; + float mVelcoityVariation; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct BSPSysLODModifier : NiPSysModifier { float mLODStartDistance; @@ -210,6 +228,26 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSPSysScaleModifier : public NiPSysModifier + { + std::vector mScales; + + void read(NIFStream* nif) override; + }; + + struct BSPSysSimpleColorModifier : NiPSysModifier + { + float mFadeInPercent; + float mFadeOutPercent; + float mColor1EndPercent; + float mColor1StartPercent; + float mColor2EndPercent; + float mColor2StartPercent; + std::vector mColors; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiPSysEmitter : public NiPSysModifier { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index e519a0bcc3..770246aa08 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -94,7 +94,10 @@ namespace Nif RC_BSMultiBoundSphere, RC_BSNiAlphaPropertyTestRefController, RC_BSPackedAdditionalGeometryData, + RC_BSPSysInheritVelocityModifier, RC_BSPSysLODModifier, + RC_BSPSysScaleModifier, + RC_BSPSysSimpleColorModifier, RC_BSStripParticleSystem, RC_BSStripPSysData, RC_BSRefractionFirePeriodController, @@ -188,6 +191,7 @@ namespace Nif RC_NiPSysAirFieldInheritVelocityCtlr, RC_NiPSysAirFieldSpreadCtlr, RC_NiPSysBoxEmitter, + RC_NiPSysBoundUpdateModifier, RC_NiPSysCylinderEmitter, RC_NiPSysData, RC_NiPSysEmitterCtlr, From 120223d8dff7c9547c582595aa3fda416c014c63 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 04:42:46 +0300 Subject: [PATCH 17/22] Read even more Gamebryo/Bethesda particle records --- components/nif/niffile.cpp | 4 ++ components/nif/particle.cpp | 81 ++++++++++++++++++++++++++++++++++ components/nif/particle.hpp | 65 ++++++++++++++++++++++++--- components/nif/record.hpp | 4 ++ components/nifosg/particle.cpp | 6 +-- components/nifosg/particle.hpp | 2 +- 6 files changed, 151 insertions(+), 11 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index b60bb74594..6d29972f63 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -295,7 +295,10 @@ namespace Nif // Modifiers, Gamebryo { "NiPSysAgeDeathModifier", &construct }, { "NiPSysBoundUpdateModifier", &construct }, + { "NiPSysDragModifier", &construct }, + { "NiPSysGravityModifier", &construct }, { "NiPSysPositionModifier", &construct }, + { "NiPSysRotationModifier", &construct }, { "NiPSysSpawnModifier", &construct }, // Modifiers, Bethesda @@ -308,6 +311,7 @@ namespace Nif // Emitters { "NiPSysBoxEmitter", &construct }, { "NiPSysCylinderEmitter", &construct }, + { "NiPSysMeshEmitter", &construct }, { "NiPSysSphereEmitter", &construct }, // Modifier controllers, Gamebryo diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index f6e4ae9bc8..42ce8b57f9 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -260,6 +260,69 @@ namespace Nif nif->read(mUpdateSkip); } + void NiPSysDragModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + mDragObject.read(nif); + nif->read(mDragAxis); + nif->read(mPercentage); + nif->read(mRange); + nif->read(mRangeFalloff); + } + + void NiPSysDragModifier::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mDragObject.post(nif); + } + + void NiPSysGravityModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + mGravityObject.read(nif); + nif->read(mGravityAxis); + nif->read(mDecay); + nif->read(mStrength); + mForceType = static_cast(nif->get()); + nif->read(mTurbulence); + nif->read(mTurbulenceScale); + + if (nif->getBethVersion() >= 17) + nif->read(mWorldAligned); + } + + void NiPSysGravityModifier::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mGravityObject.post(nif); + } + + void NiPSysRotationModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mRotationSpeed); + + if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 2)) + { + nif->read(mRotationSpeedVariation); + + if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_F76) + nif->skip(5); // Unknown + + nif->read(mRotationAngle); + nif->read(mRotationAngleVariation); + nif->read(mRandomRotSpeedSign); + } + + nif->read(mRandomAxis); + nif->read(mAxis); + } + void NiPSysSpawnModifier::read(NIFStream* nif) { NiPSysModifier::read(nif); @@ -373,6 +436,24 @@ namespace Nif nif->read(mHeight); } + void NiPSysMeshEmitter::read(NIFStream* nif) + { + NiPSysEmitter::read(nif); + + readRecordList(nif, mEmitterMeshes); + + nif->read(mInitialVelocityType); + nif->read(mEmissionType); + nif->read(mEmissionAxis); + } + + void NiPSysMeshEmitter::post(Reader& nif) + { + NiPSysEmitter::post(nif); + + postRecordList(nif, mEmitterMeshes); + } + void NiPSysSphereEmitter::read(NIFStream* nif) { NiPSysVolumeEmitter::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index e887009a13..0c9379f0f9 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -34,14 +34,14 @@ namespace Nif void post(Reader& nif) override; }; + enum class ForceType : uint32_t + { + Wind = 0, // Fixed direction + Point = 1, // Fixed origin + }; + struct NiGravity : public NiParticleModifier { - enum class ForceType : uint32_t - { - Wind = 0, // Fixed direction - Point = 1, // Fixed origin - }; - float mDecay{ 0.f }; float mForce; ForceType mType; @@ -193,6 +193,46 @@ namespace Nif void read(NIFStream* nif) override; }; + struct NiPSysDragModifier : public NiPSysModifier + { + NiAVObjectPtr mDragObject; + osg::Vec3f mDragAxis; + float mPercentage; + float mRange; + float mRangeFalloff; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysGravityModifier : public NiPSysModifier + { + NiAVObjectPtr mGravityObject; + osg::Vec3f mGravityAxis; + float mDecay; + float mStrength; + ForceType mForceType; + float mTurbulence; + float mTurbulenceScale; + bool mWorldAligned; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysRotationModifier : public NiPSysModifier + { + float mRotationSpeed; + float mRotationSpeedVariation; + float mRotationAngle; + float mRotationAngleVariation; + bool mRandomRotSpeedSign; + bool mRandomAxis; + osg::Vec3f mAxis; + + void read(NIFStream* nif) override; + }; + struct NiPSysSpawnModifier : NiPSysModifier { uint16_t mNumSpawnGenerations; @@ -209,7 +249,7 @@ namespace Nif struct BSPSysInheritVelocityModifier : public NiPSysModifier { - NiObjectNETPtr mInheritObject; + NiAVObjectPtr mInheritObject; float mInheritChance; float mVelocityMult; float mVelcoityVariation; @@ -292,6 +332,17 @@ namespace Nif void read(NIFStream* nif) override; }; + struct NiPSysMeshEmitter : public NiPSysEmitter + { + NiAVObjectList mEmitterMeshes; + uint32_t mInitialVelocityType; + uint32_t mEmissionType; + osg::Vec3f mEmissionAxis; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct NiPSysSphereEmitter : public NiPSysVolumeEmitter { float mRadius; diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 770246aa08..3d5ec01bc3 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -194,6 +194,7 @@ namespace Nif RC_NiPSysBoundUpdateModifier, RC_NiPSysCylinderEmitter, RC_NiPSysData, + RC_NiPSysDragModifier, RC_NiPSysEmitterCtlr, RC_NiPSysEmitterCtlrData, RC_NiPSysEmitterDeclinationCtlr, @@ -206,13 +207,16 @@ namespace Nif RC_NiPSysFieldAttenuationCtlr, RC_NiPSysFieldMagnitudeCtlr, RC_NiPSysFieldMaxDistanceCtlr, + RC_NiPSysGravityModifier, RC_NiPSysGravityStrengthCtlr, RC_NiPSysInitialRotSpeedCtlr, RC_NiPSysInitialRotSpeedVarCtlr, RC_NiPSysInitialRotAngleCtlr, RC_NiPSysInitialRotAngleVarCtlr, + RC_NiPSysMeshEmitter, RC_NiPSysModifierActiveCtlr, RC_NiPSysPositionModifier, + RC_NiPSysRotationModifier, RC_NiPSysResetOnLoopCtlr, RC_NiPSysSpawnModifier, RC_NiPSysSphereEmitter, diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 8be0d4ba4f..551cbfeae8 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -304,7 +304,7 @@ namespace NifOsg bool absolute = (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF); // We don't need the position for Wind gravity, except if decay is being applied - if (mType == Nif::NiGravity::ForceType::Point || mDecay != 0.f) + if (mType == Nif::ForceType::Point || mDecay != 0.f) mCachedWorldPosition = absolute ? program->transformLocalToWorld(mPosition) : mPosition; mCachedWorldDirection = absolute ? program->rotateLocalToWorld(mDirection) : mDirection; @@ -316,7 +316,7 @@ namespace NifOsg const float magic = 1.6f; switch (mType) { - case Nif::NiGravity::ForceType::Wind: + case Nif::ForceType::Wind: { float decayFactor = 1.f; if (mDecay != 0.f) @@ -330,7 +330,7 @@ namespace NifOsg break; } - case Nif::NiGravity::ForceType::Point: + case Nif::ForceType::Point: { osg::Vec3f diff = mCachedWorldPosition - particle->getPosition(); diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index a9b628f695..967531013a 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -191,7 +191,7 @@ namespace NifOsg private: float mForce{ 0.f }; - Nif::NiGravity::ForceType mType{ Nif::NiGravity::ForceType::Wind }; + Nif::ForceType mType{ Nif::ForceType::Wind }; osg::Vec3f mPosition; osg::Vec3f mDirection; float mDecay{ 0.f }; From 5de3bdd2bcad2cc91b47c4f16fbdc5bd302261c9 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 05:01:18 +0300 Subject: [PATCH 18/22] Read Gamebryo particle colliders and a few more modifiers --- components/nif/niffile.cpp | 8 ++++ components/nif/particle.cpp | 86 ++++++++++++++++++++++++++++++++++++ components/nif/particle.hpp | 69 +++++++++++++++++++++++++++++ components/nif/record.hpp | 6 +++ components/nif/recordptr.hpp | 4 ++ 5 files changed, 173 insertions(+) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 6d29972f63..7f0d630be1 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -305,8 +305,11 @@ namespace Nif { "BSPSysInheritVelocityModifier", &construct }, { "BSPSysLODModifier", &construct }, + { "BSPSysRecycleBoundModifier", &construct }, { "BSPSysScaleModifier", &construct }, { "BSPSysSimpleColorModifier", &construct }, + { "BSPSysStripUpdateModifier", &construct }, + { "BSPSysSubTexModifier", &construct }, // Emitters { "NiPSysBoxEmitter", &construct }, @@ -347,6 +350,11 @@ namespace Nif { "NiPlanarCollider", &construct }, { "NiSphericalCollider", &construct }, + // Colliders, Gamebryo + { "NiPSysColliderManager", &construct }, + { "NiPSysPlanarCollider", &construct }, + { "NiPSysSphericalCollider", &construct }, + // Particle system controllers, 4.0.0.2 { "NiParticleSystemController", &construct }, diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 42ce8b57f9..289210662e 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -364,6 +364,22 @@ namespace Nif nif->read(mEndSize); } + void BSPSysRecycleBoundModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mBoundOffset); + nif->read(mBoundExtents); + mBoundObject.read(nif); + } + + void BSPSysRecycleBoundModifier::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mBoundObject.post(nif); + } + void BSPSysScaleModifier::read(NIFStream* nif) { NiPSysModifier::read(nif); @@ -386,6 +402,26 @@ namespace Nif nif->skip(52); // Unknown } + void BSPSysStripUpdateModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mUpdateDeltaTime); + } + + void BSPSysSubTexModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mStartFrame); + nif->read(mStartFrameFudge); + nif->read(mEndFrame); + nif->read(mLoopStartFrame); + nif->read(mLoopStartFrameFudge); + nif->read(mFrameCount); + nif->read(mFrameCountFudge); + } + void NiPSysEmitter::read(NIFStream* nif) { NiPSysModifier::read(nif); @@ -496,4 +532,54 @@ namespace Nif mVisKeyList->mKeys[nif->get()].mValue = nif->get() != 0; } + void NiPSysCollider::read(NIFStream* nif) + { + nif->read(mBounce); + nif->read(mCollideSpawn); + nif->read(mCollideDie); + mSpawnModifier.read(nif); + mParent.read(nif); + mNextCollider.read(nif); + mColliderObject.read(nif); + } + + void NiPSysCollider::post(Reader& nif) + { + mSpawnModifier.post(nif); + mParent.post(nif); + mNextCollider.post(nif); + mColliderObject.post(nif); + } + + void NiPSysColliderManager::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + mCollider.read(nif); + } + + void NiPSysColliderManager::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mCollider.post(nif); + } + + void NiPSysSphericalCollider::read(NIFStream* nif) + { + NiPSysCollider::read(nif); + + nif->read(mRadius); + } + + void NiPSysPlanarCollider::read(NIFStream* nif) + { + NiPSysCollider::read(nif); + + nif->read(mWidth); + nif->read(mHeight); + nif->read(mXAxis); + nif->read(mYAxis); + } + } diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 0c9379f0f9..876c1c6a75 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -268,6 +268,16 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSPSysRecycleBoundModifier : NiPSysModifier + { + osg::Vec3f mBoundOffset; + osg::Vec3f mBoundExtents; + NiAVObjectPtr mBoundObject; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct BSPSysScaleModifier : public NiPSysModifier { std::vector mScales; @@ -288,6 +298,26 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSPSysStripUpdateModifier : NiPSysModifier + { + float mUpdateDeltaTime; + + void read(NIFStream* nif) override; + }; + + struct BSPSysSubTexModifier : public NiPSysModifier + { + float mStartFrame; + float mStartFrameFudge; + float mEndFrame; + float mLoopStartFrame; + float mLoopStartFrameFudge; + float mFrameCount; + float mFrameCountFudge; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiPSysEmitter : public NiPSysModifier { @@ -399,5 +429,44 @@ namespace Nif void read(NIFStream* nif) override; }; + struct NiPSysCollider : Record + { + float mBounce; + bool mCollideSpawn; + bool mCollideDie; + NiPSysSpawnModifierPtr mSpawnModifier; + NiPSysColliderManagerPtr mParent; + NiPSysColliderPtr mNextCollider; + NiAVObjectPtr mColliderObject; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysColliderManager : NiPSysModifier + { + NiPSysColliderPtr mCollider; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysPlanarCollider : NiPSysCollider + { + float mWidth; + float mHeight; + osg::Vec3f mXAxis; + osg::Vec3f mYAxis; + + void read(NIFStream* nif) override; + }; + + struct NiPSysSphericalCollider : NiPSysCollider + { + float mRadius; + + void read(NIFStream* nif) override; + }; + } #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 3d5ec01bc3..6b59465a14 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -96,8 +96,11 @@ namespace Nif RC_BSPackedAdditionalGeometryData, RC_BSPSysInheritVelocityModifier, RC_BSPSysLODModifier, + RC_BSPSysRecycleBoundModifier, RC_BSPSysScaleModifier, RC_BSPSysSimpleColorModifier, + RC_BSPSysStripUpdateModifier, + RC_BSPSysSubTexModifier, RC_BSStripParticleSystem, RC_BSStripPSysData, RC_BSRefractionFirePeriodController, @@ -192,6 +195,7 @@ namespace Nif RC_NiPSysAirFieldSpreadCtlr, RC_NiPSysBoxEmitter, RC_NiPSysBoundUpdateModifier, + RC_NiPSysColliderManager, RC_NiPSysCylinderEmitter, RC_NiPSysData, RC_NiPSysDragModifier, @@ -215,10 +219,12 @@ namespace Nif RC_NiPSysInitialRotAngleVarCtlr, RC_NiPSysMeshEmitter, RC_NiPSysModifierActiveCtlr, + RC_NiPSysPlanarCollider, RC_NiPSysPositionModifier, RC_NiPSysRotationModifier, RC_NiPSysResetOnLoopCtlr, RC_NiPSysSpawnModifier, + RC_NiPSysSphericalCollider, RC_NiPSysSphereEmitter, RC_NiPSysUpdateCtlr, RC_NiRollController, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 6223740e31..b2168d9f1f 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -130,6 +130,8 @@ namespace Nif struct NiPalette; struct NiParticleModifier; struct NiParticleSystem; + struct NiPSysCollider; + struct NiPSysColliderManager; struct NiPSysEmitterCtlrData; struct NiPSysModifier; struct NiPSysSpawnModifier; @@ -175,6 +177,8 @@ namespace Nif using NiPalettePtr = RecordPtrT; using NiParticleModifierPtr = RecordPtrT; using NiParticleSystemPtr = RecordPtrT; + using NiPSysColliderPtr = RecordPtrT; + using NiPSysColliderManagerPtr = RecordPtrT; using NiPSysEmitterCtlrDataPtr = RecordPtrT; using NiPSysSpawnModifierPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; From 0ad3463d36748959d6ca69d15b2281daedd4d835 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 05:28:18 +0300 Subject: [PATCH 19/22] Read BSWindModifier and NiPSysBombModifier --- components/nif/niffile.cpp | 2 ++ components/nif/particle.cpp | 26 ++++++++++++++++++++++++++ components/nif/particle.hpp | 20 ++++++++++++++++++++ components/nif/record.hpp | 4 +++- 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 7f0d630be1..b0dde04d32 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -294,6 +294,7 @@ namespace Nif // Modifiers, Gamebryo { "NiPSysAgeDeathModifier", &construct }, + { "NiPSysBombModifier", &construct }, { "NiPSysBoundUpdateModifier", &construct }, { "NiPSysDragModifier", &construct }, { "NiPSysGravityModifier", &construct }, @@ -310,6 +311,7 @@ namespace Nif { "BSPSysSimpleColorModifier", &construct }, { "BSPSysStripUpdateModifier", &construct }, { "BSPSysSubTexModifier", &construct }, + { "BSWindModifier", &construct }, // Emitters { "NiPSysBoxEmitter", &construct }, diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 289210662e..4a7603ca77 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -253,6 +253,25 @@ namespace Nif mSpawnModifier.post(nif); } + void NiPSysBombModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + mBombObject.read(nif); + nif->read(mBombAxis); + nif->read(mDecay); + nif->read(mDeltaV); + nif->read(mDecayType); + nif->read(mSymmetryType); + } + + void NiPSysBombModifier::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mBombObject.post(nif); + } + void NiPSysBoundUpdateModifier::read(NIFStream* nif) { NiPSysModifier::read(nif); @@ -422,6 +441,13 @@ namespace Nif nif->read(mFrameCountFudge); } + void BSWindModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mStrength); + } + void NiPSysEmitter::read(NIFStream* nif) { NiPSysModifier::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 876c1c6a75..6c6306701b 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -186,6 +186,19 @@ namespace Nif void post(Reader& nif) override; }; + struct NiPSysBombModifier : NiPSysModifier + { + NiAVObjectPtr mBombObject; + osg::Vec3f mBombAxis; + float mDecay; + float mDeltaV; + uint32_t mDecayType; + uint32_t mSymmetryType; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct NiPSysBoundUpdateModifier : public NiPSysModifier { uint16_t mUpdateSkip; @@ -318,6 +331,13 @@ namespace Nif void read(NIFStream* nif) override; }; + struct BSWindModifier : NiPSysModifier + { + float mStrength; + + void read(NIFStream* nif) override; + }; + // Abstract struct NiPSysEmitter : public NiPSysModifier { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 6b59465a14..ed497323a9 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -113,6 +113,7 @@ namespace Nif RC_BSTriShape, RC_BSWArray, RC_BSWaterShaderProperty, + RC_BSWindModifier, RC_BSXFlags, RC_DistantLODShaderProperty, RC_HairShaderProperty, @@ -193,8 +194,9 @@ namespace Nif RC_NiPSysAirFieldAirFrictionCtlr, RC_NiPSysAirFieldInheritVelocityCtlr, RC_NiPSysAirFieldSpreadCtlr, - RC_NiPSysBoxEmitter, + RC_NiPSysBombModifier, RC_NiPSysBoundUpdateModifier, + RC_NiPSysBoxEmitter, RC_NiPSysColliderManager, RC_NiPSysCylinderEmitter, RC_NiPSysData, From 655dcef34ca2bb06efbd17c01e2b559a47646e61 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 11:12:35 +0300 Subject: [PATCH 20/22] Fix >1 particle radii loading --- components/nif/particle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 4a7603ca77..e9da792e6e 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -102,7 +102,7 @@ namespace Nif nif->read(mNumParticles); bool isBs202 = nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() != 0; - bool numRadii = 1; + uint16_t numRadii = 1; if (nif->getVersion() > NIFStream::generateVersion(10, 0, 1, 0)) numRadii = (nif->get() && !isBs202) ? mNumVertices : 0; nif->readVector(mRadii, numRadii); From a416d18adf51ef0f97109450ffa53061b7c2ac96 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 11:32:28 +0300 Subject: [PATCH 21/22] Read NiPSysColorModifier, NiPSysGrowFadeModifier, BSPSysArrayEmitter --- components/nif/niffile.cpp | 7 ++++++- components/nif/particle.cpp | 27 +++++++++++++++++++++++++++ components/nif/particle.hpp | 19 +++++++++++++++++++ components/nif/record.hpp | 3 +++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index b0dde04d32..f526c1e3d4 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -296,8 +296,10 @@ namespace Nif { "NiPSysAgeDeathModifier", &construct }, { "NiPSysBombModifier", &construct }, { "NiPSysBoundUpdateModifier", &construct }, + { "NiPSysColorModifier", &construct }, { "NiPSysDragModifier", &construct }, { "NiPSysGravityModifier", &construct }, + { "NiPSysGrowFadeModifier", &construct }, { "NiPSysPositionModifier", &construct }, { "NiPSysRotationModifier", &construct }, { "NiPSysSpawnModifier", &construct }, @@ -313,12 +315,15 @@ namespace Nif { "BSPSysSubTexModifier", &construct }, { "BSWindModifier", &construct }, - // Emitters + // Emitters, Gamebryo { "NiPSysBoxEmitter", &construct }, { "NiPSysCylinderEmitter", &construct }, { "NiPSysMeshEmitter", &construct }, { "NiPSysSphereEmitter", &construct }, + // Emitters, Bethesda + { "BSPSysArrayEmitter", &construct }, + // Modifier controllers, Gamebryo { "NiPSysAirFieldAirFrictionCtlr", &construct }, { "NiPSysAirFieldInheritVelocityCtlr", diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index e9da792e6e..0d3545acd5 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -279,6 +279,20 @@ namespace Nif nif->read(mUpdateSkip); } + void NiPSysColorModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + mData.read(nif); + } + + void NiPSysColorModifier::post(Reader& nif) + { + NiPSysModifier::post(nif); + + mData.post(nif); + } + void NiPSysDragModifier::read(NIFStream* nif) { NiPSysModifier::read(nif); @@ -320,6 +334,19 @@ namespace Nif mGravityObject.post(nif); } + void NiPSysGrowFadeModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mGrowTime); + nif->read(mGrowGeneration); + nif->read(mFadeTime); + nif->read(mFadeGeneration); + if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS + && nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO3) + nif->read(mBaseScale); + } + void NiPSysRotationModifier::read(NIFStream* nif) { NiPSysModifier::read(nif); diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index 6c6306701b..f40dac44ce 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -206,6 +206,14 @@ namespace Nif void read(NIFStream* nif) override; }; + struct NiPSysColorModifier : NiPSysModifier + { + NiColorDataPtr mData; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + struct NiPSysDragModifier : public NiPSysModifier { NiAVObjectPtr mDragObject; @@ -233,6 +241,17 @@ namespace Nif void post(Reader& nif) override; }; + struct NiPSysGrowFadeModifier : NiPSysModifier + { + float mGrowTime; + uint16_t mGrowGeneration; + float mFadeTime; + uint16_t mFadeGeneration; + float mBaseScale; + + void read(NIFStream* nif) override; + }; + struct NiPSysRotationModifier : public NiPSysModifier { float mRotationSpeed; diff --git a/components/nif/record.hpp b/components/nif/record.hpp index ed497323a9..f7bb4fa648 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -94,6 +94,7 @@ namespace Nif RC_BSMultiBoundSphere, RC_BSNiAlphaPropertyTestRefController, RC_BSPackedAdditionalGeometryData, + RC_BSPSysArrayEmitter, RC_BSPSysInheritVelocityModifier, RC_BSPSysLODModifier, RC_BSPSysRecycleBoundModifier, @@ -198,6 +199,7 @@ namespace Nif RC_NiPSysBoundUpdateModifier, RC_NiPSysBoxEmitter, RC_NiPSysColliderManager, + RC_NiPSysColorModifier, RC_NiPSysCylinderEmitter, RC_NiPSysData, RC_NiPSysDragModifier, @@ -215,6 +217,7 @@ namespace Nif RC_NiPSysFieldMaxDistanceCtlr, RC_NiPSysGravityModifier, RC_NiPSysGravityStrengthCtlr, + RC_NiPSysGrowFadeModifier, RC_NiPSysInitialRotSpeedCtlr, RC_NiPSysInitialRotSpeedVarCtlr, RC_NiPSysInitialRotAngleCtlr, From 470852f88e2d07a05eba54f8e5998e673337f703 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 22 Sep 2023 21:59:24 +0300 Subject: [PATCH 22/22] Cleanup --- components/nif/particle.hpp | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/components/nif/particle.hpp b/components/nif/particle.hpp index f40dac44ce..8fc24ee407 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -9,7 +9,7 @@ namespace Nif { - struct NiParticleModifier : public Record + struct NiParticleModifier : Record { NiParticleModifierPtr mNext; NiTimeControllerPtr mController; @@ -18,7 +18,7 @@ namespace Nif void post(Reader& nif) override; }; - struct NiParticleGrowFade : public NiParticleModifier + struct NiParticleGrowFade : NiParticleModifier { float mGrowTime; float mFadeTime; @@ -26,7 +26,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiParticleColorModifier : public NiParticleModifier + struct NiParticleColorModifier : NiParticleModifier { NiColorDataPtr mData; @@ -40,7 +40,7 @@ namespace Nif Point = 1, // Fixed origin }; - struct NiGravity : public NiParticleModifier + struct NiGravity : NiParticleModifier { float mDecay{ 0.f }; float mForce; @@ -51,7 +51,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiParticleCollider : public NiParticleModifier + struct NiParticleCollider : NiParticleModifier { float mBounceFactor; bool mSpawnOnCollision{ false }; @@ -61,7 +61,7 @@ namespace Nif }; // NiPinaColada - struct NiPlanarCollider : public NiParticleCollider + struct NiPlanarCollider : NiParticleCollider { osg::Vec2f mExtents; osg::Vec3f mPosition; @@ -72,7 +72,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiSphericalCollider : public NiParticleCollider + struct NiSphericalCollider : NiParticleCollider { float mRadius; osg::Vec3f mCenter; @@ -80,7 +80,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiParticleRotation : public NiParticleModifier + struct NiParticleRotation : NiParticleModifier { uint8_t mRandomInitialAxis; osg::Vec3f mInitialAxis; @@ -199,7 +199,7 @@ namespace Nif void post(Reader& nif) override; }; - struct NiPSysBoundUpdateModifier : public NiPSysModifier + struct NiPSysBoundUpdateModifier : NiPSysModifier { uint16_t mUpdateSkip; @@ -214,7 +214,7 @@ namespace Nif void post(Reader& nif) override; }; - struct NiPSysDragModifier : public NiPSysModifier + struct NiPSysDragModifier : NiPSysModifier { NiAVObjectPtr mDragObject; osg::Vec3f mDragAxis; @@ -226,7 +226,7 @@ namespace Nif void post(Reader& nif) override; }; - struct NiPSysGravityModifier : public NiPSysModifier + struct NiPSysGravityModifier : NiPSysModifier { NiAVObjectPtr mGravityObject; osg::Vec3f mGravityAxis; @@ -252,7 +252,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiPSysRotationModifier : public NiPSysModifier + struct NiPSysRotationModifier : NiPSysModifier { float mRotationSpeed; float mRotationSpeedVariation; @@ -279,7 +279,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct BSPSysInheritVelocityModifier : public NiPSysModifier + struct BSPSysInheritVelocityModifier : NiPSysModifier { NiAVObjectPtr mInheritObject; float mInheritChance; @@ -310,7 +310,7 @@ namespace Nif void post(Reader& nif) override; }; - struct BSPSysScaleModifier : public NiPSysModifier + struct BSPSysScaleModifier : NiPSysModifier { std::vector mScales; @@ -337,7 +337,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct BSPSysSubTexModifier : public NiPSysModifier + struct BSPSysSubTexModifier : NiPSysModifier { float mStartFrame; float mStartFrameFudge; @@ -358,7 +358,7 @@ namespace Nif }; // Abstract - struct NiPSysEmitter : public NiPSysModifier + struct NiPSysEmitter : NiPSysModifier { float mSpeed; float mSpeedVariation; @@ -376,7 +376,7 @@ namespace Nif }; // Abstract - struct NiPSysVolumeEmitter : public NiPSysEmitter + struct NiPSysVolumeEmitter : NiPSysEmitter { NiAVObjectPtr mEmitterObject; @@ -384,7 +384,7 @@ namespace Nif void post(Reader& nif) override; }; - struct NiPSysBoxEmitter : public NiPSysVolumeEmitter + struct NiPSysBoxEmitter : NiPSysVolumeEmitter { float mWidth; float mHeight; @@ -393,7 +393,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiPSysCylinderEmitter : public NiPSysVolumeEmitter + struct NiPSysCylinderEmitter : NiPSysVolumeEmitter { float mRadius; float mHeight; @@ -401,7 +401,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiPSysMeshEmitter : public NiPSysEmitter + struct NiPSysMeshEmitter : NiPSysEmitter { NiAVObjectList mEmitterMeshes; uint32_t mInitialVelocityType; @@ -412,7 +412,7 @@ namespace Nif void post(Reader& nif) override; }; - struct NiPSysSphereEmitter : public NiPSysVolumeEmitter + struct NiPSysSphereEmitter : NiPSysVolumeEmitter { float mRadius;