// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/StaticArray.h" #include "MuR/Serialisation.h" #include "Misc/TVariant.h" #include "Math/Color.h" #include "Math/Quat.h" #include "Math/Vector.h" #include "Math/IntVector.h" #include "Math/Vector4.h" #include "Math/Transform.h" #include "MuR/Ptr.h" #include "MuR/RefCounted.h" #include "MuR/MutableMath.h" #include "MuR/Types.h" #define UE_API MUTABLERUNTIME_API namespace mu { //! class FInputMemoryStream : public FInputStream { public: //----------------------------------------------------------------------------------------- // Life cycle //----------------------------------------------------------------------------------------- //! Create the stream using an external buffer. //! The buffer will not be owned by this object, so it cannot be deallocated while this //! objects is in use. UE_API FInputMemoryStream( const void* pBuffer, uint64 size ); //----------------------------------------------------------------------------------------- // FInputStream interface //----------------------------------------------------------------------------------------- UE_API void Read( void* pData, uint64 size ) override; private: const void* Buffer = nullptr; uint64 Size = 0; uint64 Pos = 0; }; #define MUTABLE_IMPLEMENT_POD_SERIALISABLE(Type) \ void DLLEXPORT operator<<(FOutputArchive& Arch, const Type& T) \ { \ Arch.Stream->Write(&T, sizeof(Type)); \ } \ \ void DLLEXPORT operator>>(FInputArchive& Arch, Type& T) \ { \ Arch.Stream->Read(&T, sizeof(Type)); \ } \ #define MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(Type) \ template \ void DLLEXPORT operator<<(FOutputArchive& Arch, const TArray& V) \ { \ uint32 Num = uint32(V.Num()); \ Arch << Num; \ if (Num) \ { \ Arch.Stream->Write(V.GetData(), Num * sizeof(Type)); \ } \ } \ \ template \ void DLLEXPORT operator>>(FInputArchive& Arch, TArray& V) \ { \ uint32 Num; \ Arch >> Num; \ V.SetNum(Num); \ if (Num) \ { \ Arch.Stream->Read(V.GetData(), Num * sizeof(Type)); \ } \ } \ /** TVariant custom serialize. Based on the default serialization. */ template void operator<<(FOutputArchive& Ar, const TVariant& Variant) { const uint8 Index = static_cast(Variant.GetIndex()); Ar << Index; Visit([&Ar](auto& StoredValue) { Ar << StoredValue; }, Variant); } template struct TVariantLoadFromInputArchiveCaller { /** Default construct the type and load it from the FArchive */ static void Load(FInputArchive& Ar, VariantType& OutVariant) { OutVariant.template Emplace(); Ar >> OutVariant.template Get(); } }; template struct TVariantLoadFromInputArchiveLookup { using VariantType = TVariant; static_assert((std::is_default_constructible::value && ...), "Each type in TVariant template parameter pack must be default constructible in order to use FArchive serialization"); /** Load the type at the specified index from the FArchive and emplace it into the TVariant */ static void Load(SIZE_T TypeIndex, FInputArchive& Ar, VariantType& OutVariant) { static constexpr void(*Loaders[])(FInputArchive&, VariantType&) = { &TVariantLoadFromInputArchiveCaller::Load... }; check(TypeIndex < UE_ARRAY_COUNT(Loaders)); Loaders[TypeIndex](Ar, OutVariant); } }; template void operator>>(FInputArchive& Ar, TVariant& Variant) { uint8 Index; Ar >> Index; check(Index < sizeof...(Ts)); TVariantLoadFromInputArchiveLookup::Load(static_cast(Index), Ar, Variant); } #define MUTABLE_IMPLEMENT_ENUM_SERIALISABLE(Type) \ void DLLEXPORT operator<<(FOutputArchive& Arch, const Type& T) \ { \ uint32 V = (uint32)T; \ Arch.Stream->Write(&V, sizeof(uint32)); \ } \ \ void DLLEXPORT operator>>(FInputArchive& Arch, Type& T) \ { \ uint32 V; \ Arch.Stream->Read(&V, sizeof(uint32)); \ T = (Type)V; \ } \ template inline void operator<<(FOutputArchive& Arch, const std::pair& V) { Arch << V.first; Arch << V.second; } template inline void operator>>(FInputArchive& Arch, std::pair& V) { Arch >> V.first; Arch >> V.second; } template void operator<<(FOutputArchive& Arch, const TStaticArray& V) { for (int32 I = 0; I < Size; ++I) { Arch << V[I]; } } template void operator>>(FInputArchive& Arch, TStaticArray& V) { for (uint32 I = 0; I < Size; ++I) { Arch >> V[I]; } } //--------------------------------------------------------------------------------------------- template< typename K, typename T > inline void operator<< (FOutputArchive& Arch, const TMap& V) { Arch << (uint32)V.Num(); for (const TPair& Element : V) { Arch << Element.Key; Arch << Element.Value; } } template< typename K, typename T > inline void operator>> (FInputArchive& Arch, TMap& V) { uint32 Num; Arch >> Num; for (uint32 Index = 0; Index < Num; ++Index) { K Key; T Element; Arch >> Key; Arch >> Element; V.Emplace(MoveTemp(Key), MoveTemp(Element)); } } // Unreal POD Serializables MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(float); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(double); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(uint8); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(uint16); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(uint32); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(uint64); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(int8); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(int16); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(int32); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(int64); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(TCHAR); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(FIntVector2); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(FUintVector2); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(UE::Math::TIntVector2); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(UE::Math::TIntVector2); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(FVector2f); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(FVector4f); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(FMatrix44f); MUTABLE_IMPLEMENT_POD_VECTOR_SERIALISABLE(FRichCurveKey); //--------------------------------------------------------------------------------------------- template< typename T > inline void operator<< (FOutputArchive& Arch, const TSharedPtr& Ptr) { if (!Ptr) { Arch << (int32)-1; } else { int32* it = Arch.History.Find(Ptr.Get()); if (!it) { int32 Id = Arch.History.Num(); Arch.History.Add(Ptr.Get(), Id); Arch << Id; T::Serialise(Ptr.Get(), Arch); } else { Arch << *it; } } } template< typename T > inline void operator>> (FInputArchive& Arch, TSharedPtr& Ptr) { int32 Id; Arch >> Id; if (Id == -1) { Ptr.Reset(); } else { if (Id < Arch.History.Num()) { Ptr = StaticCastSharedPtr(Arch.History[Id]); // If the pointer was null it means the position in history is used, but not set yet // option 1: we have a smart pointer loop which is very bad. // option 2: the resource in this Ptr is also pointed by a Proxy that has absorbed it // and this reference should also be a proxy instead of a pointer. check(Ptr); } else { // Ids come in order, but they may have been absorbed outside in some serialisations // like proxies. //check( Id == Arch.>History.Num() ); Arch.History.SetNum(Id + 1, EAllowShrinking::No); TSharedPtr Temp = T::StaticUnserialise(Arch); Ptr = Temp; Arch.History[Id] = Temp; } } } //--------------------------------------------------------------------------------------------- template< typename T > inline void operator<< ( FOutputArchive& arch, const Ptr& p ) { operator<<( arch, (const Ptr&) p ); } template< typename T > inline void operator>> ( FInputArchive& arch, Ptr& p ) { operator>>( arch, (Ptr&) p ); } //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- template inline void operator<<(FOutputArchive& arch, const TPair& v) { arch << v.Key; arch << v.Value; } template inline void operator>>(FInputArchive& arch, TPair& v) { arch >> v.Key; arch >> v.Value; } //--------------------------------------------------------------------------------------------- // TODO: As POD? template< typename T > inline void operator<< (FOutputArchive& arch, const UE::Math::TQuat& v) { arch << v.X; arch << v.Y; arch << v.Z; arch << v.W; } template< typename T > inline void operator>> (FInputArchive& arch, UE::Math::TQuat& v) { arch >> v.X; arch >> v.Y; arch >> v.Z; arch >> v.W; } //--------------------------------------------------------------------------------------------- // TODO: As POD? template< typename T > inline void operator<< (FOutputArchive& arch, const UE::Math::TVector& v) { arch << v.X; arch << v.Y; arch << v.Z; } template< typename T > inline void operator>> (FInputArchive& arch, UE::Math::TVector& v) { arch >> v.X; arch >> v.Y; arch >> v.Z; } //--------------------------------------------------------------------------------------------- template< typename T > inline void operator<< (FOutputArchive& arch, const UE::Math::TTransform& v) { arch << v.GetRotation(); arch << v.GetTranslation(); arch << v.GetScale3D(); } template< typename T > inline void operator>> (FInputArchive& arch, UE::Math::TTransform& v) { UE::Math::TQuat Rot; UE::Math::TVector Trans; UE::Math::TVector Scale; arch >> Rot; arch >> Trans; arch >> Scale; v.SetComponents(Rot, Trans, Scale); } } #undef UE_API