1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
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"
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
24 CMovieCallback() : m_cameraObjectGUID(CryGUID::Null()) {}
25 void OnSetCamera(const SCameraParams
& cameraParams
)
27 CEntityObject
* pEditorEntity
= CEntityObject::FindFromEntityId(cameraParams
.cameraEntityId
);
30 m_cameraObjectGUID
= pEditorEntity
->GetId();
34 m_cameraObjectGUID
= CryGUID::Null();
40 m_cameraObjectGUID
= CryGUID::Null();
43 virtual CryGUID
GetActiveCameraObjectGUID() const
45 return m_cameraObjectGUID
;
48 virtual const char* GetName() const
54 CryGUID m_cameraObjectGUID
;
57 static CMovieCallback s_movieCallback
;
59 class CAnimationContextPostRender
: public IPostRenderer
62 CAnimationContextPostRender(CAnimationContext
* pAC
)
67 void OnPostRender() const { assert(m_pAC
); m_pAC
->OnPostRender(); }
70 CAnimationContext
* m_pAC
;
73 CAnimationContext::CAnimationContext()
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;
84 m_pSequence
= nullptr;
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
)
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
);
148 pViewport
->AddPostRenderer(new CAnimationContextPostRender(this));
149 m_bPostRenderRegistered
= true;
156 m_pSequence
->Deactivate();
160 m_pSequence
->EndCutScene();
163 m_pSequence
->UnBindFromEditorObjects();
164 s_movieCallback
.ResetCamera();
167 m_pSequence
= pSequence
;
173 m_pSequence
->BeginCutScene(true);
177 m_pSequence
->Activate();
178 m_pSequence
->PrecacheData(SAnimTime(0.0f
));
180 m_pSequence
->BindToEditorObjects();
187 for (size_t i
= 0; i
< m_contextListeners
.size(); ++i
)
190 m_contextListeners
[i
]->OnTimeChanged(SAnimTime(0));
192 m_contextListeners
[i
]->OnTimeChanged(pSequence
->GetTimeRange().start
);
194 m_contextListeners
[i
]->OnSequenceChanged(m_pSequence
);
198 m_bRecording
= bRecording
;
201 void CAnimationContext::UpdateTimeRange()
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
)
244 m_recordingCurrTime
= t
;
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
)
261 m_bRecording
= bRecording
;
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
)
282 m_bWasRecording
= true;
286 if (m_pSequence
== nullptr || !m_bPlaying
&& !playOrPause
|| m_bPlaying
&& playOrPause
== !m_bPaused
)
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
;
312 if (!m_bPaused
&& !playOrPause
)
314 GetIEditor()->GetMovieSystem()->Pause();
318 m_pSequence
->Pause();
323 else if (m_bPaused
&& playOrPause
)
325 GetIEditor()->GetMovieSystem()->Resume();
329 m_pSequence
->Resume();
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;
347 void CAnimationContext::Stop()
351 m_bWasRecording
= 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
)
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);
383 GetIEditor()->GetMovieSystem()->EnableCameraShake(true);
386 if ((!m_bPlaying
&& !m_bAutoRecording
&& !m_bSingleFrame
) || (m_bPlaying
&& m_bPaused
&& !m_bSingleFrame
))
390 m_pSequence
->StillUpdate();
395 GetIEditor()->GetMovieSystem()->StillUpdate();
401 if (!m_bPlaying
|| m_bPaused
)
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
)
432 ac
.dt
= SAnimTime(0);
433 ac
.time
= m_currTime
;
434 ac
.bSingleFrame
= m_bSingleFrame
;
435 ac
.m_activeCameraEntity
= GetActiveCameraEntityId();
439 m_bSingleFrame
= false;
444 ac
.bForcePlay
= false;
445 m_pSequence
->Animate(ac
);
446 m_pSequence
->SyncToConsole(ac
);
451 GetIEditor()->GetMovieSystem()->PreUpdate(frameTime
);
452 GetIEditor()->GetMovieSystem()->PostUpdate(frameTime
);
457 SAnimTime futureTime
= m_currTime
+ SAnimTime(frameTime
* m_fTimeScale
);
458 if (futureTime
> m_playbackRange
.end
)
462 m_currTime
= m_playbackRange
.start
+ futureTime
- m_playbackRange
.end
;
466 m_currTime
= m_playbackRange
.end
;
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
;
495 SetAutoRecording(false, m_recordingTimeStep
);
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
);
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;
536 return pCameraEntity
->GetId();
543 void CAnimationContext::SetAutoRecording(bool bEnable
, SAnimTime fTimeStep
)
547 m_bAutoRecording
= true;
548 m_recordingTimeStep
= fTimeStep
;
550 // Enables physics/ai.
551 GetIEditor()->GetGameEngine()->SetSimulationMode(true);
552 SetRecording(bEnable
);
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'.");
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()
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)
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);
613 bool bTimeScrubbing
= pEntityObject
->GetEntityPropertyBool("bTimeScrubbingInTrackView");
616 pEntityObject
->SetEntityPropertyFloat("_fTimeScrubbed", m_currTime
);
622 void CAnimationContext::BeginUndoTransaction()
624 m_bSavedRecordingState
= m_bRecording
;
627 void CAnimationContext::EndUndoTransaction()
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
)
646 case eNotify_OnBeginGameMode
:
649 m_pSequence
->Resume();
652 case eNotify_OnBeginSceneSave
:
653 case eNotify_OnBeginLayerExport
:
656 m_sequenceName
= m_pSequence
->GetName();
663 m_sequenceTime
= GetTime();
665 m_bSavedRecordingState
= m_bRecording
;
666 SetSequence(nullptr, true, true);
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
);
677 case eNotify_OnClearLevelContents
:
678 SetSequence(nullptr, true, false);
681 case eNotify_OnBeginNewScene
:
682 SetSequence(nullptr, false, false);
685 case eNotify_OnBeginLoad
:
686 m_bSavedRecordingState
= m_bRecording
;
687 CTrackViewPlugin::GetAnimationContext()->SetSequence(nullptr, false, false);
690 case eNotify_CameraChanged
:
696 void CAnimationContext::OnMovieEvent(EMovieEvent movieEvent
, IAnimSequence
* pAnimSequence
)
698 if (gEnv
->IsEditorGameMode())
703 case eMovieEvent_Started
:
705 CTrackViewSequence
* pTrackViewSequence
= CTrackViewPlugin::GetSequenceManager()->GetSequenceByName(pAnimSequence
->GetName());
706 SetSequence(pTrackViewSequence
, true, false);
709 case eMovieEvent_Stopped
:
710 SetSequence(nullptr, true, false);