Merge branch 'nif' into 'master'

Modernize NIF loader, part 4

See merge request OpenMW/openmw!3427
macos_ci_fix
psi29a 1 year ago
commit 64e4a33400

@ -20,7 +20,7 @@ namespace Nif::Testing
{
value.mExtra = ExtraPtr(nullptr);
value.mExtraList = ExtraList();
value.mController = ControllerPtr(nullptr);
value.mController = NiTimeControllerPtr(nullptr);
}
inline void init(NiAVObject& value)
@ -55,15 +55,15 @@ namespace Nif::Testing
value.mRoot = NiAVObjectPtr(nullptr);
}
inline void init(Controller& value)
inline void init(NiTimeController& value)
{
value.next = ControllerPtr(nullptr);
value.flags = 0;
value.frequency = 0;
value.phase = 0;
value.timeStart = 0;
value.timeStop = 0;
value.target = NiObjectNETPtr(nullptr);
value.mNext = NiTimeControllerPtr(nullptr);
value.mFlags = 0;
value.mFrequency = 0;
value.mPhase = 0;
value.mTimeStart = 0;
value.mTimeStop = 0;
value.mTarget = NiObjectNETPtr(nullptr);
}
}

@ -300,7 +300,7 @@ namespace
Nif::NiStringExtraData mNiStringExtraData;
Nif::NiStringExtraData mNiStringExtraData2;
Nif::NiIntegerExtraData mNiIntegerExtraData;
Nif::Controller mController;
Nif::NiTimeController mController;
btTransform mTransform{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(1, 2, 3) };
btTransform mTransformScale2{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(2, 4, 6) };
btTransform mTransformScale3{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(3, 6, 9) };
@ -817,11 +817,11 @@ namespace
TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_controller_should_return_animated_shape)
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::Controller::Flag_Active;
mController.mFlags |= Nif::NiTimeController::Flag_Active;
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 3;
mNiTriShape.mParents.push_back(&mNiNode);
mNiTriShape.mController = Nif::ControllerPtr(&mController);
mNiTriShape.mController = Nif::NiTimeControllerPtr(&mController);
mNiNode.mChildren = Nif::NiAVObjectList{ Nif::NiAVObjectPtr(&mNiTriShape) };
mNiNode.mTransform.mScale = 4;
@ -847,14 +847,14 @@ namespace
TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_where_one_with_controller_should_return_animated_shape)
{
mController.recType = Nif::RC_NiKeyframeController;
mController.flags |= Nif::Controller::Flag_Active;
mController.mFlags |= Nif::NiTimeController::Flag_Active;
copy(mTransform, mNiTriShape.mTransform);
mNiTriShape.mTransform.mScale = 3;
mNiTriShape.mParents.push_back(&mNiNode);
copy(mTransform, mNiTriShape2.mTransform);
mNiTriShape2.mTransform.mScale = 3;
mNiTriShape2.mParents.push_back(&mNiNode);
mNiTriShape2.mController = Nif::ControllerPtr(&mController);
mNiTriShape2.mController = Nif::NiTimeControllerPtr(&mController);
mNiNode.mChildren = Nif::NiAVObjectList{
Nif::NiAVObjectPtr(&mNiTriShape),
Nif::NiAVObjectPtr(&mNiTriShape2),

@ -21,7 +21,7 @@ namespace Nif
void post(Reader& nif) override { mNext.post(nif); }
};
struct Controller : public Record
struct NiTimeController : public Record
{
enum Flags
{
@ -36,17 +36,17 @@ namespace Nif
Mask = 6
};
ControllerPtr next;
int flags;
float frequency, phase;
float timeStart, timeStop;
NiObjectNETPtr target;
NiTimeControllerPtr mNext;
uint16_t mFlags;
float mFrequency, mPhase;
float mTimeStart, mTimeStop;
NiObjectNETPtr mTarget;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
bool isActive() const { return flags & Flag_Active; }
ExtrapolationMode extrapolationMode() const { return static_cast<ExtrapolationMode>(flags & Mask); }
bool isActive() const { return mFlags & Flag_Active; }
ExtrapolationMode extrapolationMode() const { return static_cast<ExtrapolationMode>(mFlags & Mask); }
};
/// Abstract object that has a name, extra data and controllers
@ -55,7 +55,7 @@ namespace Nif
std::string mName;
ExtraPtr mExtra;
ExtraList mExtraList;
ControllerPtr mController;
NiTimeControllerPtr mController;
void read(NIFStream* nif) override;
void post(Reader& nif) override;

@ -1,6 +1,7 @@
#include "controller.hpp"
#include "data.hpp"
#include "exception.hpp"
#include "node.hpp"
#include "particle.hpp"
#include "texture.hpp"
@ -8,25 +9,22 @@
namespace Nif
{
void Controller::read(NIFStream* nif)
void NiTimeController::read(NIFStream* nif)
{
next.read(nif);
flags = nif->getUShort();
frequency = nif->getFloat();
phase = nif->getFloat();
timeStart = nif->getFloat();
timeStop = nif->getFloat();
target.read(nif);
mNext.read(nif);
nif->read(mFlags);
nif->read(mFrequency);
nif->read(mPhase);
nif->read(mTimeStart);
nif->read(mTimeStop);
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
mTarget.read(nif);
}
void Controller::post(Reader& nif)
void NiTimeController::post(Reader& nif)
{
Record::post(nif);
next.post(nif);
target.post(nif);
mNext.post(nif);
mTarget.post(nif);
}
void ControlledBlock::read(NIFStream* nif)
@ -44,28 +42,28 @@ namespace Nif
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 110))
{
mBlendInterpolator.read(nif);
mBlendIndex = nif->getUShort();
nif->read(mBlendIndex);
}
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106) && nif->getBethVersion() > 0)
mPriority = nif->getChar();
nif->read(mPriority);
if (nif->getVersion() >= NIFStream::generateVersion(10, 2, 0, 0)
&& nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 0))
{
mStringPalette.read(nif);
mNodeNameOffset = nif->getUInt();
mPropertyTypeOffset = nif->getUInt();
mControllerTypeOffset = nif->getUInt();
mControllerIdOffset = nif->getUInt();
mInterpolatorIdOffset = nif->getUInt();
nif->read(mNodeNameOffset);
nif->read(mPropertyTypeOffset);
nif->read(mControllerTypeOffset);
nif->read(mControllerIdOffset);
nif->read(mInterpolatorIdOffset);
}
else
{
mNodeName = nif->getString();
mPropertyType = nif->getString();
mControllerType = nif->getString();
mControllerId = nif->getString();
mInterpolatorId = nif->getString();
nif->read(mNodeName);
nif->read(mPropertyType);
nif->read(mControllerType);
nif->read(mControllerId);
nif->read(mInterpolatorId);
}
}
@ -80,16 +78,15 @@ namespace Nif
void NiSequence::read(NIFStream* nif)
{
mName = nif->getString();
nif->read(mName);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
{
mAccumRootName = nif->getString();
nif->read(mAccumRootName);
mTextKeys.read(nif);
}
size_t numControlledBlocks = nif->getUInt();
mControlledBlocks.resize(nif->get<uint32_t>());
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106))
mArrayGrowBy = nif->getUInt();
mControlledBlocks.resize(numControlledBlocks);
nif->read(mArrayGrowBy);
for (ControlledBlock& block : mControlledBlocks)
block.read(nif);
}
@ -104,28 +101,30 @@ namespace Nif
void NiControllerSequence::read(NIFStream* nif)
{
NiSequence::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
return;
mWeight = nif->getFloat();
nif->read(mWeight);
mTextKeys.read(nif);
mExtrapolationMode = static_cast<Controller::ExtrapolationMode>(nif->getUInt());
mFrequency = nif->getFloat();
mExtrapolationMode = static_cast<NiTimeController::ExtrapolationMode>(nif->get<uint32_t>());
nif->read(mFrequency);
if (nif->getVersion() <= NIFStream::generateVersion(10, 4, 0, 1))
mPhase = nif->getFloat();
mStartTime = nif->getFloat();
mStopTime = nif->getFloat();
mPlayBackwards = nif->getVersion() == NIFStream::generateVersion(10, 1, 0, 106) && nif->getBoolean();
nif->read(mPhase);
nif->read(mStartTime);
nif->read(mStopTime);
if (nif->getVersion() == NIFStream::generateVersion(10, 1, 0, 106))
nif->read(mPlayBackwards);
mManager.read(nif);
mAccumRootName = nif->getString();
nif->read(mAccumRootName);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 113)
&& nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 0))
mStringPalette.read(nif);
else if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() >= 24)
{
size_t numAnimNotes = 1;
uint16_t numAnimNotes = 1;
if (nif->getBethVersion() >= 29)
numAnimNotes = nif->getUShort();
nif->read(numAnimNotes);
nif->skip(4 * numAnimNotes); // BSAnimNotes links
}
@ -134,21 +133,24 @@ namespace Nif
void NiControllerSequence::post(Reader& nif)
{
NiSequence::post(nif);
mManager.post(nif);
mStringPalette.post(nif);
}
void NiInterpController::read(NIFStream* nif)
{
Controller::read(nif);
NiTimeController::read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 104)
&& nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 108))
mManagerControlled = nif->getBoolean();
nif->read(mManagerControlled);
}
void NiSingleInterpController::read(NIFStream* nif)
{
NiInterpController::read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 104))
mInterpolator.read(nif);
}
@ -156,83 +158,86 @@ namespace Nif
void NiSingleInterpController::post(Reader& nif)
{
NiInterpController::post(nif);
mInterpolator.post(nif);
}
void NiParticleInfo::read(NIFStream* nif)
{
nif->read(mVelocity);
if (nif->getVersion() <= NIFStream::generateVersion(10, 4, 0, 1))
nif->read(mRotationAxis);
nif->read(mAge);
nif->read(mLifespan);
nif->read(mLastUpdate);
nif->read(mSpawnGeneration);
nif->read(mCode);
}
void NiParticleSystemController::read(NIFStream* nif)
{
Controller::read(nif);
velocity = nif->getFloat();
velocityRandom = nif->getFloat();
verticalDir = nif->getFloat();
verticalAngle = nif->getFloat();
horizontalDir = nif->getFloat();
horizontalAngle = nif->getFloat();
/*normal?*/ nif->getVector3();
color = nif->getVector4();
size = nif->getFloat();
startTime = nif->getFloat();
stopTime = nif->getFloat();
nif->getChar();
emitRate = nif->getFloat();
lifetime = nif->getFloat();
lifetimeRandom = nif->getFloat();
emitFlags = nif->getUShort();
offsetRandom = nif->getVector3();
emitter.read(nif);
/* Unknown Short, 0?
* Unknown Float, 1.0?
* Unknown Int, 1?
* Unknown Int, 0?
* Unknown Short, 0?
*/
nif->skip(16);
numParticles = nif->getUShort();
activeCount = nif->getUShort();
particles.resize(numParticles);
for (size_t i = 0; i < particles.size(); i++)
NiTimeController::read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
nif->read(mSpeed);
nif->read(mSpeedVariation);
nif->read(mDeclination);
nif->read(mDeclinationVariation);
nif->read(mPlanarAngle);
nif->read(mPlanarAngleVariation);
nif->read(mInitialNormal);
nif->read(mInitialColor);
nif->read(mInitialSize);
nif->read(mEmitStartTime);
nif->read(mEmitStopTime);
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
{
particles[i].velocity = nif->getVector3();
nif->getVector3(); /* unknown */
particles[i].lifetime = nif->getFloat();
particles[i].lifespan = nif->getFloat();
particles[i].timestamp = nif->getFloat();
nif->getUShort(); /* unknown */
particles[i].vertex = nif->getUShort();
mResetParticleSystem = nif->get<uint8_t>() != 0;
nif->read(mBirthRate);
}
nif->getUInt(); /* -1? */
affectors.read(nif);
colliders.read(nif);
nif->getChar();
nif->read(mLifetime);
nif->read(mLifetimeVariation);
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
nif->read(mEmitFlags);
nif->read(mEmitterDimensions);
mEmitter.read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 13))
{
nif->read(mNumSpawnGenerations);
nif->read(mPercentageSpawned);
nif->read(mSpawnMultiplier);
nif->read(mSpawnSpeedChaos);
nif->read(mSpawnDirChaos);
mParticles.resize(nif->get<uint16_t>());
nif->read(mNumValid);
for (NiParticleInfo& particle : mParticles)
particle.read(nif);
nif->skip(4); // NiEmitterModifier link
}
mModifier.read(nif);
mCollider.read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(3, 3, 0, 15))
nif->read(mStaticTargetBound);
}
void NiParticleSystemController::post(Reader& nif)
{
Controller::post(nif);
emitter.post(nif);
affectors.post(nif);
colliders.post(nif);
NiTimeController::post(nif);
mEmitter.post(nif);
mModifier.post(nif);
mCollider.post(nif);
}
void NiMaterialColorController::read(NIFStream* nif)
{
NiPoint3InterpController::read(nif);
// Two bits that correspond to the controlled material color.
// 00: Ambient
// 01: Diffuse
// 10: Specular
// 11: Emissive
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
mTargetColor = nif->getUShort() & 3;
mTargetColor = static_cast<TargetColor>(nif->get<uint16_t>() & 3);
else
mTargetColor = (flags >> 4) & 3;
mTargetColor = static_cast<TargetColor>((mFlags >> 4) & 3);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mData.read(nif);
}
@ -240,60 +245,70 @@ namespace Nif
void NiMaterialColorController::post(Reader& nif)
{
NiPoint3InterpController::post(nif);
mData.post(nif);
}
void NiLookAtController::read(NIFStream* nif)
{
Controller::read(nif);
NiTimeController::read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
lookAtFlags = nif->getUShort();
target.read(nif);
nif->read(mLookAtFlags);
mLookAt.read(nif);
}
void NiLookAtController::post(Reader& nif)
{
Controller::post(nif);
target.post(nif);
NiTimeController::post(nif);
mLookAt.post(nif);
}
void NiPathController::read(NIFStream* nif)
{
Controller::read(nif);
NiTimeController::read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
nif->read(mPathFlags);
else
mPathFlags = (mFlags >> 4);
bankDir = nif->getInt();
maxBankAngle = nif->getFloat();
smoothing = nif->getFloat();
followAxis = nif->getShort();
posData.read(nif);
floatData.read(nif);
nif->read(mBankDirection);
nif->read(mMaxBankAngle);
nif->read(mSmoothing);
nif->read(mFollowAxis);
mPathData.read(nif);
mPercentData.read(nif);
}
void NiPathController::post(Reader& nif)
{
Controller::post(nif);
NiTimeController::post(nif);
posData.post(nif);
floatData.post(nif);
mPathData.post(nif);
mPercentData.post(nif);
}
void NiUVController::read(NIFStream* nif)
{
Controller::read(nif);
NiTimeController::read(nif);
uvSet = nif->getUShort();
data.read(nif);
nif->read(mUvSet);
mData.read(nif);
}
void NiUVController::post(Reader& nif)
{
Controller::post(nif);
data.post(nif);
NiTimeController::post(nif);
mData.post(nif);
}
void NiKeyframeController::read(NIFStream* nif)
{
NiSingleInterpController::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mData.read(nif);
}
@ -301,29 +316,30 @@ namespace Nif
void NiKeyframeController::post(Reader& nif)
{
NiSingleInterpController::post(nif);
mData.post(nif);
}
void NiMultiTargetTransformController::read(NIFStream* nif)
{
NiInterpController::read(nif);
size_t numTargets = nif->getUShort();
std::vector<NiAVObjectPtr> targets;
targets.resize(numTargets);
for (size_t i = 0; i < targets.size(); i++)
targets[i].read(nif);
mExtraTargets = targets;
mExtraTargets.resize(nif->get<uint16_t>());
for (NiAVObjectPtr& extraTarget : mExtraTargets)
extraTarget.read(nif);
}
void NiMultiTargetTransformController::post(Reader& nif)
{
NiInterpController::post(nif);
postRecordList(nif, mExtraTargets);
}
void NiAlphaController::read(NIFStream* nif)
{
NiFloatInterpController::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mData.read(nif);
}
@ -331,12 +347,14 @@ namespace Nif
void NiAlphaController::post(Reader& nif)
{
NiFloatInterpController::post(nif);
mData.post(nif);
}
void NiRollController::read(NIFStream* nif)
{
NiSingleInterpController::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mData.read(nif);
}
@ -344,49 +362,47 @@ namespace Nif
void NiRollController::post(Reader& nif)
{
NiSingleInterpController::post(nif);
mData.post(nif);
}
void NiGeomMorpherController::read(NIFStream* nif)
{
NiInterpController::read(nif);
if (nif->getVersion() >= NIFFile::NIFVersion::VER_OB_OLD)
mUpdateNormals = nif->getUShort() & 1;
mUpdateNormals = nif->get<uint16_t>() & 1;
mData.read(nif);
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW)
if (nif->getVersion() < NIFFile::NIFVersion::VER_MW)
return;
mAlwaysActive = nif->get<uint8_t>() != 0;
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 105))
return;
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
{
mAlwaysActive = nif->getChar();
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106))
{
if (nif->getVersion() <= NIFFile::NIFVersion::VER_OB)
{
readRecordList(nif, mInterpolators);
if (nif->getVersion() >= NIFStream::generateVersion(10, 2, 0, 0) && nif->getBethVersion() > 9)
{
unsigned int numUnknown = nif->getUInt();
nif->skip(4 * numUnknown);
}
}
else
{
std::vector<NiInterpolatorPtr> interpolators;
size_t numInterps = nif->getUInt();
interpolators.resize(numInterps);
mWeights.resize(numInterps);
for (size_t i = 0; i < numInterps; i++)
{
interpolators[i].read(nif);
mWeights[i] = nif->getFloat();
}
mInterpolators = interpolators;
}
}
readRecordList(nif, mInterpolators);
if (nif->getVersion() >= NIFStream::generateVersion(10, 2, 0, 0) && nif->getBethVersion() >= 10)
nif->skip(4 * nif->get<uint32_t>()); // Unknown
return;
}
mInterpolators.resize(nif->get<uint32_t>());
mWeights.resize(mInterpolators.size());
for (size_t i = 0; i < mInterpolators.size(); i++)
{
mInterpolators[i].read(nif);
nif->read(mWeights[i]);
}
}
void NiGeomMorpherController::post(Reader& nif)
{
NiInterpController::post(nif);
mData.post(nif);
postRecordList(nif, mInterpolators);
}
@ -394,6 +410,7 @@ namespace Nif
void NiVisController::read(NIFStream* nif)
{
NiBoolInterpController::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mData.read(nif);
}
@ -401,17 +418,19 @@ namespace Nif
void NiVisController::post(Reader& nif)
{
NiBoolInterpController::post(nif);
mData.post(nif);
}
void NiFlipController::read(NIFStream* nif)
{
NiFloatInterpController::read(nif);
mTexSlot = nif->getUInt();
mTexSlot = static_cast<NiTexturingProperty::TextureType>(nif->get<uint32_t>());
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
{
timeStart = nif->getFloat();
mDelta = nif->getFloat();
nif->read(mTimeStart);
nif->read(mDelta);
}
readRecordList(nif, mSources);
}
@ -419,14 +438,16 @@ namespace Nif
void NiFlipController::post(Reader& nif)
{
NiFloatInterpController::post(nif);
postRecordList(nif, mSources);
}
void NiTextureTransformController::read(NIFStream* nif)
{
NiFloatInterpController::read(nif);
mShaderMap = nif->getBoolean();
nif->read(mTexSlot);
nif->read(mShaderMap);
mTexSlot = static_cast<NiTexturingProperty::TextureType>(nif->get<uint32_t>());
nif->read(mTransformMember);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 103))
mData.read(nif);
@ -435,176 +456,113 @@ namespace Nif
void NiTextureTransformController::post(Reader& nif)
{
NiFloatInterpController::post(nif);
mData.post(nif);
}
void bhkBlendController::read(NIFStream* nif)
{
Controller::read(nif);
nif->getUInt(); // Zero
NiTimeController::read(nif);
uint32_t numKeys;
nif->read(numKeys);
// Is this possible?
if (numKeys != 0)
throw Nif::Exception(
"Unsupported keys in bhkBlendController " + std::to_string(recIndex), nif->getFile().getFilename());
}
void BSEffectShaderPropertyFloatController::read(NIFStream* nif)
{
NiFloatInterpController::read(nif);
nif->read(mControlledVariable);
}
void BSEffectShaderPropertyColorController::read(NIFStream* nif)
{
NiPoint3InterpController::read(nif);
nif->read(mControlledColor);
}
void NiControllerManager::read(NIFStream* nif)
{
Controller::read(nif);
mCumulative = nif->getBoolean();
NiTimeController::read(nif);
nif->read(mCumulative);
readRecordList(nif, mSequences);
mObjectPalette.read(nif);
}
void NiControllerManager::post(Reader& nif)
{
Controller::post(nif);
NiTimeController::post(nif);
postRecordList(nif, mSequences);
mObjectPalette.post(nif);
}
void NiPoint3Interpolator::read(NIFStream* nif)
{
defaultVal = nif->getVector3();
data.read(nif);
}
void NiPoint3Interpolator::post(Reader& nif)
{
data.post(nif);
}
void NiBoolInterpolator::read(NIFStream* nif)
{
defaultVal = nif->getBoolean();
data.read(nif);
}
void NiBoolInterpolator::post(Reader& nif)
{
data.post(nif);
}
void NiFloatInterpolator::read(NIFStream* nif)
{
defaultVal = nif->getFloat();
data.read(nif);
}
void NiFloatInterpolator::post(Reader& nif)
{
data.post(nif);
}
void NiTransformInterpolator::read(NIFStream* nif)
{
defaultPos = nif->getVector3();
defaultRot = nif->getQuaternion();
defaultScale = nif->getFloat();
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109))
{
if (!nif->getBoolean())
defaultPos = osg::Vec3f();
if (!nif->getBoolean())
defaultRot = osg::Quat();
if (!nif->getBoolean())
defaultScale = 1.f;
}
data.read(nif);
}
void NiTransformInterpolator::post(Reader& nif)
{
data.post(nif);
}
void NiColorInterpolator::read(NIFStream* nif)
{
defaultVal = nif->getVector4();
data.read(nif);
}
void NiColorInterpolator::post(Reader& nif)
{
data.post(nif);
}
void NiBlendInterpolator::read(NIFStream* nif)
{
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 112))
mManagerControlled = nif->getChar() & 1;
size_t numInterps = 0;
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109))
{
numInterps = nif->getUShort();
mArrayGrowBy = nif->getUShort();
}
else
{
numInterps = nif->getChar();
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 112))
nif->read(mFlags);
mItems.resize(nif->get<uint8_t>());
nif->read(mWeightThreshold);
if (!(mFlags & Flag_ManagerControlled))
{
mWeightThreshold = nif->getFloat();
if (!mManagerControlled)
{
mInterpCount = nif->getChar();
mSingleIndex = nif->getChar();
mHighPriority = nif->getChar();
mNextHighPriority = nif->getChar();
mSingleTime = nif->getFloat();
mHighWeightsSum = nif->getFloat();
mNextHighWeightsSum = nif->getFloat();
mHighEaseSpinner = nif->getFloat();
}
mInterpCount = nif->get<uint8_t>();
mSingleIndex = nif->get<uint8_t>();
mHighPriority = nif->get<int8_t>();
mNextHighPriority = nif->get<int8_t>();
nif->read(mSingleTime);
nif->read(mHighWeightsSum);
nif->read(mNextHighWeightsSum);
nif->read(mHighEaseSpinner);
for (Item& item : mItems)
item.read(nif);
}
return;
}
if (!mManagerControlled)
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 110))
{
mItems.resize(numInterps);
mItems.resize(nif->get<uint8_t>());
for (Item& item : mItems)
item.read(nif);
if (nif->get<bool>())
mFlags |= Flag_ManagerControlled;
nif->read(mWeightThreshold);
if (nif->get<bool>())
mFlags |= Flag_OnlyUseHighestWeight;
mInterpCount = nif->get<uint8_t>();
mSingleIndex = nif->get<uint8_t>();
mSingleInterpolator.read(nif);
nif->read(mSingleTime);
mHighPriority = nif->get<int8_t>();
mNextHighPriority = nif->get<int8_t>();
return;
}
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 111))
mItems.resize(nif->get<uint16_t>());
nif->read(mArrayGrowBy);
for (Item& item : mItems)
item.read(nif);
if (nif->get<bool>())
mFlags |= Flag_ManagerControlled;
nif->read(mWeightThreshold);
if (nif->get<bool>())
mFlags |= Flag_OnlyUseHighestWeight;
nif->read(mInterpCount);
nif->read(mSingleIndex);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 108))
{
mManagerControlled = nif->getBoolean();
mWeightThreshold = nif->getFloat();
mOnlyUseHighestWeight = nif->getBoolean();
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109))
{
mInterpCount = nif->getUShort();
mSingleIndex = nif->getUShort();
}
else
{
mInterpCount = nif->getChar();
mSingleIndex = nif->getChar();
}
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 108))
{
mSingleInterpolator.read(nif);
mSingleTime = nif->getFloat();
}
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109))
{
mHighPriority = nif->getInt();
mNextHighPriority = nif->getInt();
}
else
{
mHighPriority = nif->getChar();
mNextHighPriority = nif->getChar();
}
mSingleInterpolator.read(nif);
nif->read(mSingleTime);
}
nif->read(mHighPriority);
nif->read(mNextHighPriority);
}
void NiBlendInterpolator::post(Reader& nif)
@ -617,13 +575,13 @@ namespace Nif
void NiBlendInterpolator::Item::read(NIFStream* nif)
{
mInterpolator.read(nif);
mWeight = nif->getFloat();
mNormalizedWeight = nif->getFloat();
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109))
mPriority = nif->getInt();
nif->read(mWeight);
nif->read(mNormalizedWeight);
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 110))
mPriority = nif->get<int8_t>();
else
mPriority = nif->getChar();
mEaseSpinner = nif->getFloat();
nif->read(mPriority);
nif->read(mEaseSpinner);
}
void NiBlendInterpolator::Item::post(Reader& nif)
@ -631,38 +589,4 @@ namespace Nif
mInterpolator.post(nif);
}
void NiBlendBoolInterpolator::read(NIFStream* nif)
{
NiBlendInterpolator::read(nif);
mValue = nif->getChar() != 0;
}
void NiBlendFloatInterpolator::read(NIFStream* nif)
{
NiBlendInterpolator::read(nif);
mValue = nif->getFloat();
}
void NiBlendPoint3Interpolator::read(NIFStream* nif)
{
NiBlendInterpolator::read(nif);
mValue = nif->getVector3();
}
void NiBlendTransformInterpolator::read(NIFStream* nif)
{
NiBlendInterpolator::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109))
{
mPosValue = nif->getVector3();
mRotValue = nif->getQuaternion();
mScaleValue = nif->getFloat();
if (!nif->getBoolean())
mPosValue = osg::Vec3f();
if (!nif->getBoolean())
mRotValue = osg::Quat();
if (!nif->getBoolean())
mScaleValue = 1.f;
}
}
}

@ -1,30 +1,8 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008-2010 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: https://openmw.org/
This file (controller.h) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
version 3 along with this program. If not, see
https://www.gnu.org/licenses/ .
*/
#ifndef OPENMW_COMPONENTS_NIF_CONTROLLER_HPP
#define OPENMW_COMPONENTS_NIF_CONTROLLER_HPP
#include "base.hpp"
#include "niftypes.hpp"
#include "property.hpp"
namespace Nif
@ -34,16 +12,16 @@ namespace Nif
{
std::string mTargetName;
NiInterpolatorPtr mInterpolator;
ControllerPtr mController;
NiTimeControllerPtr mController;
NiBlendInterpolatorPtr mBlendInterpolator;
unsigned short mBlendIndex;
unsigned char mPriority;
uint16_t mBlendIndex;
uint8_t mPriority;
NiStringPalettePtr mStringPalette;
size_t mNodeNameOffset;
size_t mPropertyTypeOffset;
size_t mControllerTypeOffset;
size_t mControllerIdOffset;
size_t mInterpolatorIdOffset;
uint32_t mNodeNameOffset;
uint32_t mPropertyTypeOffset;
uint32_t mControllerTypeOffset;
uint32_t mControllerIdOffset;
uint32_t mInterpolatorIdOffset;
std::string mNodeName;
std::string mPropertyType;
std::string mControllerType;
@ -60,7 +38,7 @@ namespace Nif
std::string mName;
std::string mAccumRootName;
ExtraPtr mTextKeys;
unsigned int mArrayGrowBy;
uint32_t mArrayGrowBy;
std::vector<ControlledBlock> mControlledBlocks;
void read(NIFStream* nif) override;
@ -71,7 +49,7 @@ namespace Nif
struct NiControllerSequence : public NiSequence
{
float mWeight{ 1.f };
Controller::ExtrapolationMode mExtrapolationMode{ Controller::ExtrapolationMode::Constant };
NiTimeController::ExtrapolationMode mExtrapolationMode{ NiTimeController::ExtrapolationMode::Constant };
float mFrequency{ 1.f };
float mPhase{ 1.f };
float mStartTime, mStopTime;
@ -84,7 +62,7 @@ namespace Nif
};
// Base class for controllers that use NiInterpolators to animate objects.
struct NiInterpController : public Controller
struct NiInterpController : public NiTimeController
{
// Usually one of the flags.
bool mManagerControlled{ false };
@ -116,7 +94,20 @@ namespace Nif
{
};
struct NiParticleSystemController : public Controller
struct NiParticleInfo
{
osg::Vec3f mVelocity;
osg::Vec3f mRotationAxis;
float mAge;
float mLifespan;
float mLastUpdate;
uint16_t mSpawnGeneration;
uint16_t mCode;
void read(NIFStream* nif);
};
struct NiParticleSystemController : public NiTimeController
{
enum BSPArrayController
{
@ -124,104 +115,113 @@ namespace Nif
BSPArrayController_AtVertex = 0x10
};
struct Particle
{
osg::Vec3f velocity;
float lifetime;
float lifespan;
float timestamp;
unsigned short vertex;
};
float velocity;
float velocityRandom;
float verticalDir; // 0=up, pi/2=horizontal, pi=down
float verticalAngle;
float horizontalDir;
float horizontalAngle;
osg::Vec4f color;
float size;
float startTime;
float stopTime;
float emitRate;
float lifetime;
float lifetimeRandom;
enum EmitFlags
{
EmitFlag_NoAutoAdjust = 0x1 // If this flag is set, we use the emitRate value. Otherwise,
// we calculate an emit rate so that the maximum number of particles
// in the system (numParticles) is never exceeded.
};
int emitFlags;
osg::Vec3f offsetRandom;
NiAVObjectPtr emitter;
int numParticles;
int activeCount;
std::vector<Particle> particles;
NiParticleModifierPtr affectors;
NiParticleModifierPtr colliders;
float mSpeed;
float mSpeedVariation;
float mDeclination;
float mDeclinationVariation;
float mPlanarAngle;
float mPlanarAngleVariation;
osg::Vec3f mInitialNormal;
osg::Vec4f mInitialColor;
float mInitialSize;
float mEmitStartTime;
float mEmitStopTime;
bool mResetParticleSystem{ false };
float mBirthRate;
float mLifetime;
float mLifetimeVariation;
uint16_t mEmitFlags{ 0 };
osg::Vec3f mEmitterDimensions;
NiAVObjectPtr mEmitter;
uint16_t mNumSpawnGenerations;
float mPercentageSpawned;
uint16_t mSpawnMultiplier;
float mSpawnSpeedChaos;
float mSpawnDirChaos;
uint16_t mNumParticles;
uint16_t mNumValid;
std::vector<NiParticleInfo> mParticles;
NiParticleModifierPtr mModifier;
NiParticleModifierPtr mCollider;
uint8_t mStaticTargetBound;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
bool noAutoAdjust() const { return emitFlags & EmitFlag_NoAutoAdjust; }
bool emitAtVertex() const { return flags & BSPArrayController_AtVertex; }
bool noAutoAdjust() const { return mEmitFlags & EmitFlag_NoAutoAdjust; }
bool emitAtVertex() const { return mFlags & BSPArrayController_AtVertex; }
};
using NiBSPArrayController = NiParticleSystemController;
struct NiMaterialColorController : public NiPoint3InterpController
{
enum class TargetColor
{
Ambient = 0,
Diffuse = 1,
Specular = 2,
Emissive = 3,
};
NiPosDataPtr mData;
unsigned int mTargetColor;
TargetColor mTargetColor;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiPathController : public Controller
struct NiPathController : public NiTimeController
{
NiPosDataPtr posData;
NiFloatDataPtr floatData;
enum Flags
{
Flag_OpenCurve = 0x020,
Flag_AllowFlip = 0x040,
Flag_Bank = 0x080,
Flag_ConstVelocity = 0x100,
Flag_Follow = 0x200,
Flag_FlipFollowAxis = 0x400
Flag_CVDataNeedsUpdate = 0x01,
Flag_OpenCurve = 0x02,
Flag_AllowFlip = 0x04,
Flag_Bank = 0x08,
Flag_ConstVelocity = 0x10,
Flag_Follow = 0x20,
Flag_FlipFollowAxis = 0x40,
};
int bankDir;
float maxBankAngle, smoothing;
short followAxis;
uint16_t mPathFlags;
int32_t mBankDirection;
float mMaxBankAngle;
float mSmoothing;
uint16_t mFollowAxis;
NiPosDataPtr mPathData;
NiFloatDataPtr mPercentData;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiLookAtController : public Controller
struct NiLookAtController : public NiTimeController
{
NiAVObjectPtr target;
unsigned short lookAtFlags{ 0 };
enum Flags
{
Flag_Flip = 0x1,
Flag_LookYAxis = 0x2,
Flag_LookZAxis = 0x4,
};
uint16_t mLookAtFlags{ 0 };
NiAVObjectPtr mLookAt;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiUVController : public Controller
struct NiUVController : public NiTimeController
{
NiUVDataPtr data;
unsigned int uvSet;
NiUVDataPtr mData;
uint16_t mUvSet;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
@ -281,7 +281,7 @@ namespace Nif
struct NiFlipController : public NiFloatInterpController
{
int mTexSlot; // NiTexturingProperty::TextureType
NiTexturingProperty::TextureType mTexSlot;
float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources
NiSourceTextureList mSources;
@ -292,110 +292,95 @@ namespace Nif
struct NiTextureTransformController : public NiFloatInterpController
{
bool mShaderMap;
int mTexSlot; // NiTexturingProperty::TextureType
unsigned int mTransformMember;
NiTexturingProperty::TextureType mTexSlot;
uint32_t mTransformMember;
NiFloatDataPtr mData;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct bhkBlendController : public Controller
struct bhkBlendController : public NiTimeController
{
void read(NIFStream* nif) override;
};
struct BSEffectShaderPropertyFloatController : public NiFloatInterpController
{
unsigned int mControlledVariable;
uint32_t mControlledVariable;
void read(NIFStream* nif) override;
};
struct BSEffectShaderPropertyColorController : public NiPoint3InterpController
{
unsigned int mControlledColor;
uint32_t mControlledColor;
void read(NIFStream* nif) override;
};
struct NiControllerManager : public Controller
struct NiControllerManager : public NiTimeController
{
bool mCumulative;
NiControllerSequenceList mSequences;
NiDefaultAVObjectPalettePtr mObjectPalette;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiInterpolator : public Record
{
};
struct NiPoint3Interpolator : public NiInterpolator
{
osg::Vec3f defaultVal;
NiPosDataPtr data;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiBoolInterpolator : public NiInterpolator
// Abstract
struct NiInterpolator : public Record
{
char defaultVal;
NiBoolDataPtr data;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
struct NiFloatInterpolator : public NiInterpolator
template <class T, class DataPtr>
struct TypedNiInterpolator : public NiInterpolator
{
float defaultVal;
NiFloatDataPtr data;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
T mDefaultValue;
DataPtr mData;
struct NiTransformInterpolator : public NiInterpolator
{
osg::Vec3f defaultPos;
osg::Quat defaultRot;
float defaultScale;
NiKeyframeDataPtr data;
void read(NIFStream* nif) override
{
nif->read(mDefaultValue);
mData.read(nif);
}
void read(NIFStream* nif) override;
void post(Reader& nif) override;
void post(Reader& nif) override { mData.post(nif); }
};
struct NiColorInterpolator : public NiInterpolator
{
osg::Vec4f defaultVal;
NiColorDataPtr data;
void read(NIFStream* nif) override;
void post(Reader& nif) override;
};
using NiPoint3Interpolator = TypedNiInterpolator<osg::Vec3f, NiPosDataPtr>;
using NiBoolInterpolator = TypedNiInterpolator<bool, NiBoolDataPtr>;
using NiFloatInterpolator = TypedNiInterpolator<float, NiFloatDataPtr>;
using NiTransformInterpolator = TypedNiInterpolator<NiQuatTransform, NiKeyframeDataPtr>;
using NiColorInterpolator = TypedNiInterpolator<osg::Vec4f, NiColorDataPtr>;
// Abstract
struct NiBlendInterpolator : public NiInterpolator
{
enum Flags
{
Flag_ManagerControlled = 0x1,
Flag_OnlyUseHighestWeight = 0x2,
};
struct Item
{
NiInterpolatorPtr mInterpolator;
float mWeight, mNormalizedWeight;
int mPriority;
int32_t mPriority;
float mEaseSpinner;
void read(NIFStream* nif);
void post(Reader& nif);
};
bool mManagerControlled{ false };
bool mOnlyUseHighestWeight{ false };
unsigned short mArrayGrowBy{ 0 };
uint8_t mFlags{ 0 };
uint16_t mArrayGrowBy{ 0 };
float mWeightThreshold;
unsigned short mInterpCount;
unsigned short mSingleIndex;
int mHighPriority, mNextHighPriority;
uint16_t mInterpCount;
uint16_t mSingleIndex;
int32_t mHighPriority, mNextHighPriority;
float mSingleTime;
float mHighWeightsSum, mNextHighWeightsSum;
float mHighEaseSpinner;
@ -406,31 +391,37 @@ namespace Nif
void post(Reader& nif) override;
};
struct NiBlendBoolInterpolator : public NiBlendInterpolator
template <typename T>
struct TypedNiBlendInterpolator : public NiBlendInterpolator
{
char mValue;
void read(NIFStream* nif) override;
};
T mValue;
struct NiBlendFloatInterpolator : public NiBlendInterpolator
{
float mValue;
void read(NIFStream* nif) override;
};
void read(NIFStream* nif) override
{
NiBlendInterpolator::read(nif);
struct NiBlendPoint3Interpolator : public NiBlendInterpolator
{
osg::Vec3f mValue;
void read(NIFStream* nif) override;
nif->read(mValue);
}
};
struct NiBlendTransformInterpolator : public NiBlendInterpolator
template <>
struct TypedNiBlendInterpolator<NiQuatTransform> : public NiBlendInterpolator
{
osg::Vec3f mPosValue;
osg::Quat mRotValue;
float mScaleValue;
void read(NIFStream* nif) override;
NiQuatTransform mValue;
void read(NIFStream* nif) override
{
NiBlendInterpolator::read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(10, 1, 0, 109))
nif->read(mValue);
}
};
} // Namespace
using NiBlendBoolInterpolator = TypedNiBlendInterpolator<uint8_t>;
using NiBlendFloatInterpolator = TypedNiBlendInterpolator<float>;
using NiBlendPoint3Interpolator = TypedNiBlendInterpolator<osg::Vec3f>;
using NiBlendTransformInterpolator = TypedNiBlendInterpolator<NiQuatTransform>;
}
#endif

@ -528,7 +528,7 @@ namespace Nif
void NiBoolData::read(NIFStream* nif)
{
mKeyList = std::make_shared<ByteKeyMap>();
mKeyList = std::make_shared<BoolKeyMap>();
mKeyList->read(nif);
}

@ -219,7 +219,7 @@ namespace Nif
struct NiVisData : public Record
{
// TODO: investigate possible use of ByteKeyMap
// TODO: investigate possible use of BoolKeyMap
std::shared_ptr<std::map<float, bool>> mKeys;
void read(NIFStream* nif) override;
@ -357,7 +357,8 @@ namespace Nif
struct NiBoolData : public Record
{
ByteKeyMapPtr mKeyList;
BoolKeyMapPtr mKeyList;
void read(NIFStream* nif) override;
};

@ -152,13 +152,13 @@ namespace Nif
using Vector3KeyMap = KeyMapT<osg::Vec3f, &NIFStream::get<osg::Vec3f>>;
using Vector4KeyMap = KeyMapT<osg::Vec4f, &NIFStream::get<osg::Vec4f>>;
using QuaternionKeyMap = KeyMapT<osg::Quat, &NIFStream::get<osg::Quat>>;
using ByteKeyMap = KeyMapT<char, &NIFStream::get<char>>;
using BoolKeyMap = KeyMapT<bool, &NIFStream::get<bool>>;
using FloatKeyMapPtr = std::shared_ptr<FloatKeyMap>;
using Vector3KeyMapPtr = std::shared_ptr<Vector3KeyMap>;
using Vector4KeyMapPtr = std::shared_ptr<Vector4KeyMap>;
using QuaternionKeyMapPtr = std::shared_ptr<QuaternionKeyMap>;
using ByteKeyMapPtr = std::shared_ptr<ByteKeyMap>;
using BoolKeyMapPtr = std::shared_ptr<BoolKeyMap>;
} // Namespace
#endif //#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP

@ -137,6 +137,22 @@ namespace Nif
read(transform.mScale);
}
template <>
void NIFStream::read<NiQuatTransform>(NiQuatTransform& transform)
{
read(transform.mTranslation);
read(transform.mRotation);
read(transform.mScale);
if (getVersion() >= generateVersion(10, 1, 0, 110))
return;
if (!get<bool>())
transform.mTranslation = osg::Vec3f();
if (!get<bool>())
transform.mRotation = osg::Quat();
if (!get<bool>())
transform.mScale = 1.f;
}
template <>
void NIFStream::read<bool>(bool& data)
{
@ -197,6 +213,12 @@ namespace Nif
readRange(*this, dest, size);
}
template <>
void NIFStream::read<NiQuatTransform>(NiQuatTransform* dest, size_t size)
{
readRange(*this, dest, size);
}
template <>
void NIFStream::read<bool>(bool* dest, size_t size)
{

@ -149,7 +149,6 @@ namespace Nif
/// DEPRECATED: Use read() or get()
char getChar() { return get<char>(); }
short getShort() { return get<short>(); }
unsigned short getUShort() { return get<unsigned short>(); }
int getInt() { return get<int>(); }
unsigned int getUInt() { return get<unsigned int>(); }
@ -157,10 +156,6 @@ namespace Nif
osg::Vec2f getVector2() { return get<osg::Vec2f>(); }
osg::Vec3f getVector3() { return get<osg::Vec3f>(); }
osg::Vec4f getVector4() { return get<osg::Vec4f>(); }
Matrix3 getMatrix3() { return get<Matrix3>(); }
osg::Quat getQuaternion() { return get<osg::Quat>(); }
bool getBoolean() { return get<bool>(); }
std::string getString() { return get<std::string>(); }
};
template <>
@ -178,6 +173,8 @@ namespace Nif
template <>
void NIFStream::read<NiTransform>(NiTransform& transform);
template <>
void NIFStream::read<NiQuatTransform>(NiQuatTransform& transform);
template <>
void NIFStream::read<bool>(bool& data);
template <>
void NIFStream::read<std::string>(std::string& str);
@ -197,6 +194,8 @@ namespace Nif
template <>
void NIFStream::read<NiTransform>(NiTransform* dest, size_t size);
template <>
void NIFStream::read<NiQuatTransform>(NiQuatTransform* dest, size_t size);
template <>
void NIFStream::read<bool>(bool* dest, size_t size);
template <>
void NIFStream::read<std::string>(std::string* dest, size_t size);

@ -25,6 +25,7 @@
#define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP
#include <osg/Matrixf>
#include <osg/Quat>
#include <osg/Vec3f>
// Common types used in NIF files
@ -80,5 +81,30 @@ namespace Nif
}
};
struct NiQuatTransform
{
osg::Vec3f mTranslation;
osg::Quat mRotation;
float mScale;
osg::Matrixf toMatrix() const
{
osg::Matrixf transform(mRotation);
transform.setTrans(mTranslation);
for (int i = 0; i < 3; i++)
transform(i, i) *= mScale;
return transform;
}
bool isIdentity() const { return mTranslation == osg::Vec3f() && mRotation == osg::Quat() && mScale == 1.f; }
static const NiQuatTransform& getIdentity()
{
static const NiQuatTransform identity = { osg::Vec3f(), osg::Quat(), 1.f };
return identity;
}
};
} // Namespace
#endif

@ -25,7 +25,7 @@ namespace Nif
case BOX_BV:
{
box.center = nif->getVector3();
box.axes = nif->getMatrix3();
nif->read(box.axes);
box.extents = nif->getVector3();
break;
}
@ -153,8 +153,8 @@ namespace Nif
if (nif->getVersion() < NIFStream::generateVersion(10, 0, 1, 0))
return;
unsigned int num = 0;
if (nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 3))
num = nif->getBoolean(); // Has Shader
if (nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 3) && nif->get<bool>())
num = 1;
else if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5))
num = nif->getUInt();
@ -163,7 +163,7 @@ namespace Nif
if (nif->getVersion() >= NIFStream::generateVersion(20, 2, 0, 5))
active = nif->getUInt();
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
needsUpdate = nif->getBoolean();
nif->read(needsUpdate);
}
void NiGeometry::read(NIFStream* nif)
@ -210,7 +210,7 @@ namespace Nif
nearDist = nif->getFloat();
farDist = nif->getFloat();
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
orthographic = nif->getBoolean();
nif->read(orthographic);
vleft = nif->getFloat();
vright = nif->getFloat();
vtop = nif->getFloat();

@ -9,7 +9,7 @@ namespace Nif
struct NiParticleModifier : public Record
{
NiParticleModifierPtr mNext;
ControllerPtr mController;
NiTimeControllerPtr mController;
void read(NIFStream* nif) override;
void post(Reader& nif) override;

@ -8,7 +8,7 @@ namespace Nif
void NiTexturingProperty::Texture::read(NIFStream* nif)
{
inUse = nif->getBoolean();
nif->read(inUse);
if (!inUse)
return;
@ -36,7 +36,7 @@ namespace Nif
nif->skip(2); // Unknown short
else if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
{
if (nif->getBoolean()) // Has texture transform
if (nif->get<bool>()) // Has texture transform
{
nif->getVector2(); // UV translation
nif->getVector2(); // UV scale

@ -79,7 +79,7 @@ namespace Nif
* 5 - Bump map texture
* 6 - Decal texture
*/
enum TextureType
enum TextureType : uint32_t
{
BaseTexture = 0,
DarkTexture = 1,

@ -116,7 +116,7 @@ namespace Nif
struct NiUVData;
struct NiPosData;
struct NiVisData;
struct Controller;
struct NiTimeController;
struct NiObjectNET;
struct NiSkinData;
struct NiFloatData;
@ -157,7 +157,7 @@ namespace Nif
using NiUVDataPtr = RecordPtrT<NiUVData>;
using NiPosDataPtr = RecordPtrT<NiPosData>;
using NiVisDataPtr = RecordPtrT<NiVisData>;
using ControllerPtr = RecordPtrT<Controller>;
using NiTimeControllerPtr = RecordPtrT<NiTimeController>;
using NiObjectNETPtr = RecordPtrT<NiObjectNET>;
using NiSkinDataPtr = RecordPtrT<NiSkinData>;
using NiMorphDataPtr = RecordPtrT<NiMorphData>;

@ -255,7 +255,7 @@ namespace NifBullet
if (node.recType == Nif::RC_NiCollisionSwitch && !node.collisionActive())
return;
for (Nif::ControllerPtr ctrl = node.mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = node.mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
if (args.mAnimated)
break;

@ -15,11 +15,11 @@
namespace NifOsg
{
ControllerFunction::ControllerFunction(const Nif::Controller* ctrl)
: mFrequency(ctrl->frequency)
, mPhase(ctrl->phase)
, mStartTime(ctrl->timeStart)
, mStopTime(ctrl->timeStop)
ControllerFunction::ControllerFunction(const Nif::NiTimeController* ctrl)
: mFrequency(ctrl->mFrequency)
, mPhase(ctrl->mPhase)
, mStartTime(ctrl->mTimeStart)
, mStopTime(ctrl->mTimeStop)
, mExtrapolationMode(ctrl->extrapolationMode())
{
}
@ -31,7 +31,7 @@ namespace NifOsg
return time;
switch (mExtrapolationMode)
{
case Nif::Controller::ExtrapolationMode::Cycle:
case Nif::NiTimeController::ExtrapolationMode::Cycle:
{
float delta = mStopTime - mStartTime;
if (delta <= 0)
@ -40,7 +40,7 @@ namespace NifOsg
float remainder = (cycles - std::floor(cycles)) * delta;
return mStartTime + remainder;
}
case Nif::Controller::ExtrapolationMode::Reverse:
case Nif::NiTimeController::ExtrapolationMode::Reverse:
{
float delta = mStopTime - mStartTime;
if (delta <= 0)
@ -55,7 +55,7 @@ namespace NifOsg
return mStopTime - remainder;
}
case Nif::Controller::ExtrapolationMode::Constant:
case Nif::NiTimeController::ExtrapolationMode::Constant:
default:
return std::clamp(time, mStartTime, mStopTime);
}
@ -90,21 +90,23 @@ namespace NifOsg
{
const Nif::NiTransformInterpolator* interp
= static_cast<const Nif::NiTransformInterpolator*>(keyctrl->mInterpolator.getPtr());
if (!interp->data.empty())
const Nif::NiQuatTransform& defaultTransform = interp->mDefaultValue;
if (!interp->mData.empty())
{
mRotations = QuaternionInterpolator(interp->data->mRotations, interp->defaultRot);
mXRotations = FloatInterpolator(interp->data->mXRotations);
mYRotations = FloatInterpolator(interp->data->mYRotations);
mZRotations = FloatInterpolator(interp->data->mZRotations);
mTranslations = Vec3Interpolator(interp->data->mTranslations, interp->defaultPos);
mScales = FloatInterpolator(interp->data->mScales, interp->defaultScale);
mAxisOrder = interp->data->mAxisOrder;
mRotations = QuaternionInterpolator(interp->mData->mRotations, defaultTransform.mRotation);
mXRotations = FloatInterpolator(interp->mData->mXRotations);
mYRotations = FloatInterpolator(interp->mData->mYRotations);
mZRotations = FloatInterpolator(interp->mData->mZRotations);
mTranslations = Vec3Interpolator(interp->mData->mTranslations, defaultTransform.mTranslation);
mScales = FloatInterpolator(interp->mData->mScales, defaultTransform.mScale);
mAxisOrder = interp->mData->mAxisOrder;
}
else
{
mRotations = QuaternionInterpolator(Nif::QuaternionKeyMapPtr(), interp->defaultRot);
mTranslations = Vec3Interpolator(Nif::Vector3KeyMapPtr(), interp->defaultPos);
mScales = FloatInterpolator(Nif::FloatKeyMapPtr(), interp->defaultScale);
mRotations = QuaternionInterpolator(Nif::QuaternionKeyMapPtr(), defaultTransform.mRotation);
mTranslations = Vec3Interpolator(Nif::Vector3KeyMapPtr(), defaultTransform.mTranslation);
mScales = FloatInterpolator(Nif::FloatKeyMapPtr(), defaultTransform.mScale);
}
}
}
@ -117,6 +119,7 @@ namespace NifOsg
mZRotations = FloatInterpolator(keydata->mZRotations);
mTranslations = Vec3Interpolator(keydata->mTranslations);
mScales = FloatInterpolator(keydata->mScales, 1.f);
mAxisOrder = keydata->mAxisOrder;
}
}
@ -177,11 +180,11 @@ namespace NifOsg
else
node->setRotation(node->mRotationScale);
if (!mScales.empty())
node->setScale(mScales.interpKey(time));
if (!mTranslations.empty())
node->setTranslation(mTranslations.interpKey(time));
if (!mScales.empty())
node->setScale(mScales.interpKey(time));
}
traverse(node, nv);
@ -251,9 +254,7 @@ namespace NifOsg
}
}
UVController::UVController() {}
UVController::UVController(const Nif::NiUVData* data, const std::set<int>& textureUnits)
UVController::UVController(const Nif::NiUVData* data, const std::set<unsigned int>& textureUnits)
: mUTrans(data->mKeyList[0], 0.f)
, mVTrans(data->mKeyList[1], 0.f)
, mUScale(data->mKeyList[2], 1.f)
@ -277,8 +278,8 @@ namespace NifOsg
void UVController::setDefaults(osg::StateSet* stateset)
{
osg::ref_ptr<osg::TexMat> texMat(new osg::TexMat);
for (std::set<int>::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it)
stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON);
for (unsigned int unit : mTextureUnits)
stateset->setTextureAttributeAndModes(unit, texMat, osg::StateAttribute::ON);
}
void UVController::apply(osg::StateSet* stateset, osg::NodeVisitor* nv)
@ -314,9 +315,10 @@ namespace NifOsg
{
if (!ctrl->mInterpolator.empty())
{
if (ctrl->mInterpolator->recType == Nif::RC_NiBoolInterpolator)
mInterpolator
= ByteInterpolator(static_cast<const Nif::NiBoolInterpolator*>(ctrl->mInterpolator.getPtr()));
if (ctrl->mInterpolator->recType != Nif::RC_NiBoolInterpolator)
return;
mInterpolator = { static_cast<const Nif::NiBoolInterpolator*>(ctrl->mInterpolator.getPtr()) };
}
else if (!ctrl->mData.empty())
mData = ctrl->mData->mKeys;
@ -444,7 +446,7 @@ namespace NifOsg
MaterialColorController::MaterialColorController(
const Nif::NiMaterialColorController* ctrl, const osg::Material* baseMaterial)
: mTargetColor(static_cast<MaterialColorController::TargetColor>(ctrl->mTargetColor))
: mTargetColor(ctrl->mTargetColor)
, mBaseMaterial(baseMaterial)
{
if (!ctrl->mInterpolator.empty())
@ -477,30 +479,31 @@ namespace NifOsg
{
osg::Vec3f value = mData.interpKey(getInputValue(nv));
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
using TargetColor = Nif::NiMaterialColorController::TargetColor;
switch (mTargetColor)
{
case Diffuse:
case TargetColor::Diffuse:
{
osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK);
diffuse.set(value.x(), value.y(), value.z(), diffuse.a());
mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
break;
}
case Specular:
case TargetColor::Specular:
{
osg::Vec4f specular = mat->getSpecular(osg::Material::FRONT_AND_BACK);
specular.set(value.x(), value.y(), value.z(), specular.a());
mat->setSpecular(osg::Material::FRONT_AND_BACK, specular);
break;
}
case Emissive:
case TargetColor::Emissive:
{
osg::Vec4f emissive = mat->getEmission(osg::Material::FRONT_AND_BACK);
emissive.set(value.x(), value.y(), value.z(), emissive.a());
mat->setEmission(osg::Material::FRONT_AND_BACK, emissive);
break;
}
case Ambient:
case TargetColor::Ambient:
default:
{
osg::Vec4f ambient = mat->getAmbient(osg::Material::FRONT_AND_BACK);
@ -552,14 +555,8 @@ namespace NifOsg
}
ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController* ctrl)
: mEmitStart(ctrl->startTime)
, mEmitStop(ctrl->stopTime)
{
}
ParticleSystemController::ParticleSystemController()
: mEmitStart(0.f)
, mEmitStop(0.f)
: mEmitStart(ctrl->mEmitStartTime)
, mEmitStop(ctrl->mEmitStopTime)
{
}
@ -594,9 +591,9 @@ namespace NifOsg
}
PathController::PathController(const Nif::NiPathController* ctrl)
: mPath(ctrl->posData->mKeyList, osg::Vec3f())
, mPercent(ctrl->floatData->mKeyList, 1.f)
, mFlags(ctrl->flags)
: mPath(ctrl->mPathData->mKeyList, osg::Vec3f())
, mPercent(ctrl->mPercentData->mKeyList, 1.f)
, mFlags(ctrl->mPathFlags)
{
}

@ -63,18 +63,17 @@ namespace NifOsg
ValueInterpolator() = default;
template <class T,
typename
= std::enable_if_t<std::conjunction_v<std::disjunction<std::is_same<ValueT, float>,
std::is_same<ValueT, osg::Vec3f>, std::is_same<ValueT, bool>,
std::is_same<ValueT, osg::Vec4f>, std::is_same<ValueT, char>>,
std::is_same<decltype(T::defaultVal), ValueT>>,
typename = std::enable_if_t<
std::conjunction_v<std::disjunction<std::is_same<ValueT, float>, std::is_same<ValueT, osg::Vec3f>,
std::is_same<ValueT, bool>, std::is_same<ValueT, osg::Vec4f>>,
std::is_same<decltype(T::mDefaultValue), ValueT>>,
T>>
ValueInterpolator(const T* interpolator)
: mDefaultVal(interpolator->defaultVal)
: mDefaultVal(interpolator->mDefaultValue)
{
if (interpolator->data.empty())
if (interpolator->mData.empty())
return;
mKeys = interpolator->data->mKeyList;
mKeys = interpolator->mData->mKeyList;
if (mKeys)
{
mLastLowKey = mKeys->mKeys.end();
@ -182,7 +181,7 @@ namespace NifOsg
using FloatInterpolator = ValueInterpolator<Nif::FloatKeyMap>;
using Vec3Interpolator = ValueInterpolator<Nif::Vector3KeyMap>;
using Vec4Interpolator = ValueInterpolator<Nif::Vector4KeyMap>;
using ByteInterpolator = ValueInterpolator<Nif::ByteKeyMap>;
using BoolInterpolator = ValueInterpolator<Nif::BoolKeyMap>;
class ControllerFunction : public SceneUtil::ControllerFunction
{
@ -191,10 +190,10 @@ namespace NifOsg
float mPhase;
float mStartTime;
float mStopTime;
Nif::Controller::ExtrapolationMode mExtrapolationMode;
Nif::NiTimeController::ExtrapolationMode mExtrapolationMode;
public:
ControllerFunction(const Nif::Controller* ctrl);
ControllerFunction(const Nif::NiTimeController* ctrl);
float calculate(float value) const override;
@ -262,9 +261,9 @@ namespace NifOsg
class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
{
public:
UVController();
UVController() = default;
UVController(const UVController&, const osg::CopyOp&);
UVController(const Nif::NiUVData* data, const std::set<int>& textureUnits);
UVController(const Nif::NiUVData* data, const std::set<unsigned int>& textureUnits);
META_Object(NifOsg, UVController)
@ -276,14 +275,14 @@ namespace NifOsg
FloatInterpolator mVTrans;
FloatInterpolator mUScale;
FloatInterpolator mVScale;
std::set<int> mTextureUnits;
std::set<unsigned int> mTextureUnits;
};
class VisController : public SceneUtil::NodeCallback<VisController>, public SceneUtil::Controller
{
private:
std::shared_ptr<std::map<float, bool>> mData;
ByteInterpolator mInterpolator;
BoolInterpolator mInterpolator;
unsigned int mMask{ 0u };
bool calculate(float time) const;
@ -336,13 +335,6 @@ namespace NifOsg
class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
{
public:
enum TargetColor
{
Ambient = 0,
Diffuse = 1,
Specular = 2,
Emissive = 3
};
MaterialColorController(const Nif::NiMaterialColorController* ctrl, const osg::Material* baseMaterial);
MaterialColorController();
MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop);
@ -355,7 +347,7 @@ namespace NifOsg
private:
Vec3Interpolator mData;
TargetColor mTargetColor = Ambient;
Nif::NiMaterialColorController::TargetColor mTargetColor;
osg::ref_ptr<const osg::Material> mBaseMaterial;
};
@ -386,7 +378,7 @@ namespace NifOsg
{
public:
ParticleSystemController(const Nif::NiParticleSystemController* ctrl);
ParticleSystemController();
ParticleSystemController() = default;
ParticleSystemController(const ParticleSystemController& copy, const osg::CopyOp& copyop);
META_Object(NifOsg, ParticleSystemController)
@ -394,8 +386,8 @@ namespace NifOsg
void operator()(osgParticle::ParticleProcessor* node, osg::NodeVisitor* nv);
private:
float mEmitStart;
float mEmitStop;
float mEmitStart{ 0.f };
float mEmitStop{ 0.f };
};
class PathController : public SceneUtil::NodeCallback<PathController, NifOsg::MatrixTransform*>,

@ -293,8 +293,8 @@ namespace NifOsg
auto textKeyExtraData = static_cast<const Nif::NiTextKeyExtraData*>(extraList[0].getPtr());
extractTextKeys(textKeyExtraData, target.mTextKeys);
Nif::ControllerPtr ctrl = seq->mController;
for (size_t i = 1; i < extraList.size() && !ctrl.empty(); i++, (ctrl = ctrl->next))
Nif::NiTimeControllerPtr ctrl = seq->mController;
for (size_t i = 1; i < extraList.size() && !ctrl.empty(); i++, (ctrl = ctrl->mNext))
{
Nif::ExtraPtr extra = extraList[i];
if (extra->recType != Nif::RC_NiStringExtraData || ctrl->recType != Nif::RC_NiKeyframeController)
@ -449,7 +449,7 @@ namespace NifOsg
animflags, hasStencilProperty);
}
static void setupController(const Nif::Controller* ctrl, SceneUtil::Controller* toSetup, int animflags)
static void setupController(const Nif::NiTimeController* ctrl, SceneUtil::Controller* toSetup, int animflags)
{
bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay;
if (autoPlay)
@ -725,7 +725,7 @@ namespace NifOsg
if (nifNode->isHidden())
{
bool hasVisController = false;
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
hasVisController |= (ctrl->recType == Nif::RC_NiVisController);
if (hasVisController)
@ -858,25 +858,24 @@ namespace NifOsg
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
int animflags)
{
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
if (!ctrl->isActive())
continue;
if (ctrl->recType == Nif::RC_NiUVController)
{
const Nif::NiUVController* niuvctrl = static_cast<const Nif::NiUVController*>(ctrl.getPtr());
if (niuvctrl->data.empty())
if (niuvctrl->mData.empty())
continue;
const unsigned int uvSet = niuvctrl->uvSet;
std::set<int> texUnits;
// UVController should work only for textures which use a given UV Set, usually 0.
std::set<unsigned int> texUnits;
// UVController should only work for textures which use the given UV Set.
for (unsigned int i = 0; i < boundTextures.size(); ++i)
{
if (boundTextures[i] == uvSet)
if (boundTextures[i] == niuvctrl->mUvSet)
texUnits.insert(i);
}
osg::ref_ptr<UVController> uvctrl = new UVController(niuvctrl->data.getPtr(), texUnits);
osg::ref_ptr<UVController> uvctrl = new UVController(niuvctrl->mData.getPtr(), texUnits);
setupController(niuvctrl, uvctrl, animflags);
composite->addController(uvctrl);
}
@ -885,7 +884,7 @@ namespace NifOsg
void handleNodeControllers(const Nif::NiAVObject* nifNode, osg::Node* node, int animflags, bool& isAnimated)
{
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
if (!ctrl->isActive())
continue;
@ -908,7 +907,7 @@ namespace NifOsg
else if (ctrl->recType == Nif::RC_NiPathController)
{
const Nif::NiPathController* path = static_cast<const Nif::NiPathController*>(ctrl.getPtr());
if (path->posData.empty() || path->floatData.empty())
if (path->mPathData.empty() || path->mPercentData.empty())
continue;
osg::ref_ptr<PathController> callback(new PathController(path));
setupController(path, callback, animflags);
@ -963,7 +962,7 @@ namespace NifOsg
void handleMaterialControllers(const Nif::Property* materialProperty,
SceneUtil::CompositeStateSetUpdater* composite, int animflags, const osg::Material* baseMaterial)
{
for (Nif::ControllerPtr ctrl = materialProperty->mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = materialProperty->mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
if (!ctrl->isActive())
continue;
@ -988,18 +987,16 @@ namespace NifOsg
{
const Nif::NiMaterialColorController* matctrl
= static_cast<const Nif::NiMaterialColorController*>(ctrl.getPtr());
if (matctrl->mData.empty() && matctrl->mInterpolator.empty())
Nif::NiInterpolatorPtr interp = matctrl->mInterpolator;
if (matctrl->mData.empty() && interp.empty())
continue;
auto targetColor = static_cast<MaterialColorController::TargetColor>(matctrl->mTargetColor);
if (mVersion <= Nif::NIFFile::VER_MW
&& targetColor == MaterialColorController::TargetColor::Specular)
&& matctrl->mTargetColor == Nif::NiMaterialColorController::TargetColor::Specular)
continue;
if (!matctrl->mInterpolator.empty()
&& matctrl->mInterpolator->recType != Nif::RC_NiPoint3Interpolator)
if (!interp.empty() && interp->recType != Nif::RC_NiPoint3Interpolator)
{
Log(Debug::Error)
<< "Unsupported interpolator type for NiMaterialColorController " << matctrl->recIndex
<< " in " << mFilename << ": " << matctrl->mInterpolator->recName;
Log(Debug::Error) << "Unsupported interpolator type for NiMaterialColorController "
<< matctrl->recIndex << " in " << mFilename << ": " << interp->recName;
continue;
}
osg::ref_ptr<MaterialColorController> osgctrl = new MaterialColorController(matctrl, baseMaterial);
@ -1014,7 +1011,7 @@ namespace NifOsg
void handleTextureControllers(const Nif::Property* texProperty, SceneUtil::CompositeStateSetUpdater* composite,
Resource::ImageManager* imageManager, osg::StateSet* stateset, int animflags)
{
for (Nif::ControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
if (!ctrl->isActive())
continue;
@ -1063,7 +1060,7 @@ namespace NifOsg
}
}
void handleParticlePrograms(Nif::NiParticleModifierPtr affectors, Nif::NiParticleModifierPtr colliders,
void handleParticlePrograms(Nif::NiParticleModifierPtr modifier, Nif::NiParticleModifierPtr collider,
osg::Group* attachTo, osgParticle::ParticleSystem* partsys,
osgParticle::ParticleProcessor::ReferenceFrame rf)
{
@ -1071,50 +1068,50 @@ namespace NifOsg
attachTo->addChild(program);
program->setParticleSystem(partsys);
program->setReferenceFrame(rf);
for (; !affectors.empty(); affectors = affectors->mNext)
for (; !modifier.empty(); modifier = modifier->mNext)
{
if (affectors->recType == Nif::RC_NiParticleGrowFade)
if (modifier->recType == Nif::RC_NiParticleGrowFade)
{
const Nif::NiParticleGrowFade* gf = static_cast<const Nif::NiParticleGrowFade*>(affectors.getPtr());
const Nif::NiParticleGrowFade* gf = static_cast<const Nif::NiParticleGrowFade*>(modifier.getPtr());
program->addOperator(new GrowFadeAffector(gf->mGrowTime, gf->mFadeTime));
}
else if (affectors->recType == Nif::RC_NiGravity)
else if (modifier->recType == Nif::RC_NiGravity)
{
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(affectors.getPtr());
const Nif::NiGravity* gr = static_cast<const Nif::NiGravity*>(modifier.getPtr());
program->addOperator(new GravityAffector(gr));
}
else if (affectors->recType == Nif::RC_NiParticleColorModifier)
else if (modifier->recType == Nif::RC_NiParticleColorModifier)
{
const Nif::NiParticleColorModifier* cl
= static_cast<const Nif::NiParticleColorModifier*>(affectors.getPtr());
= static_cast<const Nif::NiParticleColorModifier*>(modifier.getPtr());
if (cl->mData.empty())
continue;
const Nif::NiColorData* clrdata = cl->mData.getPtr();
program->addOperator(new ParticleColorAffector(clrdata));
}
else if (affectors->recType == Nif::RC_NiParticleRotation)
else if (modifier->recType == Nif::RC_NiParticleRotation)
{
// unused
}
else
Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename;
Log(Debug::Info) << "Unhandled particle modifier " << modifier->recName << " in " << mFilename;
}
for (; !colliders.empty(); colliders = colliders->mNext)
for (; !collider.empty(); collider = collider->mNext)
{
if (colliders->recType == Nif::RC_NiPlanarCollider)
if (collider->recType == Nif::RC_NiPlanarCollider)
{
const Nif::NiPlanarCollider* planarcollider
= static_cast<const Nif::NiPlanarCollider*>(colliders.getPtr());
= static_cast<const Nif::NiPlanarCollider*>(collider.getPtr());
program->addOperator(new PlanarCollider(planarcollider));
}
else if (colliders->recType == Nif::RC_NiSphericalCollider)
else if (collider->recType == Nif::RC_NiSphericalCollider)
{
const Nif::NiSphericalCollider* sphericalcollider
= static_cast<const Nif::NiSphericalCollider*>(colliders.getPtr());
= static_cast<const Nif::NiSphericalCollider*>(collider.getPtr());
program->addOperator(new SphericalCollider(sphericalcollider));
}
else
Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename;
Log(Debug::Info) << "Unhandled particle collider " << collider->recName << " in " << mFilename;
}
}
@ -1126,7 +1123,7 @@ namespace NifOsg
auto particleNode = static_cast<const Nif::NiParticles*>(nifNode);
if (particleNode->data.empty() || particleNode->data->recType != Nif::RC_NiParticlesData)
{
partsys->setQuota(partctrl->numParticles);
partsys->setQuota(partctrl->mParticles.size());
return;
}
@ -1136,35 +1133,35 @@ namespace NifOsg
osg::BoundingBox box;
int i = 0;
for (const auto& particle : partctrl->particles)
for (const auto& particle : partctrl->mParticles)
{
if (i++ >= particledata->mActiveCount)
break;
if (particle.lifespan <= 0)
if (particle.mLifespan <= 0)
continue;
if (particle.vertex >= particledata->mVertices.size())
if (particle.mCode >= particledata->mVertices.size())
continue;
ParticleAgeSetter particletemplate(std::max(0.f, particle.lifetime));
ParticleAgeSetter particletemplate(std::max(0.f, particle.mAge));
osgParticle::Particle* created = partsys->createParticle(&particletemplate);
created->setLifeTime(particle.lifespan);
created->setLifeTime(particle.mLifespan);
// Note this position and velocity is not correct for a particle system with absolute reference frame,
// which can not be done in this loader since we are not attached to the scene yet. Will be fixed up
// post-load in the SceneManager.
created->setVelocity(particle.velocity);
const osg::Vec3f& position = particledata->mVertices[particle.vertex];
created->setVelocity(particle.mVelocity);
const osg::Vec3f& position = particledata->mVertices[particle.mCode];
created->setPosition(position);
created->setColorRange(osgParticle::rangev4(partctrl->color, partctrl->color));
created->setColorRange(osgParticle::rangev4(partctrl->mInitialColor, partctrl->mInitialColor));
created->setAlphaRange(osgParticle::rangef(1.f, 1.f));
float size = partctrl->size;
if (particle.vertex < particledata->mSizes.size())
size *= particledata->mSizes[particle.vertex];
float size = partctrl->mInitialSize;
if (particle.mCode < particledata->mSizes.size())
size *= particledata->mSizes[particle.mCode];
created->setSizeRange(osgParticle::rangef(size, size));
box.expandBy(osg::BoundingSphere(position, size));
@ -1181,39 +1178,39 @@ namespace NifOsg
std::vector<int> targets;
if (partctrl->recType == Nif::RC_NiBSPArrayController && !partctrl->emitAtVertex())
{
getAllNiNodes(partctrl->emitter.getPtr(), targets);
getAllNiNodes(partctrl->mEmitter.getPtr(), targets);
}
osg::ref_ptr<Emitter> emitter = new Emitter(targets);
osgParticle::ConstantRateCounter* counter = new osgParticle::ConstantRateCounter;
if (partctrl->noAutoAdjust())
counter->setNumberOfParticlesPerSecondToCreate(partctrl->emitRate);
else if (partctrl->lifetime == 0 && partctrl->lifetimeRandom == 0)
counter->setNumberOfParticlesPerSecondToCreate(partctrl->mBirthRate);
else if (partctrl->mLifetime == 0 && partctrl->mLifetimeVariation == 0)
counter->setNumberOfParticlesPerSecondToCreate(0);
else
counter->setNumberOfParticlesPerSecondToCreate(
partctrl->numParticles / (partctrl->lifetime + partctrl->lifetimeRandom / 2));
partctrl->mParticles.size() / (partctrl->mLifetime + partctrl->mLifetimeVariation / 2));
emitter->setCounter(counter);
ParticleShooter* shooter = new ParticleShooter(partctrl->velocity - partctrl->velocityRandom * 0.5f,
partctrl->velocity + partctrl->velocityRandom * 0.5f, partctrl->horizontalDir,
partctrl->horizontalAngle, partctrl->verticalDir, partctrl->verticalAngle, partctrl->lifetime,
partctrl->lifetimeRandom);
ParticleShooter* shooter = new ParticleShooter(partctrl->mSpeed - partctrl->mSpeedVariation * 0.5f,
partctrl->mSpeed + partctrl->mSpeedVariation * 0.5f, partctrl->mPlanarAngle,
partctrl->mPlanarAngleVariation, partctrl->mDeclination, partctrl->mDeclinationVariation,
partctrl->mLifetime, partctrl->mLifetimeVariation);
emitter->setShooter(shooter);
emitter->setFlags(partctrl->flags);
emitter->setFlags(partctrl->mFlags);
if (partctrl->recType == Nif::RC_NiBSPArrayController && partctrl->emitAtVertex())
{
emitter->setGeometryEmitterTarget(partctrl->emitter->recIndex);
emitter->setGeometryEmitterTarget(partctrl->mEmitter->recIndex);
}
else
{
osgParticle::BoxPlacer* placer = new osgParticle::BoxPlacer;
placer->setXRange(-partctrl->offsetRandom.x() / 2.f, partctrl->offsetRandom.x() / 2.f);
placer->setYRange(-partctrl->offsetRandom.y() / 2.f, partctrl->offsetRandom.y() / 2.f);
placer->setZRange(-partctrl->offsetRandom.z() / 2.f, partctrl->offsetRandom.z() / 2.f);
placer->setXRange(-partctrl->mEmitterDimensions.x() / 2.f, partctrl->mEmitterDimensions.x() / 2.f);
placer->setYRange(-partctrl->mEmitterDimensions.y() / 2.f, partctrl->mEmitterDimensions.y() / 2.f);
placer->setZRange(-partctrl->mEmitterDimensions.z() / 2.f, partctrl->mEmitterDimensions.z() / 2.f);
emitter->setPlacer(placer);
}
@ -1254,7 +1251,7 @@ namespace NifOsg
partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT);
const Nif::NiParticleSystemController* partctrl = nullptr;
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
if (!ctrl->isActive())
continue;
@ -1282,11 +1279,13 @@ namespace NifOsg
handleParticleInitialState(nifNode, partsys, partctrl);
partsys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(partctrl->size, partctrl->size));
partsys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4(partctrl->color, partctrl->color));
partsys->getDefaultParticleTemplate().setSizeRange(
osgParticle::rangef(partctrl->mInitialSize, partctrl->mInitialSize));
partsys->getDefaultParticleTemplate().setColorRange(
osgParticle::rangev4(partctrl->mInitialColor, partctrl->mInitialColor));
partsys->getDefaultParticleTemplate().setAlphaRange(osgParticle::rangef(1.f, 1.f));
if (!partctrl->emitter.empty())
if (!partctrl->mEmitter.empty())
{
osg::ref_ptr<Emitter> emitter = handleParticleEmitter(partctrl);
emitter->setParticleSystem(partsys);
@ -1295,7 +1294,7 @@ namespace NifOsg
// The emitter node may not actually be handled yet, so let's delay attaching the emitter to a later
// moment. If the emitter node is placed later than the particle node, it'll have a single frame delay
// in particle processing. But that shouldn't be a game-breaking issue.
mEmitterQueue.emplace_back(partctrl->emitter->recIndex, emitter);
mEmitterQueue.emplace_back(partctrl->mEmitter->recIndex, emitter);
osg::ref_ptr<ParticleSystemController> callback(new ParticleSystemController(partctrl));
setupController(partctrl, callback, animflags);
@ -1312,16 +1311,16 @@ namespace NifOsg
partsys->update(0.0, nv);
}
// affectors should be attached *after* the emitter in the scene graph for correct update order
// modifiers should be attached *after* the emitter in the scene graph for correct update order
// attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct
// localToWorldMatrix for transforming to particle space
handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf);
handleParticlePrograms(partctrl->mModifier, partctrl->mCollider, parentNode, partsys.get(), rf);
std::vector<const Nif::Property*> drawableProps;
collectDrawableProperties(nifNode, parent, drawableProps);
applyDrawableProperties(parentNode, drawableProps, composite, true, animflags);
// particle system updater (after the emitters and affectors in the scene graph)
// particle system updater (after the emitters and modifiers in the scene graph)
// I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other
// way
osg::ref_ptr<osgParticle::ParticleSystemUpdater> updater = new osgParticle::ParticleSystemUpdater;
@ -1485,7 +1484,7 @@ namespace NifOsg
if (geom->empty())
return;
osg::ref_ptr<osg::Drawable> drawable;
for (Nif::ControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->next)
for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext)
{
if (!ctrl->isActive())
continue;

Loading…
Cancel
Save