Merge branch 'loadSSEAlchemyTable' into 'master'

Load SSE alchemy table

See merge request OpenMW/openmw!3267
revert-6246b479
psi29a 1 year ago
commit 81deb3796b

@ -35,8 +35,8 @@ namespace Nif::Testing
inline void init(NiGeometry& value)
{
init(static_cast<Node&>(value));
value.data = NiGeometryDataPtr(nullptr);
value.skin = NiSkinInstancePtr(nullptr);
value.mData = NiGeometryDataPtr(nullptr);
value.mSkinInstance = NiSkinInstancePtr(nullptr);
}
inline void init(NiTriShape& value)

@ -326,20 +326,20 @@ namespace
mNiTriShapeData.vertices = { osg::Vec3f(0, 0, 0), osg::Vec3f(1, 0, 0), osg::Vec3f(1, 1, 0) };
mNiTriShapeData.mNumTriangles = 1;
mNiTriShapeData.triangles = { 0, 1, 2 };
mNiTriShape.data = Nif::NiGeometryDataPtr(&mNiTriShapeData);
mNiTriShape.mData = Nif::NiGeometryDataPtr(&mNiTriShapeData);
mNiTriShapeData2.recType = Nif::RC_NiTriShapeData;
mNiTriShapeData2.vertices = { osg::Vec3f(0, 0, 1), osg::Vec3f(1, 0, 1), osg::Vec3f(1, 1, 1) };
mNiTriShapeData2.mNumTriangles = 1;
mNiTriShapeData2.triangles = { 0, 1, 2 };
mNiTriShape2.data = Nif::NiGeometryDataPtr(&mNiTriShapeData2);
mNiTriShape2.mData = Nif::NiGeometryDataPtr(&mNiTriShapeData2);
mNiTriStripsData.recType = Nif::RC_NiTriStripsData;
mNiTriStripsData.vertices
= { osg::Vec3f(0, 0, 0), osg::Vec3f(1, 0, 0), osg::Vec3f(1, 1, 0), osg::Vec3f(0, 1, 0) };
mNiTriStripsData.mNumTriangles = 2;
mNiTriStripsData.strips = { { 0, 1, 2, 3 } };
mNiTriStrips.data = Nif::NiGeometryDataPtr(&mNiTriStripsData);
mNiTriStrips.mData = Nif::NiGeometryDataPtr(&mNiTriStripsData);
}
};
@ -716,7 +716,7 @@ namespace
TEST_F(TestBulletNifLoader,
for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_static_shape)
{
mNiTriShape.skin = Nif::NiSkinInstancePtr(&mNiSkinInstance);
mNiTriShape.mSkinInstance = Nif::NiSkinInstancePtr(&mNiSkinInstance);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
@ -959,7 +959,7 @@ namespace
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_should_return_shape_with_null_collision_shape)
{
mNiTriShape.data = Nif::NiGeometryDataPtr(nullptr);
mNiTriShape.mData = Nif::NiGeometryDataPtr(nullptr);
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
@ -977,7 +977,7 @@ namespace
TEST_F(TestBulletNifLoader,
for_tri_shape_child_node_with_empty_data_triangles_should_return_shape_with_null_collision_shape)
{
auto data = static_cast<Nif::NiTriShapeData*>(mNiTriShape.data.getPtr());
auto data = static_cast<Nif::NiTriShapeData*>(mNiTriShape.mData.getPtr());
data->triangles.clear();
mNiTriShape.parents.push_back(&mNiNode);
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
@ -1111,7 +1111,7 @@ namespace
init(niTriShape);
init(emptyCollisionNode);
niTriShape.data = Nif::NiGeometryDataPtr(&mNiTriShapeData);
niTriShape.mData = Nif::NiGeometryDataPtr(&mNiTriShapeData);
niTriShape.parents.push_back(&mNiNode);
emptyCollisionNode.recType = Nif::RC_RootCollisionNode;
@ -1210,7 +1210,7 @@ namespace
TEST_F(TestBulletNifLoader, should_ignore_tri_shape_data_with_mismatching_data_rec_type)
{
mNiTriShape.data = Nif::NiGeometryDataPtr(&mNiTriStripsData);
mNiTriShape.mData = Nif::NiGeometryDataPtr(&mNiTriStripsData);
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiTriShape);
@ -1245,7 +1245,7 @@ namespace
TEST_F(TestBulletNifLoader, should_ignore_tri_strips_data_with_mismatching_data_rec_type)
{
mNiTriStrips.data = Nif::NiGeometryDataPtr(&mNiTriShapeData);
mNiTriStrips.mData = Nif::NiGeometryDataPtr(&mNiTriShapeData);
Nif::NIFFile file("test.nif");
file.mRoots.push_back(&mNiTriStrips);

@ -103,7 +103,7 @@ add_component_dir (sceneutil
)
add_component_dir (nif
controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream physics
controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream physics particle
)
add_component_dir (nifosg

@ -3,6 +3,7 @@
#include "controlled.hpp"
#include "data.hpp"
#include "node.hpp"
#include "particle.hpp"
#include "recordptr.hpp"
namespace Nif

@ -46,29 +46,47 @@ namespace Nif
void NiGeometryData::read(NIFStream* nif)
{
bool isBS202 = nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > 0;
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 114))
nif->getInt(); // Group ID. (Almost?) always 0.
int verts = nif->getUShort();
unsigned short verts = 0;
if ((nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO3 && NiPSysDataFlag) || !NiPSysDataFlag)
{
nif->read(verts);
}
unsigned short BSMaxVertices = 0;
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && NiPSysDataFlag
&& nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_FO3)
{
nif->read(BSMaxVertices);
}
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
nif->skip(2); // Keep flags and compress flags
if (nif->getBoolean())
bool hasVertices = true;
hasVertices = nif->getBoolean();
if (hasVertices)
nif->getVector3s(vertices, verts);
unsigned int dataFlags = 0;
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
dataFlags = nif->getUShort();
unsigned short NiDataFlags = 0, BSDataFlags = 0;
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0) && !isBS202)
nif->read(NiDataFlags);
if (isBS202)
nif->read(BSDataFlags);
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS
&& nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
nif->getUInt(); // Material CRC
if (nif->getBoolean())
bool hasNormals;
hasNormals = nif->getBoolean();
if (hasNormals)
{
nif->getVector3s(normals, verts);
if (dataFlags & 0x1000)
if ((NiDataFlags | BSDataFlags) & 0x1000)
{
nif->getVector3s(tangents, verts);
nif->getVector3s(bitangents, verts);
@ -78,41 +96,36 @@ namespace Nif
center = nif->getVector3();
radius = nif->getFloat();
if (nif->getBoolean())
bool hasVertexColors;
hasVertexColors = nif->getBoolean();
if (hasVertexColors)
nif->getVector4s(colors, verts);
unsigned int numUVs = dataFlags;
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0))
numUVs = nif->getUShort();
nif->read(NiDataFlags);
unsigned short numUVs = (NiDataFlags & 0x3F) | (BSDataFlags & 0x1);
// In Morrowind this field only corresponds to the number of UV sets.
// In later games only the first 6 bits are used as a count and the rest are flags.
if (nif->getVersion() > NIFFile::NIFVersion::VER_MW)
{
numUVs &= 0x3f;
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > 0)
numUVs &= 0x1;
}
bool hasUVs = true;
if (nif->getVersion() <= NIFFile::NIFVersion::VER_MW)
hasUVs = nif->getBoolean();
if (hasUVs)
{
// nif->read(hasUVs);
nif->getBoolean(); // hasUVs
uvlist.resize(numUVs);
for (unsigned int i = 0; i < numUVs; i++)
{
nif->getVector2s(uvlist[i], verts);
// flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin
for (unsigned int uv = 0; uv < uvlist[i].size(); ++uv)
for (auto& uv : uvlist[i])
{
uvlist[i][uv] = osg::Vec2f(uvlist[i][uv].x(), 1.f - uvlist[i][uv].y());
}
// flip the texture coordinates to convert them to the OpenGL convention of bottom-left image origin
uv = osg::Vec2f(uv.x(), 1.f - uv.y());
}
}
unsigned short consistencyFlag;
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
nif->getUShort(); // Consistency flags
nif->read(consistencyFlag);
if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 4))
nif->skip(4); // Additional data
@ -197,43 +210,6 @@ namespace Nif
}
}
void NiParticlesData::read(NIFStream* nif)
{
NiGeometryData::read(nif);
// Should always match the number of vertices
if (nif->getVersion() <= NIFFile::NIFVersion::VER_MW)
numParticles = nif->getUShort();
if (nif->getVersion() <= NIFStream::generateVersion(10, 0, 1, 0))
std::fill(particleRadii.begin(), particleRadii.end(), nif->getFloat());
else if (nif->getBoolean())
nif->getFloats(particleRadii, vertices.size());
activeCount = nif->getUShort();
// Particle sizes
if (nif->getBoolean())
nif->getFloats(sizes, vertices.size());
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0) && nif->getBoolean())
nif->getQuaternions(rotations, vertices.size());
if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 4))
{
if (nif->getBoolean())
nif->getFloats(rotationAngles, vertices.size());
if (nif->getBoolean())
nif->getVector3s(rotationAxes, vertices.size());
}
}
void NiRotatingParticlesData::read(NIFStream* nif)
{
NiParticlesData::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0) && nif->getBoolean())
nif->getQuaternions(rotations, vertices.size());
}
void NiPosData::read(NIFStream* nif)
{
mKeyList = std::make_shared<Vector3KeyMap>();
@ -561,5 +537,4 @@ namespace Nif
mCenter = nif->getVector3();
mRadius = nif->getFloat();
}
} // Namespace

@ -27,6 +27,7 @@
#include "nifkey.hpp"
#include "niftypes.hpp" // Transformation
#include "recordptr.hpp"
#include <components/nif/controller.hpp>
#include <components/nif/node.hpp>
namespace Nif
@ -41,6 +42,8 @@ namespace Nif
osg::Vec3f center;
float radius;
bool NiPSysDataFlag = false;
void read(NIFStream* nif) override;
};
@ -76,24 +79,6 @@ namespace Nif
void read(NIFStream* nif) override;
};
struct NiParticlesData : public NiGeometryData
{
int numParticles{ 0 };
int activeCount{ 0 };
std::vector<float> particleRadii, sizes, rotationAngles;
std::vector<osg::Quat> rotations;
std::vector<osg::Vec3f> rotationAxes;
void read(NIFStream* nif) override;
};
struct NiRotatingParticlesData : public NiParticlesData
{
void read(NIFStream* nif) override;
};
struct NiPosData : public Record
{
Vector3KeyMapPtr mKeyList;
@ -329,6 +314,5 @@ namespace Nif
void read(NIFStream* nif) override;
};
} // Namespace
#endif

@ -17,6 +17,7 @@
#include "exception.hpp"
#include "extra.hpp"
#include "node.hpp"
#include "particle.hpp"
#include "physics.hpp"
#include "property.hpp"
@ -217,6 +218,26 @@ namespace Nif
{ "BSLightingShaderPropertyColorController",
&construct<BSEffectShaderPropertyColorController, RC_BSLightingShaderPropertyColorController> },
{ "BSBehaviorGraphExtraData", &construct<BSBehaviorGraphExtraData, RC_BSBehaviorGraphExtraData> },
{ "NiPSysData", &construct<NiPSysData, RC_NiPSysData> },
{ "NiParticleSystem", &construct<NiParticleSystem, RC_NiParticleSystem> },
{ "NiPSysEmitterCtlr", &construct<NiPSysEmitterCtlr, RC_NiPSysEmitterCtlr> },
{ "NiPSysUpdateCtlr", &construct<Controller, RC_Controller> },
{ "NiPSysAgeDeathModifier", &construct<NiPSysAgeDeathModifier, RC_NiPSysAgeDeathModifier> },
{ "BSPSysLODModifier", &construct<BSPSysLODModifier, RC_BSPSysLODModifier> },
{ "NiPSysCylinderEmitter", &construct<NiPSysCylinderEmitter, RC_NiPSysCylinderEmitter> },
{ "NiPSysSpawnModifier", &construct<NiPSysSpawnModifier, RC_NiPSysSpawnModifier> },
{ "BSPSysSimpleColorModifier", &construct<BSPSysSimpleColorModifier, RC_BSPSysSimpleColorModifier> },
{ "NiPSysRotationModifier", &construct<NiPSysRotationModifier, RC_NiPSysRotationModifier> },
{ "BSPSysScaleModifier", &construct<BSPSysScaleModifier, RC_BSPSysScaleModifier> },
{ "NiPSysGravityModifier", &construct<NiPSysGravityModifier, RC_NiPSysGravityModifier> },
{ "NiPSysPositionModifier", &construct<NiPSysModifier, RC_NiPSysModifier> },
{ "NiPSysBoundUpdateModifier", &construct<NiPSysBoundUpdateModifier, RC_NiPSysBoundUpdateModifier> },
{ "NiPSysModifierActiveCtlr", &construct<NiPSysModifierActiveCtlr, RC_NiPSysModifierActiveCtlr> },
{ "NiPSysMeshEmitter", &construct<NiPSysMeshEmitter, RC_NiPSysMeshEmitter> },
{ "BSPSysInheritVelocityModifier",
&construct<BSPSysInheritVelocityModifier, RC_BSPSysInheritVelocityModifier> },
{ "NiPSysBombModifier", &construct<NiPSysBombModifier, RC_NiPSysBombModifier> },
{ "NiPSysDragModifier", &construct<NiPSysDragModifier, RC_NiPSysDragModifier> },
};
}

@ -88,6 +88,7 @@ namespace Nif
data = readLittleEndianType<T>(inp);
}
void read(osg::Vec2f& data) { readLittleEndianBufferOfType<2, float>(inp, data._v); }
void read(osg::Vec3f& data) { readLittleEndianBufferOfType<3, float>(inp, data._v); }
void read(osg::Vec4f& data) { readLittleEndianBufferOfType<4, float>(inp, data._v); }

@ -171,25 +171,48 @@ namespace Nif
void NiGeometry::read(NIFStream* nif)
{
Node::read(nif);
data.read(nif);
skin.read(nif);
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && NiParticleSystemFlag)
{
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SSE)
mBoundingVolume.read(nif);
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_F76)
nif->read(mBoundMinMax);
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SSE)
mSkin.read(nif);
}
bool SSE_flag = (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SSE && !NiParticleSystemFlag
&& nif->getVersion() == NIFFile::NIFVersion::VER_BGS);
if (nif->getBethVersion() < NIFFile::BethVersion::BETHVER_SSE || SSE_flag)
mData.read(nif);
if ((nif->getBethVersion() < NIFFile::BethVersion::BETHVER_SSE
&& nif->getVersion() > NIFStream::generateVersion(3, 3, 0, 13))
|| SSE_flag)
mSkinInstance.read(nif);
if ((nif->getBethVersion() < NIFFile::BethVersion::BETHVER_SSE
&& nif->getVersion() > NIFStream::generateVersion(10, 0, 1, 0))
|| SSE_flag)
material.read(nif);
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS
&& nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
{
shaderprop.read(nif);
alphaprop.read(nif);
mShaderProperty.read(nif);
mAlphaProperty.read(nif);
}
}
void NiGeometry::post(Reader& nif)
{
Node::post(nif);
data.post(nif);
skin.post(nif);
shaderprop.post(nif);
alphaprop.post(nif);
if (recType != RC_NiParticles && !skin.empty())
mData.post(nif);
mSkin.post(nif);
mSkinInstance.post(nif);
mShaderProperty.post(nif);
mAlphaProperty.post(nif);
if (recType != RC_NiParticles && !mSkinInstance.empty())
nif.setUseSkinning(true);
}
@ -387,7 +410,9 @@ namespace Nif
nif->read(mParticleDataSize);
if (mParticleDataSize > 0)
{
throw Nif::Exception("Unhandled Particle Data in BSTriShape: ", nif->getFile().getFilename());
nif->getVector3s(mParticleVerts, vertNum);
// nif->readVector(mParticleNormals, vertNum); //Documentation seems to be wrong about this one
nif->readVector(mParticleTriangles, triNum * 3);
}
}
}

@ -2,6 +2,7 @@
#define OPENMW_COMPONENTS_NIF_NODE_HPP
#include <array>
#include <components/nif/recordptr.hpp>
#include <unordered_map>
#include <osg/Plane>
@ -151,11 +152,17 @@ namespace Nif
void read(NIFStream* nif);
};
NiGeometryDataPtr data;
NiSkinInstancePtr skin;
NiGeometryDataPtr mData;
NiSkinInstancePtr mSkinInstance;
RecordPtr mSkin;
MaterialData material;
BSShaderPropertyPtr shaderprop;
NiAlphaPropertyPtr alphaprop;
BSShaderPropertyPtr mShaderProperty;
NiAlphaPropertyPtr mAlphaProperty;
NiBoundingVolume::NiSphereBV mBoundingVolume;
float mBoundMinMax;
bool NiParticleSystemFlag = false;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
@ -175,9 +182,6 @@ namespace Nif
struct NiLines : NiGeometry
{
};
struct NiParticles : NiGeometry
{
};
struct NiCamera : Node
{

@ -0,0 +1,483 @@
#include "particle.hpp"
#include <components/nif/exception.hpp>
namespace Nif
{
void NiParticlesData::read(NIFStream* nif)
{
bool isBS202 = nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > 0;
// if (nif->getVersion() < NIFFile::NIFVersion::VER_BGS)
NiGeometryData::read(nif);
// Should always match the number of vertices
if (nif->getVersion() <= NIFFile::NIFVersion::VER_MW)
nif->read(numParticles);
float particleRadius;
if (nif->getVersion() <= NIFStream::generateVersion(10, 0, 1, 0))
{
nif->read(particleRadius);
particleRadii.resize(vertices.size());
std::fill(particleRadii.begin(), particleRadii.end(), particleRadius);
}
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
{
bool hasRadii = nif->getBoolean();
// nif->read(hasRadii);
if (hasRadii && !isBS202)
nif->readVector(particleRadii, vertices.size());
}
activeCount = nif->getUShort();
// Particle sizes
bool hasSizes;
hasSizes = nif->getBoolean();
if (hasSizes && !isBS202)
nif->readVector(sizes, vertices.size());
bool hasRotations = false;
if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0))
{
hasRotations = nif->getBoolean();
if (hasRotations && !isBS202)
{
nif->getQuaternions(mRotations, vertices.size());
}
}
if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 4))
{
bool hasRotationAngles, hasRotationAxes;
// nif->read(hasRotationAngles);
hasRotationAngles = nif->getBoolean();
if (hasRotationAngles && !isBS202)
nif->readVector(mRotationAngles, vertices.size());
// nif->read(hasRotationAxes);
hasRotationAxes = nif->getBoolean();
if (hasRotationAxes && !isBS202)
{
nif->getVector3s(mRotationAxes, vertices.size());
}
}
bool hasTexIndices = false;
if (isBS202)
nif->read(hasTexIndices);
unsigned int subtexOffsetNum = 0;
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS)
{
if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
nif->read(subtexOffsetNum);
else if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3 && isBS202)
subtexOffsetNum = nif->get<char>();
}
if (isBS202)
nif->getVector4s(mSubtexOffsets, subtexOffsetNum);
if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3
&& nif->getVersion() == NIFFile::NIFVersion::VER_BGS)
{
nif->read(mAspectRatio);
nif->read(mAspectFlags);
nif->read(mAspect2);
nif->read(mSpeed1);
nif->read(mSpeed2);
}
}
void NiRotatingParticlesData::read(NIFStream* nif)
{
NiParticlesData::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(4, 2, 2, 0) && nif->getBoolean())
nif->getQuaternions(mRotations, vertices.size());
}
void NiParticleInfo::read(NIFStream* nif)
{
nif->read(mVelocity);
if (nif->getVersion() <= NIFStream::generateVersion(10, 4, 0, 1))
nif->read(mRotation);
nif->read(mAge);
nif->read(mLifeSpan);
nif->read(mLastUpdate);
nif->read(mSpawnGen);
nif->read(mCode);
}
void NiPSysData::read(NIFStream* nif)
{
bool isBS202 = nif->getVersion() == NIFStream::generateVersion(20, 2, 0, 7) && nif->getBethVersion() > 0;
NiPSysDataFlag = true;
NiParticlesData::read(nif);
if (nif->getVersion() != NIFStream::generateVersion(20, 2, 0, 7))
{
mParticleInfo.resize(vertices.size());
for (unsigned long i = 0; i < vertices.size(); i++)
{
NiParticleInfo temp;
temp.read(nif);
mParticleInfo[i] = temp;
}
}
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_F76)
nif->skip(sizeof(float) * 3);
if (nif->getVersion() == NIFStream::generateVersion(20, 2, 4, 7))
nif->skip(1);
if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 2))
{
bool hasRotationSpeed;
nif->read(hasRotationSpeed);
if (hasRotationSpeed && !isBS202)
{
mRotationSpeeds.resize(vertices.size());
nif->readVector(mRotationSpeeds, vertices.size());
}
}
if (!isBS202)
{
nif->read(mParticlesAddedNum);
nif->read(mParticlesBase);
}
if (nif->getVersion() == NIFStream::generateVersion(20, 2, 4, 7))
nif->skip(1);
}
void NiParticleSystem::read(NIFStream* nif)
{
NiParticleSystemFlag = true;
NiParticles::read(nif);
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SSE)
mVertexDesc.read(nif);
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SKY)
{
nif->read(mFarBegin);
nif->read(mFarEnd);
nif->read(mNearBegin);
nif->read(mNearEnd);
}
if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_SSE)
mNiPSysData.read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
{
nif->read(mWorldSpace);
unsigned int modifierNum;
nif->read(modifierNum);
mModifiers.resize(modifierNum);
for (auto& modifier : mModifiers)
{
modifier.read(nif);
}
}
}
void NiParticleSystem::post(Reader& nif)
{
NiParticles::post(nif);
mNiPSysData.post(nif);
for (auto ptr : mModifiers)
{
ptr.post(nif);
}
}
void NiPSysModifier::read(NIFStream* nif)
{
mName = nif->getString();
nif->read(mOrder);
mTarget.read(nif);
nif->read(mActive);
}
void NiPSysModifier::post(Reader& nif)
{
mTarget.post(nif);
}
void NiPSysModifierCtlr::read(NIFStream* nif)
{
NiSingleInterpController::read(nif);
mModifierName = nif->getString();
}
void NiPSysEmitterCtlr::read(NIFStream* nif)
{
NiPSysModifierCtlr::read(nif);
if (nif->getVersion() > NIFStream::generateVersion(10, 1, 0, 103))
mVisibilityInterpolator.read(nif);
// TODO: Handle pre 10.1.0.103
}
void NiPSysEmitterCtlr::post(Reader& nif)
{
NiPSysModifierCtlr::post(nif);
if (nif.getVersion() > NIFStream::generateVersion(10, 1, 0, 103))
mVisibilityInterpolator.post(nif);
}
void NiPSysAgeDeathModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
nif->read(mSpawnOnDeath);
mSpawnModifier.read(nif);
}
void NiPSysAgeDeathModifier::post(Reader& nif)
{
mSpawnModifier.post(nif);
}
void NiPSysSpawnModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
nif->read(mNumSpawnGens);
nif->read(mPercentSpawned);
nif->read(mMinSpawnNum);
nif->read(mMaxSpawnNum);
nif->read(mSpawnSpeedVariation);
nif->read(mSpawnDirVariation);
nif->read(mLifeSpan);
nif->read(mLifeSpanVariation);
}
void BSPSysLODModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
nif->read(mBeginDist);
nif->read(mEndDist);
nif->read(mEndEmitScale);
nif->read(mEndSize);
}
void NiPSysCylinderEmitter::read(NIFStream* nif)
{
NiPSysVolumeEmitter::read(nif);
nif->read(mRadius);
nif->read(mHeight);
}
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);
if (nif.getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
mEmitterObject.post(nif);
}
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);
// nif->skip(sizeof(float) * 2);
}
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->getVector4s(mColors, 3);
if (nif->getBethVersion() == NIFFile::BethVersion::BETHVER_F76)
nif->skip(sizeof(unsigned short) * 26);
}
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)
throw Nif::Exception("Fallout76 is unsupported: ", nif->getFile().getFilename());
if (nif->getVersion() >= NIFStream::generateVersion(20, 0, 0, 2))
{
nif->read(mRotationAngle);
nif->read(mRotationAngleVariation);
mRandRotSpeedSign = nif->getBoolean();
}
mRandAxis = nif->getBoolean();
nif->read(mAxis);
}
void BSPSysScaleModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
unsigned int numScales;
nif->read(numScales);
nif->readVector(mScales, numScales);
}
void NiPSysGravityModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
mGravityObject.read(nif);
nif->read(mGravityAxis);
nif->read(mDecay);
nif->read(mStrength);
nif->read(mForceType);
nif->read(mTurbulence);
nif->read(mTurbulenceScale);
if (nif->getBethVersion() > 16)
mWorldAligned = nif->getBoolean();
}
void NiPSysGravityModifier::post(Reader& nif)
{
NiPSysModifier::post(nif);
mGravityObject.post(nif);
}
void NiPSysBoundUpdateModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
nif->read(mUpdateSkip);
}
void NiPSysModifierActiveCtlr::read(NIFStream* nif)
{
NiPSysModifierCtlr::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mNiVisData.read(nif);
}
void NiPSysModifierActiveCtlr::post(Reader& nif)
{
NiPSysModifierCtlr::post(nif);
if (nif.getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mNiVisData.post(nif);
}
void NiPSysMeshEmitter::read(NIFStream* nif)
{
NiPSysEmitter::read(nif);
unsigned int meshNum;
nif->read(meshNum);
mEmitterMeshes.resize(meshNum);
for (auto& mesh : mEmitterMeshes)
mesh.read(nif);
nif->read(mInitialVelocityType);
nif->read(mEmissionType);
nif->read(mEmissionAxis);
}
void NiPSysMeshEmitter::post(Reader& nif)
{
NiPSysEmitter::post(nif);
for (auto& mesh : mEmitterMeshes)
mesh.post(nif);
}
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 NiPSysBombModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
mBombObj.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);
mBombObj.post(nif);
}
void NiPSysDragModifier::read(NIFStream* nif)
{
NiPSysModifier::read(nif);
mDragObj.read(nif);
nif->read(mDragAxis);
nif->read(mPercentage);
nif->read(mRange);
nif->read(mRangeFalloff);
}
void NiPSysDragModifier::post(Reader& nif)
{
NiPSysModifier::post(nif);
mDragObj.post(nif);
}
}

@ -0,0 +1,289 @@
#ifndef OPENMW_COMPONENTS_NIF_PARTICLE_HPP
#define OPENMW_COMPONENTS_NIF_PARTICLE_HPP
#include "nifkey.hpp"
#include "niftypes.hpp" // Transformation
#include "recordptr.hpp"
#include <components/nif/controller.hpp>
#include <components/nif/data.hpp>
#include <components/nif/node.hpp>
#include <components/settings/values.hpp>
namespace Nif
{
struct NiParticles : NiGeometry
{
};
struct NiParticlesData : public NiGeometryData
{
unsigned short numParticles{ 0 };
int activeCount{ 0 };
std::vector<float> particleRadii, sizes, mRotationAngles;
std::vector<osg::Quat> mRotations;
std::vector<osg::Vec3f> mRotationAxes;
std::vector<osg::Vec4f> mSubtexOffsets;
float mAspectRatio;
unsigned short mAspectFlags;
float mAspect2, mSpeed1, mSpeed2;
void read(NIFStream* nif) override;
};
struct NiRotatingParticlesData : public NiParticlesData
{
void read(NIFStream* nif) override;
};
struct NiParticleInfo
{
osg::Vec3f mVelocity;
osg::Vec3f mRotation;
float mAge;
float mLifeSpan;
float mLastUpdate;
unsigned short mSpawnGen;
unsigned short mCode;
void read(NIFStream* nif);
};
struct NiPSysData : public NiParticlesData
{
std::vector<NiParticleInfo> mParticleInfo;
std::vector<float> mRotationSpeeds;
unsigned short mParticlesAddedNum;
unsigned short mParticlesBase;
void read(NIFStream* nif) override;
};
struct NiParticleSystem : public NiParticles
{
BSVertexDesc mVertexDesc;
unsigned short mFarBegin;
unsigned short mFarEnd;
unsigned short mNearBegin;
unsigned short mNearEnd;
NiPSysDataPtr mNiPSysData;
bool mWorldSpace;
std::vector<NiPSysModifierPtr> mModifiers;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysModifier : public Record
{
std::string mName;
unsigned int mOrder;
NiParticleSystemPtr mTarget;
bool mActive;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysModifierCtlr : public NiSingleInterpController
{
std::string mModifierName;
void read(NIFStream* nif) override;
};
struct NiPSysEmitterCtlr : public NiPSysModifierCtlr
{
NiInterpolatorPtr mVisibilityInterpolator;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysAgeDeathModifier : public NiPSysModifier
{
bool mSpawnOnDeath;
NiPSysSpawnModifierPtr mSpawnModifier;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysSpawnModifier : public NiPSysModifier
{
unsigned short mNumSpawnGens;
float mPercentSpawned;
unsigned short mMinSpawnNum, mMaxSpawnNum;
float mSpawnSpeedVariation;
float mSpawnDirVariation;
float mLifeSpan;
float mLifeSpanVariation;
void read(NIFStream* nif) override;
};
struct BSPSysLODModifier : public NiPSysModifier
{
float mBeginDist;
float mEndDist;
float mEndEmitScale;
float mEndSize;
void read(NIFStream* nif) override;
};
struct NiPSysEmitter : public NiPSysModifier
{
float mSpeed;
float mSpeedVariation;
float mDeclination;
float mDeclinationVariation;
float mPlanarAngle;
float mPlanarAngleVariation;
osg::Vec4f mInitialColor;
float mInitialRadius;
float mRadiusVariation;
float mLifespan;
float mLifespanVariation;
void read(NIFStream* nif) override;
};
struct NiPSysVolumeEmitter : public NiPSysEmitter
{
NiNodePtr mEmitterObject;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysCylinderEmitter : public NiPSysVolumeEmitter
{
float mRadius;
float mHeight;
void read(NIFStream* nif) override;
};
struct BSPSysSimpleColorModifier : public NiPSysModifier
{
float mFadeInPercent;
float mFadeOutPercent;
float mColor1EndPercent;
float mColor1StartPercent;
float mColor2EndPercent;
float mColor2StartPercent;
std::vector<osg::Vec4f> mColors;
void read(NIFStream* nif) override;
};
struct NiPSysRotationModifier : public NiPSysModifier
{
float mRotationSpeed;
float mRotationSpeedVariation;
float mRotationAngle;
float mRotationAngleVariation;
bool mRandRotSpeedSign;
bool mRandAxis;
osg::Vec3f mAxis;
void read(NIFStream* nif) override;
};
struct BSPSysScaleModifier : public NiPSysModifier
{
std::vector<float> mScales;
void read(NIFStream* nif) override;
};
struct NiPSysGravityModifier : public NiPSysModifier
{
NamedPtr mGravityObject;
osg::Vec3f mGravityAxis;
float mDecay;
float mStrength;
unsigned int mForceType;
float mTurbulence;
float mTurbulenceScale;
bool mWorldAligned;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysBoundUpdateModifier : public NiPSysModifier
{
unsigned short mUpdateSkip;
void read(NIFStream* nif) override;
};
struct NiPSysModifierActiveCtlr : public NiPSysModifierCtlr
{
NiVisDataPtr mNiVisData;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysMeshEmitter : public NiPSysEmitter
{
std::vector<NamedPtr> mEmitterMeshes;
unsigned int mInitialVelocityType;
unsigned int mEmissionType;
osg::Vec3f mEmissionAxis;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct BSPSysInheritVelocityModifier : public NiPSysModifier
{
NamedPtr mInheritObject;
float mInheritChance;
float mVelocityMult;
float mVelcoityVariation;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysBombModifier : public NiPSysModifier
{
NiNodePtr mBombObj;
osg::Vec3f mBombAxis;
float mDecay;
float mDeltaV;
unsigned int mDecayType;
unsigned int mSymmetryType;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPSysDragModifier : public NiPSysModifier
{
NamedPtr mDragObj;
osg::Vec3f mDragAxis;
float mPercentage;
float mRange;
float mRangeFalloff;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
}
#endif

@ -170,11 +170,30 @@ namespace Nif
RC_BSMultiBoundSphere,
RC_BSInvMarker,
RC_BSTriShape,
RC_NiPSysData,
RC_BSEffectShaderPropertyFloatController,
RC_BSEffectShaderPropertyColorController,
RC_BSLightingShaderPropertyFloatController,
RC_BSLightingShaderPropertyColorController,
RC_BSBehaviorGraphExtraData,
RC_NiParticleSystem,
RC_NiPSysEmitterCtlr,
RC_Controller,
RC_NiPSysAgeDeathModifier,
RC_BSPSysLODModifier,
RC_NiPSysCylinderEmitter,
RC_NiPSysSpawnModifier,
RC_BSPSysSimpleColorModifier,
RC_NiPSysRotationModifier,
RC_BSPSysScaleModifier,
RC_NiPSysGravityModifier,
RC_NiPSysBoundUpdateModifier,
RC_NiPSysModifier,
RC_NiPSysModifierActiveCtlr,
RC_NiPSysMeshEmitter,
RC_BSPSysInheritVelocityModifier,
RC_NiPSysBombModifier,
RC_NiPSysDragModifier,
};
/// Base class for all records

@ -149,7 +149,13 @@ namespace Nif
struct bhkCompressedMeshShapeData;
struct BSMultiBound;
struct BSMultiBoundData;
struct NiPSysData;
struct NiParticleSystem;
struct NiPSysModifier;
struct NiPSysSpawnModifier;
struct NiNode;
using RecordPtr = RecordPtrT<Record>;
using NodePtr = RecordPtrT<Node>;
using ExtraPtr = RecordPtrT<Extra>;
using NiUVDataPtr = RecordPtrT<NiUVData>;
@ -187,6 +193,11 @@ namespace Nif
using bhkCompressedMeshShapeDataPtr = RecordPtrT<bhkCompressedMeshShapeData>;
using BSMultiBoundPtr = RecordPtrT<BSMultiBound>;
using BSMultiBoundDataPtr = RecordPtrT<BSMultiBoundData>;
using NiPSysDataPtr = RecordPtrT<NiPSysData>;
using NiParticleSystemPtr = RecordPtrT<NiParticleSystem>;
using NiPSysModifierPtr = RecordPtrT<NiPSysModifier>;
using NiPSysSpawnModifierPtr = RecordPtrT<NiPSysSpawnModifier>;
using NiNodePtr = RecordPtrT<NiNode>;
using NodeList = RecordListT<Node>;
using PropertyList = RecordListT<Property>;

@ -79,14 +79,14 @@ namespace
template <class Function>
auto handleNiGeometry(const Nif::NiGeometry& geometry, Function&& function)
-> decltype(function(static_cast<const Nif::NiTriShapeData&>(geometry.data.get())))
-> decltype(function(static_cast<const Nif::NiTriShapeData&>(geometry.mData.get())))
{
if (geometry.recType == Nif::RC_NiTriShape || geometry.recType == Nif::RC_BSLODTriShape)
{
if (geometry.data->recType != Nif::RC_NiTriShapeData)
if (geometry.mData->recType != Nif::RC_NiTriShapeData)
return {};
auto data = static_cast<const Nif::NiTriShapeData*>(geometry.data.getPtr());
auto data = static_cast<const Nif::NiTriShapeData*>(geometry.mData.getPtr());
if (data->triangles.empty())
return {};
@ -95,10 +95,10 @@ namespace
if (geometry.recType == Nif::RC_NiTriStrips)
{
if (geometry.data->recType != Nif::RC_NiTriStripsData)
if (geometry.mData->recType != Nif::RC_NiTriStripsData)
return {};
auto data = static_cast<const Nif::NiTriStripsData*>(geometry.data.getPtr());
auto data = static_cast<const Nif::NiTriStripsData*>(geometry.mData.getPtr());
if (data->strips.empty())
return {};
@ -380,10 +380,10 @@ namespace NifBullet
if (args.mHasMarkers && Misc::StringUtils::ciStartsWith(niGeometry.name, "EditorMarker"))
return;
if (niGeometry.data.empty() || niGeometry.data->vertices.empty())
if (niGeometry.mData.empty() || niGeometry.mData->vertices.empty())
return;
if (!niGeometry.skin.empty())
if (!niGeometry.mSkinInstance.empty())
args.mAnimated = false;
// TODO: handle NiSkinPartition

@ -1,6 +1,9 @@
#include "nifloader.hpp"
#include <algorithm>
#include <components/nif/record.hpp>
#include <mutex>
#include <osg/Vec3>
#include <string_view>
#include <osg/Array>
@ -48,6 +51,7 @@
#include <components/nif/extra.hpp>
#include <components/nif/niffile.hpp>
#include <components/nif/node.hpp>
#include <components/nif/particle.hpp>
#include <components/nif/property.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/morphgeometry.hpp>
@ -127,10 +131,10 @@ namespace
auto geometry = dynamic_cast<const Nif::NiGeometry*>(nifNode);
if (geometry)
{
if (!geometry->shaderprop.empty())
out.emplace_back(geometry->shaderprop.getPtr());
if (!geometry->alphaprop.empty())
out.emplace_back(geometry->alphaprop.getPtr());
if (!geometry->mShaderProperty.empty())
out.emplace_back(geometry->mShaderProperty.getPtr());
if (!geometry->mAlphaProperty.empty())
out.emplace_back(geometry->mAlphaProperty.getPtr());
}
}
@ -436,8 +440,8 @@ namespace NifOsg
auto geometry = dynamic_cast<const Nif::NiGeometry*>(nifNode);
// NiGeometry's NiAlphaProperty doesn't get handled here because it's a drawable property
if (geometry && !geometry->shaderprop.empty())
handleProperty(geometry->shaderprop.getPtr(), applyTo, composite, imageManager, boundTextures,
if (geometry && !geometry->mShaderProperty.empty())
handleProperty(geometry->mShaderProperty.getPtr(), applyTo, composite, imageManager, boundTextures,
animflags, hasStencilProperty);
}
@ -759,7 +763,7 @@ namespace NifOsg
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "EditorMarker");
if (!skip)
{
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->mSkinInstance;
if (skin.empty())
handleGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
@ -1120,13 +1124,13 @@ namespace NifOsg
const Nif::Node* nifNode, ParticleSystem* partsys, const Nif::NiParticleSystemController* partctrl)
{
auto particleNode = static_cast<const Nif::NiParticles*>(nifNode);
if (particleNode->data.empty() || particleNode->data->recType != Nif::RC_NiParticlesData)
if (particleNode->mData.empty() || particleNode->mData->recType != Nif::RC_NiParticlesData)
{
partsys->setQuota(partctrl->numParticles);
return;
}
auto particledata = static_cast<const Nif::NiParticlesData*>(particleNode->data.getPtr());
auto particledata = static_cast<const Nif::NiParticlesData*>(particleNode->mData.getPtr());
partsys->setQuota(particledata->numParticles);
osg::BoundingBox box;
@ -1376,13 +1380,13 @@ namespace NifOsg
const std::vector<unsigned int>& boundTextures, int animflags)
{
const Nif::NiGeometry* niGeometry = static_cast<const Nif::NiGeometry*>(nifNode);
if (niGeometry->data.empty())
if (niGeometry->mData.empty())
return;
bool hasPartitions = false;
if (!niGeometry->skin.empty())
if (!niGeometry->mSkinInstance.empty())
{
const Nif::NiSkinInstance* skin = niGeometry->skin.getPtr();
const Nif::NiSkinInstance* skin = niGeometry->mSkinInstance.getPtr();
const Nif::NiSkinData* data = nullptr;
const Nif::NiSkinPartition* partitions = nullptr;
if (!skin->data.empty())
@ -1416,7 +1420,7 @@ namespace NifOsg
}
}
const Nif::NiGeometryData* niGeometryData = niGeometry->data.getPtr();
const Nif::NiGeometryData* niGeometryData = niGeometry->mData.getPtr();
if (!hasPartitions)
{
if (niGeometry->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_BSLODTriShape)
@ -1542,7 +1546,7 @@ namespace NifOsg
// Assign bone weights
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map(new SceneUtil::RigGeometry::InfluenceMap);
const Nif::NiSkinInstance* skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin.getPtr();
const Nif::NiSkinInstance* skin = static_cast<const Nif::NiGeometry*>(nifNode)->mSkinInstance.getPtr();
const Nif::NiSkinData* data = skin->data.getPtr();
const Nif::NodeList& bones = skin->bones;
for (std::size_t i = 0, n = bones.size(); i < n; ++i)
@ -2676,5 +2680,4 @@ namespace NifOsg
LoaderImpl impl(kf.getFilename(), kf.getVersion(), kf.getUserVersion(), kf.getBethVersion());
impl.loadKf(kf, target);
}
}

Loading…
Cancel
Save