// Copyright Epic Games, Inc. All Rights Reserved. #include "SequencerKeyCollection.h" #include "MovieSceneSection.h" #include "IKeyArea.h" #include "DisplayNodes/SequencerDisplayNode.h" #include "DisplayNodes/SequencerTrackNode.h" #include "DisplayNodes/SequencerSectionKeyAreaNode.h" FSequencerKeyCollectionSignature FSequencerKeyCollectionSignature::FromNodes(const TArray& InNodes, FFrameNumber InDuplicateThresholdTime) { FSequencerKeyCollectionSignature Result; Result.DuplicateThresholdTime = InDuplicateThresholdTime; for (const FSequencerDisplayNode* Node : InNodes) { const FSequencerSectionKeyAreaNode* KeyAreaNode = nullptr; check(Node); if (Node->GetType() == ESequencerNode::KeyArea) { KeyAreaNode = static_cast(Node); } else if (Node->GetType() == ESequencerNode::Track) { KeyAreaNode = static_cast(Node)->GetTopLevelKeyNode().Get(); } if (KeyAreaNode) { for (const TSharedRef& KeyArea : KeyAreaNode->GetAllKeyAreas()) { const UMovieSceneSection* Section = KeyArea->GetOwningSection(); Result.KeyAreaToSignature.Add(KeyArea, Section ? Section->GetSignature() : FGuid()); } } } return Result; } FSequencerKeyCollectionSignature FSequencerKeyCollectionSignature::FromNodesRecursive(const TArray& InNodes, FFrameNumber InDuplicateThresholdTime) { FSequencerKeyCollectionSignature Result; Result.DuplicateThresholdTime = InDuplicateThresholdTime; TArray> AllKeyAreaNodes; AllKeyAreaNodes.Reserve(36); for (FSequencerDisplayNode* Node : InNodes) { if (Node->GetType() == ESequencerNode::KeyArea) { AllKeyAreaNodes.Add(StaticCastSharedRef(Node->AsShared())); } Node->GetChildKeyAreaNodesRecursively(AllKeyAreaNodes); } for (const TSharedRef& Node : AllKeyAreaNodes) { for (const TSharedRef& KeyArea : Node->GetAllKeyAreas()) { const UMovieSceneSection* Section = KeyArea->GetOwningSection(); Result.KeyAreaToSignature.Add(KeyArea, Section ? Section->GetSignature() : FGuid()); } } return Result; } FSequencerKeyCollectionSignature FSequencerKeyCollectionSignature::FromNodeRecursive(FSequencerDisplayNode& InNode, UMovieSceneSection* InSection, FFrameNumber InDuplicateThresholdTime) { FSequencerKeyCollectionSignature Result; Result.DuplicateThresholdTime = InDuplicateThresholdTime; TArray> AllKeyAreaNodes; AllKeyAreaNodes.Reserve(36); InNode.GetChildKeyAreaNodesRecursively(AllKeyAreaNodes); for (const auto& Node : AllKeyAreaNodes) { TSharedPtr KeyArea = Node->GetKeyArea(InSection); if (KeyArea.IsValid()) { Result.KeyAreaToSignature.Add(KeyArea.ToSharedRef(), InSection ? InSection->GetSignature() : FGuid()); } } return Result; } bool FSequencerKeyCollectionSignature::HasUncachableContent() const { for (auto& Pair : KeyAreaToSignature) { if (!Pair.Value.IsValid()) { return true; } } return false; } bool operator!=(const FSequencerKeyCollectionSignature& A, const FSequencerKeyCollectionSignature& B) { if (A.HasUncachableContent() || B.HasUncachableContent()) { return true; } if (A.KeyAreaToSignature.Num() != B.KeyAreaToSignature.Num() || A.DuplicateThresholdTime != B.DuplicateThresholdTime) { return true; } for (auto& Pair : A.KeyAreaToSignature) { const FGuid* BSig = B.KeyAreaToSignature.Find(Pair.Key); if (!BSig || *BSig != Pair.Value) { return true; } } return false; } bool operator==(const FSequencerKeyCollectionSignature& A, const FSequencerKeyCollectionSignature& B) { if (A.HasUncachableContent() || B.HasUncachableContent()) { return false; } if (A.KeyAreaToSignature.Num() != B.KeyAreaToSignature.Num() || A.DuplicateThresholdTime != B.DuplicateThresholdTime) { return false; } for (auto& Pair : A.KeyAreaToSignature) { const FGuid* BSig = B.KeyAreaToSignature.Find(Pair.Key); if (!BSig || *BSig != Pair.Value) { return false; } } return true; } bool FSequencerKeyCollection::Update(const FSequencerKeyCollectionSignature& InSignature) { if (InSignature == Signature) { return false; } TArray AllTimes; // Get all the key times for the key areas for (auto& Pair : InSignature.GetKeyAreas()) { if (Pair.Key->GetOwningSection()) { Pair.Key->GetKeyTimes(AllTimes, Pair.Key->GetOwningSection()->GetRange()); } } AllTimes.Sort(); GroupedTimes.Reset(AllTimes.Num()); int32 Index = 0; while ( Index < AllTimes.Num() ) { FFrameNumber PredicateTime = AllTimes[Index]; GroupedTimes.Add(PredicateTime); while (Index < AllTimes.Num() && FMath::Abs(AllTimes[Index] - PredicateTime) <= InSignature.GetDuplicateThreshold()) { ++Index; } } GroupedTimes.Shrink(); Signature = InSignature; return true; } TOptional FSequencerKeyCollection::FindFirstKeyInRange(const TRange& Range, EFindKeyDirection Direction) const { TArrayView KeysInRange = GetKeysInRange(Range); if (KeysInRange.Num()) { return Direction == EFindKeyDirection::Forwards ? KeysInRange[0] : KeysInRange[KeysInRange.Num()-1]; } return TOptional(); } TArrayView FSequencerKeyCollection::GetKeysInRange(const TRange& Range) const { // Binary search the first time that's >= the lower bound int32 FirstVisibleIndex = Range.GetLowerBound().IsClosed() ? Algo::LowerBound(GroupedTimes, Range.GetLowerBoundValue()) : 0; // Binary search the last time that's > the upper bound int32 LastVisibleIndex = Range.GetUpperBound().IsClosed() ? Algo::UpperBound(GroupedTimes, Range.GetUpperBoundValue()) : GroupedTimes.Num(); int32 Num = LastVisibleIndex - FirstVisibleIndex; if (GroupedTimes.IsValidIndex(FirstVisibleIndex) && LastVisibleIndex <= GroupedTimes.Num() && Num > 0) { return MakeArrayView(&GroupedTimes[FirstVisibleIndex], Num); } return TArrayView(); } /* FFrameNumber FSequencerKeyCollection::GetNextKey(FFrameNumber FrameNumber, EFindKeyDirection Direction) const { FFrameNumber NextFrame = FrameNumber; int32 Num = GroupedTimes.Num(); if (Num > 0) { if (FrameNumber < GroupedTimes[0]) { NextFrame = GroupedTimes[0]; } else if (FrameNumber > GroupedTimes[Num - 1]) { NextFrame = GroupedTimes[Num - 1]; } else { int32 Index = Algo::LowerBound(GroupedTimes, FrameNumber); if (GroupedTimes[Index] != FrameNumber) { if (Direction == EFindKeyDirection::Forwards) { NextFrame = GroupedTimes[Index]; } else { NextFrame = GroupedTimes[Index - 1]; } } else { if (Direction == EFindKeyDirection::Forwards) { if (++Index >= Num) { Index = Num - 1; } NextFrame = GroupedTimes[Index]; } else { if (--Index < 0) { Index = 0; } NextFrame = GroupedTimes[Index]; } } } } return NextFrame; } */ TOptional FSequencerKeyCollection::GetNextKey(FFrameNumber FrameNumber, EFindKeyDirection Direction) const { int32 Index = INDEX_NONE; if (Direction == EFindKeyDirection::Forwards) { Index = Algo::UpperBound(GroupedTimes, FrameNumber); } else { Index = Algo::LowerBound(GroupedTimes, FrameNumber) - 1; } if (GroupedTimes.IsValidIndex(Index)) { return GroupedTimes[Index]; } else if (GroupedTimes.Num() > 0) { if (Direction == EFindKeyDirection::Forwards) { return GroupedTimes[0]; } else { return GroupedTimes.Last(); } } return TOptional(); }