!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / Plugins / EditorTrackView / AnimationContext.cpp
blob9fb6cf9e5504d3a021889d45825693a36be9c476
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "AnimationContext.h"
6 #include "Objects/SelectionGroup.h"
7 #include "Objects/EntityObject.h"
8 #include "Objects/ObjectManager.h"
9 #include "Nodes/TrackViewSequence.h"
10 #include "Animators/CommentNodeAnimator.h"
12 #include "RenderViewport.h"
13 #include "Viewport.h"
14 #include "ViewManager.h"
15 #include "IPostRenderer.h"
16 #include "TrackViewPlugin.h"
18 #include <CryMovie/IMovieSystem.h>
19 #include <CrySystem/ITimer.h>
21 class CMovieCallback : public IMovieCallback, public ICameraDelegate
23 public:
24 CMovieCallback() : m_cameraObjectGUID(CryGUID::Null()) {}
25 void OnSetCamera(const SCameraParams& cameraParams)
27 CEntityObject* pEditorEntity = CEntityObject::FindFromEntityId(cameraParams.cameraEntityId);
28 if (pEditorEntity)
30 m_cameraObjectGUID = pEditorEntity->GetId();
32 else
34 m_cameraObjectGUID = CryGUID::Null();
38 void ResetCamera()
40 m_cameraObjectGUID = CryGUID::Null();
43 virtual CryGUID GetActiveCameraObjectGUID() const
45 return m_cameraObjectGUID;
48 virtual const char* GetName() const
50 return "TrackView";
53 private:
54 CryGUID m_cameraObjectGUID;
57 static CMovieCallback s_movieCallback;
59 class CAnimationContextPostRender : public IPostRenderer
61 public:
62 CAnimationContextPostRender(CAnimationContext* pAC)
63 : m_pAC(pAC)
67 void OnPostRender() const { assert(m_pAC); m_pAC->OnPostRender(); }
69 protected:
70 CAnimationContext* m_pAC;
73 CAnimationContext::CAnimationContext()
75 m_bPlaying = false;
76 m_bPaused = false;
77 m_bRecording = false;
78 m_bSavedRecordingState = false;
79 m_timeRange.Set(SAnimTime(0.0f), SAnimTime(0.0f));
80 m_playbackRange.Set(SAnimTime(0.0f), SAnimTime(0.0f));
81 m_currTime = SAnimTime(0.0f);
82 m_bForceUpdateInNextFrame = false;
83 m_fTimeScale = 1.0f;
84 m_pSequence = nullptr;
85 m_bLooping = false;
86 m_bAutoRecording = false;
87 m_recordingTimeStep = SAnimTime(0.0f);
88 m_bSingleFrame = false;
89 m_bPostRenderRegistered = false;
90 m_bWasRecording = false;
92 GetIEditor()->GetIUndoManager()->AddListener(this);
93 CTrackViewPlugin::GetSequenceManager()->AddListener(this);
94 GetIEditor()->RegisterNotifyListener(this);
95 GetIEditor()->GetGameEngine()->AddListener(this);
96 GetIEditor()->GetViewManager()->RegisterCameraDelegate(&s_movieCallback);
98 gEnv->pMovieSystem->SetCallback(&s_movieCallback);
99 gEnv->pMovieSystem->AddMovieListener(nullptr, this);
100 REGISTER_COMMAND("mov_goToFrameEditor", (ConsoleCommandFunc)GoToFrameCmd, 0, "Make a specified sequence go to a given frame time in the editor.");
103 CAnimationContext::~CAnimationContext()
105 gEnv->pMovieSystem->SetCallback(NULL);
106 gEnv->pMovieSystem->RemoveMovieListener(nullptr, this);
108 GetIEditor()->GetViewManager()->UnregisterCameraDelegate(&s_movieCallback);
109 GetIEditor()->GetGameEngine()->RemoveListener(this);
110 CTrackViewPlugin::GetSequenceManager()->RemoveListener(this);
111 GetIEditor()->GetIUndoManager()->RemoveListener(this);
112 GetIEditor()->UnregisterNotifyListener(this);
115 void CAnimationContext::AddListener(IAnimationContextListener* pListener)
117 stl::push_back_unique(m_contextListeners, pListener);
120 void CAnimationContext::RemoveListener(IAnimationContextListener* pListener)
122 stl::find_and_erase(m_contextListeners, pListener);
125 void CAnimationContext::SetSequence(CTrackViewSequence* pSequence, bool bForce, bool bNoNotify)
127 CTrackViewSequence* pCurrentSequence = m_pSequence;
129 if (!bForce && pSequence == pCurrentSequence)
131 return;
134 // Prevent keys being created from time change
135 const bool bRecording = m_bRecording;
136 m_bRecording = false;
138 m_currTime = m_recordingCurrTime = SAnimTime(0.0f);
140 if (!m_bPostRenderRegistered)
142 if (GetIEditor() && GetIEditor()->GetViewManager())
144 CViewport* pViewport = GetIEditor()->GetViewManager()->GetViewport(ET_ViewportCamera);
146 if (pViewport)
148 pViewport->AddPostRenderer(new CAnimationContextPostRender(this));
149 m_bPostRenderRegistered = true;
154 if (m_pSequence)
156 m_pSequence->Deactivate();
158 if (m_bPlaying)
160 m_pSequence->EndCutScene();
163 m_pSequence->UnBindFromEditorObjects();
164 s_movieCallback.ResetCamera();
167 m_pSequence = pSequence;
169 if (m_pSequence)
171 if (m_bPlaying)
173 m_pSequence->BeginCutScene(true);
176 UpdateTimeRange();
177 m_pSequence->Activate();
178 m_pSequence->PrecacheData(SAnimTime(0.0f));
180 m_pSequence->BindToEditorObjects();
183 ForceAnimation();
185 if (!bNoNotify)
187 for (size_t i = 0; i < m_contextListeners.size(); ++i)
189 if (!pSequence)
190 m_contextListeners[i]->OnTimeChanged(SAnimTime(0));
191 else
192 m_contextListeners[i]->OnTimeChanged(pSequence->GetTimeRange().start);
194 m_contextListeners[i]->OnSequenceChanged(m_pSequence);
198 m_bRecording = bRecording;
201 void CAnimationContext::UpdateTimeRange()
203 if (m_pSequence)
205 m_timeRange = m_pSequence->GetTimeRange();
206 auto seqPlaybackRange = m_pSequence->GetPlaybackRange();
207 m_playbackRange.start = seqPlaybackRange.start != SAnimTime(-1) ? std::max(seqPlaybackRange.start, m_timeRange.start) : m_timeRange.start;
208 m_playbackRange.start = std::min(m_playbackRange.start, m_timeRange.end);
209 m_playbackRange.end = seqPlaybackRange.end != SAnimTime(-1) ? std::min(seqPlaybackRange.end, m_timeRange.end) : m_timeRange.end;
210 m_playbackRange.end = std::max(m_playbackRange.end, m_playbackRange.start);
211 m_playbackRange.end = std::max(m_playbackRange.end, m_timeRange.start);
215 void CAnimationContext::SetLoopMode(bool bLooping)
217 if (m_bLooping != bLooping)
219 m_bLooping = bLooping;
221 for (size_t i = 0; i < m_contextListeners.size(); ++i)
222 m_contextListeners[i]->OnLoopingStateChanged(m_bLooping);
226 void CAnimationContext::SetTime(SAnimTime t)
228 if (t < m_timeRange.start)
230 t = m_timeRange.start;
233 if (t > m_timeRange.end)
235 t = m_timeRange.end;
238 if (m_currTime == t)
240 return;
243 m_currTime = t;
244 m_recordingCurrTime = t;
245 ForceAnimation();
246 UpdateAnimatedLights();
248 for (size_t i = 0; i < m_contextListeners.size(); ++i)
250 m_contextListeners[i]->OnTimeChanged(m_currTime);
254 void CAnimationContext::SetRecording(bool bRecording)
256 if (bRecording == m_bRecording)
258 return;
261 m_bRecording = bRecording;
262 m_bPlaying = false;
264 if (!bRecording && m_recordingTimeStep != SAnimTime(0.0f))
266 SetAutoRecording(false, SAnimTime(0));
269 // If started recording, assume we have modified the document.
270 GetIEditor()->SetModifiedFlag();
272 for (size_t i = 0; i < m_contextListeners.size(); ++i)
274 m_contextListeners[i]->OnRecordingStateChanged(bRecording);
278 void CAnimationContext::PlayPause(bool playOrPause)
280 if (m_bRecording)
282 m_bWasRecording = true;
283 SetRecording(false);
286 if (m_pSequence == nullptr || !m_bPlaying && !playOrPause || m_bPlaying && playOrPause == !m_bPaused)
288 return;
291 if (playOrPause)
293 UpdateTimeRange();
294 // We need to deactivate/activate here to ensure all nodes update
295 // to the latest changes done in editor.
297 // TODO: Nicer would be a proper way just to refresh.
298 m_pSequence->Deactivate();
299 m_pSequence->Activate();
302 if (!m_bPlaying && !m_bWasRecording)
304 m_currTime = m_playbackRange.start;
307 if (!m_bPlaying)
309 m_bPlaying = true;
312 if (!m_bPaused && !playOrPause)
314 GetIEditor()->GetMovieSystem()->Pause();
316 if (m_pSequence)
318 m_pSequence->Pause();
321 m_bPaused = true;
323 else if (m_bPaused && playOrPause)
325 GetIEditor()->GetMovieSystem()->Resume();
327 if (m_pSequence)
329 m_pSequence->Resume();
332 m_bPaused = false;
335 for (size_t i = 0; i < m_contextListeners.size(); ++i)
337 m_contextListeners[i]->OnPlaybackStateChanged(m_bPlaying, m_bPaused);
340 if (m_bPaused && m_bWasRecording)
342 m_bWasRecording = false;
343 SetRecording(true);
347 void CAnimationContext::Stop()
349 if (m_bWasRecording)
351 m_bWasRecording = false;
352 SetRecording(true);
355 m_bPlaying = false;
356 m_bPaused = false;
357 m_bSingleFrame = true; //still need one frame update
359 for (size_t i = 0; i < m_contextListeners.size(); ++i)
361 m_contextListeners[i]->OnPlaybackStateChanged(m_bPlaying, m_bPaused);
365 void CAnimationContext::Update()
367 const SAnimTime lastTime = m_currTime;
368 bool forceNotify = false;
370 if (m_bForceUpdateInNextFrame)
372 ForceAnimation();
373 m_bForceUpdateInNextFrame = false;
376 // If looking through camera object and recording animation, do not allow camera shake
377 if ((GetIEditor()->GetViewManager()->GetCameraObjectId() != CryGUID::Null()) && IsRecording())
379 GetIEditor()->GetMovieSystem()->EnableCameraShake(false);
381 else
383 GetIEditor()->GetMovieSystem()->EnableCameraShake(true);
386 if ((!m_bPlaying && !m_bAutoRecording && !m_bSingleFrame) || (m_bPlaying && m_bPaused && !m_bSingleFrame))
388 if (m_pSequence)
390 m_pSequence->StillUpdate();
393 if (!m_bRecording)
395 GetIEditor()->GetMovieSystem()->StillUpdate();
398 return;
401 if (!m_bPlaying || m_bPaused)
403 return;
406 ITimer* pTimer = GetIEditor()->GetSystem()->GetITimer();
407 const float frameTime = pTimer->GetFrameTime();
409 if (m_bAutoRecording)
411 m_recordingCurrTime += SAnimTime(frameTime * m_fTimeScale);
412 if ((m_recordingCurrTime - m_currTime) > m_recordingTimeStep)
414 m_currTime += m_recordingTimeStep;
417 if (m_currTime > m_playbackRange.end)
419 SetAutoRecording(false, SAnimTime(0));
422 // Send sync with physics event to all selected entities.
423 GetIEditor()->GetISelectionGroup()->SendEvent(EVENT_PHYSICS_GETSTATE);
425 else //normal playing code path
427 bool updateTime = true;
429 if (m_pSequence != NULL)
431 SAnimContext ac;
432 ac.dt = SAnimTime(0);
433 ac.time = m_currTime;
434 ac.bSingleFrame = m_bSingleFrame;
435 ac.m_activeCameraEntity = GetActiveCameraEntityId();
437 if (m_bSingleFrame)
439 m_bSingleFrame = false;
440 forceNotify = true;
441 updateTime = false;
444 ac.bForcePlay = false;
445 m_pSequence->Animate(ac);
446 m_pSequence->SyncToConsole(ac);
449 if (!m_bRecording)
451 GetIEditor()->GetMovieSystem()->PreUpdate(frameTime);
452 GetIEditor()->GetMovieSystem()->PostUpdate(frameTime);
455 if (updateTime)
457 SAnimTime futureTime = m_currTime + SAnimTime(frameTime * m_fTimeScale);
458 if (futureTime > m_playbackRange.end)
460 if (m_bLooping)
462 m_currTime = m_playbackRange.start + futureTime - m_playbackRange.end;
464 else
466 m_currTime = m_playbackRange.end;
467 Stop();
470 else
472 m_currTime = futureTime;
477 if (lastTime != m_currTime || forceNotify)
479 for (size_t i = 0; i < m_contextListeners.size(); ++i)
481 m_contextListeners[i]->OnTimeChanged(m_currTime);
485 UpdateAnimatedLights();
488 void CAnimationContext::ForceAnimation()
490 // For force animation, disable auto recording
491 const bool bAutoRecording = m_bAutoRecording;
493 if (bAutoRecording)
495 SetAutoRecording(false, m_recordingTimeStep);
498 if (m_pSequence)
500 SAnimContext ac;
501 ac.time = m_currTime;
502 ac.bSingleFrame = true;
503 ac.bForcePlay = true;
504 ac.m_activeCameraEntity = GetActiveCameraEntityId();
506 m_pSequence->Animate(ac);
507 m_pSequence->SyncToConsole(ac);
510 if (bAutoRecording)
512 SetAutoRecording(true, m_recordingTimeStep);
515 GetIEditor()->UpdateViews();
518 EntityId CAnimationContext::GetActiveCameraEntityId() const
520 if (GetIEditor() && GetIEditor()->GetViewManager())
522 CViewManager* pViewManager = GetIEditor()->GetViewManager();
523 const CViewport* pViewport = pViewManager->GetActiveViewport();
524 if (pViewport && pViewport->IsSequenceCamera())
526 if (pViewManager->GetCameraObjectId() != s_movieCallback.GetActiveCameraObjectGUID())
528 pViewManager->SetCameraObjectId(s_movieCallback.GetActiveCameraObjectGUID());
532 const CBaseObject* pCameraObject = GetIEditor()->GetObjectManager()->FindObject(pViewManager->GetCameraObjectId());
533 const IEntity* pCameraEntity = pCameraObject ? ((CEntityObject*)pCameraObject)->GetIEntity() : nullptr;
534 if (pCameraEntity)
536 return pCameraEntity->GetId();
540 return 0;
543 void CAnimationContext::SetAutoRecording(bool bEnable, SAnimTime fTimeStep)
545 if (bEnable)
547 m_bAutoRecording = true;
548 m_recordingTimeStep = fTimeStep;
550 // Enables physics/ai.
551 GetIEditor()->GetGameEngine()->SetSimulationMode(true);
552 SetRecording(bEnable);
554 else
556 m_bAutoRecording = false;
557 m_recordingTimeStep = SAnimTime(0);
559 // Disables physics/ai.
560 GetIEditor()->GetGameEngine()->SetSimulationMode(false);
564 void CAnimationContext::GoToFrameCmd(IConsoleCmdArgs* pArgs)
566 if (pArgs->GetArgCount() < 3)
568 gEnv->pLog->LogError("GoToFrame failed! You should provide two arguments of the 'sequence name' & 'frame time'.");
569 return;
572 CAnimationContext* pAnimationContext = CTrackViewPlugin::GetAnimationContext();
574 assert(pAnimationContext);
575 CTrackViewSequence* pSeq = pAnimationContext->GetSequence();
576 string fullname = pSeq->GetName();
577 assert(pSeq && strcmp(fullname.c_str(), pArgs->GetArg(1)) == 0);
578 float targetFrame = (float)atof(pArgs->GetArg(2));
579 assert(pSeq->GetTimeRange().start <= SAnimTime(targetFrame) && SAnimTime(targetFrame) <= pSeq->GetTimeRange().end);
580 CTrackViewPlugin::GetAnimationContext()->m_currTime = SAnimTime(targetFrame);
581 pAnimationContext->m_bSingleFrame = true;
583 pAnimationContext->ForceAnimation();
586 void CAnimationContext::OnPostRender()
588 if (m_pSequence)
590 SAnimContext ac;
591 ac.time = m_currTime;
592 ac.bSingleFrame = true;
593 ac.bForcePlay = true;
594 ac.m_activeCameraEntity = GetActiveCameraEntityId();
595 m_pSequence->Render(ac);
599 void CAnimationContext::UpdateAnimatedLights()
601 bool bLightAnimationSetActive = m_pSequence && (m_pSequence->GetFlags() & IAnimSequence::eSeqFlags_LightAnimationSet);
602 if (bLightAnimationSetActive == false)
603 return;
605 std::vector<CBaseObject*> entityObjects;
606 GetIEditor()->GetObjectManager()->FindObjectsOfType(RUNTIME_CLASS(CEntityObject), entityObjects);
607 std::for_each(std::begin(entityObjects), std::end(entityObjects), [this](CBaseObject* pBaseObject)
609 CEntityObject* pEntityObject = static_cast<CEntityObject*>(pBaseObject);
610 bool bLight = pEntityObject && (pEntityObject->GetEntityClass().Compare("Light") == 0);
611 if (bLight)
613 bool bTimeScrubbing = pEntityObject->GetEntityPropertyBool("bTimeScrubbingInTrackView");
614 if (bTimeScrubbing)
616 pEntityObject->SetEntityPropertyFloat("_fTimeScrubbed", m_currTime);
622 void CAnimationContext::BeginUndoTransaction()
624 m_bSavedRecordingState = m_bRecording;
627 void CAnimationContext::EndUndoTransaction()
629 if (m_pSequence)
631 m_pSequence->BindToEditorObjects();
635 void CAnimationContext::OnSequenceRemoved(CTrackViewSequence* pSequence)
637 if (m_pSequence == pSequence)
639 SetSequence(nullptr, true, false);
642 void CAnimationContext::OnEditorNotifyEvent(EEditorNotifyEvent event)
644 switch (event)
646 case eNotify_OnBeginGameMode:
647 if (m_pSequence)
649 m_pSequence->Resume();
652 case eNotify_OnBeginSceneSave:
653 case eNotify_OnBeginLayerExport:
654 if (m_pSequence)
656 m_sequenceName = m_pSequence->GetName();
658 else
660 m_sequenceName = "";
663 m_sequenceTime = GetTime();
665 m_bSavedRecordingState = m_bRecording;
666 SetSequence(nullptr, true, true);
667 break;
669 case eNotify_OnEndGameMode:
670 case eNotify_OnEndSceneSave:
671 case eNotify_OnEndLayerExport:
672 m_currTime = m_sequenceTime;
673 SetSequence(CTrackViewPlugin::GetSequenceManager()->GetSequenceByName(m_sequenceName), true, true);
674 SetTime(m_sequenceTime);
675 break;
677 case eNotify_OnClearLevelContents:
678 SetSequence(nullptr, true, false);
679 break;
681 case eNotify_OnBeginNewScene:
682 SetSequence(nullptr, false, false);
683 break;
685 case eNotify_OnBeginLoad:
686 m_bSavedRecordingState = m_bRecording;
687 CTrackViewPlugin::GetAnimationContext()->SetSequence(nullptr, false, false);
688 break;
690 case eNotify_CameraChanged:
691 ForceAnimation();
692 break;
696 void CAnimationContext::OnMovieEvent(EMovieEvent movieEvent, IAnimSequence* pAnimSequence)
698 if (gEnv->IsEditorGameMode())
699 return;
701 switch (movieEvent)
703 case eMovieEvent_Started:
705 CTrackViewSequence* pTrackViewSequence = CTrackViewPlugin::GetSequenceManager()->GetSequenceByName(pAnimSequence->GetName());
706 SetSequence(pTrackViewSequence, true, false);
708 break;
709 case eMovieEvent_Stopped:
710 SetSequence(nullptr, true, false);
711 break;
712 default:
713 break;