AnimationContext.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  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 "EditorDefs.h"
  9. #include "AnimationContext.h"
  10. // CryCommon
  11. #include <CryCommon/Maestro/Bus/EditorSequenceBus.h>
  12. // Editor
  13. #include "TrackView/TrackViewDialog.h"
  14. #include "ViewManager.h"
  15. #include <AzCore/Serialization/Locale.h>
  16. #include <AzCore/Time/ITime.h>
  17. #include <AzToolsFramework/API/EditorCameraBus.h>
  18. //////////////////////////////////////////////////////////////////////////
  19. // Movie Callback.
  20. //////////////////////////////////////////////////////////////////////////
  21. class CMovieCallback
  22. : public IMovieCallback
  23. {
  24. protected:
  25. void OnMovieCallback(ECallbackReason reason, [[maybe_unused]] IAnimNode* pNode) override
  26. {
  27. switch (reason)
  28. {
  29. case CBR_CHANGENODE:
  30. // Invalidate nodes
  31. break;
  32. case CBR_CHANGETRACK:
  33. {
  34. // Invalidate tracks
  35. CTrackViewDialog* pTrackViewDialog = CTrackViewDialog::GetCurrentInstance();
  36. if (pTrackViewDialog)
  37. {
  38. pTrackViewDialog->InvalidateDopeSheet();
  39. }
  40. }
  41. break;
  42. }
  43. }
  44. bool IsSequenceCamUsed() const override
  45. {
  46. if (gEnv->IsEditorGameMode() == true)
  47. {
  48. return true;
  49. }
  50. if (GetIEditor()->GetViewManager() == nullptr)
  51. {
  52. return false;
  53. }
  54. CViewport* pRendView = GetIEditor()->GetViewManager()->GetViewport(ET_ViewportCamera);
  55. if (pRendView)
  56. {
  57. return pRendView->IsSequenceCamera();
  58. }
  59. return false;
  60. }
  61. };
  62. static CMovieCallback s_movieCallback;
  63. //////////////////////////////////////////////////////////////////////////
  64. //-----------------------------------------------------------------------------
  65. //!
  66. class CAnimationContextPostRender
  67. : public IPostRenderer
  68. {
  69. public:
  70. CAnimationContextPostRender(CAnimationContext* pAC)
  71. : m_pAC(pAC){}
  72. void OnPostRender() const override { assert(m_pAC); m_pAC->OnPostRender(); }
  73. protected:
  74. CAnimationContext* m_pAC;
  75. };
  76. //////////////////////////////////////////////////////////////////////////
  77. CAnimationContext::CAnimationContext()
  78. : m_movieSystem(AZ::Interface<IMovieSystem>::Get())
  79. {
  80. m_paused = 0;
  81. m_playing = false;
  82. m_recording = false;
  83. m_bSavedRecordingState = false;
  84. m_timeRange.Set(0, 0);
  85. m_timeMarker.Set(0, 0);
  86. m_currTime = 0.0f;
  87. m_lastTimeChangedNotificationTime = .0f;
  88. m_bForceUpdateInNextFrame = false;
  89. m_fTimeScale = 1.0f;
  90. m_pSequence = nullptr;
  91. m_mostRecentSequenceId.SetInvalid();
  92. m_mostRecentSequenceTime = 0.0f;
  93. m_bLooping = false;
  94. m_bAutoRecording = false;
  95. m_fRecordingTimeStep = 0;
  96. m_bSingleFrame = false;
  97. m_bPostRenderRegistered = false;
  98. m_bForcingAnimation = false;
  99. GetIEditor()->GetUndoManager()->AddListener(this);
  100. GetIEditor()->GetSequenceManager()->AddListener(this);
  101. GetIEditor()->RegisterNotifyListener(this);
  102. AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect();
  103. }
  104. //////////////////////////////////////////////////////////////////////////
  105. CAnimationContext::~CAnimationContext()
  106. {
  107. if (Maestro::SequenceComponentNotificationBus::Handler::BusIsConnected())
  108. {
  109. Maestro::SequenceComponentNotificationBus::Handler::BusDisconnect();
  110. }
  111. AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect();
  112. GetIEditor()->GetSequenceManager()->RemoveListener(this);
  113. GetIEditor()->GetUndoManager()->RemoveListener(this);
  114. GetIEditor()->UnregisterNotifyListener(this);
  115. }
  116. //////////////////////////////////////////////////////////////////////////
  117. void CAnimationContext::Init()
  118. {
  119. if (m_movieSystem)
  120. {
  121. m_movieSystem->SetCallback(&s_movieCallback);
  122. }
  123. REGISTER_COMMAND("mov_goToFrameEditor", (ConsoleCommandFunc)GoToFrameCmd, 0, "Make a specified sequence go to a given frame time in the editor.");
  124. }
  125. //////////////////////////////////////////////////////////////////////////
  126. void CAnimationContext::AddListener(IAnimationContextListener* pListener)
  127. {
  128. stl::push_back_unique(m_contextListeners, pListener);
  129. }
  130. //////////////////////////////////////////////////////////////////////////
  131. void CAnimationContext::RemoveListener(IAnimationContextListener* pListener)
  132. {
  133. stl::find_and_erase(m_contextListeners, pListener);
  134. }
  135. void CAnimationContext::NotifyTimeChangedListenersUsingCurrTime() const
  136. {
  137. for (size_t i = 0; i < m_contextListeners.size(); ++i)
  138. {
  139. m_contextListeners[i]->OnTimeChanged(m_currTime);
  140. }
  141. m_lastTimeChangedNotificationTime = m_currTime;
  142. }
  143. //////////////////////////////////////////////////////////////////////////
  144. void CAnimationContext::SetSequence(CTrackViewSequence* sequence, bool force, bool noNotify, bool user)
  145. {
  146. if (!force && sequence == m_pSequence)
  147. {
  148. return;
  149. }
  150. if (!m_bIsInGameMode) // In Editor Play Game mode switching Editor Viewport cameras is currently not supported.
  151. {
  152. // Restore camera in the active Editor Viewport Widget to the value saved while a sequence was activated.
  153. SwitchEditorViewportCamera(m_defaulViewCameraEntityId);
  154. }
  155. // Prevent keys being created from time change
  156. const bool bRecording = m_recording;
  157. m_recording = false;
  158. SetRecordingInternal(false);
  159. const float newSeqStartTime = sequence ? sequence->GetTimeRange().start : 0.f;
  160. m_currTime = newSeqStartTime;
  161. m_fRecordingCurrTime = newSeqStartTime;
  162. if (!m_bPostRenderRegistered)
  163. {
  164. if (GetIEditor() && GetIEditor()->GetViewManager())
  165. {
  166. CViewport* pViewport = GetIEditor()->GetViewManager()->GetViewport(ET_ViewportCamera);
  167. if (pViewport)
  168. {
  169. pViewport->AddPostRenderer(new CAnimationContextPostRender(this));
  170. m_bPostRenderRegistered = true;
  171. }
  172. }
  173. }
  174. if (m_pSequence)
  175. {
  176. const auto oldSequenceEntityId = m_pSequence->GetSequenceComponentEntityId();
  177. if (Maestro::SequenceComponentNotificationBus::Handler::BusIsConnectedId(oldSequenceEntityId))
  178. {
  179. Maestro::SequenceComponentNotificationBus::Handler::BusDisconnect(oldSequenceEntityId);
  180. }
  181. m_pSequence->Deactivate();
  182. if (m_playing)
  183. {
  184. m_pSequence->EndCutScene();
  185. }
  186. m_pSequence->UnBindFromEditorObjects();
  187. }
  188. m_pSequence = sequence;
  189. // Notify a new sequence was just selected.
  190. Maestro::EditorSequenceNotificationBus::Broadcast(&Maestro::EditorSequenceNotificationBus::Events::OnSequenceSelected, m_pSequence ? m_pSequence->GetSequenceComponentEntityId() : AZ::EntityId());
  191. if (m_pSequence)
  192. {
  193. // Set the last valid sequence that was selected.
  194. m_mostRecentSequenceId = m_pSequence->GetSequenceComponentEntityId();
  195. // Get ready to handle camera switching in this sequence, if ever, in order to switch camera in Editor Viewport Widget
  196. Maestro::SequenceComponentNotificationBus::Handler::BusConnect(m_mostRecentSequenceId);
  197. if (m_playing)
  198. {
  199. m_pSequence->BeginCutScene(true);
  200. }
  201. m_timeRange = m_pSequence->GetTimeRange();
  202. m_timeMarker = m_timeRange;
  203. m_pSequence->Activate();
  204. m_pSequence->PrecacheData(newSeqStartTime);
  205. m_pSequence->BindToEditorObjects();
  206. }
  207. else if (user)
  208. {
  209. // If this was a sequence that was selected by the user in Track View
  210. // and it was "No Sequence" clear the m_mostRecentSequenceId so the sequence
  211. // will not be reselected at unwanted events like an undo operation.
  212. m_mostRecentSequenceId.SetInvalid();
  213. }
  214. ForceAnimation();
  215. if (!noNotify)
  216. {
  217. NotifyTimeChangedListenersUsingCurrTime();
  218. for (size_t i = 0; i < m_contextListeners.size(); ++i)
  219. {
  220. m_contextListeners[i]->OnSequenceChanged(m_pSequence);
  221. }
  222. }
  223. TimeChanged(newSeqStartTime);
  224. m_recording = bRecording;
  225. SetRecordingInternal(bRecording);
  226. }
  227. //////////////////////////////////////////////////////////////////////////
  228. bool CAnimationContext::IsInGameMode() const
  229. {
  230. const auto editor = GetIEditor();
  231. const bool isInGame = editor && editor->IsInGameMode();
  232. return m_bIsInGameMode || isInGame;
  233. }
  234. //////////////////////////////////////////////////////////////////////////
  235. bool CAnimationContext::IsInEditingMode() const
  236. {
  237. const auto editor = GetIEditor();
  238. const bool isNotEditing = !editor || editor->IsInConsolewMode() || editor->IsInTestMode() || editor->IsInLevelLoadTestMode() || editor->IsInPreviewMode();
  239. return !m_bIsInGameMode && !isNotEditing;
  240. }
  241. //////////////////////////////////////////////////////////////////////////
  242. bool CAnimationContext::IsSequenceAutostartFlagOn() const
  243. {
  244. const auto sequence = GetSequence();
  245. return sequence && ((sequence->GetFlags() & IAnimSequence::eSeqFlags_PlayOnReset) != 0);
  246. }
  247. //////////////////////////////////////////////////////////////////////////
  248. void CAnimationContext::SwitchEditorViewportCamera(const AZ::EntityId& newCameraEntityId)
  249. {
  250. if (!IsInEditingMode())
  251. {
  252. return; // Camera switching is currently supported in editing mode only.
  253. }
  254. AZ::EntityId currentEditorViewportCamId;
  255. Camera::EditorCameraRequestBus::BroadcastResult(currentEditorViewportCamId, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
  256. if (currentEditorViewportCamId == newCameraEntityId)
  257. {
  258. return; // Camera in Editor Viewport Widget is already set to the requested value, avoid unneeded actions.
  259. }
  260. Camera::EditorCameraRequestBus::Broadcast(&Camera::EditorCameraRequestBus::Events::SetViewFromEntityPerspective, newCameraEntityId);
  261. }
  262. //////////////////////////////////////////////////////////////////////////
  263. void CAnimationContext::OnCameraChanged([[maybe_unused]] const AZ::EntityId&, const AZ::EntityId& newCameraEntityId)
  264. {
  265. if (!newCameraEntityId.IsValid())
  266. {
  267. return; // Only valid camera Ids are sent to the active editor viewport
  268. }
  269. if (!IsInEditingMode())
  270. {
  271. return; // Camera switching is currently supported in editing mode only.
  272. }
  273. if (!IsSequenceAutostartFlagOn())
  274. {
  275. return; // The "Autostart" flag is not set for the active sequence.
  276. }
  277. AZ::EntityId currentEditorViewportCamId;
  278. Camera::EditorCameraRequestBus::BroadcastResult( currentEditorViewportCamId, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
  279. if (currentEditorViewportCamId == newCameraEntityId)
  280. {
  281. return; // Camera in Editor Viewport Widget is already set to the requested value, avoid unneeded actions.
  282. }
  283. Camera::EditorCameraRequestBus::Broadcast(&Camera::EditorCameraRequestBus::Events::SetViewFromEntityPerspective, newCameraEntityId);
  284. }
  285. //////////////////////////////////////////////////////////////////////////
  286. void CAnimationContext::UpdateTimeRange()
  287. {
  288. if (m_pSequence)
  289. {
  290. m_timeRange = m_pSequence->GetTimeRange();
  291. // reset the current time to make sure it is clamped
  292. // to the new range.
  293. SetTime(m_currTime);
  294. }
  295. }
  296. //////////////////////////////////////////////////////////////////////////
  297. void CAnimationContext::SetTime(float t)
  298. {
  299. if (t < m_timeRange.start)
  300. {
  301. t = m_timeRange.start;
  302. }
  303. if (t > m_timeRange.end)
  304. {
  305. t = m_timeRange.end;
  306. }
  307. if (fabs(m_currTime - t) < 0.001f)
  308. {
  309. return;
  310. }
  311. m_currTime = t;
  312. m_fRecordingCurrTime = t;
  313. ForceAnimation();
  314. NotifyTimeChangedListenersUsingCurrTime();
  315. }
  316. void CAnimationContext::TimeChanged(float newTime)
  317. {
  318. if (m_pSequence)
  319. {
  320. m_mostRecentSequenceTime = newTime;
  321. m_pSequence->TimeChanged(newTime);
  322. }
  323. }
  324. //////////////////////////////////////////////////////////////////////////
  325. void CAnimationContext::OnSequenceActivated(AZ::EntityId entityId)
  326. {
  327. // If nothing is selected and there is a valid most recent selected
  328. // try to find that sequence by id and select it. This is useful
  329. // for restoring the selected sequence during undo and redo.
  330. if (m_pSequence == nullptr && m_mostRecentSequenceId.IsValid())
  331. {
  332. if (entityId == m_mostRecentSequenceId)
  333. {
  334. auto editor = GetIEditor();
  335. if (editor != nullptr)
  336. {
  337. auto manager = editor->GetSequenceManager();
  338. if (manager != nullptr)
  339. {
  340. auto sequence = manager->GetSequenceByEntityId(m_mostRecentSequenceId);
  341. if (sequence != nullptr)
  342. {
  343. // Hang onto this because SetSequence() will reset it.
  344. float lastTime = m_mostRecentSequenceTime;
  345. SetSequence(sequence, false, false);
  346. // Restore the current time.
  347. SetTime(lastTime);
  348. // Notify time may have changed, use m_currTime in case it was clamped by SetTime()
  349. TimeChanged(m_currTime);
  350. }
  351. }
  352. }
  353. }
  354. }
  355. // Store initial Editor Viewport camera EntityId
  356. Camera::EditorCameraRequestBus::BroadcastResult(m_defaulViewCameraEntityId, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
  357. }
  358. void CAnimationContext::OnSequenceDeactivated(AZ::EntityId entityId)
  359. {
  360. auto editor = GetIEditor();
  361. if (editor != nullptr)
  362. {
  363. auto manager = editor->GetSequenceManager();
  364. if (manager != nullptr)
  365. {
  366. auto sequence = manager->GetSequenceByEntityId(entityId);
  367. if (sequence != nullptr && sequence == m_pSequence)
  368. {
  369. SetSequence(nullptr, true, false);
  370. }
  371. }
  372. }
  373. }
  374. //////////////////////////////////////////////////////////////////////////
  375. void CAnimationContext::Pause()
  376. {
  377. assert(m_paused >= 0);
  378. m_paused++;
  379. if (m_recording)
  380. {
  381. SetRecordingInternal(false);
  382. }
  383. if (m_movieSystem)
  384. {
  385. m_movieSystem->Pause();
  386. }
  387. if (m_pSequence)
  388. {
  389. m_pSequence->Pause();
  390. }
  391. }
  392. //////////////////////////////////////////////////////////////////////////
  393. void CAnimationContext::Resume()
  394. {
  395. assert(m_paused > 0);
  396. m_paused--;
  397. if (m_recording && m_paused == 0)
  398. {
  399. SetRecordingInternal(true);
  400. }
  401. if (m_movieSystem)
  402. {
  403. m_movieSystem->Resume();
  404. }
  405. if (m_pSequence)
  406. {
  407. m_pSequence->Resume();
  408. }
  409. }
  410. //////////////////////////////////////////////////////////////////////////
  411. void CAnimationContext::SetRecording(bool recording)
  412. {
  413. if (recording == m_recording)
  414. {
  415. return;
  416. }
  417. m_paused = 0;
  418. m_recording = recording;
  419. m_playing = false;
  420. if (!recording && m_fRecordingTimeStep != 0)
  421. {
  422. SetAutoRecording(false, 0);
  423. }
  424. // If started recording, assume we have modified the document.
  425. GetIEditor()->SetModifiedFlag();
  426. SetRecordingInternal(recording);
  427. }
  428. //////////////////////////////////////////////////////////////////////////
  429. //////////////////////////////////////////////////////////////////////////
  430. void CAnimationContext::SetPlaying(bool playing)
  431. {
  432. if (playing == m_playing)
  433. {
  434. return;
  435. }
  436. m_paused = 0;
  437. m_playing = playing;
  438. m_recording = false;
  439. SetRecordingInternal(false);
  440. if (m_movieSystem)
  441. {
  442. if (playing)
  443. {
  444. m_movieSystem->Resume();
  445. if (m_pSequence)
  446. {
  447. m_pSequence->Resume();
  448. IMovieUser* pMovieUser = m_movieSystem->GetUser();
  449. if (pMovieUser)
  450. {
  451. m_pSequence->BeginCutScene(true);
  452. }
  453. }
  454. m_movieSystem->ResumeCutScenes();
  455. }
  456. else
  457. {
  458. m_movieSystem->Pause();
  459. if (m_pSequence)
  460. {
  461. m_pSequence->Pause();
  462. }
  463. m_movieSystem->PauseCutScenes();
  464. if (m_pSequence)
  465. {
  466. IMovieUser* pMovieUser = m_movieSystem->GetUser();
  467. if (pMovieUser)
  468. {
  469. m_pSequence->EndCutScene();
  470. }
  471. }
  472. }
  473. }
  474. }
  475. //////////////////////////////////////////////////////////////////////////
  476. void CAnimationContext::Update()
  477. {
  478. if (m_countWaitingForExitingGameMode > 0) // Waiting while Editor is exiting Play Game mode ?
  479. {
  480. if (--m_countWaitingForExitingGameMode == 0) // The 2nd frame after StopPlayInEditor event sent ?
  481. {
  482. m_bIsInGameMode = false; // Now Editor Viewport Widget is in the "Editor" state,
  483. RestoreSequenceOnEnteringEditMode(); // So restore previously active sequence and camera in Editor Viewport.
  484. }
  485. else
  486. {
  487. return; // while the Editor Viewport state goes from "Started" to "Stopping" and finally back to "Editor".
  488. }
  489. }
  490. if (m_bForceUpdateInNextFrame)
  491. {
  492. ForceAnimation();
  493. m_bForceUpdateInNextFrame = false;
  494. }
  495. if (m_paused > 0 || !(m_playing || m_bAutoRecording))
  496. {
  497. if (m_pSequence)
  498. {
  499. m_pSequence->StillUpdate();
  500. }
  501. if (!m_recording)
  502. {
  503. if (m_movieSystem)
  504. {
  505. m_movieSystem->StillUpdate();
  506. }
  507. }
  508. return;
  509. }
  510. const AZ::TimeUs frameDeltaTimeUs = AZ::GetSimulationTickDeltaTimeUs();
  511. const float frameDeltaTime = AZ::TimeUsToSeconds(frameDeltaTimeUs);
  512. if (!m_bAutoRecording)
  513. {
  514. AnimateActiveSequence();
  515. m_currTime += frameDeltaTime * m_fTimeScale;
  516. if (!m_recording)
  517. {
  518. if (m_movieSystem)
  519. {
  520. m_movieSystem->PreUpdate(frameDeltaTime);
  521. m_movieSystem->PostUpdate(frameDeltaTime);
  522. }
  523. }
  524. }
  525. else
  526. {
  527. m_fRecordingCurrTime += frameDeltaTime * m_fTimeScale;
  528. if (fabs(m_fRecordingCurrTime - m_currTime) > m_fRecordingTimeStep)
  529. {
  530. m_currTime += m_fRecordingTimeStep;
  531. }
  532. }
  533. if (m_currTime > m_timeMarker.end)
  534. {
  535. if (m_bAutoRecording)
  536. {
  537. SetAutoRecording(false, 0);
  538. }
  539. else
  540. {
  541. if (m_bLooping)
  542. {
  543. m_currTime = m_timeMarker.start;
  544. if (m_pSequence)
  545. {
  546. m_pSequence->OnLoop();
  547. }
  548. }
  549. else
  550. {
  551. SetPlaying(false);
  552. m_currTime = m_timeMarker.end;
  553. }
  554. }
  555. }
  556. if (fabs(m_lastTimeChangedNotificationTime - m_currTime) > 0.001f)
  557. {
  558. NotifyTimeChangedListenersUsingCurrTime();
  559. }
  560. }
  561. //////////////////////////////////////////////////////////////////////////
  562. void CAnimationContext::ForceAnimation()
  563. {
  564. if (m_bForcingAnimation)
  565. {
  566. // reentrant calls are possible when using subsequences
  567. return;
  568. }
  569. m_bForcingAnimation = true;
  570. // Before animating node, pause recording.
  571. if (m_bAutoRecording)
  572. {
  573. Pause();
  574. }
  575. AnimateActiveSequence();
  576. // Animate a second time to properly update camera DoF
  577. AnimateActiveSequence();
  578. if (m_bAutoRecording)
  579. {
  580. Resume();
  581. }
  582. m_bForcingAnimation = false;
  583. }
  584. //////////////////////////////////////////////////////////////////////////
  585. void CAnimationContext::SetAutoRecording(bool bEnable, float fTimeStep)
  586. {
  587. if (bEnable)
  588. {
  589. m_bAutoRecording = true;
  590. m_fRecordingTimeStep = fTimeStep;
  591. SetRecording(bEnable);
  592. }
  593. else
  594. {
  595. m_bAutoRecording = false;
  596. m_fRecordingTimeStep = 0;
  597. }
  598. }
  599. //////////////////////////////////////////////////////////////////////////
  600. void CAnimationContext::GoToFrameCmd(IConsoleCmdArgs* pArgs)
  601. {
  602. if (pArgs->GetArgCount() < 2)
  603. {
  604. gEnv->pLog->LogError("GoToFrame: You must provide a 'frame time' to go to");
  605. return;
  606. }
  607. assert(GetIEditor()->GetAnimation());
  608. CTrackViewSequence* pSeq = GetIEditor()->GetAnimation()->GetSequence();
  609. if (!pSeq)
  610. {
  611. gEnv->pLog->LogError("GoToFrame: No active animation sequence");
  612. return;
  613. }
  614. // console commands are in the invariant locale, for atof()
  615. AZ::Locale::ScopedSerializationLocale scopedLocale;
  616. float targetFrame = (float)atof(pArgs->GetArg(1));
  617. scopedLocale.Deactivate();
  618. if (pSeq->GetTimeRange().start > targetFrame || targetFrame > pSeq->GetTimeRange().end)
  619. {
  620. gEnv->pLog->LogError("GoToFrame: requested time %f is outside the range of sequence %s (%f, %f)", targetFrame, pSeq->GetName().c_str(), pSeq->GetTimeRange().start, pSeq->GetTimeRange().end);
  621. return;
  622. }
  623. GetIEditor()->GetAnimation()->m_currTime = targetFrame;
  624. GetIEditor()->GetAnimation()->m_bSingleFrame = true;
  625. GetIEditor()->GetAnimation()->ForceAnimation();
  626. }
  627. //////////////////////////////////////////////////////////////////////////
  628. void CAnimationContext::OnPostRender()
  629. {
  630. if (m_pSequence)
  631. {
  632. SAnimContext ac;
  633. ac.dt = 0;
  634. const AZ::TimeUs frameDeltaTimeUs = AZ::GetSimulationTickDeltaTimeUs();
  635. const float frameDeltaTime = AZ::TimeUsToSeconds(frameDeltaTimeUs);
  636. ac.fps = 1.0f / frameDeltaTime;
  637. ac.time = m_currTime;
  638. ac.singleFrame = true;
  639. ac.forcePlay = true;
  640. m_pSequence->Render(ac);
  641. }
  642. }
  643. void CAnimationContext::BeginUndoTransaction()
  644. {
  645. m_bSavedRecordingState = m_recording;
  646. SetRecordingInternal(false);
  647. }
  648. //////////////////////////////////////////////////////////////////////////
  649. void CAnimationContext::EndUndoTransaction()
  650. {
  651. if (m_pSequence)
  652. {
  653. m_pSequence->BindToEditorObjects();
  654. }
  655. SetRecordingInternal(m_bSavedRecordingState);
  656. }
  657. void CAnimationContext::OnPrefabInstancePropagationEnd()
  658. {
  659. if (m_pSequence)
  660. {
  661. m_pSequence->BindToEditorObjects();
  662. }
  663. }
  664. //////////////////////////////////////////////////////////////////////////
  665. void CAnimationContext::TogglePlay()
  666. {
  667. if (!IsPlaying())
  668. {
  669. SetPlaying(true);
  670. }
  671. else
  672. {
  673. SetPlaying(false);
  674. }
  675. }
  676. //////////////////////////////////////////////////////////////////////////
  677. void CAnimationContext::OnSequenceRemoved(CTrackViewSequence* pSequence)
  678. {
  679. if (m_pSequence == pSequence)
  680. {
  681. SetSequence(nullptr, true, false);
  682. }
  683. }
  684. //////////////////////////////////////////////////////////////////////////
  685. void CAnimationContext::StoreSequenceOnExitingEditMode(bool isSwitchingToGameMode)
  686. {
  687. // Store currently active Editor Viewport camera EntityId
  688. Camera::EditorCameraRequestBus::BroadcastResult(
  689. m_viewCameraEntityIdToRestore, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
  690. if (isSwitchingToGameMode)
  691. {
  692. SwitchEditorViewportCamera(AZ::EntityId()); // Switch Editor Viewport back to the default Editor camera
  693. m_bIsInGameMode = true; // and set the flag of Editor being switched into Play Game mode.
  694. }
  695. if (m_pSequence)
  696. {
  697. m_sequenceToRestore = m_pSequence->GetSequenceComponentEntityId();
  698. }
  699. else
  700. {
  701. m_sequenceToRestore.SetInvalid();
  702. }
  703. m_sequenceRestoreTime = GetTime();
  704. m_bSavedRecordingState = m_recording;
  705. SetRecordingInternal(false);
  706. SetSequence(nullptr, true, true);
  707. }
  708. //////////////////////////////////////////////////////////////////////////
  709. void CAnimationContext::RestoreSequenceOnEnteringEditMode()
  710. {
  711. m_currTime = m_sequenceRestoreTime;
  712. SetSequence(GetIEditor()->GetSequenceManager()->GetSequenceByEntityId(m_sequenceToRestore), true, true);
  713. SetTime(m_sequenceRestoreTime);
  714. SetRecordingInternal(m_bSavedRecordingState);
  715. SwitchEditorViewportCamera(m_viewCameraEntityIdToRestore); // Switch Editor Viewport back to the stored camera, which was active prior to switching to Play Game mode.
  716. }
  717. //////////////////////////////////////////////////////////////////////////
  718. void CAnimationContext::OnEditorNotifyEvent(EEditorNotifyEvent event)
  719. {
  720. switch (event)
  721. {
  722. case eNotify_OnBeginGameMode:
  723. if (m_pSequence)
  724. {
  725. m_pSequence->Resume();
  726. }
  727. {
  728. // This notification arrives before even the OnStartPlayInEditorBegin and later OnStartPlayInEditor events
  729. // arrive to Editor Views, and thus switching cameras is still available.
  730. // So, after storing an active camera Id, rollback the Editor Viewport to default "Editor camera" in order
  731. // to help Editor correctly restore viewport state after switching back to Editing mode,
  732. // then set the 'm_bIsInGameMode' flag, store an active sequence and drop it.
  733. constexpr const bool isSwitchingToGameMode = true;
  734. StoreSequenceOnExitingEditMode(isSwitchingToGameMode);
  735. }
  736. break;
  737. case eNotify_OnBeginSceneSave:
  738. case eNotify_OnBeginLayerExport:
  739. {
  740. constexpr const bool isSwitchingToGameMode = false;
  741. // Store active sequence and camera Ids and drop this sequence.
  742. StoreSequenceOnExitingEditMode(isSwitchingToGameMode);
  743. }
  744. break;
  745. case eNotify_OnEndGameMode:
  746. // Delay restoring previously active sequence and Editor Viewport camera, and clearing 'm_bIsInGameMode' flag,
  747. // for 2 frames, while Editor Viewport state goes from "Started" to "Stopping" and finally back to "Editor",
  748. // and switching cameras is not supported.
  749. m_countWaitingForExitingGameMode = 2;
  750. break;
  751. case eNotify_OnEndSceneSave:
  752. case eNotify_OnEndLayerExport:
  753. // Restore previously active sequence and camera in Editor Viewport.
  754. RestoreSequenceOnEnteringEditMode();
  755. break;
  756. case eNotify_OnQuit:
  757. case eNotify_OnCloseScene:
  758. SetSequence(nullptr, true, false);
  759. break;
  760. case eNotify_OnBeginNewScene:
  761. SetSequence(nullptr, false, false);
  762. break;
  763. case eNotify_OnBeginLoad:
  764. m_mostRecentSequenceId.SetInvalid();
  765. m_mostRecentSequenceTime = 0.0f;
  766. m_bSavedRecordingState = m_recording;
  767. SetRecordingInternal(false);
  768. GetIEditor()->GetAnimation()->SetSequence(nullptr, false, false);
  769. break;
  770. case eNotify_OnEndLoad:
  771. SetRecordingInternal(m_bSavedRecordingState);
  772. break;
  773. }
  774. }
  775. void CAnimationContext::SetRecordingInternal(bool enableRecording)
  776. {
  777. if (m_movieSystem)
  778. {
  779. m_movieSystem->SetRecording(enableRecording);
  780. }
  781. if (m_pSequence)
  782. {
  783. m_pSequence->SetRecording(enableRecording);
  784. }
  785. }
  786. void CAnimationContext::AnimateActiveSequence()
  787. {
  788. if (!m_pSequence)
  789. {
  790. return;
  791. }
  792. SAnimContext ac;
  793. ac.dt = 0;
  794. const AZ::TimeUs frameDeltaTimeUs = AZ::GetSimulationTickDeltaTimeUs();
  795. const float frameDeltaTime = AZ::TimeUsToSeconds(frameDeltaTimeUs);
  796. ac.fps = 1.0f / frameDeltaTime;
  797. ac.time = m_currTime;
  798. ac.singleFrame = true;
  799. ac.forcePlay = true;
  800. m_pSequence->Animate(ac);
  801. m_pSequence->SyncToConsole(ac);
  802. }