AnimSplineTrack_Vec2Specialization.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  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. #include "AnimSplineTrack.h"
  9. #include "2DSpline.h"
  10. #include <IMovieSystem.h>
  11. #include <LyShine/UiBase.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. template <>
  14. TUiAnimSplineTrack<Vec2>::TUiAnimSplineTrack()
  15. : m_refCount(0)
  16. {
  17. AllocSpline();
  18. m_flags = 0;
  19. m_defaultValue = Vec2(0, 0);
  20. m_fMinKeyValue = 0.0f;
  21. m_fMaxKeyValue = 0.0f;
  22. m_bCustomColorSet = false;
  23. }
  24. template <>
  25. void TUiAnimSplineTrack<Vec2>::add_ref()
  26. {
  27. ++m_refCount;
  28. }
  29. //////////////////////////////////////////////////////////////////////////
  30. template <>
  31. void TUiAnimSplineTrack<Vec2>::release()
  32. {
  33. if (--m_refCount <= 0)
  34. {
  35. delete this;
  36. }
  37. }
  38. template <>
  39. void TUiAnimSplineTrack<Vec2>::GetValue(float time, float& value)
  40. {
  41. if (GetNumKeys() == 0)
  42. {
  43. value = m_defaultValue.y;
  44. }
  45. else
  46. {
  47. Spline::ValueType tmp;
  48. m_spline->Interpolate(time, tmp);
  49. value = tmp[0];
  50. }
  51. }
  52. template <>
  53. EUiAnimCurveType TUiAnimSplineTrack<Vec2>::GetCurveType() { return eUiAnimCurveType_BezierFloat; }
  54. template <>
  55. EUiAnimValue TUiAnimSplineTrack<Vec2>::GetValueType() { return eUiAnimValue_Float; }
  56. template <>
  57. void TUiAnimSplineTrack<Vec2>::SetValue(float time, const float& value, bool bDefault)
  58. {
  59. if (!bDefault)
  60. {
  61. I2DBezierKey key;
  62. key.value = Vec2(time, value);
  63. SetKeyAtTime(time, &key);
  64. }
  65. else
  66. {
  67. m_defaultValue = Vec2(time, value);
  68. }
  69. }
  70. template <>
  71. void TUiAnimSplineTrack<Vec2>::GetKey(int index, IKey* key) const
  72. {
  73. assert(index >= 0 && index < GetNumKeys());
  74. assert(key != 0);
  75. Spline::key_type& k = m_spline->key(index);
  76. I2DBezierKey* bezierkey = (I2DBezierKey*)key;
  77. bezierkey->time = k.time;
  78. bezierkey->flags = k.flags;
  79. bezierkey->value = k.value;
  80. }
  81. template <>
  82. void TUiAnimSplineTrack<Vec2>::SetKey(int index, IKey* key)
  83. {
  84. assert(index >= 0 && index < GetNumKeys());
  85. assert(key != 0);
  86. Spline::key_type& k = m_spline->key(index);
  87. I2DBezierKey* bezierkey = (I2DBezierKey*)key;
  88. k.time = bezierkey->time;
  89. k.flags = bezierkey->flags;
  90. k.value = bezierkey->value;
  91. UpdateTrackValueRange(k.value.y);
  92. Invalidate();
  93. }
  94. //! Create key at given time, and return its index.
  95. template <>
  96. int TUiAnimSplineTrack<Vec2>::CreateKey(float time)
  97. {
  98. float value;
  99. int nkey = GetNumKeys();
  100. if (nkey > 0)
  101. {
  102. GetValue(time, value);
  103. }
  104. else
  105. {
  106. value = m_defaultValue.y;
  107. }
  108. UpdateTrackValueRange(value);
  109. Spline::ValueType tmp;
  110. tmp[0] = value;
  111. tmp[1] = 0;
  112. return m_spline->InsertKey(time, tmp);
  113. }
  114. template <>
  115. int TUiAnimSplineTrack<Vec2>::CopyKey(IUiAnimTrack* pFromTrack, int nFromKey)
  116. {
  117. // This small time offset is applied to prevent the generation of singular tangents.
  118. float timeOffset = 0.01f;
  119. I2DBezierKey key;
  120. pFromTrack->GetKey(nFromKey, &key);
  121. float t = key.time + timeOffset;
  122. int newIndex = CreateKey(t);
  123. key.time = key.value.x = t;
  124. SetKey(newIndex, &key);
  125. return newIndex;
  126. }
  127. template <>
  128. bool TUiAnimSplineTrack<Vec2>::Serialize([[maybe_unused]] IUiAnimationSystem* uiAnimationSystem, XmlNodeRef& xmlNode, bool bLoading, bool bLoadEmptyTracks)
  129. {
  130. if (bLoading)
  131. {
  132. int num = xmlNode->getChildCount();
  133. int flags = m_flags;
  134. xmlNode->getAttr("Flags", flags);
  135. xmlNode->getAttr("defaultValue", m_defaultValue);
  136. SetFlags(flags);
  137. xmlNode->getAttr("HasCustomColor", m_bCustomColorSet);
  138. if (m_bCustomColorSet)
  139. {
  140. unsigned int abgr;
  141. xmlNode->getAttr("CustomColor", abgr);
  142. m_customColor = ColorB(abgr);
  143. }
  144. SetNumKeys(num);
  145. for (int i = 0; i < num; i++)
  146. {
  147. I2DBezierKey key; // Must be inside loop.
  148. XmlNodeRef keyNode = xmlNode->getChild(i);
  149. if (!keyNode->getAttr("time", key.time))
  150. {
  151. CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing time information.");
  152. return false;
  153. }
  154. if (!keyNode->getAttr("value", key.value))
  155. {
  156. CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing value information.");
  157. return false;
  158. }
  159. //assert(key.time == key.value.x);
  160. keyNode->getAttr("flags", key.flags);
  161. SetKey(i, &key);
  162. // In-/Out-tangent
  163. if (!keyNode->getAttr("ds", m_spline->key(i).ds))
  164. {
  165. CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing ds spline information.");
  166. return false;
  167. }
  168. if (!keyNode->getAttr("dd", m_spline->key(i).dd))
  169. {
  170. CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:dd spline information.");
  171. return false;
  172. }
  173. }
  174. if ((!num) && (!bLoadEmptyTracks))
  175. {
  176. return false;
  177. }
  178. }
  179. else
  180. {
  181. int num = GetNumKeys();
  182. xmlNode->setAttr("Flags", GetFlags());
  183. xmlNode->setAttr("defaultValue", m_defaultValue);
  184. xmlNode->setAttr("HasCustomColor", m_bCustomColorSet);
  185. if (m_bCustomColorSet)
  186. {
  187. xmlNode->setAttr("CustomColor", m_customColor.pack_abgr8888());
  188. }
  189. I2DBezierKey key;
  190. for (int i = 0; i < num; i++)
  191. {
  192. GetKey(i, &key);
  193. XmlNodeRef keyNode = xmlNode->newChild("Key");
  194. assert(key.time == key.value.x);
  195. keyNode->setAttr("time", key.time);
  196. keyNode->setAttr("value", key.value);
  197. int flags = key.flags;
  198. // Just save the in/out/unify mask part. Others are for editing convenience.
  199. flags &= (SPLINE_KEY_TANGENT_IN_MASK | SPLINE_KEY_TANGENT_OUT_MASK | SPLINE_KEY_TANGENT_UNIFY_MASK);
  200. if (flags != 0)
  201. {
  202. keyNode->setAttr("flags", flags);
  203. }
  204. // We also have to save in-/out-tangents, because TCB infos are not used for custom tangent keys.
  205. keyNode->setAttr("ds", m_spline->key(i).ds);
  206. keyNode->setAttr("dd", m_spline->key(i).dd);
  207. }
  208. }
  209. return true;
  210. }
  211. template <>
  212. bool TUiAnimSplineTrack<Vec2>::SerializeSelection(XmlNodeRef& xmlNode, bool bLoading, bool bCopySelected, float fTimeOffset)
  213. {
  214. if (bLoading)
  215. {
  216. int numCur = GetNumKeys();
  217. int num = xmlNode->getChildCount();
  218. unsigned int type;
  219. xmlNode->getAttr("TrackType", type);
  220. if (type != GetCurveType())
  221. {
  222. return false;
  223. }
  224. SetNumKeys(num + numCur);
  225. for (int i = 0; i < num; i++)
  226. {
  227. I2DBezierKey key; // Must be inside loop.
  228. XmlNodeRef keyNode = xmlNode->getChild(i);
  229. keyNode->getAttr("time", key.time);
  230. keyNode->getAttr("value", key.value);
  231. assert(key.time == key.value.x);
  232. key.time += fTimeOffset;
  233. key.value.x += fTimeOffset;
  234. keyNode->getAttr("flags", key.flags);
  235. SetKey(i + numCur, &key);
  236. if (bCopySelected)
  237. {
  238. SelectKey(i + numCur, true);
  239. }
  240. // In-/Out-tangent
  241. keyNode->getAttr("ds", m_spline->key(i + numCur).ds);
  242. keyNode->getAttr("dd", m_spline->key(i + numCur).dd);
  243. }
  244. SortKeys();
  245. }
  246. else
  247. {
  248. int num = GetNumKeys();
  249. xmlNode->setAttr("TrackType", GetCurveType());
  250. I2DBezierKey key;
  251. for (int i = 0; i < num; i++)
  252. {
  253. GetKey(i, &key);
  254. assert(key.time == key.value.x);
  255. if (!bCopySelected || IsKeySelected(i))
  256. {
  257. XmlNodeRef keyNode = xmlNode->newChild("Key");
  258. keyNode->setAttr("time", key.time);
  259. keyNode->setAttr("value", key.value);
  260. int flags = key.flags;
  261. // Just save the in/out mask part. Others are for editing convenience.
  262. flags &= (SPLINE_KEY_TANGENT_IN_MASK | SPLINE_KEY_TANGENT_OUT_MASK);
  263. if (flags != 0)
  264. {
  265. keyNode->setAttr("flags", flags);
  266. }
  267. // We also have to save in-/out-tangents, because TCB infos are not used for custom tangent keys.
  268. keyNode->setAttr("ds", m_spline->key(i).ds);
  269. keyNode->setAttr("dd", m_spline->key(i).dd);
  270. }
  271. }
  272. }
  273. return true;
  274. }
  275. //////////////////////////////////////////////////////////////////////////
  276. template<>
  277. void TUiAnimSplineTrack<Vec2>::GetKeyInfo(int index, const char*& description, float& duration)
  278. {
  279. duration = 0;
  280. static char str[64];
  281. description = str;
  282. assert(index >= 0 && index < GetNumKeys());
  283. Spline::key_type& k = m_spline->key(index);
  284. sprintf_s(str, "%.2f", k.value.y);
  285. }
  286. //////////////////////////////////////////////////////////////////////////
  287. namespace UiSpline
  288. {
  289. using BezierSplineVec2 = BezierSpline<Vec2, SplineKeyEx<Vec2> >;
  290. using TSplineBezierBasisVec2 = TSpline<SplineKeyEx<Vec2>, spline::BezierBasis>;
  291. // Implement Reflection functions for Spline full template specializations in a cpp file
  292. //////////////////////////////////////////////////////////////////////////
  293. template <>
  294. void TSplineBezierBasisVec2::Reflect(AZ::ReflectContext* context);
  295. //////////////////////////////////////////////////////////////////////////
  296. template <>
  297. void BezierSplineVec2::Reflect(AZ::ReflectContext* context);
  298. AZ_TYPE_INFO_SPECIALIZE_WITH_NAME_DECL(TrackSplineInterpolator<Vec2>);
  299. AZ_TYPE_INFO_SPECIALIZE_WITH_NAME_IMPL(TrackSplineInterpolator<Vec2>, "TrackSplineInterpolator<Vec2>", "{38F814D4-6041-4442-9704-9F68E996D55B}");
  300. AZ_TYPE_INFO_SPECIALIZE(SplineKey<Vec2>, "{E2301E81-6BAF-4A17-886C-76F1A9C37118}");
  301. AZ_TYPE_INFO_SPECIALIZE(SplineKeyEx<Vec2>, "{1AE37C63-D5C2-4E65-A08B-7020E7696233}");
  302. AZ_TYPE_INFO_SPECIALIZE(BezierSplineVec2, "{EC8BA7BD-EF3B-453A-8017-CD1BF5B7C011}");
  303. AZ_TYPE_INFO_SPECIALIZE(TSplineBezierBasisVec2, "{B661D05E-B912-4BD9-B102-FA82938243A9}");
  304. template<>
  305. void SplineKey<Vec2>::Reflect(AZ::ReflectContext* context)
  306. {
  307. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  308. {
  309. serializeContext->Class<SplineKey<Vec2> >()
  310. ->Version(1)
  311. ->Field("time", &SplineKey<Vec2>::time)
  312. ->Field("flags", &SplineKey<Vec2>::flags)
  313. ->Field("value", &SplineKey<Vec2>::value)
  314. ->Field("ds", &SplineKey<Vec2>::ds)
  315. ->Field("dd", &SplineKey<Vec2>::dd);
  316. }
  317. }
  318. template<>
  319. void SplineKeyEx<Vec2>::Reflect(AZ::ReflectContext* context)
  320. {
  321. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  322. {
  323. serializeContext->Class<SplineKeyEx<Vec2>, SplineKey<Vec2> >()
  324. ->Version(1)
  325. ;
  326. }
  327. }
  328. template <>
  329. void TSplineBezierBasisVec2::Reflect(AZ::ReflectContext* context)
  330. {
  331. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  332. {
  333. serializeContext->Class<TSplineBezierBasisVec2>()
  334. ->Version(1)
  335. ->Field("Keys", &BezierSplineVec2::m_keys);
  336. }
  337. }
  338. //////////////////////////////////////////////////////////////////////////
  339. template <>
  340. void BezierSplineVec2::Reflect(AZ::ReflectContext* context)
  341. {
  342. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  343. {
  344. TSplineBezierBasisVec2::Reflect(serializeContext);
  345. serializeContext->Class<BezierSplineVec2, TSplineBezierBasisVec2>()
  346. ->Version(1)
  347. ;
  348. }
  349. }
  350. void TrackSplineInterpolator<Vec2>::Reflect(AZ::ReflectContext* context)
  351. {
  352. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  353. {
  354. serializeContext->Class<TrackSplineInterpolator<Vec2>,
  355. UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > >()
  356. ->Version(1)
  357. ;
  358. }
  359. }
  360. }
  361. // When TUiAnimSplineTrack<Vec2> is deserialized, a spline instance
  362. // is first created in the TUiAnimSplineTrack<Vec2> constructor (via AllocSpline()),
  363. // then the pointer is overwritten when "Spline" field is deserialized.
  364. // To prevent a memory leak, m_spline is now an intrusive pointer, so that if/when
  365. // the "Spline" field is deserialized, the old object will be deleted.
  366. static bool TUiAnimSplineTrackVec2VersionConverter(AZ::SerializeContext& context,
  367. AZ::SerializeContext::DataElementNode& classElement)
  368. {
  369. bool converted = false;
  370. if (classElement.GetVersion() == 1)
  371. {
  372. int splineElementIdx = classElement.FindElement(AZ_CRC("Spline", 0x35f655e9));
  373. if (splineElementIdx != -1)
  374. {
  375. // Find & copy the raw pointer node
  376. AZ::SerializeContext::DataElementNode& splinePtrNodeRef = classElement.GetSubElement(splineElementIdx);
  377. AZ::SerializeContext::DataElementNode splinePtrNodeCopy = splinePtrNodeRef;
  378. // Reset the node, then convert it to an intrusive pointer
  379. splinePtrNodeRef = AZ::SerializeContext::DataElementNode();
  380. const bool result = splinePtrNodeRef.Convert<AZStd::intrusive_ptr<UiSpline::TrackSplineInterpolator<Vec2>>>(context, "Spline");
  381. if (result)
  382. {
  383. // Use the standard name used with the smart pointers serialization
  384. // (smart pointers are serialized as containers with one element);
  385. // Set the intrusive pointer to the raw pointer value
  386. splinePtrNodeCopy.SetName(AZ::SerializeContext::IDataContainer::GetDefaultElementName());
  387. splinePtrNodeRef.AddElement(splinePtrNodeCopy);
  388. converted = true;
  389. }
  390. }
  391. }
  392. // Did not convert. Discard unknown versions if failed to convert, and hope for the best
  393. AZ_Assert(converted, "Failed to convert TUiAnimSplineTrack<Vec2> version %d to the current version", classElement.GetVersion());
  394. return converted;
  395. }
  396. template<>
  397. void TUiAnimSplineTrack<Vec2>::Reflect(AZ::ReflectContext* context)
  398. {
  399. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
  400. {
  401. UiSpline::SplineKey<Vec2>::Reflect(serializeContext);
  402. UiSpline::SplineKeyEx<Vec2>::Reflect(serializeContext);
  403. UiSpline::TrackSplineInterpolator<Vec2>::Reflect(serializeContext);
  404. UiSpline::BezierSplineVec2::Reflect(serializeContext);
  405. serializeContext->Class<TUiAnimSplineTrack<Vec2> >()
  406. ->Version(2, &TUiAnimSplineTrackVec2VersionConverter)
  407. ->Field("Flags", &TUiAnimSplineTrack<Vec2>::m_flags)
  408. ->Field("DefaultValue", &TUiAnimSplineTrack<Vec2>::m_defaultValue)
  409. ->Field("ParamType", &TUiAnimSplineTrack<Vec2>::m_nParamType)
  410. ->Field("ParamData", &TUiAnimSplineTrack<Vec2>::m_componentParamData)
  411. ->Field("Spline", &TUiAnimSplineTrack<Vec2>::m_spline);
  412. }
  413. }