Files
UnrealEngine/Engine/Source/Runtime/MovieScene/Public/Evaluation/MovieScenePropertyTemplate.h
2025-05-18 13:04:45 +08:00

333 lines
14 KiB
C++

// 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<FTrackInstancePropertyBindings> PropertyBindings;
/** Cached identifier of the property we're editing */
FMovieSceneAnimTypeID PropertyID;
};
template<typename PropertyValueType, typename IntermediateType = PropertyValueType>
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 PropertyValueType, typename IntermediateType = PropertyValueType>
typename TTemporarySetterType<PropertyValueType, IntermediateType>::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 PropertyValueType, typename IntermediateType = PropertyValueType>
typename TTemporarySetterType<PropertyValueType, IntermediateType>::Type
ConvertFromIntermediateType(const IntermediateType& InIntermediateType, const FMovieSceneEvaluationOperand& Operand, FPersistentEvaluationData& PersistentData, IMovieScenePlayer& Player)
{
return InIntermediateType;
}
template<typename PropertyValueType, typename IntermediateType = PropertyValueType>
IntermediateType ConvertToIntermediateType(PropertyValueType&& NewValue)
{
return Forward<PropertyValueType>(NewValue);
}
template<typename T>
bool IsValueValid(const T& InValue)
{
return true;
}
/** Cached preanimated state for a given property */
template<typename PropertyValueType, typename IntermediateType = PropertyValueType>
struct TCachedState : IMovieScenePreAnimatedToken
{
TCachedState(typename TCallTraits<IntermediateType>::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<PropertyValueType, IntermediateType>(Value, *Player);
if (IsValueValid(NewValue))
{
Bindings.CallFunction<PropertyValueType>(Object, NewValue);
}
}
IntermediateType Value;
FTrackInstancePropertyBindings Bindings;
};
template<typename PropertyValueType, typename IntermediateType = PropertyValueType>
static IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject& Object, FTrackInstancePropertyBindings& PropertyBindings)
{
return TCachedState<PropertyValueType, IntermediateType>(PropertyTemplate::ConvertToIntermediateType(PropertyBindings.GetCurrentValue<PropertyValueType>(Object)), PropertyBindings);
}
template<typename PropertyValueType>
struct FTokenProducer : IMovieScenePreAnimatedTokenProducer
{
FTokenProducer(FTrackInstancePropertyBindings& InPropertyBindings) : PropertyBindings(InPropertyBindings) {}
virtual IMovieScenePreAnimatedTokenPtr CacheExistingState(UObject& Object) const
{
return PropertyTemplate::CacheExistingState<PropertyValueType>(Object, PropertyBindings);
}
FTrackInstancePropertyBindings& PropertyBindings;
};
}
/** Execution token that simple stores a value, and sets it when executed */
template<typename PropertyValueType, typename IntermediateType = PropertyValueType>
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<FSectionData>();
FTrackInstancePropertyBindings* PropertyBindings = PropertyTrackData.PropertyBindings.Get();
auto NewValue = PropertyTemplate::ConvertFromIntermediateType<PropertyValueType, IntermediateType>(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<PropertyValueType>(*PropertyBindings));
PropertyBindings->CallFunction<PropertyValueType>(*ObjectPtr, NewValue);
}
}
}
IntermediateType Value;
};
/** Blending actuator type that knows how to apply values of type PropertyType */
template<typename PropertyType>
struct TPropertyActuator : TMovieSceneBlendingActuator<PropertyType>
{
PropertyTemplate::FSectionData PropertyData;
TPropertyActuator(const PropertyTemplate::FSectionData& InPropertyData)
: TMovieSceneBlendingActuator<PropertyType>(FMovieSceneBlendingActuatorID(InPropertyData.PropertyID))
, PropertyData(InPropertyData)
{}
virtual PropertyType RetrieveCurrentValue(UObject* InObject, IMovieScenePlayer* Player) const
{
return PropertyData.PropertyBindings->GetCurrentValue<PropertyType>(*InObject);
}
virtual void Actuate(UObject* InObject, typename TCallTraits<PropertyType>::ParamType InFinalValue, const TBlendableTokenStack<PropertyType>& 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<PropertyType>(*PropertyData.PropertyBindings));
PropertyData.PropertyBindings->CallFunction<PropertyType>(*InObject, InFinalValue);
}
}
//This will be specialized at end of this file for floats, transforms,eulertransforms and vectors
virtual void Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<PropertyType>::ParamType InValue, const TBlendableTokenStack<PropertyType>& 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<PropertyTemplate::FSectionData>(PersistentData);
}
template<typename T>
void SetupTrack(FPersistentEvaluationData& PersistentData) const
{
PersistentData.AddSectionData<T>().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<typename PropertyType> FMovieSceneBlendingActuatorID EnsureActuator(FMovieSceneBlendingAccumulator& Accumulator) const
{
// Actuator type ID for this property
FMovieSceneAnimTypeID UniquePropertyID = GetPropertyTypeID();
FMovieSceneBlendingActuatorID ActuatorTypeID = FMovieSceneBlendingActuatorID(UniquePropertyID);
if (!Accumulator.FindActuator<PropertyType>(ActuatorTypeID))
{
PropertyTemplate::FSectionData SectionData;
SectionData.Initialize(PropertyData.PropertyName, PropertyData.PropertyPath);
Accumulator.DefineActuator(ActuatorTypeID, MakeShared<TPropertyActuator<PropertyType>>(SectionData));
}
return ActuatorTypeID;
}
UPROPERTY()
FMovieScenePropertySectionData PropertyData;
};
//Specializations
template<>
inline void TPropertyActuator<float>::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<float>::ParamType InValue, const TBlendableTokenStack<float>& OriginalStack, const FMovieSceneContext& Context) const
{
float Value = InValue;
InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetFloatInterrogationKey());
};
template<>
inline void TPropertyActuator<int32>::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<int32>::ParamType InValue, const TBlendableTokenStack<int32>& OriginalStack, const FMovieSceneContext& Context) const
{
int32 Value = InValue;
InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetInt32InterrogationKey());
};
template<>
inline void TPropertyActuator<FVector2D>::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<FVector2D>::ParamType InValue, const TBlendableTokenStack<FVector2D>& OriginalStack, const FMovieSceneContext& Context) const
{
FVector2D Value = InValue;
InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetVector2DInterrogationKey());
};
template<>
inline void TPropertyActuator<FEulerTransform>::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<FEulerTransform>::ParamType InValue, const TBlendableTokenStack<FEulerTransform>& 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<FTransform>::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<FTransform>::ParamType InValue, const TBlendableTokenStack<FTransform>& 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<FVector4>::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<FVector4>::ParamType InValue, const TBlendableTokenStack<FVector4>& OriginalStack, const FMovieSceneContext& Context) const
{
FVector4 Value = InValue;
InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetVector4InterrogationKey());
};
template<>
inline void TPropertyActuator<FVector>::Actuate(FMovieSceneInterrogationData& InterrogationData, typename TCallTraits<FVector>::ParamType InValue, const TBlendableTokenStack<FVector>& OriginalStack, const FMovieSceneContext& Context) const
{
FVector Value = InValue;
InterrogationData.Add(Value, FMovieScenePropertySectionTemplate::GetVectorInterrogationKey());
};