UiAnimViewSplineCtrl.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  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 "UiEditorAnimationBus.h"
  9. #include "EditorDefs.h"
  10. #include "Editor/Resource.h"
  11. #include "UiAnimViewSequenceManager.h"
  12. #include "UiAnimViewSplineCtrl.h"
  13. #include "UiAnimViewSequence.h"
  14. #include "UiAnimViewDialog.h"
  15. #include "UiAnimViewUndo.h"
  16. #include "UiAnimViewTrack.h"
  17. #include <QMouseEvent>
  18. #include <QRubberBand>
  19. class CUndoUiAnimViewSplineCtrl
  20. : public ISplineCtrlUndo
  21. , public CUndoAnimKeySelection
  22. {
  23. public:
  24. CUndoUiAnimViewSplineCtrl(CUiAnimViewSplineCtrl* pCtrl, std::vector<ISplineInterpolator*>& splineContainer)
  25. : CUndoAnimKeySelection(CUiAnimViewSequenceManager::GetSequenceManager()->GetAnimationContext()->GetSequence())
  26. {
  27. m_sequenceName = QString::fromUtf8(CUiAnimViewSequenceManager::GetSequenceManager()->GetAnimationContext()->GetSequence()->GetName().c_str());
  28. m_pCtrl = pCtrl;
  29. // Loop over all affected splines
  30. for (size_t splineIndex = 0; splineIndex < splineContainer.size(); ++splineIndex)
  31. {
  32. AddSpline(splineContainer[splineIndex]);
  33. }
  34. SerializeSplines(&CSplineEntry::m_undo, false);
  35. }
  36. protected:
  37. void AddSpline(ISplineInterpolator* pSpline)
  38. {
  39. // Find corresponding track and remember it
  40. for (size_t trackIndex = 0; trackIndex < m_pCtrl->m_tracks.size(); ++trackIndex)
  41. {
  42. CUiAnimViewTrack* pTrack = m_pCtrl->m_tracks[trackIndex];
  43. if (pTrack->GetSpline() == pSpline)
  44. {
  45. CSplineEntry entry;
  46. entry.m_pTrack = pTrack;
  47. m_splineEntries.push_back(entry);
  48. }
  49. }
  50. }
  51. virtual int GetSize() { return sizeof(*this); }
  52. virtual const char* GetDescription() { return "UndoUiAnimViewSplineCtrl"; };
  53. virtual void Undo(bool bUndo)
  54. {
  55. CUiAnimViewSplineCtrl* pCtrl = FindControl(m_pCtrl);
  56. if (pCtrl)
  57. {
  58. pCtrl->SendNotifyEvent(SPLN_BEFORE_CHANGE);
  59. }
  60. const CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
  61. CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByName(m_sequenceName);
  62. assert(pSequence);
  63. if (!pSequence)
  64. {
  65. return;
  66. }
  67. CUiAnimViewSequenceNotificationContext context(pSequence);
  68. if (bUndo)
  69. {
  70. // Save key selection states for redo if necessary
  71. m_redoKeyStates = SaveKeyStates(pSequence);
  72. SerializeSplines(&CSplineEntry::m_redo, false);
  73. }
  74. SerializeSplines(&CSplineEntry::m_undo, true);
  75. // Undo key selection state
  76. RestoreKeyStates(pSequence, m_undoKeyStates);
  77. if (pCtrl && bUndo)
  78. {
  79. pCtrl->m_bKeyTimesDirty = true;
  80. pCtrl->SendNotifyEvent(SPLN_CHANGE);
  81. pCtrl->update();
  82. }
  83. if (bUndo)
  84. {
  85. pSequence->OnKeySelectionChanged();
  86. }
  87. }
  88. virtual void Redo()
  89. {
  90. const CUiAnimViewSequenceManager* pSequenceManager = CUiAnimViewSequenceManager::GetSequenceManager();
  91. CUiAnimViewSequence* pSequence = pSequenceManager->GetSequenceByName(m_sequenceName);
  92. assert(pSequence);
  93. if (!pSequence)
  94. {
  95. return;
  96. }
  97. CUiAnimViewSequenceNotificationContext context(pSequence);
  98. CUiAnimViewSplineCtrl* pCtrl = FindControl(m_pCtrl);
  99. if (pCtrl)
  100. {
  101. pCtrl->SendNotifyEvent(SPLN_BEFORE_CHANGE);
  102. }
  103. SerializeSplines(&CSplineEntry::m_redo, true);
  104. // Redo key selection state
  105. RestoreKeyStates(pSequence, m_redoKeyStates);
  106. if (pCtrl)
  107. {
  108. pCtrl->m_bKeyTimesDirty = true;
  109. pCtrl->SendNotifyEvent(SPLN_CHANGE);
  110. pCtrl->update();
  111. }
  112. pSequence->OnKeySelectionChanged();
  113. }
  114. virtual bool IsSelectionChanged() const
  115. {
  116. return CUndoAnimKeySelection::IsSelectionChanged();
  117. }
  118. public:
  119. typedef std::list<CUiAnimViewSplineCtrl*> CUiAnimViewSplineCtrls;
  120. static CUiAnimViewSplineCtrl* FindControl(CUiAnimViewSplineCtrl* pCtrl)
  121. {
  122. if (!pCtrl)
  123. {
  124. return 0;
  125. }
  126. auto iter = std::find(s_activeCtrls.begin(), s_activeCtrls.end(), pCtrl);
  127. if (iter == s_activeCtrls.end())
  128. {
  129. return 0;
  130. }
  131. return *iter;
  132. }
  133. static void RegisterControl(CUiAnimViewSplineCtrl* pCtrl)
  134. {
  135. if (!FindControl(pCtrl))
  136. {
  137. s_activeCtrls.push_back(pCtrl);
  138. }
  139. }
  140. static void UnregisterControl(CUiAnimViewSplineCtrl* pCtrl)
  141. {
  142. if (FindControl(pCtrl))
  143. {
  144. s_activeCtrls.remove(pCtrl);
  145. }
  146. }
  147. static CUiAnimViewSplineCtrls s_activeCtrls;
  148. private:
  149. class CSplineEntry
  150. {
  151. public:
  152. _smart_ptr<ISplineBackup> m_undo;
  153. _smart_ptr<ISplineBackup> m_redo;
  154. CUiAnimViewTrack* m_pTrack;
  155. };
  156. void SerializeSplines(_smart_ptr<ISplineBackup> CSplineEntry::* backup, bool bLoading)
  157. {
  158. for (auto it = m_splineEntries.begin(); it != m_splineEntries.end(); ++it)
  159. {
  160. CSplineEntry& entry = *it;
  161. ISplineInterpolator* pSpline = entry.m_pTrack->GetSpline();
  162. if (pSpline && bLoading)
  163. {
  164. pSpline->Restore(entry.*backup);
  165. }
  166. else if (pSpline)
  167. {
  168. (entry.*backup) = pSpline->Backup();
  169. }
  170. }
  171. }
  172. QString m_sequenceName;
  173. CUiAnimViewSplineCtrl* m_pCtrl;
  174. std::vector<CSplineEntry> m_splineEntries;
  175. std::vector<float> m_keyTimes;
  176. };
  177. CUndoUiAnimViewSplineCtrl::CUiAnimViewSplineCtrls CUndoUiAnimViewSplineCtrl::s_activeCtrls;
  178. //////////////////////////////////////////////////////////////////////////
  179. CUiAnimViewSplineCtrl::CUiAnimViewSplineCtrl(QWidget* parent)
  180. : SplineWidget(parent)
  181. , m_bKeysFreeze(false)
  182. , m_bTangentsFreeze(false)
  183. {
  184. CUndoUiAnimViewSplineCtrl::RegisterControl(this);
  185. }
  186. CUiAnimViewSplineCtrl::~CUiAnimViewSplineCtrl()
  187. {
  188. CUndoUiAnimViewSplineCtrl::UnregisterControl(this);
  189. }
  190. bool CUiAnimViewSplineCtrl::GetTangentHandlePts(QPoint& inTangentPt, QPoint& pt, QPoint& outTangentPt,
  191. int nSpline, int nKey, int nDimension)
  192. {
  193. ISplineInterpolator* pSpline = m_splines[nSpline].pSpline;
  194. CUiAnimViewTrack* pTrack = m_tracks[nSpline];
  195. float time = pSpline->GetKeyTime(nKey);
  196. ISplineInterpolator::ValueType value, tin, tout;
  197. ISplineInterpolator::ZeroValue(value);
  198. pSpline->GetKeyValue(nKey, value);
  199. pSpline->GetKeyTangents(nKey, tin, tout);
  200. CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(nKey);
  201. if (pTrack->GetCurveType() == eUiAnimCurveType_TCBFloat)
  202. {
  203. ITcbKey tcbKey;
  204. keyHandle.GetKey(&tcbKey);
  205. Vec2 va, vb, vc;
  206. va.x = time - 1.0f;
  207. va.y = value[nDimension] - tin[nDimension];
  208. vb.x = time;
  209. vb.y = value[nDimension];
  210. vc.x = time + 1.0f;
  211. vc.y = value[nDimension] + tout[nDimension];
  212. inTangentPt = WorldToClient(va);
  213. pt = WorldToClient(vb);
  214. outTangentPt = WorldToClient(vc);
  215. Vec2 tinv, toutv;
  216. float maxLength = float(outTangentPt.x() - pt.x());
  217. tinv.x = float(inTangentPt.x() - pt.x());
  218. tinv.y = float(inTangentPt.y() - pt.y());
  219. toutv.x = float(outTangentPt.x() - pt.x());
  220. toutv.y = float(outTangentPt.y() - pt.y());
  221. tinv.Normalize();
  222. toutv.Normalize();
  223. tinv *= maxLength / (2 - tcbKey.easeto);
  224. toutv *= maxLength / (2 - tcbKey.easefrom);
  225. inTangentPt = pt + QPoint(int(tinv.x), int(tinv.y));
  226. outTangentPt = pt + QPoint(int(toutv.x), int(toutv.y));
  227. }
  228. else
  229. {
  230. assert(pTrack->GetCurveType() == eUiAnimCurveType_BezierFloat);
  231. assert(nDimension == 0);
  232. I2DBezierKey bezierKey;
  233. keyHandle.GetKey(&bezierKey);
  234. Vec2 va, vb, vc;
  235. va.x = time - tin[0];
  236. va.y = value[0] - tin[1];
  237. vb.x = time;
  238. vb.y = value[0];
  239. vc.x = time + tout[0];
  240. vc.y = value[0] + tout[1];
  241. inTangentPt = WorldToClient(va);
  242. pt = WorldToClient(vb);
  243. outTangentPt = WorldToClient(vc);
  244. }
  245. return true;
  246. }
  247. void CUiAnimViewSplineCtrl::ComputeIncomingTangentAndEaseTo(float& ds, float& easeTo, QPoint inTangentPt,
  248. int nSpline, int nKey, int nDimension)
  249. {
  250. ISplineInterpolator* pSpline = m_splines[nSpline].pSpline;
  251. CUiAnimViewTrack* pTrack = m_tracks[nSpline];
  252. float time = pSpline->GetKeyTime(nKey);
  253. ISplineInterpolator::ValueType value, tin, tout;
  254. ISplineInterpolator::ZeroValue(value);
  255. pSpline->GetKeyValue(nKey, value);
  256. pSpline->GetKeyTangents(nKey, tin, tout);
  257. CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(nKey);
  258. ITcbKey tcbKey;
  259. keyHandle.GetKey(&tcbKey);
  260. // Get the control point.
  261. Vec2 tinv, vb;
  262. vb.x = time;
  263. vb.y = value[nDimension];
  264. QPoint pt = WorldToClient(vb);
  265. // Get the max length to compute the 'ease' value.
  266. float maxLength = float(WorldToClient(Vec2(vb.x + 1, vb.y)).x() - pt.x());
  267. QPoint tmp = inTangentPt - pt;
  268. tinv.x = float(tmp.x());
  269. tinv.y = float(tmp.y());
  270. // Compute the 'easeTo'.
  271. easeTo = 2.0f - maxLength / tinv.GetLength();
  272. // Compute the 'ds'.
  273. Vec2 va = ClientToWorld(inTangentPt);
  274. if (time < va.x + 0.000001f)
  275. {
  276. if (value[nDimension] > va.y)
  277. {
  278. ds = 1000000.0f;
  279. }
  280. else
  281. {
  282. ds = -1000000.0f;
  283. }
  284. }
  285. else
  286. {
  287. ds = (value[nDimension] - va.y) / (time - va.x);
  288. }
  289. }
  290. void CUiAnimViewSplineCtrl::ComputeOutgoingTangentAndEaseFrom(float& dd, float& easeFrom, QPoint outTangentPt,
  291. int nSpline, int nKey, int nDimension)
  292. {
  293. ISplineInterpolator* pSpline = m_splines[nSpline].pSpline;
  294. CUiAnimViewTrack* pTrack = m_tracks[nSpline];
  295. float time = pSpline->GetKeyTime(nKey);
  296. ISplineInterpolator::ValueType value, tin, tout;
  297. ISplineInterpolator::ZeroValue(value);
  298. pSpline->GetKeyValue(nKey, value);
  299. pSpline->GetKeyTangents(nKey, tin, tout);
  300. CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(nKey);
  301. ITcbKey tcbKey;
  302. keyHandle.GetKey(&tcbKey);
  303. // Get the control point.
  304. Vec2 toutv, vb;
  305. vb.x = time;
  306. vb.y = value[nDimension];
  307. QPoint pt = WorldToClient(vb);
  308. // Get the max length to comute the 'ease' value.
  309. float maxLength = float(WorldToClient(Vec2(vb.x + 1, vb.y)).x() - pt.x());
  310. QPoint tmp = outTangentPt - pt;
  311. toutv.x = float(tmp.x());
  312. toutv.y = float(tmp.y());
  313. // Compute the 'easeFrom'.
  314. easeFrom = 2.0f - maxLength / toutv.GetLength();
  315. // Compute the 'dd'.
  316. Vec2 vc = ClientToWorld(outTangentPt);
  317. if (vc.x < time + 0.000001f)
  318. {
  319. if (value[nDimension] < vc.y)
  320. {
  321. dd = 1000000.0f;
  322. }
  323. else
  324. {
  325. dd = -1000000.0f;
  326. }
  327. }
  328. else
  329. {
  330. dd = (vc.y - value[nDimension]) / (vc.x - time);
  331. }
  332. }
  333. void CUiAnimViewSplineCtrl::AddSpline(ISplineInterpolator* pSpline, CUiAnimViewTrack* pTrack, const QColor& color)
  334. {
  335. QColor colorArray[4];
  336. colorArray[0] = colorArray[1] = colorArray[2] = colorArray[3] = color;
  337. AddSpline(pSpline, pTrack, colorArray);
  338. }
  339. void CUiAnimViewSplineCtrl::AddSpline(ISplineInterpolator* pSpline, CUiAnimViewTrack* pTrack, QColor anColorArray[4])
  340. {
  341. for (int i = 0; i < (int)m_splines.size(); i++)
  342. {
  343. if (m_splines[i].pSpline == pSpline)
  344. {
  345. return;
  346. }
  347. }
  348. SSplineInfo si;
  349. for (int nCurrentDimension = 0; nCurrentDimension < pSpline->GetNumDimensions(); nCurrentDimension++)
  350. {
  351. si.anColorArray[nCurrentDimension] = anColorArray[nCurrentDimension];
  352. }
  353. si.pSpline = pSpline;
  354. si.pDetailSpline = NULL;
  355. m_splines.push_back(si);
  356. m_tracks.push_back(pTrack);
  357. m_bKeyTimesDirty = true;
  358. update();
  359. }
  360. void CUiAnimViewSplineCtrl::RemoveAllSplines()
  361. {
  362. m_tracks.clear();
  363. SplineWidget::RemoveAllSplines();
  364. }
  365. void CUiAnimViewSplineCtrl::MoveSelectedTangentHandleTo(const QPoint& point)
  366. {
  367. assert(m_pHitSpline && m_nHitKeyIndex >= 0 && m_bHitIncomingHandle >= 0);
  368. // Set the custom flag to the key.
  369. int nRemoveFlags, nAddFlags;
  370. if (m_bHitIncomingHandle)
  371. {
  372. nRemoveFlags = SPLINE_KEY_TANGENT_IN_MASK;
  373. nAddFlags = SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_IN_SHIFT;
  374. }
  375. else
  376. {
  377. nRemoveFlags = SPLINE_KEY_TANGENT_OUT_MASK;
  378. nAddFlags = SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_OUT_SHIFT;
  379. }
  380. int flags = m_pHitSpline->GetKeyFlags(m_nHitKeyIndex);
  381. flags &= ~nRemoveFlags;
  382. flags |= nAddFlags;
  383. m_pHitSpline->SetKeyFlags(m_nHitKeyIndex, flags);
  384. // Adjust the incoming or outgoing tangent.
  385. int splineIndex;
  386. for (splineIndex = 0; splineIndex < m_splines.size(); ++splineIndex)
  387. {
  388. if (m_pHitSpline == m_splines[splineIndex].pSpline)
  389. {
  390. break;
  391. }
  392. }
  393. assert(splineIndex < m_splines.size());
  394. CUiAnimViewTrack* pTrack = m_tracks[splineIndex];
  395. CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(m_nHitKeyIndex);
  396. if (pTrack->GetCurveType() == eUiAnimCurveType_TCBFloat)
  397. {
  398. if (m_bHitIncomingHandle)
  399. {
  400. float ds, easeTo;
  401. ComputeIncomingTangentAndEaseTo(ds, easeTo, point, splineIndex, m_nHitKeyIndex, m_nHitDimension);
  402. // ease-to
  403. ITcbKey key;
  404. keyHandle.GetKey(&key);
  405. key.easeto += easeTo;
  406. if (key.easeto > 1)
  407. {
  408. key.easeto = 1.0f;
  409. }
  410. else if (key.easeto < 0)
  411. {
  412. key.easeto = 0;
  413. }
  414. keyHandle.SetKey(&key);
  415. // tin
  416. ISplineInterpolator::ValueType tin, tout;
  417. m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
  418. tin[m_nHitDimension] = ds;
  419. m_pHitSpline->SetKeyInTangent(m_nHitKeyIndex, tin);
  420. }
  421. else
  422. {
  423. float dd, easeFrom;
  424. ComputeOutgoingTangentAndEaseFrom(dd, easeFrom, point, splineIndex, m_nHitKeyIndex, m_nHitDimension);
  425. // ease-from
  426. ITcbKey key;
  427. keyHandle.GetKey(&key);
  428. key.easefrom += easeFrom;
  429. if (key.easefrom > 1)
  430. {
  431. key.easefrom = 1.0f;
  432. }
  433. else if (key.easefrom < 0)
  434. {
  435. key.easefrom = 0;
  436. }
  437. keyHandle.SetKey(&key);
  438. // tout
  439. ISplineInterpolator::ValueType tin, tout;
  440. m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
  441. tout[m_nHitDimension] = dd;
  442. m_pHitSpline->SetKeyOutTangent(m_nHitKeyIndex, tout);
  443. }
  444. }
  445. else
  446. {
  447. assert(pTrack->GetCurveType() == eUiAnimCurveType_BezierFloat);
  448. assert(m_nHitDimension == 0);
  449. Vec2 tp = ClientToWorld(point);
  450. if (m_bHitIncomingHandle)
  451. {
  452. // tin
  453. ISplineInterpolator::ValueType value, tin, tout;
  454. float time = m_pHitSpline->GetKeyTime(m_nHitKeyIndex);
  455. m_pHitSpline->GetKeyValue(m_nHitKeyIndex, value);
  456. m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
  457. tin[0] = time - tp.x;
  458. // Constrain the time range so that the time curve is always monotonically increasing.
  459. if (tin[0] < 0)
  460. {
  461. tin[0] = 0;
  462. }
  463. else if (m_nHitKeyIndex > 0
  464. && tin[0] > (time - m_pHitSpline->GetKeyTime(m_nHitKeyIndex - 1)))
  465. {
  466. tin[0] = time - m_pHitSpline->GetKeyTime(m_nHitKeyIndex - 1);
  467. }
  468. tin[1] = value[0] - tp.y;
  469. m_pHitSpline->SetKeyInTangent(m_nHitKeyIndex, tin);
  470. }
  471. else
  472. {
  473. // tout
  474. ISplineInterpolator::ValueType value, tin, tout;
  475. float time = m_pHitSpline->GetKeyTime(m_nHitKeyIndex);
  476. m_pHitSpline->GetKeyValue(m_nHitKeyIndex, value);
  477. m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
  478. tout[0] = tp.x - time;
  479. // Constrain the time range so that the time curve is always monotonically increasing.
  480. if (tout[0] < 0)
  481. {
  482. tout[0] = 0;
  483. }
  484. else if (m_nHitKeyIndex < m_pHitSpline->GetKeyCount() - 1
  485. && tout[0] > (m_pHitSpline->GetKeyTime(m_nHitKeyIndex + 1) - time))
  486. {
  487. tout[0] = m_pHitSpline->GetKeyTime(m_nHitKeyIndex + 1) - time;
  488. }
  489. tout[1] = tp.y - value[0];
  490. m_pHitSpline->SetKeyOutTangent(m_nHitKeyIndex, tout);
  491. }
  492. }
  493. SendNotifyEvent(SPLN_CHANGE);
  494. update();
  495. }
  496. void CUiAnimViewSplineCtrl::mouseMoveEvent(QMouseEvent* event)
  497. {
  498. const QPoint point = event->pos();
  499. CUiAnimViewSequence* pSequence = nullptr;
  500. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  501. if (!pSequence)
  502. {
  503. return;
  504. }
  505. CUiAnimViewSequenceNotificationContext context(pSequence);
  506. m_cMousePos = point;
  507. if (m_editMode == SelectMode)
  508. {
  509. unsetCursor();
  510. QRect rc(m_cMouseDownPos, point);
  511. rc = rc.normalized().intersected(m_rcSpline);
  512. m_rcSelect = rc;
  513. m_rubberBand->setGeometry(m_rcSelect);
  514. m_rubberBand->setVisible(true);
  515. }
  516. if (m_editMode == TimeMarkerMode)
  517. {
  518. unsetCursor();
  519. SetTimeMarker(XOfsToTime(point.x()));
  520. SendNotifyEvent(SPLN_TIME_CHANGE);
  521. }
  522. if (m_boLeftMouseButtonDown)
  523. {
  524. if (m_editMode == TrackingMode && point != m_cMouseDownPos)
  525. {
  526. m_startedDragging = true;
  527. UiAnimUndoManager::Get()->Restore();
  528. m_pCurrentUndo = nullptr;
  529. StoreUndo();
  530. bool bAltClick = CheckVirtualKey(Qt::Key_Menu);
  531. bool bShiftClick = CheckVirtualKey(Qt::Key_Shift);
  532. bool bSpaceClick = CheckVirtualKey(Qt::Key_Space);
  533. Vec2 v0 = ClientToWorld(m_cMouseDownPos);
  534. Vec2 v1 = ClientToWorld(point);
  535. if (m_hitCode == HIT_TANGENT_HANDLE)
  536. {
  537. if (!m_bTangentsFreeze)
  538. {
  539. MoveSelectedTangentHandleTo(point);
  540. }
  541. }
  542. else if (!m_bKeysFreeze)
  543. {
  544. if (bAltClick && bShiftClick)
  545. {
  546. ValueScaleKeys(v0.y, v1.y);
  547. }
  548. else if (bAltClick)
  549. {
  550. TimeScaleKeys(m_fTimeMarker, v0.x, v1.x);
  551. }
  552. else if (bShiftClick)
  553. {
  554. // Constrains the move to the vertical direction.
  555. MoveSelectedKeys(Vec2(0, v1.y - v0.y), false);
  556. }
  557. else if (bSpaceClick)
  558. {
  559. // Reset to the original position.
  560. MoveSelectedKeys(Vec2(0, 0), false);
  561. }
  562. else
  563. {
  564. MoveSelectedKeys(v1 - v0, m_copyKeys);
  565. }
  566. }
  567. }
  568. }
  569. if (m_editMode == TrackingMode && GetNumSelected() == 1)
  570. {
  571. float time = 0;
  572. ISplineInterpolator::ValueType afValue;
  573. QString tipText;
  574. bool boFoundTheSelectedKey(false);
  575. for (size_t splineIndex = 0, endSpline = m_splines.size(); splineIndex < endSpline; ++splineIndex)
  576. {
  577. ISplineInterpolator* pSpline = m_splines[splineIndex].pSpline;
  578. CUiAnimViewTrack* pTrack = m_tracks[splineIndex];
  579. for (int i = 0; i < pSpline->GetKeyCount(); i++)
  580. {
  581. CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(i);
  582. for (int nCurrentDimension = 0; nCurrentDimension < pSpline->GetNumDimensions(); nCurrentDimension++)
  583. {
  584. if (pSpline->IsKeySelectedAtDimension(i, nCurrentDimension))
  585. {
  586. time = pSpline->GetKeyTime(i);
  587. pSpline->GetKeyValue(i, afValue);
  588. if (pTrack->GetCurveType() == eUiAnimCurveType_TCBFloat)
  589. {
  590. ITcbKey key;
  591. keyHandle.GetKey(&key);
  592. tipText = QStringLiteral("t=%1 v=%2 / T=%3 C=%4 B=%5")
  593. .arg(time * m_fTooltipScaleX, 0, 'f', 3).arg(afValue[nCurrentDimension] * m_fTooltipScaleY, 2, 'f', 3)
  594. .arg(key.tens, 0, 'f', 3).arg(key.cont, 0, 'f', 3).arg(key.bias, 0, 'f', 3);
  595. }
  596. else
  597. {
  598. assert(pTrack->GetCurveType() == eUiAnimCurveType_BezierFloat);
  599. ISplineInterpolator::ValueType tin, tout;
  600. pSpline->GetKeyTangents(i, tin, tout);
  601. tipText = QStringLiteral("t=%1 v=%2 / tin=(%3,%4) tout=(%5,%6)")
  602. .arg(time * m_fTooltipScaleX, 0, 'f', 3).arg(afValue[0] * m_fTooltipScaleY, 2, 'f', 3)
  603. .arg(tin[0], 0, 'f', 3).arg(tin[1], 2, 'f', 3).arg(tout[0], 0, 'f', 3).arg(tout[1], 2, 'f', 3);
  604. }
  605. boFoundTheSelectedKey = true;
  606. break;
  607. }
  608. }
  609. if (boFoundTheSelectedKey)
  610. {
  611. break;
  612. }
  613. }
  614. }
  615. if (point != m_lastToolTipPos)
  616. {
  617. m_lastToolTipPos = point;
  618. m_tooltipText = tipText;
  619. update();
  620. }
  621. }
  622. switch (m_editMode)
  623. {
  624. case ScrollMode:
  625. {
  626. // Set the new scrolled coordinates
  627. const float ofsx = m_grid.origin.GetX() - (point.x() - m_cMouseDownPos.x()) / m_grid.zoom.GetX();
  628. const float ofsy = m_grid.origin.GetY() + (point.y() - m_cMouseDownPos.y()) / m_grid.zoom.GetY();
  629. SetScrollOffset(Vec2(ofsx, ofsy));
  630. m_cMouseDownPos = point;
  631. }
  632. break;
  633. case ZoomMode:
  634. {
  635. const float ofsx = (point.x() - m_cMouseDownPos.x()) * 0.01f;
  636. const float ofsy = (point.y() - m_cMouseDownPos.y()) * 0.01f;
  637. AZ::Vector2 z = m_grid.zoom;
  638. if (ofsx != 0)
  639. {
  640. z.SetX(max(z.GetX() * (1.0f + ofsx), 0.001f));
  641. }
  642. if (ofsy != 0)
  643. {
  644. z.SetY(max(z.GetY() * (1.0f + ofsy), 0.001f));
  645. }
  646. SetZoom(Vec2(z.GetX(), z.GetY()), m_cMouseDownPos);
  647. m_cMouseDownPos = point;
  648. }
  649. break;
  650. }
  651. }
  652. void CUiAnimViewSplineCtrl::AdjustTCB(float d_tension, float d_continuity, float d_bias)
  653. {
  654. UiAnimUndo undo("Modify Spline Keys TCB");
  655. ConditionalStoreUndo();
  656. SendNotifyEvent(SPLN_BEFORE_CHANGE);
  657. for (size_t splineIndex = 0, splineCount = m_splines.size(); splineIndex < splineCount; ++splineIndex)
  658. {
  659. ISplineInterpolator* pSpline = m_splines[splineIndex].pSpline;
  660. CUiAnimViewTrack* pTrack = m_tracks[splineIndex];
  661. if (pTrack->GetCurveType() != eUiAnimCurveType_TCBFloat)
  662. {
  663. continue;
  664. }
  665. for (int i = 0; i < (int)pSpline->GetKeyCount(); i++)
  666. {
  667. CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(i);
  668. // If the key is selected in any dimension...
  669. for (
  670. int nCurrentDimension = 0;
  671. nCurrentDimension < pSpline->GetNumDimensions();
  672. nCurrentDimension++
  673. )
  674. {
  675. if (IsKeySelected(pSpline, i, nCurrentDimension))
  676. {
  677. ITcbKey key;
  678. keyHandle.GetKey(&key);
  679. // tension
  680. key.tens += d_tension;
  681. if (key.tens > 1)
  682. {
  683. key.tens = 1.0f;
  684. }
  685. else if (key.tens < -1)
  686. {
  687. key.tens = -1.0f;
  688. }
  689. // continuity
  690. key.cont += d_continuity;
  691. if (key.cont > 1)
  692. {
  693. key.cont = 1.0f;
  694. }
  695. else if (key.cont < -1)
  696. {
  697. key.cont = -1.0f;
  698. }
  699. // bias
  700. key.bias += d_bias;
  701. if (key.bias > 1)
  702. {
  703. key.bias = 1.0f;
  704. }
  705. else if (key.bias < -1)
  706. {
  707. key.bias = -1.0f;
  708. }
  709. keyHandle.SetKey(&key);
  710. OnUserCommand(ID_TANGENT_AUTO);
  711. break;
  712. }
  713. }
  714. }
  715. }
  716. SendNotifyEvent(SPLN_CHANGE);
  717. update();
  718. }
  719. void CUiAnimViewSplineCtrl::OnUserCommand(UINT cmd)
  720. {
  721. CUiAnimViewSequence* pSequence = nullptr;
  722. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  723. if (!pSequence)
  724. {
  725. return; // no active sequence
  726. }
  727. if (cmd == ID_TANGENT_UNIFY)
  728. {
  729. // do nothing if there are no splines
  730. if (m_splines.size() == 0)
  731. {
  732. return;
  733. }
  734. if (IsUnifiedKeyCurrentlySelected() == false)
  735. {
  736. ModifySelectedKeysFlags(SPLINE_KEY_TANGENT_ALL_MASK, SPLINE_KEY_TANGENT_UNIFIED);
  737. }
  738. else
  739. {
  740. ModifySelectedKeysFlags(SPLINE_KEY_TANGENT_ALL_MASK, SPLINE_KEY_TANGENT_BROKEN);
  741. }
  742. }
  743. else if (cmd == ID_FREEZE_KEYS)
  744. {
  745. m_bKeysFreeze = !m_bKeysFreeze;
  746. }
  747. else if (cmd == ID_FREEZE_TANGENTS)
  748. {
  749. m_bTangentsFreeze = !m_bTangentsFreeze;
  750. }
  751. else
  752. {
  753. SplineWidget::OnUserCommand(cmd);
  754. }
  755. }
  756. bool CUiAnimViewSplineCtrl::IsUnifiedKeyCurrentlySelected() const
  757. {
  758. for (size_t splineIndex = 0, splineCount = m_splines.size(); splineIndex < splineCount; ++splineIndex)
  759. {
  760. ISplineInterpolator* pSpline = m_splines[splineIndex].pSpline;
  761. if (!pSpline)
  762. {
  763. continue;
  764. }
  765. for (int i = 0; i < pSpline->GetKeyCount(); i++)
  766. {
  767. // If the key is selected in any dimension...
  768. for (
  769. int nCurrentDimension = 0;
  770. nCurrentDimension < pSpline->GetNumDimensions();
  771. nCurrentDimension++
  772. )
  773. {
  774. if (IsKeySelected(pSpline, i, nCurrentDimension))
  775. {
  776. int flags = pSpline->GetKeyFlags(i);
  777. if ((flags & SPLINE_KEY_TANGENT_ALL_MASK) != SPLINE_KEY_TANGENT_UNIFIED)
  778. {
  779. return false;
  780. }
  781. }
  782. }
  783. }
  784. }
  785. return true;
  786. }
  787. void CUiAnimViewSplineCtrl::ClearSelection()
  788. {
  789. // In this case, we should deselect all keys, even ones in other tracks.
  790. // So this overriding is necessary.
  791. CUiAnimViewSequence* pSequence = nullptr;
  792. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  793. if (pSequence)
  794. {
  795. pSequence->DeselectAllKeys();
  796. }
  797. }
  798. ISplineCtrlUndo* CUiAnimViewSplineCtrl::CreateSplineCtrlUndoObject(std::vector<ISplineInterpolator*>& splineContainer)
  799. {
  800. return new CUndoUiAnimViewSplineCtrl(this, splineContainer);
  801. }
  802. void CUiAnimViewSplineCtrl::mousePressEvent(QMouseEvent* event)
  803. {
  804. CUiAnimViewSequence* pSequence = nullptr;
  805. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  806. if (pSequence)
  807. {
  808. SplineWidget::mousePressEvent(event);
  809. }
  810. }
  811. void CUiAnimViewSplineCtrl::mouseReleaseEvent(QMouseEvent* event)
  812. {
  813. CUiAnimViewSequence* pSequence = nullptr;
  814. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  815. if (pSequence)
  816. {
  817. SplineWidget::mouseReleaseEvent(event);
  818. }
  819. }
  820. void CUiAnimViewSplineCtrl::mouseDoubleClickEvent(QMouseEvent* event)
  821. {
  822. CUiAnimViewSequence* pSequence = nullptr;
  823. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  824. if (pSequence)
  825. {
  826. SplineWidget::mouseDoubleClickEvent(event);
  827. }
  828. }
  829. void CUiAnimViewSplineCtrl::keyPressEvent(QKeyEvent* event)
  830. {
  831. CUiAnimViewSequence* pSequence = nullptr;
  832. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  833. if (pSequence)
  834. {
  835. SplineWidget::keyPressEvent(event);
  836. if (event->key() == Qt::Key_S && m_playCallback)
  837. {
  838. m_playCallback();
  839. }
  840. }
  841. }
  842. void CUiAnimViewSplineCtrl::wheelEvent(QWheelEvent* event)
  843. {
  844. CUiAnimViewSequence* pSequence = nullptr;
  845. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  846. if (pSequence)
  847. {
  848. SplineWidget::wheelEvent(event);
  849. }
  850. }
  851. void CUiAnimViewSplineCtrl::SelectKey(ISplineInterpolator* pSpline, int nKey, int nDimension, bool bSelect)
  852. {
  853. SplineWidget::SelectKey(pSpline, nKey, nDimension, bSelect);
  854. CUiAnimViewSequence* pSequence = nullptr;
  855. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  856. pSequence->OnKeySelectionChanged();
  857. }
  858. void CUiAnimViewSplineCtrl::SelectRectangle(const QRect& rc, bool bSelect)
  859. {
  860. SplineWidget::SelectRectangle(rc, bSelect);
  861. CUiAnimViewSequence* pSequence = nullptr;
  862. UiEditorAnimationBus::BroadcastResult(pSequence, &UiEditorAnimationBus::Events::GetCurrentSequence);
  863. pSequence->OnKeySelectionChanged();
  864. }
  865. void CUiAnimViewSplineCtrl::SetPlayCallback(const std::function<void()>& callback)
  866. {
  867. m_playCallback = callback;
  868. }