123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #ifndef CRYINCLUDE_CRYCOMMON_ISPLINES_H
- #define CRYINCLUDE_CRYCOMMON_ISPLINES_H
- #pragma once
- #include <IXml.h>
- #include <AzCore/std/containers/vector.h>
- //////////////////////////////////////////////////////////////////////////
- namespace AZ
- {
- class ReflectContext;
- }
- // These flags are mostly applicable for hermit based splines.
- enum ESplineKeyTangentType
- {
- SPLINE_KEY_TANGENT_NONE = 0,
- SPLINE_KEY_TANGENT_CUSTOM = 1,
- SPLINE_KEY_TANGENT_ZERO = 2,
- SPLINE_KEY_TANGENT_STEP = 3,
- SPLINE_KEY_TANGENT_LINEAR = 4,
- SPLINE_KEY_TANGENT_BEZIER = 5
- };
- #define SPLINE_KEY_TANGENT_IN_SHIFT (0)
- #define SPLINE_KEY_TANGENT_IN_MASK (0x07) // 0000111
- #define SPLINE_KEY_TANGENT_OUT_SHIFT (3)
- #define SPLINE_KEY_TANGENT_OUT_MASK (0x07 << (SPLINE_KEY_TANGENT_OUT_SHIFT)) // 0111000
- #define SPLINE_KEY_TANGENT_UNIFY_SHIFT (6)
- #define SPLINE_KEY_TANGENT_UNIFY_MASK (0x01 << (SPLINE_KEY_TANGENT_UNIFY_SHIFT)) // 1000000
- #define SPLINE_KEY_TANGENT_ALL_MASK (SPLINE_KEY_TANGENT_IN_MASK | SPLINE_KEY_TANGENT_OUT_MASK | SPLINE_KEY_TANGENT_UNIFY_MASK)
- #define SPLINE_KEY_TANGENT_UNIFIED ((SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_IN_SHIFT) \
- | (SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_OUT_SHIFT) \
- | (0x01 << SPLINE_KEY_TANGENT_UNIFY_SHIFT))
- #define SPLINE_KEY_TANGENT_BROKEN ((SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_IN_SHIFT) \
- | (SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_OUT_SHIFT) \
- | (0x00 << SPLINE_KEY_TANGENT_UNIFY_SHIFT))
- enum ESplineKeyFlags
- {
- ESPLINE_KEY_UI_SELECTED_SHIFT = 16,
- ESPLINE_KEY_UI_SELECTED_MAX_DIMENSION_COUNT = 4, // should be power of 2 (see ESPLINE_KEY_UI_SELECTED_MASK)
- ESPLINE_KEY_UI_SELECTED_MASK = ((1 << ESPLINE_KEY_UI_SELECTED_MAX_DIMENSION_COUNT) - 1) << ESPLINE_KEY_UI_SELECTED_SHIFT
- };
- // Return value closest to 0 if same sign, or 0 if opposite.
- template<class T>
- inline T minmag(T const& a, T const& b)
- {
- if (a * b <= T(0.f))
- {
- return T(0.f);
- }
- else if (a < T(0.f))
- {
- return max(a, b);
- }
- else
- {
- return min(a, b);
- }
- }
- template<class T>
- inline Vec3_tpl<T> minmag(Vec3_tpl<T> const& a, Vec3_tpl<T> const& b)
- {
- return Vec3_tpl<T>(minmag(a.x, b.x), minmag(a.y, b.y), minmag(a.z, b.z));
- }
- template<class T>
- T abs(Vec3_tpl<T> v)
- {
- return v.GetLength();
- }
- //////////////////////////////////////////////////////////////////////////
- // Interface returned by backup methods of ISplineInterpolator.
- //////////////////////////////////////////////////////////////////////////
- struct ISplineBackup
- {
- // <interfuscator:shuffle>
- virtual ~ISplineBackup(){}
- virtual void AddRef() = 0;
- virtual void Release() = 0;
- // </interfuscator:shuffle>
- };
- //////////////////////////////////////////////////////////////////////////
- // General Interpolation interface.
- //////////////////////////////////////////////////////////////////////////
- struct ISplineInterpolator
- {
- typedef float ElemType;
- typedef ElemType ValueType[4];
- // <interfuscator:shuffle>
- virtual ~ISplineInterpolator(){}
- // Dimension of the spline from 0 to 3, number of parameters used in ValueType.
- virtual int GetNumDimensions() = 0;
- // Insert`s a new key, returns index of the key.
- virtual int InsertKey(float time, ValueType value) = 0;
- virtual void RemoveKey(int key) = 0;
- virtual void FindKeysInRange(float startTime, float endTime, int& firstFoundKey, int& numFoundKeys) = 0;
- virtual void RemoveKeysInRange(float startTime, float endTime) = 0;
- virtual int GetKeyCount() = 0;
- virtual void SetKeyTime(int key, float time) = 0;
- virtual float GetKeyTime(int key) = 0;
- virtual void SetKeyValue(int key, ValueType value) = 0;
- virtual bool GetKeyValue(int key, ValueType& value) = 0;
- virtual void SetKeyInTangent(int key, ValueType tin) = 0;
- virtual void SetKeyOutTangent(int key, ValueType tout) = 0;
- virtual void SetKeyTangents(int key, ValueType tin, ValueType tout) = 0;
- virtual bool GetKeyTangents(int key, ValueType& tin, ValueType& tout) = 0;
- // Changes key flags, @see ESplineKeyFlags
- virtual void SetKeyFlags(int key, int flags) = 0;
- // Retrieve key flags, @see ESplineKeyFlags
- virtual int GetKeyFlags(int key) = 0;
- virtual void Interpolate(float time, ValueType& value) = 0;
- virtual void EvalInTangent([[maybe_unused]] float time, [[maybe_unused]] ValueType& value) {};
- virtual void EvalOutTangent([[maybe_unused]] float time, [[maybe_unused]] ValueType& value) {};
- virtual void SerializeSpline(XmlNodeRef& node, bool bLoading) = 0;
- virtual ISplineBackup* Backup() = 0;
- virtual void Restore(ISplineBackup* pBackup) = 0;
- void ClearAllKeys()
- {
- while (GetKeyCount() > 0)
- {
- RemoveKey(0);
- }
- Update();
- }
- // </interfuscator:shuffle>
- //////////////////////////////////////////////////////////////////////////
- // Helper functions.
- //////////////////////////////////////////////////////////////////////////
- inline bool IsKeySelectedAtAnyDimension(const int key)
- {
- const int flags = GetKeyFlags(key);
- const int dimensionCount = GetNumDimensions();
- const int mask = ((1 << dimensionCount) - 1) << ESPLINE_KEY_UI_SELECTED_SHIFT;
- return (flags & mask) != 0;
- }
- inline bool IsKeySelectedAtDimension(const int key, const int dimension)
- {
- const int flags = GetKeyFlags(key);
- const int mask = 1 << (ESPLINE_KEY_UI_SELECTED_SHIFT + dimension);
- return (flags & mask) != 0;
- }
- void SelectKeyAllDimensions(int key, bool select)
- {
- const int flags = GetKeyFlags(key);
- if (select)
- {
- const int dimensionCount = GetNumDimensions();
- const int mask = ((1 << dimensionCount) - 1) << ESPLINE_KEY_UI_SELECTED_SHIFT;
- SetKeyFlags(key, (flags & (~ESPLINE_KEY_UI_SELECTED_MASK)) | mask);
- }
- else
- {
- SetKeyFlags(key, flags & (~ESPLINE_KEY_UI_SELECTED_MASK));
- }
- }
- void SelectKeyAtDimension(int key, int dimension, bool select)
- {
- const int flags = GetKeyFlags(key);
- const int mask = 1 << (ESPLINE_KEY_UI_SELECTED_SHIFT + dimension);
- SetKeyFlags(key, (select ? (flags | mask) : (flags & (~mask))));
- }
- inline int InsertKeyFloat(float time, float val) { ValueType v = {val, 0, 0, 0}; return InsertKey(time, v); }
- inline int InsertKeyFloat3(float time, float* vals) { ValueType v = {vals[0], vals[1], vals[2], 0}; return InsertKey(time, v); }
- inline bool GetKeyValueFloat(int key, float& value) { ValueType v = {value}; bool b = GetKeyValue(key, v); value = v[0]; return b; }
- inline void SetKeyValueFloat(int key, float value) { ValueType v = {value, 0, 0, 0}; SetKeyValue(key, v); }
- inline void SetKeyValueFloat3(int key, float* vals) { ValueType v = {vals[0], vals[1], vals[2], 0}; SetKeyValue(key, v); }
- inline void InterpolateFloat(float time, float& val) { ValueType v = {val}; Interpolate(time, v); val = v[0]; }
- inline void InterpolateFloat3(float time, float* vals) { ValueType v = {vals[0], vals[1], vals[2]}; Interpolate(time, v); vals[0] = v[0]; vals[1] = v[1]; vals[2] = v[2]; }
- inline void EvalInTangentFloat(float time, float& val) { ValueType v = { val }; EvalInTangent(time, v); val = v[0]; }
- inline void EvalOutTangentFloat(float time, float& val) { ValueType v = { val }; EvalOutTangent(time, v); val = v[0]; }
- // Return Key closest to the specified time.
- inline int FindKey(float fTime, float fEpsilon = 0.01f)
- {
- int nKey = -1;
- // Find key.
- for (int k = 0; k < GetKeyCount(); k++)
- {
- if (fabs(GetKeyTime(k) - fTime) < fEpsilon)
- {
- nKey = k;
- break;
- }
- }
- return nKey;
- }
- // Force update.
- void Update() { ValueType val; Interpolate(0.f, val); }
- static void ZeroValue(ValueType& value) { value[0] = 0; value[1] = 0; value[2] = 0; value[3] = 0; }
- };
- //////////////////////////////////////////////////////////////////////////
- //
- //////////////////////////////////////////////////////////////////////////
- namespace spline
- {
- template <int N>
- class BasisFunction
- {
- public:
- const float& operator[](int i) const { return m_f[i]; };
- protected:
- float m_f[N];
- };
- // Special functions that makes parameter zero.
- template <class T>
- inline void Zero(T& val)
- {
- memset(&val, 0, sizeof(val));
- }
- // Specialized Zero functions
- template <>
- inline void Zero(float& val) { val = 0.0f; }
- template <>
- inline void Zero(Vec2& val) { val = Vec2(0.0f, 0.0f); }
- template <>
- inline void Zero(Vec3& val) { val = Vec3(0.0f, 0.0f, 0.0f); }
- template <>
- inline void Zero(Quat& val) { val.SetIdentity(); }
- inline float Concatenate(float left, float right) { return left + right; }
- inline Vec3 Concatenate(const Vec3& left, const Vec3& right) { return left + right; }
- inline Quat Concatenate(const Quat& left, const Quat& right) { return left * right; }
- inline float Subtract (float left, float right) { return left - right; }
- inline Vec3 Subtract (const Vec3& left, const Vec3& right) { return left - right; }
- inline Quat Subtract(const Quat& left, const Quat& right) { return left / right; }
- ///////////////////////////////////////////////////////////////////////////////
- // HermitBasis.
- class HermitBasis
- : public BasisFunction<4>
- {
- public:
- HermitBasis(float t)
- {
- float t2, t3, t2_3, t3_2, t3_t2;
- t2 = t * t; // t2 = t^2;
- t3 = t2 * t; // t3 = t^3;
- t3_2 = t3 + t3;
- t2_3 = 3 * t2;
- t3_t2 = t3 - t2;
- m_f[0] = t3_2 - t2_3 + 1;
- m_f[1] = -t3_2 + t2_3;
- m_f[2] = t3_t2 - t2 + t;
- m_f[3] = t3_t2;
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // BezierBasis.
- class BezierBasis
- : public BasisFunction<4>
- {
- public:
- BezierBasis(const float t)
- {
- const float t2 = t * t;
- const float t3 = t2 * t;
- m_f[0] = -t3 + 3 * t2 - 3 * t + 1;
- m_f[1] = 3 * t3 - 6 * t2 + 3 * t;
- m_f[2] = -3 * t3 + 3 * t2;
- m_f[3] = t3;
- }
- };
- template<class T>
- struct TCoeffBasis
- {
- // Coefficients for a cubic polynomial.
- T m_c[4];
- inline T eval(float t) const
- {
- return m_c[0] + t * (m_c[1] + t * (m_c[2] + t * m_c[3]));
- }
- // Compute coeffs based on 2 endpoints & slopes.
- void set(float t0, T v0, T s0, float t1, T v1, T s1)
- {
- /*
- Solve cubic equation:
- v(u) = d t^3 + c t^2 + b t + a
- for
- v(0) = v0, v'(0) = s0, v(t1) = v1, v'(t1) = s1
- Solution:
- a = v0
- b = s0
- c = -3v0 +3v1 -2s0 -s1
- d = +2v0 -2v1 +s0 +s1
- */
- /*
- Polynomial will be evaluated on adjusted parameter u == t-t0. u0 = 0, u1 = t1-t0.
- The range is normalised to start at 0 to avoid extra terms in the coefficient
- computation that can compromise precision. However, the range is not normalised
- to length 1, because that would require a division at runtime. Instead, we perform
- the division on the coefficients.
- */
- m_c[0] = v0;
- if (t1 <= t0)
- {
- m_c[1] = m_c[2] = m_c[3] = T(0.f);
- }
- else
- {
- float idt = 1.f / (t1 - t0);
- m_c[1] = T(s0 * idt);
- m_c[2] = T((-3.0f * v0 + 3.0f * v1 - 2.0f * s0 - s1) * idt * idt);
- m_c[3] = T((2.0f * v0 - 2.0f * v1 + s0 + s1) * idt * idt * idt);
- }
- }
- };
- inline float fast_fmod(float x, float y)
- {
- return fmod_tpl(x, y);
- //int ival = ftoi(x/y);
- //return x - ival*y;
- }
- /****************************************************************************
- ** Key classes **
- ****************************************************************************/
- template <class T>
- struct SplineKey
- {
- typedef T value_type;
- float time; //!< Key time.
- int flags; //!< Key flags.
- value_type value; //!< Key value.
- value_type ds; //!< Incoming tangent.
- value_type dd; //!< Outgoing tangent.
- SplineKey()
- {
- memset(this, 0, sizeof(SplineKey));
- }
- SplineKey& operator=(const SplineKey& src) { memcpy(this, &src, sizeof(*this)); return *this; }
- static void Reflect(AZ::ReflectContext* context) {}
- };
- template <class T>
- bool operator ==(const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time == k2.time; };
- template <class T>
- bool operator !=(const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time != k2.time; };
- template <class T>
- bool operator < (const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time < k2.time; };
- template <class T>
- bool operator > (const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time > k2.time; };
- //////////////////////////////////////////////////////////////////////////
- // TCBSplineKey class
- //////////////////////////////////////////////////////////////////////////
- template <class T>
- struct TCBSplineKey
- : public SplineKey<T>
- {
- // Key controls.
- float tens; //!< Key tension value.
- float cont; //!< Key continuity value.
- float bias; //!< Key bias value.
- float easeto; //!< Key ease to value.
- float easefrom; //!< Key ease from value.
- TCBSplineKey() { tens = 0, cont = 0, bias = 0, easeto = 0, easefrom = 0; };
- };
- //! TCB spline key used in quaternion spline with angle axis as input.
- struct TCBAngAxisKey
- : public TCBSplineKey<Quat>
- {
- float angle;
- Vec3 axis;
- TCBAngAxisKey()
- : axis(0, 0, 0)
- , angle(0) {};
- };
- //////////////////////////////////////////////////////////////////////////
- // General Spline class
- //////////////////////////////////////////////////////////////////////////
- template <class KeyType, class BasisType>
- class TSpline
- {
- public:
- typedef KeyType key_type;
- typedef typename KeyType::value_type value_type;
- typedef BasisType basis_type;
- // Out of range types.
- enum
- {
- ORT_CONSTANT = 0x0001, // Constant track.
- ORT_CYCLE = 0x0002, // Cycle track
- ORT_LOOP = 0x0003, // Loop track.
- ORT_OSCILLATE = 0x0004, // Oscillate track.
- ORT_LINEAR = 0x0005, // Linear track.
- ORT_RELATIVE_REPEAT = 0x0007 // Relative repeat track.
- };
- // Spline flags.
- enum
- {
- MODIFIED = 0x0001, // Track modified.
- MUST_SORT = 0x0002, // Track modified and must be sorted.
- };
- /////////////////////////////////////////////////////////////////////////////
- // Methods.
- inline TSpline()
- {
- m_flags = MODIFIED;
- m_ORT = 0;
- m_curr = 0;
- m_rangeStart = 0;
- m_rangeEnd = 0;
- m_refCount = 0;
- }
- virtual ~TSpline() {};
- ILINE void flag_set(int flag) { m_flags |= flag; };
- ILINE void flag_clr(int flag) { m_flags &= ~flag; };
- ILINE int flag(int flag) { return m_flags & flag; };
- ILINE void ORT(int ort) { m_ORT = static_cast<uint8>(ort); };
- ILINE int ORT() const { return m_ORT; };
- ILINE int isORT(int o) const { return (m_ORT == o); };
- ILINE void SetRange(float start, float end) { m_rangeStart = start; m_rangeEnd = end; };
- ILINE float GetRangeStart() const { return m_rangeStart; };
- ILINE float GetRangeEnd() const { return m_rangeEnd; };
- // Keys access methods.
- ILINE void reserve_keys(int n) { m_keys.reserve(n); }; // Reserve memory for more keys.
- ILINE void clear() { m_keys.clear(); };
- ILINE void resize(int num) { m_keys.resize(num); SetModified(true); }; // Set new key count.
- ILINE bool empty() const { return m_keys.empty(); }; // Check if curve empty (no keys).
- ILINE int num_keys() const { return (int)m_keys.size(); }; // Return number of keys in curve.
- ILINE key_type& key(int n) { return m_keys[n]; }; // Return n key.
- ILINE float& time(int n) { return m_keys[n].time; }; // Shortcut to key n time.
- ILINE value_type& value(int n) { return m_keys[n].value; }; // Shortcut to key n value.
- ILINE value_type& ds(int n) { return m_keys[n].ds; }; // Shortcut to key n incoming tangent.
- ILINE value_type& dd(int n) { return m_keys[n].dd; }; // Shortcut to key n outgoing tangent.
- ILINE int& flags(int n) { return m_keys[n].flags; }; // Shortcut to key n flags.
- ILINE key_type const& key(int n) const { return m_keys[n]; }; // Return n key.
- ILINE float time(int n) const { return m_keys[n].time; }; // Shortcut to key n time.
- ILINE value_type const& value(int n) const { return m_keys[n].value; }; // Shortcut to key n value.
- ILINE value_type const& ds(int n) const { return m_keys[n].ds; }; // Shortcut to key n incoming tangent.
- ILINE value_type const& dd(int n) const { return m_keys[n].dd; }; // Shortcut to key n outgoing tangent.
- ILINE int flags(int n) const { return m_keys[n].flags; }; // Shortcut to key n flags.
- ILINE int GetInTangentType(int nkey) const { return (flags(nkey) & SPLINE_KEY_TANGENT_IN_MASK) >> SPLINE_KEY_TANGENT_IN_SHIFT; }
- ILINE int GetOutTangentType(int nkey) const { return (flags(nkey) & SPLINE_KEY_TANGENT_OUT_MASK) >> SPLINE_KEY_TANGENT_OUT_SHIFT; }
- ILINE void erase(int key) { m_keys.erase(m_keys.begin() + key); SetModified(true); };
- ILINE bool closed() { return (ORT() == ORT_LOOP); } // return True if curve closed.
- ILINE void SetModified(bool bOn, bool bSort = false)
- {
- if (bOn)
- {
- m_flags |= MODIFIED;
- }
- else
- {
- m_flags &= ~(MODIFIED);
- }
- if (bSort)
- {
- m_flags |= MUST_SORT;
- }
- m_curr = 0;
- }
- ILINE void sort_keys()
- {
- std::stable_sort(m_keys.begin(), m_keys.end());
- m_flags &= ~MUST_SORT;
- }
- ILINE void push_back(const key_type& k)
- {
- m_keys.push_back(k);
- SetModified(true);
- };
- ILINE int insert_key(const key_type& k)
- {
- int num = num_keys();
- for (int i = 0; i < num; i++)
- {
- if (m_keys[i].time > k.time)
- {
- m_keys.insert(m_keys.begin() + i, k);
- SetModified(true);
- return i;
- }
- }
- m_keys.push_back(k);
- SetModified(true);
- return num_keys() - 1;
- };
- ILINE int insert_key(float t, value_type const& val)
- {
- key_type key;
- key.time = t;
- key.value = val;
- key.flags = 0;
- Zero(key.ds);
- Zero(key.dd);
- return insert_key(key);
- }
- inline void update()
- {
- if (m_flags & MODIFIED)
- {
- sort_keys();
- if (m_flags & MODIFIED)
- {
- comp_deriv();
- }
- }
- }
- inline bool is_updated() const
- {
- return (m_flags & MODIFIED) == 0;
- }
- // Interpolate the value along the spline.
- inline bool interpolate(float t, value_type& val)
- {
- update();
- if (empty())
- {
- return false;
- }
- if (t < time(0))
- {
- val = value(0);
- return true;
- }
- adjust_time(t);
- int curr = seek_key(t);
- if (curr < num_keys() - 1)
- {
- assert(t >= time(curr));
- float u = (t - time(curr)) / (time(curr + 1) - time(curr));
- interp_keys(curr, curr + 1, u, val);
- }
- else
- {
- val = value(num_keys() - 1);
- }
- return true;
- }
- size_t mem_size() const
- {
- return this->m_keys.capacity() * sizeof(this->m_keys[0]);
- }
- size_t sizeofThis() const
- {
- return sizeof(*this) + mem_size();
- }
- void swap(TSpline<KeyType, BasisType>& b)
- {
- using std::swap;
- m_keys.swap(b.m_keys);
- swap(m_flags, b.m_flags);
- swap(m_ORT, b.m_ORT);
- swap(m_curr, b.m_curr);
- swap(m_rangeStart, b.m_rangeStart);
- swap(m_rangeEnd, b.m_rangeEnd);
- }
- //////////////////////////////////////////////////////////////////////////
- // This two functions must be overridden in derived spline classes.
- //////////////////////////////////////////////////////////////////////////
- // Pre-compute spline tangents.
- virtual void comp_deriv() = 0;
- // Interpolate value between two keys.
- virtual void interp_keys(int key1, int key2, float u, value_type& val) = 0;
- //////////////////////////////////////////////////////////////////////////
- static void Reflect(AZ::ReflectContext* context) {}
- inline void add_ref()
- {
- ++m_refCount;
- };
- inline void release()
- {
- AZ_Assert(m_refCount > 0, "Reference count logic error, trying to decrement reference when refCount is 0");
- if (--m_refCount == 0)
- {
- delete this;
- }
- }
- private:
- int m_refCount;
- protected:
- AZStd::vector<key_type> m_keys; // List of keys.
- uint8 m_flags;
- uint8 m_ORT; // Out-Of-Range type.
- int16 m_curr; // Current key in track.
- float m_rangeStart;
- float m_rangeEnd;
- // Return key before or equal to this time.
- inline int seek_key(float t)
- {
- assert(num_keys() < (1 << 15));
- if ((m_curr >= num_keys()) || (time(m_curr) > t))
- {
- // Search from begining.
- m_curr = 0;
- }
- while ((m_curr < num_keys() - 1) && (time(m_curr + 1) <= t))
- {
- ++m_curr;
- }
- return m_curr;
- }
- inline void adjust_time(float& t)
- {
- if (isORT(ORT_CYCLE) || isORT(ORT_LOOP))
- {
- if (num_keys() > 0)
- {
- float endtime = time(num_keys() - 1);
- if (t > endtime)
- {
- // Warp time.
- t = fast_fmod(t, endtime);
- }
- }
- }
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // TSplineSlopes is default implementation of slope computation
- //////////////////////////////////////////////////////////////////////////
- template < class T, class Key = SplineKey<T>, bool bCLAMP = false >
- class TSplineSlopes
- : public TSpline< Key, TCoeffBasis<T> >
- {
- public:
- typedef TSpline< Key, TCoeffBasis<T> > super_type;
- using_type(super_type, key_type);
- using_type(super_type, value_type);
- static const bool clamp_range = bCLAMP;
- void comp_deriv()
- {
- this->SetModified(false);
- int last = this->num_keys() - 1;
- if (last <= 0)
- {
- return;
- }
- if (bCLAMP)
- {
- // Change discontinuous slopes.
- for (int i = 0; i <= last; ++i)
- {
- // Out slopes.
- if (i < last && this->GetOutTangentType(i) == SPLINE_KEY_TANGENT_LINEAR)
- {
- // Set linear between points.
- this->dd(i) = this->value(i + 1) - this->value(i);
- if (this->GetInTangentType(i + 1) == SPLINE_KEY_TANGENT_NONE)
- {
- // Match continuous slope on right.
- this->dd(i) = 2.0f * this->dd(i) - this->ds(i + 1);
- }
- }
- else if (i < last && this->GetOutTangentType(i) == SPLINE_KEY_TANGENT_NONE)
- {
- this->dd(i) = value_type(0.f);
- }
- // In slopes.
- if (i > 0 && this->GetInTangentType(i) == SPLINE_KEY_TANGENT_LINEAR)
- {
- // Set linear between points.
- this->ds(i) = this->value(i) - this->value(i - 1);
- if (this->GetOutTangentType(i - 1) == SPLINE_KEY_TANGENT_NONE)
- {
- // Match continuous slope on left.
- this->ds(i) = 2.0f * this->ds(i) - this->dd(i - 1);
- }
- }
- else if (i < last && this->GetInTangentType(i) == SPLINE_KEY_TANGENT_NONE)
- {
- this->ds(i) = value_type(0.f);
- }
- }
- }
- else
- {
- key_type& k0 = this->key(0);
- key_type& k1 = this->key(last);
- Zero(k0.ds);
- k0.dd = (0.5f) * (this->value(1) - this->value(0));
- k1.ds = (0.5f) * (this->value(last) - this->value(last - 1));
- Zero(k1.dd);
- for (int i = 1; i < (this->num_keys() - 1); ++i)
- {
- key_type& key = this->key(i);
- key.ds = 0.5f * (this->value(i + 1) - this->value(i - 1));
- key.dd = key.ds;
- }
- }
- }
- virtual void interp_keys(int key1, int key2, float u, value_type& val)
- {
- // Compute coeffs dynamically.
- TCoeffBasis<T> coeff;
- coeff.set(0.f, this->value(key1), this->dd(key1), 1.f, this->value(key2), this->ds(key2));
- val = coeff.eval(u);
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // CatmullRomSpline class implementation
- //////////////////////////////////////////////////////////////////////////
- template <class T, class Key = SplineKey<T>, bool bRangeLimit = false >
- class CatmullRomSpline
- : public TSplineSlopes< T, Key, bRangeLimit >
- {
- protected:
- typedef TSplineSlopes< T, Key, bRangeLimit > super_type;
- std::vector< TCoeffBasis<T> > m_coeffs;
- virtual void comp_deriv()
- {
- super_type::comp_deriv();
- // Store coeffs for each segment.
- m_coeffs.resize(this->num_keys());
- if (this->num_keys() > 0)
- {
- unsigned i;
- for (i = 0; i < m_coeffs.size() - 1; i++)
- {
- m_coeffs[i].set(this->time(i), this->value(i), this->dd(i), this->time(i + 1), this->value(i + 1), this->ds(i + 1));
- }
- // Last segment is just constant value.
- m_coeffs[i].set(this->time(i), this->value(i), T(0.f), this->time(i) + 1.f, this->value(i), T(0.f));
- }
- }
- virtual void interp_keys(int key1, int key2, float u, typename TSpline<Key, HermitBasis>::value_type& val)
- {
- u *= this->time(key2) - this->time(key1);
- val = m_coeffs[key1].eval(u);
- }
- public:
- size_t mem_size() const
- {
- return super_type::mem_size() + this->m_coeffs.capacity() * sizeof(this->m_coeffs[0]);
- }
- size_t sizeofThis() const
- {
- return sizeof(*this) + mem_size();
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // Extended version of Hermit Spline.
- // Provides more control on key tangents.
- //////////////////////////////////////////////////////////////////////////
- template <class T, class Key = SplineKey<T> >
- class HermitSplineEx
- : public TSpline< Key, HermitBasis >
- {
- public:
- typedef TSpline< Key, HermitBasis > super_type;
- using_type(super_type, key_type);
- using_type(super_type, value_type);
- virtual void comp_deriv()
- {
- this->SetModified(false);
- if (this->num_keys() > 1)
- {
- int last = this->num_keys() - 1;
- key_type& k0 = this->key(0);
- key_type& k1 = this->key(last);
- Zero(k0.ds);
- Zero(k0.dd);
- Zero(k1.ds);
- Zero(k1.dd);
- Zero(k0.ds);
- k0.dd = (0.5f) * (this->value(1) - this->value(0));
- k1.ds = (0.5f) * (this->value(last) - this->value(last - 1));
- Zero(k1.dd);
- for (int i = 1; i < (this->num_keys() - 1); ++i)
- {
- key_type& key = this->key(i);
- key.ds = 0.5f * (this->value(i + 1) - this->value(i - 1));
- key.dd = key.ds;
- switch (this->GetInTangentType(i))
- {
- case SPLINE_KEY_TANGENT_STEP:
- key.ds = value_type();
- break;
- case SPLINE_KEY_TANGENT_ZERO:
- key.ds = value_type();
- break;
- case SPLINE_KEY_TANGENT_LINEAR:
- key.ds = this->value(i) - this->value(i - 1);
- break;
- }
- switch (this->GetOutTangentType(i))
- {
- case SPLINE_KEY_TANGENT_STEP:
- key.dd = value_type();
- break;
- case SPLINE_KEY_TANGENT_ZERO:
- key.dd = value_type();
- break;
- case SPLINE_KEY_TANGENT_LINEAR:
- key.dd = this->value(i + 1) - this->value(i);
- break;
- }
- }
- }
- }
- protected:
- virtual void interp_keys(int from, int to, float u, T& val)
- {
- if (this->GetInTangentType(to) == SPLINE_KEY_TANGENT_STEP || this->GetOutTangentType(from) == SPLINE_KEY_TANGENT_STEP)
- {
- val = this->value(from);
- return;
- }
- typename TSpline<Key, HermitBasis >::basis_type basis(u);
- val = (basis[0] * this->value(from)) + (basis[1] * this->value(to)) + (basis[2] * this->dd(from)) + (basis[3] * this->ds(to));
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // Bezier Spline.
- //////////////////////////////////////////////////////////////////////////
- template <class T, class Key = SplineKey<T> >
- class BezierSpline
- : public TSpline< Key, BezierBasis >
- {
- public:
- typedef TSpline< Key, BezierBasis > super_type;
- using_type(super_type, key_type);
- using_type(super_type, value_type);
- virtual void comp_deriv()
- {
- this->SetModified(false);
- if (this->num_keys() > 1)
- {
- const float oneThird = 1 / 3.0f;
- const int last = this->num_keys() - 1;
- {
- if (this->GetInTangentType(0) != SPLINE_KEY_TANGENT_CUSTOM)
- {
- Zero(this->key(0).ds);
- }
- if (this->GetOutTangentType(0) != SPLINE_KEY_TANGENT_CUSTOM)
- {
- this->key(0).dd = oneThird * (this->value(1) - this->value(0));
- }
- if (this->GetInTangentType(last) != SPLINE_KEY_TANGENT_CUSTOM)
- {
- this->key(last).ds = oneThird * (this->value(last) - this->value(last - 1));
- }
- if (this->GetOutTangentType(last) != SPLINE_KEY_TANGENT_CUSTOM)
- {
- Zero(this->key(last).dd);
- }
- }
- for (int i = 1; i < last; ++i)
- {
- key_type& key = this->key(i);
- T ds0 = key.ds;
- T dd0 = key.dd;
- const float deltaTime = this->time(i + 1) - this->time(i - 1);
- if (deltaTime <= 0)
- {
- Zero(key.ds);
- Zero(key.dd);
- }
- else
- {
- const float k = (this->time(i) - this->time(i - 1)) / deltaTime;
- const value_type deltaValue = this->value(i + 1) - this->value(i - 1);
- key.ds = oneThird * deltaValue * k;
- key.dd = oneThird * deltaValue * (1 - k);
- }
- switch (this->GetInTangentType(i))
- {
- case SPLINE_KEY_TANGENT_STEP:
- Zero(key.ds);
- break;
- case SPLINE_KEY_TANGENT_ZERO:
- Zero(key.ds);
- break;
- case SPLINE_KEY_TANGENT_LINEAR:
- key.ds = oneThird * (this->value(i) - this->value(i - 1));
- break;
- case SPLINE_KEY_TANGENT_CUSTOM:
- key.ds = ds0;
- break;
- }
- switch (this->GetOutTangentType(i))
- {
- case SPLINE_KEY_TANGENT_STEP:
- Zero(key.dd);
- break;
- case SPLINE_KEY_TANGENT_ZERO:
- Zero(key.dd);
- break;
- case SPLINE_KEY_TANGENT_LINEAR:
- key.dd = oneThird * (this->value(i + 1) - this->value(i));
- break;
- case SPLINE_KEY_TANGENT_CUSTOM:
- key.dd = dd0;
- break;
- }
- }
- }
- }
- static void Reflect(AZ::ReflectContext* context) {}
- protected:
- virtual void interp_keys(int from, int to, float u, T& val)
- {
- if (this->GetOutTangentType(from) == SPLINE_KEY_TANGENT_STEP)
- {
- val = this->value(to);
- }
- else if (this->GetInTangentType(to) == SPLINE_KEY_TANGENT_STEP)
- {
- val = this->value(from);
- }
- else
- {
- typename TSpline<Key, BezierBasis >::basis_type basis(u);
- const T p0 = this->value(from);
- const T p3 = this->value(to);
- const T p1 = p0 + this->dd(from);
- const T p2 = p3 - this->ds(to);
- val = (basis[0] * p0) + (basis[1] * p1) + (basis[2] * p2) + (basis[3] * p3);
- }
- }
- };
- //////////////////////////////////////////////////////////////////////////
- // Base class for spline interpolators.
- //////////////////////////////////////////////////////////////////////////
- template <typename spline_type>
- struct SSplineBackup
- : public ISplineBackup
- , public spline_type
- {
- int refCount;
- SSplineBackup(spline_type const& s)
- : spline_type(s)
- , refCount(0) {}
- virtual void AddRef() {++refCount; }
- virtual void Release()
- {
- if (--refCount <= 0)
- {
- delete this;
- }
- }
- };
- template <class value_type, class spline_type>
- class CBaseSplineInterpolator
- : public ISplineInterpolator
- , public spline_type
- {
- public:
- static const int DIM = sizeof(value_type) / sizeof(ElemType);
- //////////////////////////////////////////////////////////////////////////
- inline void ToValueType(const value_type& t, ValueType& v) { *(value_type*)v = t; }
- inline void FromValueType(ValueType v, value_type& t) { t = *(value_type*)v; }
- //////////////////////////////////////////////////////////////////////////
- virtual void SetModified(bool b, bool bSort = false)
- {
- spline_type::SetModified(b, bSort);
- }
- virtual int GetNumDimensions()
- {
- assert(sizeof(value_type) % sizeof(ElemType) == 0);
- return DIM;
- }
- virtual int InsertKey(float t, ValueType val)
- {
- value_type value;
- FromValueType(val, value);
- return spline_type::insert_key(t, value);
- }
- virtual void RemoveKey(int key)
- {
- if (key >= 0 && key < this->num_keys())
- {
- this->erase(key);
- }
- }
- virtual void FindKeysInRange(float startTime, float endTime, int& firstFoundKey, int& numFoundKeys)
- {
- int count = this->num_keys();
- int start = 0;
- int end = count;
- for (int i = 0; i < count; ++i)
- {
- float keyTime = this->key(i).time;
- if (keyTime < startTime)
- {
- start = i + 1;
- }
- if (keyTime > endTime && end > i)
- {
- end = i;
- }
- }
- if (start < end)
- {
- firstFoundKey = start;
- numFoundKeys = end - start;
- }
- else
- {
- firstFoundKey = -1;
- numFoundKeys = 0;
- }
- }
- virtual void RemoveKeysInRange(float startTime, float endTime)
- {
- int firstFoundKey, numFoundKeys;
- FindKeysInRange(startTime, endTime, firstFoundKey, numFoundKeys);
- while (numFoundKeys-- > 0)
- {
- this->erase(firstFoundKey++);
- }
- }
- virtual int GetKeyCount()
- {
- return this->num_keys();
- };
- virtual float GetKeyTime(int key)
- {
- if (key >= 0 && key < this->num_keys())
- {
- return this->key(key).time;
- }
- return 0;
- }
- virtual bool GetKeyValue(int key, ValueType& val)
- {
- if (key >= 0 && key < this->num_keys())
- {
- ToValueType(this->key(key).value, val);
- return true;
- }
- return false;
- }
- virtual void SetKeyValue(int k, ValueType val)
- {
- if (k >= 0 && k < this->num_keys())
- {
- FromValueType(val, this->key(k).value);
- this->SetModified(true);
- }
- }
- virtual void SetKeyTime(int k, float fTime)
- {
- if (k >= 0 && k < this->num_keys())
- {
- this->key(k).time = fTime;
- this->SetModified(true, true);
- }
- }
- virtual void SetKeyInTangent(int k, ValueType tin)
- {
- if (k >= 0 && k < this->num_keys())
- {
- FromValueType(tin, this->key(k).ds);
- this->SetModified(true);
- }
- }
- virtual void SetKeyOutTangent(int k, ValueType tout)
- {
- if (k >= 0 && k < this->num_keys())
- {
- FromValueType(tout, this->key(k).dd);
- this->SetModified(true);
- }
- }
- virtual void SetKeyTangents(int k, ValueType tin, ValueType tout)
- {
- if (k >= 0 && k < this->num_keys())
- {
- FromValueType(tin, this->key(k).ds);
- FromValueType(tout, this->key(k).dd);
- this->SetModified(true);
- }
- }
- virtual bool GetKeyTangents(int k, ValueType& tin, ValueType& tout)
- {
- if (k >= 0 && k < this->num_keys())
- {
- ToValueType(this->key(k).ds, tin);
- ToValueType(this->key(k).dd, tout);
- return true;
- }
- else
- {
- return false;
- }
- }
- virtual void SetKeyFlags(int k, int flags)
- {
- if (k >= 0 && k < this->num_keys())
- {
- this->key(k).flags = flags;
- this->SetModified(true);
- }
- }
- virtual int GetKeyFlags(int k)
- {
- if (k >= 0 && k < this->num_keys())
- {
- return this->key(k).flags;
- }
- return 0;
- }
- virtual void Interpolate(float time, ValueType& value)
- {
- value_type v;
- if (spline_type::interpolate(time, v))
- {
- ToValueType(v, value);
- }
- }
- virtual ISplineBackup* Backup()
- {
- return new SSplineBackup<spline_type>(*this);
- }
- virtual void Restore(ISplineBackup* p)
- {
- SSplineBackup<spline_type>* pBackup = static_cast<SSplineBackup<spline_type>*>(p);
- static_cast<spline_type&>(*this) = *pBackup;
- }
- };
- }
- namespace AZ
- {
- AZ_TYPE_INFO_SPECIALIZE(spline::SplineKey<Vec2>, "{24A4D7E5-C36D-427D-AB49-CD86573B7288}");
- }
- #endif // CRYINCLUDE_CRYCOMMON_ISPLINES_H
|