1082 lines
38 KiB
C++
1082 lines
38 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Containers/ContainersFwd.h"
|
|
#include "Containers/Array.h"
|
|
#include "MovieSceneFwd.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Misc/FrameNumber.h"
|
|
#include "Misc/FrameTime.h"
|
|
#include "MovieSceneTimeTransform.h"
|
|
#include "MovieSceneTimeWarping.h"
|
|
#include "Variants/MovieSceneTimeWarpVariant.h"
|
|
|
|
#include "MovieSceneSequenceTransform.generated.h"
|
|
|
|
template<typename> class TRange;
|
|
|
|
struct FMovieSceneTransformBreadcrumbs;
|
|
struct FMovieSceneNestedSequenceTransform;
|
|
struct FMovieSceneInverseNestedSequenceTransform;
|
|
|
|
namespace UE::MovieScene
|
|
{
|
|
struct FInverseTransformTimeParams;
|
|
struct FTransformTimeParams;
|
|
|
|
enum class ETimeWarpChannelDomain : uint8;
|
|
}
|
|
|
|
|
|
/*~
|
|
* This file contains the structures necessary for representing transformations of time between various different
|
|
* 'spaces' within the Sequencer/MovieScene codebase. Typically these spaces denote root and sub-sequences,
|
|
* or sub-sub-suquences. 'Lossy' transformations (ie, transformations that are mathematically non-linear)
|
|
* are supported and typically referred to as 'warping' or 'non-linear' transforms. Such transforms are always
|
|
* stored as a stack of nested FMovieSceneNestedSequenceTransform structures and cannot be combined mathematically
|
|
* like FMovieSceneTimeTransform can.
|
|
*
|
|
* When dealing with time transformations, it is common to use the following nomenclature interchangably:
|
|
* - Outer, Untransformed, Unwarped space; and,
|
|
* - Inner, Transformed, Warped space.
|
|
*
|
|
* Inverse transformations are also supported, but via a different, more restrictive API. Where outer->inner transforms
|
|
* must always map an outer time to an inner time, inverse transformations can fail. This is clearly the case when
|
|
* attempting to inverse-transform a time of 20 from a loop that only spans [0, 10). The requested time is not present
|
|
* in the set of times that can result from the outer->inner transform, and so the operation fails.
|
|
* Similarly, inverse transformations may have zero or more real solutions. Consider the previous example, but with a
|
|
* time of 5; the operation has an infinite number of solutions (one for each loop, or every t where t%5==0).
|
|
*
|
|
* ________ << FMovieSceneInverseSequenceTransform << ___________
|
|
* / \
|
|
* ---------------------- -----------------------
|
|
* | Untransformed space | | Transformed space |
|
|
* ----------------------- -----------------------
|
|
* \_____________ >> FMovieSceneSequenceTransform >> _____________/
|
|
*/
|
|
|
|
|
|
/**
|
|
* Enumeration defining how to store breadcrumb trails
|
|
*/
|
|
UENUM()
|
|
enum class EMovieSceneBreadcrumbMode : uint8
|
|
{
|
|
/** Default: Only store breadcrumbs for non-linear transformations */
|
|
Sparse,
|
|
/** Store breadcrumbs for every nested time transformation */
|
|
Dense
|
|
};
|
|
|
|
/**
|
|
* Struct that tracks a breadcumb trail when transformiung a time through FMovieSceneSequenceTransform
|
|
*/
|
|
USTRUCT()
|
|
struct FMovieSceneTransformBreadcrumbs
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/**
|
|
* Default constructor, optionally taking a mode
|
|
*/
|
|
FMovieSceneTransformBreadcrumbs(EMovieSceneBreadcrumbMode InMode = EMovieSceneBreadcrumbMode::Sparse)
|
|
: Mode(InMode)
|
|
{}
|
|
|
|
|
|
/**
|
|
* Return the breadcrumb at the specified index
|
|
*/
|
|
FFrameTime operator[](int32 Index) const
|
|
{
|
|
return Breadcrumbs[Index];
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve the length of this breadcrumb trail
|
|
*/
|
|
int32 Num() const
|
|
{
|
|
return Breadcrumbs.Num();
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if the specified index is valid
|
|
*/
|
|
bool IsValidIndex(int32 Index) const
|
|
{
|
|
return Breadcrumbs.IsValidIndex(Index);
|
|
}
|
|
|
|
|
|
/**
|
|
* Check whether this breadcrumb trail only contains breadcrumbs for non-linear transformations (true) or for everything (false)
|
|
*/
|
|
bool IsSparse() const
|
|
{
|
|
return Mode == EMovieSceneBreadcrumbMode::Sparse;
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve this breadcrumb trail's capture mode
|
|
*/
|
|
EMovieSceneBreadcrumbMode GetMode() const
|
|
{
|
|
return Mode;
|
|
}
|
|
|
|
|
|
/**
|
|
* Restore this trail to its original (empty) state
|
|
*/
|
|
void Reset()
|
|
{
|
|
Breadcrumbs.Reset();
|
|
}
|
|
|
|
|
|
/**
|
|
* Add a breadcrumb to this trail
|
|
*/
|
|
void AddBreadcrumb(const FFrameTime& Breadcrumb)
|
|
{
|
|
Breadcrumbs.Add(Breadcrumb);
|
|
}
|
|
|
|
|
|
/**
|
|
* Pop the most recently added breadcrumb off this trail
|
|
*/
|
|
FFrameTime PopBreadcrumb()
|
|
{
|
|
return Breadcrumbs.Pop();
|
|
}
|
|
|
|
|
|
/**
|
|
* Prepend the specified breadcrumb trail to this one, resulting in a path from the start of Outer to the end of this
|
|
*/
|
|
void CombineWithOuterBreadcrumbs(const FMovieSceneTransformBreadcrumbs& OuterBreadcrumbs)
|
|
{
|
|
// Append the outer breadcrumbs to the head of this list
|
|
Breadcrumbs.Insert(OuterBreadcrumbs.Breadcrumbs, 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Create a new breadcrumb trail of the same size as this one, but with all times set to a specific time
|
|
*/
|
|
FMovieSceneTransformBreadcrumbs OverwriteWith(FFrameTime InTime) const
|
|
{
|
|
FMovieSceneTransformBreadcrumbs Result;
|
|
Result.Breadcrumbs.SetNum(Breadcrumbs.Num());
|
|
for (FFrameTime& X : Result.Breadcrumbs)
|
|
{
|
|
X = InTime;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
public:
|
|
|
|
TArray<FFrameTime>::RangedForConstIteratorType begin () const { return Breadcrumbs.begin(); }
|
|
TArray<FFrameTime>::RangedForConstIteratorType end () const { return Breadcrumbs.end(); }
|
|
|
|
MOVIESCENE_API operator TArrayView<const FFrameTime>() const;
|
|
|
|
private:
|
|
|
|
UPROPERTY()
|
|
TArray<FFrameTime> Breadcrumbs;
|
|
|
|
UPROPERTY()
|
|
EMovieSceneBreadcrumbMode Mode;
|
|
};
|
|
|
|
|
|
USTRUCT()
|
|
struct FMovieSceneWarpCounter : public FMovieSceneTransformBreadcrumbs
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
|
|
MOVIESCENE_API FMovieSceneWarpCounter();
|
|
|
|
MOVIESCENE_API FMovieSceneWarpCounter(const FMovieSceneWarpCounter&);
|
|
MOVIESCENE_API FMovieSceneWarpCounter& operator=(const FMovieSceneWarpCounter&);
|
|
|
|
MOVIESCENE_API FMovieSceneWarpCounter(FMovieSceneWarpCounter&&);
|
|
MOVIESCENE_API FMovieSceneWarpCounter& operator=(FMovieSceneWarpCounter&&);
|
|
|
|
MOVIESCENE_API ~FMovieSceneWarpCounter();
|
|
|
|
UE_DEPRECATED(5.5, "This function is no longer used. Please update your code to use time-based breadcrumbs instead.")
|
|
void AddWarpingLevel(uint32 WarpCount)
|
|
{
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "This function is no longer used. Please update your code to use time-based breadcrumbs instead.")
|
|
void AddNonWarpingLevel()
|
|
{
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "This function is no longer used. Please update your code to use time-based breadcrumbs instead.")
|
|
int32 NumWarpCounts() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "This function is no longer used. Please update your code to use time-based breadcrumbs instead.")
|
|
uint32 LastWarpCount() const
|
|
{
|
|
return (uint32)(-1);
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "Warp counts are no longer supported.")
|
|
TArray<uint32> WarpCounts;
|
|
};
|
|
|
|
|
|
/**
|
|
* Structure used to represent a specific inverse transformation (ie from transformed to untransformed space) that cannot be combined with another.
|
|
* Stored as a stack inside FMovieSceneInverseSequenceTransform to represent a complete transformation
|
|
* from inner time-space to outer time-space.
|
|
*/
|
|
USTRUCT()
|
|
struct FMovieSceneInverseNestedSequenceTransform
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/**
|
|
* Default construction to an identity linear transform. Should only be used by serialization.
|
|
*/
|
|
FMovieSceneInverseNestedSequenceTransform()
|
|
{}
|
|
|
|
|
|
/**
|
|
* Construction from a linear transform
|
|
*/
|
|
FMovieSceneInverseNestedSequenceTransform(const FMovieSceneTimeTransform& InLinearTransform)
|
|
: TimeScale(InLinearTransform.TimeScale), Offset(InLinearTransform.Offset)
|
|
{}
|
|
|
|
|
|
|
|
/**
|
|
* Construction from a linear transform represented as an offset and scale (scale is applied first)
|
|
*/
|
|
FMovieSceneInverseNestedSequenceTransform(const FFrameTime& InOffset, double InTimeScale)
|
|
: TimeScale(InTimeScale), Offset(InOffset)
|
|
{}
|
|
|
|
|
|
public:
|
|
|
|
|
|
/**
|
|
* Check whether this transform is linear (true) or not (false)
|
|
*/
|
|
bool IsLinear() const
|
|
{
|
|
return TimeScale.GetType() == EMovieSceneTimeWarpType::FixedPlayRate;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check whether this transformation requires a breadcrumb trail (true) or not (false)
|
|
* @note Breadcrumbs may still be added for dense trails
|
|
*/
|
|
bool NeedsBreadcrumb() const
|
|
{
|
|
return !IsLinear();
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert this transform to its linear form.
|
|
* @note This is only valid to call where IsLinear() is true
|
|
*/
|
|
MOVIESCENE_API FMovieSceneTimeTransform AsLinear() const;
|
|
|
|
|
|
/**
|
|
* Convert this transform to its inverse (ie a transform that converts from untransformed space to transformed space)
|
|
*/
|
|
MOVIESCENE_API FMovieSceneNestedSequenceTransform Inverse() const;
|
|
|
|
|
|
/**
|
|
* Attempt to transform the specified time by this inverse transform. The operation can fail if the time does not map to the un-transformed time space (for example, when looping).
|
|
*
|
|
* @param Time The time to transform
|
|
* @param Breadcrumb A breadcrumb in the un-transformed space to assist in resolving ambiguous transformations (ie, to transform into the correct time based on the breadcrumb's loop)
|
|
*
|
|
* @return The transformed time if successful, or an epty optional otherwise
|
|
*/
|
|
MOVIESCENE_API TOptional<FFrameTime> TryTransformTime(FFrameTime Time, FFrameTime Breadcrumb) const;
|
|
|
|
|
|
/**
|
|
* Attempt to transform the specified time by this inverse transform. The operation can fail if the time does not map to the un-transformed time space (for example, when looping).
|
|
*
|
|
* @param Time The time to transform
|
|
* @param Breadcrumb A breadcrumb in the un-transformed space to assist in resolving ambiguous transformations (ie, to transform into the correct time based on the breadcrumb's loop)
|
|
* @param Params Parameter structure that controls how to perform the inverse operation (ie to disallow cycling outside of the current loop; to ignore clamps etc)
|
|
*
|
|
* @return The transformed time if successful, or an epty optional otherwise
|
|
*/
|
|
MOVIESCENE_API TOptional<FFrameTime> TryTransformTime(FFrameTime Time, FFrameTime Breadcrumb, const UE::MovieScene::FInverseTransformTimeParams& Params) const;
|
|
|
|
|
|
/**
|
|
* Attempt to transform the specified time by this inverse transform within a specified un-transformed range, calling a functor for every instance of the specified time in the un-transformed space.
|
|
*
|
|
* @param Time The time to transform
|
|
* @param Visitor A callback to invoke for every instance of Time in the untransformed range. The result of the functor determines whether to continue iteration (true) or not (false).
|
|
* @param UntransformedRangeStart The inclusive start time in untransformed space within which to allow Visitor to be invoked
|
|
* @param UntransformedRangeEnd The inclusive end time in untransformed space within which to allow Visitor to be invoked
|
|
*
|
|
* @return True if every invocation of Visitor returned true, or there were no invocations; false if any invocation of Visitor returned false.
|
|
*/
|
|
MOVIESCENE_API bool TransformTimeWithinRange(FFrameTime Time, const TFunctionRef<bool(FFrameTime)>& Visitor, FFrameTime UntransformedRangeStart, FFrameTime UntransformedRangeEnd) const;
|
|
|
|
private:
|
|
|
|
friend FMovieSceneNestedSequenceTransform;
|
|
|
|
/** Time scale as either a fixed play rate, or as an external implementation */
|
|
UPROPERTY()
|
|
FMovieSceneTimeWarpVariant TimeScale;
|
|
|
|
/** Constant time offset. Offset is applied differently for different internal implementations of TimeScale. */
|
|
UPROPERTY()
|
|
FFrameTime Offset;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Structure used to represent a specific transformation (ie from untransformed to transformed space) that cannot be combined with another.
|
|
*
|
|
* Stored as a stack inside FMovieSceneSequenceTransform to represent a complete transformation from inner time-space to outer time-space.
|
|
*/
|
|
USTRUCT()
|
|
struct FMovieSceneNestedSequenceTransform
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
|
|
/**
|
|
* Default construction to an identity linear transform
|
|
*/
|
|
MOVIESCENE_API FMovieSceneNestedSequenceTransform();
|
|
|
|
MOVIESCENE_API FMovieSceneNestedSequenceTransform(const FMovieSceneNestedSequenceTransform&);
|
|
MOVIESCENE_API FMovieSceneNestedSequenceTransform& operator=(const FMovieSceneNestedSequenceTransform&);
|
|
|
|
MOVIESCENE_API FMovieSceneNestedSequenceTransform(FMovieSceneNestedSequenceTransform&&);
|
|
MOVIESCENE_API FMovieSceneNestedSequenceTransform& operator=(FMovieSceneNestedSequenceTransform&&);
|
|
|
|
MOVIESCENE_API ~FMovieSceneNestedSequenceTransform();
|
|
|
|
/**
|
|
* Construction from a time warp variant
|
|
*/
|
|
FMovieSceneNestedSequenceTransform(FMovieSceneTimeWarpVariant&& InVariant)
|
|
: TimeScale(MoveTemp(InVariant))
|
|
{
|
|
TimeScale.MakeWeakUnsafe();
|
|
}
|
|
|
|
|
|
/**
|
|
* Construction from a linear time transformation
|
|
*/
|
|
FMovieSceneNestedSequenceTransform(const FMovieSceneTimeTransform& InLinearTransform)
|
|
: TimeScale(InLinearTransform.TimeScale), Offset(InLinearTransform.Offset)
|
|
{}
|
|
|
|
|
|
/**
|
|
* Construction from a linear time transformation (scale applies first)
|
|
*/
|
|
FMovieSceneNestedSequenceTransform(FFrameTime InOffset, double InTimeScale)
|
|
: TimeScale(InTimeScale), Offset(InOffset)
|
|
{}
|
|
|
|
|
|
/**
|
|
* Default construction to an identity linear transform
|
|
*/
|
|
FMovieSceneNestedSequenceTransform(FFrameTime InOffset, FMovieSceneTimeWarpVariant&& InTimeScale)
|
|
: TimeScale(MoveTemp(InTimeScale)), Offset(InOffset)
|
|
{
|
|
TimeScale.MakeWeakUnsafe();
|
|
}
|
|
|
|
|
|
public:
|
|
|
|
|
|
/**
|
|
* Check whether this transform is linear (true) or not (false)
|
|
*/
|
|
bool IsLinear() const
|
|
{
|
|
return TimeScale.GetType() == EMovieSceneTimeWarpType::FixedPlayRate;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert this transform to its linear form.
|
|
* @note This is only valid to call where IsLinear() is true
|
|
*/
|
|
FMovieSceneTimeTransform AsLinear() const
|
|
{
|
|
return FMovieSceneTimeTransform(Offset, TimeScale.AsFixedPlayRateFloat());
|
|
}
|
|
|
|
|
|
/**
|
|
* Check whether this transformation requires a breadcrumb trail (true) or not (false)
|
|
* @note Breadcrumbs may still be added for dense trails
|
|
*/
|
|
bool NeedsBreadcrumb() const
|
|
{
|
|
return !IsLinear();
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns whether this transform is an identity transformation (ie, a*T = a)
|
|
*/
|
|
bool IsIdentity() const
|
|
{
|
|
return Offset == 0 && TimeScale.GetType() == EMovieSceneTimeWarpType::FixedPlayRate && TimeScale.AsFixedPlayRate() == 1.0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Transform the specified time from untransformed to transformed space
|
|
*
|
|
* @param Time The untransformed time to transform
|
|
*
|
|
* @return the transformed time
|
|
*/
|
|
MOVIESCENE_API FFrameTime TransformTime(FFrameTime Time) const;
|
|
|
|
|
|
/**
|
|
* Transform the specified time from untransformed to transformed space
|
|
*
|
|
* @param Time The untransformed time to transform
|
|
* @param Params Transformation parameters, allowing control over the transformation, and gathering of breadcrumbs
|
|
*
|
|
* @return the transformed time
|
|
*/
|
|
MOVIESCENE_API FFrameTime TransformTime(FFrameTime Time, const UE::MovieScene::FTransformTimeParams& Params) const;
|
|
|
|
|
|
/**
|
|
* Generate the inverse of this transformation (ie a transform from transformed to untransformed space)
|
|
*/
|
|
MOVIESCENE_API FMovieSceneInverseNestedSequenceTransform Inverse() const;
|
|
|
|
|
|
/**
|
|
* Given a range in untransformed space, compute the hull of times that this range encompass when transformed.
|
|
* For instance, if this transform represents a loop of [0, 10) an input range of:
|
|
* - [15,19) would yield [5,9)
|
|
* - [5,25) would yield [0,10)
|
|
*
|
|
* @note Disjoint ranges are not supported by this function. An input of [5, 19) under the previous example would yield
|
|
* [0, 9) because we can only return a single range.
|
|
*/
|
|
MOVIESCENE_API TRange<FFrameTime> ComputeTraversedHull(const TRange<FFrameTime>& Range) const;
|
|
|
|
|
|
/**
|
|
* Check whether this transformation supports 'boundaries'. A boundary is implementation defined,
|
|
* but is generally a loop or cycle point.
|
|
*/
|
|
MOVIESCENE_API bool SupportsBoundaries() const;
|
|
|
|
|
|
/**
|
|
* Retrieve this nested transform's time-warp domain, if it has one
|
|
*/
|
|
MOVIESCENE_API TOptional<UE::MovieScene::ETimeWarpChannelDomain> GetWarpDomain() const;
|
|
|
|
|
|
/**
|
|
* Extract all the boundaries for this transform within the specified untransformed start and end time,
|
|
* invoking Visitor for every boundary that is present within the range. Iteration will continue until
|
|
* Visitor returns false, at which point this function itself will return false.
|
|
*
|
|
* @param UntransformedRange The range within which Visitor can be invoked in untransformed space
|
|
* @param Visitor A functor to invoke for every boundary that is found within the range. Return value signifies whether iteration continues (true) or not (false)
|
|
*
|
|
* @return (true) if there were no boundaries, or Visitor returned true for all encountered boundaries; false otherwise
|
|
*/
|
|
MOVIESCENE_API bool ExtractBoundariesWithinRange(const TRange<FFrameTime>& UntransformedRange, const TFunctionRef<bool(FFrameTime)>& Visitor) const;
|
|
|
|
|
|
/**
|
|
* Convert this transformation to a string representation
|
|
*/
|
|
MOVIESCENE_API void ToString(TStringBuilderBase<TCHAR>& OutBuilder) const;
|
|
|
|
|
|
/**
|
|
* Equality comparison
|
|
*/
|
|
friend bool operator==(const FMovieSceneNestedSequenceTransform& A, const FMovieSceneNestedSequenceTransform& B)
|
|
{
|
|
return A.TimeScale == B.TimeScale && A.Offset == B.Offset;
|
|
}
|
|
|
|
|
|
/**
|
|
* Inequality comparison
|
|
*/
|
|
friend bool operator!=(const FMovieSceneNestedSequenceTransform& A, const FMovieSceneNestedSequenceTransform& B)
|
|
{
|
|
return A.TimeScale != B.TimeScale || A.Offset != B.Offset;
|
|
}
|
|
|
|
/*~ Begin StructOpsTypeTraits */
|
|
void PostSerialize(const FArchive& Ar);
|
|
/*~ End StructOpsTypeTraits */
|
|
|
|
private:
|
|
|
|
/**
|
|
* Time scale implemented as an optionally-warping variant
|
|
*/
|
|
UPROPERTY()
|
|
FMovieSceneTimeWarpVariant TimeScale;
|
|
|
|
/**
|
|
* Linear time transform for this sub-sequence.
|
|
*/
|
|
UPROPERTY()
|
|
FFrameTime Offset;
|
|
|
|
public:
|
|
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Begin API deprecation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
UE_DEPRECATED(5.5, "Please update your code to use a FMovieSceneTimeWarpVariant")
|
|
FMovieSceneNestedSequenceTransform(const FMovieSceneTimeWarping& InWarping)
|
|
{
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "Please update your code to use a FMovieSceneTimeWarpVariant")
|
|
FMovieSceneNestedSequenceTransform(FMovieSceneTimeTransform InLinearTransform, const FMovieSceneTimeWarping& InWarping)
|
|
: TimeScale(InLinearTransform.TimeScale), Offset(InLinearTransform.Offset)
|
|
{
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "Please update your code to check for IsLinear()")
|
|
bool IsLooping() const
|
|
{
|
|
return TimeScale.GetType() == EMovieSceneTimeWarpType::Loop;
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "Please use Inverse()")
|
|
FMovieSceneNestedSequenceTransform InverseLinearOnly() const
|
|
{
|
|
return IsLinear() ? AsLinear().Inverse() : FMovieSceneNestedSequenceTransform();
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "Please use Inverse()")
|
|
FMovieSceneNestedSequenceTransform InverseFromWarp(uint32 WarpCount) const
|
|
{
|
|
return IsLinear() ? AsLinear().Inverse() : FMovieSceneNestedSequenceTransform();
|
|
}
|
|
|
|
UE_DEPRECATED(5.5, "Warping is now implemented as a variant within TimeScale")
|
|
FMovieSceneTimeWarping Warping;
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ End API deprecation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
};
|
|
template<>
|
|
struct TStructOpsTypeTraits<FMovieSceneNestedSequenceTransform> : public TStructOpsTypeTraitsBase2<FMovieSceneNestedSequenceTransform>
|
|
{
|
|
enum
|
|
{
|
|
WithPostSerialize = true,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Movie scene sequence transform class that transforms from one time-space to another, represented as
|
|
* a linear transformation plus zero or more complex, non-linear transformations.
|
|
*/
|
|
USTRUCT()
|
|
struct FMovieSceneSequenceTransform
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
|
|
/**
|
|
* Default construction to the identity transform
|
|
*/
|
|
FMovieSceneSequenceTransform()
|
|
{}
|
|
|
|
/**
|
|
* Construction from an offset, and a scale
|
|
*
|
|
* @param InOffset The offset to translate by
|
|
* @param InTimeScale The timescale. For instance, if a sequence is playing twice as fast, pass 2.f
|
|
*/
|
|
explicit FMovieSceneSequenceTransform(FFrameTime InOffset, float InTimeScale = 1.f)
|
|
: LinearTransform(InOffset, InTimeScale)
|
|
{}
|
|
|
|
|
|
/**
|
|
* Construction from a linear time transform.
|
|
*
|
|
* @param InLinearTransform The linear transform
|
|
*/
|
|
explicit FMovieSceneSequenceTransform(FMovieSceneTimeTransform InLinearTransform)
|
|
: LinearTransform(InLinearTransform)
|
|
{}
|
|
|
|
|
|
/**
|
|
* Construction from a single nested sequence transform structure
|
|
*
|
|
* @param InNestedTransform The transform
|
|
*/
|
|
explicit FMovieSceneSequenceTransform(FMovieSceneNestedSequenceTransform&& InNestedTransform)
|
|
{
|
|
if (InNestedTransform.IsLinear())
|
|
{
|
|
LinearTransform = InNestedTransform.AsLinear();
|
|
}
|
|
else
|
|
{
|
|
NestedTransforms.Emplace(InNestedTransform);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Equality comparison
|
|
*/
|
|
friend bool operator==(const FMovieSceneSequenceTransform& A, const FMovieSceneSequenceTransform& B)
|
|
{
|
|
return A.LinearTransform == B.LinearTransform && A.NestedTransforms == B.NestedTransforms;
|
|
}
|
|
|
|
|
|
/**
|
|
* Inequality comparison
|
|
*/
|
|
friend bool operator!=(const FMovieSceneSequenceTransform& A, const FMovieSceneSequenceTransform& B)
|
|
{
|
|
return A.LinearTransform != B.LinearTransform || A.NestedTransforms != B.NestedTransforms;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns whether this sequence transform includes any time warping.
|
|
*/
|
|
bool NeedsBreadcrumbs() const
|
|
{
|
|
return !IsLinear();
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns whether this sequence transform is purely linear (i.e. doesn't involve time warping).
|
|
*/
|
|
bool IsLinear() const
|
|
{
|
|
return NestedTransforms.Num() == 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert this transform to its linear representation.
|
|
* @note It is invalid to call this function unless IsLinear() is true
|
|
*/
|
|
FMovieSceneTimeTransform AsLinear() const
|
|
{
|
|
return LinearTransform;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns whether this sequence transform is an identity transform (i.e. it doesn't change anything).
|
|
*/
|
|
MOVIESCENE_API bool IsIdentity() const;
|
|
|
|
|
|
/**
|
|
* Transform the specified time into the inner-most (transformed) space
|
|
*
|
|
* @param Time The input time to transform
|
|
*
|
|
* @return The resulting time in transformed space
|
|
*/
|
|
MOVIESCENE_API FFrameTime TransformTime(FFrameTime Time) const;
|
|
|
|
|
|
/**
|
|
* Transform the specified time into the inner-most (transformed) space
|
|
*
|
|
* @param Time The input time to transform
|
|
* @param Params Parameters for controlling the transform operation, and harvesting breadcrumbs
|
|
*
|
|
* @return The resulting time in transformed space
|
|
*/
|
|
MOVIESCENE_API FFrameTime TransformTime(FFrameTime InTime, const UE::MovieScene::FTransformTimeParams& Params) const;
|
|
|
|
|
|
/**
|
|
* Given a range in untransformed space, compute the hull of times that this range encompass when transformed.
|
|
* For instance, if this transform represents a loop of [0, 10) an input range of:
|
|
* - [15,19) would yield [5,9)
|
|
* - [5,25) would yield [0,10)
|
|
*
|
|
* @note Disjoint ranges are not supported by this function. An input of [5, 19) under the previous example would yield
|
|
* [0, 9) because we can only return a single range.
|
|
*/
|
|
MOVIESCENE_API TRange<FFrameTime> ComputeTraversedHull(const TRange<FFrameTime>& Range) const;
|
|
|
|
|
|
/**
|
|
* Given a range in untransformed space, compute the hull of times that this range encompass when transformed.
|
|
* See above overload for additional details.
|
|
*/
|
|
MOVIESCENE_API TRange<FFrameTime> ComputeTraversedHull(const TRange<FFrameNumber>& Range) const;
|
|
|
|
|
|
/**
|
|
* Retrieve the first active timewarp domain that is present in this transform, if any is present at all
|
|
*/
|
|
MOVIESCENE_API TOptional<UE::MovieScene::ETimeWarpChannelDomain> FindFirstWarpDomain() const;
|
|
|
|
|
|
public:
|
|
|
|
|
|
/**
|
|
* Add the specified linear transform to the end of this transform stack (ie, applying it last)
|
|
*/
|
|
MOVIESCENE_API void Add(FMovieSceneTimeTransform InTransform);
|
|
|
|
|
|
|
|
/**
|
|
* Add the specified nested transform to the end of this transform stack (ie, applying it last). Does nothing if the supplied transform is an identity.
|
|
*/
|
|
MOVIESCENE_API void Add(FMovieSceneNestedSequenceTransform InTransform);
|
|
|
|
|
|
/**
|
|
* Add the specified warping transform to the end of this transform stack with an offset (ie, applying it last)
|
|
*/
|
|
MOVIESCENE_API void Add(FFrameTime InOffset, FMovieSceneTimeWarpVariant&& InTimeWarp);
|
|
|
|
|
|
/**
|
|
* Add an entry to this transform denoting it should loop between the specified start and end point
|
|
* @note Start and End are interpreted in the transformed space of the current stack of transforms in this class.
|
|
*
|
|
* @param Start The start frame number of the loop
|
|
* @param End The ending frame number of the loop
|
|
*/
|
|
MOVIESCENE_API void AddLoop(FFrameNumber Start, FFrameNumber End);
|
|
|
|
|
|
/**
|
|
* Append another transform to this one, resulting in a transform that effectively goes from this -> Tail
|
|
*
|
|
* @param Tail The transform to append
|
|
*/
|
|
MOVIESCENE_API void Append(const FMovieSceneSequenceTransform& Tail);
|
|
|
|
|
|
/**
|
|
* Multiply this tranmsform with another transform, resulting in a single transform that gets from RHS parent to LHS space
|
|
* @note Transforms apply from right to left
|
|
*/
|
|
MOVIESCENE_API FMovieSceneSequenceTransform operator*(const FMovieSceneSequenceTransform& RHS) const;
|
|
|
|
|
|
/**
|
|
* Compute the inverse of this transform, that is: the transform that goes from transformed to untransformed space.
|
|
*/
|
|
MOVIESCENE_API FMovieSceneInverseSequenceTransform Inverse() const;
|
|
|
|
|
|
/**
|
|
* Extract all the boundaries for this transform within the specified untransformed start and end time,
|
|
* invoking Visitor for every boundary that is present within the range. Iteration will continue until
|
|
* Visitor returns false, at which point this function itself will return false.
|
|
*
|
|
* @param UntransformedStart The inclusive start of the range within which Visitor can be invoked
|
|
* @param UntransformedEnd The inclusive end of the range within which Visitor can be invoked
|
|
* @param Visitor A functor to invoke for every boundary that is found within the range. Return value signifies whether iteration continues (true) or not (false)
|
|
*
|
|
* @return (true) if there were no boundaries, or Visitor returned true for all encountered boundaries; false otherwise
|
|
*/
|
|
MOVIESCENE_API bool ExtractBoundariesWithinRange(FFrameTime UntransformedStart, FFrameTime UntransformedEnd, const TFunctionRef<bool(FFrameTime)>& Visitor) const;
|
|
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Begin API deprecation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
UE_DEPRECATED(5.5, "This function is no longer supported. Please use !IsLinear()")
|
|
bool IsLooping() const;
|
|
UE_DEPRECATED(5.5, "Please upgrade your code to use TransformTime that takes breadcrumbs")
|
|
MOVIESCENE_API void TransformTime(FFrameTime InTime, FFrameTime& OutTime, FMovieSceneWarpCounter& OutWarpCounter) const;
|
|
UE_DEPRECATED(5.5, "Transforms no longer have a constant time scale.")
|
|
MOVIESCENE_API float GetTimeScale() const;
|
|
UE_DEPRECATED(5.5, "Please use ComputeTraversedHull or TransformTime")
|
|
MOVIESCENE_API TRange<FFrameTime> TransformRangePure(const TRange<FFrameTime>& Range) const;
|
|
UE_DEPRECATED(5.5, "Please use ComputeTraversedHull or TransformTime")
|
|
MOVIESCENE_API TRange<FFrameTime> TransformRangeUnwarped(const TRange<FFrameTime>& Range) const;
|
|
UE_DEPRECATED(5.5, "Please use ComputeTraversedHull or TransformTime")
|
|
MOVIESCENE_API TRange<FFrameTime> TransformRangeConstrained(const TRange<FFrameTime>& Range) const;
|
|
UE_DEPRECATED(5.5, "Please use ComputeTraversedHull or TransformTime")
|
|
MOVIESCENE_API TRange<FFrameNumber> TransformRangePure(const TRange<FFrameNumber>& Range) const;
|
|
UE_DEPRECATED(5.5, "Please use ComputeTraversedHull or TransformTime")
|
|
MOVIESCENE_API TRange<FFrameNumber> TransformRangeUnwarped(const TRange<FFrameNumber>& Range) const;
|
|
UE_DEPRECATED(5.5, "Please use ComputeTraversedHull or TransformTime")
|
|
MOVIESCENE_API TRange<FFrameNumber> TransformRangeConstrained(const TRange<FFrameNumber>& Range) const;
|
|
UE_DEPRECATED(5.5, "Please use Inverse()")
|
|
MOVIESCENE_API FMovieSceneSequenceTransform InverseNoLooping() const;
|
|
UE_DEPRECATED(5.4, "Please use InverseNoLooping instead.")
|
|
MOVIESCENE_API FMovieSceneTimeTransform InverseLinearOnly() const;
|
|
UE_DEPRECATED(5.4, "Please use InverseFromAllFirstLoops instead.")
|
|
MOVIESCENE_API FMovieSceneTimeTransform InverseFromAllFirstWarps() const;
|
|
UE_DEPRECATED(5.4, "Please use InverseFromLoop instead.")
|
|
MOVIESCENE_API FMovieSceneTimeTransform InverseFromWarp(const FMovieSceneWarpCounter& WarpCounter) const;
|
|
UE_DEPRECATED(5.4, "Please use InverseFromLoop instead.")
|
|
MOVIESCENE_API FMovieSceneTimeTransform InverseFromWarp(const TArrayView<const uint32>& WarpCounts) const;
|
|
UE_DEPRECATED(5.5, "Please use Inverse()")
|
|
MOVIESCENE_API FMovieSceneSequenceTransform InverseFromAllFirstLoops() const;
|
|
UE_DEPRECATED(5.5, "Please use Inverse()")
|
|
MOVIESCENE_API FMovieSceneSequenceTransform InverseFromLoop(const FMovieSceneWarpCounter& LoopCounter) const;
|
|
UE_DEPRECATED(5.5, "Please use Inverse()")
|
|
FMovieSceneSequenceTransform InverseFromLoop(const TArrayView<const FFrameTime>& Breadcrumbs) const;
|
|
UE_DEPRECATED(5.5, "Please use Inverse()")
|
|
MOVIESCENE_API FMovieSceneSequenceTransform InverseFromLoop(const TArrayView<const uint32>& LoopCounts) const;
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ End API deprecation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
|
|
/**
|
|
* The initial linear transformation represented as a 2D matrix. Always applied first.
|
|
*/
|
|
UPROPERTY()
|
|
FMovieSceneTimeTransform LinearTransform;
|
|
|
|
/**
|
|
* Additional transformations that should be applied after LinearTransform.
|
|
* This array is populated whenever a non-linear transform is encountered.
|
|
* */
|
|
UPROPERTY()
|
|
TArray<FMovieSceneNestedSequenceTransform> NestedTransforms;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* The inverse of a FMovieSceneSequenceTransform representing a transformation from transformed, to untransformed space.
|
|
* This uses a different class and API because the algorithms for computing the inverse of non-linear are different,
|
|
* often more complex, and can fail. Whereas an FMovieSceneSequenceTransform can only represent a 1:1 mapping from outer
|
|
* to inner space, its inverse is a (sometimes empty) many:many mapping.
|
|
*
|
|
* Consider a looping transform with a duration of 10 frames: [0, 10). Every time in the outer space maps to a time in the
|
|
* inner space, but the opposite is not true. Only frames 0-10 exist in the inner space, and each frame in that time maps
|
|
* to an infinite number of solutions in the outer space. Conversely, any inner time outside the loop range, ie, [-inf, 0)..(10, +inf]
|
|
* cannot be transformed into the outer space.
|
|
*
|
|
* For this reason, the API only has functions for attempting such computations (TryTransformTime), and iterating the solutions
|
|
* for any given time within a range.
|
|
*
|
|
* The inverse of an inverse transform is the original transform such that T*(1/T)=I theoretically holds true, although transform
|
|
* multiplication is not actually supported by the API.
|
|
*/
|
|
USTRUCT()
|
|
struct FMovieSceneInverseSequenceTransform
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
|
|
/**
|
|
* Returns whether this is a linear transform involving no non-linear components
|
|
*/
|
|
bool IsLinear() const
|
|
{
|
|
return NestedTransforms.Num() == 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Cast this transform to a linear transformation, provided IsLinear() is true.
|
|
*/
|
|
FMovieSceneTimeTransform AsLinear() const
|
|
{
|
|
check(IsLinear());
|
|
return LinearTransform;
|
|
}
|
|
|
|
|
|
/**
|
|
* Attempt to transform the specified transformed time into its untransformed space.
|
|
* This function can fail if the time does not map to any other times in the untransformed space.
|
|
*
|
|
* @param Time The transformed time to convert to untransformed space
|
|
* @param Breadcrumbs A trail of breadcrumbs that lead us from untransformed to transformed space.
|
|
* The algorithm will attempt to find the closest solution to each breadcrumb as it goes.
|
|
*
|
|
* @return The time in untransformed space if succesful, or an empty optional otherwise.
|
|
*/
|
|
MOVIESCENE_API TOptional<FFrameTime> TryTransformTime(FFrameTime Time, const FMovieSceneTransformBreadcrumbs& Breadcrumbs) const;
|
|
|
|
|
|
/**
|
|
* Attempt to transform the specified transformed time into its untransformed space.
|
|
* This function can fail if the time does not map to any other times in the untransformed space.
|
|
*
|
|
* @param Time The transformed time to convert to untransformed space
|
|
* @param Breadcrumbs A trail of breadcrumbs that lead us from untransformed to transformed space.
|
|
* The algorithm will attempt to find the closest solution to each breadcrumb as it goes.
|
|
* @param Params Additional parameters that control the algotihm, such as whether it can look forwards, backwards, or across cycles/loops.
|
|
*
|
|
* @return The time in untransformed space if succesful, or an empty optional otherwise.
|
|
*/
|
|
MOVIESCENE_API TOptional<FFrameTime> TryTransformTime(FFrameTime Time, const FMovieSceneTransformBreadcrumbs& Breadcrumbs, const UE::MovieScene::FInverseTransformTimeParams& Params) const;
|
|
|
|
|
|
/**
|
|
* Fallback overload that does not require a breadcrumb trail if one is not available.
|
|
*
|
|
* Attempt to transform the specified transformed time into its untransformed space.
|
|
* This function can fail if the time does not map to any other times in the untransformed space.
|
|
*
|
|
* @note This overload may yield unexpected times due to the lack of breadcrumb context. Breadcrumbs should be used if possible.
|
|
*
|
|
* @param Time The transformed time to convert to untransformed space
|
|
*
|
|
* @return The time in untransformed space if succesful, or an empty optional otherwise.
|
|
*/
|
|
MOVIESCENE_API TOptional<FFrameTime> TryTransformTime(FFrameTime Time) const;
|
|
|
|
|
|
/**
|
|
* Fallback overload that does not require a breadcrumb trail if one is not available.
|
|
*
|
|
* Attempt to transform the specified transformed time into its untransformed space.
|
|
* This function can fail if the time does not map to any other times in the untransformed space.
|
|
*
|
|
* @note This overload may yield unexpected times due to the lack of breadcrumb context. Breadcrumbs should be used if possible.
|
|
*
|
|
* @param Time The transformed time to convert to untransformed space
|
|
* @param Params Additional parameters that control the algotihm, such as whether it can look forwards, backwards, or across cycles/loops.
|
|
*
|
|
* @return The time in untransformed space if succesful, or an empty optional otherwise.
|
|
*/
|
|
MOVIESCENE_API TOptional<FFrameTime> TryTransformTime(FFrameTime Time, const UE::MovieScene::FInverseTransformTimeParams& Params) const;
|
|
|
|
/**
|
|
* Transforms a time from transformed to untransformed space within a finite range specified by two breadcrumb trails.
|
|
* For each solution that exists in the untransformed space, Visitor will be invoked and its result defines whether the
|
|
* algorithm continues (true) or terminates early (false).
|
|
*
|
|
* @param Time The transformed time to convert to untransformed space
|
|
* @param Visitor A functor to invoke for every solution that exists within the range.
|
|
* Returning true will allow the algorithm to continue, false will cause it to terminate early.
|
|
* @param StartBreadCrumbs A breadcrumb trail for the start of the allowable range to solve within.
|
|
* @param EndBreadCrumbs A breadcrumb trail for the end of the allowable range to solve within.
|
|
*
|
|
* @return False if any invocation of Visitor returned false, true otherwise (if there were no solutions, or every invocation of Visitor returned true).
|
|
*/
|
|
MOVIESCENE_API bool TransformTimeWithinRange(FFrameTime Time, const TFunctionRef<bool(FFrameTime)>& Visitor, const FMovieSceneTransformBreadcrumbs& StartBreadcrumbs, const FMovieSceneTransformBreadcrumbs& EndBreadcrumbs) const;
|
|
|
|
|
|
/**
|
|
* Transforms a finite range in the transformed space, to non-empty ranges in untransformed space.
|
|
* For each solution that exists in the untransformed space, Visitor will be invoked and its result defines whether the
|
|
* algorithm continues (true) or terminates early (false).
|
|
*
|
|
* @param Range The range in transformed space to convert to untransformed space.
|
|
* @param Visitor A functor to invoke for every solution that exists within the range.
|
|
* Returning true will allow the algorithm to continue, false will cause it to terminate early.
|
|
* @param StartBreadCrumbs A breadcrumb trail for the start of the allowable range to solve within.
|
|
* @param EndBreadCrumbs A breadcrumb trail for the end of the allowable range to solve within.
|
|
*
|
|
* @return False if any invocation of Visitor returned false, true otherwise (if there were no solutions, or every invocation of Visitor returned true).
|
|
*/
|
|
MOVIESCENE_API bool TransformFiniteRangeWithinRange(const TRange<FFrameTime>& Range, TFunctionRef<bool(TRange<FFrameTime>)> Visitor, const FMovieSceneTransformBreadcrumbs& StartBreadcrumbs, const FMovieSceneTransformBreadcrumbs& EndBreadcrumbs) const;
|
|
|
|
|
|
/**
|
|
* Legacy function that folds all linear transforms together. Does not account for non-linear transforms and should not be used any more.
|
|
*/
|
|
UE_DEPRECATED(5.5, "This function is no longer supported. Please use FMovieSceneInverseSequenceTransform directly.")
|
|
MOVIESCENE_API FMovieSceneTimeTransform AsLegacyLinearTimeTransform() const;
|
|
|
|
private:
|
|
|
|
|
|
/**
|
|
* Implementation function for TransformTimeWithinRange that recursively solves 1:many transformations
|
|
*/
|
|
bool RecursiveTransformTimeWithinRange(int32 NestingIndex, FFrameTime Time, const TFunctionRef<bool(FFrameTime)>& FinalVisitor, TArrayView<const FFrameTime> StartBreadcrumbs, TArrayView<const FFrameTime> EndBreadcrumbs) const;
|
|
|
|
private:
|
|
|
|
friend FMovieSceneSequenceTransform;
|
|
|
|
|
|
/**
|
|
* The final linear transformation represented as a 2D matrix. Always applied last.
|
|
*/
|
|
UPROPERTY()
|
|
FMovieSceneTimeTransform LinearTransform;
|
|
|
|
|
|
/**
|
|
* Additional transformations that should be applied before LinearTransform.
|
|
* This array is populated whenever a non-linear transform is encountered.
|
|
* */
|
|
UPROPERTY()
|
|
TArray<FMovieSceneInverseNestedSequenceTransform> NestedTransforms;
|
|
};
|
|
|
|
/**
|
|
* Transform a time by a sequence transform
|
|
*
|
|
* @param InTime The time to transform
|
|
* @param RHS The transform
|
|
*/
|
|
MOVIESCENE_API FFrameTime operator*(FFrameTime InTime, const FMovieSceneSequenceTransform& RHS);
|
|
|
|
/**
|
|
* Transform a time by a sequence transform
|
|
*
|
|
* @param InTime The time to transform
|
|
* @param RHS The transform
|
|
*/
|
|
inline FFrameTime& operator*=(FFrameTime& InTime, const FMovieSceneSequenceTransform& RHS)
|
|
{
|
|
InTime = InTime * RHS;
|
|
return InTime;
|
|
}
|
|
|
|
/** Convert a FMovieSceneSequenceTransform into a string */
|
|
FString LexToString(const FMovieSceneSequenceTransform& InTransform);
|
|
|
|
/** Convert a FMovieSceneWarpCounter into a string */
|
|
FString LexToString(const FMovieSceneWarpCounter& InCounter); |