forked from mirror/openmw-tes3mp
Cache the current position in the animation track and attempt to reuse it in the next frame. Decent speed up for the Update phase, about 0.3 ms faster in Balmora.
327 lines
9.5 KiB
C++
327 lines
9.5 KiB
C++
#ifndef COMPONENTS_NIFOSG_CONTROLLER_H
|
|
#define COMPONENTS_NIFOSG_CONTROLLER_H
|
|
|
|
#include <components/nif/niffile.hpp>
|
|
#include <components/nif/nifkey.hpp>
|
|
#include <components/nif/controller.hpp>
|
|
#include <components/nif/data.hpp>
|
|
|
|
#include <components/sceneutil/controller.hpp>
|
|
#include <components/sceneutil/statesetupdater.hpp>
|
|
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
#include <set> //UVController
|
|
|
|
// FlipController
|
|
#include <osg/Texture2D>
|
|
#include <osg/ref_ptr>
|
|
|
|
#include <osg/Timer>
|
|
#include <osg/StateSet>
|
|
#include <osg/NodeCallback>
|
|
#include <osg/Drawable>
|
|
|
|
|
|
namespace osg
|
|
{
|
|
class Node;
|
|
class StateSet;
|
|
}
|
|
|
|
namespace osgParticle
|
|
{
|
|
class Emitter;
|
|
}
|
|
|
|
namespace osgAnimation
|
|
{
|
|
class MorphGeometry;
|
|
}
|
|
|
|
namespace NifOsg
|
|
{
|
|
|
|
// interpolation of keyframes
|
|
template <typename MapT, typename InterpolationFunc>
|
|
class ValueInterpolator
|
|
{
|
|
public:
|
|
ValueInterpolator()
|
|
: mDefaultVal(typename MapT::ValueType())
|
|
{
|
|
}
|
|
|
|
ValueInterpolator(boost::shared_ptr<MapT> keys, typename MapT::ValueType defaultVal = typename MapT::ValueType())
|
|
: mKeys(keys)
|
|
, mDefaultVal(defaultVal)
|
|
{
|
|
if (keys)
|
|
{
|
|
mLastLowKey = mKeys->mKeys.end();
|
|
mLastHighKey = mKeys->mKeys.end();
|
|
}
|
|
}
|
|
|
|
typename MapT::ValueType interpKey(float time) const
|
|
{
|
|
if (empty())
|
|
return mDefaultVal;
|
|
|
|
const typename MapT::MapType & keys = mKeys->mKeys;
|
|
|
|
if(time <= keys.begin()->first)
|
|
return keys.begin()->second.mValue;
|
|
|
|
// retrieve the current position in the map, optimized for the most common case
|
|
// where time moves linearly along the keyframe track
|
|
typename MapT::MapType::const_iterator it = mLastHighKey;
|
|
if (mLastHighKey != keys.end())
|
|
{
|
|
if (time > mLastHighKey->first)
|
|
{
|
|
// try if we're there by incrementing one
|
|
++mLastLowKey;
|
|
++mLastHighKey;
|
|
it = mLastHighKey;
|
|
}
|
|
if (mLastHighKey == keys.end() || (time < mLastLowKey->first || time > mLastHighKey->first))
|
|
it = keys.lower_bound(time); // still not there, reorient by performing lower_bound check on the whole map
|
|
}
|
|
else
|
|
it = keys.lower_bound(time);
|
|
|
|
// now do the actual interpolation
|
|
if (it != keys.end())
|
|
{
|
|
float aTime = it->first;
|
|
const typename MapT::KeyType* aKey = &it->second;
|
|
|
|
// cache for next time
|
|
mLastHighKey = it;
|
|
|
|
assert (it != keys.begin()); // Shouldn't happen, was checked at beginning of this function
|
|
|
|
typename MapT::MapType::const_iterator last = --it;
|
|
mLastLowKey = last;
|
|
float aLastTime = last->first;
|
|
const typename MapT::KeyType* aLastKey = &last->second;
|
|
|
|
float a = (time - aLastTime) / (aTime - aLastTime);
|
|
|
|
return InterpolationFunc()(aLastKey->mValue, aKey->mValue, a);
|
|
}
|
|
else
|
|
return keys.rbegin()->second.mValue;
|
|
}
|
|
|
|
bool empty() const
|
|
{
|
|
return !mKeys || mKeys->mKeys.empty();
|
|
}
|
|
|
|
private:
|
|
mutable typename MapT::MapType::const_iterator mLastLowKey;
|
|
mutable typename MapT::MapType::const_iterator mLastHighKey;
|
|
|
|
boost::shared_ptr<MapT> mKeys;
|
|
|
|
typename MapT::ValueType mDefaultVal;
|
|
};
|
|
|
|
struct LerpFunc
|
|
{
|
|
template <typename ValueType>
|
|
inline ValueType operator()(const ValueType& a, const ValueType& b, float fraction)
|
|
{
|
|
return a + ((b - a) * fraction);
|
|
}
|
|
};
|
|
|
|
struct QuaternionSlerpFunc
|
|
{
|
|
inline osg::Quat operator()(const osg::Quat& a, const osg::Quat& b, float fraction)
|
|
{
|
|
osg::Quat result;
|
|
result.slerp(fraction, a, b);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
typedef ValueInterpolator<Nif::QuaternionKeyMap, QuaternionSlerpFunc> QuaternionInterpolator;
|
|
typedef ValueInterpolator<Nif::FloatKeyMap, LerpFunc> FloatInterpolator;
|
|
typedef ValueInterpolator<Nif::Vector3KeyMap, LerpFunc> Vec3Interpolator;
|
|
|
|
class ControllerFunction : public SceneUtil::ControllerFunction
|
|
{
|
|
private:
|
|
float mFrequency;
|
|
float mPhase;
|
|
float mStartTime;
|
|
float mStopTime;
|
|
enum ExtrapolationMode
|
|
{
|
|
Cycle = 0,
|
|
Reverse = 1,
|
|
Constant = 2
|
|
};
|
|
ExtrapolationMode mExtrapolationMode;
|
|
|
|
public:
|
|
ControllerFunction(const Nif::Controller *ctrl);
|
|
|
|
float calculate(float value) const;
|
|
|
|
virtual float getMaximum() const;
|
|
};
|
|
|
|
/// Must be set on an osgAnimation::MorphGeometry.
|
|
class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller
|
|
{
|
|
public:
|
|
GeomMorpherController(const Nif::NiMorphData* data);
|
|
GeomMorpherController();
|
|
GeomMorpherController(const GeomMorpherController& copy, const osg::CopyOp& copyop);
|
|
|
|
META_Object(NifOsg, GeomMorpherController)
|
|
|
|
virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable);
|
|
|
|
private:
|
|
std::vector<FloatInterpolator> mKeyFrames;
|
|
};
|
|
|
|
class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller
|
|
{
|
|
public:
|
|
KeyframeController(const Nif::NiKeyframeData *data);
|
|
KeyframeController();
|
|
KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop);
|
|
|
|
META_Object(NifOsg, KeyframeController)
|
|
|
|
virtual osg::Vec3f getTranslation(float time) const;
|
|
|
|
virtual void operator() (osg::Node*, osg::NodeVisitor*);
|
|
|
|
private:
|
|
QuaternionInterpolator mRotations;
|
|
|
|
FloatInterpolator mXRotations;
|
|
FloatInterpolator mYRotations;
|
|
FloatInterpolator mZRotations;
|
|
|
|
Vec3Interpolator mTranslations;
|
|
FloatInterpolator mScales;
|
|
|
|
osg::Quat getXYZRotation(float time) const;
|
|
};
|
|
|
|
class UVController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
|
|
{
|
|
public:
|
|
UVController();
|
|
UVController(const UVController&,const osg::CopyOp&);
|
|
UVController(const Nif::NiUVData *data, std::set<int> textureUnits);
|
|
|
|
META_Object(NifOsg,UVController)
|
|
|
|
virtual void setDefaults(osg::StateSet* stateset);
|
|
virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv);
|
|
|
|
private:
|
|
FloatInterpolator mUTrans;
|
|
FloatInterpolator mVTrans;
|
|
FloatInterpolator mUScale;
|
|
FloatInterpolator mVScale;
|
|
std::set<int> mTextureUnits;
|
|
};
|
|
|
|
class VisController : public osg::NodeCallback, public SceneUtil::Controller
|
|
{
|
|
private:
|
|
std::vector<Nif::NiVisData::VisData> mData;
|
|
|
|
bool calculate(float time) const;
|
|
|
|
public:
|
|
VisController(const Nif::NiVisData *data);
|
|
VisController();
|
|
VisController(const VisController& copy, const osg::CopyOp& copyop);
|
|
|
|
META_Object(NifOsg, VisController)
|
|
|
|
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
|
|
};
|
|
|
|
class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
|
|
{
|
|
private:
|
|
FloatInterpolator mData;
|
|
|
|
public:
|
|
AlphaController(const Nif::NiFloatData *data);
|
|
AlphaController();
|
|
AlphaController(const AlphaController& copy, const osg::CopyOp& copyop);
|
|
|
|
virtual void setDefaults(osg::StateSet* stateset);
|
|
|
|
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv);
|
|
|
|
META_Object(NifOsg, AlphaController)
|
|
};
|
|
|
|
class MaterialColorController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
|
|
{
|
|
private:
|
|
Vec3Interpolator mData;
|
|
|
|
public:
|
|
MaterialColorController(const Nif::NiPosData *data);
|
|
MaterialColorController();
|
|
MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop);
|
|
|
|
META_Object(NifOsg, MaterialColorController)
|
|
|
|
virtual void setDefaults(osg::StateSet* stateset);
|
|
|
|
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv);
|
|
};
|
|
|
|
class FlipController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller
|
|
{
|
|
private:
|
|
int mTexSlot;
|
|
float mDelta;
|
|
std::vector<osg::ref_ptr<osg::Texture2D> > mTextures;
|
|
|
|
public:
|
|
FlipController(const Nif::NiFlipController* ctrl, std::vector<osg::ref_ptr<osg::Texture2D> > textures);
|
|
FlipController(int texSlot, float delta, std::vector<osg::ref_ptr<osg::Texture2D> > textures);
|
|
FlipController();
|
|
FlipController(const FlipController& copy, const osg::CopyOp& copyop);
|
|
|
|
META_Object(NifOsg, FlipController)
|
|
|
|
virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv);
|
|
};
|
|
|
|
class ParticleSystemController : public osg::NodeCallback, public SceneUtil::Controller
|
|
{
|
|
public:
|
|
ParticleSystemController(const Nif::NiParticleSystemController* ctrl);
|
|
ParticleSystemController();
|
|
ParticleSystemController(const ParticleSystemController& copy, const osg::CopyOp& copyop);
|
|
|
|
META_Object(NifOsg, ParticleSystemController)
|
|
|
|
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
|
|
|
|
private:
|
|
float mEmitStart;
|
|
float mEmitStop;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|