// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Misc/FrameTime.h" #include "UObject/ObjectMacros.h" #include "UObject/Class.h" #include "Containers/ArrayView.h" #include "UObject/SequencerObjectVersion.h" #include "MovieSceneFrameMigration.h" #include "MovieSceneSegment.generated.h" struct FMovieSceneEvaluationTrackSegments; /** Enumeration specifying how to evaluate a particular section when inside a segment */ UENUM() enum class ESectionEvaluationFlags : uint8 { /** No special flags - normal evaluation */ None = 0x00, /** Segment resides inside the 'pre-roll' time for the section */ PreRoll = 0x01, /** Segment resides inside the 'post-roll' time for the section */ PostRoll = 0x02, ForceKeepState = 0x04, ForceRestoreState = 0x08, }; ENUM_CLASS_FLAGS(ESectionEvaluationFlags); /** A unique identifier for a segment within a FMovieSceneEvaluationTrackSegments container */ USTRUCT() struct FMovieSceneSegmentIdentifier { GENERATED_BODY() FMovieSceneSegmentIdentifier() : IdentifierIndex(INDEX_NONE) {} FMovieSceneSegmentIdentifier(int32 InIndex) : IdentifierIndex(InIndex) {} friend bool operator==(FMovieSceneSegmentIdentifier A, FMovieSceneSegmentIdentifier B) { return A.IdentifierIndex == B.IdentifierIndex; } friend bool operator!=(FMovieSceneSegmentIdentifier A, FMovieSceneSegmentIdentifier B) { return A.IdentifierIndex != B.IdentifierIndex; } friend uint32 GetTypeHash(FMovieSceneSegmentIdentifier LHS) { return GetTypeHash(LHS.IdentifierIndex); } bool IsValid() const { return IdentifierIndex != INDEX_NONE; } /** Custom serializer as this is just a type-safe int */ bool Serialize(FArchive& Ar) { Ar << IdentifierIndex; return true; } friend FArchive& operator<<(FArchive& Ar, FMovieSceneSegmentIdentifier& ID) { ID.Serialize(Ar); return Ar; } int32 GetIndex() const { return IdentifierIndex; } UPROPERTY() int32 IdentifierIndex; }; template<> struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 { enum { WithSerializer = true, WithIdenticalViaEquality = true }; static constexpr EPropertyObjectReferenceType WithSerializerObjectReferences = EPropertyObjectReferenceType::None; }; /** * Evaluation data that specifies information about what to evaluate for a given template */ USTRUCT() struct FSectionEvaluationData { GENERATED_BODY() /** Default constructor */ FSectionEvaluationData() : ImplIndex(-1), ForcedTime(TNumericLimits::Lowest()), Flags(ESectionEvaluationFlags::None) {} /** Construction from an implementaiton index (probably a section) */ explicit FSectionEvaluationData(int32 InImplIndex) : ImplIndex(InImplIndex), ForcedTime(TNumericLimits::Lowest()), Flags(ESectionEvaluationFlags::None) {} /** Construction from an implementaiton index and a time to force evaluation at */ FSectionEvaluationData(int32 InImplIndex, FFrameNumber InForcedTime) : ImplIndex(InImplIndex), ForcedTime(InForcedTime), Flags(ESectionEvaluationFlags::None) {} /** Construction from an implementaiton index and custom eval flags */ FSectionEvaluationData(int32 InImplIndex, ESectionEvaluationFlags InFlags) : ImplIndex(InImplIndex), ForcedTime(TNumericLimits::Lowest()), Flags(InFlags) {} friend bool operator==(FSectionEvaluationData A, FSectionEvaluationData B) { return A.ImplIndex == B.ImplIndex && A.ForcedTime == B.ForcedTime && A.Flags == B.Flags; } FFrameTime GetTime(FFrameTime InActualTime) { return ForcedTime == TNumericLimits::Lowest() ? InActualTime : FFrameTime(ForcedTime); } /** Check if this is a preroll eval */ FORCEINLINE bool IsPreRoll() const { return (Flags & ESectionEvaluationFlags::PreRoll) != ESectionEvaluationFlags::None; } /** Check if this is a postroll eval */ FORCEINLINE bool IsPostRoll() const { return (Flags & ESectionEvaluationFlags::PostRoll) != ESectionEvaluationFlags::None; } friend FArchive& operator<<(FArchive& Ar, FSectionEvaluationData& Data) { FSectionEvaluationData::StaticStruct()->SerializeItem(Ar, &Data, nullptr); return Ar; } /** The implementation index we should evaluate (index into FMovieSceneEvaluationTrack::ChildTemplates) */ UPROPERTY() int32 ImplIndex; /** A forced time to evaluate this section at */ UPROPERTY() FFrameNumber ForcedTime; /** Additional flags for evaluating this section */ UPROPERTY() ESectionEvaluationFlags Flags; }; /** * Information about a single segment of an evaluation track */ USTRUCT() struct FMovieSceneSegment { GENERATED_BODY() FMovieSceneSegment() {} FMovieSceneSegment(const TRange& InRange) : Range(InRange) , bAllowEmpty(false) {} FMovieSceneSegment(const TRange& InRange, TArrayView InApplicationImpls) : Range(InRange) , bAllowEmpty(true) { Impls.Reserve(InApplicationImpls.Num()); for (const FSectionEvaluationData& Impl : InApplicationImpls) { Impls.Add(Impl); } } FMovieSceneSegment(const TRange& InRange, std::initializer_list InApplicationImpls) : FMovieSceneSegment(InRange, MakeArrayView(InApplicationImpls)) { } friend bool operator==(const FMovieSceneSegment& A, const FMovieSceneSegment& B) { return A.Range == B.Range && A.ID == B.ID && A.bAllowEmpty == B.bAllowEmpty && A.Impls == B.Impls; } bool IsValid() const { return bAllowEmpty || Impls.Num() != 0; } bool CombineWith(const FMovieSceneSegment& OtherSegment) { if (Range.Adjoins(OtherSegment.Range) && Impls == OtherSegment.Impls && bAllowEmpty == OtherSegment.bAllowEmpty) { Range = TRange::Hull(OtherSegment.Range, Range); return true; } return false; } /** Custom serializer to accomodate the inline allocator on our array */ bool Serialize(FArchive& Ar) { Ar.UsingCustomVersion(FSequencerObjectVersion::GUID); if (Ar.IsLoading() && Ar.CustomVer(FSequencerObjectVersion::GUID) < FSequencerObjectVersion::FloatToIntConversion) { TRange OldFloatRange; Ar << OldFloatRange; Range = FMovieSceneFrameRange::FromFloatRange(OldFloatRange); } else { Ar << Range; } if (Ar.CustomVer(FSequencerObjectVersion::GUID) >= FSequencerObjectVersion::EvaluationTree) { Ar << ID; Ar << bAllowEmpty; } int32 NumStructs = Impls.Num(); Ar << NumStructs; if (Ar.IsLoading()) { for (int32 Index = 0; Index < NumStructs; ++Index) { FSectionEvaluationData Data; Ar << Data; Impls.Add(Data); } } else if (Ar.IsSaving()) { for (FSectionEvaluationData& Data : Impls) { Ar << Data; } } return true; } /** The segment's range */ TRange Range; FMovieSceneSegmentIdentifier ID; /** Whether this segment has been generated yet or not */ bool bAllowEmpty; /** Array of implementations that reside at the segment's range */ TArray> Impls; }; template<> struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 { enum { WithSerializer = true, WithCopy = true, WithIdenticalViaEquality = true }; static constexpr EPropertyObjectReferenceType WithSerializerObjectReferences = EPropertyObjectReferenceType::None; };