Merge branch 'somethinginparticlular' into 'master'

Read even more NIF records

See merge request OpenMW/openmw!3442
macos_ci_fix
psi29a 1 year ago
commit 6d32caa2d6

@ -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 {};
}
};
}

@ -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))

@ -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<NiQuatTransform, NiKeyframeDataPtr>;
using NiColorInterpolator = TypedNiInterpolator<osg::Vec4f, NiColorDataPtr>;
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
{

@ -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<bool>())
if (nif->get<bool>() && 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<bool>())
if (nif->get<bool>() && hasData)
{
nif->readVector(mNormals, mNumVertices);
if (mDataFlags & DataFlag_HasTangents)
@ -46,7 +58,7 @@ namespace Nif
nif->read(mBoundingSphere);
if (nif->get<bool>())
if (nif->get<bool>() && hasData)
nif->readVector(mColors, mNumVertices);
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0))
@ -64,13 +76,16 @@ namespace Nif
else if (!nif->get<bool>())
numUVs = 0;
mUVList.resize(numUVs);
for (std::vector<osg::Vec2f>& 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<osg::Vec2f>& 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<bool>() && !isBs202) ? mNumVertices : 0;
nif->readVector(mRadii, numRadii);
nif->read(mActiveCount);
if (nif->get<bool>() && !isBs202)
nif->readVector(mSizes, mNumVertices);
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
{
if (nif->get<bool>() && !isBs202)
nif->readVector(mRotations, mNumVertices);
if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 4))
{
if (nif->get<bool>() && !isBs202)
nif->readVector(mRotationAngles, mNumVertices);
if (nif->get<bool>() && !isBs202)
nif->readVector(mRotationAxes, mNumVertices);
if (isBs202)
{
nif->read(mHasTextureIndices);
uint32_t numSubtextureOffsets;
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
numSubtextureOffsets = nif->get<uint8_t>();
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<bool>())
nif->readVector(mRotations, mNumVertices);
}
void NiPosData::read(NIFStream* nif)
{
mKeyList = std::make_shared<Vector3KeyMap>();

@ -70,32 +70,6 @@ namespace Nif
void read(NIFStream* nif) override;
};
struct NiParticlesData : public NiGeometryData
{
uint16_t mNumParticles{ 0 };
uint16_t mActiveCount;
std::vector<float> mRadii;
std::vector<float> mSizes;
std::vector<osg::Quat> mRotations;
std::vector<float> mRotationAngles;
std::vector<osg::Vec3f> mRotationAxes;
bool mHasTextureIndices{ false };
std::vector<osg::Vec4f> 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;

@ -69,6 +69,7 @@ namespace Nif
// NiNode-like nodes, Bethesda
{ "BSBlastNode", &construct<BSRangeNode, RC_NiNode> },
{ "BSDamageStage", &construct<BSRangeNode, RC_NiNode> },
{ "BSDebrisNode", &construct<BSRangeNode, RC_NiNode> },
{ "BSFadeNode", &construct<NiNode, RC_NiNode> },
{ "BSLeafAnimNode", &construct<NiNode, RC_NiNode> },
{ "BSMultiBoundNode", &construct<BSMultiBoundNode, RC_NiNode> },
@ -107,8 +108,9 @@ namespace Nif
{ "NiGeomMorpherController", &construct<NiGeomMorpherController, RC_NiGeomMorpherController> },
{ "NiKeyframeController", &construct<NiKeyframeController, RC_NiKeyframeController> },
{ "NiLookAtController", &construct<NiLookAtController, RC_NiLookAtController> },
// FIXME: NiLightColorController should have its own struct
{ "NiLightColorController", &construct<NiMaterialColorController, RC_NiLightColorController> },
{ "NiMaterialColorController", &construct<NiMaterialColorController, RC_NiMaterialColorController> },
{ "NiParticleSystemController", &construct<NiParticleSystemController, RC_NiParticleSystemController> },
{ "NiPathController", &construct<NiPathController, RC_NiPathController> },
{ "NiRollController", &construct<NiRollController, RC_NiRollController> },
{ "NiUVController", &construct<NiUVController, RC_NiUVController> },
@ -123,6 +125,13 @@ namespace Nif
{ "NiMultiTargetTransformController",
&construct<NiMultiTargetTransformController, RC_NiMultiTargetTransformController> },
// Extra data controllers, Gamebryo
{ "NiColorExtraDataController", &construct<NiExtraDataController, RC_NiColorExtraDataController> },
{ "NiFloatExtraDataController", &construct<NiFloatExtraDataController, RC_NiFloatExtraDataController> },
{ "NiFloatsExtraDataController", &construct<NiFloatsExtraDataController, RC_NiFloatsExtraDataController> },
{ "NiFloatsExtraDataPoint3Controller",
&construct<NiFloatsExtraDataPoint3Controller, RC_NiFloatsExtraDataPoint3Controller> },
// Bethesda
{ "BSFrustumFOVController", &construct<NiFloatInterpController, RC_BSFrustumFOVController> },
{ "BSKeyframeController", &construct<BSKeyframeController, RC_BSKeyframeController> },
@ -155,6 +164,7 @@ namespace Nif
{ "NiBoolTimelineInterpolator", &construct<NiBoolInterpolator, RC_NiBoolTimelineInterpolator> },
{ "NiColorInterpolator", &construct<NiColorInterpolator, RC_NiColorInterpolator> },
{ "NiFloatInterpolator", &construct<NiFloatInterpolator, RC_NiFloatInterpolator> },
{ "NiPathInterpolator", &construct<NiPathInterpolator, RC_NiPathInterpolator> },
{ "NiPoint3Interpolator", &construct<NiPoint3Interpolator, RC_NiPoint3Interpolator> },
{ "NiTransformInterpolator", &construct<NiTransformInterpolator, RC_NiTransformInterpolator> },
@ -240,14 +250,8 @@ namespace Nif
// GEOMETRY
// 4.0.0.2
{ "NiAutoNormalParticles", &construct<NiParticles, RC_NiParticles> },
{ "NiAutoNormalParticlesData", &construct<NiParticlesData, RC_NiParticlesData> },
{ "NiLines", &construct<NiLines, RC_NiLines> },
{ "NiLinesData", &construct<NiLinesData, RC_NiLinesData> },
{ "NiParticles", &construct<NiParticles, RC_NiParticles> },
{ "NiParticlesData", &construct<NiParticlesData, RC_NiParticlesData> },
{ "NiRotatingParticles", &construct<NiParticles, RC_NiParticles> },
{ "NiRotatingParticlesData", &construct<NiRotatingParticlesData, RC_NiParticlesData> },
{ "NiSkinData", &construct<NiSkinData, RC_NiSkinData> },
{ "NiSkinInstance", &construct<NiSkinInstance, RC_NiSkinInstance> },
{ "NiSkinPartition", &construct<NiSkinPartition, RC_NiSkinPartition> },
@ -265,16 +269,106 @@ namespace Nif
// PARTICLES
// Geometry, 4.0.0.2
{ "NiAutoNormalParticles", &construct<NiParticles, RC_NiParticles> },
{ "NiAutoNormalParticlesData", &construct<NiParticlesData, RC_NiParticlesData> },
{ "NiParticles", &construct<NiParticles, RC_NiParticles> },
{ "NiParticlesData", &construct<NiParticlesData, RC_NiParticlesData> },
{ "NiRotatingParticles", &construct<NiParticles, RC_NiParticles> },
{ "NiRotatingParticlesData", &construct<NiRotatingParticlesData, RC_NiParticlesData> },
// Geometry, Gamebryo
{ "NiParticleSystem", &construct<NiParticleSystem, RC_NiParticleSystem> },
{ "NiMeshParticleSystem", &construct<NiParticleSystem, RC_NiParticleSystem> },
{ "NiPSysData", &construct<NiPSysData, RC_NiPSysData> },
// Geometry, Bethesda
{ "BSStripParticleSystem", &construct<NiParticleSystem, RC_BSStripParticleSystem> },
{ "BSStripPSysData", &construct<BSStripPSysData, RC_BSStripPSysData> },
// Modifiers, 4.0.0.2
{ "NiGravity", &construct<NiGravity, RC_NiGravity> },
{ "NiParticleColorModifier", &construct<NiParticleColorModifier, RC_NiParticleColorModifier> },
{ "NiParticleGrowFade", &construct<NiParticleGrowFade, RC_NiParticleGrowFade> },
{ "NiParticleRotation", &construct<NiParticleRotation, RC_NiParticleRotation> },
// Modifiers, Gamebryo
{ "NiPSysAgeDeathModifier", &construct<NiPSysAgeDeathModifier, RC_NiPSysAgeDeathModifier> },
{ "NiPSysBombModifier", &construct<NiPSysBombModifier, RC_NiPSysBombModifier> },
{ "NiPSysBoundUpdateModifier", &construct<NiPSysBoundUpdateModifier, RC_NiPSysBoundUpdateModifier> },
{ "NiPSysColorModifier", &construct<NiPSysColorModifier, RC_NiPSysColorModifier> },
{ "NiPSysDragModifier", &construct<NiPSysDragModifier, RC_NiPSysDragModifier> },
{ "NiPSysGravityModifier", &construct<NiPSysGravityModifier, RC_NiPSysGravityModifier> },
{ "NiPSysGrowFadeModifier", &construct<NiPSysGrowFadeModifier, RC_NiPSysGrowFadeModifier> },
{ "NiPSysPositionModifier", &construct<NiPSysModifier, RC_NiPSysPositionModifier> },
{ "NiPSysRotationModifier", &construct<NiPSysRotationModifier, RC_NiPSysRotationModifier> },
{ "NiPSysSpawnModifier", &construct<NiPSysSpawnModifier, RC_NiPSysSpawnModifier> },
// Modifiers, Bethesda
{ "BSPSysInheritVelocityModifier",
&construct<BSPSysInheritVelocityModifier, RC_BSPSysInheritVelocityModifier> },
{ "BSPSysLODModifier", &construct<BSPSysLODModifier, RC_BSPSysLODModifier> },
{ "BSPSysRecycleBoundModifier", &construct<BSPSysRecycleBoundModifier, RC_BSPSysRecycleBoundModifier> },
{ "BSPSysScaleModifier", &construct<BSPSysScaleModifier, RC_BSPSysScaleModifier> },
{ "BSPSysSimpleColorModifier", &construct<BSPSysSimpleColorModifier, RC_BSPSysSimpleColorModifier> },
{ "BSPSysStripUpdateModifier", &construct<BSPSysStripUpdateModifier, RC_BSPSysStripUpdateModifier> },
{ "BSPSysSubTexModifier", &construct<BSPSysSubTexModifier, RC_BSPSysSubTexModifier> },
{ "BSWindModifier", &construct<BSWindModifier, RC_BSWindModifier> },
// Emitters, Gamebryo
{ "NiPSysBoxEmitter", &construct<NiPSysBoxEmitter, RC_NiPSysBoxEmitter> },
{ "NiPSysCylinderEmitter", &construct<NiPSysCylinderEmitter, RC_NiPSysCylinderEmitter> },
{ "NiPSysMeshEmitter", &construct<NiPSysMeshEmitter, RC_NiPSysMeshEmitter> },
{ "NiPSysSphereEmitter", &construct<NiPSysSphereEmitter, RC_NiPSysSphereEmitter> },
// Emitters, Bethesda
{ "BSPSysArrayEmitter", &construct<NiPSysVolumeEmitter, RC_BSPSysArrayEmitter> },
// Modifier controllers, Gamebryo
{ "NiPSysAirFieldAirFrictionCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysAirFieldAirFrictionCtlr> },
{ "NiPSysAirFieldInheritVelocityCtlr",
&construct<NiPSysModifierFloatCtlr, RC_NiPSysAirFieldInheritVelocityCtlr> },
{ "NiPSysAirFieldSpreadCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysAirFieldSpreadCtlr> },
{ "NiPSysEmitterCtlr", &construct<NiPSysEmitterCtlr, RC_NiPSysEmitterCtlr> },
{ "NiPSysEmitterDeclinationCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterDeclinationCtlr> },
{ "NiPSysEmitterDeclinationVarCtlr",
&construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterDeclinationVarCtlr> },
{ "NiPSysEmitterInitialRadiusCtlr",
&construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterInitialRadiusCtlr> },
{ "NiPSysEmitterLifeSpanCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterLifeSpanCtlr> },
{ "NiPSysEmitterPlanarAngleCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterPlanarAngleCtlr> },
{ "NiPSysEmitterPlanarAngleVarCtlr",
&construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterPlanarAngleVarCtlr> },
{ "NiPSysEmitterSpeedCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterSpeedCtlr> },
{ "NiPSysFieldAttenuationCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysFieldAttenuationCtlr> },
{ "NiPSysFieldMagnitudeCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysFieldMagnitudeCtlr> },
{ "NiPSysFieldMaxDistanceCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysFieldMaxDistanceCtlr> },
{ "NiPSysGravityStrengthCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysGravityStrengthCtlr> },
{ "NiPSysInitialRotSpeedCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotSpeedCtlr> },
{ "NiPSysInitialRotSpeedVarCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotSpeedVarCtlr> },
{ "NiPSysInitialRotAngleCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotAngleCtlr> },
{ "NiPSysInitialRotAngleVarCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotAngleVarCtlr> },
{ "NiPSysModifierActiveCtlr", &construct<NiPSysModifierBoolCtlr, RC_NiPSysModifierActiveCtlr> },
// Modifier controller data, Gamebryo
{ "NiPSysEmitterCtlrData", &construct<NiPSysEmitterCtlrData, RC_NiPSysEmitterCtlrData> },
// Colliders, 4.0.0.2
{ "NiPlanarCollider", &construct<NiPlanarCollider, RC_NiPlanarCollider> },
{ "NiSphericalCollider", &construct<NiSphericalCollider, RC_NiSphericalCollider> },
// Colliders, Gamebryo
{ "NiPSysColliderManager", &construct<NiPSysColliderManager, RC_NiPSysColliderManager> },
{ "NiPSysPlanarCollider", &construct<NiPSysPlanarCollider, RC_NiPSysPlanarCollider> },
{ "NiPSysSphericalCollider", &construct<NiPSysSphericalCollider, RC_NiPSysSphericalCollider> },
// Particle system controllers, 4.0.0.2
{ "NiParticleSystemController", &construct<NiParticleSystemController, RC_NiParticleSystemController> },
// Particle system controllers, Gamebryo
{ "NiPSysResetOnLoopCtlr", &construct<NiTimeController, RC_NiPSysResetOnLoopCtlr> },
{ "NiPSysUpdateCtlr", &construct<NiTimeController, RC_NiPSysUpdateCtlr> },
// PHYSICS
// Collision objects, Gamebryo
@ -288,9 +382,11 @@ namespace Nif
{ "bhkBlendCollisionObject", &construct<bhkBlendCollisionObject, RC_bhkBlendCollisionObject> },
// Constraint records, Bethesda
{ "bhkBallAndSocketConstraint", &construct<bhkBallAndSocketConstraint, RC_bhkBallAndSocketConstraint> },
{ "bhkHingeConstraint", &construct<bhkHingeConstraint, RC_bhkHingeConstraint> },
{ "bhkLimitedHingeConstraint", &construct<bhkLimitedHingeConstraint, RC_bhkLimitedHingeConstraint> },
{ "bhkRagdollConstraint", &construct<bhkRagdollConstraint, RC_bhkRagdollConstraint> },
{ "bhkStiffSpringConstraint", &construct<bhkStiffSpringConstraint, RC_bhkStiffSpringConstraint> },
// Physics body records, Bethesda
{ "bhkRigidBody", &construct<bhkRigidBody, RC_bhkRigidBody> },
@ -341,6 +437,8 @@ namespace Nif
{ "BSDistantTreeShaderProperty", &construct<BSShaderProperty, RC_BSDistantTreeShaderProperty> },
{ "BSLightingShaderProperty", &construct<BSLightingShaderProperty, RC_BSLightingShaderProperty> },
{ "BSEffectShaderProperty", &construct<BSEffectShaderProperty, RC_BSEffectShaderProperty> },
{ "BSSkyShaderProperty", &construct<BSSkyShaderProperty, RC_BSSkyShaderProperty> },
{ "BSWaterShaderProperty", &construct<BSWaterShaderProperty, RC_BSWaterShaderProperty> },
{ "DistantLODShaderProperty", &construct<BSShaderProperty, RC_DistantLODShaderProperty> },
{ "HairShaderProperty", &construct<BSShaderProperty, RC_HairShaderProperty> },
{ "Lighting30ShaderProperty", &construct<BSShaderPPLightingProperty, RC_BSShaderPPLightingProperty> },
@ -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<int32_t>())
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<int32_t>())
throw Nif::Exception("Non-zero separator precedes " + rec + ", index " + std::to_string(i), mFilename);
const auto entry = factories.find(rec);

@ -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<bool>() && !isBs202) ? mNumVertices : 0;
nif->readVector(mRadii, numRadii);
nif->read(mActiveCount);
if (nif->get<bool>() && !isBs202)
nif->readVector(mSizes, mNumVertices);
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
{
if (nif->get<bool>() && !isBs202)
nif->readVector(mRotations, mNumVertices);
if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 4))
{
if (nif->get<bool>() && !isBs202)
nif->readVector(mRotationAngles, mNumVertices);
if (nif->get<bool>() && !isBs202)
nif->readVector(mRotationAxes, mNumVertices);
if (isBs202)
{
nif->read(mHasTextureIndices);
uint32_t numSubtextureOffsets;
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
numSubtextureOffsets = nif->get<uint8_t>();
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<bool>())
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<bool>() && 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<NiPSysModifierOrder>(nif->get<uint32_t>());
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<ForceType>(nif->get<uint32_t>());
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<uint32_t>());
}
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<FloatKeyMap>();
mVisKeyList = std::make_shared<BoolKeyMap>();
uint32_t numVisKeys;
nif->read(numVisKeys);
for (size_t i = 0; i < numVisKeys; i++)
mVisKeyList->mKeys[nif->get<float>()].mValue = nif->get<uint8_t>() != 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);
}
}

@ -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<float> mRadii;
std::vector<float> mSizes;
std::vector<osg::Quat> mRotations;
std::vector<float> mRotationAngles;
std::vector<osg::Vec3f> mRotationAxes;
bool mHasTextureIndices{ false };
std::vector<osg::Vec4f> 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<float, 6> mBoundMinMax;
BSVertexDesc mVertDesc;
std::array<uint16_t, 4> mNearFar;
bool mWorldSpace{ true };
NiPSysModifierList mModifiers;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysData : NiParticlesData
{
std::vector<NiParticleInfo> mParticles;
std::vector<float> 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<float> mScales;
void read(NIFStream* nif) override;
};
struct BSPSysSimpleColorModifier : NiPSysModifier
{
float mFadeInPercent;
float mFadeOutPercent;
float mColor1EndPercent;
float mColor1StartPercent;
float mColor2EndPercent;
float mColor2StartPercent;
std::vector<osg::Vec4f> 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 <class DataPtr>
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<NiVisDataPtr>;
using NiPSysModifierFloatCtlr = TypedNiPSysModifierCtlr<NiFloatDataPtr>;
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

@ -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

@ -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

@ -232,7 +232,7 @@ namespace Nif
BSShaderLightingProperty::read(nif);
mFilename = nif->getSizedString();
mSkyObjectType = static_cast<ObjectType>(nif->get<uint32_t>());
mSkyObjectType = static_cast<SkyObjectType>(nif->get<uint32_t>());
}
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<SkyObjectType>(nif->get<uint32_t>());
}
void BSWaterShaderProperty::read(NIFStream* nif)
{
BSShaderProperty::read(nif);
nif->read(mFlags);
}
void NiAlphaProperty::read(NIFStream* nif)
{
NiProperty::read(nif);

@ -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

@ -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,

@ -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<NiSourceTexture>;
using NiPalettePtr = RecordPtrT<NiPalette>;
using NiParticleModifierPtr = RecordPtrT<NiParticleModifier>;
using NiParticleSystemPtr = RecordPtrT<NiParticleSystem>;
using NiPSysColliderPtr = RecordPtrT<NiPSysCollider>;
using NiPSysColliderManagerPtr = RecordPtrT<NiPSysColliderManager>;
using NiPSysEmitterCtlrDataPtr = RecordPtrT<NiPSysEmitterCtlrData>;
using NiPSysSpawnModifierPtr = RecordPtrT<NiPSysSpawnModifier>;
using NiBoolDataPtr = RecordPtrT<NiBoolData>;
using NiSkinPartitionPtr = RecordPtrT<NiSkinPartition>;
using BSShaderTextureSetPtr = RecordPtrT<BSShaderTextureSet>;
@ -202,6 +213,7 @@ namespace Nif
using bhkSerializableList = RecordListT<bhkSerializable>;
using bhkEntityList = RecordListT<bhkEntity>;
using NiControllerSequenceList = RecordListT<NiControllerSequence>;
using NiPSysModifierList = RecordListT<NiPSysModifier>;
} // Namespace
#endif

@ -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();

@ -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 };

@ -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);
}

Loading…
Cancel
Save