AnimSplineTrack_Vec2Specialization.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  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. // Description : 'Vec2' explicit specialization of the class template
  9. // TAnimSplineTrack
  10. // Notice : Should be included in AnimSplineTrack h only
  11. #include "AnimSplineTrack.h"
  12. #include "2DSpline.h"
  13. #include <AzCore/Serialization/EditContext.h>
  14. namespace spline
  15. {
  16. template<>
  17. void SplineKey<Vec2>::Reflect(AZ::ReflectContext* context);
  18. }
  19. namespace Maestro
  20. {
  21. template<>
  22. TAnimSplineTrack<Vec2>::TAnimSplineTrack()
  23. : m_refCount(0)
  24. {
  25. AllocSpline();
  26. m_flags = 0;
  27. m_defaultValue = Vec2(0, 0);
  28. m_fMinKeyValue = 0.0f;
  29. m_fMaxKeyValue = 0.0f;
  30. m_bCustomColorSet = false;
  31. m_node = nullptr;
  32. m_trackMultiplier = 1.0f;
  33. }
  34. template<>
  35. void TAnimSplineTrack<Vec2>::add_ref()
  36. {
  37. ++m_refCount;
  38. }
  39. template<>
  40. void TAnimSplineTrack<Vec2>::release()
  41. {
  42. if (--m_refCount <= 0)
  43. {
  44. delete this;
  45. }
  46. }
  47. template<>
  48. void TAnimSplineTrack<Vec2>::GetValue(float time, float& value, bool applyMultiplier) const
  49. {
  50. if (GetNumKeys() == 0)
  51. {
  52. value = m_defaultValue.y;
  53. }
  54. else
  55. {
  56. Spline::ValueType tmp;
  57. m_spline->Interpolate(time, tmp);
  58. value = tmp[0];
  59. }
  60. if (applyMultiplier && m_trackMultiplier != 1.0f && m_trackMultiplier > AZ::Constants::Tolerance)
  61. {
  62. value /= m_trackMultiplier;
  63. }
  64. }
  65. template<>
  66. EAnimCurveType TAnimSplineTrack<Vec2>::GetCurveType() const
  67. {
  68. return eAnimCurveType_BezierFloat;
  69. }
  70. template<>
  71. AnimValueType TAnimSplineTrack<Vec2>::GetValueType() const
  72. {
  73. return kAnimValueDefault;
  74. }
  75. template<>
  76. void TAnimSplineTrack<Vec2>::SetValue(float time, const float& value, bool bDefault, bool applyMultiplier)
  77. {
  78. const Range timeRange(GetTimeRange().start, GetTimeRange().end);
  79. if ((timeRange.end - timeRange.start > AZ::Constants::Tolerance) && (time < timeRange.start || time > timeRange.end))
  80. {
  81. AZ_WarningOnce("AnimSplineTrack", false, "SetValue(%f): Time is out of range (%f .. %f) in track (%s), clamped.",
  82. time, timeRange.start, timeRange.end, (GetNode() ? GetNode()->GetName() : ""));
  83. AZStd::clamp(time, timeRange.start, timeRange.end);
  84. }
  85. if (!bDefault)
  86. {
  87. I2DBezierKey key;
  88. if (applyMultiplier && m_trackMultiplier != 1.0f)
  89. {
  90. key.value = Vec2(time, value * m_trackMultiplier);
  91. }
  92. else
  93. {
  94. key.value = Vec2(time, value);
  95. }
  96. SetKeyAtTime(time, &key);
  97. }
  98. else
  99. {
  100. if (applyMultiplier && m_trackMultiplier != 1.0f)
  101. {
  102. m_defaultValue.set(time, value * m_trackMultiplier);
  103. }
  104. else
  105. {
  106. m_defaultValue.set(time, value);
  107. }
  108. }
  109. }
  110. template<>
  111. void TAnimSplineTrack<Vec2>::GetKey(int keyIndex, IKey* key) const
  112. {
  113. if (keyIndex < 0 || keyIndex >= GetNumKeys() || !key || !(m_spline))
  114. {
  115. AZ_Assert(keyIndex >= 0 && keyIndex < GetNumKeys(), "Key index (%d) is out of range (0 .. %d).", keyIndex, GetNumKeys());
  116. AZ_Assert(key, "Key is null");
  117. AZ_Assert((m_spline), "Invalid spline.");
  118. return;
  119. }
  120. Spline::key_type& k = m_spline->key(keyIndex);
  121. I2DBezierKey* bezierkey = (I2DBezierKey*)key;
  122. bezierkey->time = k.time;
  123. bezierkey->flags = k.flags;
  124. bezierkey->value = k.value;
  125. }
  126. template<>
  127. void TAnimSplineTrack<Vec2>::SetKey(int keyIndex, IKey* key)
  128. {
  129. if (keyIndex < 0 || keyIndex >= GetNumKeys() || !key || !(m_spline))
  130. {
  131. AZ_Assert(keyIndex >= 0 && keyIndex < GetNumKeys(), "Key index (%d) is out of range (0 .. %d).", keyIndex, GetNumKeys());
  132. AZ_Assert(key, "Key is null");
  133. AZ_Assert((m_spline), "Invalid spline.");
  134. return;
  135. }
  136. Spline::key_type& k = m_spline->key(keyIndex);
  137. I2DBezierKey* bezierkey = (I2DBezierKey*)key;
  138. k.time = bezierkey->time;
  139. k.flags = bezierkey->flags;
  140. k.value = bezierkey->value;
  141. UpdateTrackValueRange(k.value.y);
  142. Invalidate();
  143. SortKeys();
  144. }
  145. //! Create key at given time, and return its index.
  146. template<>
  147. int TAnimSplineTrack<Vec2>::CreateKey(float time)
  148. {
  149. const Range timeRange(GetTimeRange());
  150. if ((timeRange.end - timeRange.start > AZ::Constants::Tolerance) && (time < timeRange.start || time > timeRange.end))
  151. {
  152. AZ_WarningOnce("AnimSplineTrack", false, "CreateKey(%f): Time is out of range (%f .. %f) in track (%s), clamped.",
  153. time, timeRange.start, timeRange.end, (GetNode() ? GetNode()->GetName() : ""));
  154. AZStd::clamp(time, timeRange.start, timeRange.end);
  155. }
  156. float value;
  157. const int numKeys = GetNumKeys();
  158. bool bUseDefault = true;
  159. if (numKeys > 0)
  160. {
  161. SortKeys();
  162. // Check that no keys exist at the same time
  163. auto prevKeyIdx = numKeys - 1;
  164. while ((prevKeyIdx > 0) && (GetKeyTime(prevKeyIdx) > time))
  165. {
  166. --prevKeyIdx;
  167. }
  168. float dt = AZStd::abs(time - GetKeyTime(prevKeyIdx)); // delta time to previous key
  169. if (prevKeyIdx < numKeys - 1) // Is there next key?
  170. {
  171. dt = AZStd::min(dt, AZStd::abs(time - GetKeyTime(prevKeyIdx + 1))); // delta time to closest key
  172. }
  173. if (dt < GetMinKeyTimeDelta())
  174. {
  175. AZ_Error("AnimSplineTrack", false, "CreateKey(%f): A key at this time exists in track (%s).", time, (GetNode() ? GetNode()->GetName() : ""));
  176. return -1; // a key is too close in time, reject adding a key
  177. }
  178. // Check if Default Value was recently updated, and is closer in time than existing keys
  179. bUseDefault = AZStd::abs(time - m_defaultValue.x) < dt;
  180. }
  181. if (bUseDefault)
  182. {
  183. value = m_defaultValue.y;
  184. }
  185. else
  186. {
  187. GetValue(time, value);
  188. }
  189. UpdateTrackValueRange(value);
  190. Spline::ValueType tmp;
  191. tmp[0] = value;
  192. tmp[1] = 0.f;
  193. tmp[2] = 0.f;
  194. tmp[3] = 0.f;
  195. m_spline->InsertKey(time, tmp);
  196. Invalidate();
  197. SortKeys();
  198. return FindKey(time);
  199. }
  200. template<>
  201. int TAnimSplineTrack<Vec2>::CloneKey(int srcKeyIndex, float timeOffset)
  202. {
  203. const auto numKeys = GetNumKeys();
  204. if (srcKeyIndex < 0 || srcKeyIndex >= numKeys)
  205. {
  206. AZ_Assert(false, "Key index (%d) is out of range (0 .. %d).", srcKeyIndex, numKeys);
  207. return -1;
  208. }
  209. I2DBezierKey key;
  210. GetKey(srcKeyIndex, &key);
  211. // Key time offset must be big enough to prevent generation of singular tangents
  212. const auto minTimeOffset = AZStd::max(0.01f, GetMinKeyTimeDelta() * 1.1f);
  213. if (AZStd::abs(timeOffset) < minTimeOffset)
  214. {
  215. timeOffset = timeOffset >= 0.0f ? minTimeOffset : minTimeOffset;
  216. }
  217. key.time += timeOffset;
  218. const auto timeRange = GetTimeRange();
  219. AZStd::clamp(key.time, timeRange.start, timeRange.end);
  220. // Check that no key is too close
  221. for (int i = 0; i < numKeys; ++i)
  222. {
  223. I2DBezierKey aKey;
  224. GetKey(i, &aKey);
  225. const auto dt = AZStd::abs(aKey.time - key.time);
  226. if (dt < minTimeOffset)
  227. {
  228. AZ_Error("AnimSplineTrack", false,
  229. "CloneKey(%d, %f): A key at time (%f) with index (%d) in this track (%s) is too close to cloned key time (%f).",
  230. srcKeyIndex, timeOffset, aKey.time, i, (GetNode() ? GetNode()->GetName() : ""), key.time);
  231. return -1;
  232. }
  233. }
  234. const auto newIndex = CreateKey(key.time);
  235. if (newIndex < 0)
  236. {
  237. return -1;
  238. }
  239. key.value.x = key.time;
  240. SetKey(newIndex, &key);
  241. SortKeys();
  242. return FindKey(key.time);
  243. }
  244. template<>
  245. int TAnimSplineTrack<Vec2>::CopyKey(IAnimTrack* pFromTrack, int fromKeyIndex)
  246. {
  247. if (!pFromTrack || fromKeyIndex < 0 || fromKeyIndex >= pFromTrack->GetNumKeys())
  248. {
  249. AZ_Assert(pFromTrack != nullptr, "Expected valid track pointer.");
  250. AZ_Assert(fromKeyIndex >= 0 && fromKeyIndex < pFromTrack->GetNumKeys(), "Key index (%d) is out of range (0 .. %d).", fromKeyIndex, GetNumKeys());
  251. return -1;
  252. }
  253. I2DBezierKey key;
  254. pFromTrack->GetKey(fromKeyIndex, &key);
  255. if (this == pFromTrack)
  256. {
  257. // Shift key time to prevent generation of singular tangents, with offset selected bigger than minimal legal key time delta.
  258. const float timeOffset = AZStd::max(0.01f, GetMinKeyTimeDelta() * 1.1f);
  259. const auto timeRange = GetTimeRange();
  260. bool allowToAddKey = timeRange.end - timeRange.start > timeOffset;
  261. if (allowToAddKey)
  262. {
  263. key.time += timeOffset;
  264. if (key.time > timeRange.end)
  265. {
  266. key.time -= timeOffset * 2.0f;
  267. if (key.time < timeRange.start)
  268. {
  269. allowToAddKey = false;
  270. }
  271. }
  272. }
  273. if (!allowToAddKey)
  274. {
  275. AZ_Error("AnimSplineTrack", false, "CopyKey(%s, %d): Too narrow time range (%f .. %f) to clone key in this track.",
  276. (GetNode() ? GetNode()->GetName() : ""), fromKeyIndex, timeRange.start, timeRange.end);
  277. return -1;
  278. }
  279. const auto existingKeyIndex = FindKey(key.time);
  280. if (existingKeyIndex >= 0)
  281. {
  282. AZ_Error("AnimSplineTrack", false, "CopyKey(%s, %d): A key at time (%f) with index (%d) already exists in this track.",
  283. (GetNode() ? GetNode()->GetName() : ""), fromKeyIndex, key.time, existingKeyIndex);
  284. return -1;
  285. }
  286. }
  287. else
  288. {
  289. const auto existingKeyIndex = FindKey(key.time);
  290. if (existingKeyIndex >= 0)
  291. {
  292. AZ_Error("AnimSplineTrack", false, "CopyKey(%s, %d): A key at time (%f) with index (%d) already exists in this track (%s).",
  293. (pFromTrack->GetNode() ? pFromTrack->GetNode()->GetName() : ""), fromKeyIndex, key.time, existingKeyIndex, (GetNode() ? GetNode()->GetName() : ""));
  294. return -1;
  295. }
  296. }
  297. const auto newIndex = CreateKey(key.time);
  298. if (newIndex < 0)
  299. {
  300. return -1;
  301. }
  302. key.value.x = key.time;
  303. SetKey(newIndex, &key);
  304. SortKeys();
  305. return FindKey(key.time);
  306. }
  307. /// @deprecated Serialization for Sequence data in Component Entity Sequences now occurs through AZ::SerializeContext and the Sequence
  308. /// Component
  309. template<>
  310. bool TAnimSplineTrack<Vec2>::Serialize(XmlNodeRef& xmlNode, bool bLoading, bool bLoadEmptyTracks)
  311. {
  312. if (bLoading)
  313. {
  314. int num = xmlNode->getChildCount();
  315. int flags = m_flags;
  316. xmlNode->getAttr("Flags", flags);
  317. xmlNode->getAttr("defaultValue", m_defaultValue);
  318. SetFlags(flags);
  319. xmlNode->getAttr("HasCustomColor", m_bCustomColorSet);
  320. if (m_bCustomColorSet)
  321. {
  322. unsigned int abgr;
  323. xmlNode->getAttr("CustomColor", abgr);
  324. m_customColor = ColorB(abgr);
  325. }
  326. SetNumKeys(num);
  327. for (int i = 0; i < num; i++)
  328. {
  329. I2DBezierKey key; // Must be inside loop.
  330. XmlNodeRef keyNode = xmlNode->getChild(i);
  331. if (!keyNode->getAttr("time", key.time))
  332. {
  333. CryLog("[CRYMOVIE:TAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing time information.");
  334. return false;
  335. }
  336. if (!keyNode->getAttr("value", key.value))
  337. {
  338. CryLog("[CRYMOVIE:TAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing value information.");
  339. return false;
  340. }
  341. keyNode->getAttr("flags", key.flags);
  342. SetKey(i, &key);
  343. // In-/Out-tangent
  344. if (!keyNode->getAttr("ds", m_spline->key(i).ds))
  345. {
  346. CryLog("[CRYMOVIE:TAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing ds spline information.");
  347. return false;
  348. }
  349. if (!keyNode->getAttr("dd", m_spline->key(i).dd))
  350. {
  351. CryLog("[CRYMOVIE:TAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:dd spline information.");
  352. return false;
  353. }
  354. // now that tangents are loaded, compute the relative angle and size for later unified Tangent manipulations
  355. m_spline->key(i).ComputeThetaAndScale();
  356. }
  357. xmlNode->getAttr("Id", m_id);
  358. if ((!num) && (!bLoadEmptyTracks))
  359. {
  360. return false;
  361. }
  362. }
  363. else
  364. {
  365. int num = GetNumKeys();
  366. xmlNode->setAttr("Flags", GetFlags());
  367. xmlNode->setAttr("defaultValue", m_defaultValue);
  368. xmlNode->setAttr("HasCustomColor", m_bCustomColorSet);
  369. if (m_bCustomColorSet)
  370. {
  371. xmlNode->setAttr("CustomColor", m_customColor.pack_abgr8888());
  372. }
  373. I2DBezierKey key;
  374. for (int i = 0; i < num; i++)
  375. {
  376. GetKey(i, &key);
  377. XmlNodeRef keyNode = xmlNode->newChild("Key");
  378. AZ_Assert(key.time == key.value.x, "Invalid Bezier key at %i", i);
  379. keyNode->setAttr("time", key.time);
  380. keyNode->setAttr("value", key.value);
  381. int flags = key.flags;
  382. // Just save the in/out/unify mask part. Others are for editing convenience.
  383. flags &= (SPLINE_KEY_TANGENT_IN_MASK | SPLINE_KEY_TANGENT_OUT_MASK | SPLINE_KEY_TANGENT_UNIFY_MASK);
  384. if (flags != 0)
  385. {
  386. keyNode->setAttr("flags", flags);
  387. }
  388. // We also have to save in-/out-tangents, because TCB infos are not used for custom tangent keys.
  389. keyNode->setAttr("ds", m_spline->key(i).ds);
  390. keyNode->setAttr("dd", m_spline->key(i).dd);
  391. }
  392. xmlNode->setAttr("Id", m_id);
  393. }
  394. return true;
  395. }
  396. template<>
  397. bool TAnimSplineTrack<Vec2>::SerializeSelection(XmlNodeRef& xmlNode, bool bLoading, bool bCopySelected, float fTimeOffset)
  398. {
  399. bool result = true;
  400. if (bLoading)
  401. {
  402. int numKeys = GetNumKeys();
  403. int numNewKeys = xmlNode->getChildCount();
  404. unsigned int type;
  405. xmlNode->getAttr("TrackType", type);
  406. if (type != GetCurveType())
  407. {
  408. return false;
  409. }
  410. SetNumKeys(numNewKeys + numKeys);
  411. for (int i = 0; i < numNewKeys; i++)
  412. {
  413. I2DBezierKey key; // Must be inside loop.
  414. XmlNodeRef keyNode = xmlNode->getChild(i);
  415. keyNode->getAttr("time", key.time);
  416. keyNode->getAttr("value", key.value);
  417. if (AZStd::abs(key.time - key.value.x) > AZ::Constants::FloatEpsilon)
  418. {
  419. AZ_Assert(false, "Invalid Bezier key at %i", i);
  420. result = false;
  421. continue;
  422. }
  423. key.time += fTimeOffset;
  424. key.value.x += fTimeOffset;
  425. keyNode->getAttr("flags", key.flags);
  426. SetKey(i + numKeys, &key);
  427. const int newKeyIndex = FindKey(key.time);
  428. if (newKeyIndex < 0)
  429. {
  430. AZ_Assert(false, "Failed to set a new key.");
  431. result = false;
  432. continue;
  433. }
  434. if (bCopySelected)
  435. {
  436. SelectKey(newKeyIndex, true);
  437. }
  438. // In-/Out-tangent
  439. keyNode->getAttr("ds", m_spline->key(newKeyIndex).ds);
  440. keyNode->getAttr("dd", m_spline->key(newKeyIndex).dd);
  441. }
  442. }
  443. else
  444. {
  445. int numKeys = GetNumKeys();
  446. xmlNode->setAttr("TrackType", GetCurveType());
  447. I2DBezierKey key;
  448. for (int i = 0; i < numKeys; i++)
  449. {
  450. GetKey(i, &key);
  451. if (AZStd::abs(key.time - key.value.x) > AZ::Constants::FloatEpsilon)
  452. {
  453. AZ_Assert(false, "Invalid Bezier key at %i", i);
  454. result = false;
  455. continue;
  456. }
  457. if (!bCopySelected || IsKeySelected(i))
  458. {
  459. XmlNodeRef keyNode = xmlNode->newChild("Key");
  460. keyNode->setAttr("time", key.time);
  461. keyNode->setAttr("value", key.value);
  462. int flags = key.flags;
  463. // Just save the in/out mask part. Others are for editing convenience.
  464. flags &= (SPLINE_KEY_TANGENT_IN_MASK | SPLINE_KEY_TANGENT_OUT_MASK);
  465. if (flags != 0)
  466. {
  467. keyNode->setAttr("flags", flags);
  468. }
  469. // We also have to save in-/out-tangents, because TCB infos are not used for custom tangent keys.
  470. keyNode->setAttr("ds", m_spline->key(i).ds);
  471. keyNode->setAttr("dd", m_spline->key(i).dd);
  472. }
  473. }
  474. }
  475. SortKeys();
  476. return result;
  477. }
  478. template<>
  479. void TAnimSplineTrack<Vec2>::GetKeyInfo(int keyIndex, const char*& description, float& duration) const
  480. {
  481. duration = 0;
  482. static char str[64];
  483. description = str;
  484. if (keyIndex < 0 || keyIndex >= GetNumKeys())
  485. {
  486. AZ_Assert(false, "Key index (%d) is out of range (0 .. %d).", keyIndex, GetNumKeys());
  487. return;
  488. }
  489. Spline::key_type& k = m_spline->key(keyIndex);
  490. azsnprintf(str, AZ_ARRAY_SIZE(str), "%.2f", k.value.y);
  491. }
  492. } // namespace Maestro
  493. namespace spline
  494. {
  495. using BezierSplineVec2 = BezierSpline<Vec2, SplineKeyEx<Vec2>>;
  496. using TSplineBezierBasisVec2 = TSpline<SplineKeyEx<Vec2>, BezierBasis>;
  497. template <>
  498. void TSplineBezierBasisVec2::Reflect(AZ::ReflectContext* context);
  499. template <>
  500. void BezierSplineVec2::Reflect(AZ::ReflectContext* context);
  501. AZ_TYPE_INFO_SPECIALIZE(TrackSplineInterpolator<Vec2>, "{173AC8F0-FD63-4583-8D38-F43FE59F2209}");
  502. AZ_TYPE_INFO_SPECIALIZE(SplineKeyEx<Vec2>, "{96BCA307-A4D5-43A0-9985-08A29BCCCB30}");
  503. AZ_TYPE_INFO_SPECIALIZE(BezierSplineVec2, "{EE318F13-A608-4047-85B3-3D40745A19C7}");
  504. AZ_TYPE_INFO_SPECIALIZE(TSplineBezierBasisVec2, "{B638C840-C1D7-483A-B04E-B22DA539DB8D}");
  505. template<>
  506. void SplineKey<Vec2>::Reflect(AZ::ReflectContext* context)
  507. {
  508. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  509. {
  510. serializeContext->Class<SplineKey<Vec2> >()
  511. ->Version(1)
  512. ->Field("time", &SplineKey<Vec2>::time)
  513. ->Field("flags", &SplineKey<Vec2>::flags)
  514. ->Field("value", &SplineKey<Vec2>::value)
  515. ->Field("ds", &SplineKey<Vec2>::ds)
  516. ->Field("dd", &SplineKey<Vec2>::dd);
  517. }
  518. }
  519. template<>
  520. void SplineKeyEx<Vec2>::Reflect(AZ::ReflectContext* context)
  521. {
  522. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  523. {
  524. serializeContext->Class<SplineKeyEx<Vec2>, SplineKey<Vec2> >()
  525. ->Version(1);
  526. }
  527. }
  528. void TrackSplineInterpolator<Vec2>::Reflect(AZ::ReflectContext* context)
  529. {
  530. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  531. {
  532. serializeContext->Class<TrackSplineInterpolator<Vec2>, spline::BezierSpline<Vec2, spline::SplineKeyEx<Vec2> > >()
  533. ->Version(1);
  534. }
  535. }
  536. template <>
  537. void TSplineBezierBasisVec2::Reflect(AZ::ReflectContext* context)
  538. {
  539. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  540. {
  541. serializeContext->Class<TSplineBezierBasisVec2>()
  542. ->Version(1)
  543. ->Field("Keys", &BezierSplineVec2::m_keys);
  544. }
  545. }
  546. template <>
  547. void BezierSplineVec2::Reflect(AZ::ReflectContext* context)
  548. {
  549. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  550. {
  551. TSplineBezierBasisVec2::Reflect(serializeContext);
  552. serializeContext->Class<BezierSplineVec2, TSplineBezierBasisVec2>()
  553. ->Version(1);
  554. }
  555. }
  556. } // namespace spline
  557. namespace Maestro
  558. {
  559. // When TAnimSplineTrack<Vec2> is deserialized, a spline instance
  560. // is first created in the TUiAnimSplineTrack<Vec2> constructor (via AllocSpline()),
  561. // then the pointer is overwritten when "Spline" field is deserialized.
  562. // To prevent a memory leak, m_spline is now an intrusive pointer, so that if/when
  563. // the "Spline" field is deserialized, the old object will be deleted.
  564. static bool TAnimSplineTrackVec2VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  565. {
  566. bool result = true;
  567. if (classElement.GetVersion() < 5)
  568. {
  569. classElement.AddElement(context, "BaseClass1", azrtti_typeid<IAnimTrack>());
  570. if (classElement.GetVersion() == 1)
  571. {
  572. bool converted = false;
  573. int splineElementIdx = classElement.FindElement(AZ_CRC_CE("Spline"));
  574. if (splineElementIdx != -1)
  575. {
  576. // Find & copy the raw pointer node
  577. AZ::SerializeContext::DataElementNode& splinePtrNodeRef = classElement.GetSubElement(splineElementIdx);
  578. AZ::SerializeContext::DataElementNode splinePtrNodeCopy = splinePtrNodeRef;
  579. // Reset the node, then convert it to an intrusive pointer
  580. splinePtrNodeRef = AZ::SerializeContext::DataElementNode();
  581. if (splinePtrNodeRef.Convert<AZStd::intrusive_ptr<spline::TrackSplineInterpolator<Vec2>>>(context, "Spline"))
  582. {
  583. // Use the standard name used with the smart pointers serialization
  584. // (smart pointers are serialized as containers with one element);
  585. // Set the intrusive pointer to the raw pointer value
  586. splinePtrNodeCopy.SetName(AZ::SerializeContext::IDataContainer::GetDefaultElementName());
  587. splinePtrNodeRef.AddElement(splinePtrNodeCopy);
  588. converted = true;
  589. }
  590. }
  591. // Did not convert. Discard unknown versions if failed to convert, and hope for the best
  592. AZ_Assert(
  593. converted, "Failed to convert TUiAnimSplineTrack<Vec2> version %d to the current version", classElement.GetVersion());
  594. result = converted;
  595. }
  596. }
  597. return result;
  598. }
  599. template<>
  600. void TAnimSplineTrack<Vec2>::Reflect(AZ::ReflectContext* context)
  601. {
  602. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  603. {
  604. spline::SplineKey<Vec2>::Reflect(serializeContext);
  605. spline::SplineKeyEx<Vec2>::Reflect(serializeContext);
  606. spline::TrackSplineInterpolator<Vec2>::Reflect(serializeContext);
  607. spline::BezierSplineVec2::Reflect(serializeContext);
  608. serializeContext->Class<TAnimSplineTrack<Vec2>, IAnimTrack>()
  609. ->Version(5, &TAnimSplineTrackVec2VersionConverter)
  610. ->Field("Flags", &TAnimSplineTrack<Vec2>::m_flags)
  611. ->Field("DefaultValue", &TAnimSplineTrack<Vec2>::m_defaultValue)
  612. ->Field("ParamType", &TAnimSplineTrack<Vec2>::m_nParamType)
  613. ->Field("Spline", &TAnimSplineTrack<Vec2>::m_spline)
  614. ->Field("Id", &TAnimSplineTrack<Vec2>::m_id);
  615. AZ::EditContext* ec = serializeContext->GetEditContext();
  616. // Preventing the default value from being pushed to slice to keep it from dirtying the slice when updated internally
  617. if (ec)
  618. {
  619. ec->Class<TAnimSplineTrack<Vec2>>("TAnimSplineTrack Vec2", "Specialization track for Vec2 AnimSpline")
  620. ->DataElement(AZ::Edit::UIHandlers::Vector2, &TAnimSplineTrack<Vec2>::m_defaultValue, "DefaultValue", "")
  621. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
  622. ->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushable);
  623. }
  624. }
  625. }
  626. } // namespace Maestro