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

268 lines
9.5 KiB
C++

// 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<typename StorageType, typename ...MetaDataTypes>
struct TPreAnimatedPropertyValue
{
TPreAnimatedPropertyValue()
{}
TPreAnimatedPropertyValue(typename TCallTraits<MetaDataTypes>::ParamType... InMetaData)
: MetaData(InMetaData...)
{}
StorageType Data;
TVariant<const FCustomPropertyAccessor*, uint16, TSharedPtr<FTrackInstancePropertyBindings>> Binding;
TTuple<MetaDataTypes...> MetaData;
};
/**
* Pre-animated property value, specialized for no meta-data
*/
template<typename StorageType>
struct TPreAnimatedPropertyValue<StorageType>
{
StorageType Data;
TVariant<const FCustomPropertyAccessor*, uint16, TSharedPtr<FTrackInstancePropertyBindings>> Binding;
};
/**
* Pre-Animated traits class that wraps a user-provided property trait that defines property accessors
*/
template<typename PropertyTraits, typename MetaDataIndices, typename ...MetaDataTypes>
struct TPreAnimatedPropertyTraits;
template<typename PropertyTraits, int... MetaDataIndices, typename ...MetaDataTypes>
struct TPreAnimatedPropertyTraits<PropertyTraits, TIntegerSequence<int, MetaDataIndices...>, MetaDataTypes...> : FBoundObjectPreAnimatedStateTraits
{
using KeyType = TTuple<FObjectKey, FName>;
using StorageType = TPreAnimatedPropertyValue<typename PropertyTraits::StorageType, MetaDataTypes...>;
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<uint16>())
{
PropertyTraits::SetObjectPropertyValue(Object, CachedValue.MetaData.template Get<MetaDataIndices>()..., *FastOffset, CachedValue.Data);
}
else if (const TSharedPtr<FTrackInstancePropertyBindings>* Bindings = CachedValue.Binding.template TryGet<TSharedPtr<FTrackInstancePropertyBindings>>())
{
PropertyTraits::SetObjectPropertyValue(Object, CachedValue.MetaData.template Get<MetaDataIndices>()..., Bindings->Get(), CachedValue.Data);
}
else if (const FCustomPropertyAccessor* CustomAccessor = CachedValue.Binding.template Get<const FCustomPropertyAccessor*>())
{
PropertyTraits::SetObjectPropertyValue(Object, CachedValue.MetaData.template Get<MetaDataIndices>()..., *CustomAccessor, CachedValue.Data);
}
}
};
/**
* Pre-Animated traits class that wraps a user-provided property trait that defines property accessors with no meta-data
*/
template<typename PropertyTraits>
struct TPreAnimatedPropertyTraits<PropertyTraits, TPropertyMetaData<>, TIntegerSequence<int>> : FBoundObjectPreAnimatedStateTraits
{
using KeyType = TTuple<FObjectKey, FName>;
using StorageType = TPreAnimatedPropertyValue<typename PropertyTraits::StorageType>;
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<uint16>())
{
PropertyTraits::SetObjectPropertyValue(Object, *FastOffset, CachedValue.Data);
}
else if (const TSharedPtr<FTrackInstancePropertyBindings>* Bindings = CachedValue.Binding.template TryGet<TSharedPtr<FTrackInstancePropertyBindings>>())
{
PropertyTraits::SetObjectPropertyValue(Object, Bindings->Get(), CachedValue.Data);
}
else if (const FCustomPropertyAccessor* CustomAccessor = CachedValue.Binding.template Get<const FCustomPropertyAccessor*>())
{
PropertyTraits::SetObjectPropertyValue(Object, *CustomAccessor, CachedValue.Data);
}
}
};
template<typename PropertyTraits, typename MetaDataTypes, typename MetaDataIndices>
struct TPreAnimatedPropertyStorageImpl;
template<typename PropertyTraits, typename ...MetaDataTypes, int ...MetaDataIndices>
struct TPreAnimatedPropertyStorageImpl<PropertyTraits, TPropertyMetaData<MetaDataTypes...>, TIntegerSequence<int, MetaDataIndices...>>
: TPreAnimatedStateStorage<TPreAnimatedPropertyTraits<PropertyTraits, TIntegerSequence<int, MetaDataIndices...>, MetaDataTypes...>>
, IPreAnimatedObjectPropertyStorage
{
using StorageTraits = TPreAnimatedPropertyTraits<PropertyTraits, TIntegerSequence<int, MetaDataIndices...>, 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<FMovieSceneEntityID> EntityIDs, TRead<FRootInstanceHandle> InstanceHandles, TRead<UObject*> BoundObjects, TRead<FMovieScenePropertyBinding> 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<UObject*> BoundObjects, TRead<FMovieScenePropertyBinding> PropertyBindings, FThreeWayAccessor Properties) override
{
const FEntityAllocation* Allocation = Item.GetAllocation();
TTuple< TComponentReader<MetaDataTypes>... > MetaData(
Allocation->ReadComponents(MetaDataComponents[MetaDataIndices].template ReinterpretCast<MetaDataTypes>())...
);
const uint16* Fast = Properties.Get<1>();
const FCustomPropertyIndex* Custom = Properties.Get<0>();
const TSharedPtr<FTrackInstancePropertyBindings>* 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<MetaDataIndices>()[Index]...);
if (Fast)
{
NewValue.Binding.template Set<uint16>(Fast[Index]);
PropertyTraits::GetObjectPropertyValue(BoundObjects[Index], MetaData.template Get<MetaDataIndices>()[Index]..., Fast[Index], NewValue.Data);
}
else if (Custom)
{
const FCustomPropertyAccessor& Accessor = this->CustomAccessors[Custom[Index].Value];
NewValue.Binding.template Set<const FCustomPropertyAccessor*>(&Accessor);
PropertyTraits::GetObjectPropertyValue(BoundObjects[Index], MetaData.template Get<MetaDataIndices>()[Index]..., Accessor, NewValue.Data);
}
else if (Slow)
{
const TSharedPtr<FTrackInstancePropertyBindings>& Bindings = Slow[Index];
NewValue.Binding.template Set<TSharedPtr<FTrackInstancePropertyBindings>>(Bindings);
PropertyTraits::GetObjectPropertyValue(BoundObjects[Index], MetaData.template Get<MetaDataIndices>()[Index]..., Bindings.Get(), NewValue.Data);
}
this->AssignPreAnimatedValue(Entry.ValueHandle.StorageIndex, StorageRequirement, MoveTemp(NewValue));
}
if (Params.bForcePersist)
{
this->ForciblyPersistStorage(Entry.ValueHandle.StorageIndex);
}
}
}
protected:
TArrayView<const FComponentTypeID> MetaDataComponents;
FCustomAccessorView CustomAccessors;
};
template<typename PropertyTraits>
using TPreAnimatedPropertyStorage = TPreAnimatedPropertyStorageImpl<PropertyTraits, typename PropertyTraits::MetaDataType, TMakeIntegerSequence<int, PropertyTraits::MetaDataType::Num>>;
} // namespace MovieScene
} // namespace UE