// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreTypes.h" #include "Evaluation/MovieSceneEvaluationKey.h" #include "UObject/ObjectKey.h" #include "UObject/Object.h" #include "EntitySystem/MovieSceneEntityIDs.h" #include "EntitySystem/MovieScenePropertySystemTypes.h" #include "EntitySystem/MovieScenePropertyRegistry.h" #include "EntitySystem/BuiltInComponentTypes.h" #include "EntitySystem/MovieSceneEntitySystemTask.h" #include "EntitySystem/MovieScenePropertyBinding.h" #include "Evaluation/PreAnimatedState/MovieSceneRestoreStateParams.h" #include "Evaluation/PreAnimatedState/MovieScenePreAnimatedStorageID.inl" #include "Evaluation/PreAnimatedState/MovieScenePreAnimatedObjectStorage.h" #include "Evaluation/PreAnimatedState/MovieScenePreAnimatedCaptureSources.h" namespace UE { namespace MovieScene { /** * Pre-animated property value, including cached meta-data */ template struct TPreAnimatedPropertyValue { TPreAnimatedPropertyValue() {} TPreAnimatedPropertyValue(typename TCallTraits::ParamType... InMetaData) : MetaData(InMetaData...) {} StorageType Data; TVariant> Binding; TTuple MetaData; }; /** * Pre-animated property value, specialized for no meta-data */ template struct TPreAnimatedPropertyValue { StorageType Data; TVariant> Binding; }; /** * Pre-Animated traits class that wraps a user-provided property trait that defines property accessors */ template struct TPreAnimatedPropertyTraits; template struct TPreAnimatedPropertyTraits, MetaDataTypes...> : FBoundObjectPreAnimatedStateTraits { using KeyType = TTuple; using StorageType = TPreAnimatedPropertyValue; static void RestorePreAnimatedValue(const KeyType& InKey, StorageType& CachedValue, const FRestoreStateParams& Params) { UObject* Object = InKey.Get<0>().ResolveObjectPtr(); if (!Object) { return; } if (const uint16* FastOffset = CachedValue.Binding.template TryGet()) { PropertyTraits::SetObjectPropertyValue(Object, CachedValue.MetaData.template Get()..., *FastOffset, CachedValue.Data); } else if (const TSharedPtr* Bindings = CachedValue.Binding.template TryGet>()) { PropertyTraits::SetObjectPropertyValue(Object, CachedValue.MetaData.template Get()..., Bindings->Get(), CachedValue.Data); } else if (const FCustomPropertyAccessor* CustomAccessor = CachedValue.Binding.template Get()) { PropertyTraits::SetObjectPropertyValue(Object, CachedValue.MetaData.template Get()..., *CustomAccessor, CachedValue.Data); } } }; /** * Pre-Animated traits class that wraps a user-provided property trait that defines property accessors with no meta-data */ template struct TPreAnimatedPropertyTraits, TIntegerSequence> : FBoundObjectPreAnimatedStateTraits { using KeyType = TTuple; using StorageType = TPreAnimatedPropertyValue; static void RestorePreAnimatedValue(const KeyType& InKey, StorageType& CachedValue, const FRestoreStateParams& Params) { UObject* Object = InKey.Get<0>().ResolveObjectPtr(); if (!Object) { return; } if (const uint16* FastOffset = CachedValue.Binding.template TryGet()) { PropertyTraits::SetObjectPropertyValue(Object, *FastOffset, CachedValue.Data); } else if (const TSharedPtr* Bindings = CachedValue.Binding.template TryGet>()) { PropertyTraits::SetObjectPropertyValue(Object, Bindings->Get(), CachedValue.Data); } else if (const FCustomPropertyAccessor* CustomAccessor = CachedValue.Binding.template Get()) { PropertyTraits::SetObjectPropertyValue(Object, *CustomAccessor, CachedValue.Data); } } }; template struct TPreAnimatedPropertyStorageImpl; template struct TPreAnimatedPropertyStorageImpl, TIntegerSequence> : TPreAnimatedStateStorage, MetaDataTypes...>> , IPreAnimatedObjectPropertyStorage { using StorageTraits = TPreAnimatedPropertyTraits, MetaDataTypes...>; using StorageType = typename StorageTraits::StorageType; static_assert(StorageTraits::SupportsGrouping, "Pre-animated storage for properties should support grouping by object"); TPreAnimatedPropertyStorageImpl(const FPropertyDefinition& InPropertyDefinition) : MetaDataComponents(InPropertyDefinition.MetaDataTypes) { check(MetaDataComponents.Num() == sizeof...(MetaDataIndices)); if (InPropertyDefinition.CustomPropertyRegistration) { CustomAccessors = InPropertyDefinition.CustomPropertyRegistration->GetAccessors(); } } IPreAnimatedObjectPropertyStorage* AsPropertyStorage() override { return this; } void BeginTrackingEntities(const FPreAnimatedTrackerParams& Params, TRead EntityIDs, TRead InstanceHandles, TRead BoundObjects, TRead PropertyBindings) override { const int32 Num = Params.Num; const bool bWantsRestore = Params.bWantsRestoreState; if (!this->ParentExtension->IsCapturingGlobalState() && !bWantsRestore) { return; } FPreAnimatedEntityCaptureSource* EntityMetaData = this->ParentExtension->GetOrCreateEntityMetaData(); for (int32 Index = 0; Index < Num; ++Index) { UObject* BoundObject = BoundObjects[Index]; if (!BoundObject) { continue; } FPreAnimatedStateEntry Entry = this->MakeEntry(BoundObject, PropertyBindings[Index].PropertyPath); EntityMetaData->BeginTrackingEntity(Entry, EntityIDs[Index], InstanceHandles[Index], bWantsRestore); } } void CachePreAnimatedValues(const FCachePreAnimatedValueParams& Params, FEntityAllocationProxy Item, TRead BoundObjects, TRead PropertyBindings, FThreeWayAccessor Properties) override { const FEntityAllocation* Allocation = Item.GetAllocation(); TTuple< TComponentReader... > MetaData( Allocation->ReadComponents(MetaDataComponents[MetaDataIndices].template ReinterpretCast())... ); const uint16* Fast = Properties.Get<1>(); const FCustomPropertyIndex* Custom = Properties.Get<0>(); const TSharedPtr* Slow = Properties.Get<2>(); const int32 Num = Allocation->Num(); for (int32 Index = 0; Index < Num; ++Index) { UObject* BoundObject = BoundObjects[Index]; if (!BoundObject) { continue; } if (!this->ShouldTrackCaptureSource(EPreAnimatedCaptureSourceTracking::CacheIfTracked, BoundObject, PropertyBindings[Index].PropertyPath)) { continue; } FPreAnimatedStateEntry Entry = this->MakeEntry(BoundObject, PropertyBindings[Index].PropertyPath); this->TrackCaptureSource(Entry, EPreAnimatedCaptureSourceTracking::CacheIfTracked); EPreAnimatedStorageRequirement StorageRequirement = this->ParentExtension->GetStorageRequirement(Entry); if (!this->IsStorageRequirementSatisfied(Entry.ValueHandle.StorageIndex, StorageRequirement)) { StorageType NewValue(MetaData.template Get()[Index]...); if (Fast) { NewValue.Binding.template Set(Fast[Index]); PropertyTraits::GetObjectPropertyValue(BoundObjects[Index], MetaData.template Get()[Index]..., Fast[Index], NewValue.Data); } else if (Custom) { const FCustomPropertyAccessor& Accessor = this->CustomAccessors[Custom[Index].Value]; NewValue.Binding.template Set(&Accessor); PropertyTraits::GetObjectPropertyValue(BoundObjects[Index], MetaData.template Get()[Index]..., Accessor, NewValue.Data); } else if (Slow) { const TSharedPtr& Bindings = Slow[Index]; NewValue.Binding.template Set>(Bindings); PropertyTraits::GetObjectPropertyValue(BoundObjects[Index], MetaData.template Get()[Index]..., Bindings.Get(), NewValue.Data); } this->AssignPreAnimatedValue(Entry.ValueHandle.StorageIndex, StorageRequirement, MoveTemp(NewValue)); } if (Params.bForcePersist) { this->ForciblyPersistStorage(Entry.ValueHandle.StorageIndex); } } } protected: TArrayView MetaDataComponents; FCustomAccessorView CustomAccessors; }; template using TPreAnimatedPropertyStorage = TPreAnimatedPropertyStorageImpl>; } // namespace MovieScene } // namespace UE