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

563 lines
15 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Variants/MovieSceneTimeWarpVariant.h"
#include "Variants/MovieSceneTimeWarpVariantPayloads.h"
#include "Variants/MovieSceneTimeWarpGetter.h"
#include "MovieScene.h"
#include "MovieSceneTimeHelpers.h"
#include "UObject/FortniteMainBranchObjectVersion.h"
void FMovieSceneTimeWarpVariant::Set(double InLiteralPlayRate)
{
if (FMath::IsNearlyZero(InLiteralPlayRate))
{
Set(FMovieSceneTimeWarpFixedFrame{0});
}
else
{
Variant.Set(InLiteralPlayRate);
}
}
void FMovieSceneTimeWarpVariant::Set(const FMovieSceneTimeWarpFixedFrame& InValue)
{
Variant.SetTypedData(InValue, (uint8)EMovieSceneTimeWarpType::FixedTime - 1);
}
void FMovieSceneTimeWarpVariant::Set(const FMovieSceneTimeWarpFrameRate& InValue)
{
Variant.SetTypedData(InValue, (uint8)EMovieSceneTimeWarpType::FrameRate - 1);
}
void FMovieSceneTimeWarpVariant::Set(const FMovieSceneTimeWarpLoop& InValue)
{
Variant.SetTypedData(InValue, (uint8)EMovieSceneTimeWarpType::Loop - 1);
}
void FMovieSceneTimeWarpVariant::Set(const FMovieSceneTimeWarpClamp& InValue)
{
Variant.SetTypedData(InValue, (uint8)EMovieSceneTimeWarpType::Clamp - 1);
}
void FMovieSceneTimeWarpVariant::Set(const FMovieSceneTimeWarpLoopFloat& InValue)
{
Variant.SetTypedData(InValue, (uint8)EMovieSceneTimeWarpType::LoopFloat - 1);
}
void FMovieSceneTimeWarpVariant::Set(const FMovieSceneTimeWarpClampFloat& InValue)
{
Variant.SetTypedData(InValue, (uint8)EMovieSceneTimeWarpType::ClampFloat - 1);
}
double FMovieSceneTimeWarpVariant::AsFixedPlayRate() const
{
check(Variant.IsLiteral());
return Variant.GetLiteral();
}
float FMovieSceneTimeWarpVariant::AsFixedPlayRateFloat() const
{
check(Variant.IsLiteral());
return Variant.GetLiteralAsFloat();
}
FMovieSceneTimeWarpFixedFrame FMovieSceneTimeWarpVariant::AsFixedTime() const
{
check(GetType() == EMovieSceneTimeWarpType::FixedTime);
return Variant.UnsafePayloadCast<FMovieSceneTimeWarpFixedFrame>();
}
FMovieSceneTimeWarpFrameRate FMovieSceneTimeWarpVariant::AsFrameRate() const
{
check(GetType() == EMovieSceneTimeWarpType::FrameRate);
return Variant.UnsafePayloadCast<FMovieSceneTimeWarpFrameRate>();
}
FMovieSceneTimeWarpLoop FMovieSceneTimeWarpVariant::AsLoop() const
{
check(GetType() == EMovieSceneTimeWarpType::Loop);
return Variant.UnsafePayloadCast<FMovieSceneTimeWarpLoop>();
}
FMovieSceneTimeWarpClamp FMovieSceneTimeWarpVariant::AsClamp() const
{
check(GetType() == EMovieSceneTimeWarpType::Clamp);
return Variant.UnsafePayloadCast<FMovieSceneTimeWarpClamp>();
}
FMovieSceneTimeWarpLoopFloat FMovieSceneTimeWarpVariant::AsLoopFloat() const
{
check(GetType() == EMovieSceneTimeWarpType::LoopFloat);
return Variant.UnsafePayloadCast<FMovieSceneTimeWarpLoopFloat>();
}
FMovieSceneTimeWarpClampFloat FMovieSceneTimeWarpVariant::AsClampFloat() const
{
check(GetType() == EMovieSceneTimeWarpType::ClampFloat);
return Variant.UnsafePayloadCast<FMovieSceneTimeWarpClampFloat>();
}
UMovieSceneTimeWarpGetter* FMovieSceneTimeWarpVariant::AsCustom() const
{
check(GetType() == EMovieSceneTimeWarpType::Custom);
return static_cast<UMovieSceneTimeWarpGetter*>(Variant.GetCustomPtr());
}
void FMovieSceneTimeWarpVariant::Set(UMovieSceneTimeWarpGetter* InDynamicValue)
{
Variant.Set(InDynamicValue);
}
void FMovieSceneTimeWarpVariant::ScaleBy(double ScaleFactor)
{
switch(GetType())
{
case EMovieSceneTimeWarpType::FixedPlayRate:
{
const double NewPlayRate = AsFixedPlayRate() * ScaleFactor;
// Use Set() here in order to properly handle (near-)zero play rates
Set(NewPlayRate);
}
break;
case EMovieSceneTimeWarpType::Custom:
if (UMovieSceneTimeWarpGetter* Custom = AsCustom())
{
Custom->ScaleBy(ScaleFactor);
}
break;
case EMovieSceneTimeWarpType::FixedTime:
break;
case EMovieSceneTimeWarpType::FrameRate:
break;
case EMovieSceneTimeWarpType::Loop:
{
FMovieSceneTimeWarpLoop Loop = AsLoop();
Loop.Duration = (Loop.Duration * ScaleFactor);
Set(Loop);
}
break;
case EMovieSceneTimeWarpType::Clamp:
{
FMovieSceneTimeWarpClamp Clamp = AsClamp();
Clamp.Max = (Clamp.Max * ScaleFactor);
Set(Clamp);
}
break;
case EMovieSceneTimeWarpType::LoopFloat:
{
FMovieSceneTimeWarpLoopFloat Loop = AsLoopFloat();
Loop.Duration *= ScaleFactor;
Set(Loop);
}
break;
case EMovieSceneTimeWarpType::ClampFloat:
{
FMovieSceneTimeWarpClampFloat Clamp = AsClampFloat();
Clamp.Max *= ScaleFactor;
Set(Clamp);
}
break;
}
}
FFrameTime FMovieSceneTimeWarpVariant::RemapTime(FFrameTime InTime) const
{
switch(GetType())
{
case EMovieSceneTimeWarpType::FixedPlayRate:
return InTime * AsFixedPlayRate();
case EMovieSceneTimeWarpType::Custom:
if (UMovieSceneTimeWarpGetter* Custom = AsCustom())
{
return Custom->RemapTime(InTime);
}
return InTime;
case EMovieSceneTimeWarpType::FixedTime:
return AsFixedTime().FrameNumber;
case EMovieSceneTimeWarpType::FrameRate:
return ConvertFrameTime(InTime, FFrameRate(1, 1), AsFrameRate().GetFrameRate());
case EMovieSceneTimeWarpType::Loop:
return AsLoop().LoopTime(InTime);
case EMovieSceneTimeWarpType::Clamp:
return AsClamp().Clamp(InTime);
case EMovieSceneTimeWarpType::LoopFloat:
return AsLoopFloat().LoopTime(InTime);
case EMovieSceneTimeWarpType::ClampFloat:
return AsClampFloat().Clamp(InTime);
}
return InTime;
}
bool FMovieSceneTimeWarpVariant::Serialize(FArchive& Ar)
{
Ar.UsingCustomVersion(FFortniteMainBranchObjectVersion::GUID);
return Variant.SerializeCustom(Ar, [this](FArchive& InAr, uint8& TypeBits, void* DataPtr){
const bool bIsLoading = InAr.GetArchiveState().IsLoading();
EMovieSceneTimeWarpType Type = this->GetType();
InAr << Type;
if (bIsLoading)
{
TypeBits = (uint8)Type - 1;
}
switch(Type)
{
case EMovieSceneTimeWarpType::Custom:
if (bIsLoading)
{
UMovieSceneNumericVariantGetter* Custom = nullptr;
InAr << Custom;
Variant.Set(Custom);
}
else
{
UMovieSceneNumericVariantGetter* Custom = this->AsCustom();
InAr << Custom;
}
break;
case EMovieSceneTimeWarpType::FixedTime:
FMovieSceneTimeWarpFixedFrame::StaticStruct()->SerializeItem(InAr, DataPtr, nullptr);
break;
case EMovieSceneTimeWarpType::FrameRate:
if (bIsLoading)
{
FMovieSceneTimeWarpFrameRate* Rate = static_cast<FMovieSceneTimeWarpFrameRate*>(DataPtr);
FFrameRate FrameRate;
TBaseStructure<FFrameRate>::Get()->SerializeItem(InAr, &FrameRate, nullptr);
*Rate = FMovieSceneTimeWarpFrameRate(FrameRate);
}
else
{
FMovieSceneTimeWarpFrameRate* Rate = static_cast<FMovieSceneTimeWarpFrameRate*>(DataPtr);
FFrameRate FrameRate = Rate->GetFrameRate();
TBaseStructure<FFrameRate>::Get()->SerializeItem(InAr, &FrameRate, nullptr);
}
break;
case EMovieSceneTimeWarpType::Loop:
FMovieSceneTimeWarpLoop::StaticStruct()->SerializeItem(InAr, DataPtr, nullptr);
break;
case EMovieSceneTimeWarpType::Clamp:
FMovieSceneTimeWarpClamp::StaticStruct()->SerializeItem(InAr, DataPtr, nullptr);
break;
case EMovieSceneTimeWarpType::LoopFloat:
FMovieSceneTimeWarpLoopFloat::StaticStruct()->SerializeItem(InAr, DataPtr, nullptr);
break;
case EMovieSceneTimeWarpType::ClampFloat:
FMovieSceneTimeWarpClampFloat::StaticStruct()->SerializeItem(InAr, DataPtr, nullptr);
break;
}
});
}
bool FMovieSceneTimeWarpVariant::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 FMovieSceneTimeWarpVariant::ExportTextItem(FString& ValueStr, const FMovieSceneTimeWarpVariant& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const
{
EMovieSceneTimeWarpType Type = this->GetType();
ValueStr += UEnum::GetValueAsString(Type);
switch(Type)
{
case EMovieSceneTimeWarpType::FixedPlayRate:
{
FMovieSceneFixedPlayRateStruct Struct = {this->AsFixedPlayRate()};
FMovieSceneFixedPlayRateStruct::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
case EMovieSceneTimeWarpType::Custom:
{
FMovieSceneCustomTimeWarpGetterStruct Struct = {this->AsCustom()};
FMovieSceneCustomTimeWarpGetterStruct::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
case EMovieSceneTimeWarpType::FixedTime:
{
FMovieSceneTimeWarpFixedFrame Struct = this->AsFixedTime();
FMovieSceneTimeWarpFixedFrame::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
case EMovieSceneTimeWarpType::FrameRate:
{
FMovieSceneTimeWarpFrameRate Struct = this->AsFrameRate();
FMovieSceneTimeWarpFrameRate::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
case EMovieSceneTimeWarpType::Loop:
{
FMovieSceneTimeWarpLoop Struct = this->AsLoop();
FMovieSceneTimeWarpLoop::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
case EMovieSceneTimeWarpType::Clamp:
{
FMovieSceneTimeWarpClamp Struct = this->AsClamp();
FMovieSceneTimeWarpClamp::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
case EMovieSceneTimeWarpType::LoopFloat:
{
FMovieSceneTimeWarpLoopFloat Struct = this->AsLoopFloat();
FMovieSceneTimeWarpLoopFloat::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
case EMovieSceneTimeWarpType::ClampFloat:
{
FMovieSceneTimeWarpClampFloat Struct = this->AsClampFloat();
FMovieSceneTimeWarpClampFloat::StaticStruct()->ExportText(ValueStr, &Struct, nullptr, Parent, PortFlags, ExportRootScope);
return true;
}
default:
ensureMsgf(false, TEXT("Unimplemented type found when exporting text!"));
return false;
}
}
bool FMovieSceneTimeWarpVariant::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText)
{
FNameBuilder TypeEnumEntry;
TStringView<TCHAR> EnumToken = TEXTVIEW("EMovieSceneTimeWarpType::");
if (FCString::Strncmp(EnumToken.GetData(), Buffer, EnumToken.Len()) != 0)
{
return false;
}
Buffer += EnumToken.Len();
TypeEnumEntry += EnumToken;
if (const TCHAR* TypeNameEnd = FPropertyHelpers::ReadToken(Buffer, TypeEnumEntry))
{
Buffer = TypeNameEnd;
}
else
{
return false;
}
FName EnumEntryName(TypeEnumEntry.ToView(), FNAME_Find);
if (EnumEntryName.IsNone())
{
return false;
}
UEnum* Enum = StaticEnum<EMovieSceneTimeWarpType>();
check(Enum);
const int64 EnumValue = Enum->GetValueByName(EnumEntryName);
if (EnumValue == INDEX_NONE)
{
return false;
}
EMovieSceneTimeWarpType NewType = (EMovieSceneTimeWarpType)EnumValue;
switch(NewType)
{
case EMovieSceneTimeWarpType::FixedPlayRate:
{
FMovieSceneFixedPlayRateStruct Struct;
if (const TCHAR* Result = FMovieSceneFixedPlayRateStruct::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneFixedPlayRateStruct::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct.PlayRate);
return true;
}
return false;
}
case EMovieSceneTimeWarpType::Custom:
{
FMovieSceneCustomTimeWarpGetterStruct Struct;
if (const TCHAR* Result = FMovieSceneCustomTimeWarpGetterStruct::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneCustomTimeWarpGetterStruct::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct.Object);
return true;
}
return false;
}
case EMovieSceneTimeWarpType::FixedTime:
{
FMovieSceneTimeWarpFixedFrame Struct;
if (const TCHAR* Result = FMovieSceneTimeWarpFixedFrame::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneTimeWarpFixedFrame::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct);
return true;
}
return false;
}
case EMovieSceneTimeWarpType::FrameRate:
{
FMovieSceneTimeWarpFrameRate Struct;
if (const TCHAR* Result = FMovieSceneTimeWarpFrameRate::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneTimeWarpFrameRate::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct);
return true;
}
return false;
}
case EMovieSceneTimeWarpType::Loop:
{
FMovieSceneTimeWarpLoop Struct;
if (const TCHAR* Result = FMovieSceneTimeWarpLoop::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneTimeWarpLoop::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct);
return true;
}
return false;
}
case EMovieSceneTimeWarpType::Clamp:
{
FMovieSceneTimeWarpClamp Struct;
if (const TCHAR* Result = FMovieSceneTimeWarpClamp::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneTimeWarpClamp::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct);
return true;
}
return false;
}
case EMovieSceneTimeWarpType::LoopFloat:
{
FMovieSceneTimeWarpLoopFloat Struct;
if (const TCHAR* Result = FMovieSceneTimeWarpLoopFloat::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneTimeWarpLoopFloat::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct);
return true;
}
return false;
}
case EMovieSceneTimeWarpType::ClampFloat:
{
FMovieSceneTimeWarpClampFloat Struct;
if (const TCHAR* Result = FMovieSceneTimeWarpClampFloat::StaticStruct()->ImportText(Buffer, &Struct, Parent, PortFlags, ErrorText, []{ return FMovieSceneTimeWarpClampFloat::StaticStruct()->GetName(); }))
{
Buffer = Result;
Set(Struct);
return true;
}
return false;
}
default:
ensureMsgf(false, TEXT("Unimplemented type found when importing text!"));
return false;
}
}