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/nif/controller.cpp b/components/nif/controller.cpp index 73644f1541..a3033357ec 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -526,6 +526,80 @@ 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 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 3104c29f94..8a7d306a85 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 { @@ -372,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/data.cpp b/components/nif/data.cpp index c7f9e71fda..9aa61b4db7 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -13,16 +13,28 @@ 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 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)) { nif->read(mKeepFlags); 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 +46,7 @@ namespace Nif nif->read(mMaterialHash); } - if (nif->get()) + if (nif->get() && hasData) { nif->readVector(mNormals, mNumVertices); if (mDataFlags & DataFlag_HasTangents) @@ -46,7 +58,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 +76,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 +161,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..f526c1e3d4 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 }, @@ -107,8 +108,9 @@ namespace Nif { "NiGeomMorpherController", &construct }, { "NiKeyframeController", &construct }, { "NiLookAtController", &construct }, + // FIXME: NiLightColorController should have its own struct + { "NiLightColorController", &construct }, { "NiMaterialColorController", &construct }, - { "NiParticleSystemController", &construct }, { "NiPathController", &construct }, { "NiRollController", &construct }, { "NiUVController", &construct }, @@ -123,6 +125,13 @@ namespace Nif { "NiMultiTargetTransformController", &construct }, + // Extra data controllers, Gamebryo + { "NiColorExtraDataController", &construct }, + { "NiFloatExtraDataController", &construct }, + { "NiFloatsExtraDataController", &construct }, + { "NiFloatsExtraDataPoint3Controller", + &construct }, + // Bethesda { "BSFrustumFOVController", &construct }, { "BSKeyframeController", &construct }, @@ -155,6 +164,7 @@ namespace Nif { "NiBoolTimelineInterpolator", &construct }, { "NiColorInterpolator", &construct }, { "NiFloatInterpolator", &construct }, + { "NiPathInterpolator", &construct }, { "NiPoint3Interpolator", &construct }, { "NiTransformInterpolator", &construct }, @@ -240,14 +250,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,16 +269,106 @@ namespace Nif // PARTICLES + // Geometry, 4.0.0.2 + { "NiAutoNormalParticles", &construct }, + { "NiAutoNormalParticlesData", &construct }, + { "NiParticles", &construct }, + { "NiParticlesData", &construct }, + { "NiRotatingParticles", &construct }, + { "NiRotatingParticlesData", &construct }, + + // Geometry, Gamebryo + { "NiParticleSystem", &construct }, + { "NiMeshParticleSystem", &construct }, + { "NiPSysData", &construct }, + + // Geometry, Bethesda + { "BSStripParticleSystem", &construct }, + { "BSStripPSysData", &construct }, + // Modifiers, 4.0.0.2 { "NiGravity", &construct }, { "NiParticleColorModifier", &construct }, { "NiParticleGrowFade", &construct }, { "NiParticleRotation", &construct }, + // Modifiers, Gamebryo + { "NiPSysAgeDeathModifier", &construct }, + { "NiPSysBombModifier", &construct }, + { "NiPSysBoundUpdateModifier", &construct }, + { "NiPSysColorModifier", &construct }, + { "NiPSysDragModifier", &construct }, + { "NiPSysGravityModifier", &construct }, + { "NiPSysGrowFadeModifier", &construct }, + { "NiPSysPositionModifier", &construct }, + { "NiPSysRotationModifier", &construct }, + { "NiPSysSpawnModifier", &construct }, + + // Modifiers, Bethesda + { "BSPSysInheritVelocityModifier", + &construct }, + { "BSPSysLODModifier", &construct }, + { "BSPSysRecycleBoundModifier", &construct }, + { "BSPSysScaleModifier", &construct }, + { "BSPSysSimpleColorModifier", &construct }, + { "BSPSysStripUpdateModifier", &construct }, + { "BSPSysSubTexModifier", &construct }, + { "BSWindModifier", &construct }, + + // Emitters, Gamebryo + { "NiPSysBoxEmitter", &construct }, + { "NiPSysCylinderEmitter", &construct }, + { "NiPSysMeshEmitter", &construct }, + { "NiPSysSphereEmitter", &construct }, + + // Emitters, Bethesda + { "BSPSysArrayEmitter", &construct }, + + // 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 { "NiPlanarCollider", &construct }, { "NiSphericalCollider", &construct }, + // Colliders, Gamebryo + { "NiPSysColliderManager", &construct }, + { "NiPSysPlanarCollider", &construct }, + { "NiPSysSphericalCollider", &construct }, + + // Particle system controllers, 4.0.0.2 + { "NiParticleSystemController", &construct }, + + // Particle system controllers, Gamebryo + { "NiPSysResetOnLoopCtlr", &construct }, + { "NiPSysUpdateCtlr", &construct }, + // PHYSICS // Collision objects, Gamebryo @@ -288,9 +382,11 @@ namespace Nif { "bhkBlendCollisionObject", &construct }, // Constraint records, Bethesda + { "bhkBallAndSocketConstraint", &construct }, { "bhkHingeConstraint", &construct }, { "bhkLimitedHingeConstraint", &construct }, { "bhkRagdollConstraint", &construct }, + { "bhkStiffSpringConstraint", &construct }, // Physics body records, Bethesda { "bhkRigidBody", &construct }, @@ -341,6 +437,8 @@ namespace Nif { "BSDistantTreeShaderProperty", &construct }, { "BSLightingShaderProperty", &construct }, { "BSEffectShaderProperty", &construct }, + { "BSSkyShaderProperty", &construct }, + { "BSWaterShaderProperty", &construct }, { "DistantLODShaderProperty", &construct }, { "HairShaderProperty", &construct }, { "Lighting30ShaderProperty", &construct }, @@ -505,10 +603,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); diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index ae391c59e4..0d3545acd5 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -92,4 +92,547 @@ 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; + + uint16_t 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 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); + + 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 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); + mOrder = static_cast(nif->get()); + mTarget.read(nif); + nif->read(mActive); + } + + void NiPSysModifier::post(Reader& 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 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); + + 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); + + 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 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); + + 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); + + 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 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); + + nif->read(mLODStartDistance); + nif->read(mLODEndDistance); + nif->read(mEndEmitScale); + 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); + + 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 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 BSWindModifier::read(NIFStream* nif) + { + NiPSysModifier::read(nif); + + nif->read(mStrength); + } + + 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 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); + + nif->read(mRadius); + } + + 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(); + 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; + } + + 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 328498210a..8fc24ee407 100644 --- a/components/nif/particle.hpp +++ b/components/nif/particle.hpp @@ -2,11 +2,14 @@ #define OPENMW_COMPONENTS_NIF_PARTICLE_HPP #include "base.hpp" +#include "controller.hpp" +#include "data.hpp" +#include "node.hpp" namespace Nif { - struct NiParticleModifier : public Record + struct NiParticleModifier : Record { NiParticleModifierPtr mNext; NiTimeControllerPtr mController; @@ -15,7 +18,7 @@ namespace Nif void post(Reader& nif) override; }; - struct NiParticleGrowFade : public NiParticleModifier + struct NiParticleGrowFade : NiParticleModifier { float mGrowTime; float mFadeTime; @@ -23,7 +26,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiParticleColorModifier : public NiParticleModifier + struct NiParticleColorModifier : NiParticleModifier { NiColorDataPtr mData; @@ -31,14 +34,14 @@ namespace Nif void post(Reader& nif) override; }; - struct NiGravity : public NiParticleModifier + enum class ForceType : uint32_t { - enum class ForceType : uint32_t - { - Wind = 0, // Fixed direction - Point = 1, // Fixed origin - }; + Wind = 0, // Fixed direction + Point = 1, // Fixed origin + }; + struct NiGravity : NiParticleModifier + { float mDecay{ 0.f }; float mForce; ForceType mType; @@ -48,7 +51,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiParticleCollider : public NiParticleModifier + struct NiParticleCollider : NiParticleModifier { float mBounceFactor; bool mSpawnOnCollision{ false }; @@ -58,7 +61,7 @@ namespace Nif }; // NiPinaColada - struct NiPlanarCollider : public NiParticleCollider + struct NiPlanarCollider : NiParticleCollider { osg::Vec2f mExtents; osg::Vec3f mPosition; @@ -69,7 +72,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiSphericalCollider : public NiParticleCollider + struct NiSphericalCollider : NiParticleCollider { float mRadius; osg::Vec3f mCenter; @@ -77,7 +80,7 @@ namespace Nif void read(NIFStream* nif) override; }; - struct NiParticleRotation : public NiParticleModifier + struct NiParticleRotation : NiParticleModifier { uint8_t mRandomInitialAxis; osg::Vec3f mInitialAxis; @@ -86,5 +89,423 @@ 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 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; + std::vector mRotationSpeeds; + uint16_t mNumAddedParticles; + uint16_t mAddedParticlesBase; + + 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 + { + 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; + }; + + struct NiPSysAgeDeathModifier : NiPSysModifier + { + bool mSpawnOnDeath; + NiPSysSpawnModifierPtr mSpawnModifier; + + void read(NIFStream* nif) override; + 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 : NiPSysModifier + { + uint16_t mUpdateSkip; + + void read(NIFStream* nif) override; + }; + + struct NiPSysColorModifier : NiPSysModifier + { + NiColorDataPtr mData; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysDragModifier : NiPSysModifier + { + NiAVObjectPtr mDragObject; + osg::Vec3f mDragAxis; + float mPercentage; + float mRange; + float mRangeFalloff; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysGravityModifier : 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 NiPSysGrowFadeModifier : NiPSysModifier + { + float mGrowTime; + uint16_t mGrowGeneration; + float mFadeTime; + uint16_t mFadeGeneration; + float mBaseScale; + + void read(NIFStream* nif) override; + }; + + struct NiPSysRotationModifier : 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; + float mPercentageSpawned; + uint16_t mMinNumToSpawn; + uint16_t mMaxNumToSpawn; + float mSpawnSpeedVariation; + float mSpawnDirVariation; + float mLifespan; + float mLifespanVariation; + + void read(NIFStream* nif) override; + }; + + struct BSPSysInheritVelocityModifier : NiPSysModifier + { + NiAVObjectPtr mInheritObject; + float mInheritChance; + float mVelocityMult; + float mVelcoityVariation; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct BSPSysLODModifier : NiPSysModifier + { + float mLODStartDistance; + float mLODEndDistance; + float mEndEmitScale; + float mEndSize; + + 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 : 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; + }; + + struct BSPSysStripUpdateModifier : NiPSysModifier + { + float mUpdateDeltaTime; + + void read(NIFStream* nif) override; + }; + + struct BSPSysSubTexModifier : NiPSysModifier + { + float mStartFrame; + float mStartFrameFudge; + float mEndFrame; + float mLoopStartFrame; + float mLoopStartFrameFudge; + float mFrameCount; + float mFrameCountFudge; + + void read(NIFStream* nif) override; + }; + + struct BSWindModifier : NiPSysModifier + { + float mStrength; + + void read(NIFStream* nif) override; + }; + + // Abstract + struct NiPSysEmitter : 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 : NiPSysEmitter + { + NiAVObjectPtr mEmitterObject; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysBoxEmitter : NiPSysVolumeEmitter + { + float mWidth; + float mHeight; + float mDepth; + + void read(NIFStream* nif) override; + }; + + struct NiPSysCylinderEmitter : NiPSysVolumeEmitter + { + float mRadius; + float mHeight; + + void read(NIFStream* nif) override; + }; + + struct NiPSysMeshEmitter : NiPSysEmitter + { + NiAVObjectList mEmitterMeshes; + uint32_t mInitialVelocityType; + uint32_t mEmissionType; + osg::Vec3f mEmissionAxis; + + void read(NIFStream* nif) override; + void post(Reader& nif) override; + }; + + struct NiPSysSphereEmitter : NiPSysVolumeEmitter + { + float mRadius; + + 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; + BoolKeyMapPtr mVisKeyList; + + 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/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/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; }; - struct SkyShaderProperty : BSShaderLightingProperty + enum class SkyObjectType : uint32_t { - enum class ObjectType : uint32_t - { - SkyTexture = 0, - SkySunglare = 1, - Sky = 2, - SkyClouds = 3, - SkyStars = 5, - SkyMoonStarsMask = 7, - }; + SkyTexture = 0, + SkySunglare = 1, + Sky = 2, + SkyClouds = 3, + SkyStars = 5, + SkyMoonStarsMask = 7, + }; + struct SkyShaderProperty : BSShaderLightingProperty + { 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 cecb9631d6..f7bb4fa648 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, @@ -92,14 +94,27 @@ namespace Nif RC_BSMultiBoundSphere, RC_BSNiAlphaPropertyTestRefController, RC_BSPackedAdditionalGeometryData, + RC_BSPSysArrayEmitter, + RC_BSPSysInheritVelocityModifier, + RC_BSPSysLODModifier, + RC_BSPSysRecycleBoundModifier, + RC_BSPSysScaleModifier, + RC_BSPSysSimpleColorModifier, + RC_BSPSysStripUpdateModifier, + RC_BSPSysSubTexModifier, + RC_BSStripParticleSystem, + RC_BSStripPSysData, RC_BSRefractionFirePeriodController, RC_BSRefractionStrengthController, RC_BSShaderNoLightingProperty, RC_BSShaderPPLightingProperty, RC_BSShaderProperty, RC_BSShaderTextureSet, + RC_BSSkyShaderProperty, RC_BSTriShape, RC_BSWArray, + RC_BSWaterShaderProperty, + RC_BSWindModifier, RC_BSXFlags, RC_DistantLODShaderProperty, RC_HairShaderProperty, @@ -127,6 +142,7 @@ namespace Nif RC_NiCollisionSwitch, RC_NiColorData, RC_NiColorExtraData, + RC_NiColorExtraDataController, RC_NiColorInterpolator, RC_NiControllerManager, RC_NiControllerSequence, @@ -136,8 +152,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, @@ -147,6 +166,7 @@ namespace Nif RC_NiKeyframeController, RC_NiKeyframeData, RC_NiLight, + RC_NiLightColorController, RC_NiLightDimmerController, RC_NiLines, RC_NiLinesData, @@ -163,12 +183,55 @@ namespace Nif RC_NiParticleRotation, RC_NiParticles, RC_NiParticlesData, + RC_NiParticleSystem, RC_NiParticleSystemController, RC_NiPathController, + RC_NiPathInterpolator, RC_NiPixelData, RC_NiPlanarCollider, RC_NiPoint3Interpolator, RC_NiPosData, + RC_NiPSysAgeDeathModifier, + RC_NiPSysAirFieldAirFrictionCtlr, + RC_NiPSysAirFieldInheritVelocityCtlr, + RC_NiPSysAirFieldSpreadCtlr, + RC_NiPSysBombModifier, + RC_NiPSysBoundUpdateModifier, + RC_NiPSysBoxEmitter, + RC_NiPSysColliderManager, + RC_NiPSysColorModifier, + RC_NiPSysCylinderEmitter, + RC_NiPSysData, + RC_NiPSysDragModifier, + 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_NiPSysGravityModifier, + RC_NiPSysGravityStrengthCtlr, + RC_NiPSysGrowFadeModifier, + RC_NiPSysInitialRotSpeedCtlr, + RC_NiPSysInitialRotSpeedVarCtlr, + RC_NiPSysInitialRotAngleCtlr, + RC_NiPSysInitialRotAngleVarCtlr, + RC_NiPSysMeshEmitter, + RC_NiPSysModifierActiveCtlr, + RC_NiPSysPlanarCollider, + RC_NiPSysPositionModifier, + RC_NiPSysRotationModifier, + RC_NiPSysResetOnLoopCtlr, + RC_NiPSysSpawnModifier, + RC_NiPSysSphericalCollider, + RC_NiPSysSphereEmitter, + RC_NiPSysUpdateCtlr, RC_NiRollController, RC_NiSequence, RC_NiSequenceStreamHelper, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 8598a88f0e..b2168d9f1f 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -129,6 +129,12 @@ namespace Nif struct NiSourceTexture; struct NiPalette; struct NiParticleModifier; + struct NiParticleSystem; + struct NiPSysCollider; + struct NiPSysColliderManager; + struct NiPSysEmitterCtlrData; + struct NiPSysModifier; + struct NiPSysSpawnModifier; struct NiBoolData; struct NiSkinPartition; struct BSShaderTextureSet; @@ -170,6 +176,11 @@ namespace Nif using NiSourceTexturePtr = RecordPtrT; using NiPalettePtr = RecordPtrT; using NiParticleModifierPtr = RecordPtrT; + using NiParticleSystemPtr = RecordPtrT; + using NiPSysColliderPtr = RecordPtrT; + using NiPSysColliderManagerPtr = RecordPtrT; + using NiPSysEmitterCtlrDataPtr = RecordPtrT; + using NiPSysSpawnModifierPtr = RecordPtrT; using NiBoolDataPtr = RecordPtrT; using NiSkinPartitionPtr = RecordPtrT; using BSShaderTextureSetPtr = RecordPtrT; @@ -202,6 +213,7 @@ namespace Nif using bhkSerializableList = RecordListT; using bhkEntityList = RecordListT; using NiControllerSequenceList = RecordListT; + using NiPSysModifierList = RecordListT; } // Namespace #endif 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 }; 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); }