mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-02 16:36:41 +00:00
Revert "reworked Nif::KeyListT into Nif::CurveT"
This reverts commit e7665582ad
.
This commit is contained in:
parent
de3c76a54b
commit
24f968623f
5 changed files with 258 additions and 483 deletions
|
@ -1,424 +0,0 @@
|
||||||
#ifndef _NIF_KEYLIST_H_
|
|
||||||
#define _NIF_KEYLIST_H_
|
|
||||||
|
|
||||||
#include <cfloat>
|
|
||||||
|
|
||||||
namespace Nif
|
|
||||||
{
|
|
||||||
|
|
||||||
template <typename iterator , typename predicate>
|
|
||||||
void bubble_sort (iterator begin, iterator end, predicate const & in_order)
|
|
||||||
{
|
|
||||||
if (end > begin)
|
|
||||||
{
|
|
||||||
for (iterator i = begin; i != end - 1; ++i)
|
|
||||||
{
|
|
||||||
if (in_order (*(i+0), *(i+1)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (iterator j = i; j >= begin; --j)
|
|
||||||
{
|
|
||||||
std::swap (*(j+0), *(j+1));
|
|
||||||
|
|
||||||
if (in_order (*(j+0), *(j+1)))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename value_type>
|
|
||||||
value_type linear_interpolate (float amount, value_type prev, value_type next)
|
|
||||||
{
|
|
||||||
return prev + (next - prev) * amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
Ogre::Quaternion linear_interpolate (float amount, Ogre::Quaternion prev, Ogre::Quaternion next)
|
|
||||||
{
|
|
||||||
return Ogre::Quaternion::nlerp (amount, prev, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename value_type>
|
|
||||||
struct KeyT {
|
|
||||||
|
|
||||||
static const size_t EncodedLength =
|
|
||||||
NIFStream::handler <float>::EncodedLength +
|
|
||||||
NIFStream::handler <value_type>::EncodedLength
|
|
||||||
;
|
|
||||||
|
|
||||||
float mTime;
|
|
||||||
value_type mValue;
|
|
||||||
|
|
||||||
void extract (NIFStream &nif)
|
|
||||||
{
|
|
||||||
nif.uncheckedRead (mTime);
|
|
||||||
nif.uncheckedRead (mValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool in_order (KeyT <value_type> const & l, KeyT <value_type> const & r)
|
|
||||||
{
|
|
||||||
return l.mTime < r.mTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename derived_type>
|
|
||||||
struct NIFStream_handler
|
|
||||||
{
|
|
||||||
static const bool FixedLength = true;
|
|
||||||
static const size_t EncodedLength = derived_type::EncodedLength;
|
|
||||||
static const bool FileCompatibleLayout = true;
|
|
||||||
|
|
||||||
static void extract (NIFStream& Stream, KeyT <value_type> & Value)
|
|
||||||
{
|
|
||||||
static_cast <derived_type &> (Value).extract (Stream);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct LinearKeyT : KeyT <T>
|
|
||||||
{
|
|
||||||
static T interpolate (LinearKeyT <T> * prev, LinearKeyT <T> * next, float amount)
|
|
||||||
{
|
|
||||||
return linear_interpolate (amount, prev->mValue, next->mValue);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct QuadraticKeyT : KeyT <T>
|
|
||||||
{
|
|
||||||
static const size_t EncodedLength =
|
|
||||||
KeyT <T>::EncodedLength +
|
|
||||||
NIFStream::handler <T>::EncodedLength * 2
|
|
||||||
;
|
|
||||||
|
|
||||||
T mForwardValue;
|
|
||||||
T mBackwardValue;
|
|
||||||
|
|
||||||
static T interpolate (QuadraticKeyT <T> * prev, QuadraticKeyT <T> * next, float amount)
|
|
||||||
{
|
|
||||||
return linear_interpolate (amount, prev->mValue, next->mValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void extract (NIFStream &nif)
|
|
||||||
{
|
|
||||||
KeyT<T>::extract (nif);
|
|
||||||
|
|
||||||
nif.uncheckedRead (mForwardValue);
|
|
||||||
nif.uncheckedRead (mBackwardValue);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct TbcKeyT : KeyT <T>
|
|
||||||
{
|
|
||||||
static const size_t EncodedLength =
|
|
||||||
KeyT <T>::EncodedLength +
|
|
||||||
NIFStream::handler <float>::EncodedLength * 3
|
|
||||||
;
|
|
||||||
|
|
||||||
float mTension;
|
|
||||||
float mBias;
|
|
||||||
float mContinuity;
|
|
||||||
|
|
||||||
static T interpolate (TbcKeyT <T> * prev, TbcKeyT <T> * next, float amount)
|
|
||||||
{
|
|
||||||
return linear_interpolate (amount, prev->mValue, next->mValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void extract (NIFStream &nif)
|
|
||||||
{
|
|
||||||
KeyT<T>::extract (nif);
|
|
||||||
|
|
||||||
nif.uncheckedRead (mTension);
|
|
||||||
nif.uncheckedRead (mBias);
|
|
||||||
nif.uncheckedRead (mContinuity);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// register NIFStream extraction handlers for KeyT derivatives
|
|
||||||
template <typename T> struct NIFStream::handler < LinearKeyT <T> > : KeyT <T>::template NIFStream_handler < LinearKeyT <T> > {};
|
|
||||||
template <typename T> struct NIFStream::handler < QuadraticKeyT <T> > : KeyT <T>::template NIFStream_handler < QuadraticKeyT <T> > {};
|
|
||||||
template <typename T> struct NIFStream::handler < TbcKeyT <T> > : KeyT <T>::template NIFStream_handler < TbcKeyT <T> > {};
|
|
||||||
|
|
||||||
struct Curve
|
|
||||||
{
|
|
||||||
static const int sLinearInterpolation = 1;
|
|
||||||
static const int sQuadraticInterpolation = 2;
|
|
||||||
static const int sTBCInterpolation = 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename value_type>
|
|
||||||
struct CurveT : Curve {
|
|
||||||
|
|
||||||
typedef KeyT <value_type> BaseKey;
|
|
||||||
typedef TbcKeyT <value_type> TcbKey;
|
|
||||||
typedef LinearKeyT <value_type> LinearKey;
|
|
||||||
typedef QuadraticKeyT <value_type> QuadraticKey;
|
|
||||||
|
|
||||||
union keys {
|
|
||||||
LinearKey* Linear;
|
|
||||||
QuadraticKey* Quadratic;
|
|
||||||
TcbKey* Tcb;
|
|
||||||
};
|
|
||||||
|
|
||||||
class interpolator;
|
|
||||||
|
|
||||||
int mInterpolationType;
|
|
||||||
size_t mSize;
|
|
||||||
keys mKeys;
|
|
||||||
|
|
||||||
value_type sample (float time) const;
|
|
||||||
|
|
||||||
KeyT <value_type> const * const & keyAtIndex (size_t Index) const
|
|
||||||
{
|
|
||||||
switch (mInterpolationType)
|
|
||||||
{
|
|
||||||
case sLinearInterpolation: return mKeys.Linear + Index;
|
|
||||||
case sQuadraticInterpolation: return mKeys.Quadratic + Index;
|
|
||||||
case sTBCInterpolation: return mKeys.Tcb + Index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void read(NIFStream *nif, bool force=false)
|
|
||||||
{
|
|
||||||
size_t count = nif->getInt();
|
|
||||||
|
|
||||||
mSize = 0;
|
|
||||||
|
|
||||||
if(count > 0 || force)
|
|
||||||
{
|
|
||||||
mInterpolationType = nif->getInt();
|
|
||||||
|
|
||||||
assert (mInterpolationType >= sLinearInterpolation && mInterpolationType <= sTBCInterpolation);
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
if(mInterpolationType == sLinearInterpolation)
|
|
||||||
read_keys (nif, mKeys.Linear, count);
|
|
||||||
else if(mInterpolationType == sQuadraticInterpolation)
|
|
||||||
read_keys (nif, mKeys.Quadratic, count);
|
|
||||||
else if(mInterpolationType == sTBCInterpolation)
|
|
||||||
read_keys (nif, mKeys.Tcb, count);
|
|
||||||
else
|
|
||||||
nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mInterpolationType = sLinearInterpolation;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurveT () { init (); }
|
|
||||||
CurveT (CurveT <value_type> const & k) { init (k); }
|
|
||||||
//CurveT (CurveT <value_type> && k) { init (); swap (std::move (k)); }
|
|
||||||
~CurveT () { dest (); }
|
|
||||||
|
|
||||||
operator bool () const { return mSize > 0; }
|
|
||||||
|
|
||||||
//void operator = (CurveT<value_type> && k) { swap(k); }
|
|
||||||
void operator = (CurveT<value_type> const & k) { dest (); init (k); }
|
|
||||||
|
|
||||||
void swap (CurveT<value_type> & k)
|
|
||||||
{
|
|
||||||
std::swap (mSize, k.mSize);
|
|
||||||
std::swap (mInterpolationType, k.mInterpolationType);
|
|
||||||
std::swap (mKeys, k.mKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void init ()
|
|
||||||
{
|
|
||||||
mSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init (CurveT<value_type> const & k)
|
|
||||||
{
|
|
||||||
mInterpolationType = k.mInterpolationType;
|
|
||||||
switch (mInterpolationType)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case sLinearInterpolation:
|
|
||||||
mKeys.Linear = new LinearKey [k.mSize];
|
|
||||||
memcpy (mKeys.Linear, k.mKeys.Linear, sizeof (LinearKey) * k.mSize);
|
|
||||||
mSize = k.mSize;
|
|
||||||
break;
|
|
||||||
case sQuadraticInterpolation:
|
|
||||||
mKeys.Quadratic = new QuadraticKey [k.mSize];
|
|
||||||
memcpy (mKeys.Quadratic, k.mKeys.Quadratic, sizeof (QuadraticKey) * k.mSize);
|
|
||||||
mSize = k.mSize;
|
|
||||||
break;
|
|
||||||
case sTBCInterpolation:
|
|
||||||
mKeys.Tcb = new TcbKey [k.mSize];
|
|
||||||
memcpy (mKeys.Tcb, k.mKeys.Tcb, sizeof (TcbKey) * k.mSize);
|
|
||||||
mSize = k.mSize;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dest ()
|
|
||||||
{
|
|
||||||
if (mSize > 0)
|
|
||||||
{
|
|
||||||
switch (mInterpolationType)
|
|
||||||
{
|
|
||||||
case sLinearInterpolation: delete mKeys.Linear; break;
|
|
||||||
case sQuadraticInterpolation: delete mKeys.Quadratic; break;
|
|
||||||
case sTBCInterpolation: delete mKeys.Tcb; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void read_keys (NIFStream *nif, T * & store, size_t count)
|
|
||||||
{
|
|
||||||
store = new T [count];
|
|
||||||
|
|
||||||
mSize = count;
|
|
||||||
|
|
||||||
nif->getArray (store, count);
|
|
||||||
|
|
||||||
//NOTE: Is this really necessary? It seems reasonable to assume that
|
|
||||||
// animation data is already sorted by time...
|
|
||||||
// verified no out of order frames in GOTY edition
|
|
||||||
bubble_sort (store, store+count, T::in_order);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename value_type>
|
|
||||||
class CurveT<value_type>::interpolator
|
|
||||||
{
|
|
||||||
template <typename key_type>
|
|
||||||
struct impl
|
|
||||||
{
|
|
||||||
key_type *Cur, *End;
|
|
||||||
|
|
||||||
void init (key_type * Beg, size_t Len)
|
|
||||||
{
|
|
||||||
if (Len > 0)
|
|
||||||
{
|
|
||||||
Cur = Beg;
|
|
||||||
End = Beg + Len - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cur = End = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasData () const
|
|
||||||
{
|
|
||||||
return Cur && Cur <= End;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type valueAt (float time)
|
|
||||||
{
|
|
||||||
while ((Cur < End) && (time >= Cur [1].mTime))
|
|
||||||
++Cur;
|
|
||||||
|
|
||||||
if (Cur < End)
|
|
||||||
{
|
|
||||||
if (time > Cur->mTime)
|
|
||||||
{
|
|
||||||
key_type * Nxt = Cur + 1;
|
|
||||||
|
|
||||||
float offset = time - Cur->mTime;
|
|
||||||
float length = Nxt->mTime - Cur->mTime;
|
|
||||||
|
|
||||||
return key_type::interpolate (Cur, Nxt, offset / length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return Cur->mValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return End->mValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float curTime () const
|
|
||||||
{
|
|
||||||
return (Cur != NULL) ? Cur->Time : FLT_MIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
float nextTime () const
|
|
||||||
{
|
|
||||||
return Cur < End ? (Cur + 1)->mTime : FLT_MAX;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
int mInterpolationType;
|
|
||||||
union {
|
|
||||||
impl <LinearKey> Linear;
|
|
||||||
impl <QuadraticKey> Quadratic;
|
|
||||||
impl <TcbKey> Tcb;
|
|
||||||
};
|
|
||||||
|
|
||||||
interpolator (CurveT <value_type> const & Curve)
|
|
||||||
{
|
|
||||||
mInterpolationType = Curve.mInterpolationType;
|
|
||||||
|
|
||||||
switch (mInterpolationType)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case Curve::sLinearInterpolation: Linear .init (Curve.mKeys.Linear, Curve.mSize); break;
|
|
||||||
case Curve::sQuadraticInterpolation: Quadratic.init (Curve.mKeys.Quadratic, Curve.mSize); break;
|
|
||||||
case Curve::sTBCInterpolation: Tcb .init (Curve.mKeys.Tcb, Curve.mSize); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if there is any value(s) in this curve
|
|
||||||
float hasData () const
|
|
||||||
{
|
|
||||||
switch (mInterpolationType)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case Curve::sLinearInterpolation: return Linear .hasData ();
|
|
||||||
case Curve::sQuadraticInterpolation: return Quadratic.hasData ();
|
|
||||||
case Curve::sTBCInterpolation: return Tcb .hasData ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the timestamp of the next key-frame, or FLT_MAX if
|
|
||||||
// there are no more key-frames, valid if hasData returns false
|
|
||||||
float nextTime () const
|
|
||||||
{
|
|
||||||
switch (mInterpolationType)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case Curve::sLinearInterpolation: return Linear .nextTime ();
|
|
||||||
case Curve::sQuadraticInterpolation: return Quadratic.nextTime ();
|
|
||||||
case Curve::sTBCInterpolation: return Tcb .nextTime ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the value of the curve at the specified time
|
|
||||||
// the passed in time should never exceed the result of
|
|
||||||
// nextTime, not valid if hasData returns false
|
|
||||||
value_type valueAt (float time)
|
|
||||||
{
|
|
||||||
switch (mInterpolationType)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case Curve::sLinearInterpolation: return Linear .valueAt (time);
|
|
||||||
case Curve::sQuadraticInterpolation: return Quadratic.valueAt (time);
|
|
||||||
case Curve::sTBCInterpolation: return Tcb .valueAt (time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename value_type>
|
|
||||||
value_type CurveT<value_type>::sample (float time) const
|
|
||||||
{
|
|
||||||
interpolator i (*this);
|
|
||||||
return i.valueAt (time);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef CurveT<float> FloatCurve;
|
|
||||||
typedef CurveT<Ogre::Vector3> Vector3Curve;
|
|
||||||
typedef CurveT<Ogre::Vector4> Vector4Curve;
|
|
||||||
typedef CurveT<Ogre::Quaternion> QuaternionCurve;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -25,7 +25,6 @@
|
||||||
#define OPENMW_COMPONENTS_NIF_DATA_HPP
|
#define OPENMW_COMPONENTS_NIF_DATA_HPP
|
||||||
|
|
||||||
#include "controlled.hpp"
|
#include "controlled.hpp"
|
||||||
#include "curve.hpp"
|
|
||||||
|
|
||||||
#include <OgreQuaternion.h>
|
#include <OgreQuaternion.h>
|
||||||
#include <OgreVector3.h>
|
#include <OgreVector3.h>
|
||||||
|
@ -212,7 +211,7 @@ public:
|
||||||
class NiPosData : public Record
|
class NiPosData : public Record
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Vector3Curve mKeyList;
|
Vector3KeyList mKeyList;
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +222,7 @@ public:
|
||||||
class NiUVData : public Record
|
class NiUVData : public Record
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FloatCurve mKeyList[4];
|
FloatKeyList mKeyList[4];
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
@ -235,7 +234,7 @@ public:
|
||||||
class NiFloatData : public Record
|
class NiFloatData : public Record
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FloatCurve mKeyList;
|
FloatKeyList mKeyList;
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
@ -285,7 +284,7 @@ public:
|
||||||
class NiColorData : public Record
|
class NiColorData : public Record
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Vector4Curve mKeyList;
|
Vector4KeyList mKeyList;
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
@ -390,7 +389,7 @@ public:
|
||||||
struct NiMorphData : public Record
|
struct NiMorphData : public Record
|
||||||
{
|
{
|
||||||
struct MorphData {
|
struct MorphData {
|
||||||
FloatCurve mData;
|
FloatKeyList mData;
|
||||||
std::vector<Ogre::Vector3> mVertices;
|
std::vector<Ogre::Vector3> mVertices;
|
||||||
};
|
};
|
||||||
std::vector<MorphData> mMorphs;
|
std::vector<MorphData> mMorphs;
|
||||||
|
@ -413,9 +412,9 @@ struct NiMorphData : public Record
|
||||||
|
|
||||||
struct NiKeyframeData : public Record
|
struct NiKeyframeData : public Record
|
||||||
{
|
{
|
||||||
QuaternionCurve mRotations;
|
QuaternionKeyList mRotations;
|
||||||
Vector3Curve mTranslations;
|
Vector3KeyList mTranslations;
|
||||||
FloatCurve mScales;
|
FloatKeyList mScales;
|
||||||
|
|
||||||
void read(NIFStream *nif)
|
void read(NIFStream *nif)
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,5 +132,81 @@ public:
|
||||||
size_t numRoots() { return roots.size(); }
|
size_t numRoots() { return roots.size(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct KeyT {
|
||||||
|
float mTime;
|
||||||
|
T mValue;
|
||||||
|
T mForwardValue; // Only for Quadratic interpolation
|
||||||
|
T mBackwardValue; // Only for Quadratic interpolation
|
||||||
|
float mTension; // Only for TBC interpolation
|
||||||
|
float mBias; // Only for TBC interpolation
|
||||||
|
float mContinuity; // Only for TBC interpolation
|
||||||
|
};
|
||||||
|
typedef KeyT<float> FloatKey;
|
||||||
|
typedef KeyT<Ogre::Vector3> Vector3Key;
|
||||||
|
typedef KeyT<Ogre::Vector4> Vector4Key;
|
||||||
|
typedef KeyT<Ogre::Quaternion> QuaternionKey;
|
||||||
|
|
||||||
|
template<typename T, T (NIFStream::*getValue)()>
|
||||||
|
struct KeyListT {
|
||||||
|
typedef std::vector< KeyT<T> > VecType;
|
||||||
|
|
||||||
|
static const int sLinearInterpolation = 1;
|
||||||
|
static const int sQuadraticInterpolation = 2;
|
||||||
|
static const int sTBCInterpolation = 3;
|
||||||
|
|
||||||
|
int mInterpolationType;
|
||||||
|
VecType mKeys;
|
||||||
|
|
||||||
|
void read(NIFStream *nif, bool force=false)
|
||||||
|
{
|
||||||
|
size_t count = nif->getInt();
|
||||||
|
if(count == 0 && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mInterpolationType = nif->getInt();
|
||||||
|
mKeys.resize(count);
|
||||||
|
if(mInterpolationType == sLinearInterpolation)
|
||||||
|
{
|
||||||
|
for(size_t i = 0;i < count;i++)
|
||||||
|
{
|
||||||
|
KeyT<T> &key = mKeys[i];
|
||||||
|
key.mTime = nif->getFloat();
|
||||||
|
key.mValue = (nif->*getValue)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(mInterpolationType == sQuadraticInterpolation)
|
||||||
|
{
|
||||||
|
for(size_t i = 0;i < count;i++)
|
||||||
|
{
|
||||||
|
KeyT<T> &key = mKeys[i];
|
||||||
|
key.mTime = nif->getFloat();
|
||||||
|
key.mValue = (nif->*getValue)();
|
||||||
|
key.mForwardValue = (nif->*getValue)();
|
||||||
|
key.mBackwardValue = (nif->*getValue)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(mInterpolationType == sTBCInterpolation)
|
||||||
|
{
|
||||||
|
for(size_t i = 0;i < count;i++)
|
||||||
|
{
|
||||||
|
KeyT<T> &key = mKeys[i];
|
||||||
|
key.mTime = nif->getFloat();
|
||||||
|
key.mValue = (nif->*getValue)();
|
||||||
|
key.mTension = nif->getFloat();
|
||||||
|
key.mBias = nif->getFloat();
|
||||||
|
key.mContinuity = nif->getFloat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef KeyListT<float,&NIFStream::getFloat> FloatKeyList;
|
||||||
|
typedef KeyListT<Ogre::Vector3,&NIFStream::getVector3> Vector3KeyList;
|
||||||
|
typedef KeyListT<Ogre::Vector4,&NIFStream::getVector4> Vector4KeyList;
|
||||||
|
typedef KeyListT<Ogre::Quaternion,&NIFStream::getQuaternion> QuaternionKeyList;
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -166,9 +166,9 @@ public:
|
||||||
class Value : public NodeTargetValue<Ogre::Real>
|
class Value : public NodeTargetValue<Ogre::Real>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Nif::QuaternionCurve mRotations;
|
Nif::QuaternionKeyList mRotations;
|
||||||
Nif::Vector3Curve mTranslations;
|
Nif::Vector3KeyList mTranslations;
|
||||||
Nif::FloatCurve mScales;
|
Nif::FloatKeyList mScales;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value(Ogre::Node *target, const Nif::NiKeyframeData *data)
|
Value(Ogre::Node *target, const Nif::NiKeyframeData *data)
|
||||||
|
@ -186,16 +186,68 @@ public:
|
||||||
|
|
||||||
virtual void setValue(Ogre::Real time)
|
virtual void setValue(Ogre::Real time)
|
||||||
{
|
{
|
||||||
if(mRotations)
|
if(mRotations.mKeys.size() > 0)
|
||||||
mNode->setOrientation(mRotations.sample (time));
|
|
||||||
|
|
||||||
if(mTranslations)
|
|
||||||
mNode->setPosition(mTranslations.sample (time));
|
|
||||||
|
|
||||||
if(mScales)
|
|
||||||
{
|
{
|
||||||
float s = mScales.sample (time);
|
if(time <= mRotations.mKeys.front().mTime)
|
||||||
mNode->setScale(s, s, s);
|
mNode->setOrientation(mRotations.mKeys.front().mValue);
|
||||||
|
else if(time >= mRotations.mKeys.back().mTime)
|
||||||
|
mNode->setOrientation(mRotations.mKeys.back().mValue);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1);
|
||||||
|
for(;iter != mRotations.mKeys.end();iter++)
|
||||||
|
{
|
||||||
|
if(iter->mTime < time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Nif::QuaternionKeyList::VecType::const_iterator last(iter-1);
|
||||||
|
float a = (time-last->mTime) / (iter->mTime-last->mTime);
|
||||||
|
mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mTranslations.mKeys.size() > 0)
|
||||||
|
{
|
||||||
|
if(time <= mTranslations.mKeys.front().mTime)
|
||||||
|
mNode->setPosition(mTranslations.mKeys.front().mValue);
|
||||||
|
else if(time >= mTranslations.mKeys.back().mTime)
|
||||||
|
mNode->setPosition(mTranslations.mKeys.back().mValue);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1);
|
||||||
|
for(;iter != mTranslations.mKeys.end();iter++)
|
||||||
|
{
|
||||||
|
if(iter->mTime < time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Nif::Vector3KeyList::VecType::const_iterator last(iter-1);
|
||||||
|
float a = (time-last->mTime) / (iter->mTime-last->mTime);
|
||||||
|
mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mScales.mKeys.size() > 0)
|
||||||
|
{
|
||||||
|
if(time <= mScales.mKeys.front().mTime)
|
||||||
|
mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue));
|
||||||
|
else if(time >= mScales.mKeys.back().mTime)
|
||||||
|
mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1);
|
||||||
|
for(;iter != mScales.mKeys.end();iter++)
|
||||||
|
{
|
||||||
|
if(iter->mTime < time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator last(iter-1);
|
||||||
|
float a = (time-last->mTime) / (iter->mTime-last->mTime);
|
||||||
|
mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -210,14 +262,30 @@ public:
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Ogre::MaterialPtr mMaterial;
|
Ogre::MaterialPtr mMaterial;
|
||||||
Nif::FloatCurve mUTrans;
|
Nif::FloatKeyList mUTrans;
|
||||||
Nif::FloatCurve mVTrans;
|
Nif::FloatKeyList mVTrans;
|
||||||
Nif::FloatCurve mUScale;
|
Nif::FloatKeyList mUScale;
|
||||||
Nif::FloatCurve mVScale;
|
Nif::FloatKeyList mVScale;
|
||||||
|
|
||||||
static float lookupValue(const Nif::FloatCurve &keys, float time, float def)
|
static float lookupValue(const Nif::FloatKeyList &keys, float time, float def)
|
||||||
{
|
{
|
||||||
return keys ? keys.sample (time) : def;
|
if(keys.mKeys.size() == 0)
|
||||||
|
return def;
|
||||||
|
|
||||||
|
if(time <= keys.mKeys.front().mTime)
|
||||||
|
return keys.mKeys.front().mValue;
|
||||||
|
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1);
|
||||||
|
for(;iter != keys.mKeys.end();iter++)
|
||||||
|
{
|
||||||
|
if(iter->mTime < time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator last(iter-1);
|
||||||
|
float a = (time-last->mTime) / (iter->mTime-last->mTime);
|
||||||
|
return last->mValue + ((iter->mValue - last->mValue)*a);
|
||||||
|
}
|
||||||
|
return keys.mKeys.back().mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -324,19 +392,18 @@ class NIFObjectLoader
|
||||||
const Nif::NiColorData *clrdata = cl->data.getPtr();
|
const Nif::NiColorData *clrdata = cl->data.getPtr();
|
||||||
|
|
||||||
Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator");
|
Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator");
|
||||||
size_t num_colors = std::min<size_t>(6, clrdata->mKeyList.mSize);
|
size_t num_colors = std::min<size_t>(6, clrdata->mKeyList.mKeys.size());
|
||||||
for(size_t i = 0;i < num_colors;i++)
|
for(size_t i = 0;i < num_colors;i++)
|
||||||
{
|
{
|
||||||
Nif::Vector4Curve::BaseKey const * Key = clrdata->mKeyList.keyAtIndex (i);
|
|
||||||
Ogre::ColourValue color;
|
Ogre::ColourValue color;
|
||||||
color.r = Key->mValue[0];
|
color.r = clrdata->mKeyList.mKeys[i].mValue[0];
|
||||||
color.g = Key->mValue[1];
|
color.g = clrdata->mKeyList.mKeys[i].mValue[1];
|
||||||
color.b = Key->mValue[2];
|
color.b = clrdata->mKeyList.mKeys[i].mValue[2];
|
||||||
color.a = Key->mValue[3];
|
color.a = clrdata->mKeyList.mKeys[i].mValue[3];
|
||||||
affector->setParameter("colour"+Ogre::StringConverter::toString(i),
|
affector->setParameter("colour"+Ogre::StringConverter::toString(i),
|
||||||
Ogre::StringConverter::toString(color));
|
Ogre::StringConverter::toString(color));
|
||||||
affector->setParameter("time"+Ogre::StringConverter::toString(i),
|
affector->setParameter("time"+Ogre::StringConverter::toString(i),
|
||||||
Ogre::StringConverter::toString(Key->mTime));
|
Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(e->recType == Nif::RC_NiParticleRotation)
|
else if(e->recType == Nif::RC_NiParticleRotation)
|
||||||
|
|
|
@ -10,11 +10,6 @@
|
||||||
|
|
||||||
namespace NifOgre
|
namespace NifOgre
|
||||||
{
|
{
|
||||||
template <typename value_type>
|
|
||||||
static value_type min (value_type V0, value_type V1, value_type V2, value_type V3)
|
|
||||||
{
|
|
||||||
return std::min (std::min (V0, V1), std::min (V2, V3));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector<const Nif::NiKeyframeController*> &ctrls, const std::vector<std::string> &targets, float startTime, float stopTime)
|
void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector<const Nif::NiKeyframeController*> &ctrls, const std::vector<std::string> &targets, float startTime, float stopTime)
|
||||||
{
|
{
|
||||||
|
@ -27,6 +22,15 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &
|
||||||
continue;
|
continue;
|
||||||
const Nif::NiKeyframeData *kf = kfc->data.getPtr();
|
const Nif::NiKeyframeData *kf = kfc->data.getPtr();
|
||||||
|
|
||||||
|
/* Get the keyframes and make sure they're sorted first to last */
|
||||||
|
const Nif::QuaternionKeyList &quatkeys = kf->mRotations;
|
||||||
|
const Nif::Vector3KeyList &trankeys = kf->mTranslations;
|
||||||
|
const Nif::FloatKeyList &scalekeys = kf->mScales;
|
||||||
|
|
||||||
|
Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin();
|
||||||
|
Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin();
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin();
|
||||||
|
|
||||||
Ogre::Bone *bone = skel->getBone(targets[i]);
|
Ogre::Bone *bone = skel->getBone(targets[i]);
|
||||||
// NOTE: For some reason, Ogre doesn't like the node track ID being different from
|
// NOTE: For some reason, Ogre doesn't like the node track ID being different from
|
||||||
// the bone ID
|
// the bone ID
|
||||||
|
@ -34,30 +38,83 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &
|
||||||
anim->getNodeTrack(bone->getHandle()) :
|
anim->getNodeTrack(bone->getHandle()) :
|
||||||
anim->createNodeTrack(bone->getHandle(), bone);
|
anim->createNodeTrack(bone->getHandle(), bone);
|
||||||
|
|
||||||
Nif::QuaternionCurve::interpolator rci (kf->mRotations);
|
Ogre::Quaternion lastquat, curquat;
|
||||||
Nif::Vector3Curve::interpolator tci (kf->mTranslations);
|
Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f);
|
||||||
Nif::FloatCurve::interpolator sci (kf->mScales);
|
Ogre::Vector3 lastscale(1.0f), curscale(1.0f);
|
||||||
|
if(quatiter != quatkeys.mKeys.end())
|
||||||
|
lastquat = curquat = quatiter->mValue;
|
||||||
|
if(traniter != trankeys.mKeys.end())
|
||||||
|
lasttrans = curtrans = traniter->mValue;
|
||||||
|
if(scaleiter != scalekeys.mKeys.end())
|
||||||
|
lastscale = curscale = Ogre::Vector3(scaleiter->mValue);
|
||||||
|
|
||||||
float next_timestamp = startTime;
|
bool didlast = false;
|
||||||
|
while(!didlast)
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
static const Ogre::Vector3 one (1,1,1);
|
float curtime = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
|
//Get latest time
|
||||||
|
if(quatiter != quatkeys.mKeys.end())
|
||||||
|
curtime = std::min(curtime, quatiter->mTime);
|
||||||
|
if(traniter != trankeys.mKeys.end())
|
||||||
|
curtime = std::min(curtime, traniter->mTime);
|
||||||
|
if(scaleiter != scalekeys.mKeys.end())
|
||||||
|
curtime = std::min(curtime, scaleiter->mTime);
|
||||||
|
|
||||||
|
curtime = std::max(curtime, startTime);
|
||||||
|
if(curtime >= stopTime)
|
||||||
|
{
|
||||||
|
didlast = true;
|
||||||
|
curtime = stopTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the latest quaternions, translations, and scales for the
|
||||||
|
// current time
|
||||||
|
while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime)
|
||||||
|
{
|
||||||
|
lastquat = curquat;
|
||||||
|
if(++quatiter != quatkeys.mKeys.end())
|
||||||
|
curquat = quatiter->mValue;
|
||||||
|
}
|
||||||
|
while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime)
|
||||||
|
{
|
||||||
|
lasttrans = curtrans;
|
||||||
|
if(++traniter != trankeys.mKeys.end())
|
||||||
|
curtrans = traniter->mValue;
|
||||||
|
}
|
||||||
|
while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime)
|
||||||
|
{
|
||||||
|
lastscale = curscale;
|
||||||
|
if(++scaleiter != scalekeys.mKeys.end())
|
||||||
|
curscale = Ogre::Vector3(scaleiter->mValue);
|
||||||
|
}
|
||||||
|
|
||||||
Ogre::TransformKeyFrame *kframe;
|
Ogre::TransformKeyFrame *kframe;
|
||||||
kframe = nodetrack->createNodeKeyFrame (next_timestamp);
|
kframe = nodetrack->createNodeKeyFrame(curtime);
|
||||||
|
if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin())
|
||||||
if (rci.hasData ()) kframe->setRotation (rci.valueAt (next_timestamp));
|
kframe->setRotation(curquat);
|
||||||
if (tci.hasData ()) kframe->setTranslate (tci.valueAt (next_timestamp));
|
else
|
||||||
if (sci.hasData ()) kframe->setScale (sci.valueAt (next_timestamp)*one);
|
{
|
||||||
|
Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1;
|
||||||
if (next_timestamp >= stopTime)
|
float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime);
|
||||||
break;
|
kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat));
|
||||||
|
}
|
||||||
next_timestamp = min (stopTime,
|
if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin())
|
||||||
rci.nextTime (),
|
kframe->setTranslate(curtrans);
|
||||||
tci.nextTime (),
|
else
|
||||||
sci.nextTime ());
|
{
|
||||||
|
Nif::Vector3KeyList::VecType::const_iterator last = traniter-1;
|
||||||
|
float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime);
|
||||||
|
kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff));
|
||||||
|
}
|
||||||
|
if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin())
|
||||||
|
kframe->setScale(curscale);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1;
|
||||||
|
float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime);
|
||||||
|
kframe->setScale(lastscale + ((curscale-lastscale)*diff));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
anim->optimise();
|
anim->optimise();
|
||||||
|
|
Loading…
Reference in a new issue