2020-08-11 01:36:57 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Compilation/MovieSceneCompiledDataManager.h"
# include "Compilation/IMovieSceneTemplateGenerator.h"
# include "Compilation/IMovieSceneTrackTemplateProducer.h"
2021-05-11 01:10:20 -04:00
# include "Compilation/IMovieSceneDeterminismSource.h"
2020-08-11 01:36:57 -04:00
# include "EntitySystem/IMovieSceneEntityProvider.h"
# include "Evaluation/MovieSceneEvaluationCustomVersion.h"
# include "Evaluation/MovieSceneRootOverridePath.h"
2022-04-05 18:58:45 -04:00
# include "MovieScene.h"
2020-08-11 01:36:57 -04:00
# include "MovieSceneSequence.h"
# include "Sections/MovieSceneSubSection.h"
# include "Tracks/MovieSceneSubTrack.h"
# include "IMovieSceneModule.h"
2021-05-11 01:10:20 -04:00
# include "MovieSceneTimeHelpers.h"
# include "Algo/Sort.h"
# include "Algo/Unique.h"
2020-08-11 01:36:57 -04:00
# include "Containers/SortedMap.h"
# include "UObject/UObjectGlobals.h"
# include "UObject/Package.h"
2021-01-08 19:56:07 -04:00
# include "UObject/PackageReload.h"
2020-08-11 01:36:57 -04:00
FString GMovieSceneCompilerVersion = TEXT ( " 7D4B98092FAC4A6B964ECF72D8279EF8 " ) ;
FAutoConsoleVariableRef CVarMovieSceneCompilerVersion (
TEXT ( " Sequencer.CompilerVersion " ) ,
GMovieSceneCompilerVersion ,
TEXT ( " Defines a global identifer for moviescene compiler logic. \n " ) ,
ECVF_Default
) ;
2021-09-03 19:14:18 -04:00
TAutoConsoleVariable < bool > CVarAddKeepStateDeterminismFences (
TEXT ( " Sequencer.AddKeepStateDeterminismFences " ) ,
true ,
TEXT ( " Whether the Sequencer compiler should auto-add determinism fences for the last frame of KeepState sections. "
" This ensures that the last possible value of the section is consistently evaluated regardless of framerate, "
" at the cost of an extra evaluation on frames that cross over KeepState sections' end time. \n " ) ,
ECVF_Default ) ;
2020-08-11 01:36:57 -04:00
IMovieSceneModule & GetMovieSceneModule ( )
{
static TWeakPtr < IMovieSceneModule > WeakMovieSceneModule ;
TSharedPtr < IMovieSceneModule > Shared = WeakMovieSceneModule . Pin ( ) ;
if ( ! Shared . IsValid ( ) )
{
WeakMovieSceneModule = IMovieSceneModule : : Get ( ) . GetWeakPtr ( ) ;
Shared = WeakMovieSceneModule . Pin ( ) ;
}
check ( Shared . IsValid ( ) ) ;
return * Shared ;
}
struct FMovieSceneCompileDataManagerGenerator : public IMovieSceneTemplateGenerator
{
FMovieSceneCompileDataManagerGenerator ( UMovieSceneCompiledDataManager * InCompiledDataManager )
{
CompiledDataManager = InCompiledDataManager ;
Entry = nullptr ;
Template = nullptr ;
}
void Reset ( FMovieSceneCompiledDataEntry * InEntry )
{
check ( InEntry ) ;
Entry = InEntry ;
Template = CompiledDataManager - > TrackTemplates . Find ( Entry - > DataID . Value ) ;
}
virtual void AddOwnedTrack ( FMovieSceneEvaluationTrack & & InTrackTemplate , const UMovieSceneTrack & SourceTrack ) override
{
check ( Entry ) ;
if ( ! Template )
{
Template = & CompiledDataManager - > TrackTemplates . FindOrAdd ( Entry - > DataID . Value ) ;
}
Template - > AddTrack ( SourceTrack . GetSignature ( ) , MoveTemp ( InTrackTemplate ) ) ;
}
private :
UMovieSceneCompiledDataManager * CompiledDataManager ;
FMovieSceneCompiledDataEntry * Entry ;
FMovieSceneEvaluationTemplate * Template ;
} ;
struct FCompileOnTheFlyData
{
/** Primary sort - group */
uint16 GroupEvaluationPriority ;
/** Secondary sort - Hierarchical bias */
int16 HierarchicalBias ;
/** Tertiary sort - Eval priority */
int16 EvaluationPriority ;
/** Quaternary sort - Child priority */
int16 ChildPriority ;
/** */
FName EvaluationGroup ;
/** Whether the track requires initialization or not */
bool bRequiresInit ;
bool bPriorityTearDown ;
FMovieSceneEvaluationFieldTrackPtr Track ;
FMovieSceneFieldEntry_ChildTemplate Child ;
} ;
/** Gathered data for a given time or range */
struct FMovieSceneGatheredCompilerData
{
/** Tree of tracks to evaluate */
TMovieSceneEvaluationTree < FCompileOnTheFlyData > TrackTemplates ;
/** Tree of active sequences */
TMovieSceneEvaluationTree < FMovieSceneSequenceID > Sequences ;
FMovieSceneEntityComponentField * EntityField = nullptr ;
2021-05-11 01:10:20 -04:00
FMovieSceneDeterminismData DeterminismData ;
2020-08-11 01:36:57 -04:00
EMovieSceneSequenceFlags InheritedFlags = EMovieSceneSequenceFlags : : None ;
EMovieSceneSequenceCompilerMask AccumulatedMask = EMovieSceneSequenceCompilerMask : : None ;
} ;
/** Parameter structure used for gathering entities for a given time or range */
struct FGatherParameters
{
FGatherParameters ( )
: SequenceID ( MovieSceneSequenceID : : Root )
, RootClampRange ( TRange < FFrameNumber > : : All ( ) )
, LocalClampRange ( RootClampRange )
, Flags ( ESectionEvaluationFlags : : None )
, HierarchicalBias ( 0 )
2020-09-01 14:07:48 -04:00
, bHasHierarchicalEasing ( false )
2020-08-11 01:36:57 -04:00
{ }
FGatherParameters CreateForSubData ( const FMovieSceneSubSequenceData & SubData , FMovieSceneSequenceID InSubSequenceID ) const
2021-08-03 11:56:47 -04:00
{
2021-10-20 11:49:19 -04:00
return CreateForSubData ( SubData , InSubSequenceID , FMovieSceneWarpCounter ( ) ) ;
2021-08-03 11:56:47 -04:00
}
2021-10-20 11:49:19 -04:00
FGatherParameters CreateForSubData ( const FMovieSceneSubSequenceData & SubData , FMovieSceneSequenceID InSubSequenceID , FMovieSceneWarpCounter WarpCounter ) const
2020-08-11 01:36:57 -04:00
{
FGatherParameters SubParams = * this ;
SubParams . RootToSequenceTransform = SubData . RootToSequenceTransform ;
SubParams . HierarchicalBias = SubData . HierarchicalBias ;
2021-08-03 11:56:47 -04:00
SubParams . bHasHierarchicalEasing = SubData . bHasHierarchicalEasing ;
2020-08-11 01:36:57 -04:00
SubParams . SequenceID = InSubSequenceID ;
2021-10-20 11:49:19 -04:00
SubParams . RootToSequenceWarpCounter = WarpCounter ;
2020-08-11 01:36:57 -04:00
2021-11-07 23:43:01 -05:00
SubParams . LocalClampRange = SubData . RootToSequenceTransform . TransformRangeUnwarped ( SubParams . RootClampRange ) ;
2021-08-03 11:56:47 -04:00
2020-08-11 01:36:57 -04:00
return SubParams ;
}
void SetClampRange ( TRange < FFrameNumber > InNewRootClampRange )
{
RootClampRange = InNewRootClampRange ;
LocalClampRange = RootToSequenceTransform . TransformRangeUnwarped ( InNewRootClampRange ) ;
}
/** Clamp the specified range to the current clamp range (in root space) */
TRange < FFrameNumber > ClampRoot ( const TRange < FFrameNumber > & InRootRange ) const
{
return TRange < FFrameNumber > : : Intersection ( RootClampRange , InRootRange ) ;
}
2020-09-24 00:43:27 -04:00
/** The ID of the sequence being compiled */
2020-08-11 01:36:57 -04:00
FMovieSceneSequenceID SequenceID ;
/** A range to clamp compilation to in the root's time-space */
TRange < FFrameNumber > RootClampRange ;
/** A range to clamp compilation to in the current sequence's time-space */
TRange < FFrameNumber > LocalClampRange ;
/** Evaluation flags for the current sequence */
ESectionEvaluationFlags Flags ;
/** Transform from the root time-space to the current sequence's time-space */
FMovieSceneSequenceTransform RootToSequenceTransform ;
2021-08-03 11:56:47 -04:00
/** Loop counts from the root to the current sequence */
FMovieSceneWarpCounter RootToSequenceWarpCounter ;
2020-08-11 01:36:57 -04:00
/** Current accumulated hierarchical bias */
int16 HierarchicalBias ;
2020-09-01 14:07:48 -04:00
/** Whether the current sequence is receiving hierarchical easing from some parent sequence */
bool bHasHierarchicalEasing ;
2020-10-09 22:42:26 -04:00
EMovieSceneServerClientMask NetworkMask ;
2020-08-11 01:36:57 -04:00
} ;
/** Parameter structure used for gathering entities for a given time or range */
struct FTrackGatherParameters : FGatherParameters
{
FTrackGatherParameters ( UMovieSceneCompiledDataManager * InCompiledDataManager )
: TemplateGenerator ( InCompiledDataManager )
{ }
2021-10-20 11:49:19 -04:00
FTrackGatherParameters CreateForSubData ( const FMovieSceneSubSequenceData & SubData , FMovieSceneSequenceID InSubSequenceID , FMovieSceneWarpCounter WarpCounter ) const
2020-08-11 01:36:57 -04:00
{
FTrackGatherParameters SubParams = * this ;
2021-10-20 11:49:19 -04:00
static_cast < FGatherParameters & > ( SubParams ) = FGatherParameters : : CreateForSubData ( SubData , InSubSequenceID , WarpCounter ) ;
2020-08-11 01:36:57 -04:00
return SubParams ;
}
/** Store from which to retrieve templates */
mutable FMovieSceneCompileDataManagerGenerator TemplateGenerator ;
} ;
bool SortPredicate ( const FCompileOnTheFlyData & A , const FCompileOnTheFlyData & B )
{
if ( A . GroupEvaluationPriority ! = B . GroupEvaluationPriority )
{
return A . GroupEvaluationPriority > B . GroupEvaluationPriority ;
}
else if ( A . HierarchicalBias ! = B . HierarchicalBias )
{
return A . HierarchicalBias < B . HierarchicalBias ;
}
else if ( A . EvaluationPriority ! = B . EvaluationPriority )
{
return A . EvaluationPriority > B . EvaluationPriority ;
}
else
{
return A . ChildPriority > B . ChildPriority ;
}
}
void AddPtrsToGroup (
FMovieSceneEvaluationGroup * OutGroup ,
TArray < FMovieSceneFieldEntry_EvaluationTrack > & InitTrackLUT ,
TArray < FMovieSceneFieldEntry_ChildTemplate > & InitSectionLUT ,
TArray < FMovieSceneFieldEntry_EvaluationTrack > & EvalTrackLUT ,
TArray < FMovieSceneFieldEntry_ChildTemplate > & EvalSectionLUT
)
{
if ( ! InitTrackLUT . Num ( ) & & ! EvalTrackLUT . Num ( ) )
{
return ;
}
FMovieSceneEvaluationGroupLUTIndex Index ;
Index . NumInitPtrs = InitTrackLUT . Num ( ) ;
Index . NumEvalPtrs = EvalTrackLUT . Num ( ) ;
OutGroup - > LUTIndices . Add ( Index ) ;
OutGroup - > TrackLUT . Append ( InitTrackLUT ) ;
OutGroup - > TrackLUT . Append ( EvalTrackLUT ) ;
OutGroup - > SectionLUT . Append ( InitSectionLUT ) ;
OutGroup - > SectionLUT . Append ( EvalSectionLUT ) ;
InitTrackLUT . Reset ( ) ;
InitSectionLUT . Reset ( ) ;
EvalTrackLUT . Reset ( ) ;
EvalSectionLUT . Reset ( ) ;
}
FMovieSceneCompiledDataEntry : : FMovieSceneCompiledDataEntry ( )
: AccumulatedFlags ( EMovieSceneSequenceFlags : : None )
, AccumulatedMask ( EMovieSceneSequenceCompilerMask : : None )
{ }
2020-09-01 14:07:48 -04:00
UMovieSceneSequence * FMovieSceneCompiledDataEntry : : GetSequence ( ) const
{
return CastChecked < UMovieSceneSequence > ( SequenceKey . ResolveObjectPtr ( ) , ECastCheckedType : : NullAllowed ) ;
}
2020-08-11 01:36:57 -04:00
UMovieSceneCompiledData : : UMovieSceneCompiledData ( )
{
AccumulatedMask = EMovieSceneSequenceCompilerMask : : None ;
AllocatedMask = EMovieSceneSequenceCompilerMask : : None ;
AccumulatedFlags = EMovieSceneSequenceFlags : : None ;
}
void UMovieSceneCompiledData : : Reset ( )
{
EvaluationTemplate = FMovieSceneEvaluationTemplate ( ) ;
Hierarchy = FMovieSceneSequenceHierarchy ( ) ;
EntityComponentField = FMovieSceneEntityComponentField ( ) ;
TrackTemplateField = FMovieSceneEvaluationField ( ) ;
DeterminismFences . Reset ( ) ;
CompiledSignature . Invalidate ( ) ;
CompilerVersion . Invalidate ( ) ;
AccumulatedMask = EMovieSceneSequenceCompilerMask : : None ;
AllocatedMask = EMovieSceneSequenceCompilerMask : : None ;
AccumulatedFlags = EMovieSceneSequenceFlags : : None ;
}
UMovieSceneCompiledDataManager : : UMovieSceneCompiledDataManager ( )
{
const bool bParsed = FGuid : : Parse ( GMovieSceneCompilerVersion , CompilerVersion ) ;
ensureMsgf ( bParsed , TEXT ( " Invalid compiler version specific - this will break any persistent compiled data " ) ) ;
IConsoleManager : : Get ( ) . RegisterConsoleVariableSink_Handle ( FConsoleCommandDelegate : : CreateUObject ( this , & UMovieSceneCompiledDataManager : : ConsoleVariableSink ) ) ;
ReallocationVersion = 0 ;
2020-10-09 22:42:26 -04:00
NetworkMask = EMovieSceneServerClientMask : : All ;
2021-01-08 19:56:07 -04:00
auto OnPackageReloaded = [ this ] ( const EPackageReloadPhase InPackageReloadPhase , FPackageReloadedEvent * InPackageReloadedEvent )
{
if ( InPackageReloadPhase ! = EPackageReloadPhase : : OnPackageFixup )
{
return ;
}
for ( const TPair < UObject * , UObject * > & Pair : InPackageReloadedEvent - > GetRepointedObjects ( ) )
{
UMovieSceneSequence * OldSequence = Cast < UMovieSceneSequence > ( Pair . Key ) ;
UMovieSceneSequence * NewSequence = Cast < UMovieSceneSequence > ( Pair . Value ) ;
if ( OldSequence & & NewSequence )
{
FMovieSceneCompiledDataID DataID = this - > SequenceToDataIDs . FindRef ( OldSequence ) ;
if ( DataID . IsValid ( ) )
{
// Repoint the data ID for the old sequence to the new sequence
{
FMovieSceneCompiledDataEntry & Entry = CompiledDataEntries [ DataID . Value ] ;
this - > SequenceToDataIDs . Remove ( Entry . SequenceKey ) ;
// Entry is a ref here, so care is taken to ensure we do not allocate CompiledDataEntries while the ref is around
Entry = FMovieSceneCompiledDataEntry ( ) ;
Entry . SequenceKey = NewSequence ;
2021-10-12 21:21:22 -04:00
Entry . DataID = DataID ;
2021-01-08 19:56:07 -04:00
this - > SequenceToDataIDs . Add ( Entry . SequenceKey , DataID ) ;
}
// Destroy all the old compiled data as it is no longer valid
this - > Hierarchies . Remove ( DataID . Value ) ;
this - > TrackTemplates . Remove ( DataID . Value ) ;
this - > TrackTemplateFields . Remove ( DataID . Value ) ;
this - > EntityComponentFields . Remove ( DataID . Value ) ;
+ + this - > ReallocationVersion ;
}
}
}
} ;
if ( ! HasAnyFlags ( RF_ClassDefaultObject ) )
{
FCoreUObjectDelegates : : OnPackageReloaded . AddWeakLambda ( this , OnPackageReloaded ) ;
}
2020-08-11 01:36:57 -04:00
}
2020-10-09 22:42:26 -04:00
void UMovieSceneCompiledDataManager : : DestroyAllData ( )
2020-08-11 01:36:57 -04:00
{
// Eradicate all compiled data
for ( int32 Index = 0 ; Index < CompiledDataEntries . GetMaxIndex ( ) ; + + Index )
{
if ( CompiledDataEntries . IsAllocated ( Index ) )
{
FMovieSceneCompiledDataEntry & Entry = CompiledDataEntries [ Index ] ;
Entry . CompiledSignature = FGuid ( ) ;
Entry . AccumulatedFlags = EMovieSceneSequenceFlags : : None ;
Entry . AccumulatedMask = EMovieSceneSequenceCompilerMask : : None ;
}
}
2020-10-09 22:42:26 -04:00
Hierarchies . Empty ( ) ;
TrackTemplates . Empty ( ) ;
TrackTemplateFields . Empty ( ) ;
EntityComponentFields . Empty ( ) ;
}
void UMovieSceneCompiledDataManager : : ConsoleVariableSink ( )
{
FGuid NewCompilerVersion ;
const bool bParsed = FGuid : : Parse ( GMovieSceneCompilerVersion , NewCompilerVersion ) ;
ensureMsgf ( bParsed , TEXT ( " Invalid compiler version specific - this will break any persistent compiled data " ) ) ;
if ( CompilerVersion ! = NewCompilerVersion )
{
DestroyAllData ( ) ;
}
2020-08-11 01:36:57 -04:00
}
void UMovieSceneCompiledDataManager : : CopyCompiledData ( UMovieSceneSequence * Sequence )
{
UMovieSceneCompiledData * CompiledData = Sequence - > GetOrCreateCompiledData ( ) ;
CompiledData - > Reset ( ) ;
FMovieSceneCompiledDataID DataID = GetDataID ( Sequence ) ;
Compile ( DataID , Sequence ) ;
if ( const FMovieSceneSequenceHierarchy * Hierarchy = FindHierarchy ( DataID ) )
{
CompiledData - > Hierarchy = * Hierarchy ;
CompiledData - > AllocatedMask . bHierarchy = true ;
}
if ( const FMovieSceneEvaluationTemplate * TrackTemplate = FindTrackTemplate ( DataID ) )
{
CompiledData - > EvaluationTemplate = * TrackTemplate ;
CompiledData - > AllocatedMask . bEvaluationTemplate = true ;
}
if ( const FMovieSceneEvaluationField * TrackTemplateField = FindTrackTemplateField ( DataID ) )
{
if ( Sequence - > IsPlayableDirectly ( ) )
{
CompiledData - > TrackTemplateField = * TrackTemplateField ;
CompiledData - > AllocatedMask . bEvaluationTemplateField = true ;
}
}
if ( const FMovieSceneEntityComponentField * EntityComponentField = FindEntityComponentField ( DataID ) )
{
CompiledData - > EntityComponentField = * EntityComponentField ;
CompiledData - > AllocatedMask . bEntityComponentField = true ;
}
const FMovieSceneCompiledDataEntry & DataEntry = CompiledDataEntries [ DataID . Value ] ;
CompiledData - > DeterminismFences = DataEntry . DeterminismFences ;
CompiledData - > CompiledSignature = Sequence - > GetSignature ( ) ;
CompiledData - > CompilerVersion = CompilerVersion ;
CompiledData - > AccumulatedMask = DataEntry . AccumulatedMask ;
CompiledData - > AccumulatedFlags = DataEntry . AccumulatedFlags ;
2021-05-11 01:10:20 -04:00
CompiledData - > CompiledFlags = DataEntry . CompiledFlags ;
2020-08-11 01:36:57 -04:00
}
void UMovieSceneCompiledDataManager : : LoadCompiledData ( UMovieSceneSequence * Sequence )
{
// This can be called during Async Loads
FScopeLock AsyncLoadLock ( & AsyncLoadCriticalSection ) ;
UMovieSceneCompiledData * CompiledData = Sequence - > GetCompiledData ( ) ;
if ( CompiledData )
{
FMovieSceneCompiledDataID DataID = GetDataID ( Sequence ) ;
if ( CompiledData - > CompilerVersion ! = CompilerVersion )
{
CompiledDataEntries [ DataID . Value ] . AccumulatedFlags | = EMovieSceneSequenceFlags : : Volatile ;
return ;
}
if ( CompiledData - > AllocatedMask . bHierarchy )
{
Hierarchies . Add ( DataID . Value , MoveTemp ( CompiledData - > Hierarchy ) ) ;
}
if ( CompiledData - > AllocatedMask . bEvaluationTemplate )
{
TrackTemplates . Add ( DataID . Value , MoveTemp ( CompiledData - > EvaluationTemplate ) ) ;
}
if ( CompiledData - > AllocatedMask . bEvaluationTemplateField )
{
TrackTemplateFields . Add ( DataID . Value , MoveTemp ( CompiledData - > TrackTemplateField ) ) ;
}
if ( CompiledData - > AllocatedMask . bEntityComponentField )
{
EntityComponentFields . Add ( DataID . Value , MoveTemp ( CompiledData - > EntityComponentField ) ) ;
}
FMovieSceneCompiledDataEntry * EntryPtr = GetEntryPtr ( DataID ) ;
EntryPtr - > DeterminismFences = MoveTemp ( CompiledData - > DeterminismFences ) ;
EntryPtr - > CompiledSignature = CompiledData - > CompiledSignature ;
EntryPtr - > AccumulatedMask = CompiledData - > AccumulatedMask . AsEnum ( ) ;
EntryPtr - > AccumulatedFlags = CompiledData - > AccumulatedFlags ;
2021-05-11 01:10:20 -04:00
EntryPtr - > CompiledFlags = CompiledData - > CompiledFlags ;
2020-08-11 01:36:57 -04:00
+ + ReallocationVersion ;
}
else
{
Reset ( Sequence ) ;
}
}
2020-10-09 22:42:26 -04:00
void UMovieSceneCompiledDataManager : : SetEmulatedNetworkMask ( EMovieSceneServerClientMask NewMask )
{
DestroyAllData ( ) ;
NetworkMask = NewMask ;
}
2020-08-11 01:36:57 -04:00
void UMovieSceneCompiledDataManager : : Reset ( UMovieSceneSequence * Sequence )
{
2021-02-03 14:57:28 -04:00
// Care is taken here not to use GetDataID which _creates_ a new data ID if
// one is not available. This ensures that calling Reset() does not create
// new data for sequences that have not yet been encountered
2020-10-09 22:42:26 -04:00
FMovieSceneCompiledDataID DataID = SequenceToDataIDs . FindRef ( Sequence ) ;
2020-08-11 01:36:57 -04:00
if ( DataID . IsValid ( ) )
{
2020-10-09 22:42:26 -04:00
DestroyData ( DataID ) ;
SequenceToDataIDs . Remove ( Sequence ) ;
2020-08-11 01:36:57 -04:00
}
}
2020-10-09 22:42:26 -04:00
FMovieSceneCompiledDataID UMovieSceneCompiledDataManager : : FindDataID ( UMovieSceneSequence * Sequence ) const
{
return SequenceToDataIDs . FindRef ( Sequence ) ;
}
2020-08-11 01:36:57 -04:00
FMovieSceneCompiledDataID UMovieSceneCompiledDataManager : : GetDataID ( UMovieSceneSequence * Sequence )
{
check ( Sequence ) ;
2020-10-09 22:42:26 -04:00
FMovieSceneCompiledDataID ExistingDataID = FindDataID ( Sequence ) ;
2020-08-11 01:36:57 -04:00
if ( ExistingDataID . IsValid ( ) )
{
return ExistingDataID ;
}
const int32 Index = CompiledDataEntries . Add ( FMovieSceneCompiledDataEntry ( ) ) ;
ExistingDataID = FMovieSceneCompiledDataID { Index } ;
FMovieSceneCompiledDataEntry & NewEntry = CompiledDataEntries [ Index ] ;
2020-09-01 14:07:48 -04:00
NewEntry . SequenceKey = Sequence ;
2020-08-11 01:36:57 -04:00
NewEntry . DataID = ExistingDataID ;
NewEntry . AccumulatedFlags = Sequence - > GetFlags ( ) ;
SequenceToDataIDs . Add ( Sequence , ExistingDataID ) ;
return ExistingDataID ;
}
FMovieSceneCompiledDataID UMovieSceneCompiledDataManager : : GetSubDataID ( FMovieSceneCompiledDataID DataID , FMovieSceneSequenceID SubSequenceID )
{
if ( SubSequenceID = = MovieSceneSequenceID : : Root )
{
return DataID ;
}
const FMovieSceneSequenceHierarchy * Hierarchy = FindHierarchy ( DataID ) ;
if ( Hierarchy )
{
const FMovieSceneSubSequenceData * SubData = Hierarchy - > FindSubData ( SubSequenceID ) ;
UMovieSceneSequence * SubSequence = SubData ? SubData - > GetSequence ( ) : nullptr ;
if ( SubSequence )
{
return GetDataID ( SubSequence ) ;
}
}
return FMovieSceneCompiledDataID ( ) ;
}
2020-10-09 22:42:26 -04:00
# if WITH_EDITOR
UMovieSceneCompiledDataManager * UMovieSceneCompiledDataManager : : GetPrecompiledData ( EMovieSceneServerClientMask EmulatedMask )
{
ensureMsgf ( ! GExitPurge , TEXT ( " Attempting to access precompiled data manager during shutdown - this is undefined behavior since the manager may have already been destroyed, or could be unconstrictible " ) ) ;
if ( EmulatedMask = = EMovieSceneServerClientMask : : Client )
{
static UMovieSceneCompiledDataManager * GEmulatedClientDataManager = NewObject < UMovieSceneCompiledDataManager > ( GetTransientPackage ( ) , " EmulatedClientDataManager " , RF_MarkAsRootSet ) ;
GEmulatedClientDataManager - > NetworkMask = EMovieSceneServerClientMask : : Client ;
return GEmulatedClientDataManager ;
}
if ( EmulatedMask = = EMovieSceneServerClientMask : : Server )
{
static UMovieSceneCompiledDataManager * GEmulatedServerDataManager = NewObject < UMovieSceneCompiledDataManager > ( GetTransientPackage ( ) , " EmulatedServerDataManager " , RF_MarkAsRootSet ) ;
GEmulatedServerDataManager - > NetworkMask = EMovieSceneServerClientMask : : Server ;
return GEmulatedServerDataManager ;
}
static UMovieSceneCompiledDataManager * GPrecompiledDataManager = NewObject < UMovieSceneCompiledDataManager > ( GetTransientPackage ( ) , " PrecompiledDataManager " , RF_MarkAsRootSet ) ;
return GPrecompiledDataManager ;
}
# else // WITH_EDITOR
2020-08-11 01:36:57 -04:00
UMovieSceneCompiledDataManager * UMovieSceneCompiledDataManager : : GetPrecompiledData ( )
{
2020-09-01 14:07:48 -04:00
ensureMsgf ( ! GExitPurge , TEXT ( " Attempting to access precompiled data manager during shutdown - this is undefined behavior since the manager may have already been destroyed, or could be unconstrictible " ) ) ;
2020-08-11 01:36:57 -04:00
static UMovieSceneCompiledDataManager * GPrecompiledDataManager = NewObject < UMovieSceneCompiledDataManager > ( GetTransientPackage ( ) , " PrecompiledDataManager " , RF_MarkAsRootSet ) ;
return GPrecompiledDataManager ;
}
2020-10-09 22:42:26 -04:00
# endif // WITH_EDITOR
2020-08-11 01:36:57 -04:00
2020-10-09 22:42:26 -04:00
void UMovieSceneCompiledDataManager : : DestroyData ( FMovieSceneCompiledDataID DataID )
2020-08-11 01:36:57 -04:00
{
check ( DataID . IsValid ( ) & & CompiledDataEntries . IsValidIndex ( DataID . Value ) ) ;
Hierarchies . Remove ( DataID . Value ) ;
TrackTemplates . Remove ( DataID . Value ) ;
TrackTemplateFields . Remove ( DataID . Value ) ;
EntityComponentFields . Remove ( DataID . Value ) ;
CompiledDataEntries . RemoveAt ( DataID . Value ) ;
2020-10-09 22:42:26 -04:00
}
2020-08-11 01:36:57 -04:00
2020-10-09 22:42:26 -04:00
void UMovieSceneCompiledDataManager : : DestroyTemplate ( FMovieSceneCompiledDataID DataID )
{
check ( DataID . IsValid ( ) & & CompiledDataEntries . IsValidIndex ( DataID . Value ) ) ;
// Remove the lookup entry for this sequence/network mask combination
const FMovieSceneCompiledDataEntry & Entry = CompiledDataEntries [ DataID . Value ] ;
SequenceToDataIDs . Remove ( Entry . SequenceKey ) ;
DestroyData ( DataID ) ;
2020-08-11 01:36:57 -04:00
}
bool UMovieSceneCompiledDataManager : : IsDirty ( const FMovieSceneCompiledDataEntry & Entry ) const
{
2021-12-14 13:34:16 -05:00
if ( ! Entry . GetSequence ( ) )
{
return false ;
}
2020-09-01 14:07:48 -04:00
if ( Entry . CompiledSignature ! = Entry . GetSequence ( ) - > GetSignature ( ) )
2020-08-11 01:36:57 -04:00
{
return true ;
}
if ( const FMovieSceneSequenceHierarchy * Hierarchy = FindHierarchy ( Entry . DataID ) )
{
for ( const TTuple < FMovieSceneSequenceID , FMovieSceneSubSequenceData > & Pair : Hierarchy - > AllSubSequenceData ( ) )
{
if ( UMovieSceneSequence * SubSequence = Pair . Value . GetSequence ( ) )
{
2020-10-09 22:42:26 -04:00
FMovieSceneCompiledDataID SubDataID = FindDataID ( SubSequence ) ;
2020-08-11 01:36:57 -04:00
if ( ! SubDataID . IsValid ( ) | | CompiledDataEntries [ SubDataID . Value ] . CompiledSignature ! = SubSequence - > GetSignature ( ) )
{
return true ;
}
}
else
{
return true ;
}
}
}
return false ;
}
bool UMovieSceneCompiledDataManager : : IsDirty ( FMovieSceneCompiledDataID CompiledDataID ) const
{
2020-12-11 14:21:20 -04:00
check ( CompiledDataID . IsValid ( ) & & CompiledDataEntries . IsValidIndex ( CompiledDataID . Value ) ) ;
2020-08-11 01:36:57 -04:00
return IsDirty ( CompiledDataEntries [ CompiledDataID . Value ] ) ;
}
bool UMovieSceneCompiledDataManager : : IsDirty ( UMovieSceneSequence * Sequence ) const
{
2020-10-09 22:42:26 -04:00
FMovieSceneCompiledDataID ExistingDataID = FindDataID ( Sequence ) ;
2020-08-11 01:36:57 -04:00
if ( ExistingDataID . IsValid ( ) )
{
2020-12-11 14:21:20 -04:00
check ( CompiledDataEntries . IsValidIndex ( ExistingDataID . Value ) ) ;
2020-08-11 01:36:57 -04:00
FMovieSceneCompiledDataEntry Entry = CompiledDataEntries [ ExistingDataID . Value ] ;
return IsDirty ( Entry ) ;
}
return true ;
}
void UMovieSceneCompiledDataManager : : Compile ( FMovieSceneCompiledDataID DataID )
{
2020-12-11 14:21:20 -04:00
check ( DataID . IsValid ( ) & & CompiledDataEntries . IsValidIndex ( DataID . Value ) ) ;
2020-09-01 14:07:48 -04:00
UMovieSceneSequence * Sequence = CompiledDataEntries [ DataID . Value ] . GetSequence ( ) ;
2020-08-11 01:36:57 -04:00
check ( Sequence ) ;
Compile ( DataID , Sequence ) ;
}
FMovieSceneCompiledDataID UMovieSceneCompiledDataManager : : Compile ( UMovieSceneSequence * Sequence )
{
FMovieSceneCompiledDataID DataID = GetDataID ( Sequence ) ;
Compile ( DataID , Sequence ) ;
return DataID ;
}
void UMovieSceneCompiledDataManager : : Compile ( FMovieSceneCompiledDataID DataID , UMovieSceneSequence * Sequence )
{
2020-12-11 14:21:20 -04:00
check ( DataID . IsValid ( ) & & CompiledDataEntries . IsValidIndex ( DataID . Value ) ) ;
2020-08-11 01:36:57 -04:00
FMovieSceneCompiledDataEntry Entry = CompiledDataEntries [ DataID . Value ] ;
if ( ! IsDirty ( Entry ) )
{
return ;
}
FMovieSceneGatheredCompilerData GatheredData ;
FTrackGatherParameters Params ( this ) ;
2021-05-11 01:10:20 -04:00
Entry . DeterminismFences . Empty ( ) ;
2020-08-11 01:36:57 -04:00
Entry . AccumulatedFlags = Sequence - > GetFlags ( ) ;
Params . TemplateGenerator . Reset ( & Entry ) ;
2020-10-09 22:42:26 -04:00
Params . NetworkMask = NetworkMask ;
2020-08-11 01:36:57 -04:00
// ---------------------------------------------------------------------------------------------------
// Step 1 - Always ensure the hierarchy information is completely up to date first
FMovieSceneSequenceHierarchy NewHierarchy ;
const bool bHasHierarchy = CompileHierarchy ( Sequence , Params , & NewHierarchy ) ;
2021-05-11 01:10:20 -04:00
if ( IMovieSceneDeterminismSource * DeterminismSource = Cast < IMovieSceneDeterminismSource > ( Sequence ) )
{
DeterminismSource - > PopulateDeterminismData ( GatheredData . DeterminismData , TRange < FFrameNumber > : : All ( ) ) ;
}
2020-08-11 01:36:57 -04:00
TSet < FGuid > GatheredSignatures ;
{
UMovieScene * MovieScene = Sequence - > GetMovieScene ( ) ;
2021-08-10 19:26:19 -04:00
if ( ensure ( MovieScene ) )
2021-05-11 01:10:20 -04:00
{
2021-08-10 19:26:19 -04:00
for ( const FMovieSceneMarkedFrame & Mark : MovieScene - > GetMarkedFrames ( ) )
2021-05-11 01:10:20 -04:00
{
2021-08-10 19:26:19 -04:00
if ( Mark . bIsDeterminismFence )
{
GatheredData . DeterminismData . Fences . Add ( Mark . FrameNumber ) ;
}
2021-05-11 01:10:20 -04:00
}
2021-08-10 19:26:19 -04:00
if ( UMovieSceneTrack * Track = MovieScene - > GetCameraCutTrack ( ) )
2020-08-11 01:36:57 -04:00
{
2021-08-10 19:26:19 -04:00
CompileTrack ( & Entry , nullptr , Track , Params , & GatheredSignatures , & GatheredData ) ;
}
for ( UMovieSceneTrack * Track : MovieScene - > GetMasterTracks ( ) )
{
CompileTrack ( & Entry , nullptr , Track , Params , & GatheredSignatures , & GatheredData ) ;
}
for ( const FMovieSceneBinding & ObjectBinding : MovieScene - > GetBindings ( ) )
{
for ( UMovieSceneTrack * Track : ObjectBinding . GetTracks ( ) )
{
CompileTrack ( & Entry , & ObjectBinding , Track , Params , & GatheredSignatures , & GatheredData ) ;
}
2020-08-11 01:36:57 -04:00
}
}
}
// ---------------------------------------------------------------------------------------------------
// Step 2 - Gather compilation data
FMovieSceneEntityComponentField ThisSequenceEntityField ;
{
GatheredData . EntityField = & ThisSequenceEntityField ;
Gather ( Entry , Sequence , Params , & GatheredData ) ;
GatheredData . EntityField = nullptr ;
}
// ---------------------------------------------------------------------------------------------------
// Step 3 - Assign entity field from data gathered for _this sequence only_
if ( ThisSequenceEntityField . IsEmpty ( ) )
{
EntityComponentFields . Remove ( DataID . Value ) ;
}
else
{
// EntityComponent data is not flattened so we assign that now after the initial gather
EntityComponentFields . FindOrAdd ( DataID . Value ) = MoveTemp ( ThisSequenceEntityField ) ;
GatheredData . AccumulatedMask | = EMovieSceneSequenceCompilerMask : : EntityComponentField ;
}
// ---------------------------------------------------------------------------------------------------
// Step 4 - If we have a hierarchy, perform a gather for sub sequences
if ( bHasHierarchy )
{
CompileSubSequences ( NewHierarchy , Params , & GatheredData ) ;
Entry . AccumulatedFlags | = GatheredData . InheritedFlags ;
Entry . AccumulatedMask | = GatheredData . AccumulatedMask ;
}
// ---------------------------------------------------------------------------------------------------
// Step 5 - Consolidate track template data from gathered data
if ( FMovieSceneEvaluationTemplate * TrackTemplate = TrackTemplates . Find ( Entry . DataID . Value ) )
{
TrackTemplate - > RemoveStaleData ( GatheredSignatures ) ;
}
CompileTrackTemplateField ( & Entry , NewHierarchy , & GatheredData ) ;
// ---------------------------------------------------------------------------------------------------
// Step 6 - Reassign or remove the new hierarchy
if ( bHasHierarchy )
{
Hierarchies . FindOrAdd ( DataID . Value ) = MoveTemp ( NewHierarchy ) ;
}
else
{
Hierarchies . Remove ( DataID . Value ) ;
}
// ---------------------------------------------------------------------------------------------------
// Step 7: Apply the final state to the entry
2021-05-11 01:10:20 -04:00
Entry . CompiledFlags . bParentSequenceRequiresLowerFence = GatheredData . DeterminismData . bParentSequenceRequiresLowerFence ;
Entry . CompiledFlags . bParentSequenceRequiresUpperFence = GatheredData . DeterminismData . bParentSequenceRequiresUpperFence ;
2020-08-11 01:36:57 -04:00
Entry . CompiledSignature = Sequence - > GetSignature ( ) ;
Entry . AccumulatedMask = GatheredData . AccumulatedMask ;
2021-05-11 01:10:20 -04:00
Entry . DeterminismFences = MoveTemp ( GatheredData . DeterminismData . Fences ) ;
if ( Entry . DeterminismFences . Num ( ) )
{
Algo : : Sort ( Entry . DeterminismFences ) ;
const int32 NewNum = Algo : : Unique ( Entry . DeterminismFences ) ;
if ( NewNum ! = Entry . DeterminismFences . Num ( ) )
{
Entry . DeterminismFences . SetNum ( NewNum ) ;
}
}
2020-08-11 01:36:57 -04:00
CompiledDataEntries [ DataID . Value ] = Entry ;
+ + ReallocationVersion ;
2021-08-03 11:56:47 -04:00
#if 0
# if !NO_LOGGING
if ( bHasHierarchy )
{
FMovieSceneSequenceHierarchy * HierarchyToLog = Hierarchies . Find ( DataID . Value ) ;
if ( ensure ( HierarchyToLog ) )
{
UE_LOG ( LogMovieScene , Log , TEXT ( " Newly compiled sequence hierarchy: " ) ) ;
HierarchyToLog - > LogHierarchy ( ) ;
HierarchyToLog - > LogSubSequenceTree ( ) ;
}
}
else
{
UE_LOG ( LogMovieScene , Log , TEXT ( " No sequence hierarchy " ) ) ;
}
# endif
# endif
2020-08-11 01:36:57 -04:00
}
void UMovieSceneCompiledDataManager : : Gather ( const FMovieSceneCompiledDataEntry & Entry , UMovieSceneSequence * Sequence , const FTrackGatherParameters & Params , FMovieSceneGatheredCompilerData * OutCompilerData ) const
{
const FMovieSceneEvaluationTemplate * TrackTemplate = FindTrackTemplate ( Entry . DataID ) ;
UMovieScene * MovieScene = Sequence - > GetMovieScene ( ) ;
2021-08-10 19:26:19 -04:00
if ( ensure ( MovieScene ) )
2020-08-11 01:36:57 -04:00
{
2021-08-10 19:26:19 -04:00
if ( UMovieSceneTrack * Track = MovieScene - > GetCameraCutTrack ( ) )
2020-08-11 01:36:57 -04:00
{
2021-08-10 19:26:19 -04:00
GatherTrack ( nullptr , Track , Params , TrackTemplate , OutCompilerData ) ;
}
for ( UMovieSceneTrack * Track : MovieScene - > GetMasterTracks ( ) )
{
GatherTrack ( nullptr , Track , Params , TrackTemplate , OutCompilerData ) ;
}
for ( const FMovieSceneBinding & ObjectBinding : MovieScene - > GetBindings ( ) )
{
for ( UMovieSceneTrack * Track : ObjectBinding . GetTracks ( ) )
{
GatherTrack ( & ObjectBinding , Track , Params , TrackTemplate , OutCompilerData ) ;
}
2020-08-11 01:36:57 -04:00
}
}
}
void UMovieSceneCompiledDataManager : : CompileSubSequences ( const FMovieSceneSequenceHierarchy & Hierarchy , const FTrackGatherParameters & Params , FMovieSceneGatheredCompilerData * OutCompilerData )
{
2021-05-11 01:10:20 -04:00
using namespace UE : : MovieScene ;
2020-08-11 01:36:57 -04:00
OutCompilerData - > AccumulatedMask | = EMovieSceneSequenceCompilerMask : : Hierarchy ;
// Ensure all sub sequences are compiled
for ( const TTuple < FMovieSceneSequenceID , FMovieSceneSubSequenceData > & Pair : Hierarchy . AllSubSequenceData ( ) )
{
if ( UMovieSceneSequence * SubSequence = Pair . Value . GetSequence ( ) )
{
Compile ( SubSequence ) ;
}
}
const TMovieSceneEvaluationTree < FMovieSceneSubSequenceTreeEntry > & SubSequenceTree = Hierarchy . GetTree ( ) ;
2021-05-12 10:18:48 -04:00
// When adding determinism fences for sub sequences, we track the iteration index for each sequence ID so that
// we only add a fence when the sub sequence truly ends or begins, not for every segmentation of the sub sequence tree
struct FSubSequenceItMetaData
{
int32 LastIterIndex = INDEX_NONE ;
TOptional < FFrameNumber > TrailingFence ;
} ;
TSortedMap < FMovieSceneSequenceID , FSubSequenceItMetaData > ItMetaData ;
2020-08-11 01:36:57 -04:00
// Start iterating the field from the lower bound of the compile range
FMovieSceneEvaluationTreeRangeIterator SubSequenceIt = SubSequenceTree . IterateFromLowerBound ( Params . RootClampRange . GetLowerBound ( ) ) ;
2021-05-12 10:18:48 -04:00
for ( int32 ItIndex = 0 ; SubSequenceIt & & SubSequenceIt . Range ( ) . Overlaps ( Params . RootClampRange ) ; + + SubSequenceIt , + + ItIndex )
2020-08-11 01:36:57 -04:00
{
// Iterate all sub sequences in the current range
2021-08-03 11:56:47 -04:00
for ( const FMovieSceneSubSequenceTreeEntry & SubSequenceEntry : SubSequenceTree . GetAllData ( SubSequenceIt . Node ( ) ) )
2020-08-11 01:36:57 -04:00
{
2021-05-12 10:18:48 -04:00
FMovieSceneSequenceID SubSequenceID = SubSequenceEntry . SequenceID ;
const FMovieSceneSubSequenceData * SubData = Hierarchy . FindSubData ( SubSequenceID ) ;
2020-08-11 01:36:57 -04:00
checkf ( SubData , TEXT ( " Sub data could not be found for a sequence that exists in the sub sequence tree - this indicates an error while populating the sub sequence hierarchy tree. " ) ) ;
UMovieSceneSequence * SubSequence = SubData - > GetSequence ( ) ;
if ( SubSequence )
{
2021-10-20 11:49:19 -04:00
FTrackGatherParameters SubSectionGatherParams = Params . CreateForSubData ( * SubData , SubSequenceID , SubSequenceEntry . RootToSequenceWarpCounter ) ;
2020-09-01 14:07:48 -04:00
SubSectionGatherParams . Flags | = SubSequenceEntry . Flags ;
2020-08-11 01:36:57 -04:00
SubSectionGatherParams . SetClampRange ( SubSequenceIt . Range ( ) ) ;
// Access the sub entry data after compilation
FMovieSceneCompiledDataID SubDataID = GetDataID ( SubSequence ) ;
check ( SubDataID . IsValid ( ) ) ;
// Gather track template data for the sub sequence
FMovieSceneCompiledDataEntry SubEntry = CompiledDataEntries [ SubDataID . Value ] ;
if ( TrackTemplates . Contains ( SubDataID . Value ) )
{
Gather ( SubEntry , SubSequence , SubSectionGatherParams , OutCompilerData ) ;
}
// Inherit flags from sub sequences (if a sub sequence is volatile, so must this be)
OutCompilerData - > InheritedFlags | = ( CompiledDataEntries [ SubDataID . Value ] . AccumulatedFlags & EMovieSceneSequenceFlags : : InheritedFlags ) ;
OutCompilerData - > AccumulatedMask | = SubEntry . AccumulatedMask ;
2021-05-11 01:10:20 -04:00
2021-05-12 10:18:48 -04:00
FSubSequenceItMetaData * MetaData = & ItMetaData . FindOrAdd ( SubSequenceID ) ;
const bool bWasEvaluatedLastFrame = MetaData - > LastIterIndex ! = INDEX_NONE & & MetaData - > LastIterIndex = = ItIndex - 1 ;
if ( SubEntry . CompiledFlags . bParentSequenceRequiresLowerFence & & bWasEvaluatedLastFrame = = false )
2021-05-11 01:10:20 -04:00
{
OutCompilerData - > DeterminismData . Fences . Add ( DiscreteInclusiveLower ( SubSequenceIt . Range ( ) ) ) ;
}
if ( SubEntry . CompiledFlags . bParentSequenceRequiresUpperFence )
{
2021-05-12 10:18:48 -04:00
MetaData - > TrailingFence = DiscreteExclusiveUpper ( SubSequenceIt . Range ( ) ) ;
2021-05-11 01:10:20 -04:00
}
2021-05-12 10:18:48 -04:00
MetaData - > LastIterIndex = ItIndex ;
}
}
for ( TPair < FMovieSceneSequenceID , FSubSequenceItMetaData > & Pair : ItMetaData )
{
if ( Pair . Value . LastIterIndex = = ItIndex - 1 & & Pair . Value . TrailingFence . IsSet ( ) )
{
OutCompilerData - > DeterminismData . Fences . Add ( Pair . Value . TrailingFence . GetValue ( ) ) ;
Pair . Value . TrailingFence . Reset ( ) ;
2020-08-11 01:36:57 -04:00
}
}
}
}
void UMovieSceneCompiledDataManager : : CompileTrackTemplateField ( FMovieSceneCompiledDataEntry * OutEntry , const FMovieSceneSequenceHierarchy & Hierarchy , FMovieSceneGatheredCompilerData * InCompilerData )
{
if ( ! EnumHasAnyFlags ( InCompilerData - > AccumulatedMask , EMovieSceneSequenceCompilerMask : : EvaluationTemplate ) )
{
TrackTemplateFields . Remove ( OutEntry - > DataID . Value ) ;
return ;
}
FMovieSceneEvaluationField * TrackTemplateField = & TrackTemplateFields . FindOrAdd ( OutEntry - > DataID . Value ) ;
// Wipe the current evaluation field for the template
* TrackTemplateField = FMovieSceneEvaluationField ( ) ;
InCompilerData - > AccumulatedMask | = EMovieSceneSequenceCompilerMask : : EvaluationTemplateField ;
TArray < FCompileOnTheFlyData > CompileData ;
for ( FMovieSceneEvaluationTreeRangeIterator It ( InCompilerData - > TrackTemplates ) ; It ; + + It )
{
CompileData . Reset ( ) ;
TRange < FFrameNumber > FieldRange = It . Range ( ) ;
for ( const FCompileOnTheFlyData & TrackData : InCompilerData - > TrackTemplates . GetAllData ( It . Node ( ) ) )
{
CompileData . Add ( TrackData ) ;
}
// Sort the compilation data based on (in order):
// 1. Group
// 2. Hierarchical bias
// 3. Evaluation priority
CompileData . Sort ( SortPredicate ) ;
// Generate the evaluation group by gathering initialization and evaluation ptrs for each unique group
FMovieSceneEvaluationGroup EvaluationGroup ;
PopulateEvaluationGroup ( CompileData , & EvaluationGroup ) ;
// Compute meta data for this segment
TMovieSceneEvaluationTreeDataIterator < FMovieSceneSubSequenceTreeEntry > SubSequences = Hierarchy . GetTree ( ) . GetAllData ( Hierarchy . GetTree ( ) . IterateFromLowerBound ( FieldRange . GetLowerBound ( ) ) . Node ( ) ) ;
FMovieSceneEvaluationMetaData MetaData ;
PopulateMetaData ( Hierarchy , CompileData , SubSequences , & MetaData ) ;
TrackTemplateField - > Add ( FieldRange , MoveTemp ( EvaluationGroup ) , MoveTemp ( MetaData ) ) ;
}
}
void UMovieSceneCompiledDataManager : : PopulateEvaluationGroup ( const TArray < FCompileOnTheFlyData > & SortedCompileData , FMovieSceneEvaluationGroup * OutGroup )
{
check ( OutGroup ) ;
if ( SortedCompileData . Num ( ) = = 0 )
{
return ;
}
static TArray < FMovieSceneFieldEntry_EvaluationTrack > InitTrackLUT ;
static TArray < FMovieSceneFieldEntry_ChildTemplate > InitSectionLUT ;
static TArray < FMovieSceneFieldEntry_EvaluationTrack > EvalTrackLUT ;
static TArray < FMovieSceneFieldEntry_ChildTemplate > EvalSectionLUT ;
InitTrackLUT . Reset ( ) ;
InitSectionLUT . Reset ( ) ;
EvalTrackLUT . Reset ( ) ;
EvalSectionLUT . Reset ( ) ;
// Now iterate the tracks and insert indices for initialization and evaluation
FName LastEvaluationGroup = SortedCompileData [ 0 ] . EvaluationGroup ;
int32 Index = 0 ;
while ( Index < SortedCompileData . Num ( ) )
{
const FCompileOnTheFlyData & Data = SortedCompileData [ Index ] ;
// Check for different evaluation groups
if ( Data . EvaluationGroup ! = LastEvaluationGroup )
{
// If we're now in a different flush group, add the ptrs to the group
AddPtrsToGroup ( OutGroup , InitTrackLUT , InitSectionLUT , EvalTrackLUT , EvalSectionLUT ) ;
}
LastEvaluationGroup = Data . EvaluationGroup ;
// Add all subsequent entries that relate to the same track
FMovieSceneEvaluationFieldTrackPtr MatchTrack = Data . Track ;
uint16 NumChildren = 0 ;
for ( ; Index < SortedCompileData . Num ( ) & & SortedCompileData [ Index ] . Track = = MatchTrack ; + + Index )
{
if ( SortedCompileData [ Index ] . Child . ChildIndex ! = uint16 ( - 1 ) )
{
+ + NumChildren ;
// If this track requires initialization, add it to the init array
if ( Data . bRequiresInit )
{
InitSectionLUT . Add ( SortedCompileData [ Index ] . Child ) ;
}
EvalSectionLUT . Add ( SortedCompileData [ Index ] . Child ) ;
}
}
FMovieSceneFieldEntry_EvaluationTrack Entry { Data . Track , NumChildren } ;
if ( Data . bRequiresInit )
{
InitTrackLUT . Add ( Entry ) ;
}
EvalTrackLUT . Add ( Entry ) ;
}
AddPtrsToGroup ( OutGroup , InitTrackLUT , InitSectionLUT , EvalTrackLUT , EvalSectionLUT ) ;
}
void UMovieSceneCompiledDataManager : : PopulateMetaData ( const FMovieSceneSequenceHierarchy & RootHierarchy , const TArray < FCompileOnTheFlyData > & SortedCompileData , TMovieSceneEvaluationTreeDataIterator < FMovieSceneSubSequenceTreeEntry > SubSequences , FMovieSceneEvaluationMetaData * OutMetaData )
{
check ( OutMetaData ) ;
OutMetaData - > Reset ( ) ;
uint16 SetupIndex = 0 ;
uint16 TearDownIndex = 0 ;
for ( const FCompileOnTheFlyData & CompileData : SortedCompileData )
{
if ( CompileData . bRequiresInit )
{
uint32 ChildIndex = CompileData . Child . ChildIndex = = uint16 ( - 1 ) ? uint32 ( - 1 ) : CompileData . Child . ChildIndex ;
FMovieSceneEvaluationKey TrackKey ( CompileData . Track . SequenceID , CompileData . Track . TrackIdentifier , ChildIndex ) ;
OutMetaData - > ActiveEntities . Add ( FMovieSceneOrderedEvaluationKey { TrackKey , SetupIndex + + , ( CompileData . bPriorityTearDown ? TearDownIndex : uint16 ( MAX_uint16 - TearDownIndex ) ) } ) ;
+ + TearDownIndex ;
}
}
// Then all the eval tracks
for ( const FCompileOnTheFlyData & CompileData : SortedCompileData )
{
if ( ! CompileData . bRequiresInit )
{
uint32 ChildIndex = CompileData . Child . ChildIndex = = uint16 ( - 1 ) ? uint32 ( - 1 ) : CompileData . Child . ChildIndex ;
FMovieSceneEvaluationKey TrackKey ( CompileData . Track . SequenceID , CompileData . Track . TrackIdentifier , ChildIndex ) ;
OutMetaData - > ActiveEntities . Add ( FMovieSceneOrderedEvaluationKey { TrackKey , SetupIndex + + , ( CompileData . bPriorityTearDown ? TearDownIndex : uint16 ( MAX_uint16 - TearDownIndex ) ) } ) ;
+ + TearDownIndex ;
}
}
Algo : : SortBy ( OutMetaData - > ActiveEntities , & FMovieSceneOrderedEvaluationKey : : Key ) ;
{
OutMetaData - > ActiveSequences . Reset ( ) ;
OutMetaData - > ActiveSequences . Add ( MovieSceneSequenceID : : Root ) ;
2021-08-03 11:56:47 -04:00
for ( const FMovieSceneSubSequenceTreeEntry & SubSequenceEntry : SubSequences )
2020-08-11 01:36:57 -04:00
{
OutMetaData - > ActiveSequences . Add ( SubSequenceEntry . SequenceID ) ;
}
OutMetaData - > ActiveSequences . Sort ( ) ;
}
}
void UMovieSceneCompiledDataManager : : CompileTrack ( FMovieSceneCompiledDataEntry * OutEntry , const FMovieSceneBinding * ObjectBinding , UMovieSceneTrack * Track , const FTrackGatherParameters & Params , TSet < FGuid > * OutCompiledSignatures , FMovieSceneGatheredCompilerData * OutCompilerData )
{
using namespace UE : : MovieScene ;
check ( Track ) ;
check ( OutCompiledSignatures ) ;
const bool bTrackMatchesFlags = ( Params . Flags = = ESectionEvaluationFlags : : None )
| | ( EnumHasAnyFlags ( Params . Flags , ESectionEvaluationFlags : : PreRoll ) & & Track - > EvalOptions . bEvaluateInPreroll )
| | ( EnumHasAnyFlags ( Params . Flags , ESectionEvaluationFlags : : PostRoll ) & & Track - > EvalOptions . bEvaluateInPostroll ) ;
if ( ! bTrackMatchesFlags )
{
return ;
}
if ( Track - > IsEvalDisabled ( ) )
{
return ;
}
2020-09-01 14:07:48 -04:00
UMovieSceneSequence * Sequence = OutEntry - > GetSequence ( ) ;
2020-08-11 01:36:57 -04:00
check ( Sequence ) ;
// -------------------------------------------------------------------------------------------------------------------------------------
// Step 1 - ensure that track templates exist for any track that implements IMovieSceneTrackTemplateProducer
FMovieSceneTrackIdentifier TrackIdentifier ;
FMovieSceneEvaluationTemplate * TrackTemplate = nullptr ;
if ( const IMovieSceneTrackTemplateProducer * TrackTemplateProducer = Cast < const IMovieSceneTrackTemplateProducer > ( Track ) )
{
TrackTemplate = & TrackTemplates . FindOrAdd ( OutEntry - > DataID . Value ) ;
check ( TrackTemplate ) ;
TrackIdentifier = TrackTemplate - > GetLedger ( ) . FindTrackIdentifier ( Track - > GetSignature ( ) ) ;
if ( ! TrackIdentifier )
{
// If the track doesn't exist - we need to generate it from scratch
FMovieSceneTrackCompilerArgs Args ( Track , & Params . TemplateGenerator ) ;
if ( ObjectBinding )
{
Args . ObjectBindingId = ObjectBinding - > GetObjectGuid ( ) ;
}
Args . DefaultCompletionMode = Sequence - > DefaultCompletionMode ;
TrackTemplateProducer - > GenerateTemplate ( Args ) ;
TrackIdentifier = TrackTemplate - > GetLedger ( ) . FindTrackIdentifier ( Track - > GetSignature ( ) ) ;
}
if ( TrackIdentifier )
{
OutCompiledSignatures - > Add ( Track - > GetSignature ( ) ) ;
}
OutCompilerData - > AccumulatedMask | = EMovieSceneSequenceCompilerMask : : EvaluationTemplate ;
}
2021-05-11 01:10:20 -04:00
2021-09-03 19:14:18 -04:00
// -------------------------------------------------------------------------------------------------------------------------------------
// Step 2 - let the track or its sections add determinism fences
2021-05-11 01:10:20 -04:00
if ( IMovieSceneDeterminismSource * DeterminismSource = Cast < IMovieSceneDeterminismSource > ( Track ) )
{
DeterminismSource - > PopulateDeterminismData ( OutCompilerData - > DeterminismData , TRange < FFrameNumber > : : All ( ) ) ;
}
const FMovieSceneTrackEvaluationField & EvaluationField = Track - > GetEvaluationField ( ) ;
2021-09-03 19:14:18 -04:00
const EMovieSceneCompletionMode DefaultCompletionMode = Sequence - > DefaultCompletionMode ;
const bool bAddKeepStateDeterminismFences = CVarAddKeepStateDeterminismFences . GetValueOnGameThread ( ) ;
2021-05-11 01:10:20 -04:00
for ( const FMovieSceneTrackEvaluationFieldEntry & Entry : EvaluationField . Entries )
{
2021-09-03 23:48:20 -04:00
if ( bAddKeepStateDeterminismFences & & Entry . Section )
2021-09-03 19:14:18 -04:00
{
// If a section is KeepState, we need to make sure to evaluate it on its last frame so that the value that "sticks" is correct.
const TRange < FFrameNumber > SectionRange = Entry . Section - > GetRange ( ) ;
const EMovieSceneCompletionMode SectionCompletionMode = Entry . Section - > GetCompletionMode ( ) ;
if ( SectionRange . HasUpperBound ( ) & &
( SectionCompletionMode = = EMovieSceneCompletionMode : : KeepState | |
( SectionCompletionMode = = EMovieSceneCompletionMode : : ProjectDefault & & DefaultCompletionMode = = EMovieSceneCompletionMode : : KeepState ) ) )
{
// We simply use the end time of the section for the fence, regardless of whether it's inclusive or exclusive.
// When exclusive, the ECS system will query entities just before that time, but still pass that time for
// evaluation purposes, so we will get the correct evaluated values.
const FFrameNumber FenceTime ( SectionRange . GetUpperBoundValue ( ) ) ;
OutCompilerData - > DeterminismData . Fences . Add ( FenceTime ) ;
}
}
2021-05-11 01:10:20 -04:00
IMovieSceneDeterminismSource * DeterminismSource = Cast < IMovieSceneDeterminismSource > ( Entry . Section ) ;
if ( DeterminismSource )
{
DeterminismSource - > PopulateDeterminismData ( OutCompilerData - > DeterminismData , Entry . Range ) ;
}
}
2020-08-11 01:36:57 -04:00
}
void UMovieSceneCompiledDataManager : : GatherTrack ( const FMovieSceneBinding * ObjectBinding , UMovieSceneTrack * Track , const FTrackGatherParameters & Params , const FMovieSceneEvaluationTemplate * TrackTemplate , FMovieSceneGatheredCompilerData * OutCompilerData ) const
{
using namespace UE : : MovieScene ;
check ( Track ) ;
const bool bTrackMatchesFlags = ( Params . Flags = = ESectionEvaluationFlags : : None )
| | ( EnumHasAnyFlags ( Params . Flags , ESectionEvaluationFlags : : PreRoll ) & & Track - > EvalOptions . bEvaluateInPreroll )
| | ( EnumHasAnyFlags ( Params . Flags , ESectionEvaluationFlags : : PostRoll ) & & Track - > EvalOptions . bEvaluateInPostroll ) ;
if ( ! bTrackMatchesFlags )
{
return ;
}
if ( Track - > IsEvalDisabled ( ) )
{
return ;
}
2020-09-24 00:43:27 -04:00
// Some tracks could want to do some custom pre-compilation things.
2021-03-05 19:27:14 -04:00
FMovieSceneTrackPreCompileResult PreCompileResult ;
Track - > PreCompile ( PreCompileResult ) ;
2020-09-24 00:43:27 -04:00
2020-08-11 01:36:57 -04:00
const FMovieSceneTrackEvaluationField & EvaluationField = Track - > GetEvaluationField ( ) ;
// -------------------------------------------------------------------------------------------------------------------------------------
// Step 1 - Handle any entity producers that exist within the field
if ( OutCompilerData - > EntityField )
{
2020-09-01 14:07:48 -04:00
FMovieSceneEntityComponentFieldBuilder FieldBuilder ( OutCompilerData - > EntityField ) ;
if ( ObjectBinding )
{
FieldBuilder . GetSharedMetaData ( ) . ObjectBindingID = ObjectBinding - > GetObjectGuid ( ) ;
}
2020-08-11 01:36:57 -04:00
for ( const FMovieSceneTrackEvaluationFieldEntry & Entry : EvaluationField . Entries )
{
2021-10-12 21:21:22 -04:00
if ( Entry . Section & & Track - > IsRowEvalDisabled ( Entry . Section - > GetRowIndex ( ) ) )
{
continue ;
}
2020-08-11 01:36:57 -04:00
IMovieSceneEntityProvider * EntityProvider = Cast < IMovieSceneEntityProvider > ( Entry . Section ) ;
if ( ! EntityProvider )
{
continue ;
}
// This codepath should only ever execute for the highest level so we do not need to do any transformations
TRange < FFrameNumber > EffectiveRange = TRange < FFrameNumber > : : Intersection ( Params . LocalClampRange , Entry . Range ) ;
if ( ! EffectiveRange . IsEmpty ( ) )
{
2021-03-05 19:27:14 -04:00
FMovieSceneEvaluationFieldEntityMetaData MetaData ( PreCompileResult . DefaultMetaData ) ;
2020-08-11 01:36:57 -04:00
2020-09-01 14:07:48 -04:00
MetaData . ForcedTime = Entry . ForcedTime ;
MetaData . Flags = Entry . Flags ;
MetaData . bEvaluateInSequencePreRoll = Track - > EvalOptions . bEvaluateInPreroll ;
MetaData . bEvaluateInSequencePostRoll = Track - > EvalOptions . bEvaluateInPostroll ;
if ( ! EntityProvider - > PopulateEvaluationField ( EffectiveRange , MetaData , & FieldBuilder ) )
{
const int32 EntityIndex = FieldBuilder . FindOrAddEntity ( Entry . Section , 0 ) ;
const int32 MetaDataIndex = FieldBuilder . AddMetaData ( MetaData ) ;
FieldBuilder . AddPersistentEntity ( EffectiveRange , EntityIndex , MetaDataIndex ) ;
}
2020-08-11 01:36:57 -04:00
}
}
}
// -------------------------------------------------------------------------------------------------------------------------------------
// Step 2 - Handle the track being a template producer
FMovieSceneTrackIdentifier TrackIdentifier = TrackTemplate ? TrackTemplate - > GetLedger ( ) . FindTrackIdentifier ( Track - > GetSignature ( ) ) : FMovieSceneTrackIdentifier ( ) ;
if ( TrackIdentifier )
{
// Iterate everything in the field
for ( const FMovieSceneTrackEvaluationFieldEntry & Entry : EvaluationField . Entries )
{
2021-08-03 11:56:47 -04:00
FMovieSceneSequenceTransform SequenceToRootTransform = Params . RootToSequenceTransform . InverseFromWarp ( Params . RootToSequenceWarpCounter ) ;
2020-08-11 01:36:57 -04:00
TRange < FFrameNumber > ClampedRangeRoot = Params . ClampRoot ( SequenceToRootTransform . TransformRangeUnwarped ( Entry . Range ) ) ;
UMovieSceneSection * Section = Entry . Section ;
2021-04-29 19:32:06 -04:00
if ( Section & & Track - > IsRowEvalDisabled ( Section - > GetRowIndex ( ) ) )
{
continue ;
}
2020-08-11 01:36:57 -04:00
if ( ClampedRangeRoot . IsEmpty ( ) )
{
continue ;
}
check ( TrackTemplate ) ;
const FMovieSceneEvaluationTrack * EvaluationTrack = TrackTemplate - > FindTrack ( TrackIdentifier ) ;
check ( EvaluationTrack ) ;
// Get the correct template for the sub sequence
FCompileOnTheFlyData CompileData ;
CompileData . Track = FMovieSceneEvaluationFieldTrackPtr ( Params . SequenceID , TrackIdentifier ) ;
CompileData . EvaluationPriority = EvaluationTrack - > GetEvaluationPriority ( ) ;
CompileData . EvaluationGroup = EvaluationTrack - > GetEvaluationGroup ( ) ;
CompileData . GroupEvaluationPriority = GetMovieSceneModule ( ) . GetEvaluationGroupParameters ( CompileData . EvaluationGroup ) . EvaluationPriority ;
CompileData . HierarchicalBias = Params . HierarchicalBias ;
CompileData . bPriorityTearDown = EvaluationTrack - > HasTearDownPriority ( ) ;
2021-01-08 19:56:07 -04:00
auto FindChildWithSection = [ Section ] ( const FMovieSceneEvalTemplatePtr & ChildTemplate )
2020-08-11 01:36:57 -04:00
{
return ChildTemplate . IsValid ( ) & & ChildTemplate - > GetSourceSection ( ) = = Section ;
} ;
const int32 ChildTemplateIndex = Section ? EvaluationTrack - > GetChildTemplates ( ) . IndexOfByPredicate ( FindChildWithSection ) : INDEX_NONE ;
if ( ChildTemplateIndex ! = INDEX_NONE )
{
check ( ChildTemplateIndex > = 0 & & ChildTemplateIndex < TNumericLimits < uint16 > : : Max ( ) ) ;
ESectionEvaluationFlags Flags = Params . Flags = = ESectionEvaluationFlags : : None ? Entry . Flags : Params . Flags ;
CompileData . ChildPriority = Entry . LegacySortOrder ;
CompileData . Child = FMovieSceneFieldEntry_ChildTemplate ( ( uint16 ) ChildTemplateIndex , Flags , Entry . ForcedTime ) ;
CompileData . bRequiresInit = EvaluationTrack - > GetChildTemplate ( ChildTemplateIndex ) . RequiresInitialization ( ) ;
}
else
{
CompileData . ChildPriority = 0 ;
CompileData . Child = FMovieSceneFieldEntry_ChildTemplate { } ;
CompileData . bRequiresInit = false ;
}
OutCompilerData - > TrackTemplates . Add ( ClampedRangeRoot , CompileData ) ;
}
}
}
2020-10-09 22:42:26 -04:00
bool UMovieSceneCompiledDataManager : : CompileHierarchy ( UMovieSceneSequence * Sequence , FMovieSceneSequenceHierarchy * InOutHierarchy , EMovieSceneServerClientMask InNetworkMask )
2020-08-11 01:36:57 -04:00
{
FGatherParameters Params ;
2020-10-09 22:42:26 -04:00
Params . NetworkMask = InNetworkMask ;
2020-08-11 01:36:57 -04:00
return CompileHierarchy ( Sequence , Params , InOutHierarchy ) ;
}
bool UMovieSceneCompiledDataManager : : CompileHierarchy ( UMovieSceneSequence * Sequence , const FGatherParameters & Params , FMovieSceneSequenceHierarchy * InOutHierarchy )
{
2020-12-14 14:36:17 -04:00
UE : : MovieScene : : FSubSequencePath RootPath ;
2021-06-22 00:27:54 -04:00
// Compile all the sub data for every part of the hierarchy
const bool bContainsSubSequences = GenerateSubSequenceData ( Sequence , Params , FMovieSceneEvaluationOperand ( ) , & RootPath , InOutHierarchy ) ;
// Populate the sub sequence tree that defines which sub sequences happen at a given time
PopulateSubSequenceTree ( Sequence , Params , & RootPath , InOutHierarchy ) ;
return bContainsSubSequences ;
2020-08-11 01:36:57 -04:00
}
2021-06-22 00:27:54 -04:00
bool UMovieSceneCompiledDataManager : : GenerateSubSequenceData ( UMovieSceneSequence * SubSequence , const FGatherParameters & Params , const FMovieSceneEvaluationOperand & Operand , UE : : MovieScene : : FSubSequencePath * RootPath , FMovieSceneSequenceHierarchy * InOutHierarchy )
2020-08-11 01:36:57 -04:00
{
2021-06-22 00:27:54 -04:00
UMovieScene * MovieScene = SubSequence ? SubSequence - > GetMovieScene ( ) : nullptr ;
if ( ! MovieScene )
{
return false ;
}
check ( RootPath & & InOutHierarchy ) ;
2020-08-11 01:36:57 -04:00
bool bContainsSubSequences = false ;
for ( UMovieSceneTrack * Track : MovieScene - > GetMasterTracks ( ) )
{
if ( UMovieSceneSubTrack * SubTrack = Cast < UMovieSceneSubTrack > ( Track ) )
{
2021-06-22 00:27:54 -04:00
bContainsSubSequences | = GenerateSubSequenceData ( SubTrack , Params , Operand , RootPath , InOutHierarchy ) ;
2020-08-11 01:36:57 -04:00
}
}
for ( const FMovieSceneBinding & ObjectBinding : MovieScene - > GetBindings ( ) )
{
for ( UMovieSceneTrack * Track : ObjectBinding . GetTracks ( ) )
{
if ( UMovieSceneSubTrack * SubTrack = Cast < UMovieSceneSubTrack > ( Track ) )
{
const FMovieSceneEvaluationOperand ChildOperand ( Params . SequenceID , ObjectBinding . GetObjectGuid ( ) ) ;
2021-06-22 00:27:54 -04:00
bContainsSubSequences | = GenerateSubSequenceData ( SubTrack , Params , ChildOperand , RootPath , InOutHierarchy ) ;
2020-08-11 01:36:57 -04:00
}
}
}
return bContainsSubSequences ;
}
2021-06-22 00:27:54 -04:00
bool UMovieSceneCompiledDataManager : : GenerateSubSequenceData ( UMovieSceneSubTrack * SubTrack , const FGatherParameters & Params , const FMovieSceneEvaluationOperand & Operand , UE : : MovieScene : : FSubSequencePath * RootPath , FMovieSceneSequenceHierarchy * InOutHierarchy )
2020-08-11 01:36:57 -04:00
{
bool bContainsSubSequences = false ;
check ( SubTrack & & RootPath ) ;
const FMovieSceneSequenceID ParentSequenceID = Params . SequenceID ;
for ( UMovieSceneSection * Section : SubTrack - > GetAllSections ( ) )
{
2021-04-29 19:32:06 -04:00
if ( SubTrack - > IsRowEvalDisabled ( Section - > GetRowIndex ( ) ) )
{
continue ;
}
2020-08-11 01:36:57 -04:00
UMovieSceneSubSection * SubSection = Cast < UMovieSceneSubSection > ( Section ) ;
if ( ! SubSection )
{
continue ;
}
2020-10-09 22:42:26 -04:00
// Note: we always compile FMovieSceneSubSequenceData for all entries of a hierarchy, even if excluded from the network mask
// to ensure that hierarchical information is still available when emulating different network masks
2020-08-11 01:36:57 -04:00
UMovieSceneSequence * SubSequence = SubSection - > GetSequence ( ) ;
if ( ! SubSequence )
{
continue ;
}
2021-08-10 19:26:19 -04:00
UMovieScene * MovieScene = SubSequence - > GetMovieScene ( ) ;
if ( ! MovieScene )
{
continue ;
}
2020-12-14 14:36:17 -04:00
const FMovieSceneSequenceID InnerSequenceID = RootPath - > ResolveChildSequenceID ( SubSection - > GetSequenceID ( ) ) ;
2020-08-11 01:36:57 -04:00
FSubSequenceInstanceDataParams InstanceParams { InnerSequenceID , Operand } ;
FMovieSceneSubSequenceData NewSubData = SubSection - > GenerateSubSequenceData ( InstanceParams ) ;
2021-08-03 11:56:47 -04:00
// LocalClampRange here is in SubTrack's space, so we need to multiply that by the OuterToInnerTransform
// (which is the same as RootToSequenceTransform here before we transform it)
2020-10-29 13:38:15 -04:00
TRange < FFrameNumber > InnerClampRange = NewSubData . RootToSequenceTransform . TransformRangeUnwarped ( Params . LocalClampRange ) ;
NewSubData . PlayRange = TRange < FFrameNumber > : : Intersection ( InnerClampRange , NewSubData . PlayRange . Value ) ;
2020-08-11 01:36:57 -04:00
NewSubData . RootToSequenceTransform = NewSubData . RootToSequenceTransform * Params . RootToSequenceTransform ;
NewSubData . HierarchicalBias = Params . HierarchicalBias + NewSubData . HierarchicalBias ;
2020-09-01 14:07:48 -04:00
NewSubData . bHasHierarchicalEasing = Params . bHasHierarchicalEasing | | NewSubData . bHasHierarchicalEasing ;
2020-08-11 01:36:57 -04:00
// Add the sub data to the root hierarchy
InOutHierarchy - > Add ( NewSubData , InnerSequenceID , ParentSequenceID ) ;
2021-06-22 00:27:54 -04:00
// Iterate into the sub sequence
FGatherParameters SubParams = Params . CreateForSubData ( NewSubData , InnerSequenceID ) ;
// This is a bit of hack to make sure that LocalClampRange gets sent through to the next GenerateSubSequenceData call,
// but we do not set RootClampRange because it would be ambiguous to do so w.r.t looping sub sequences
SubParams . LocalClampRange = NewSubData . PlayRange . Value ;
RootPath - > PushGeneration ( InnerSequenceID , NewSubData . DeterministicSequenceID ) ;
GenerateSubSequenceData ( SubSequence , SubParams , Operand , RootPath , InOutHierarchy ) ;
RootPath - > PopGenerations ( 1 ) ;
2020-08-11 01:36:57 -04:00
bContainsSubSequences = true ;
}
2021-06-22 00:27:54 -04:00
return bContainsSubSequences ;
}
void UMovieSceneCompiledDataManager : : PopulateSubSequenceTree ( UMovieSceneSequence * SubSequence , const FGatherParameters & Params , UE : : MovieScene : : FSubSequencePath * RootPath , FMovieSceneSequenceHierarchy * InOutHierarchy )
{
UMovieScene * MovieScene = SubSequence ? SubSequence - > GetMovieScene ( ) : nullptr ;
if ( ! MovieScene )
{
return ;
}
check ( RootPath & & InOutHierarchy ) ;
for ( UMovieSceneTrack * Track : MovieScene - > GetMasterTracks ( ) )
{
if ( UMovieSceneSubTrack * SubTrack = Cast < UMovieSceneSubTrack > ( Track ) )
{
PopulateSubSequenceTree ( SubTrack , Params , RootPath , InOutHierarchy ) ;
}
}
for ( const FMovieSceneBinding & ObjectBinding : MovieScene - > GetBindings ( ) )
{
for ( UMovieSceneTrack * Track : ObjectBinding . GetTracks ( ) )
{
if ( UMovieSceneSubTrack * SubTrack = Cast < UMovieSceneSubTrack > ( Track ) )
{
PopulateSubSequenceTree ( SubTrack , Params , RootPath , InOutHierarchy ) ;
}
}
}
}
void UMovieSceneCompiledDataManager : : PopulateSubSequenceTree ( UMovieSceneSubTrack * SubTrack , const FGatherParameters & Params , UE : : MovieScene : : FSubSequencePath * RootPath , FMovieSceneSequenceHierarchy * InOutHierarchy )
{
2021-08-03 11:56:47 -04:00
using namespace UE : : MovieScene ;
2021-06-22 00:27:54 -04:00
check ( SubTrack & & RootPath ) ;
2020-08-11 01:36:57 -04:00
const bool bTrackMatchesFlags = ( Params . Flags = = ESectionEvaluationFlags : : None )
| | ( EnumHasAnyFlags ( Params . Flags , ESectionEvaluationFlags : : PreRoll ) & & SubTrack - > EvalOptions . bEvaluateInPreroll )
| | ( EnumHasAnyFlags ( Params . Flags , ESectionEvaluationFlags : : PostRoll ) & & SubTrack - > EvalOptions . bEvaluateInPostroll ) ;
2021-06-22 00:27:54 -04:00
if ( ! bTrackMatchesFlags )
2020-08-11 01:36:57 -04:00
{
2021-06-22 00:27:54 -04:00
return ;
}
if ( SubTrack - > IsEvalDisabled ( ) )
{
return ;
}
2021-08-03 11:56:47 -04:00
UMovieSceneSequence * OuterSequence = SubTrack - > GetTypedOuter < UMovieSceneSequence > ( ) ;
if ( ! OuterSequence )
{
return ;
}
2021-06-22 00:27:54 -04:00
for ( const FMovieSceneTrackEvaluationFieldEntry & Entry : SubTrack - > GetEvaluationField ( ) . Entries )
{
UMovieSceneSubSection * SubSection = Cast < UMovieSceneSubSection > ( Entry . Section ) ;
if ( ! SubSection | | SubSection - > GetSequence ( ) = = nullptr )
2020-08-11 01:36:57 -04:00
{
2021-06-22 00:27:54 -04:00
continue ;
}
2020-10-09 22:42:26 -04:00
2021-06-22 00:27:54 -04:00
if ( SubTrack - > IsRowEvalDisabled ( SubSection - > GetRowIndex ( ) ) )
{
continue ;
}
2021-04-29 19:32:06 -04:00
2021-06-22 00:27:54 -04:00
EMovieSceneServerClientMask NewMask = Params . NetworkMask & SubSection - > GetNetworkMask ( ) ;
if ( NewMask = = EMovieSceneServerClientMask : : None )
{
continue ;
}
2020-08-11 01:36:57 -04:00
2022-04-04 14:24:46 -04:00
const FMovieSceneTimeTransform SequenceToRootTransform = Params . RootToSequenceTransform . InverseFromWarp ( Params . RootToSequenceWarpCounter ) ;
TRange < FFrameNumber > EffectiveRange = Params . ClampRoot ( Entry . Range * SequenceToRootTransform ) ;
2021-06-22 00:27:54 -04:00
if ( EffectiveRange . IsEmpty ( ) )
{
continue ;
}
2021-04-29 19:32:06 -04:00
2021-06-22 00:27:54 -04:00
const FMovieSceneSequenceID SubSequenceID = RootPath - > ResolveChildSequenceID ( SubSection - > GetSequenceID ( ) ) ;
const FMovieSceneSubSequenceData * SubData = InOutHierarchy - > FindSubData ( SubSequenceID ) ;
2020-08-11 01:36:57 -04:00
2021-06-22 00:27:54 -04:00
checkf ( SubData , TEXT ( " Unable to locate sub-data for a sub section that appears in the track's evaluation field - this indicates that the section is being evaluated even though it is not active " ) ) ;
2020-08-11 01:36:57 -04:00
2021-08-03 11:56:47 -04:00
const FMovieSceneFrameRange & SubSectionRange = SubSection - > SectionRange ;
const FMovieSceneSectionParameters & SubSectionParams = SubSection - > Parameters ;
2020-08-11 01:36:57 -04:00
2021-08-03 11:56:47 -04:00
const ESectionEvaluationFlags SubEntryFlags = Entry . Flags | Params . Flags ;
if ( ! SubSectionParams . bCanLoop )
2021-06-22 00:27:54 -04:00
{
2021-10-20 11:49:19 -04:00
FGatherParameters SubParams = Params . CreateForSubData ( * SubData , SubSequenceID , Params . RootToSequenceWarpCounter ) ;
2020-10-29 13:38:15 -04:00
SubParams . SetClampRange ( EffectiveRange ) ;
2020-09-01 14:07:48 -04:00
SubParams . Flags | = Entry . Flags ;
2020-10-09 22:42:26 -04:00
SubParams . NetworkMask = NewMask ;
2021-10-20 11:49:19 -04:00
SubParams . RootToSequenceWarpCounter . AddNonWarpingLevel ( ) ;
2020-08-11 01:36:57 -04:00
2021-08-03 11:56:47 -04:00
// The section isn't looping, so we can just add it to the tree.
InOutHierarchy - > AddRange ( EffectiveRange , SubSequenceID , SubEntryFlags , SubParams . RootToSequenceWarpCounter ) ;
// Recurse into the sub sequence
RootPath - > PushGeneration ( SubSequenceID , SubData - > DeterministicSequenceID ) ;
{
2022-01-31 17:02:45 -05:00
PopulateSubSequenceTree ( SubData - > GetSequence ( ) , SubParams , RootPath , InOutHierarchy ) ;
}
RootPath - > PopGenerations ( 1 ) ;
2020-08-11 01:36:57 -04:00
}
2021-08-03 11:56:47 -04:00
else
{
// The section is looping so we need to add its contents to the tree as many times as it has loops.
2021-10-20 11:49:19 -04:00
const float RootToSubSequenceTimeScale = SubData - > RootToSequenceTransform . GetTimeScale ( ) ;
2021-08-03 11:56:47 -04:00
const float SubSequenceToRootTimeScale = ( RootToSubSequenceTimeScale ! = 0.f ) ? 1.0f / RootToSubSequenceTimeScale : 1.f ;
UMovieSceneSequence * SubSequence = SubData - > GetSequence ( ) ;
const TRange < FFrameNumber > SubSequencePlaybackRange = SubSequence - > GetMovieScene ( ) - > GetPlaybackRange ( ) ;
const FFrameNumber SubSequenceLength = DiscreteSize ( SubSequencePlaybackRange ) ;
const FFrameTime RootLoopLength = FMath : : Max (
FFrameTime ( SubSequenceLength - SubSectionParams . StartFrameOffset - SubSectionParams . EndFrameOffset ) * SubSequenceToRootTimeScale ,
FFrameTime ( 1 ) ) ;
const FFrameTime FirstRootLoopLength = FMath : : Max (
RootLoopLength - SubSectionParams . FirstLoopStartFrameOffset * SubSequenceToRootTimeScale ,
FFrameTime ( 1 ) ) ;
const TOptional < FFrameNumber > LocalSectionExclusiveEndTime = GetLoopingSubSectionEndTime ( OuterSequence , SubSection , Params ) ;
if ( LocalSectionExclusiveEndTime . IsSet ( ) & & ! SubSectionRange . GetLowerBound ( ) . IsOpen ( ) )
{
uint32 LoopCount = 0 ;
FFrameTime CurRootRangeStart = DiscreteInclusiveLower ( SubSectionRange . GetLowerBound ( ) ) * SequenceToRootTransform ;
TRange < FFrameNumber > CurRootRange ( CurRootRangeStart . FloorToFrame ( ) , ( CurRootRangeStart + FirstRootLoopLength ) . CeilToFrame ( ) ) ;
const FFrameNumber RootSectionEndTime = ( LocalSectionExclusiveEndTime . GetValue ( ) * SequenceToRootTransform ) . CeilToFrame ( ) ;
while ( CurRootRange . GetLowerBoundValue ( ) < RootSectionEndTime )
{
if ( CurRootRange . Overlaps ( Params . RootClampRange ) )
{
2022-04-04 14:24:46 -04:00
// Clamp the sub-sequence's range by the containing section's range and the current compilation range.
const TRange < FFrameNumber > ClampedCurRootRange = TRange < FFrameNumber > : : Intersection ( CurRootRange , EffectiveRange ) ;
2021-10-20 11:49:19 -04:00
FGatherParameters CurLoopParams = Params . CreateForSubData ( * SubData , SubSequenceID , Params . RootToSequenceWarpCounter ) ;
2022-04-04 14:24:46 -04:00
CurLoopParams . SetClampRange ( ClampedCurRootRange ) ;
2021-08-03 11:56:47 -04:00
CurLoopParams . Flags | = Entry . Flags ;
CurLoopParams . NetworkMask = NewMask ;
2021-10-20 11:49:19 -04:00
CurLoopParams . RootToSequenceWarpCounter . AddWarpingLevel ( LoopCount ) ;
2021-08-03 11:56:47 -04:00
// Add the section to the tree for the current loop.
InOutHierarchy - > AddRange ( ClampedCurRootRange , SubSequenceID , SubEntryFlags , CurLoopParams . RootToSequenceWarpCounter ) ;
// Recurse into this loop's sub sequence.
RootPath - > PushGeneration ( SubSequenceID , SubData - > DeterministicSequenceID ) ;
{
PopulateSubSequenceTree ( SubData - > GetSequence ( ) , CurLoopParams , RootPath , InOutHierarchy ) ;
}
RootPath - > PopGenerations ( 1 ) ;
}
2021-09-06 12:23:53 -04:00
2022-04-04 14:24:46 -04:00
// Move on to the next loop.
2021-08-03 11:56:47 -04:00
CurRootRangeStart = CurRootRange . GetUpperBoundValue ( ) ;
CurRootRange = TRange < FFrameNumber > ( CurRootRangeStart . FloorToFrame ( ) , ( CurRootRangeStart + RootLoopLength ) . FloorToFrame ( ) ) ;
if ( CurRootRange . GetUpperBoundValue ( ) > RootSectionEndTime )
CurRootRange . SetUpperBoundValue ( RootSectionEndTime ) ;
+ + LoopCount ;
}
}
2022-04-04 14:24:46 -04:00
// Faced with the cosmic horror of infinites, we choose to shield our sanity and skip this sub-section.
2021-08-03 11:56:47 -04:00
// (it either has an open-ended start time, which means we needed to loop since before time began, which means
// we don't know where loops are in the present... or it means the section and root sequence have open-ended
// end times, which means we would need to compile loops forever)
}
}
}
TOptional < FFrameNumber > UMovieSceneCompiledDataManager : : GetLoopingSubSectionEndTime ( const UMovieSceneSequence * InRootSequence , const UMovieSceneSubSection * SubSection , const FGatherParameters & Params )
{
using namespace UE : : MovieScene ;
TRangeBound < FFrameNumber > SectionRangeEnd = SubSection - > SectionRange . GetUpperBound ( ) ;
if ( ! SectionRangeEnd . IsOpen ( ) )
{
return DiscreteExclusiveUpper ( SectionRangeEnd ) ;
}
// This section is open ended... we don't want to compile its sub-sequence in an infinite loop so we'll bound
// that by the playback end of is own sequence.
if ( const UMovieScene * MovieScene = InRootSequence - > GetMovieScene ( ) )
{
const TRange < FFrameNumber > PlaybackRange = MovieScene - > GetPlaybackRange ( ) ;
if ( ! PlaybackRange . GetUpperBound ( ) . IsOpen ( ) )
{
return DiscreteExclusiveUpper ( PlaybackRange . GetUpperBound ( ) ) ;
}
}
// Sadly, the root sequence is also open ended, so we effectively would need to loop the sub-sequence
// indefinitely... we don't support that yet.
return TOptional < FFrameNumber > ( ) ;
2020-08-11 01:36:57 -04:00
}