// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/Array.h" #include "Containers/ArrayView.h" #include "CoreTypes.h" #include "EntitySystem/IMovieScenePropertyComponentHandler.h" #include "EntitySystem/MovieSceneEntityIDs.h" #include "EntitySystem/MovieSceneEntitySystemTypes.h" #include "EntitySystem/MovieScenePropertySystemTypes.h" #include "EntitySystem/MovieSceneSystemTaskDependencies.h" #include "Math/NumericLimits.h" #include "Misc/AssertionMacros.h" #include "Misc/GeneratedTypeName.h" #include "Misc/InlineValue.h" #include "Misc/Optional.h" #include "Misc/TVariant.h" #include "Stats/Stats.h" #include "Templates/SharedPointer.h" #include "Templates/UnrealTemplate.h" #include "Templates/UnrealTypeTraits.h" #include "UObject/NameTypes.h" #include class FTrackInstancePropertyBindings; class UClass; class UMovieSceneBlenderSystem; class UMovieSceneEntitySystemLinker; class UObject; struct FMovieScenePropertyBinding; namespace UE { namespace MovieScene { struct FFloatDecompositionParams; struct FPropertyCompositeDefinition; struct FPropertyDefinition; DECLARE_CYCLE_STAT(TEXT("Apply properties"), MovieSceneEval_ApplyProperties, STATGROUP_MovieSceneECS); /** * Stats pertaining to a given type of property including how many properties exist in the linker, * and how many of those are partially animated */ struct FPropertyStats { /** The total number of properties currently animated, including partial properties */ int32 NumProperties = 0; /** The number of properties partially animated */ int32 NumPartialProperties = 0; }; /** * Structure defining a type of property that can be animated by sequencer */ struct FPropertyDefinition { FPropertyDefinition() = default; FPropertyDefinition( uint16 InVariableSizeCompositeOffset, FComponentTypeID InPropertyType, FComponentTypeID InInitialValueType) : CustomPropertyRegistration(nullptr) , DoubleCompositeMask(0) , VariableSizeCompositeOffset(InVariableSizeCompositeOffset) , CompositeSize(0) , PropertyType(InPropertyType) , InitialValueType(InInitialValueType) , BlenderSystemClass(nullptr) { } FPropertyDefinition(FPropertyDefinition&&) = default; FPropertyDefinition(const FPropertyDefinition&) = delete; /** * Return a typed component ID for the meta data at the specified index. * Care should obviously be taken here to ensure that the meta data type being used * matches the TPropertyComponents traits that constructed this property definition. */ template TComponentTypeID GetMetaDataComponent(int32 Index) const { return MetaDataTypes[Index].ReinterpretCast(); } /** * Sets up an initial value processor for this property type */ MOVIESCENE_API void SetupInitialValueProcessor() const; /** Pointer to a custom getter/setter registry for short circuiting the UObject VM. Must outlive this definitions lifetime (usually these are static or singletons) */ ICustomPropertyRegistration* CustomPropertyRegistration = nullptr; /** Stat ID for this property type */ TStatId StatID; /** A mask of which composite indices pertain to doubles */ uint32 DoubleCompositeMask = 0; /** The number of channels that this property comprises */ uint16 VariableSizeCompositeOffset = INDEX_NONE; /** The number of channels that this property comprises */ uint16 CompositeSize = 0; /** The component type or tag of the property itself */ FComponentTypeID PropertyType; /** The component type for this property's inital value (used for relative and/or additive blending) */ FComponentTypeID InitialValueType; /** MetaData types */ TArrayView MetaDataTypes; /** The blender system to use by default (if specified here) to blend composites of this property (it can be overriden per-entity with a blender system component) */ UClass* BlenderSystemClass; /** Implementation of type specific property actions such as applying properties from entities or recomposing values */ TInlineValue Handler; }; /** A generic definition of a composite channel that contributes to a property */ struct FPropertyCompositeDefinition { /** The type of component that contains the value for this channel (ie a TComponentTypeID) */ FComponentTypeID ComponentTypeID; /** * The offset of the member variable within the operational type of the property in bytes. * Ie for FIntermediate3DTransform::T_Z, the composite offset is 8 Bytes. */ uint16 CompositeOffset; }; /** Type aliases for a property that resolved to either a fast pointer offset (type index 0), or a custom property index (specific to the path of the property - type index 1) */ using FResolvedFastProperty = TVariant; /** Type aliases for a property that resolved to either a fast pointer offset (type index 0), or a custom property index (specific to the path of the property - type index 1) with a fallback to a slow property binding (type index 2) */ using FResolvedProperty = TVariant>; template struct TCompositePropertyDefinitionBuilder; template struct TPropertyDefinitionBuilder; /** * Central registry of all property types animatable by sequencer. * Once registered, properties cannot be de-registered. This vastly simplifies the lifetime and ID management of the class */ class FPropertyRegistry { public: FPropertyRegistry() = default; FPropertyRegistry(FPropertyRegistry&&) = delete; FPropertyRegistry(const FPropertyRegistry&) = delete; /** * Resolve a property to either a fast ptr offset, or a custom property accessor based on the specified array * * @param Object The object to resolve the property for * @param PropertyBinding The property binding to resolve * @param CustomAccessors A view to an array of custom accessors (as retrieved from ICustomPropertyRegistration::GetAccessors) * @return An optional variant specifying the resolved property if it resolved successfully */ static MOVIESCENE_API TOptional< FResolvedFastProperty > ResolveFastProperty(UObject* Object, const FMovieScenePropertyBinding& PropertyBinding, FCustomAccessorView CustomAccessors); /** * Resolve a property to either a fast ptr offset, or a custom property accessor based on the specified array falling back to a slow instance binding if possible * * @param Object The object to resolve the property for * @param PropertyBinding The property binding to resolve * @param CustomAccessors A view to an array of custom accessors (as retrieved from ICustomPropertyRegistration::GetAccessors) * @return An optional variant specifying the resolved property if it resolved successfully */ static MOVIESCENE_API TOptional< FResolvedProperty > ResolveProperty(UObject* Object, const FMovieScenePropertyBinding& PropertyBinding, FCustomAccessorView CustomAccessors); /** * Define a new animatable composite property type from its components. * * @param InOutPropertyComponents The property's components that are used for animating this property. TPropertyComponents::CompositeID is written to. * @return A builder class that should be used to define the composites that contribute to this property */ template TCompositePropertyDefinitionBuilder DefineCompositeProperty(TPropertyComponents& InOutPropertyComponents, const TCHAR* InStatName) { DefinePropertyImpl(InOutPropertyComponents, InStatName); FPropertyDefinition* Property = &Properties[InOutPropertyComponents.CompositeID.AsIndex()]; return TCompositePropertyDefinitionBuilder(Property, this); } /** * Define a new animatable property type from its components. * * @param InOutPropertyComponents The property's components that are used for animating this property. TPropertyComponents::CompositeID is written to. * @return A builder class that should be used to define the composites that contribute to this property */ template TPropertyDefinitionBuilder DefineProperty(TPropertyComponents& InOutPropertyComponents, const TCHAR* InStatName) { DefinePropertyImpl(InOutPropertyComponents, InStatName); FPropertyDefinition* Property = &Properties[InOutPropertyComponents.CompositeID.AsIndex()]; return TPropertyDefinitionBuilder(Property, this); } /** * Retrieve a property definition from its ID */ const FPropertyDefinition& GetDefinition(FCompositePropertyTypeID PropertyID) const { return Properties[PropertyID.TypeIndex]; } /** * Access all the properties currently registered */ TArrayView GetProperties() const { return Properties; } /** * Retrieve a generic representation of all the composites that contribute to a given property */ TArrayView GetComposites(const FPropertyDefinition& Property) const { const int32 CompositeOffset = Property.VariableSizeCompositeOffset; const int32 NumComposites = Property.CompositeSize; return MakeArrayView(CompositeDefinitions.GetData() + CompositeOffset, NumComposites); } /** * Retrieve a generic representation of all the composites that contribute to a given property */ TArrayView GetComposites(FCompositePropertyTypeID PropertyID) const { return GetComposites(GetDefinition(PropertyID)); } private: template friend struct TPropertyDefinitionBuilder; template friend struct TCompositePropertyDefinitionBuilder; /** * Define a new animatable property type from its components. * * @param InOutPropertyComponents The property's components that are used for animating this property. TPropertyComponents::CompositeID is written to. * @return A builder class that should be used to define the composites that contribute to this property */ template void DefinePropertyImpl(TPropertyComponents& InOutPropertyComponents, const TCHAR* InStatName) { using StorageType = typename PropertyTraits::StorageType; const int32 CompositeOffsetInt32 = CompositeDefinitions.Num(); checkf(CompositeOffsetInt32 <= MAX_uint16, TEXT("Maximum number of composite definitions reached")); const uint16 CompositeOffset = static_cast(CompositeOffsetInt32); TStatId StatID; #if STATS || ENABLE_STATNAMEDEVENTS #if STATS // Use FDynamicStats to create the stat in the right stat group if possible StatID = FDynamicStats::CreateStatId( FName(InStatName) ); #else // Otherwise just make a named stat const auto& ConversionData = StringCast(InStatName); const int32 NumStorageChars = (ConversionData.Length() + 1); //length doesn't include null terminator // We leak this string PROFILER_CHAR* StoragePtr = new PROFILER_CHAR[NumStorageChars]; FMemory::Memcpy(StoragePtr, ConversionData.Get(), NumStorageChars * sizeof(PROFILER_CHAR)); StatID = TStatId(StoragePtr); #endif #endif FPropertyDefinition NewDefinition( CompositeOffset, InOutPropertyComponents.PropertyTag, InOutPropertyComponents.InitialValue); NewDefinition.StatID = StatID; NewDefinition.MetaDataTypes = InOutPropertyComponents.MetaDataComponents.GetTypes(); checkf(!NewDefinition.MetaDataTypes.Contains(FComponentTypeID()), TEXT("Property meta-data component is not defined")); const int32 NewPropertyIndex = Properties.Add(MoveTemp(NewDefinition)); checkf(!InOutPropertyComponents.CompositeID, TEXT("Property already defined")); static_cast(InOutPropertyComponents.CompositeID) = FCompositePropertyTypeID::FromIndex(NewPropertyIndex); } TArray Properties; TArray CompositeDefinitions; }; } // namespace MovieScene } // namespace UE #if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_5 #include "Templates/IsTriviallyDestructible.h" #endif