Files
UnrealEngine/Engine/Source/Runtime/MovieScene/Private/Variants/MovieSceneNumericVariant.cpp
2025-05-18 13:04:45 +08:00

421 lines
8.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Variants/MovieSceneNumericVariant.h"
#include "Variants/MovieSceneNumericVariantGetter.h"
bool operator==(const FMovieSceneNumericVariant& A, const FMovieSceneNumericVariant& B)
{
if (A.IsLiteral() != B.IsLiteral())
{
return false;
}
else if (A.IsLiteral())
{
return *reinterpret_cast<const double*>(A.Data) == *reinterpret_cast<const double*>(B.Data);
}
else if (A.GetTypeBits() == B.GetTypeBits())
{
if (A.IsCustomPtr())
{
// Deep compare if possible.
UMovieSceneNumericVariantGetter* PtrA = A.GetCustomPtr();
UMovieSceneNumericVariantGetter* PtrB = B.GetCustomPtr();
if (PtrA == PtrB)
{
return true;
}
if (PtrA && PtrB)
{
UClass* Class = PtrA->GetClass();
if (Class == PtrB->GetClass())
{
for (TFieldIterator<FProperty> It(Class); It; ++It)
{
for (int32 i=0; i<It->ArrayDim; i++)
{
if (!It->Identical_InContainer(PtrA,PtrB,i,PPF_None))
{
return false;
}
}
}
return PtrA->AreNativePropertiesIdenticalTo(PtrB);
}
}
}
else
{
// Bitwise compare
return
(*reinterpret_cast<const uint64*>(A.Data) & FMovieSceneNumericVariant::PAYLOAD_Bits) ==
(*reinterpret_cast<const uint64*>(B.Data) & FMovieSceneNumericVariant::PAYLOAD_Bits);
}
}
return false;
}
bool operator!=(const FMovieSceneNumericVariant& A, const FMovieSceneNumericVariant& B)
{
return !(A == B);
}
FMovieSceneNumericVariant::FMovieSceneNumericVariant()
{
Set(0.0);
}
FMovieSceneNumericVariant::FMovieSceneNumericVariant(double InValue)
{
Set(InValue);
}
FMovieSceneNumericVariant::FMovieSceneNumericVariant(UMovieSceneNumericVariantGetter* InGetter)
{
Set(InGetter);
}
FMovieSceneNumericVariant FMovieSceneNumericVariant::ShallowCopy() const
{
// Bitwise copy
FMovieSceneNumericVariant New(NoInit);
FMemory::Memcpy(New.Data, this->Data, sizeof(Data));
#if UE_MOVIESCENE_WEAKNUMERICVARIANT_CHECKS
New.WeakCustomGetter = this->WeakCustomGetter;
#endif
return New;
}
FMovieSceneNumericVariant FMovieSceneNumericVariant::DeepCopy(UObject* NewOuter) const
{
if (this->IsCustomPtr())
{
UMovieSceneNumericVariantGetter* Getter = this->GetCustomPtr();
if (Getter)
{
Getter = DuplicateObject(Getter, NewOuter);
}
FMovieSceneNumericVariant New(Getter);
if (this->HasCustomWeakPtrFlag())
{
New.MakeWeakUnsafe();
}
return New;
}
return ShallowCopy();
}
void FMovieSceneNumericVariant::Set(double InLiteralValue)
{
*reinterpret_cast<double*>(Data) = InLiteralValue;
#if UE_MOVIESCENE_WEAKNUMERICVARIANT_CHECKS
WeakCustomGetter = nullptr;
#endif
}
void FMovieSceneNumericVariant::Set(UMovieSceneNumericVariantGetter* InDynamicValue)
{
if (InDynamicValue)
{
InDynamicValue->ReferenceToSelf = InDynamicValue;
}
uint64 NewValue = reinterpret_cast<const uint64>(InDynamicValue);
checkf((NewValue & ~PAYLOAD_Bits) == 0, TEXT("Unable to store a pointer outside of a 48 bit address space in this container"));
*reinterpret_cast<uint64*>(Data) = NewValue | TAGGED_Bits | TYPE_CustomPtr;
}
void FMovieSceneNumericVariant::SetWeakUnsafe(UMovieSceneNumericVariantGetter* InDynamicValue)
{
Set(InDynamicValue);
MakeWeakUnsafe();
}
void FMovieSceneNumericVariant::MakeWeakUnsafe()
{
if (IsCustomPtr())
{
#if UE_MOVIESCENE_WEAKNUMERICVARIANT_CHECKS
WeakCustomGetter = GetCustomPtr();
#endif
*reinterpret_cast<uint64*>(Data) |= CUSTOMPTR_Weak;
}
}
double FMovieSceneNumericVariant::Get() const
{
if (IsLiteral())
{
return GetLiteral();
}
if (IsCustomPtr())
{
UMovieSceneNumericVariantGetter* Getter = GetCustomPtr();
if (Getter)
{
return Getter->GetValue();
}
}
return 0.0;
}
void FMovieSceneNumericVariant::SetTypeBits(uint8 InType)
{
check(!IsLiteral() && (InType & 0x7) == InType); // Must fit into the type mask
const uint64 TypeMask = uint64(InType & 0x7) << 48;
*reinterpret_cast<uint64*>(Data) |= (TypeMask & TYPE_Bits);
#if UE_MOVIESCENE_WEAKNUMERICVARIANT_CHECKS
WeakCustomGetter = nullptr;
#endif
}
uint8 FMovieSceneNumericVariant::GetTypeBits() const
{
check(!IsLiteral());
const uint64 Type = (*reinterpret_cast<const uint64*>(Data)) & TYPE_Bits;
return uint8(Type >> 48);
}
bool FMovieSceneNumericVariant::HasCustomWeakPtrFlag() const
{
check(!IsLiteral() && (GetTypeBits() == TYPE_CustomPtr));
return (*reinterpret_cast<const uint64*>(Data) & CUSTOMPTR_Weak) != 0ull;
}
UMovieSceneNumericVariantGetter* FMovieSceneNumericVariant::GetCustomPtr() const
{
check(IsCustomPtr());
const uint64 PtrValue = (*reinterpret_cast<const uint64*>(Data) & PAYLOAD_Bits) & ~CUSTOMPTR_FlagBits;
UMovieSceneNumericVariantGetter* Ptr = reinterpret_cast<UMovieSceneNumericVariantGetter*>(PtrValue);
#if UE_MOVIESCENE_WEAKNUMERICVARIANT_CHECKS
if (Ptr && HasCustomWeakPtrFlag() && !ensureMsgf(WeakCustomGetter.Get() != nullptr, TEXT("Weakly referenced getter stored in FMovieSceneNumericVariant has been destroyed!")))
{
return nullptr;
}
#endif
return Ptr;
}
bool FMovieSceneNumericVariant::Serialize(FArchive& Ar)
{
if (Ar.IsLoading())
{
SerializeCustom(Ar, [this](FArchive& Ar, uint8& TypeBits, void* InOutData){
uint8 Type = 0;
Ar << Type;
if (Type == 0)
{
UMovieSceneNumericVariantGetter* Getter = nullptr;
Ar << Getter;
Set(Getter);
}
else
{
uint8 Payload[6];
Ar.Serialize(Payload, sizeof(Payload));
FMemory::Memcpy(InOutData, Payload, sizeof(Payload));
TypeBits = Type;
}
});
}
else
{
SerializeCustom(Ar, [this](FArchive& Ar, uint8& TypeBits, void* InOutData){
uint8 Type = GetTypeBits();
if (Ar.GetArchiveState().IsSaving())
{
Ar << Type;
}
if (Type == 0)
{
UMovieSceneNumericVariantGetter* Getter = GetCustomPtr();
Ar << Getter;
}
else
{
uint8 Payload[6];
FMemory::Memcpy(Payload, InOutData, sizeof(Payload));
Ar.Serialize(Payload, sizeof(Payload));
}
});
}
return true;
}
bool FMovieSceneNumericVariant::SerializeCustom(FArchive& Ar, TFunctionRef<void(FArchive&, uint8&, void*)> InCustomSerializer)
{
if (Ar.IsLoading())
{
bool bIsLiteral = true;
Ar << bIsLiteral;
if (bIsLiteral)
{
Ar << GetLiteralRef();
}
else
{
// First off, initialize this type to be a custom type specified by the tagged bits
uint64* Value = reinterpret_cast<uint64*>(Data);
*Value = TAGGED_Bits;
// Pass the type bits through to the serializer
uint8 TypeBits = 0;
InCustomSerializer(Ar, TypeBits, Data);
// Assign type bits
SetTypeBits(TypeBits);
}
}
else
{
bool bIsLiteral = IsLiteral();
if (Ar.GetArchiveState().IsSaving())
{
Ar << bIsLiteral;
}
if (bIsLiteral)
{
Ar << GetLiteralRef();
}
else
{
uint8 TypeBits = GetTypeBits();
InCustomSerializer(Ar, TypeBits, Data);
}
}
return true;
}
bool FMovieSceneNumericVariant::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot)
{
if (Tag.Type == NAME_DoubleProperty)
{
double Value = 0.0;
Slot << Value;
Set(Value);
return true;
}
if (Tag.Type == NAME_FloatProperty)
{
float Value = 0.f;
Slot << Value;
Set(Value);
return true;
}
// int64 and uint64 are not supported in this variant without loss of precision
if (Tag.Type == NAME_ByteProperty)
{
int32 Value = 0;
Slot << Value;
Set(Value);
return true;
}
if (Tag.Type == NAME_Int32Property || Tag.Type == NAME_IntProperty)
{
int32 Value = 0;
Slot << Value;
Set(Value);
return true;
}
if (Tag.Type == NAME_Int16Property)
{
int16 Value = 0;
Slot << Value;
Set(Value);
return true;
}
if (Tag.Type == NAME_Int8Property)
{
int8 Value = 0;
Slot << Value;
Set(Value);
return true;
}
if (Tag.Type == NAME_UInt32Property)
{
uint32 Value = 0;
Slot << Value;
Set(Value);
return true;
}
if (Tag.Type == NAME_UInt16Property)
{
uint16 Value = 0;
Slot << Value;
Set(Value);
return true;
}
if (Tag.Type == NAME_ByteProperty)
{
uint8 Value = 0;
Slot << Value;
Set(Value);
return true;
}
return false;
}
bool FMovieSceneNumericVariant::Identical(const FMovieSceneNumericVariant* Other, uint32 PortFlags) const
{
return *this == *Other;
}
void FMovieSceneNumericVariant::AddStructReferencedObjects(FReferenceCollector& Collector)
{
if (!IsLiteral() && GetTypeBits() == TYPE_CustomPtr)
{
UMovieSceneNumericVariantGetter* Getter = GetCustomPtr();
const bool bReportReference = !HasCustomWeakPtrFlag();
if (bReportReference && Getter)
{
const FProperty* Property = Collector.GetSerializedProperty();
Collector.AddReferencedObject(Getter->ReferenceToSelf, nullptr, Property);
}
}
}
bool FMovieSceneNumericVariant::ExportTextItem(FString& ValueStr, const FMovieSceneNumericVariant& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const
{
return false;
}
bool FMovieSceneNumericVariant::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText, FArchive* InSerializingArchive)
{
return false;
}
void FMovieSceneNumericVariant::GetPreloadDependencies(TArray<UObject*>& OutDeps)
{
}