1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "EditorDefs.h"
- #include "AnimationContext.h"
- // CryCommon
- #include <CryCommon/Maestro/Bus/EditorSequenceBus.h>
- // Editor
- #include "TrackView/TrackViewDialog.h"
- #include "ViewManager.h"
- #include <AzCore/Serialization/Locale.h>
- #include <AzCore/Time/ITime.h>
- #include <AzToolsFramework/API/EditorCameraBus.h>
- #include <Maestro/Bus/EditorSequenceComponentBus.h>
- #include <Maestro/Types/AnimNodeType.h>
- //////////////////////////////////////////////////////////////////////////
- // Movie Callback.
- //////////////////////////////////////////////////////////////////////////
- class CMovieCallback
- : public IMovieCallback
- {
- protected:
- void OnMovieCallback(ECallbackReason reason, [[maybe_unused]] IAnimNode* pNode) override
- {
- switch (reason)
- {
- case CBR_CHANGENODE:
- // Invalidate nodes
- break;
- case CBR_CHANGETRACK:
- {
- // Invalidate tracks
- CTrackViewDialog* pTrackViewDialog = CTrackViewDialog::GetCurrentInstance();
- if (pTrackViewDialog)
- {
- pTrackViewDialog->InvalidateDopeSheet();
- }
- }
- break;
- }
- }
- bool IsSequenceCamUsed() const override
- {
- if (gEnv->IsEditorGameMode() == true)
- {
- return true;
- }
- if (GetIEditor()->GetViewManager() == nullptr)
- {
- return false;
- }
- CViewport* pRendView = GetIEditor()->GetViewManager()->GetViewport(ET_ViewportCamera);
- if (pRendView)
- {
- return pRendView->IsSequenceCamera();
- }
- return false;
- }
- };
- static CMovieCallback s_movieCallback;
- //////////////////////////////////////////////////////////////////////////
- //-----------------------------------------------------------------------------
- //!
- class CAnimationContextPostRender
- : public IPostRenderer
- {
- public:
- CAnimationContextPostRender(CAnimationContext* pAC)
- : m_pAC(pAC){}
- void OnPostRender() const override { assert(m_pAC); m_pAC->OnPostRender(); }
- protected:
- CAnimationContext* m_pAC;
- };
- //////////////////////////////////////////////////////////////////////////
- CAnimationContext::CAnimationContext()
- : m_movieSystem(AZ::Interface<IMovieSystem>::Get())
- {
- m_paused = 0;
- m_playing = false;
- m_recording = false;
- m_bSavedRecordingState = false;
- m_timeRange.Set(0, 0);
- m_timeMarker.Set(0, 0);
- m_currTime = 0.0f;
- m_lastTimeChangedNotificationTime = .0f;
- m_bForceUpdateInNextFrame = false;
- m_fTimeScale = 1.0f;
- m_pSequence = nullptr;
- m_mostRecentSequenceId.SetInvalid();
- m_mostRecentSequenceTime = 0.0f;
- m_bLooping = false;
- m_bAutoRecording = false;
- m_fRecordingTimeStep = 0;
- m_bSingleFrame = false;
- m_bPostRenderRegistered = false;
- m_bForcingAnimation = false;
- GetIEditor()->GetUndoManager()->AddListener(this);
- GetIEditor()->GetSequenceManager()->AddListener(this);
- GetIEditor()->RegisterNotifyListener(this);
- AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect();
- }
- //////////////////////////////////////////////////////////////////////////
- CAnimationContext::~CAnimationContext()
- {
- if (Maestro::SequenceComponentNotificationBus::Handler::BusIsConnected())
- {
- Maestro::SequenceComponentNotificationBus::Handler::BusDisconnect();
- }
- AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect();
- GetIEditor()->GetSequenceManager()->RemoveListener(this);
- GetIEditor()->GetUndoManager()->RemoveListener(this);
- GetIEditor()->UnregisterNotifyListener(this);
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::Init()
- {
- if (m_movieSystem)
- {
- m_movieSystem->SetCallback(&s_movieCallback);
- }
- REGISTER_COMMAND("mov_goToFrameEditor", (ConsoleCommandFunc)GoToFrameCmd, 0, "Make a specified sequence go to a given frame time in the editor.");
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::AddListener(IAnimationContextListener* pListener)
- {
- stl::push_back_unique(m_contextListeners, pListener);
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::RemoveListener(IAnimationContextListener* pListener)
- {
- stl::find_and_erase(m_contextListeners, pListener);
- }
- void CAnimationContext::NotifyTimeChangedListenersUsingCurrTime() const
- {
- for (size_t i = 0; i < m_contextListeners.size(); ++i)
- {
- m_contextListeners[i]->OnTimeChanged(m_currTime);
- }
- m_lastTimeChangedNotificationTime = m_currTime;
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::SetSequence(CTrackViewSequence* sequence, bool force, bool noNotify, bool user)
- {
- if (!force && sequence == m_pSequence)
- {
- return;
- }
- if (!m_bIsInGameMode) // In Editor Play Game mode switching Editor Viewport cameras is currently not supported.
- {
- // Restore camera in the active Editor Viewport Widget to the value saved while a sequence was activated.
- SwitchEditorViewportCamera(m_defaulViewCameraEntityId);
- }
- // Prevent keys being created from time change
- const bool bRecording = m_recording;
- m_recording = false;
- SetRecordingInternal(false);
- const float newSeqStartTime = sequence ? sequence->GetTimeRange().start : 0.f;
- m_currTime = newSeqStartTime;
- m_fRecordingCurrTime = newSeqStartTime;
- if (!m_bPostRenderRegistered)
- {
- if (GetIEditor() && GetIEditor()->GetViewManager())
- {
- CViewport* pViewport = GetIEditor()->GetViewManager()->GetViewport(ET_ViewportCamera);
- if (pViewport)
- {
- pViewport->AddPostRenderer(new CAnimationContextPostRender(this));
- m_bPostRenderRegistered = true;
- }
- }
- }
- if (m_pSequence)
- {
- const auto oldSequenceEntityId = m_pSequence->GetSequenceComponentEntityId();
- if (Maestro::SequenceComponentNotificationBus::Handler::BusIsConnectedId(oldSequenceEntityId))
- {
- Maestro::SequenceComponentNotificationBus::Handler::BusDisconnect(oldSequenceEntityId);
- }
- m_pSequence->Deactivate();
- if (m_playing)
- {
- m_pSequence->EndCutScene();
- }
- m_pSequence->UnBindFromEditorObjects();
- }
- m_pSequence = sequence;
- // Notify a new sequence was just selected.
- Maestro::EditorSequenceNotificationBus::Broadcast(&Maestro::EditorSequenceNotificationBus::Events::OnSequenceSelected, m_pSequence ? m_pSequence->GetSequenceComponentEntityId() : AZ::EntityId());
- if (m_pSequence)
- {
- // Set the last valid sequence that was selected.
- m_mostRecentSequenceId = m_pSequence->GetSequenceComponentEntityId();
- if (!m_mostRecentSequenceId.IsValid())
- {
- m_pSequence = nullptr;
- return;
- }
- // Get ready to handle camera switching in this sequence, if ever, in order to switch camera in Editor Viewport Widget
- Maestro::SequenceComponentNotificationBus::Handler::BusConnect(m_mostRecentSequenceId);
- if (m_playing)
- {
- m_pSequence->BeginCutScene(true);
- }
- m_timeRange = m_pSequence->GetTimeRange();
- m_timeMarker = m_timeRange;
- m_pSequence->Activate();
- m_pSequence->PrecacheData(newSeqStartTime);
- m_pSequence->BindToEditorObjects();
- }
- else if (user)
- {
- // If this was a sequence that was selected by the user in Track View
- // and it was "No Sequence" clear the m_mostRecentSequenceId so the sequence
- // will not be reselected at unwanted events like an undo operation.
- m_mostRecentSequenceId.SetInvalid();
- }
- ForceAnimation();
- if (!noNotify)
- {
- NotifyTimeChangedListenersUsingCurrTime();
- for (size_t i = 0; i < m_contextListeners.size(); ++i)
- {
- m_contextListeners[i]->OnSequenceChanged(m_pSequence);
- }
- }
- TimeChanged(newSeqStartTime);
- m_recording = bRecording;
- SetRecordingInternal(bRecording);
- }
- //////////////////////////////////////////////////////////////////////////
- bool CAnimationContext::IsInGameMode() const
- {
- const auto editor = GetIEditor();
- const bool isInGame = editor && editor->IsInGameMode();
- return m_bIsInGameMode || isInGame;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CAnimationContext::IsInEditingMode() const
- {
- const auto editor = GetIEditor();
- const bool isNotEditing = !editor || editor->IsInConsolewMode() || editor->IsInTestMode() || editor->IsInLevelLoadTestMode() ||
- editor->IsInPreviewMode() || editor->IsInSimulationMode();
- return !m_bIsInGameMode && !isNotEditing;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CAnimationContext::IsSequenceAutostartFlagOn() const
- {
- const auto sequence = GetSequence();
- return sequence && ((sequence->GetFlags() & IAnimSequence::eSeqFlags_PlayOnReset) != 0);
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::SwitchEditorViewportCamera(const AZ::EntityId& newCameraEntityId)
- {
- if (!IsInEditingMode())
- {
- return; // Camera switching is currently supported in editing mode only.
- }
- AZ::EntityId currentEditorViewportCamId;
- Camera::EditorCameraRequestBus::BroadcastResult(currentEditorViewportCamId, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
- if (currentEditorViewportCamId == newCameraEntityId)
- {
- return; // Camera in Editor Viewport Widget is already set to the requested value, avoid unneeded actions.
- }
- Camera::EditorCameraRequestBus::Broadcast(&Camera::EditorCameraRequestBus::Events::SetViewFromEntityPerspective, newCameraEntityId);
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::OnCameraChanged([[maybe_unused]] const AZ::EntityId&, const AZ::EntityId& newCameraEntityId)
- {
- if (!newCameraEntityId.IsValid())
- {
- return; // Only valid camera Ids are sent to the active editor viewport
- }
- if (!IsInEditingMode())
- {
- return; // Camera switching is currently supported in editing mode only.
- }
- if (!IsSequenceAutostartFlagOn())
- {
- return; // The "Autostart" flag is not set for the active sequence.
- }
- AZ::EntityId currentEditorViewportCamId;
- Camera::EditorCameraRequestBus::BroadcastResult( currentEditorViewportCamId, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
- if (currentEditorViewportCamId == newCameraEntityId)
- {
- return; // Camera in Editor Viewport Widget is already set to the requested value, avoid unneeded actions.
- }
- Camera::EditorCameraRequestBus::Broadcast(&Camera::EditorCameraRequestBus::Events::SetViewFromEntityPerspective, newCameraEntityId);
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::UpdateTimeRange()
- {
- if (m_pSequence)
- {
- m_timeRange = m_pSequence->GetTimeRange();
- // reset the current time to make sure it is clamped
- // to the new range.
- SetTime(m_currTime);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::SetTime(float t)
- {
- if (t < m_timeRange.start)
- {
- t = m_timeRange.start;
- }
- if (t > m_timeRange.end)
- {
- t = m_timeRange.end;
- }
- if (fabs(m_currTime - t) < 0.001f)
- {
- return;
- }
- m_currTime = t;
- m_fRecordingCurrTime = t;
- ForceAnimation();
- NotifyTimeChangedListenersUsingCurrTime();
- }
- void CAnimationContext::TimeChanged(float newTime)
- {
- if (m_pSequence)
- {
- m_mostRecentSequenceTime = newTime;
- m_pSequence->TimeChanged(newTime);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::OnSequenceActivated(AZ::EntityId entityId)
- {
- if (!entityId.IsValid())
- {
- AZ_Assert(false, "Expected valid sequence EntityId.");
- return;
- }
- const auto editor = GetIEditor();
- if (!editor)
- {
- AZ_Assert(false, "No Editor.");
- return;
- }
- const auto manager = editor->GetSequenceManager();
- if (!manager)
- {
- AZ_Assert(false, "No SequenceManager.");
- return;
- }
- const auto sequence = manager->GetSequenceByEntityId(entityId);
- if (!sequence)
- {
- AZ_Assert(false, "No sequence with EntityId=%s.", entityId.ToString().c_str());
- return;
- }
- // Store initial Editor Viewport camera EntityId
- Camera::EditorCameraRequestBus::BroadcastResult(m_defaulViewCameraEntityId, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
- // If nothing is selected and there is a valid most recent selected
- // try to find that sequence by id and select it. This is useful
- // for restoring the selected sequence during undo and redo.
- if (m_pSequence == nullptr && m_mostRecentSequenceId.IsValid() && entityId == m_mostRecentSequenceId)
- {
- // Hang onto this because SetSequence() will reset it.
- float lastTime = m_mostRecentSequenceTime;
- SetSequence(sequence, false, false);
- // Restore the current time.
- SetTime(lastTime);
- // Notify time may have changed, use m_currTime in case it was clamped by SetTime()
- TimeChanged(m_currTime);
- return;
- }
- // This method could be invoked after Undoing a sequence deletion, so try to find this sequence and reconnect it
- const auto entityNodes = sequence->GetAnimNodesByType(AnimNodeType::AzEntity);
- const auto numNodes = entityNodes.GetCount();
- for (unsigned int i = 0; i < numNodes; ++i)
- {
- const auto animatedEntityId = entityNodes.GetNode(i)->GetAzEntityId();
- if (!animatedEntityId.IsValid())
- {
- AZ_Error("AnimationContext", false, "OnSequenceActivated('%s' %s): AzEntityNode has invalid EntityId %s.",
- sequence->GetName().c_str(), entityId.ToString().c_str(), animatedEntityId.ToString().c_str());
- continue;
- }
- bool wasInvoked = false;
- Maestro::EditorSequenceComponentRequestBus::EventResult(
- wasInvoked, entityId, &Maestro::EditorSequenceComponentRequestBus::Events::AddEntityToAnimate, animatedEntityId);
- if (!wasInvoked)
- {
- AZ_Error("AnimationContext", false, "OnSequenceActivated('%s' %s): Failed to connect to animated EntityId %s.",
- sequence->GetName().c_str(), entityId.ToString().c_str(), animatedEntityId.ToString().c_str());
- }
- }
- }
- void CAnimationContext::OnSequenceDeactivated(AZ::EntityId entityId)
- {
- auto editor = GetIEditor();
- if (editor != nullptr)
- {
- auto manager = editor->GetSequenceManager();
- if (manager != nullptr)
- {
- auto sequence = manager->GetSequenceByEntityId(entityId);
- if (sequence != nullptr && sequence == m_pSequence)
- {
- SetSequence(nullptr, true, false);
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::Pause()
- {
- assert(m_paused >= 0);
- m_paused++;
- if (m_recording)
- {
- SetRecordingInternal(false);
- }
- if (m_movieSystem)
- {
- m_movieSystem->Pause();
- }
- if (m_pSequence)
- {
- m_pSequence->Pause();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::Resume()
- {
- assert(m_paused > 0);
- m_paused--;
- if (m_recording && m_paused == 0)
- {
- SetRecordingInternal(true);
- }
- if (m_movieSystem)
- {
- m_movieSystem->Resume();
- }
- if (m_pSequence)
- {
- m_pSequence->Resume();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::SetRecording(bool recording)
- {
- if (recording == m_recording)
- {
- return;
- }
- m_paused = 0;
- m_recording = recording;
- m_playing = false;
- if (!recording && m_fRecordingTimeStep != 0)
- {
- SetAutoRecording(false, 0);
- }
- // If started recording, assume we have modified the document.
- GetIEditor()->SetModifiedFlag();
- SetRecordingInternal(recording);
- }
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::SetPlaying(bool playing)
- {
- if (playing == m_playing)
- {
- return;
- }
- m_paused = 0;
- m_playing = playing;
- m_recording = false;
- SetRecordingInternal(false);
- if (m_movieSystem)
- {
- if (playing)
- {
- m_movieSystem->Resume();
- if (m_pSequence)
- {
- m_pSequence->Resume();
- IMovieUser* pMovieUser = m_movieSystem->GetUser();
- if (pMovieUser)
- {
- m_pSequence->BeginCutScene(true);
- }
- }
- m_movieSystem->ResumeCutScenes();
- }
- else
- {
- m_movieSystem->Pause();
- if (m_pSequence)
- {
- m_pSequence->Pause();
- }
- m_movieSystem->PauseCutScenes();
- if (m_pSequence)
- {
- IMovieUser* pMovieUser = m_movieSystem->GetUser();
- if (pMovieUser)
- {
- m_pSequence->EndCutScene();
- }
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::Update()
- {
- if (m_countWaitingForExitingGameMode > 0) // Waiting while Editor is exiting Play Game mode ?
- {
- if (--m_countWaitingForExitingGameMode == 0) // The 2nd frame after StopPlayInEditor event sent ?
- {
- m_bIsInGameMode = false; // Now Editor Viewport Widget is in the "Editor" state,
- RestoreSequenceOnEnteringEditMode(); // So restore previously active sequence and camera in Editor Viewport.
- }
- else
- {
- return; // while the Editor Viewport state goes from "Started" to "Stopping" and finally back to "Editor".
- }
- }
- if (m_bForceUpdateInNextFrame)
- {
- ForceAnimation();
- m_bForceUpdateInNextFrame = false;
- }
- if (m_paused > 0 || !(m_playing || m_bAutoRecording))
- {
- if (m_pSequence)
- {
- m_pSequence->StillUpdate();
- }
- if (!m_recording)
- {
- if (m_movieSystem)
- {
- m_movieSystem->StillUpdate();
- }
- }
- return;
- }
- const AZ::TimeUs frameDeltaTimeUs = AZ::GetSimulationTickDeltaTimeUs();
- const float frameDeltaTime = AZ::TimeUsToSeconds(frameDeltaTimeUs);
- if (!m_bAutoRecording)
- {
- AnimateActiveSequence();
- m_currTime += frameDeltaTime * m_fTimeScale;
- if (!m_recording)
- {
- if (m_movieSystem)
- {
- m_movieSystem->PreUpdate(frameDeltaTime);
- m_movieSystem->PostUpdate(frameDeltaTime);
- }
- }
- }
- else
- {
- m_fRecordingCurrTime += frameDeltaTime * m_fTimeScale;
- if (fabs(m_fRecordingCurrTime - m_currTime) > m_fRecordingTimeStep)
- {
- m_currTime += m_fRecordingTimeStep;
- }
- }
- if (m_currTime > m_timeMarker.end)
- {
- if (m_bAutoRecording)
- {
- SetAutoRecording(false, 0);
- }
- else
- {
- if (m_bLooping)
- {
- m_currTime = m_timeMarker.start;
- if (m_pSequence)
- {
- m_pSequence->OnLoop();
- }
- }
- else
- {
- SetPlaying(false);
- m_currTime = m_timeMarker.end;
- }
- }
- }
- if (fabs(m_lastTimeChangedNotificationTime - m_currTime) > 0.001f)
- {
- NotifyTimeChangedListenersUsingCurrTime();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::ForceAnimation()
- {
- if (m_bForcingAnimation)
- {
- // reentrant calls are possible when using subsequences
- return;
- }
- m_bForcingAnimation = true;
- // Before animating node, pause recording.
- if (m_bAutoRecording)
- {
- Pause();
- }
- AnimateActiveSequence();
- // Animate a second time to properly update camera DoF
- AnimateActiveSequence();
- if (m_bAutoRecording)
- {
- Resume();
- }
- m_bForcingAnimation = false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::SetAutoRecording(bool bEnable, float fTimeStep)
- {
- if (bEnable)
- {
- m_bAutoRecording = true;
- m_fRecordingTimeStep = fTimeStep;
- SetRecording(bEnable);
- }
- else
- {
- m_bAutoRecording = false;
- m_fRecordingTimeStep = 0;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::GoToFrameCmd(IConsoleCmdArgs* pArgs)
- {
- if (pArgs->GetArgCount() < 2)
- {
- gEnv->pLog->LogError("GoToFrame: You must provide a 'frame time' to go to");
- return;
- }
- assert(GetIEditor()->GetAnimation());
- CTrackViewSequence* pSeq = GetIEditor()->GetAnimation()->GetSequence();
- if (!pSeq)
- {
- gEnv->pLog->LogError("GoToFrame: No active animation sequence");
- return;
- }
- // console commands are in the invariant locale, for atof()
- AZ::Locale::ScopedSerializationLocale scopedLocale;
- float targetFrame = (float)atof(pArgs->GetArg(1));
- scopedLocale.Deactivate();
- if (pSeq->GetTimeRange().start > targetFrame || targetFrame > pSeq->GetTimeRange().end)
- {
- 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);
- return;
- }
- GetIEditor()->GetAnimation()->m_currTime = targetFrame;
- GetIEditor()->GetAnimation()->m_bSingleFrame = true;
- GetIEditor()->GetAnimation()->ForceAnimation();
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::OnPostRender()
- {
- if (m_pSequence)
- {
- SAnimContext ac;
- ac.dt = 0;
- const AZ::TimeUs frameDeltaTimeUs = AZ::GetSimulationTickDeltaTimeUs();
- const float frameDeltaTime = AZ::TimeUsToSeconds(frameDeltaTimeUs);
- ac.fps = 1.0f / frameDeltaTime;
- ac.time = m_currTime;
- ac.singleFrame = true;
- ac.forcePlay = true;
- m_pSequence->Render(ac);
- }
- }
- void CAnimationContext::BeginUndoTransaction()
- {
- m_bSavedRecordingState = m_recording;
- SetRecordingInternal(false);
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::EndUndoTransaction()
- {
- if (m_pSequence)
- {
- m_pSequence->BindToEditorObjects();
- }
- SetRecordingInternal(m_bSavedRecordingState);
- }
- void CAnimationContext::OnPrefabInstancePropagationEnd()
- {
- if (m_pSequence)
- {
- m_pSequence->BindToEditorObjects();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::TogglePlay()
- {
- if (!IsPlaying())
- {
- SetPlaying(true);
- }
- else
- {
- SetPlaying(false);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::OnSequenceRemoved(CTrackViewSequence* pSequence)
- {
- if (m_pSequence == pSequence)
- {
- SetSequence(nullptr, true, false);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::StoreSequenceOnExitingEditMode(bool isSwitchingToGameMode)
- {
- // Store currently active Editor Viewport camera EntityId
- Camera::EditorCameraRequestBus::BroadcastResult(
- m_viewCameraEntityIdToRestore, &Camera::EditorCameraRequestBus::Events::GetCurrentViewEntityId);
- if (isSwitchingToGameMode)
- {
- SwitchEditorViewportCamera(AZ::EntityId()); // Switch Editor Viewport back to the default Editor camera
- m_bIsInGameMode = true; // and set the flag of Editor being switched into Play Game mode.
- }
- if (m_pSequence)
- {
- m_sequenceToRestore = m_pSequence->GetSequenceComponentEntityId();
- }
- else
- {
- m_sequenceToRestore.SetInvalid();
- }
- m_sequenceRestoreTime = GetTime();
- m_bSavedRecordingState = m_recording;
- SetRecordingInternal(false);
- SetSequence(nullptr, true, true);
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::RestoreSequenceOnEnteringEditMode()
- {
- m_currTime = m_sequenceRestoreTime;
- SetSequence(GetIEditor()->GetSequenceManager()->GetSequenceByEntityId(m_sequenceToRestore), true, true);
- SetTime(m_sequenceRestoreTime);
- SetRecordingInternal(m_bSavedRecordingState);
- SwitchEditorViewportCamera(m_viewCameraEntityIdToRestore); // Switch Editor Viewport back to the stored camera, which was active prior to switching to Play Game mode.
- }
- //////////////////////////////////////////////////////////////////////////
- void CAnimationContext::OnEditorNotifyEvent(EEditorNotifyEvent event)
- {
- switch (event)
- {
- case eNotify_OnBeginGameMode:
- if (m_pSequence)
- {
- // Reset the sequence, so that changed camera positions are restored
- m_pSequence->Reset(false);
- // Force recent changes made in TrackView, updating in-memory prefab using Undo/Redo framework
- AzToolsFramework::ScopedUndoBatch undoBatch("Update TrackView Sequence Before Playing Game");
- undoBatch.MarkEntityDirty(m_pSequence->GetSequenceComponentEntityId());
- }
- {
- // This notification arrives before even the OnStartPlayInEditorBegin and later OnStartPlayInEditor events
- // arrive to Editor Views, and thus switching cameras is still available.
- // So, after storing an active camera Id, rollback the Editor Viewport to default "Editor camera" in order
- // to help Editor correctly restore viewport state after switching back to Editing mode,
- // then set the 'm_bIsInGameMode' flag, store an active sequence and drop it.
- constexpr const bool isSwitchingToGameMode = true;
- StoreSequenceOnExitingEditMode(isSwitchingToGameMode);
- }
- break;
- case eNotify_OnBeginSceneSave:
- case eNotify_OnBeginLayerExport:
- if (m_pSequence)
- {
- // Reset the sequence, so that changed camera positions are restored
- m_pSequence->Reset(false);
- // Force recent changes made in TrackView, updating in-memory prefab using Undo/Redo framework
- AzToolsFramework::ScopedUndoBatch undoBatch("Update TrackView Sequence Before Saving");
- undoBatch.MarkEntityDirty(m_pSequence->GetSequenceComponentEntityId());
- }
- {
- // Store active sequence and camera Ids and drop this sequence.
- constexpr const bool isSwitchingToGameMode = false;
- StoreSequenceOnExitingEditMode(isSwitchingToGameMode);
- }
- break;
- case eNotify_OnEndGameMode:
- // Delay restoring previously active sequence and Editor Viewport camera, and clearing 'm_bIsInGameMode' flag,
- // for 2 frames, while Editor Viewport state goes from "Started" to "Stopping" and finally back to "Editor",
- // and switching cameras is not supported.
- m_countWaitingForExitingGameMode = 2;
- break;
- case eNotify_OnEndSceneSave:
- case eNotify_OnEndLayerExport:
- // Restore previously active sequence and camera in Editor Viewport.
- RestoreSequenceOnEnteringEditMode();
- break;
- case eNotify_OnQuit:
- case eNotify_OnCloseScene:
- SetSequence(nullptr, true, false);
- break;
- case eNotify_OnBeginNewScene:
- SetSequence(nullptr, false, false);
- break;
- case eNotify_OnBeginLoad:
- m_mostRecentSequenceId.SetInvalid();
- m_mostRecentSequenceTime = 0.0f;
- m_bSavedRecordingState = m_recording;
- SetRecordingInternal(false);
- SetSequence(nullptr, false, false);
- break;
- case eNotify_OnEndLoad:
- SetRecordingInternal(m_bSavedRecordingState);
- break;
- }
- }
- void CAnimationContext::SetRecordingInternal(bool enableRecording)
- {
- if (m_movieSystem)
- {
- m_movieSystem->SetRecording(enableRecording);
- }
- if (m_pSequence)
- {
- m_pSequence->SetRecording(enableRecording);
- }
- }
- void CAnimationContext::AnimateActiveSequence()
- {
- if (!m_pSequence)
- {
- return;
- }
- SAnimContext ac;
- ac.dt = 0;
- const AZ::TimeUs frameDeltaTimeUs = AZ::GetSimulationTickDeltaTimeUs();
- const float frameDeltaTime = AZ::TimeUsToSeconds(frameDeltaTimeUs);
- ac.fps = 1.0f / frameDeltaTime;
- ac.time = m_currTime;
- ac.singleFrame = true;
- ac.forcePlay = true;
- m_pSequence->Animate(ac);
- m_pSequence->SyncToConsole(ac);
- }
|