// Copyright Epic Games, Inc. All Rights Reserved. #include "MovieSceneTimeHelpers.h" #include "CoreTypes.h" #include "Misc/FrameNumber.h" #include "Misc/FrameRate.h" #include "Misc/FrameTime.h" #include "Misc/ScopedSlowTask.h" #include "Sections/MovieSceneSubSection.h" #include "Sections/MovieSceneSubSection.h" #include "Tracks/MovieSceneSubTrack.h" #include "MovieScene.h" #include "MovieSceneSection.h" #include "MovieSceneTrack.h" #include "MovieSceneSequence.h" #include "Channels/MovieSceneChannelProxy.h" #include "Channels/MovieSceneChannel.h" #include "IMovieSceneRetimingInterface.h" namespace UE { namespace MovieScene { TRange MigrateFrameRange(const TRange& SourceRange, const IRetimingInterface& RetimingInterface) { TRange NewRange = TRange::All(); if (!SourceRange.GetLowerBound().IsOpen()) { const FFrameNumber FrameNumber = RetimingInterface.RemapTime(SourceRange.GetLowerBoundValue()); NewRange.SetLowerBound( SourceRange.GetLowerBound().IsExclusive() ? TRangeBound::Exclusive(FrameNumber) : TRangeBound::Inclusive(FrameNumber) ); } if (!SourceRange.GetUpperBound().IsOpen()) { const FFrameNumber FrameNumber = RetimingInterface.RemapTime(SourceRange.GetUpperBoundValue()); NewRange.SetUpperBound( SourceRange.GetUpperBound().IsExclusive() ? TRangeBound::Exclusive(FrameNumber) : TRangeBound::Inclusive(FrameNumber) ); } return NewRange; } void MigrateFrameTimes(const IRetimingInterface& Retimer, UMovieSceneSection* Section) { Section->Modify(); const bool bSectionWasLocked = Section->IsLocked(); Section->SetIsLocked(false); TRangeBound NewLowerBound, NewUpperBound; if (Section->HasStartFrame()) { FFrameNumber NewLowerBoundFrame = Retimer.RemapTime(Section->GetInclusiveStartFrame()); NewLowerBound = TRangeBound::Inclusive(NewLowerBoundFrame); } if (Section->HasEndFrame()) { FFrameNumber NewUpperBoundValue = Retimer.RemapTime(Section->GetExclusiveEndFrame()); NewUpperBound = TRangeBound::Exclusive(NewUpperBoundValue); } Section->SetRange(TRange(NewLowerBound, NewUpperBound)); if (Section->GetPreRollFrames() > 0) { FFrameNumber NewPreRollFrameCount = Retimer.RemapTime(FFrameNumber(Section->GetPreRollFrames())); Section->SetPreRollFrames(NewPreRollFrameCount.Value); } if (Section->GetPostRollFrames() > 0) { FFrameNumber NewPostRollFrameCount = Retimer.RemapTime(FFrameNumber(Section->GetPostRollFrames())); Section->SetPostRollFrames(NewPostRollFrameCount.Value); } Section->MigrateFrameTimes(Retimer); Section->Easing.AutoEaseInDuration = Retimer.RemapTime(FFrameNumber(Section->Easing.AutoEaseInDuration)).Value; Section->Easing.AutoEaseOutDuration = Retimer.RemapTime(FFrameNumber(Section->Easing.AutoEaseOutDuration)).Value; Section->Easing.ManualEaseInDuration = Retimer.RemapTime(FFrameNumber(Section->Easing.ManualEaseInDuration)).Value; Section->Easing.ManualEaseOutDuration = Retimer.RemapTime(FFrameNumber(Section->Easing.ManualEaseOutDuration)).Value; for (const FMovieSceneChannelEntry& Entry : Section->GetChannelProxy().GetAllEntries()) { for (FMovieSceneChannel* Channel : Entry.GetChannels()) { Channel->RemapTimes(Retimer); } } Section->SetIsLocked(bSectionWasLocked); } void MigrateFrameTimes(const IRetimingInterface& Retimer, UMovieSceneTrack* Track) { FScopedSlowTask SlowTask(Track->GetAllSections().Num()); for (UMovieSceneSection* Section : Track->GetAllSections()) { SlowTask.EnterProgressFrame(); MigrateFrameTimes(Retimer, Section); } } void TimeHelpers::MigrateFrameTimes(FFrameRate SourceRate, FFrameRate DestinationRate, UMovieScene* MovieScene, bool bApplyRecursively) { FFrameRateRetiming Retimer(SourceRate, DestinationRate); MigrateFrameTimes(Retimer, MovieScene, bApplyRecursively); } void TimeHelpers::MigrateFrameTimes(const IRetimingInterface& Retimer, UMovieScene* MovieScene, bool bApplyRecursively) { MovieScene->Modify(); #if WITH_EDITOR const bool bMovieSceneReadOnly = MovieScene->IsReadOnly(); MovieScene->SetReadOnly(false); #endif Retimer.Begin(MovieScene); int32 TotalNumTracks = MovieScene->GetTracks().Num() + (MovieScene->GetCameraCutTrack() ? 1 : 0); for (const FMovieSceneBinding& Binding : MovieScene->GetBindings()) { TotalNumTracks += Binding.GetTracks().Num(); } FScopedSlowTask SlowTask(TotalNumTracks, NSLOCTEXT("MovieScene", "ChangingTickResolution", "Migrating sequence frame timing")); SlowTask.MakeDialogDelayed(0.25f, true); MovieScene->SetPlaybackRange(MigrateFrameRange(MovieScene->GetPlaybackRange(), Retimer)); #if WITH_EDITORONLY_DATA MovieScene->SetSelectionRange(MigrateFrameRange(MovieScene->GetSelectionRange(), Retimer)); #endif for (UMovieSceneTrack* Track : MovieScene->GetTracks()) { SlowTask.EnterProgressFrame(); UE::MovieScene::MigrateFrameTimes(Retimer, Track); // We iterate through recursively here (and not in MigrateFrameTimes) so that the movie scene is taken // into account for locking/modifying/etc. if (bApplyRecursively && Track->IsA()) { for (UMovieSceneSection* Section : Track->GetAllSections()) { UMovieSceneSubSection* SubSection = Cast(Section); if (SubSection) { if (UMovieSceneSequence* SubSequence = SubSection->GetSequence()) { UMovieScene* ChildMovieScene = SubSequence->GetMovieScene(); if (ChildMovieScene) { TUniquePtr ChildRetimer = Retimer.RecurseInto(ChildMovieScene); if (ChildRetimer) { TimeHelpers::MigrateFrameTimes(*ChildRetimer, ChildMovieScene, bApplyRecursively); } } } } } } } if (UMovieSceneTrack* Track = MovieScene->GetCameraCutTrack()) { SlowTask.EnterProgressFrame(); UE::MovieScene::MigrateFrameTimes(Retimer, Track); } for (const FMovieSceneBinding& Binding : MovieScene->GetBindings()) { for (UMovieSceneTrack* Track : Binding.GetTracks()) { SlowTask.EnterProgressFrame(); UE::MovieScene::MigrateFrameTimes(Retimer, Track); } } { TArray MarkedFrames = MovieScene->GetMarkedFrames(); // Clear the marked frames as the returned array is immutable MovieScene->DeleteMarkedFrames(); for (FMovieSceneMarkedFrame& MarkedFrame : MarkedFrames) { MarkedFrame.FrameNumber = Retimer.RemapTime(MarkedFrame.FrameNumber); // Add it back in MovieScene->AddMarkedFrame(MarkedFrame); } // Ensure they're in order as they may not have been before. MovieScene->SortMarkedFrames(); } Retimer.End(MovieScene); #if WITH_EDITOR MovieScene->SetReadOnly(bMovieSceneReadOnly); #endif } } // namespace MovieScene } // namespace UE