2DSpline.h 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <ISplines.h>
  10. namespace AZ
  11. {
  12. class ReflectContext;
  13. }
  14. namespace UiSpline
  15. {
  16. //////////////////////////////////////////////////////////////////////////
  17. // General Spline class (this is a modified version of spline::TSpline)
  18. // It is modified so that we can use AZ::Serialization
  19. //////////////////////////////////////////////////////////////////////////
  20. template <class KeyType, class BasisType>
  21. class TSpline
  22. {
  23. public:
  24. typedef KeyType key_type;
  25. typedef typename KeyType::value_type value_type;
  26. typedef BasisType basis_type;
  27. // Out of range types.
  28. enum
  29. {
  30. ORT_CONSTANT = 0x0001, // Constant track.
  31. ORT_CYCLE = 0x0002, // Cycle track
  32. ORT_LOOP = 0x0003, // Loop track.
  33. ORT_OSCILLATE = 0x0004, // Oscillate track.
  34. ORT_LINEAR = 0x0005, // Linear track.
  35. ORT_RELATIVE_REPEAT = 0x0007 // Relative repeat track.
  36. };
  37. // Spline flags.
  38. enum
  39. {
  40. MODIFIED = 0x0001, // Track modified.
  41. MUST_SORT = 0x0002, // Track modified and must be sorted.
  42. };
  43. /////////////////////////////////////////////////////////////////////////////
  44. // Methods.
  45. inline TSpline()
  46. {
  47. m_flags = MODIFIED;
  48. m_ORT = 0;
  49. m_curr = 0;
  50. m_rangeStart = 0;
  51. m_rangeEnd = 0;
  52. m_refCount = 0;
  53. }
  54. virtual ~TSpline() {};
  55. ILINE void flag_set(int flag) { m_flags |= flag; };
  56. ILINE void flag_clr(int flag) { m_flags &= ~flag; };
  57. ILINE int flag(int flag) { return m_flags & flag; };
  58. ILINE void ORT(int ort) { m_ORT = static_cast<uint8>(ort); };
  59. ILINE int ORT() const { return m_ORT; };
  60. ILINE int isORT(int o) const { return (m_ORT == o); };
  61. ILINE void SetRange(float start, float end) { m_rangeStart = start; m_rangeEnd = end; };
  62. ILINE float GetRangeStart() const { return m_rangeStart; };
  63. ILINE float GetRangeEnd() const { return m_rangeEnd; };
  64. // Keys access methods.
  65. ILINE void reserve_keys(int n) { m_keys.reserve(n); }; // Reserve memory for more keys.
  66. ILINE void clear() { m_keys.clear(); };
  67. ILINE void resize(int num) { m_keys.resize(num); SetModified(true); }; // Set new key count.
  68. ILINE bool empty() const { return m_keys.empty(); }; // Check if curve empty (no keys).
  69. ILINE int num_keys() const { return (int)m_keys.size(); }; // Return number of keys in curve.
  70. ILINE key_type& key(int n) { return m_keys[n]; }; // Return n key.
  71. ILINE float& time(int n) { return m_keys[n].time; }; // Shortcut to key n time.
  72. ILINE value_type& value(int n) { return m_keys[n].value; }; // Shortcut to key n value.
  73. ILINE value_type& ds(int n) { return m_keys[n].ds; }; // Shortcut to key n incoming tangent.
  74. ILINE value_type& dd(int n) { return m_keys[n].dd; }; // Shortcut to key n outgoing tangent.
  75. ILINE int& flags(int n) { return m_keys[n].flags; }; // Shortcut to key n flags.
  76. ILINE key_type const& key(int n) const { return m_keys[n]; }; // Return n key.
  77. ILINE float time(int n) const { return m_keys[n].time; }; // Shortcut to key n time.
  78. ILINE value_type const& value(int n) const { return m_keys[n].value; }; // Shortcut to key n value.
  79. ILINE value_type const& ds(int n) const { return m_keys[n].ds; }; // Shortcut to key n incoming tangent.
  80. ILINE value_type const& dd(int n) const { return m_keys[n].dd; }; // Shortcut to key n outgoing tangent.
  81. ILINE int flags(int n) const { return m_keys[n].flags; }; // Shortcut to key n flags.
  82. ILINE int GetInTangentType(int nkey) const { return (flags(nkey) & SPLINE_KEY_TANGENT_IN_MASK) >> SPLINE_KEY_TANGENT_IN_SHIFT; }
  83. ILINE int GetOutTangentType(int nkey) const { return (flags(nkey) & SPLINE_KEY_TANGENT_OUT_MASK) >> SPLINE_KEY_TANGENT_OUT_SHIFT; }
  84. ILINE void erase(int key) { m_keys.erase(m_keys.begin() + key); SetModified(true); };
  85. ILINE bool closed() { return (ORT() == ORT_LOOP); } // return True if curve closed.
  86. ILINE void SetModified(bool bOn, bool bSort = false)
  87. {
  88. if (bOn)
  89. {
  90. m_flags |= MODIFIED;
  91. }
  92. else
  93. {
  94. m_flags &= ~(MODIFIED);
  95. }
  96. if (bSort)
  97. {
  98. m_flags |= MUST_SORT;
  99. }
  100. m_curr = 0;
  101. }
  102. ILINE void sort_keys()
  103. {
  104. std::sort(m_keys.begin(), m_keys.end());
  105. m_flags &= ~MUST_SORT;
  106. }
  107. ILINE void push_back(const key_type& k)
  108. {
  109. m_keys.push_back(k);
  110. SetModified(true);
  111. };
  112. ILINE int insert_key(const key_type& k)
  113. {
  114. int num = num_keys();
  115. for (int i = 0; i < num; i++)
  116. {
  117. if (m_keys[i].time > k.time)
  118. {
  119. m_keys.insert(m_keys.begin() + i, k);
  120. SetModified(true);
  121. return i;
  122. }
  123. }
  124. m_keys.push_back(k);
  125. SetModified(true);
  126. return num_keys() - 1;
  127. };
  128. ILINE int insert_key(float t, value_type const& val)
  129. {
  130. key_type key;
  131. key.time = t;
  132. key.value = val;
  133. key.flags = 0;
  134. spline::Zero(key.ds);
  135. spline::Zero(key.dd);
  136. return insert_key(key);
  137. }
  138. inline void update()
  139. {
  140. if (m_flags & MODIFIED)
  141. {
  142. sort_keys();
  143. if (m_flags & MODIFIED)
  144. {
  145. comp_deriv();
  146. }
  147. }
  148. }
  149. inline bool is_updated() const
  150. {
  151. return (m_flags & MODIFIED) == 0;
  152. }
  153. // Interpolate the value along the spline.
  154. inline bool interpolate(float t, value_type& val)
  155. {
  156. update();
  157. if (empty())
  158. {
  159. return false;
  160. }
  161. if (t < time(0))
  162. {
  163. val = value(0);
  164. return true;
  165. }
  166. adjust_time(t);
  167. int curr = seek_key(t);
  168. if (curr < num_keys() - 1)
  169. {
  170. assert(t >= time(curr));
  171. float u = (t - time(curr)) / (time(curr + 1) - time(curr));
  172. interp_keys(curr, curr + 1, u, val);
  173. }
  174. else
  175. {
  176. val = value(num_keys() - 1);
  177. }
  178. return true;
  179. }
  180. size_t mem_size() const
  181. {
  182. return this->m_keys.capacity() * sizeof(this->m_keys[0]);
  183. }
  184. size_t sizeofThis() const
  185. {
  186. return sizeof(*this) + mem_size();
  187. }
  188. void swap(TSpline<KeyType, BasisType>& b)
  189. {
  190. using std::swap;
  191. m_keys.swap(b.m_keys);
  192. swap(m_flags, b.m_flags);
  193. swap(m_ORT, b.m_ORT);
  194. swap(m_curr, b.m_curr);
  195. swap(m_rangeStart, b.m_rangeStart);
  196. swap(m_rangeEnd, b.m_rangeEnd);
  197. }
  198. //////////////////////////////////////////////////////////////////////////
  199. // This two functions must be overridden in derived spline classes.
  200. //////////////////////////////////////////////////////////////////////////
  201. // Pre-compute spline tangents.
  202. virtual void comp_deriv() = 0;
  203. // Interpolate value between two keys.
  204. virtual void interp_keys(int key1, int key2, float u, value_type& val) = 0;
  205. //////////////////////////////////////////////////////////////////////////
  206. static void Reflect(AZ::ReflectContext*) {}
  207. protected:
  208. AZStd::vector<key_type> m_keys; // List of keys.
  209. uint8 m_flags;
  210. uint8 m_ORT; // Out-Of-Range type.
  211. int16 m_curr; // Current key in track.
  212. float m_rangeStart;
  213. float m_rangeEnd;
  214. // Return key before or equal to this time.
  215. inline int seek_key(float t)
  216. {
  217. assert(num_keys() < (1 << 15));
  218. if ((m_curr >= num_keys()) || (time(m_curr) > t))
  219. {
  220. // Search from begining.
  221. m_curr = 0;
  222. }
  223. while ((m_curr < num_keys() - 1) && (time(m_curr + 1) <= t))
  224. {
  225. ++m_curr;
  226. }
  227. return m_curr;
  228. }
  229. inline void adjust_time(float& t)
  230. {
  231. if (isORT(ORT_CYCLE) || isORT(ORT_LOOP))
  232. {
  233. if (num_keys() > 0)
  234. {
  235. float endtime = time(num_keys() - 1);
  236. if (t > endtime)
  237. {
  238. // Warp time.
  239. t = spline::fast_fmod(t, endtime);
  240. }
  241. }
  242. }
  243. }
  244. private:
  245. int m_refCount;
  246. public:
  247. inline void add_ref()
  248. {
  249. ++m_refCount;
  250. };
  251. inline void release()
  252. {
  253. AZ_Assert(m_refCount > 0, "Reference count logic error, trying to decrement reference when refCount is 0");
  254. if (--m_refCount == 0)
  255. {
  256. delete this;
  257. }
  258. }
  259. };
  260. template <class T>
  261. struct SplineKey
  262. {
  263. typedef T value_type;
  264. float time; //!< Key time.
  265. int flags; //!< Key flags.
  266. value_type value; //!< Key value.
  267. value_type ds; //!< Incoming tangent.
  268. value_type dd; //!< Outgoing tangent.
  269. SplineKey()
  270. {
  271. memset(this, 0, sizeof(SplineKey));
  272. }
  273. SplineKey& operator=(const SplineKey& src) { memcpy(this, &src, sizeof(*this)); return *this; }
  274. static void Reflect(AZ::ReflectContext*) {}
  275. };
  276. template <class T>
  277. bool operator ==(const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time == k2.time; };
  278. template <class T>
  279. bool operator !=(const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time != k2.time; };
  280. template <class T>
  281. bool operator < (const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time < k2.time; };
  282. template <class T>
  283. bool operator > (const SplineKey<T>& k1, const SplineKey<T>& k2) { return k1.time > k2.time; };
  284. template<>
  285. void SplineKey<Vec2>::Reflect(AZ::ReflectContext* context);
  286. /** Bezier spline key extended for tangent unify/break.
  287. */
  288. template <class T>
  289. struct SplineKeyEx
  290. : public UiSpline::SplineKey<T>
  291. {
  292. float theta_from_dd_to_ds;
  293. float scale_from_dd_to_ds;
  294. void ComputeThetaAndScale() { assert(0); }
  295. void SetOutTangentFromIn() { assert(0); }
  296. void SetInTangentFromOut() { assert(0); }
  297. SplineKeyEx()
  298. : theta_from_dd_to_ds(gf_PI)
  299. , scale_from_dd_to_ds(1.0f) {}
  300. static void Reflect(AZ::ReflectContext*) {}
  301. };
  302. template <>
  303. inline void SplineKeyEx<Vec2>::ComputeThetaAndScale()
  304. {
  305. scale_from_dd_to_ds = (ds.GetLength() + 1.0f) / (dd.GetLength() + 1.0f);
  306. float out = fabs(dd.x) > 0.000001f ? atan_tpl(dd.y / dd.x) : (dd.x * dd.y >= 0 ? gf_PI / 2.0f : -gf_PI / 2.0f);
  307. float in = fabs(ds.x) > 0.000001f ? atan_tpl(ds.y / ds.x) : (ds.x * ds.y >= 0 ? gf_PI / 2.0f : -gf_PI / 2.0f);
  308. theta_from_dd_to_ds = in + gf_PI - out;
  309. }
  310. template<>
  311. inline void SplineKeyEx<Vec2>::SetOutTangentFromIn()
  312. {
  313. assert((flags & SPLINE_KEY_TANGENT_ALL_MASK) == SPLINE_KEY_TANGENT_UNIFIED);
  314. float outLength = (ds.GetLength() + 1.0f) / scale_from_dd_to_ds - 1.0f;
  315. float in = fabs(ds.x) > 0.000001f ? atan_tpl(ds.y / ds.x) : (ds.x * ds.y >= 0 ? gf_PI / 2.0f : -gf_PI / 2.0f);
  316. dd.x = 1.0f;
  317. dd.y = tan_tpl(in + gf_PI - theta_from_dd_to_ds);
  318. dd.Normalize();
  319. dd *= outLength;
  320. }
  321. template<>
  322. inline void SplineKeyEx<Vec2>::SetInTangentFromOut()
  323. {
  324. assert((flags & SPLINE_KEY_TANGENT_ALL_MASK) == SPLINE_KEY_TANGENT_UNIFIED);
  325. float inLength = scale_from_dd_to_ds * (dd.GetLength() + 1.0f) - 1.0f;
  326. float out = fabs(dd.x) > 0.000001f ? atan_tpl(dd.y / dd.x) : (dd.x * dd.y >= 0 ? gf_PI / 2.0f : -gf_PI / 2.0f);
  327. ds.x = 1.0f;
  328. ds.y = tan_tpl(out + theta_from_dd_to_ds - gf_PI);
  329. ds.Normalize();
  330. ds *= inLength;
  331. }
  332. template<>
  333. void SplineKeyEx<Vec2>::Reflect(AZ::ReflectContext* context);
  334. //////////////////////////////////////////////////////////////////////////
  335. // Bezier Spline.
  336. // This is a modified version of spline::BezierSpline
  337. // It is modified so that we can use AZ serialization
  338. //////////////////////////////////////////////////////////////////////////
  339. template <class T, class Key = SplineKeyEx<T> >
  340. class BezierSpline
  341. : public TSpline< Key, spline::BezierBasis >
  342. {
  343. public:
  344. typedef TSpline< Key, spline::BezierBasis > super_type;
  345. using_type(super_type, key_type);
  346. using_type(super_type, value_type);
  347. virtual void comp_deriv()
  348. {
  349. this->SetModified(false);
  350. if (this->num_keys() > 1)
  351. {
  352. const float oneThird = 1 / 3.0f;
  353. const int last = this->num_keys() - 1;
  354. {
  355. if (this->GetInTangentType(0) != SPLINE_KEY_TANGENT_CUSTOM)
  356. {
  357. spline::Zero(this->key(0).ds);
  358. }
  359. if (this->GetOutTangentType(0) != SPLINE_KEY_TANGENT_CUSTOM)
  360. {
  361. this->key(0).dd = oneThird * (this->value(1) - this->value(0));
  362. }
  363. if (this->GetInTangentType(last) != SPLINE_KEY_TANGENT_CUSTOM)
  364. {
  365. this->key(last).ds = oneThird * (this->value(last) - this->value(last - 1));
  366. }
  367. if (this->GetOutTangentType(last) != SPLINE_KEY_TANGENT_CUSTOM)
  368. {
  369. spline::Zero(this->key(last).dd);
  370. }
  371. }
  372. for (int i = 1; i < last; ++i)
  373. {
  374. key_type& key = this->key(i);
  375. T ds0 = key.ds;
  376. T dd0 = key.dd;
  377. const float deltaTime = this->time(i + 1) - this->time(i - 1);
  378. if (deltaTime <= 0)
  379. {
  380. spline::Zero(key.ds);
  381. spline::Zero(key.dd);
  382. }
  383. else
  384. {
  385. const float k = (this->time(i) - this->time(i - 1)) / deltaTime;
  386. const value_type deltaValue = this->value(i + 1) - this->value(i - 1);
  387. key.ds = oneThird * deltaValue * k;
  388. key.dd = oneThird * deltaValue * (1 - k);
  389. }
  390. switch (this->GetInTangentType(i))
  391. {
  392. case SPLINE_KEY_TANGENT_STEP:
  393. spline::Zero(key.ds);
  394. break;
  395. case SPLINE_KEY_TANGENT_ZERO:
  396. spline::Zero(key.ds);
  397. break;
  398. case SPLINE_KEY_TANGENT_LINEAR:
  399. key.ds = oneThird * (this->value(i) - this->value(i - 1));
  400. break;
  401. case SPLINE_KEY_TANGENT_CUSTOM:
  402. key.ds = ds0;
  403. break;
  404. }
  405. switch (this->GetOutTangentType(i))
  406. {
  407. case SPLINE_KEY_TANGENT_STEP:
  408. spline::Zero(key.dd);
  409. break;
  410. case SPLINE_KEY_TANGENT_ZERO:
  411. spline::Zero(key.dd);
  412. break;
  413. case SPLINE_KEY_TANGENT_LINEAR:
  414. key.dd = oneThird * (this->value(i + 1) - this->value(i));
  415. break;
  416. case SPLINE_KEY_TANGENT_CUSTOM:
  417. key.dd = dd0;
  418. break;
  419. }
  420. }
  421. }
  422. }
  423. static void Reflect(AZ::ReflectContext*) {}
  424. protected:
  425. virtual void interp_keys(int from, int to, float u, T& val)
  426. {
  427. if (this->GetOutTangentType(from) == SPLINE_KEY_TANGENT_STEP)
  428. {
  429. val = this->value(to);
  430. }
  431. else if (this->GetInTangentType(to) == SPLINE_KEY_TANGENT_STEP)
  432. {
  433. val = this->value(from);
  434. }
  435. else
  436. {
  437. typename TSpline<Key, spline::BezierBasis >::basis_type basis(u);
  438. const T p0 = this->value(from);
  439. const T p3 = this->value(to);
  440. const T p1 = p0 + this->dd(from);
  441. const T p2 = p3 - this->ds(to);
  442. val = (basis[0] * p0) + (basis[1] * p1) + (basis[2] * p2) + (basis[3] * p3);
  443. }
  444. }
  445. };
  446. template <class T>
  447. class TrackSplineInterpolator;
  448. template <>
  449. class TrackSplineInterpolator<Vec2>
  450. : public spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >
  451. {
  452. public:
  453. AZ_CLASS_ALLOCATOR(TrackSplineInterpolator<Vec2>, AZ::SystemAllocator)
  454. virtual int GetNumDimensions()
  455. {
  456. // It's actually one-dimensional since the x component curve is for a time-warping.
  457. return 1;
  458. }
  459. virtual void SerializeSpline([[maybe_unused]] XmlNodeRef& node, [[maybe_unused]] bool bLoading) {};
  460. private:
  461. // An utility function for the Newton-Raphson method
  462. float comp_time_deriv(int from, int to, float u) const
  463. {
  464. float u2 = u * u;
  465. float b0 = -3.0f * u2 + 6.0f * u - 3;
  466. float b1 = 9.0f * u2 - 12.0f * u + 3;
  467. float b2 = -9.0f * u2 + 6.0f * u;
  468. float b3 = 3.0f * u2;
  469. float p0 = this->value(from).x;
  470. float p3 = this->value(to).x;
  471. float p1 = p0 + this->dd(from).x;
  472. float p2 = p3 - this->ds(to).x;
  473. return (b0 * p0) + (b1 * p1) + (b2 * p2) + (b3 * p3);
  474. }
  475. float comp_value_deriv(int from, int to, float u) const
  476. {
  477. float u2 = u * u;
  478. float b0 = -3.0f * u2 + 6.0f * u - 3;
  479. float b1 = 9.0f * u2 - 12.0f * u + 3;
  480. float b2 = -9.0f * u2 + 6.0f * u;
  481. float b3 = 3.0f * u2;
  482. float p0 = this->value(from).y;
  483. float p3 = this->value(to).y;
  484. float p1 = p0 + this->dd(from).y;
  485. float p2 = p3 - this->ds(to).y;
  486. return (b0 * p0) + (b1 * p1) + (b2 * p2) + (b3 * p3);
  487. }
  488. float comp_area(int from, int to, float u = 1.0f) const
  489. {
  490. if (GetOutTangentType(from) == SPLINE_KEY_TANGENT_STEP || GetInTangentType(to) == SPLINE_KEY_TANGENT_STEP)
  491. {
  492. float value = this->value(from).y;
  493. if (GetOutTangentType(from) == SPLINE_KEY_TANGENT_STEP)
  494. {
  495. value = this->value(to).y;
  496. }
  497. float timeDelta = this->time(to) - this->time(from);
  498. return value * timeDelta * u;
  499. }
  500. float p0 = this->value(from).y;
  501. float p3 = this->value(to).y;
  502. float p1 = p0 + this->dd(from).y;
  503. float p2 = p3 - this->ds(to).y;
  504. // y = A*t^3 + B*t^2 + C*t + D
  505. float A = -p0 + 3 * p1 - 3 * p2 + p3;
  506. float B = 3 * p0 - 6 * p1 + 3 * p2;
  507. float C = -3 * p0 + 3 * p1;
  508. float D = p0;
  509. p0 = this->value(from).x;
  510. p3 = this->value(to).x;
  511. p1 = p0 + this->dd(from).x;
  512. p2 = p3 - this->ds(to).x;
  513. // dx/dt = a*t^2 + b*t + c
  514. float a = 3 * (-p0 + 3 * p1 - 3 * p2 + p3);
  515. float b = 2 * (3 * p0 - 6 * p1 + 3 * p2);
  516. float c = 1 * (-3 * p0 + 3 * p1);
  517. // y * (dx/dt) = k5*t^5 + k4*t^4 + k3*t^3 + k2*t^2 + k1*t + k0
  518. float k5 = A * a;
  519. float k4 = B * a + A * b;
  520. float k3 = C * a + B * b + A * c;
  521. float k2 = D * a + C * b + B * c;
  522. float k1 = D * b + C * c;
  523. float k0 = D * c;
  524. // Integral (y*(dx/dt) dt from 0 to u
  525. float u2 = u * u;
  526. float u3 = u2 * u;
  527. float u4 = u3 * u;
  528. float u5 = u4 * u;
  529. float u6 = u5 * u;
  530. return (k5 / 6) * u6 + (k4 / 5) * u5 + (k3 / 4) * u4 + (k2 / 3) * u3 + (k1 / 2) * u2 + k0 * u;
  531. }
  532. float search_u(float time, ISplineInterpolator::ValueType& value)
  533. {
  534. float time_to_check = time;
  535. int count = 0;
  536. int curr = seek_key(time);
  537. int next = (curr < num_keys() - 1) ? curr + 1 : curr;
  538. // Clamp the time first.
  539. if (time < this->time(0))
  540. {
  541. time = this->time(0);
  542. }
  543. else if (time > this->time(num_keys() - 1))
  544. {
  545. time = this->time(num_keys() - 1);
  546. }
  547. // It's somewhat tricky here. We should find the 't' where the x element
  548. // of the 2D Bezier curve equals to the specified 'time'.
  549. // The y component of the curve there is our value.
  550. // We use the 'Newton's method' to find the root.
  551. float u = 0;
  552. const float epsilon = 0.00001f;
  553. float timeDelta = this->time(next) - this->time(curr);
  554. if (timeDelta == 0)
  555. {
  556. timeDelta = epsilon;
  557. }
  558. // In case of stepping tangents, we don't need this special processing.
  559. if (GetOutTangentType(curr) == SPLINE_KEY_TANGENT_STEP || GetInTangentType(next) == SPLINE_KEY_TANGENT_STEP)
  560. {
  561. spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::Interpolate(time_to_check, value);
  562. return (time_to_check - this->time(curr)) / timeDelta;
  563. }
  564. do
  565. {
  566. spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::Interpolate(time_to_check, value);
  567. u = (time_to_check - this->time(curr)) / timeDelta;
  568. if (fabs(value[0] - time) < epsilon)
  569. {
  570. // Finally, we got the solution.
  571. break;
  572. }
  573. else
  574. {
  575. // Apply the Newton's method to compute the next time value to try.
  576. assert(next != curr);
  577. float dt = comp_time_deriv(curr, next, u);
  578. double dfdt = (double(value[0]) - double(time)) / (double(dt) + epsilon);
  579. u -= float(dfdt);
  580. if (u < 0)
  581. {
  582. u = 0;
  583. }
  584. else if (u > 1)
  585. {
  586. u = 1;
  587. }
  588. time_to_check = u * (this->time(next) - this->time(curr)) + this->time(curr);
  589. }
  590. ++count;
  591. }
  592. while (count < 10);
  593. return u;
  594. }
  595. Vec2 interpolate_tangent(float time, float& u)
  596. {
  597. Vec2 tangent;
  598. int curr = seek_key(time);
  599. int next = curr + 1;
  600. assert(0 <= curr && next < num_keys());
  601. ISplineInterpolator::ValueType value;
  602. u = search_u(time, value);
  603. tangent.x = comp_time_deriv(curr, next, u);
  604. tangent.y = comp_value_deriv(curr, next, u);
  605. tangent /= 3.0f;
  606. return tangent;
  607. }
  608. public:
  609. // We should override following 4 methods to make it act like an 1D curve although it's actually a 2D curve.
  610. virtual void SetKeyTime(int key, float time)
  611. {
  612. ISplineInterpolator::ValueType value;
  613. ISplineInterpolator::ZeroValue(value);
  614. spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::GetKeyValue(key, value);
  615. value[0] = time;
  616. spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::SetKeyValue(key, value);
  617. spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::SetKeyTime(key, time);
  618. }
  619. virtual void SetKeyValue(int key, ISplineInterpolator::ValueType value)
  620. {
  621. ISplineInterpolator::ValueType value0;
  622. ISplineInterpolator::ZeroValue(value0);
  623. value0[0] = GetKeyTime(key);
  624. value0[1] = value[0];
  625. spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::SetKeyValue(key, value0);
  626. }
  627. virtual bool GetKeyValue(int key, ISplineInterpolator::ValueType& value)
  628. {
  629. if (spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::GetKeyValue(key, value))
  630. {
  631. value[0] = value[1];
  632. value[1] = 0;
  633. return true;
  634. }
  635. return false;
  636. }
  637. virtual void Interpolate(float time, ISplineInterpolator::ValueType& value)
  638. {
  639. if (empty())
  640. {
  641. return;
  642. }
  643. adjust_time(time);
  644. search_u(time, value);
  645. value[0] = value[1];
  646. value[1] = 0;
  647. }
  648. float Integrate(float time)
  649. {
  650. if (empty())
  651. {
  652. return 0;
  653. }
  654. if (time < this->time(0))
  655. {
  656. return 0;
  657. }
  658. int curr = seek_key(time);
  659. int next = curr + 1;
  660. float area = 0;
  661. for (int i = 0; i < curr; ++i)
  662. {
  663. area += comp_area(i, i + 1);
  664. }
  665. if (next < this->num_keys())
  666. {
  667. ISplineInterpolator::ValueType value;
  668. float u = search_u(time, value);
  669. area += comp_area(curr, next, u);
  670. }
  671. else
  672. {
  673. area += (time - this->time(curr)) * this->value(curr).y;
  674. }
  675. return area;
  676. }
  677. virtual void SetKeyFlags(int k, int flags)
  678. {
  679. if (k >= 0 && k < this->num_keys())
  680. {
  681. if ((this->key(k).flags & SPLINE_KEY_TANGENT_ALL_MASK) != SPLINE_KEY_TANGENT_UNIFIED
  682. && (flags & SPLINE_KEY_TANGENT_ALL_MASK) == SPLINE_KEY_TANGENT_UNIFIED)
  683. {
  684. this->key(k).ComputeThetaAndScale();
  685. }
  686. }
  687. spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::SetKeyFlags(k, flags);
  688. }
  689. virtual void SetKeyInTangent(int k, ISplineInterpolator::ValueType tin)
  690. {
  691. if (k >= 0 && k < this->num_keys())
  692. {
  693. FromValueType(tin, this->key(k).ds);
  694. if ((this->key(k).flags & SPLINE_KEY_TANGENT_ALL_MASK) == SPLINE_KEY_TANGENT_UNIFIED)
  695. {
  696. this->key(k).SetOutTangentFromIn();
  697. ConstrainOutTangentsOf(k);
  698. }
  699. this->SetModified(true);
  700. }
  701. }
  702. virtual void SetKeyOutTangent(int k, ISplineInterpolator::ValueType tout)
  703. {
  704. if (k >= 0 && k < this->num_keys())
  705. {
  706. FromValueType(tout, this->key(k).dd);
  707. if ((this->key(k).flags & SPLINE_KEY_TANGENT_ALL_MASK) == SPLINE_KEY_TANGENT_UNIFIED)
  708. {
  709. this->key(k).SetInTangentFromOut();
  710. ConstrainInTangentsOf(k);
  711. }
  712. this->SetModified(true);
  713. }
  714. }
  715. // A pair of utility functions to constrain the time range
  716. // so that the time curve is always monotonically increasing.
  717. void ConstrainOutTangentsOf(int k)
  718. {
  719. if (k < num_keys() - 1
  720. && this->key(k).dd.x > (this->time(k + 1) - this->time(k)))
  721. {
  722. this->key(k).dd *= (this->time(k + 1) - this->time(k)) / this->key(k).dd.x;
  723. }
  724. }
  725. void ConstrainInTangentsOf(int k)
  726. {
  727. if (k > 0
  728. && this->key(k).ds.x > (this->time(k) - this->time(k - 1)))
  729. {
  730. this->key(k).ds *= (this->time(k) - this->time(k - 1)) / this->key(k).ds.x;
  731. }
  732. }
  733. virtual void comp_deriv()
  734. {
  735. UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> >::comp_deriv();
  736. // To process the 'zero tangent' case more properly,
  737. // here we override the tangent behavior for the case of SPLINE_KEY_TANGENT_ZERO.
  738. if (this->num_keys() > 1)
  739. {
  740. const float oneThird = 1 / 3.0f;
  741. const int last = this->num_keys() - 1;
  742. {
  743. if (GetOutTangentType(0) == SPLINE_KEY_TANGENT_ZERO)
  744. {
  745. this->key(0).dd.x = oneThird * (this->value(1).x - this->value(0).x);
  746. this->key(0).dd.y = 0;
  747. }
  748. else
  749. {
  750. ConstrainOutTangentsOf(0);
  751. }
  752. // Set the in-tangent same to the out.
  753. if (GetInTangentType(0) == SPLINE_KEY_TANGENT_ZERO)
  754. {
  755. this->key(0).ds.x = oneThird * (this->value(1).x - this->value(0).x);
  756. this->key(0).ds.y = 0;
  757. }
  758. else
  759. {
  760. ConstrainInTangentsOf(0);
  761. }
  762. if (GetInTangentType(last) == SPLINE_KEY_TANGENT_ZERO)
  763. {
  764. this->key(last).ds.x = oneThird * (this->value(last).x - this->value(last - 1).x);
  765. this->key(last).ds.y = 0;
  766. }
  767. else
  768. {
  769. ConstrainInTangentsOf(last);
  770. }
  771. // Set the out-tangent same to the in.
  772. if (GetOutTangentType(last) == SPLINE_KEY_TANGENT_ZERO)
  773. {
  774. this->key(last).dd.x = oneThird * (this->value(last).x - this->value(last - 1).x);
  775. this->key(last).dd.y = 0;
  776. }
  777. else
  778. {
  779. ConstrainOutTangentsOf(last);
  780. }
  781. }
  782. for (int i = 1; i < last; ++i)
  783. {
  784. key_type& key = this->key(i);
  785. switch (GetInTangentType(i))
  786. {
  787. case SPLINE_KEY_TANGENT_ZERO:
  788. key.ds.x = oneThird * (this->value(i).x - this->value(i - 1).x);
  789. key.ds.y = 0;
  790. break;
  791. default:
  792. ConstrainInTangentsOf(i);
  793. break;
  794. }
  795. switch (GetOutTangentType(i))
  796. {
  797. case SPLINE_KEY_TANGENT_ZERO:
  798. key.dd.x = oneThird * (this->value(i + 1).x - this->value(i).x);
  799. key.dd.y = 0;
  800. break;
  801. default:
  802. ConstrainOutTangentsOf(i);
  803. break;
  804. }
  805. }
  806. }
  807. }
  808. virtual int InsertKey(float t, ISplineInterpolator::ValueType val)
  809. {
  810. Vec2 tangent;
  811. float u = 0;
  812. bool inRange = false;
  813. if (num_keys() > 1 && this->time(0) <= t && t <= this->time(num_keys() - 1))
  814. {
  815. tangent = interpolate_tangent(t, u);
  816. inRange = true;
  817. }
  818. val[1] = val[0];
  819. val[0] = t;
  820. int keyIndex = spline::CBaseSplineInterpolator<Vec2, UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >::InsertKey(t, val);
  821. // Sets the default tangents properly.
  822. if (inRange)
  823. {
  824. this->key(keyIndex).ds = tangent * u;
  825. this->key(keyIndex).dd = tangent * (1 - u);
  826. ConstrainInTangentsOf(keyIndex);
  827. ConstrainOutTangentsOf(keyIndex);
  828. }
  829. else
  830. {
  831. const float oneThird = 1 / 3.0f;
  832. if (keyIndex == 0)
  833. {
  834. u = 0;
  835. if (num_keys() > 1)
  836. {
  837. this->key(0).dd.x = oneThird * (this->value(1).x - this->value(0).x);
  838. }
  839. else
  840. {
  841. this->key(0).dd.x = 1.0f; // Just an arbitrary value
  842. }
  843. this->key(0).dd.y = 0;
  844. // Set the in-tangent same to the out.
  845. this->key(0).ds.x = this->key(0).dd.x;
  846. this->key(0).ds.y = 0;
  847. }
  848. else if (keyIndex == num_keys() - 1)
  849. {
  850. u = 1;
  851. int last = num_keys() - 1;
  852. this->key(last).ds.x = oneThird * (this->value(last).x - this->value(last - 1).x);
  853. this->key(last).ds.y = 0;
  854. // Set the out-tangent same to the in.
  855. this->key(last).dd.x = this->key(last).ds.x;
  856. this->key(last).dd.y = 0;
  857. }
  858. else
  859. {
  860. assert(0);
  861. }
  862. }
  863. // Sets the unified tangent handles to the default.
  864. SetKeyFlags(keyIndex, SPLINE_KEY_TANGENT_UNIFIED);
  865. // Adjusts neighbors.
  866. if (keyIndex - 1 >= 0)
  867. {
  868. this->key(keyIndex - 1).dd *= u;
  869. ConstrainOutTangentsOf(keyIndex - 1);
  870. }
  871. if (keyIndex + 1 < num_keys())
  872. {
  873. this->key(keyIndex + 1).ds *= (1 - u);
  874. ConstrainInTangentsOf(keyIndex + 1);
  875. }
  876. return keyIndex;
  877. }
  878. static void Reflect(AZ::ReflectContext* context);
  879. };
  880. }; // namespace spline