// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Stats/Stats.h" #include "UObject/ObjectMacros.h" #include "IMovieScenePlayer.h" #include "MovieSceneFwd.h" #include "MovieSceneCommonHelpers.h" #include "Evaluation/MovieSceneAnimTypeID.h" #include "MovieSceneExecutionToken.h" #include "Evaluation/PersistentEvaluationData.h" #include "Evaluation/MovieSceneEvalTemplate.h" #include "Logging/MessageLog.h" #include "Misc/UObjectToken.h" #include "Evaluation/MovieSceneEvaluationTemplateInstance.h" #include "MovieSceneSequence.h" #include "Evaluation/Blending/MovieSceneBlendingActuator.h" #include "Evaluation/Blending/MovieSceneMultiChannelBlending.h" #include "Compilation/MovieSceneTemplateInterrogation.h" #include "TransformData.h" #include "MovieScenePropertyTemplate.generated.h" class UMovieScenePropertyTrack; DECLARE_CYCLE_STAT(TEXT("Property Track Token Execute"), MovieSceneEval_PropertyTrack_TokenExecute, STATGROUP_MovieSceneEval); namespace PropertyTemplate { /** Persistent section data for a property section */ struct FSectionData : IPersistentEvaluationData { MOVIESCENE_API FSectionData(); /** Initialize track data with the specified property name, path, optional setter function, and optional notify function */ MOVIESCENE_API void Initialize(FName InPropertyName, FString InPropertyPath); /** Property bindings used to get and set the property */ TSharedPtr PropertyBindings; /** Cached identifier of the property we're editing */ FMovieSceneAnimTypeID PropertyID; }; template struct TTemporarySetterType { typedef PropertyValueType Type; }; /** Convert from an intermediate type to the type used for setting a property value. Called when resetting pre animated state */ template typename TTemporarySetterType::Type ConvertFromIntermediateType(const IntermediateType& InIntermediateType, IMovieScenePlayer& Player) { return InIntermediateType; } /** Convert from an intermediate type to the type used for setting a property value. Called during token execution. */ template typename TTemporarySetterType::Type ConvertFromIntermediateType(const IntermediateType& InIntermediateType, const FMovieSceneEvaluationOperand& Operand, FPersistentEvaluationData& PersistentData, IMovieScenePlayer& Player) { return InIntermediateType; } template IntermediateType ConvertToIntermediateType(PropertyValueType&& NewValue) { return Forward(NewValue); } template bool IsValueValid(const T& InValue) { return true; } /** Cached preanimated state for a given property */ template struct TCachedState : IMovieScenePreAnimatedToken { TCachedState(typename TCallTraits::ParamType InValue, const FTrackInstancePropertyBindings& InBindings) : Value(MoveTempIfPossible(InValue)) , Bindings(InBindings) { } virtual void RestoreState(UObject& Object, const UE::MovieScene::FRestoreStateParams& Params) override { IMovieScenePlayer* Player = Params.GetTerminalPlayer(); if (!ensure(Player)) { return; } auto NewValue = PropertyTemplate::ConvertFromIntermediateType(Value, *Player); if (IsValueValid(NewValue)) { Bindings.CallFunction(Object, NewValue); } } IntermediateType Value; FTrackInstancePropertyBindings Bindings; }; template static IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject& Object, FTrackInstancePropertyBindings& PropertyBindings) { return TCachedState(PropertyTemplate::ConvertToIntermediateType(PropertyBindings.GetCurrentValue(Object)), PropertyBindings); } template struct FTokenProducer : IMovieScenePreAnimatedTokenProducer { FTokenProducer(FTrackInstancePropertyBindings& InPropertyBindings) : PropertyBindings(InPropertyBindings) {} virtual IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject& Object) const { return PropertyTemplate::CacheExistingState(Object, PropertyBindings); } FTrackInstancePropertyBindings& PropertyBindings; }; } /** Execution token that simple stores a value, and sets it when executed */ template struct TPropertyTrackExecutionToken : IMovieSceneExecutionToken { TPropertyTrackExecutionToken(IntermediateType InValue) : Value(MoveTemp(InValue)) {} /** Execute this token, operating on all objects referenced by 'Operand' */ virtual void Execute(const FMovieSceneContext& Context, const FMovieSceneEvaluationOperand& Operand, FPersistentEvaluationData& PersistentData, IMovieScenePlayer& Player) override { using namespace PropertyTemplate; MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PropertyTrack_TokenExecute) FSectionData& PropertyTrackData = PersistentData.GetSectionData(); FTrackInstancePropertyBindings* PropertyBindings = PropertyTrackData.PropertyBindings.Get(); auto NewValue = PropertyTemplate::ConvertFromIntermediateType(Value, Operand, PersistentData, Player); if (!IsValueValid(NewValue)) { return; } for (TWeakObjectPtr<> WeakObject : Player.FindBoundObjects(Operand)) { if (UObject* ObjectPtr = WeakObject.Get()) { Player.SavePreAnimatedState(*ObjectPtr, PropertyTrackData.PropertyID, FTokenProducer(*PropertyBindings)); PropertyBindings->CallFunction(*ObjectPtr, NewValue); } } } IntermediateType Value; }; /** Blending actuator type that knows how to apply values of type PropertyType */ template struct TPropertyActuator : TMovieSceneBlendingActuator { PropertyTemplate::FSectionData PropertyData; TPropertyActuator(const PropertyTemplate::FSectionData& InPropertyData) : TMovieSceneBlendingActuator(FMovieSceneBlendingActuatorID(InPropertyData.PropertyID)) , PropertyData(InPropertyData) {} virtual PropertyType RetrieveCurrentValue(UObject* InObject, IMovieScenePlayer* Player) const { return PropertyData.PropertyBindings->GetCurrentValue(*InObject); } virtual void Actuate(UObject* InObject, typename TCallTraits::ParamType InFinalValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context, FPersistentEvaluationData& PersistentData, IMovieScenePlayer& Player) override { ensureMsgf(InObject, TEXT("Attempting to evaluate a Property track '%s' with a null object."), *PropertyData.PropertyBindings->GetPropertyName().ToString()); if (InObject) { OriginalStack.SavePreAnimatedState(Player, *InObject, PropertyData.PropertyID, PropertyTemplate::FTokenProducer(*PropertyData.PropertyBindings)); PropertyData.PropertyBindings->CallFunction(*InObject, InFinalValue); } } //This will be specialized at end of this file for floats, transforms,eulertransforms and vectors virtual void Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const override { } }; USTRUCT() struct FMovieScenePropertySectionData { GENERATED_BODY() UPROPERTY() FName PropertyName; UPROPERTY() FString PropertyPath; FMovieScenePropertySectionData() {} FMovieScenePropertySectionData(FName InPropertyName, FString InPropertyPath) : PropertyName(InPropertyName), PropertyPath(MoveTemp(InPropertyPath)) {} /** Helper function to create FSectionData for a property section */ void SetupTrack(FPersistentEvaluationData& PersistentData) const { SetupTrack(PersistentData); } template void SetupTrack(FPersistentEvaluationData& PersistentData) const { PersistentData.AddSectionData().Initialize(PropertyName, PropertyPath); } }; USTRUCT() struct FMovieScenePropertySectionTemplate : public FMovieSceneEvalTemplate { GENERATED_BODY() MOVIESCENE_API FMovieScenePropertySectionTemplate(); MOVIESCENE_API FMovieScenePropertySectionTemplate(FName PropertyName, const FString& InPropertyPath); MOVIESCENE_API FMovieScenePropertySectionTemplate(const FMovieScenePropertySectionTemplate&); MOVIESCENE_API ~FMovieScenePropertySectionTemplate(); public: //use thse keys for setting and iterating the correct types. MOVIESCENE_API const static FMovieSceneInterrogationKey GetFloatInterrogationKey(); MOVIESCENE_API const static FMovieSceneInterrogationKey GetInt32InterrogationKey(); MOVIESCENE_API const static FMovieSceneInterrogationKey GetVector4InterrogationKey(); MOVIESCENE_API const static FMovieSceneInterrogationKey GetVectorInterrogationKey(); MOVIESCENE_API const static FMovieSceneInterrogationKey GetVector2DInterrogationKey(); MOVIESCENE_API const static FMovieSceneInterrogationKey GetColorInterrogationKey(); protected: virtual UScriptStruct& GetScriptStructImpl() const override { return *StaticStruct(); } /** Setup is only called if derived classes enable RequiresSetupFlag */ MOVIESCENE_API virtual void Setup(FPersistentEvaluationData& PersistentData, IMovieScenePlayer& Player) const override; /** Access an animation type identifier that uniquely represents the property this section animates */ MOVIESCENE_API FMovieSceneAnimTypeID GetPropertyTypeID() const; /** Ensure that an actutor for this property type exists */ template FMovieSceneBlendingActuatorID EnsureActuator(FMovieSceneBlendingAccumulator& Accumulator) const { // Actuator type ID for this property FMovieSceneAnimTypeID UniquePropertyID = GetPropertyTypeID(); FMovieSceneBlendingActuatorID ActuatorTypeID = FMovieSceneBlendingActuatorID(UniquePropertyID); if (!Accumulator.FindActuator(ActuatorTypeID)) { PropertyTemplate::FSectionData SectionData; SectionData.Initialize(PropertyData.PropertyName, PropertyData.PropertyPath); Accumulator.DefineActuator(ActuatorTypeID, MakeShared>(SectionData)); } return ActuatorTypeID; } UPROPERTY() FMovieScenePropertySectionData PropertyData; }; //Specializations template<> inline void TPropertyActuator::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const { float Value = InValue; InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetFloatInterrogationKey()); }; template<> inline void TPropertyActuator::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const { int32 Value = InValue; InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetInt32InterrogationKey()); }; template<> inline void TPropertyActuator::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const { FVector2D Value = InValue; InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetVector2DInterrogationKey()); }; template<> inline void TPropertyActuator::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const { FTransformData Value; Value.Translation = InValue.Location; Value.Rotation = InValue.Rotation; Value.Scale = InValue.Scale; InterrogationData.Add(Value, FMovieSceneInterrogationKey::GetTransformInterrogationKey()); }; template<> inline void TPropertyActuator::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const { FTransformData Value; Value.Translation = InValue.GetTranslation(); Value.Rotation = InValue.GetRotation().Rotator(); Value.Scale = InValue.GetScale3D(); InterrogationData.Add(Value, FMovieSceneInterrogationKey::GetTransformInterrogationKey()); }; template<> inline void TPropertyActuator::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const { FVector4 Value = InValue; InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetVector4InterrogationKey()); }; template<> inline void TPropertyActuator::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits::ParamType InValue, const TBlendableTokenStack& OriginalStack, const FMovieSceneContext& Context) const { FVector Value = InValue; InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetVectorInterrogationKey()); };