Files
UnrealEngine/Engine/Source/Runtime/MovieScene/Private/MovieSceneTimeHelpers.cpp
2025-05-18 13:04:45 +08:00

219 lines
6.7 KiB
C++

// 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<FFrameNumber> MigrateFrameRange(const TRange<FFrameNumber>& SourceRange, const IRetimingInterface& RetimingInterface)
{
TRange<FFrameNumber> NewRange = TRange<FFrameNumber>::All();
if (!SourceRange.GetLowerBound().IsOpen())
{
const FFrameNumber FrameNumber = RetimingInterface.RemapTime(SourceRange.GetLowerBoundValue());
NewRange.SetLowerBound(
SourceRange.GetLowerBound().IsExclusive()
? TRangeBound<FFrameNumber>::Exclusive(FrameNumber)
: TRangeBound<FFrameNumber>::Inclusive(FrameNumber)
);
}
if (!SourceRange.GetUpperBound().IsOpen())
{
const FFrameNumber FrameNumber = RetimingInterface.RemapTime(SourceRange.GetUpperBoundValue());
NewRange.SetUpperBound(
SourceRange.GetUpperBound().IsExclusive()
? TRangeBound<FFrameNumber>::Exclusive(FrameNumber)
: TRangeBound<FFrameNumber>::Inclusive(FrameNumber)
);
}
return NewRange;
}
void MigrateFrameTimes(const IRetimingInterface& Retimer, UMovieSceneSection* Section)
{
Section->Modify();
const bool bSectionWasLocked = Section->IsLocked();
Section->SetIsLocked(false);
TRangeBound<FFrameNumber> NewLowerBound, NewUpperBound;
if (Section->HasStartFrame())
{
FFrameNumber NewLowerBoundFrame = Retimer.RemapTime(Section->GetInclusiveStartFrame());
NewLowerBound = TRangeBound<FFrameNumber>::Inclusive(NewLowerBoundFrame);
}
if (Section->HasEndFrame())
{
FFrameNumber NewUpperBoundValue = Retimer.RemapTime(Section->GetExclusiveEndFrame());
NewUpperBound = TRangeBound<FFrameNumber>::Exclusive(NewUpperBoundValue);
}
Section->SetRange(TRange<FFrameNumber>(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<UMovieSceneSubTrack>())
{
for (UMovieSceneSection* Section : Track->GetAllSections())
{
UMovieSceneSubSection* SubSection = Cast<UMovieSceneSubSection>(Section);
if (SubSection)
{
if (UMovieSceneSequence* SubSequence = SubSection->GetSequence())
{
UMovieScene* ChildMovieScene = SubSequence->GetMovieScene();
if (ChildMovieScene)
{
TUniquePtr<IRetimingInterface> 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<FMovieSceneMarkedFrame> 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