mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 19:45:40 +00:00
Merge branch 'nif' into 'master'
Modernize NIF loader, part 4 See merge request OpenMW/openmw!3427
This commit is contained in:
commit
64e4a33400
20 changed files with 648 additions and 697 deletions
|
@ -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);
|
||||
NiTimeController::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++)
|
||||
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);
|
||||
|
||||
bankDir = nif->getInt();
|
||||
maxBankAngle = nif->getFloat();
|
||||
smoothing = nif->getFloat();
|
||||
followAxis = nif->getShort();
|
||||
posData.read(nif);
|
||||
floatData.read(nif);
|
||||
if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0))
|
||||
nif->read(mPathFlags);
|
||||
else
|
||||
mPathFlags = (mFlags >> 4);
|
||||
|
||||
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
|
||||
{
|
||||
NiPosDataPtr mData;
|
||||
unsigned int mTargetColor;
|
||||
|
||||
void read(NIFStream* nif) override;
|
||||
void post(Reader& nif) override;
|
||||
};
|
||||
|
||||
struct NiPathController : public Controller
|
||||
{
|
||||
NiPosDataPtr posData;
|
||||
NiFloatDataPtr floatData;
|
||||
|
||||
enum Flags
|
||||
enum class TargetColor
|
||||
{
|
||||
Flag_OpenCurve = 0x020,
|
||||
Flag_AllowFlip = 0x040,
|
||||
Flag_Bank = 0x080,
|
||||
Flag_ConstVelocity = 0x100,
|
||||
Flag_Follow = 0x200,
|
||||
Flag_FlipFollowAxis = 0x400
|
||||
Ambient = 0,
|
||||
Diffuse = 1,
|
||||
Specular = 2,
|
||||
Emissive = 3,
|
||||
};
|
||||
|
||||
int bankDir;
|
||||
float maxBankAngle, smoothing;
|
||||
short followAxis;
|
||||
NiPosDataPtr mData;
|
||||
TargetColor mTargetColor;
|
||||
|
||||
void read(NIFStream* nif) override;
|
||||
void post(Reader& nif) override;
|
||||
};
|
||||
|
||||
struct NiLookAtController : public Controller
|
||||
struct NiPathController : public NiTimeController
|
||||
{
|
||||
NiAVObjectPtr target;
|
||||
unsigned short lookAtFlags{ 0 };
|
||||
enum Flags
|
||||
{
|
||||
Flag_CVDataNeedsUpdate = 0x01,
|
||||
Flag_OpenCurve = 0x02,
|
||||
Flag_AllowFlip = 0x04,
|
||||
Flag_Bank = 0x08,
|
||||
Flag_ConstVelocity = 0x10,
|
||||
Flag_Follow = 0x20,
|
||||
Flag_FlipFollowAxis = 0x40,
|
||||
};
|
||||
|
||||
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 NiUVController : public Controller
|
||||
struct NiLookAtController : public NiTimeController
|
||||
{
|
||||
NiUVDataPtr data;
|
||||
unsigned int uvSet;
|
||||
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 NiTimeController
|
||||
{
|
||||
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
|
||||
{
|
||||
char defaultVal;
|
||||
NiBoolDataPtr data;
|
||||
void read(NIFStream* nif) override;
|
||||
void post(Reader& nif) override;
|
||||
};
|
||||
|
||||
struct NiFloatInterpolator : public NiInterpolator
|
||||
{
|
||||
float defaultVal;
|
||||
NiFloatDataPtr data;
|
||||
void read(NIFStream* nif) override;
|
||||
void post(Reader& nif) override;
|
||||
};
|
||||
|
||||
struct NiTransformInterpolator : public NiInterpolator
|
||||
{
|
||||
osg::Vec3f defaultPos;
|
||||
osg::Quat defaultRot;
|
||||
float defaultScale;
|
||||
NiKeyframeDataPtr data;
|
||||
|
||||
void read(NIFStream* nif) override;
|
||||
void post(Reader& nif) override;
|
||||
};
|
||||
|
||||
struct NiColorInterpolator : public NiInterpolator
|
||||
{
|
||||
osg::Vec4f defaultVal;
|
||||
NiColorDataPtr data;
|
||||
void read(NIFStream* nif) override;
|
||||
void post(Reader& nif) override;
|
||||
};
|
||||
|
||||
// Abstract
|
||||
struct NiInterpolator : public Record
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, class DataPtr>
|
||||
struct TypedNiInterpolator : public NiInterpolator
|
||||
{
|
||||
T mDefaultValue;
|
||||
DataPtr mData;
|
||||
|
||||
void read(NIFStream* nif) override
|
||||
{
|
||||
nif->read(mDefaultValue);
|
||||
mData.read(nif);
|
||||
}
|
||||
|
||||
void post(Reader& nif) override { mData.post(nif); }
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
void read(NIFStream* nif) override
|
||||
{
|
||||
NiBlendInterpolator::read(nif);
|
||||
|
||||
nif->read(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
struct NiBlendFloatInterpolator : public NiBlendInterpolator
|
||||
template <>
|
||||
struct TypedNiBlendInterpolator<NiQuatTransform> : public NiBlendInterpolator
|
||||
{
|
||||
float mValue;
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
struct NiBlendPoint3Interpolator : public NiBlendInterpolator
|
||||
{
|
||||
osg::Vec3f mValue;
|
||||
void read(NIFStream* nif) override;
|
||||
};
|
||||
using NiBlendBoolInterpolator = TypedNiBlendInterpolator<uint8_t>;
|
||||
using NiBlendFloatInterpolator = TypedNiBlendInterpolator<float>;
|
||||
using NiBlendPoint3Interpolator = TypedNiBlendInterpolator<osg::Vec3f>;
|
||||
using NiBlendTransformInterpolator = TypedNiBlendInterpolator<NiQuatTransform>;
|
||||
|
||||
struct NiBlendTransformInterpolator : public NiBlendInterpolator
|
||||
{
|
||||
osg::Vec3f mPosValue;
|
||||
osg::Quat mRotValue;
|
||||
float mScaleValue;
|
||||
void read(NIFStream* nif) override;
|
||||
};
|
||||
|
||||
} // Namespace
|
||||
}
|
||||
#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…
Reference in a new issue