Files
UnrealEngine/Engine/Source/Editor/Sequencer/Private/SequencerMarkedFrameHelper.cpp
2025-05-18 13:04:45 +08:00

194 lines
6.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SequencerMarkedFrameHelper.h"
#include "Containers/ArrayView.h"
#include "Containers/Map.h"
#include "Evaluation/MovieSceneEvaluationTemplateInstance.h"
#include "Evaluation/MovieSceneSectionParameters.h"
#include "Evaluation/MovieSceneSequenceHierarchy.h"
#include "Evaluation/MovieSceneSequenceTransform.h"
#include "Evaluation/MovieSceneTimeArray.h"
#include "Evaluation/MovieSceneTimeTransform.h"
#include "HAL/PlatformCrt.h"
#include "ISequencer.h"
#include "Math/Range.h"
#include "Math/UnrealMathSSE.h"
#include "Misc/AssertionMacros.h"
#include "Misc/FrameNumber.h"
#include "Misc/FrameRate.h"
#include "Misc/FrameTime.h"
#include "MovieScene.h"
#include "MovieSceneFrameMigration.h"
#include "MovieSceneSequence.h"
#include "MovieSceneSequenceID.h"
#include "MovieSceneTimeHelpers.h"
#include "Sections/MovieSceneSubSection.h"
#include "Templates/Tuple.h"
#include "Templates/UnrealTemplate.h"
namespace UE
{
namespace MovieScene
{
static void FindGlobalMarkedFrames(
const ISequencer& Sequencer, const FMovieSceneSequenceHierarchy* SequenceHierarchy,
FMovieSceneSequenceIDRef FocusedSequenceID, FMovieSceneSequenceIDRef SequenceID,
TRange<FFrameNumber> GatherRange,
const FMovieSceneInverseSequenceTransform& SequenceToRootTransform,
const FMovieSceneTransformBreadcrumbs& StartBreadcrumbs,
const FMovieSceneTransformBreadcrumbs& EndBreadcrumbs,
TMovieSceneTimeArray<FMovieSceneMarkedFrame>& OutTimestampedGlobalMarkedFrames)
{
// Find the current sequence in the hierarchy.
const FMovieSceneSubSequenceData* const SequenceSubData = SequenceHierarchy->FindSubData(SequenceID);
const UMovieSceneSequence* const Sequence = SequenceSubData ? SequenceSubData->GetSequence() : Sequencer.GetRootMovieSceneSequence();
const UMovieScene* const MovieScene = Sequence ? Sequence->GetMovieScene() : nullptr;
if (UNLIKELY(!ensure(MovieScene)))
{
return;
}
// Get the marked frames of the current sequence if it's not the focused sequence.
if (SequenceID != FocusedSequenceID && MovieScene->GetGloballyShowMarkedFrames())
{
const TArray<FMovieSceneMarkedFrame>& MarkedFrames = MovieScene->GetMarkedFrames();
for (const FMovieSceneMarkedFrame& MarkedFrame : MarkedFrames)
{
if (GatherRange.Contains(MarkedFrame.FrameNumber))
{
// Iterate all mappings in the root
auto VisitMarkedFrame = [&OutTimestampedGlobalMarkedFrames, &MarkedFrame](FFrameTime RootTime)
{
OutTimestampedGlobalMarkedFrames.Add(RootTime, MarkedFrame);
return true;
};
SequenceToRootTransform.TransformTimeWithinRange(MarkedFrame.FrameNumber, VisitMarkedFrame, StartBreadcrumbs, EndBreadcrumbs);
}
}
}
// Dive into the current sequence's sub-sequences.
const FMovieSceneSequenceHierarchyNode* const SequenceNode = SequenceHierarchy->FindNode(SequenceID);
if (ensure(SequenceNode))
{
for (const FMovieSceneSequenceID ChildID : SequenceNode->Children)
{
const FMovieSceneSubSequenceData* const ChildSubData = SequenceHierarchy->FindSubData(ChildID);
if (UNLIKELY(!ensure(ChildSubData)))
{
continue;
}
const UMovieSceneSequence* const ChildSequence = ChildSubData->GetSequence();
const UMovieScene* const ChildMovieScene = ChildSequence ? ChildSequence->GetMovieScene() : nullptr;
if (UNLIKELY(!ensure(ChildMovieScene)))
{
continue;
}
// Gather marked frames in this "window".
FindGlobalMarkedFrames(
Sequencer,
SequenceHierarchy,
FocusedSequenceID,
ChildID,
ChildSubData->PlayRange.Value,
ChildSubData->RootToSequenceTransform.Inverse(),
ChildSubData->StartTimeBreadcrumbs,
ChildSubData->EndTimeBreadcrumbs,
OutTimestampedGlobalMarkedFrames
);
}
}
}
} // namespace MovieScene
} // namespace UE
void FSequencerMarkedFrameHelper::FindGlobalMarkedFrames(ISequencer& Sequencer, TArray<FMovieSceneMarkedFrame>& OutGlobalMarkedFrames)
{
// Get the focused sequence info. We want to gather all the marked frames that are in the subset of the sequence hierarchy
// that hangs below this focused sequence.
UMovieSceneSequence* FocusedMovieSequence = Sequencer.GetFocusedMovieSceneSequence();
const FMovieSceneSequenceID FocusedMovieSequenceID = Sequencer.GetFocusedTemplateID();
UMovieSceneSequence* RootMovieSequence = Sequencer.GetRootMovieSceneSequence();
if (!FocusedMovieSequence || !RootMovieSequence)
{
return;
}
// Get the sequence hierarchy so that we can iterate it.
const FMovieSceneRootEvaluationTemplateInstance& EvalTemplate = Sequencer.GetEvaluationTemplate();
const FMovieSceneSequenceHierarchy* SequenceHierarchy = EvalTemplate.GetHierarchy();
if (!SequenceHierarchy)
{
return;
}
// All the marked frames will be added using their root time, but we want to actually display them in the time space of whatever
// is the currently focused sequence. We therefore add the inverse time transform of the focused sequence at the top of the
// transform stack if the focused sequence isn't the root sequence (which has no time transform).
TMovieSceneTimeArray<FMovieSceneMarkedFrame> TimestampedGlobalMarkedFrames;
// Grab the marked frames from the root sequence, and recursively across the whole hierarchy.
UE::MovieScene::FindGlobalMarkedFrames(
Sequencer,
SequenceHierarchy,
FocusedMovieSequenceID,
MovieSceneSequenceID::Root,
TRange<FFrameNumber>::All(),
FMovieSceneInverseSequenceTransform(),
FMovieSceneTransformBreadcrumbs(),
FMovieSceneTransformBreadcrumbs(),
TimestampedGlobalMarkedFrames);
FMovieSceneSequenceTransform RootToFocusedTransform;
if (const FMovieSceneSubSequenceData* SubData = SequenceHierarchy->FindSubData(FocusedMovieSequenceID))
{
RootToFocusedTransform = SubData->RootToSequenceTransform;
}
// Export the modified timestamped entries.
for (const TMovieSceneTimeArrayEntry<FMovieSceneMarkedFrame>& Entry : TimestampedGlobalMarkedFrames.GetEntries())
{
FMovieSceneMarkedFrame MarkedFrame = Entry.Datum;
MarkedFrame.FrameNumber = RootToFocusedTransform.TransformTime(Entry.RootTime).FrameNumber;
OutGlobalMarkedFrames.Add(MarkedFrame);
}
}
void FSequencerMarkedFrameHelper::ClearGlobalMarkedFrames(ISequencer& Sequencer)
{
const FMovieSceneRootEvaluationTemplateInstance& EvalTemplate = Sequencer.GetEvaluationTemplate();
ClearGlobalMarkedFrames(EvalTemplate.GetRootSequence());
const FMovieSceneSequenceHierarchy* SequenceHierarchy = EvalTemplate.GetHierarchy();
if (SequenceHierarchy)
{
for (const TTuple<FMovieSceneSequenceID, FMovieSceneSubSequenceData>& Pair : SequenceHierarchy->AllSubSequenceData())
{
ClearGlobalMarkedFrames(Pair.Value.GetSequence());
}
}
}
void FSequencerMarkedFrameHelper::ClearGlobalMarkedFrames(UMovieSceneSequence* Sequence)
{
if (Sequence)
{
if (UMovieScene* MovieScene = Sequence->GetMovieScene())
{
MovieScene->SetGloballyShowMarkedFrames(false);
}
}
}