This commit is contained in:
2026-03-04 00:50:15 -08:00
parent 9126175569
commit 4211317c03
569 changed files with 122194 additions and 0 deletions

View File

@ -0,0 +1,54 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/Core/RTTI.h>
JPH_NAMESPACE_BEGIN
/// Helper functions to get the underlying RTTI type of a type (so e.g. Array<sometype> will return sometype)
template <class T>
const RTTI *GetPrimitiveTypeOfType(T *)
{
return GetRTTIOfType((T *)nullptr);
}
template <class T>
const RTTI *GetPrimitiveTypeOfType(T **)
{
return GetRTTIOfType((T *)nullptr);
}
template <class T>
const RTTI *GetPrimitiveTypeOfType(Ref<T> *)
{
return GetRTTIOfType((T *)nullptr);
}
template <class T>
const RTTI *GetPrimitiveTypeOfType(RefConst<T> *)
{
return GetRTTIOfType((T *)nullptr);
}
template <class T, class A>
const RTTI *GetPrimitiveTypeOfType(Array<T, A> *)
{
return GetPrimitiveTypeOfType((T *)nullptr);
}
template <class T, uint N>
const RTTI *GetPrimitiveTypeOfType(StaticArray<T, N> *)
{
return GetPrimitiveTypeOfType((T *)nullptr);
}
template <class T, uint N>
const RTTI *GetPrimitiveTypeOfType(T (*)[N])
{
return GetPrimitiveTypeOfType((T *)nullptr);
}
JPH_NAMESPACE_END

View File

@ -0,0 +1,38 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/ObjectStream/ObjectStream.h>
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
// Define macro to declare functions for a specific primitive type
#define JPH_DECLARE_PRIMITIVE(name) \
bool OSIsType(name *, int inArrayDepth, EOSDataType inDataType, const char *inClassName) \
{ \
return inArrayDepth == 0 && inDataType == EOSDataType::T_##name; \
} \
bool OSReadData(IObjectStreamIn &ioStream, name &outPrimitive) \
{ \
return ioStream.ReadPrimitiveData(outPrimitive); \
} \
void OSWriteDataType(IObjectStreamOut &ioStream, name *) \
{ \
ioStream.WriteDataType(EOSDataType::T_##name); \
} \
void OSWriteData(IObjectStreamOut &ioStream, const name &inPrimitive) \
{ \
ioStream.HintNextItem(); \
ioStream.WritePrimitiveData(inPrimitive); \
}
// This file uses the JPH_DECLARE_PRIMITIVE macro to define all types
#include <Jolt/ObjectStream/ObjectStreamTypes.h>
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,337 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/Core/StaticArray.h>
#include <Jolt/Core/Reference.h>
#include <Jolt/Core/RTTI.h>
#include <Jolt/Core/NonCopyable.h>
#include <Jolt/ObjectStream/SerializableAttribute.h>
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
/// Base class for object stream input and output streams.
class JPH_EXPORT ObjectStream : public NonCopyable
{
public:
/// Stream type
enum class EStreamType
{
Text,
Binary,
};
protected:
/// Destructor
virtual ~ObjectStream() = default;
/// Identifier for objects
using Identifier = uint32;
static constexpr int sVersion = 1;
static constexpr int sRevision = 0;
static constexpr Identifier sNullIdentifier = 0;
};
/// Interface class for reading from an object stream
class JPH_EXPORT IObjectStreamIn : public ObjectStream
{
public:
///@name Input type specific operations
virtual bool ReadDataType(EOSDataType &outType) = 0;
virtual bool ReadName(String &outName) = 0;
virtual bool ReadIdentifier(Identifier &outIdentifier) = 0;
virtual bool ReadCount(uint32 &outCount) = 0;
///@name Read primitives
virtual bool ReadPrimitiveData(uint8 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(uint16 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(int &outPrimitive) = 0;
virtual bool ReadPrimitiveData(uint32 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(uint64 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(float &outPrimitive) = 0;
virtual bool ReadPrimitiveData(double &outPrimitive) = 0;
virtual bool ReadPrimitiveData(bool &outPrimitive) = 0;
virtual bool ReadPrimitiveData(String &outPrimitive) = 0;
virtual bool ReadPrimitiveData(Float3 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(Float4 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(Double3 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(Vec3 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(DVec3 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(Vec4 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(UVec4 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(Quat &outPrimitive) = 0;
virtual bool ReadPrimitiveData(Mat44 &outPrimitive) = 0;
virtual bool ReadPrimitiveData(DMat44 &outPrimitive) = 0;
///@name Read compounds
virtual bool ReadClassData(const char *inClassName, void *inInstance) = 0;
virtual bool ReadPointerData(const RTTI *inRTTI, void **inPointer, int inRefCountOffset = -1) = 0;
};
/// Interface class for writing to an object stream
class JPH_EXPORT IObjectStreamOut : public ObjectStream
{
public:
///@name Output type specific operations
virtual void WriteDataType(EOSDataType inType) = 0;
virtual void WriteName(const char *inName) = 0;
virtual void WriteIdentifier(Identifier inIdentifier) = 0;
virtual void WriteCount(uint32 inCount) = 0;
///@name Write primitives
virtual void WritePrimitiveData(const uint8 &inPrimitive) = 0;
virtual void WritePrimitiveData(const uint16 &inPrimitive) = 0;
virtual void WritePrimitiveData(const int &inPrimitive) = 0;
virtual void WritePrimitiveData(const uint32 &inPrimitive) = 0;
virtual void WritePrimitiveData(const uint64 &inPrimitive) = 0;
virtual void WritePrimitiveData(const float &inPrimitive) = 0;
virtual void WritePrimitiveData(const double &inPrimitive) = 0;
virtual void WritePrimitiveData(const bool &inPrimitive) = 0;
virtual void WritePrimitiveData(const String &inPrimitive) = 0;
virtual void WritePrimitiveData(const Float3 &inPrimitive) = 0;
virtual void WritePrimitiveData(const Float4 &inPrimitive) = 0;
virtual void WritePrimitiveData(const Double3 &inPrimitive) = 0;
virtual void WritePrimitiveData(const Vec3 &inPrimitive) = 0;
virtual void WritePrimitiveData(const DVec3 &inPrimitive) = 0;
virtual void WritePrimitiveData(const Vec4 &inPrimitive) = 0;
virtual void WritePrimitiveData(const UVec4 &inPrimitive) = 0;
virtual void WritePrimitiveData(const Quat &inPrimitive) = 0;
virtual void WritePrimitiveData(const Mat44 &inPrimitive) = 0;
virtual void WritePrimitiveData(const DMat44 &inPrimitive) = 0;
///@name Write compounds
virtual void WritePointerData(const RTTI *inRTTI, const void *inPointer) = 0;
virtual void WriteClassData(const RTTI *inRTTI, const void *inInstance) = 0;
///@name Layout hints (for text output)
virtual void HintNextItem() { /* Default is do nothing */ }
virtual void HintIndentUp() { /* Default is do nothing */ }
virtual void HintIndentDown() { /* Default is do nothing */ }
};
// Define macro to declare functions for a specific primitive type
#define JPH_DECLARE_PRIMITIVE(name) \
JPH_EXPORT bool OSIsType(name *, int inArrayDepth, EOSDataType inDataType, const char *inClassName); \
JPH_EXPORT bool OSReadData(IObjectStreamIn &ioStream, name &outPrimitive); \
JPH_EXPORT void OSWriteDataType(IObjectStreamOut &ioStream, name *); \
JPH_EXPORT void OSWriteData(IObjectStreamOut &ioStream, const name &inPrimitive);
// This file uses the JPH_DECLARE_PRIMITIVE macro to define all types
#include <Jolt/ObjectStream/ObjectStreamTypes.h>
// Define serialization templates
template <class T, class A>
bool OSIsType(Array<T, A> *, int inArrayDepth, EOSDataType inDataType, const char *inClassName)
{
return (inArrayDepth > 0 && OSIsType(static_cast<T *>(nullptr), inArrayDepth - 1, inDataType, inClassName));
}
template <class T, uint N>
bool OSIsType(StaticArray<T, N> *, int inArrayDepth, EOSDataType inDataType, const char *inClassName)
{
return (inArrayDepth > 0 && OSIsType(static_cast<T *>(nullptr), inArrayDepth - 1, inDataType, inClassName));
}
template <class T, uint N>
bool OSIsType(T (*)[N], int inArrayDepth, EOSDataType inDataType, const char *inClassName)
{
return (inArrayDepth > 0 && OSIsType(static_cast<T *>(nullptr), inArrayDepth - 1, inDataType, inClassName));
}
template <class T>
bool OSIsType(Ref<T> *, int inArrayDepth, EOSDataType inDataType, const char *inClassName)
{
return OSIsType(static_cast<T *>(nullptr), inArrayDepth, inDataType, inClassName);
}
template <class T>
bool OSIsType(RefConst<T> *, int inArrayDepth, EOSDataType inDataType, const char *inClassName)
{
return OSIsType(static_cast<T *>(nullptr), inArrayDepth, inDataType, inClassName);
}
/// Define serialization templates for dynamic arrays
template <class T, class A>
bool OSReadData(IObjectStreamIn &ioStream, Array<T, A> &inArray)
{
bool continue_reading = true;
// Read array length
uint32 array_length;
continue_reading = ioStream.ReadCount(array_length);
// Read array items
if (continue_reading)
{
inArray.clear();
inArray.resize(array_length);
for (uint32 el = 0; el < array_length && continue_reading; ++el)
continue_reading = OSReadData(ioStream, inArray[el]);
}
return continue_reading;
}
/// Define serialization templates for static arrays
template <class T, uint N>
bool OSReadData(IObjectStreamIn &ioStream, StaticArray<T, N> &inArray)
{
bool continue_reading = true;
// Read array length
uint32 array_length;
continue_reading = ioStream.ReadCount(array_length);
// Check if we can fit this many elements
if (array_length > N)
return false;
// Read array items
if (continue_reading)
{
inArray.clear();
inArray.resize(array_length);
for (uint32 el = 0; el < array_length && continue_reading; ++el)
continue_reading = OSReadData(ioStream, inArray[el]);
}
return continue_reading;
}
/// Define serialization templates for C style arrays
template <class T, uint N>
bool OSReadData(IObjectStreamIn &ioStream, T (&inArray)[N])
{
bool continue_reading = true;
// Read array length
uint32 array_length;
continue_reading = ioStream.ReadCount(array_length);
if (array_length != N)
return false;
// Read array items
for (uint32 el = 0; el < N && continue_reading; ++el)
continue_reading = OSReadData(ioStream, inArray[el]);
return continue_reading;
}
/// Define serialization templates for references
template <class T>
bool OSReadData(IObjectStreamIn &ioStream, Ref<T> &inRef)
{
return ioStream.ReadPointerData(JPH_RTTI(T), inRef.InternalGetPointer(), T::sInternalGetRefCountOffset());
}
template <class T>
bool OSReadData(IObjectStreamIn &ioStream, RefConst<T> &inRef)
{
return ioStream.ReadPointerData(JPH_RTTI(T), inRef.InternalGetPointer(), T::sInternalGetRefCountOffset());
}
// Define serialization templates for dynamic arrays
template <class T, class A>
void OSWriteDataType(IObjectStreamOut &ioStream, Array<T, A> *)
{
ioStream.WriteDataType(EOSDataType::Array);
OSWriteDataType(ioStream, static_cast<T *>(nullptr));
}
template <class T, class A>
void OSWriteData(IObjectStreamOut &ioStream, const Array<T, A> &inArray)
{
// Write size of array
ioStream.HintNextItem();
ioStream.WriteCount(static_cast<uint32>(inArray.size()));
// Write data in array
ioStream.HintIndentUp();
for (const T &v : inArray)
OSWriteData(ioStream, v);
ioStream.HintIndentDown();
}
/// Define serialization templates for static arrays
template <class T, uint N>
void OSWriteDataType(IObjectStreamOut &ioStream, StaticArray<T, N> *)
{
ioStream.WriteDataType(EOSDataType::Array);
OSWriteDataType(ioStream, static_cast<T *>(nullptr));
}
template <class T, uint N>
void OSWriteData(IObjectStreamOut &ioStream, const StaticArray<T, N> &inArray)
{
// Write size of array
ioStream.HintNextItem();
ioStream.WriteCount(inArray.size());
// Write data in array
ioStream.HintIndentUp();
for (const typename StaticArray<T, N>::value_type &v : inArray)
OSWriteData(ioStream, v);
ioStream.HintIndentDown();
}
/// Define serialization templates for C style arrays
template <class T, uint N>
void OSWriteDataType(IObjectStreamOut &ioStream, T (*)[N])
{
ioStream.WriteDataType(EOSDataType::Array);
OSWriteDataType(ioStream, static_cast<T *>(nullptr));
}
template <class T, uint N>
void OSWriteData(IObjectStreamOut &ioStream, const T (&inArray)[N])
{
// Write size of array
ioStream.HintNextItem();
ioStream.WriteCount(uint32(N));
// Write data in array
ioStream.HintIndentUp();
for (const T &v : inArray)
OSWriteData(ioStream, v);
ioStream.HintIndentDown();
}
/// Define serialization templates for references
template <class T>
void OSWriteDataType(IObjectStreamOut &ioStream, Ref<T> *)
{
OSWriteDataType(ioStream, static_cast<T *>(nullptr));
}
template <class T>
void OSWriteData(IObjectStreamOut &ioStream, const Ref<T> &inRef)
{
if (inRef != nullptr)
ioStream.WritePointerData(GetRTTI(inRef.GetPtr()), inRef.GetPtr());
else
ioStream.WritePointerData(nullptr, nullptr);
}
template <class T>
void OSWriteDataType(IObjectStreamOut &ioStream, RefConst<T> *)
{
OSWriteDataType(ioStream, static_cast<T *>(nullptr));
}
template <class T>
void OSWriteData(IObjectStreamOut &ioStream, const RefConst<T> &inRef)
{
if (inRef != nullptr)
ioStream.WritePointerData(GetRTTI(inRef.GetPtr()), inRef.GetPtr());
else
ioStream.WritePointerData(nullptr, nullptr);
}
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,252 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#ifdef JPH_OBJECT_STREAM
#include <Jolt/ObjectStream/ObjectStreamBinaryIn.h>
JPH_NAMESPACE_BEGIN
ObjectStreamBinaryIn::ObjectStreamBinaryIn(istream &inStream) :
ObjectStreamIn(inStream)
{
}
bool ObjectStreamBinaryIn::ReadDataType(EOSDataType &outType)
{
uint32 type;
mStream.read((char *)&type, sizeof(type));
if (mStream.fail()) return false;
outType = (EOSDataType)type;
return true;
}
bool ObjectStreamBinaryIn::ReadName(String &outName)
{
return ReadPrimitiveData(outName);
}
bool ObjectStreamBinaryIn::ReadIdentifier(Identifier &outIdentifier)
{
Identifier id;
mStream.read((char *)&id, sizeof(id));
if (mStream.fail()) return false;
outIdentifier = id;
return true;
}
bool ObjectStreamBinaryIn::ReadCount(uint32 &outCount)
{
uint32 count;
mStream.read((char *)&count, sizeof(count));
if (mStream.fail()) return false;
outCount = count;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(uint8 &outPrimitive)
{
uint8 primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(uint16 &outPrimitive)
{
uint16 primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(int &outPrimitive)
{
int primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(uint32 &outPrimitive)
{
uint32 primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(uint64 &outPrimitive)
{
uint64 primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(float &outPrimitive)
{
float primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(double &outPrimitive)
{
double primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(bool &outPrimitive)
{
bool primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(String &outPrimitive)
{
// Read length or ID of string
uint32 len;
if (!ReadPrimitiveData(len))
return false;
// Check empty string
if (len == 0)
{
outPrimitive.clear();
return true;
}
// Check if it is an ID in the string table
if (len & 0x80000000)
{
StringTable::iterator i = mStringTable.find(len);
if (i == mStringTable.end())
return false;
outPrimitive = i->second;
return true;
}
// Read the string
char *data = (char *)JPH_STACK_ALLOC(len + 1);
mStream.read(data, len);
if (mStream.fail()) return false;
data[len] = 0;
outPrimitive = data;
// Insert string in table
mStringTable.try_emplace(mNextStringID, outPrimitive);
mNextStringID++;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(Float3 &outPrimitive)
{
Float3 primitive;
mStream.read((char *)&primitive, sizeof(Float3));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(Float4 &outPrimitive)
{
Float4 primitive;
mStream.read((char *)&primitive, sizeof(Float4));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(Double3 &outPrimitive)
{
Double3 primitive;
mStream.read((char *)&primitive, sizeof(Double3));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(Vec3 &outPrimitive)
{
Float3 primitive;
mStream.read((char *)&primitive, sizeof(Float3));
if (mStream.fail()) return false;
outPrimitive = Vec3(primitive); // Use Float3 constructor so that we initialize W too
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(DVec3 &outPrimitive)
{
Double3 primitive;
mStream.read((char *)&primitive, sizeof(Double3));
if (mStream.fail()) return false;
outPrimitive = DVec3(primitive); // Use Float3 constructor so that we initialize W too
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(Vec4 &outPrimitive)
{
Vec4 primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(UVec4 &outPrimitive)
{
UVec4 primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(Quat &outPrimitive)
{
Quat primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(Mat44 &outPrimitive)
{
Mat44 primitive;
mStream.read((char *)&primitive, sizeof(primitive));
if (mStream.fail()) return false;
outPrimitive = primitive;
return true;
}
bool ObjectStreamBinaryIn::ReadPrimitiveData(DMat44 &outPrimitive)
{
Vec4 c0, c1, c2;
DVec3 c3;
if (!ReadPrimitiveData(c0) || !ReadPrimitiveData(c1) || !ReadPrimitiveData(c2) || !ReadPrimitiveData(c3))
return false;
outPrimitive = DMat44(c0, c1, c2, c3);
return true;
}
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,57 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/ObjectStreamIn.h>
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
/// Implementation of ObjectStream binary input stream.
class JPH_EXPORT ObjectStreamBinaryIn : public ObjectStreamIn
{
public:
JPH_OVERRIDE_NEW_DELETE
/// Constructor
explicit ObjectStreamBinaryIn(istream &inStream);
///@name Input type specific operations
virtual bool ReadDataType(EOSDataType &outType) override;
virtual bool ReadName(String &outName) override;
virtual bool ReadIdentifier(Identifier &outIdentifier) override;
virtual bool ReadCount(uint32 &outCount) override;
virtual bool ReadPrimitiveData(uint8 &outPrimitive) override;
virtual bool ReadPrimitiveData(uint16 &outPrimitive) override;
virtual bool ReadPrimitiveData(int &outPrimitive) override;
virtual bool ReadPrimitiveData(uint32 &outPrimitive) override;
virtual bool ReadPrimitiveData(uint64 &outPrimitive) override;
virtual bool ReadPrimitiveData(float &outPrimitive) override;
virtual bool ReadPrimitiveData(double &outPrimitive) override;
virtual bool ReadPrimitiveData(bool &outPrimitive) override;
virtual bool ReadPrimitiveData(String &outPrimitive) override;
virtual bool ReadPrimitiveData(Float3 &outPrimitive) override;
virtual bool ReadPrimitiveData(Float4 &outPrimitive) override;
virtual bool ReadPrimitiveData(Double3 &outPrimitive) override;
virtual bool ReadPrimitiveData(Vec3 &outPrimitive) override;
virtual bool ReadPrimitiveData(DVec3 &outPrimitive) override;
virtual bool ReadPrimitiveData(Vec4 &outPrimitive) override;
virtual bool ReadPrimitiveData(UVec4 &outPrimitive) override;
virtual bool ReadPrimitiveData(Quat &outPrimitive) override;
virtual bool ReadPrimitiveData(Mat44 &outPrimitive) override;
virtual bool ReadPrimitiveData(DMat44 &outPrimitive) override;
private:
using StringTable = UnorderedMap<uint32, String>;
StringTable mStringTable;
uint32 mNextStringID = 0x80000000;
};
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,165 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#ifdef JPH_OBJECT_STREAM
#include <Jolt/ObjectStream/ObjectStreamBinaryOut.h>
#include <Jolt/Core/StringTools.h>
JPH_NAMESPACE_BEGIN
ObjectStreamBinaryOut::ObjectStreamBinaryOut(ostream &inStream) :
ObjectStreamOut(inStream)
{
String header;
header = StringFormat("BOS%2d.%02d", ObjectStream::sVersion, ObjectStream::sRevision);
mStream.write(header.c_str(), header.size());
}
void ObjectStreamBinaryOut::WriteDataType(EOSDataType inType)
{
mStream.write((const char *)&inType, sizeof(inType));
}
void ObjectStreamBinaryOut::WriteName(const char *inName)
{
WritePrimitiveData(String(inName));
}
void ObjectStreamBinaryOut::WriteIdentifier(Identifier inIdentifier)
{
mStream.write((const char *)&inIdentifier, sizeof(inIdentifier));
}
void ObjectStreamBinaryOut::WriteCount(uint32 inCount)
{
mStream.write((const char *)&inCount, sizeof(inCount));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const uint8 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const uint16 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const int &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const uint32 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const uint64 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const float &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const double &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const bool &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const String &inPrimitive)
{
// Empty strings are trivial
if (inPrimitive.empty())
{
WritePrimitiveData((uint32)0);
return;
}
// Check if we've already written this string
StringTable::iterator i = mStringTable.find(inPrimitive);
if (i != mStringTable.end())
{
WritePrimitiveData(i->second);
return;
}
// Insert string in table
mStringTable.try_emplace(inPrimitive, mNextStringID);
mNextStringID++;
// Write string
uint32 len = min((uint32)inPrimitive.size(), (uint32)0x7fffffff);
WritePrimitiveData(len);
mStream.write(inPrimitive.c_str(), len);
}
void ObjectStreamBinaryOut::WritePrimitiveData(const Float3 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(Float3));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const Float4 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(Float4));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const Double3 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(Double3));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const Vec3 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, 3 * sizeof(float));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const DVec3 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, 3 * sizeof(double));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const Vec4 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const UVec4 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const Quat &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const Mat44 &inPrimitive)
{
mStream.write((const char *)&inPrimitive, sizeof(inPrimitive));
}
void ObjectStreamBinaryOut::WritePrimitiveData(const DMat44 &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetColumn4(0));
WritePrimitiveData(inPrimitive.GetColumn4(1));
WritePrimitiveData(inPrimitive.GetColumn4(2));
WritePrimitiveData(inPrimitive.GetTranslation());
}
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,57 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/ObjectStreamOut.h>
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
/// Implementation of ObjectStream binary output stream.
class JPH_EXPORT ObjectStreamBinaryOut : public ObjectStreamOut
{
public:
JPH_OVERRIDE_NEW_DELETE
/// Constructor and destructor
explicit ObjectStreamBinaryOut(ostream &inStream);
///@name Output type specific operations
virtual void WriteDataType(EOSDataType inType) override;
virtual void WriteName(const char *inName) override;
virtual void WriteIdentifier(Identifier inIdentifier) override;
virtual void WriteCount(uint32 inCount) override;
virtual void WritePrimitiveData(const uint8 &inPrimitive) override;
virtual void WritePrimitiveData(const uint16 &inPrimitive) override;
virtual void WritePrimitiveData(const int &inPrimitive) override;
virtual void WritePrimitiveData(const uint32 &inPrimitive) override;
virtual void WritePrimitiveData(const uint64 &inPrimitive) override;
virtual void WritePrimitiveData(const float &inPrimitive) override;
virtual void WritePrimitiveData(const double &inPrimitive) override;
virtual void WritePrimitiveData(const bool &inPrimitive) override;
virtual void WritePrimitiveData(const String &inPrimitive) override;
virtual void WritePrimitiveData(const Float3 &inPrimitive) override;
virtual void WritePrimitiveData(const Float4 &inPrimitive) override;
virtual void WritePrimitiveData(const Double3 &inPrimitive) override;
virtual void WritePrimitiveData(const Vec3 &inPrimitive) override;
virtual void WritePrimitiveData(const DVec3 &inPrimitive) override;
virtual void WritePrimitiveData(const Vec4 &inPrimitive) override;
virtual void WritePrimitiveData(const UVec4 &inPrimitive) override;
virtual void WritePrimitiveData(const Quat &inPrimitive) override;
virtual void WritePrimitiveData(const Mat44 &inPrimitive) override;
virtual void WritePrimitiveData(const DMat44 &inPrimitive) override;
private:
using StringTable = UnorderedMap<String, uint32>;
StringTable mStringTable;
uint32 mNextStringID = 0x80000000;
};
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,635 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#ifdef JPH_OBJECT_STREAM
#include <Jolt/ObjectStream/ObjectStreamIn.h>
#include <Jolt/Core/Factory.h>
#include <Jolt/Core/UnorderedSet.h>
#include <Jolt/ObjectStream/ObjectStreamTextIn.h>
#include <Jolt/ObjectStream/ObjectStreamBinaryIn.h>
#include <Jolt/ObjectStream/SerializableObject.h>
JPH_NAMESPACE_BEGIN
ObjectStreamIn::ObjectStreamIn(istream &inStream) :
mStream(inStream)
{
}
bool ObjectStreamIn::GetInfo(istream &inStream, EStreamType &outType, int &outVersion, int &outRevision)
{
// Read header and check if it is the correct format, e.g. "TOS 1.00"
char header[9];
memset(header, 0, 9);
inStream.read(header, 8);
if ((header[0] == 'B' || header[0] == 'T') && header[1] == 'O' && header[2] == 'S'
&& (header[3] == ' ' || isdigit(header[3])) && isdigit(header[4])
&& header[5] == '.' && isdigit(header[6]) && isdigit(header[7]))
{
// Check if this is a binary or text objectfile
switch (header[0])
{
case 'T': outType = ObjectStream::EStreamType::Text; break;
case 'B': outType = ObjectStream::EStreamType::Binary; break;
default: JPH_ASSERT(false); break;
}
// Extract version and revision
header[5] = '\0';
outVersion = atoi(&header[3]);
outRevision = atoi(&header[6]);
return true;
}
Trace("ObjectStreamIn: Not a valid object stream.");
return false;
}
ObjectStreamIn *ObjectStreamIn::Open(istream &inStream)
{
// Check if file is an ObjectStream of the correct version and revision
EStreamType type;
int version;
int revision;
if (GetInfo(inStream, type, version, revision))
{
if (version == sVersion && revision == sRevision)
{
// Create an input stream of the correct type
switch (type)
{
case EStreamType::Text: return new ObjectStreamTextIn(inStream);
case EStreamType::Binary: return new ObjectStreamBinaryIn(inStream);
default: JPH_ASSERT(false);
}
}
else
{
Trace("ObjectStreamIn: Different version stream (%d.%02d, expected %d.%02d).", version, revision, sVersion, sRevision);
}
}
return nullptr;
}
void *ObjectStreamIn::Read(const RTTI *inRTTI)
{
using ObjectSet = UnorderedSet<void *>;
// Read all information on the stream
void *main_object = nullptr;
bool continue_reading = true;
for (;;)
{
// Get type of next operation
EOSDataType data_type;
if (!ReadDataType(data_type))
break;
if (data_type == EOSDataType::Declare)
{
// Read type declaration
if (!ReadRTTI())
{
Trace("ObjectStreamIn: Fatal error while reading class description for class %s.", inRTTI->GetName());
continue_reading = false;
break;
}
}
else if (data_type == EOSDataType::Object)
{
const RTTI *rtti;
void *object = ReadObject(rtti);
if (!main_object && object)
{
// This is the first and thus main object of the file.
if (rtti->IsKindOf(inRTTI))
{
// Object is of correct type
main_object = object;
}
else
{
Trace("ObjectStreamIn: Main object of different type. Expected %s, but found %s.", inRTTI->GetName(), rtti->GetName());
continue_reading = false;
break;
}
}
}
else
{
// Invalid or out of place token found
Trace("ObjectStreamIn: Invalid or out of place token found.");
continue_reading = false;
break;
}
}
// Resolve links (pointer, references)
if (continue_reading)
{
// Resolve links
ObjectSet referenced_objects;
for (Link &link : mUnresolvedLinks)
{
IdentifierMap::const_iterator j = mIdentifierMap.find(link.mIdentifier);
if (j != mIdentifierMap.end() && j->second.mRTTI->IsKindOf(link.mRTTI))
{
const ObjectInfo &obj_info = j->second;
// Set pointer
*link.mPointer = obj_info.mInstance;
// Increment refcount if it was a referencing pointer
if (link.mRefCountOffset != -1)
++(*(uint32 *)(((uint8 *)obj_info.mInstance) + link.mRefCountOffset));
// Add referenced object to the list
if (referenced_objects.find(obj_info.mInstance) == referenced_objects.end())
referenced_objects.insert(obj_info.mInstance);
}
else
{
// Referenced object not found, set pointer to nullptr
Trace("ObjectStreamIn: Setting incorrect pointer to class of type %s to nullptr.", link.mRTTI->GetName());
*link.mPointer = nullptr;
}
}
// Release unreferenced objects except the main object
for (const IdentifierMap::value_type &j : mIdentifierMap)
{
const ObjectInfo &obj_info = j.second;
if (obj_info.mInstance != main_object)
{
ObjectSet::const_iterator k = referenced_objects.find(obj_info.mInstance);
if (k == referenced_objects.end())
{
Trace("ObjectStreamIn: Releasing unreferenced object of type %s.", obj_info.mRTTI->GetName());
obj_info.mRTTI->DestructObject(obj_info.mInstance);
}
}
}
return main_object;
}
else
{
// Release all objects if a fatal error occurred
for (const IdentifierMap::value_type &i : mIdentifierMap)
{
const ObjectInfo &obj_info = i.second;
obj_info.mRTTI->DestructObject(obj_info.mInstance);
}
return nullptr;
}
}
void *ObjectStreamIn::ReadObject(const RTTI *& outRTTI)
{
// Read the object class
void *object = nullptr;
String class_name;
if (ReadName(class_name))
{
// Get class description
ClassDescriptionMap::iterator i = mClassDescriptionMap.find(class_name);
if (i != mClassDescriptionMap.end())
{
const ClassDescription &class_desc = i->second;
// Read object identifier
Identifier identifier;
if (ReadIdentifier(identifier))
{
// Check if this object can be read or must be skipped
if (identifier != sNullIdentifier
&& class_desc.mRTTI
&& !class_desc.mRTTI->IsAbstract())
{
// Create object instance
outRTTI = class_desc.mRTTI;
object = outRTTI->CreateObject();
// Read object attributes
if (ReadClassData(class_desc, object))
{
// Add object to identifier map
mIdentifierMap.try_emplace(identifier, object, outRTTI);
}
else
{
// Fatal error while reading attributes, release object
outRTTI->DestructObject(object);
object = nullptr;
}
}
else
{
// Skip this object
// TODO: This operation can fail, but there is no check yet
Trace("ObjectStreamIn: Found uncreatable object %s.", class_name.c_str());
ReadClassData(class_desc, nullptr);
}
}
}
else
{
// TODO: This is a fatal error, but this function has no way of indicating this
Trace("ObjectStreamIn: Found object of unknown class %s.", class_name.c_str());
}
}
return object;
}
bool ObjectStreamIn::ReadRTTI()
{
// Read class name and find it's attribute info
String class_name;
if (!ReadName(class_name))
return false;
// Find class
const RTTI *rtti = Factory::sInstance->Find(class_name.c_str());
if (rtti == nullptr)
Trace("ObjectStreamIn: Unknown class: \"%s\".", class_name.c_str());
// Insert class description
ClassDescription &class_desc = mClassDescriptionMap.try_emplace(class_name, rtti).first->second;
// Read the number of entries in the description
uint32 count;
if (!ReadCount(count))
return false;
// Read the entries
for (uint32 i = 0; i < count; ++i)
{
AttributeDescription attribute;
// Read name
String attribute_name;
if (!ReadName(attribute_name))
return false;
// Read type
if (!ReadDataType(attribute.mSourceType))
return false;
// Read array depth
while (attribute.mSourceType == EOSDataType::Array)
{
++attribute.mArrayDepth;
if (!ReadDataType(attribute.mSourceType))
return false;
}
// Read instance/pointer class name
if ((attribute.mSourceType == EOSDataType::Instance || attribute.mSourceType == EOSDataType::Pointer)
&& !ReadName(attribute.mClassName))
return false;
// Find attribute in rtti
if (rtti)
{
// Find attribute index
for (int idx = 0; idx < rtti->GetAttributeCount(); ++idx)
{
const SerializableAttribute &attr = rtti->GetAttribute(idx);
if (attribute_name.compare(attr.GetName()) == 0)
{
attribute.mIndex = idx;
break;
}
}
// Check if attribute is of expected type
if (attribute.mIndex >= 0)
{
const SerializableAttribute &attr = rtti->GetAttribute(attribute.mIndex);
if (attr.IsType(attribute.mArrayDepth, attribute.mSourceType, attribute.mClassName.c_str()))
{
// No conversion needed
attribute.mDestinationType = attribute.mSourceType;
}
else if (attribute.mArrayDepth == 0 && attribute.mClassName.empty())
{
// Try to apply type conversions
if (attribute.mSourceType == EOSDataType::T_Vec3 && attr.IsType(0, EOSDataType::T_DVec3, ""))
attribute.mDestinationType = EOSDataType::T_DVec3;
else if (attribute.mSourceType == EOSDataType::T_DVec3 && attr.IsType(0, EOSDataType::T_Vec3, ""))
attribute.mDestinationType = EOSDataType::T_Vec3;
else
attribute.mIndex = -1;
}
else
{
// No conversion exists
attribute.mIndex = -1;
}
}
}
// Add attribute to the class description
class_desc.mAttributes.push_back(attribute);
}
return true;
}
bool ObjectStreamIn::ReadClassData(const char *inClassName, void *inInstance)
{
// Find the class description
ClassDescriptionMap::iterator i = mClassDescriptionMap.find(inClassName);
if (i != mClassDescriptionMap.end())
return ReadClassData(i->second, inInstance);
return false;
}
bool ObjectStreamIn::ReadClassData(const ClassDescription &inClassDesc, void *inInstance)
{
// Read data for this class
bool continue_reading = true;
for (const AttributeDescription &attr_desc : inClassDesc.mAttributes)
{
// Read or skip the attribute data
if (attr_desc.mIndex >= 0 && inInstance)
{
const SerializableAttribute &attr = inClassDesc.mRTTI->GetAttribute(attr_desc.mIndex);
if (attr_desc.mSourceType == attr_desc.mDestinationType)
{
continue_reading = attr.ReadData(*this, inInstance);
}
else if (attr_desc.mSourceType == EOSDataType::T_Vec3 && attr_desc.mDestinationType == EOSDataType::T_DVec3)
{
// Vec3 to DVec3
Vec3 tmp;
continue_reading = ReadPrimitiveData(tmp);
if (continue_reading)
*attr.GetMemberPointer<DVec3>(inInstance) = DVec3(tmp);
}
else if (attr_desc.mSourceType == EOSDataType::T_DVec3 && attr_desc.mDestinationType == EOSDataType::T_Vec3)
{
// DVec3 to Vec3
DVec3 tmp;
continue_reading = ReadPrimitiveData(tmp);
if (continue_reading)
*attr.GetMemberPointer<Vec3>(inInstance) = Vec3(tmp);
}
else
{
JPH_ASSERT(false); // Unknown conversion
continue_reading = SkipAttributeData(attr_desc.mArrayDepth, attr_desc.mSourceType, attr_desc.mClassName.c_str());
}
}
else
continue_reading = SkipAttributeData(attr_desc.mArrayDepth, attr_desc.mSourceType, attr_desc.mClassName.c_str());
if (!continue_reading)
break;
}
return continue_reading;
}
bool ObjectStreamIn::ReadPointerData(const RTTI *inRTTI, void **inPointer, int inRefCountOffset)
{
Identifier identifier;
if (ReadIdentifier(identifier))
{
if (identifier == sNullIdentifier)
{
// Set nullptr pointer
inPointer = nullptr;
}
else
{
// Put pointer on the list to be resolved later on
Link &link = mUnresolvedLinks.emplace_back();
link.mPointer = inPointer;
link.mRefCountOffset = inRefCountOffset;
link.mIdentifier = identifier;
link.mRTTI = inRTTI;
}
return true;
}
return false;
}
bool ObjectStreamIn::SkipAttributeData(int inArrayDepth, EOSDataType inDataType, const char *inClassName)
{
bool continue_reading = true;
// Get number of items to read
uint32 count = 1;
for (; inArrayDepth > 0; --inArrayDepth)
{
uint32 temporary;
if (ReadCount(temporary))
{
// Multiply for multi dimensional arrays
count *= temporary;
}
else
{
// Fatal error while reading array size
continue_reading = false;
break;
}
}
// Read data for all items
if (continue_reading)
{
if (inDataType == EOSDataType::Instance)
{
// Get the class description
ClassDescriptionMap::iterator i = mClassDescriptionMap.find(inClassName);
if (i != mClassDescriptionMap.end())
{
for (; count > 0 && continue_reading; --count)
continue_reading = ReadClassData(i->second, nullptr);
}
else
{
continue_reading = false;
Trace("ObjectStreamIn: Found instance of unknown class %s.", inClassName);
}
}
else
{
for (; count > 0 && continue_reading; --count)
{
switch (inDataType)
{
case EOSDataType::Pointer:
{
Identifier temporary;
continue_reading = ReadIdentifier(temporary);
break;
}
case EOSDataType::T_uint8:
{
uint8 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_uint16:
{
uint16 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_int:
{
int temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_uint32:
{
uint32 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_uint64:
{
uint64 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_float:
{
float temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_double:
{
double temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_bool:
{
bool temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_String:
{
String temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_Float3:
{
Float3 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_Float4:
{
Float4 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_Double3:
{
Double3 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_Vec3:
{
Vec3 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_DVec3:
{
DVec3 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_Vec4:
{
Vec4 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_UVec4:
{
UVec4 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_Quat:
{
Quat temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_Mat44:
{
Mat44 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::T_DMat44:
{
DMat44 temporary;
continue_reading = ReadPrimitiveData(temporary);
break;
}
case EOSDataType::Array:
case EOSDataType::Object:
case EOSDataType::Declare:
case EOSDataType::Instance:
case EOSDataType::Invalid:
default:
continue_reading = false;
break;
}
}
}
}
return continue_reading;
}
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,148 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/ObjectStream.h>
#include <Jolt/Core/Reference.h>
#include <Jolt/Core/RTTI.h>
#include <Jolt/Core/UnorderedMap.h>
JPH_SUPPRESS_WARNINGS_STD_BEGIN
#include <fstream>
JPH_SUPPRESS_WARNINGS_STD_END
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
/// ObjectStreamIn contains all logic for reading an object from disk. It is the base
/// class for the text and binary input streams (ObjectStreamTextIn and ObjectStreamBinaryIn).
class JPH_EXPORT ObjectStreamIn : public IObjectStreamIn
{
private:
struct ClassDescription;
public:
/// Main function to read an object from a stream
template <class T>
static bool sReadObject(istream &inStream, T *&outObject)
{
// Create the input stream
bool result = false;
ObjectStreamIn *stream = ObjectStreamIn::Open(inStream);
if (stream)
{
// Read the object
outObject = (T *)stream->Read(JPH_RTTI(T));
result = (outObject != nullptr);
delete stream;
}
return result;
}
/// Main function to read an object from a stream (reference counting pointer version)
template <class T>
static bool sReadObject(istream &inStream, Ref<T> &outObject)
{
T *object = nullptr;
bool result = sReadObject(inStream, object);
outObject = object;
return result;
}
/// Main function to read an object from a file
template <class T>
static bool sReadObject(const char *inFileName, T *&outObject)
{
std::ifstream stream;
stream.open(inFileName, std::ifstream::in | std::ifstream::binary);
if (!stream.is_open())
return false;
return sReadObject(stream, outObject);
}
/// Main function to read an object from a file (reference counting pointer version)
template <class T>
static bool sReadObject(const char *inFileName, Ref<T> &outObject)
{
T *object = nullptr;
bool result = sReadObject(inFileName, object);
outObject = object;
return result;
}
//////////////////////////////////////////////////////
// EVERYTHING BELOW THIS SHOULD NOT DIRECTLY BE CALLED
//////////////////////////////////////////////////////
///@name Serialization operations
void * Read(const RTTI *inRTTI);
void * ReadObject(const RTTI *& outRTTI);
bool ReadRTTI();
virtual bool ReadClassData(const char *inClassName, void *inInstance) override;
bool ReadClassData(const ClassDescription &inClassDesc, void *inInstance);
virtual bool ReadPointerData(const RTTI *inRTTI, void **inPointer, int inRefCountOffset = -1) override;
bool SkipAttributeData(int inArrayDepth, EOSDataType inDataType, const char *inClassName);
protected:
/// Constructor
explicit ObjectStreamIn(istream &inStream);
/// Determine the type and version of an object stream
static bool GetInfo(istream &inStream, EStreamType &outType, int &outVersion, int &outRevision);
/// Static constructor
static ObjectStreamIn * Open(istream &inStream);
istream & mStream;
private:
/// Class descriptions
struct AttributeDescription
{
int mArrayDepth = 0;
EOSDataType mSourceType = EOSDataType::Invalid;
EOSDataType mDestinationType = EOSDataType::Invalid;
String mClassName;
int mIndex = -1;
};
struct ClassDescription
{
ClassDescription() = default;
explicit ClassDescription(const RTTI *inRTTI) : mRTTI(inRTTI) { }
const RTTI * mRTTI = nullptr;
Array<AttributeDescription> mAttributes;
};
struct ObjectInfo
{
ObjectInfo() = default;
ObjectInfo(void *inInstance, const RTTI *inRTTI) : mInstance(inInstance), mRTTI(inRTTI) { }
void * mInstance = nullptr;
const RTTI * mRTTI = nullptr;
};
struct Link
{
void ** mPointer;
int mRefCountOffset;
Identifier mIdentifier;
const RTTI * mRTTI;
};
using IdentifierMap = UnorderedMap<Identifier, ObjectInfo>;
using ClassDescriptionMap = UnorderedMap<String, ClassDescription>;
ClassDescriptionMap mClassDescriptionMap;
IdentifierMap mIdentifierMap; ///< Links identifier to an object pointer
Array<Link> mUnresolvedLinks; ///< All pointers (links) are resolved after reading the entire file, e.g. when all object exist
};
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,166 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/ObjectStream/ObjectStreamOut.h>
#include <Jolt/ObjectStream/ObjectStreamTextOut.h>
#include <Jolt/ObjectStream/ObjectStreamBinaryOut.h>
#include <Jolt/ObjectStream/TypeDeclarations.h>
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
ObjectStreamOut::ObjectStreamOut(ostream &inStream) :
mStream(inStream)
{
// Add all primitives to the class set
#define JPH_DECLARE_PRIMITIVE(name) mClassSet.insert(JPH_RTTI(name));
#include <Jolt/ObjectStream/ObjectStreamTypes.h>
}
ObjectStreamOut *ObjectStreamOut::Open(EStreamType inType, ostream &inStream)
{
switch (inType)
{
case EStreamType::Text: return new ObjectStreamTextOut(inStream);
case EStreamType::Binary: return new ObjectStreamBinaryOut(inStream);
default: JPH_ASSERT(false);
}
return nullptr;
}
bool ObjectStreamOut::Write(const void *inObject, const RTTI *inRTTI)
{
// Assign a new identifier to the object and write it
mIdentifierMap.try_emplace(inObject, mNextIdentifier, inRTTI);
mNextIdentifier++;
WriteObject(inObject);
// Write all linked objects
ObjectQueue::size_type cur = 0;
for (; cur < mObjectQueue.size() && !mStream.fail(); ++cur)
WriteObject(mObjectQueue[cur]);
mObjectQueue.erase(mObjectQueue.begin(), mObjectQueue.begin() + cur);
return !mStream.fail();
}
void ObjectStreamOut::WriteObject(const void *inObject)
{
// Find object identifier
IdentifierMap::iterator i = mIdentifierMap.find(inObject);
JPH_ASSERT(i != mIdentifierMap.end());
// Write class description and associated descriptions
QueueRTTI(i->second.mRTTI);
ClassQueue::size_type cur = 0;
for (; cur < mClassQueue.size() && !mStream.fail(); ++cur)
WriteRTTI(mClassQueue[cur]);
mClassQueue.erase(mClassQueue.begin(), mClassQueue.begin() + cur);
HintNextItem();
HintNextItem();
// Write object header.
WriteDataType(EOSDataType::Object);
WriteName(i->second.mRTTI->GetName());
WriteIdentifier(i->second.mIdentifier);
// Write attribute data
WriteClassData(i->second.mRTTI, inObject);
}
void ObjectStreamOut::QueueRTTI(const RTTI *inRTTI)
{
ClassSet::const_iterator i = mClassSet.find(inRTTI);
if (i == mClassSet.end())
{
mClassSet.insert(inRTTI);
mClassQueue.push_back(inRTTI);
}
}
void ObjectStreamOut::WriteRTTI(const RTTI *inRTTI)
{
HintNextItem();
HintNextItem();
// Write class header. E.g. in text mode: "class <name> <attr-count>"
WriteDataType(EOSDataType::Declare);
WriteName(inRTTI->GetName());
WriteCount(inRTTI->GetAttributeCount());
// Write class attribute info
HintIndentUp();
for (int attr_index = 0; attr_index < inRTTI->GetAttributeCount(); ++attr_index)
{
// Get attribute
const SerializableAttribute &attr = inRTTI->GetAttribute(attr_index);
// Write definition of attribute class if undefined
const RTTI *rtti = attr.GetMemberPrimitiveType();
if (rtti != nullptr)
QueueRTTI(rtti);
HintNextItem();
// Write attribute information.
WriteName(attr.GetName());
attr.WriteDataType(*this);
}
HintIndentDown();
}
void ObjectStreamOut::WriteClassData(const RTTI *inRTTI, const void *inInstance)
{
JPH_ASSERT(inInstance);
// Write attributes
HintIndentUp();
for (int attr_index = 0; attr_index < inRTTI->GetAttributeCount(); ++attr_index)
{
// Get attribute
const SerializableAttribute &attr = inRTTI->GetAttribute(attr_index);
attr.WriteData(*this, inInstance);
}
HintIndentDown();
}
void ObjectStreamOut::WritePointerData(const RTTI *inRTTI, const void *inPointer)
{
Identifier identifier;
if (inPointer)
{
// Check if this object has an identifier
IdentifierMap::iterator i = mIdentifierMap.find(inPointer);
if (i != mIdentifierMap.end())
{
// Object already has an identifier
identifier = i->second.mIdentifier;
}
else
{
// Assign a new identifier to this object and queue it for serialization
identifier = mNextIdentifier++;
mIdentifierMap.try_emplace(inPointer, identifier, inRTTI);
mObjectQueue.push_back(inPointer);
}
}
else
{
// Write nullptr pointer
identifier = sNullIdentifier;
}
// Write the identifier
HintNextItem();
WriteIdentifier(identifier);
}
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,101 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/ObjectStream.h>
#include <Jolt/Core/RTTI.h>
#include <Jolt/Core/UnorderedMap.h>
#include <Jolt/Core/UnorderedSet.h>
JPH_SUPPRESS_WARNINGS_STD_BEGIN
#include <fstream>
JPH_SUPPRESS_WARNINGS_STD_END
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
/// ObjectStreamOut contains all logic for writing an object to disk. It is the base
/// class for the text and binary output streams (ObjectStreamTextOut and ObjectStreamBinaryOut).
class JPH_EXPORT ObjectStreamOut : public IObjectStreamOut
{
private:
struct ObjectInfo;
public:
/// Main function to write an object to a stream
template <class T>
static bool sWriteObject(ostream &inStream, ObjectStream::EStreamType inType, const T &inObject)
{
// Create the output stream
bool result = false;
ObjectStreamOut *stream = ObjectStreamOut::Open(inType, inStream);
if (stream)
{
// Write the object to the stream
result = stream->Write((void *)&inObject, GetRTTI(&inObject));
delete stream;
}
return result;
}
/// Main function to write an object to a file
template <class T>
static bool sWriteObject(const char *inFileName, ObjectStream::EStreamType inType, const T &inObject)
{
std::ofstream stream;
stream.open(inFileName, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
if (!stream.is_open())
return false;
return sWriteObject(stream, inType, inObject);
}
//////////////////////////////////////////////////////
// EVERYTHING BELOW THIS SHOULD NOT DIRECTLY BE CALLED
//////////////////////////////////////////////////////
///@name Serialization operations
bool Write(const void *inObject, const RTTI *inRTTI);
void WriteObject(const void *inObject);
void QueueRTTI(const RTTI *inRTTI);
void WriteRTTI(const RTTI *inRTTI);
virtual void WriteClassData(const RTTI *inRTTI, const void *inInstance) override;
virtual void WritePointerData(const RTTI *inRTTI, const void *inPointer) override;
protected:
/// Static constructor
static ObjectStreamOut * Open(EStreamType inType, ostream &inStream);
/// Constructor
explicit ObjectStreamOut(ostream &inStream);
ostream & mStream;
private:
struct ObjectInfo
{
ObjectInfo() : mIdentifier(0), mRTTI(nullptr) { }
ObjectInfo(Identifier inIdentifier, const RTTI *inRTTI) : mIdentifier(inIdentifier), mRTTI(inRTTI) { }
Identifier mIdentifier;
const RTTI * mRTTI;
};
using IdentifierMap = UnorderedMap<const void *, ObjectInfo>;
using ClassSet = UnorderedSet<const RTTI *>;
using ObjectQueue = Array<const void *>;
using ClassQueue = Array<const RTTI *>;
Identifier mNextIdentifier = sNullIdentifier + 1; ///< Next free identifier for this stream
IdentifierMap mIdentifierMap; ///< Links object pointer to an identifier
ObjectQueue mObjectQueue; ///< Queue of objects to be written
ClassSet mClassSet; ///< List of classes already written
ClassQueue mClassQueue; ///< List of classes waiting to be written
};
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,418 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#ifdef JPH_OBJECT_STREAM
#include <Jolt/ObjectStream/ObjectStreamTextIn.h>
JPH_NAMESPACE_BEGIN
ObjectStreamTextIn::ObjectStreamTextIn(istream &inStream) :
ObjectStreamIn(inStream)
{
}
bool ObjectStreamTextIn::ReadDataType(EOSDataType &outType)
{
String token;
if (ReadWord(token))
{
transform(token.begin(), token.end(), token.begin(), [](char inValue) { return (char)tolower(inValue); });
if (token == "declare")
outType = EOSDataType::Declare;
else if (token == "object")
outType = EOSDataType::Object;
else if (token == "instance")
outType = EOSDataType::Instance;
else if (token == "pointer")
outType = EOSDataType::Pointer;
else if (token == "array")
outType = EOSDataType::Array;
else if (token == "uint8")
outType = EOSDataType::T_uint8;
else if (token == "uint16")
outType = EOSDataType::T_uint16;
else if (token == "int")
outType = EOSDataType::T_int;
else if (token == "uint32")
outType = EOSDataType::T_uint32;
else if (token == "uint64")
outType = EOSDataType::T_uint64;
else if (token == "float")
outType = EOSDataType::T_float;
else if (token == "double")
outType = EOSDataType::T_double;
else if (token == "bool")
outType = EOSDataType::T_bool;
else if (token == "string")
outType = EOSDataType::T_String;
else if (token == "float3")
outType = EOSDataType::T_Float3;
else if (token == "float4")
outType = EOSDataType::T_Float4;
else if (token == "double3")
outType = EOSDataType::T_Double3;
else if (token == "vec3")
outType = EOSDataType::T_Vec3;
else if (token == "dvec3")
outType = EOSDataType::T_DVec3;
else if (token == "vec4")
outType = EOSDataType::T_Vec4;
else if (token == "uvec4")
outType = EOSDataType::T_UVec4;
else if (token == "quat")
outType = EOSDataType::T_Quat;
else if (token == "mat44")
outType = EOSDataType::T_Mat44;
else if (token == "dmat44")
outType = EOSDataType::T_DMat44;
else
{
Trace("ObjectStreamTextIn: Found unknown data type.");
return false;
}
return true;
}
return false;
}
bool ObjectStreamTextIn::ReadName(String &outName)
{
return ReadWord(outName);
}
bool ObjectStreamTextIn::ReadIdentifier(Identifier &outIdentifier)
{
String token;
if (!ReadWord(token))
return false;
outIdentifier = (uint32)std::strtoul(token.c_str(), nullptr, 16);
if (errno == ERANGE)
{
outIdentifier = sNullIdentifier;
return false;
}
return true;
}
bool ObjectStreamTextIn::ReadCount(uint32 &outCount)
{
return ReadPrimitiveData(outCount);
}
bool ObjectStreamTextIn::ReadPrimitiveData(uint8 &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
uint32 temporary;
IStringStream stream(token);
stream >> temporary;
if (!stream.fail())
{
outPrimitive = (uint8)temporary;
return true;
}
return false;
}
bool ObjectStreamTextIn::ReadPrimitiveData(uint16 &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
uint32 temporary;
IStringStream stream(token);
stream >> temporary;
if (!stream.fail())
{
outPrimitive = (uint16)temporary;
return true;
}
return false;
}
bool ObjectStreamTextIn::ReadPrimitiveData(int &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
IStringStream stream(token);
stream >> outPrimitive;
return !stream.fail();
}
bool ObjectStreamTextIn::ReadPrimitiveData(uint32 &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
IStringStream stream(token);
stream >> outPrimitive;
return !stream.fail();
}
bool ObjectStreamTextIn::ReadPrimitiveData(uint64 &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
IStringStream stream(token);
stream >> outPrimitive;
return !stream.fail();
}
bool ObjectStreamTextIn::ReadPrimitiveData(float &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
IStringStream stream(token);
stream >> outPrimitive;
return !stream.fail();
}
bool ObjectStreamTextIn::ReadPrimitiveData(double &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
IStringStream stream(token);
stream >> outPrimitive;
return !stream.fail();
}
bool ObjectStreamTextIn::ReadPrimitiveData(bool &outPrimitive)
{
String token;
if (!ReadWord(token))
return false;
transform(token.begin(), token.end(), token.begin(), [](char inValue) { return (char)tolower(inValue); });
outPrimitive = token == "true";
return outPrimitive || token == "false";
}
bool ObjectStreamTextIn::ReadPrimitiveData(String &outPrimitive)
{
outPrimitive.clear();
char c;
// Skip whitespace
for (;;)
{
if (!ReadChar(c))
return false;
if (!isspace(c))
break;
}
// Check if it is a opening quote
if (c != '\"')
return false;
// Read string and interpret special characters
String result;
bool escaped = false;
for (;;)
{
if (!ReadChar(c))
break;
switch (c)
{
case '\n':
case '\t':
break;
case '\\':
if (escaped)
{
result += '\\';
escaped = false;
}
else
escaped = true;
break;
case 'n':
if (escaped)
{
result += '\n';
escaped = false;
}
else
result += 'n';
break;
case 't':
if (escaped)
{
result += '\t';
escaped = false;
}
else
result += 't';
break;
case '\"':
if (escaped)
{
result += '\"';
escaped = false;
}
else
{
// Found closing double quote
outPrimitive = result;
return true;
}
break;
default:
if (escaped)
escaped = false;
else
result += c;
break;
}
}
return false;
}
bool ObjectStreamTextIn::ReadPrimitiveData(Float3 &outPrimitive)
{
float x, y, z;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z))
return false;
outPrimitive = Float3(x, y, z);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(Float4 &outPrimitive)
{
float x, y, z, w;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z) || !ReadPrimitiveData(w))
return false;
outPrimitive = Float4(x, y, z, w);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(Double3 &outPrimitive)
{
double x, y, z;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z))
return false;
outPrimitive = Double3(x, y, z);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(Vec3 &outPrimitive)
{
float x, y, z;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z))
return false;
outPrimitive = Vec3(x, y, z);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(DVec3 &outPrimitive)
{
double x, y, z;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z))
return false;
outPrimitive = DVec3(x, y, z);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(Vec4 &outPrimitive)
{
float x, y, z, w;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z) || !ReadPrimitiveData(w))
return false;
outPrimitive = Vec4(x, y, z, w);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(UVec4 &outPrimitive)
{
uint32 x, y, z, w;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z) || !ReadPrimitiveData(w))
return false;
outPrimitive = UVec4(x, y, z, w);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(Quat &outPrimitive)
{
float x, y, z, w;
if (!ReadPrimitiveData(x) || !ReadPrimitiveData(y) || !ReadPrimitiveData(z) || !ReadPrimitiveData(w))
return false;
outPrimitive = Quat(x, y, z, w);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(Mat44 &outPrimitive)
{
Vec4 c0, c1, c2, c3;
if (!ReadPrimitiveData(c0) || !ReadPrimitiveData(c1) || !ReadPrimitiveData(c2) || !ReadPrimitiveData(c3))
return false;
outPrimitive = Mat44(c0, c1, c2, c3);
return true;
}
bool ObjectStreamTextIn::ReadPrimitiveData(DMat44 &outPrimitive)
{
Vec4 c0, c1, c2;
DVec3 c3;
if (!ReadPrimitiveData(c0) || !ReadPrimitiveData(c1) || !ReadPrimitiveData(c2) || !ReadPrimitiveData(c3))
return false;
outPrimitive = DMat44(c0, c1, c2, c3);
return true;
}
bool ObjectStreamTextIn::ReadChar(char &outChar)
{
mStream.get(outChar);
return !mStream.eof();
}
bool ObjectStreamTextIn::ReadWord(String &outWord)
{
outWord.clear();
char c;
// Skip whitespace
for (;;)
{
if (!ReadChar(c))
return false;
if (!isspace(c))
break;
}
// Read word
for (;;)
{
outWord += c;
if (!ReadChar(c))
break;
if (isspace(c))
break;
}
return !outWord.empty();
}
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,55 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/ObjectStreamIn.h>
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
/// Implementation of ObjectStream text input stream.
class JPH_EXPORT ObjectStreamTextIn : public ObjectStreamIn
{
public:
JPH_OVERRIDE_NEW_DELETE
/// Constructor
explicit ObjectStreamTextIn(istream &inStream);
///@name Input type specific operations
virtual bool ReadDataType(EOSDataType &outType) override;
virtual bool ReadName(String &outName) override;
virtual bool ReadIdentifier(Identifier &outIdentifier) override;
virtual bool ReadCount(uint32 &outCount) override;
virtual bool ReadPrimitiveData(uint8 &outPrimitive) override;
virtual bool ReadPrimitiveData(uint16 &outPrimitive) override;
virtual bool ReadPrimitiveData(int &outPrimitive) override;
virtual bool ReadPrimitiveData(uint32 &outPrimitive) override;
virtual bool ReadPrimitiveData(uint64 &outPrimitive) override;
virtual bool ReadPrimitiveData(float &outPrimitive) override;
virtual bool ReadPrimitiveData(double &outPrimitive) override;
virtual bool ReadPrimitiveData(bool &outPrimitive) override;
virtual bool ReadPrimitiveData(String &outPrimitive) override;
virtual bool ReadPrimitiveData(Float3 &outPrimitive) override;
virtual bool ReadPrimitiveData(Float4 &outPrimitive) override;
virtual bool ReadPrimitiveData(Double3 &outPrimitive) override;
virtual bool ReadPrimitiveData(Vec3 &outPrimitive) override;
virtual bool ReadPrimitiveData(DVec3 &outPrimitive) override;
virtual bool ReadPrimitiveData(Vec4 &outPrimitive) override;
virtual bool ReadPrimitiveData(UVec4 &outPrimitive) override;
virtual bool ReadPrimitiveData(Quat &outPrimitive) override;
virtual bool ReadPrimitiveData(Mat44 &outPrimitive) override;
virtual bool ReadPrimitiveData(DMat44 &outPrimitive) override;
private:
bool ReadChar(char &outChar);
bool ReadWord(String &outWord);
};
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,255 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#ifdef JPH_OBJECT_STREAM
#include <Jolt/ObjectStream/ObjectStreamTextOut.h>
#include <Jolt/Core/StringTools.h>
JPH_NAMESPACE_BEGIN
ObjectStreamTextOut::ObjectStreamTextOut(ostream &inStream) :
ObjectStreamOut(inStream)
{
WriteWord(StringFormat("TOS%2d.%02d", ObjectStream::sVersion, ObjectStream::sRevision));
}
void ObjectStreamTextOut::WriteDataType(EOSDataType inType)
{
switch (inType)
{
case EOSDataType::Declare: WriteWord("declare "); break;
case EOSDataType::Object: WriteWord("object "); break;
case EOSDataType::Instance: WriteWord("instance "); break;
case EOSDataType::Pointer: WriteWord("pointer "); break;
case EOSDataType::Array: WriteWord("array "); break;
case EOSDataType::T_uint8: WriteWord("uint8"); break;
case EOSDataType::T_uint16: WriteWord("uint16"); break;
case EOSDataType::T_int: WriteWord("int"); break;
case EOSDataType::T_uint32: WriteWord("uint32"); break;
case EOSDataType::T_uint64: WriteWord("uint64"); break;
case EOSDataType::T_float: WriteWord("float"); break;
case EOSDataType::T_double: WriteWord("double"); break;
case EOSDataType::T_bool: WriteWord("bool"); break;
case EOSDataType::T_String: WriteWord("string"); break;
case EOSDataType::T_Float3: WriteWord("float3"); break;
case EOSDataType::T_Float4: WriteWord("float4"); break;
case EOSDataType::T_Double3: WriteWord("double3"); break;
case EOSDataType::T_Vec3: WriteWord("vec3"); break;
case EOSDataType::T_DVec3: WriteWord("dvec3"); break;
case EOSDataType::T_Vec4: WriteWord("vec4"); break;
case EOSDataType::T_UVec4: WriteWord("uvec4"); break;
case EOSDataType::T_Quat: WriteWord("quat"); break;
case EOSDataType::T_Mat44: WriteWord("mat44"); break;
case EOSDataType::T_DMat44: WriteWord("dmat44"); break;
case EOSDataType::Invalid:
default: JPH_ASSERT(false); break;
}
}
void ObjectStreamTextOut::WriteName(const char *inName)
{
WriteWord(String(inName) + " ");
}
void ObjectStreamTextOut::WriteIdentifier(Identifier inIdentifier)
{
WriteWord(StringFormat("%08X", inIdentifier));
}
void ObjectStreamTextOut::WriteCount(uint32 inCount)
{
WriteWord(std::to_string(inCount));
}
void ObjectStreamTextOut::WritePrimitiveData(const uint8 &inPrimitive)
{
WriteWord(std::to_string(inPrimitive));
}
void ObjectStreamTextOut::WritePrimitiveData(const uint16 &inPrimitive)
{
WriteWord(std::to_string(inPrimitive));
}
void ObjectStreamTextOut::WritePrimitiveData(const int &inPrimitive)
{
WriteWord(std::to_string(inPrimitive));
}
void ObjectStreamTextOut::WritePrimitiveData(const uint32 &inPrimitive)
{
WriteWord(std::to_string(inPrimitive));
}
void ObjectStreamTextOut::WritePrimitiveData(const uint64 &inPrimitive)
{
WriteWord(std::to_string(inPrimitive));
}
void ObjectStreamTextOut::WritePrimitiveData(const float &inPrimitive)
{
std::ostringstream stream;
stream.precision(9);
stream << inPrimitive;
WriteWord(stream.str());
}
void ObjectStreamTextOut::WritePrimitiveData(const double &inPrimitive)
{
std::ostringstream stream;
stream.precision(17);
stream << inPrimitive;
WriteWord(stream.str());
}
void ObjectStreamTextOut::WritePrimitiveData(const bool &inPrimitive)
{
WriteWord(inPrimitive? "true" : "false");
}
void ObjectStreamTextOut::WritePrimitiveData(const Float3 &inPrimitive)
{
WritePrimitiveData(inPrimitive.x);
WriteChar(' ');
WritePrimitiveData(inPrimitive.y);
WriteChar(' ');
WritePrimitiveData(inPrimitive.z);
}
void ObjectStreamTextOut::WritePrimitiveData(const Float4 &inPrimitive)
{
WritePrimitiveData(inPrimitive.x);
WriteChar(' ');
WritePrimitiveData(inPrimitive.y);
WriteChar(' ');
WritePrimitiveData(inPrimitive.z);
WriteChar(' ');
WritePrimitiveData(inPrimitive.w);
}
void ObjectStreamTextOut::WritePrimitiveData(const Double3 &inPrimitive)
{
WritePrimitiveData(inPrimitive.x);
WriteChar(' ');
WritePrimitiveData(inPrimitive.y);
WriteChar(' ');
WritePrimitiveData(inPrimitive.z);
}
void ObjectStreamTextOut::WritePrimitiveData(const Vec3 &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetX());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetY());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetZ());
}
void ObjectStreamTextOut::WritePrimitiveData(const DVec3 &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetX());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetY());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetZ());
}
void ObjectStreamTextOut::WritePrimitiveData(const Vec4 &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetX());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetY());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetZ());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetW());
}
void ObjectStreamTextOut::WritePrimitiveData(const UVec4 &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetX());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetY());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetZ());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetW());
}
void ObjectStreamTextOut::WritePrimitiveData(const Quat &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetX());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetY());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetZ());
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetW());
}
void ObjectStreamTextOut::WritePrimitiveData(const Mat44 &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetColumn4(0));
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetColumn4(1));
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetColumn4(2));
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetColumn4(3));
}
void ObjectStreamTextOut::WritePrimitiveData(const DMat44 &inPrimitive)
{
WritePrimitiveData(inPrimitive.GetColumn4(0));
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetColumn4(1));
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetColumn4(2));
WriteChar(' ');
WritePrimitiveData(inPrimitive.GetTranslation());
}
void ObjectStreamTextOut::WritePrimitiveData(const String &inPrimitive)
{
String temporary(inPrimitive);
StringReplace(temporary, "\\", "\\\\");
StringReplace(temporary, "\n", "\\n");
StringReplace(temporary, "\t", "\\t");
StringReplace(temporary, "\"", "\\\"");
WriteWord(String("\"") + temporary + String("\""));
}
void ObjectStreamTextOut::HintNextItem()
{
WriteWord("\r\n");
for (int i = 0; i < mIndentation; ++i)
WriteWord(" ");
}
void ObjectStreamTextOut::HintIndentUp()
{
++mIndentation;
}
void ObjectStreamTextOut::HintIndentDown()
{
--mIndentation;
}
void ObjectStreamTextOut::WriteChar(char inChar)
{
mStream.put(inChar);
}
void ObjectStreamTextOut::WriteWord(const string_view &inWord)
{
mStream << inWord;
}
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,62 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/ObjectStreamOut.h>
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
/// Implementation of ObjectStream text output stream.
class JPH_EXPORT ObjectStreamTextOut : public ObjectStreamOut
{
public:
JPH_OVERRIDE_NEW_DELETE
/// Constructor and destructor
explicit ObjectStreamTextOut(ostream &inStream);
///@name Output type specific operations
virtual void WriteDataType(EOSDataType inType) override;
virtual void WriteName(const char *inName) override;
virtual void WriteIdentifier(Identifier inIdentifier) override;
virtual void WriteCount(uint32 inCount) override;
virtual void WritePrimitiveData(const uint8 &inPrimitive) override;
virtual void WritePrimitiveData(const uint16 &inPrimitive) override;
virtual void WritePrimitiveData(const int &inPrimitive) override;
virtual void WritePrimitiveData(const uint32 &inPrimitive) override;
virtual void WritePrimitiveData(const uint64 &inPrimitive) override;
virtual void WritePrimitiveData(const float &inPrimitive) override;
virtual void WritePrimitiveData(const double &inPrimitive) override;
virtual void WritePrimitiveData(const bool &inPrimitive) override;
virtual void WritePrimitiveData(const String &inPrimitive) override;
virtual void WritePrimitiveData(const Float3 &inPrimitive) override;
virtual void WritePrimitiveData(const Float4 &inPrimitive) override;
virtual void WritePrimitiveData(const Double3 &inPrimitive) override;
virtual void WritePrimitiveData(const Vec3 &inPrimitive) override;
virtual void WritePrimitiveData(const DVec3 &inPrimitive) override;
virtual void WritePrimitiveData(const Vec4 &inPrimitive) override;
virtual void WritePrimitiveData(const UVec4 &inPrimitive) override;
virtual void WritePrimitiveData(const Quat &inPrimitive) override;
virtual void WritePrimitiveData(const Mat44 &inPrimitive) override;
virtual void WritePrimitiveData(const DMat44 &inPrimitive) override;
///@name Layout hints (for text output)
virtual void HintNextItem() override;
virtual void HintIndentUp() override;
virtual void HintIndentDown() override;
private:
void WriteChar(char inChar);
void WriteWord(const string_view &inWord);
int mIndentation = 0;
};
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,26 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
// Note: Order is important, an enum is created and its value is stored in a binary stream!
JPH_DECLARE_PRIMITIVE(uint8)
JPH_DECLARE_PRIMITIVE(uint16)
JPH_DECLARE_PRIMITIVE(int)
JPH_DECLARE_PRIMITIVE(uint32)
JPH_DECLARE_PRIMITIVE(uint64)
JPH_DECLARE_PRIMITIVE(float)
JPH_DECLARE_PRIMITIVE(bool)
JPH_DECLARE_PRIMITIVE(String)
JPH_DECLARE_PRIMITIVE(Float3)
JPH_DECLARE_PRIMITIVE(Vec3)
JPH_DECLARE_PRIMITIVE(Vec4)
JPH_DECLARE_PRIMITIVE(Quat)
JPH_DECLARE_PRIMITIVE(Mat44)
JPH_DECLARE_PRIMITIVE(double)
JPH_DECLARE_PRIMITIVE(DVec3)
JPH_DECLARE_PRIMITIVE(DMat44)
JPH_DECLARE_PRIMITIVE(Double3)
JPH_DECLARE_PRIMITIVE(Float4)
JPH_DECLARE_PRIMITIVE(UVec4)
#undef JPH_DECLARE_PRIMITIVE

View File

@ -0,0 +1,111 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#ifdef JPH_OBJECT_STREAM
JPH_NAMESPACE_BEGIN
class RTTI;
class IObjectStreamIn;
class IObjectStreamOut;
/// Data type
enum class EOSDataType
{
/// Control codes
Declare, ///< Used to declare the attributes of a new object type
Object, ///< Start of a new object
Instance, ///< Used in attribute declaration, indicates that an object is an instanced attribute (no pointer)
Pointer, ///< Used in attribute declaration, indicates that an object is a pointer attribute
Array, ///< Used in attribute declaration, indicates that this is an array of objects
// Basic types (primitives)
#define JPH_DECLARE_PRIMITIVE(name) T_##name,
// This file uses the JPH_DECLARE_PRIMITIVE macro to define all types
#include <Jolt/ObjectStream/ObjectStreamTypes.h>
// Error values for read functions
Invalid, ///< Next token on the stream was not a valid data type
};
/// Attributes are members of classes that need to be serialized.
class SerializableAttribute
{
public:
///@ Serialization functions
using pGetMemberPrimitiveType = const RTTI * (*)();
using pIsType = bool (*)(int inArrayDepth, EOSDataType inDataType, const char *inClassName);
using pReadData = bool (*)(IObjectStreamIn &ioStream, void *inObject);
using pWriteData = void (*)(IObjectStreamOut &ioStream, const void *inObject);
using pWriteDataType = void (*)(IObjectStreamOut &ioStream);
/// Constructor
SerializableAttribute(const char *inName, uint inMemberOffset, pGetMemberPrimitiveType inGetMemberPrimitiveType, pIsType inIsType, pReadData inReadData, pWriteData inWriteData, pWriteDataType inWriteDataType) : mName(inName), mMemberOffset(inMemberOffset), mGetMemberPrimitiveType(inGetMemberPrimitiveType), mIsType(inIsType), mReadData(inReadData), mWriteData(inWriteData), mWriteDataType(inWriteDataType) { }
/// Construct from other attribute with base class offset
SerializableAttribute(const SerializableAttribute &inOther, int inBaseOffset) : mName(inOther.mName), mMemberOffset(inOther.mMemberOffset + inBaseOffset), mGetMemberPrimitiveType(inOther.mGetMemberPrimitiveType), mIsType(inOther.mIsType), mReadData(inOther.mReadData), mWriteData(inOther.mWriteData), mWriteDataType(inOther.mWriteDataType) { }
/// Name of the attribute
void SetName(const char *inName) { mName = inName; }
const char * GetName() const { return mName; }
/// Access to the memory location that contains the member
template <class T>
inline T * GetMemberPointer(void *inObject) const { return reinterpret_cast<T *>(reinterpret_cast<uint8 *>(inObject) + mMemberOffset); }
template <class T>
inline const T * GetMemberPointer(const void *inObject) const { return reinterpret_cast<const T *>(reinterpret_cast<const uint8 *>(inObject) + mMemberOffset); }
/// In case this attribute contains an RTTI type, return it (note that a Array<sometype> will return the rtti of sometype)
const RTTI * GetMemberPrimitiveType() const
{
return mGetMemberPrimitiveType();
}
/// Check if this attribute is of a specific type
bool IsType(int inArrayDepth, EOSDataType inDataType, const char *inClassName) const
{
return mIsType(inArrayDepth, inDataType, inClassName);
}
/// Read the data for this attribute into attribute containing class inObject
bool ReadData(IObjectStreamIn &ioStream, void *inObject) const
{
return mReadData(ioStream, GetMemberPointer<void>(inObject));
}
/// Write the data for this attribute from attribute containing class inObject
void WriteData(IObjectStreamOut &ioStream, const void *inObject) const
{
mWriteData(ioStream, GetMemberPointer<void>(inObject));
}
/// Write the data type of this attribute to a stream
void WriteDataType(IObjectStreamOut &ioStream) const
{
mWriteDataType(ioStream);
}
private:
// Name of the attribute
const char * mName;
// Offset of the member relative to the class
uint mMemberOffset;
// In case this attribute contains an RTTI type, return it (note that a Array<sometype> will return the rtti of sometype)
pGetMemberPrimitiveType mGetMemberPrimitiveType;
// Serialization operations
pIsType mIsType;
pReadData mReadData;
pWriteData mWriteData;
pWriteDataType mWriteDataType;
};
JPH_NAMESPACE_END
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,67 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#ifdef JPH_OBJECT_STREAM
#include <Jolt/ObjectStream/SerializableAttribute.h>
#include <Jolt/ObjectStream/ObjectStream.h>
JPH_NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////////////////////
// Macros to add properties to be serialized
//////////////////////////////////////////////////////////////////////////////////////////
template <class MemberType>
inline void AddSerializableAttributeEnum(RTTI &inRTTI, uint inOffset, const char *inName)
{
inRTTI.AddAttribute(SerializableAttribute(inName, inOffset,
[]() -> const RTTI *
{
return nullptr;
},
[](int inArrayDepth, EOSDataType inDataType, [[maybe_unused]] const char *inClassName)
{
return inArrayDepth == 0 && inDataType == EOSDataType::T_uint32;
},
[](IObjectStreamIn &ioStream, void *inObject)
{
uint32 temporary;
if (OSReadData(ioStream, temporary))
{
*reinterpret_cast<MemberType *>(inObject) = static_cast<MemberType>(temporary);
return true;
}
return false;
},
[](IObjectStreamOut &ioStream, const void *inObject)
{
static_assert(sizeof(MemberType) <= sizeof(uint32));
uint32 temporary = uint32(*reinterpret_cast<const MemberType *>(inObject));
OSWriteData(ioStream, temporary);
},
[](IObjectStreamOut &ioStream)
{
ioStream.WriteDataType(EOSDataType::T_uint32);
}));
}
// JPH_ADD_ENUM_ATTRIBUTE_WITH_ALIAS
#define JPH_ADD_ENUM_ATTRIBUTE_WITH_ALIAS(class_name, member_name, alias_name) \
JPH::AddSerializableAttributeEnum<decltype(class_name::member_name)>(inRTTI, offsetof(class_name, member_name), alias_name);
// JPH_ADD_ENUM_ATTRIBUTE
#define JPH_ADD_ENUM_ATTRIBUTE(class_name, member_name) \
JPH_ADD_ENUM_ATTRIBUTE_WITH_ALIAS(class_name, member_name, #member_name);
JPH_NAMESPACE_END
#else
#define JPH_ADD_ENUM_ATTRIBUTE_WITH_ALIAS(...)
#define JPH_ADD_ENUM_ATTRIBUTE(...)
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,60 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#ifdef JPH_OBJECT_STREAM
#include <Jolt/ObjectStream/SerializableAttribute.h>
#include <Jolt/ObjectStream/GetPrimitiveTypeOfType.h>
#include <Jolt/ObjectStream/ObjectStream.h>
JPH_NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////////////////////
// Macros to add properties to be serialized
//////////////////////////////////////////////////////////////////////////////////////////
template <class MemberType>
inline void AddSerializableAttributeTyped(RTTI &inRTTI, uint inOffset, const char *inName)
{
inRTTI.AddAttribute(SerializableAttribute(inName, inOffset,
[]()
{
return GetPrimitiveTypeOfType((MemberType *)nullptr);
},
[](int inArrayDepth, EOSDataType inDataType, const char *inClassName)
{
return OSIsType((MemberType *)nullptr, inArrayDepth, inDataType, inClassName);
},
[](IObjectStreamIn &ioStream, void *inObject)
{
return OSReadData(ioStream, *reinterpret_cast<MemberType *>(inObject));
},
[](IObjectStreamOut &ioStream, const void *inObject)
{
OSWriteData(ioStream, *reinterpret_cast<const MemberType *>(inObject));
},
[](IObjectStreamOut &ioStream)
{
OSWriteDataType(ioStream, (MemberType *)nullptr);
}));
}
// JPH_ADD_ATTRIBUTE
#define JPH_ADD_ATTRIBUTE_WITH_ALIAS(class_name, member_name, alias_name) \
JPH::AddSerializableAttributeTyped<decltype(class_name::member_name)>(inRTTI, offsetof(class_name, member_name), alias_name);
// JPH_ADD_ATTRIBUTE
#define JPH_ADD_ATTRIBUTE(class_name, member_name) \
JPH_ADD_ATTRIBUTE_WITH_ALIAS(class_name, member_name, #member_name)
JPH_NAMESPACE_END
#else
#define JPH_ADD_ATTRIBUTE_WITH_ALIAS(...)
#define JPH_ADD_ATTRIBUTE(...)
#endif // JPH_OBJECT_STREAM

View File

@ -0,0 +1,15 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/ObjectStream/SerializableObject.h>
JPH_NAMESPACE_BEGIN
JPH_IMPLEMENT_SERIALIZABLE_ABSTRACT(SerializableObject)
{
}
JPH_NAMESPACE_END

View File

@ -0,0 +1,170 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/ObjectStream.h>
JPH_NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////////////////////
// Helper macros
//////////////////////////////////////////////////////////////////////////////////////////
#ifdef JPH_OBJECT_STREAM
// JPH_DECLARE_SERIALIZATION_FUNCTIONS
#define JPH_DECLARE_SERIALIZATION_FUNCTIONS(linkage, prefix, class_name) \
linkage prefix bool OSReadData(JPH::IObjectStreamIn &ioStream, class_name &inInstance); \
linkage prefix bool OSReadData(JPH::IObjectStreamIn &ioStream, class_name *&inPointer); \
linkage prefix bool OSIsType(class_name *, int inArrayDepth, JPH::EOSDataType inDataType, const char *inClassName); \
linkage prefix bool OSIsType(class_name **, int inArrayDepth, JPH::EOSDataType inDataType, const char *inClassName); \
linkage prefix void OSWriteData(JPH::IObjectStreamOut &ioStream, const class_name &inInstance); \
linkage prefix void OSWriteData(JPH::IObjectStreamOut &ioStream, class_name *const &inPointer); \
linkage prefix void OSWriteDataType(JPH::IObjectStreamOut &ioStream, class_name *); \
linkage prefix void OSWriteDataType(JPH::IObjectStreamOut &ioStream, class_name **);
// JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS
#define JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(class_name) \
bool OSReadData(JPH::IObjectStreamIn &ioStream, class_name &inInstance) \
{ \
return ioStream.ReadClassData(#class_name, (void *)&inInstance); \
} \
bool OSReadData(JPH::IObjectStreamIn &ioStream, class_name *&inPointer) \
{ \
return ioStream.ReadPointerData(JPH_RTTI(class_name), (void **)&inPointer); \
} \
bool OSIsType(class_name *, int inArrayDepth, JPH::EOSDataType inDataType, const char *inClassName) \
{ \
return inArrayDepth == 0 && inDataType == JPH::EOSDataType::Instance && strcmp(inClassName, #class_name) == 0; \
} \
bool OSIsType(class_name **, int inArrayDepth, JPH::EOSDataType inDataType, const char *inClassName) \
{ \
return inArrayDepth == 0 && inDataType == JPH::EOSDataType::Pointer && strcmp(inClassName, #class_name) == 0; \
} \
void OSWriteData(JPH::IObjectStreamOut &ioStream, const class_name &inInstance) \
{ \
ioStream.WriteClassData(JPH_RTTI(class_name), (void *)&inInstance); \
} \
void OSWriteData(JPH::IObjectStreamOut &ioStream, class_name *const &inPointer) \
{ \
if (inPointer) \
ioStream.WritePointerData(GetRTTI(inPointer), (void *)inPointer); \
else \
ioStream.WritePointerData(nullptr, nullptr); \
} \
void OSWriteDataType(JPH::IObjectStreamOut &ioStream, class_name *) \
{ \
ioStream.WriteDataType(JPH::EOSDataType::Instance); \
ioStream.WriteName(#class_name); \
} \
void OSWriteDataType(JPH::IObjectStreamOut &ioStream, class_name **) \
{ \
ioStream.WriteDataType(JPH::EOSDataType::Pointer); \
ioStream.WriteName(#class_name); \
}
#else
#define JPH_DECLARE_SERIALIZATION_FUNCTIONS(...)
#define JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(...)
#endif // JPH_OBJECT_STREAM
//////////////////////////////////////////////////////////////////////////////////////////
// Use these macros on non-virtual objects to make them serializable
//////////////////////////////////////////////////////////////////////////////////////////
// JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL
#define JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(linkage, class_name) \
public: \
JPH_DECLARE_RTTI_NON_VIRTUAL(linkage, class_name) \
JPH_DECLARE_SERIALIZATION_FUNCTIONS(linkage, friend, class_name) \
// JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL
#define JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(class_name) \
JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(class_name) \
JPH_IMPLEMENT_RTTI_NON_VIRTUAL(class_name) \
//////////////////////////////////////////////////////////////////////////////////////////
// Same as above, but when you cannot insert the declaration in the class itself
//////////////////////////////////////////////////////////////////////////////////////////
// JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS
#define JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS(linkage, class_name) \
JPH_DECLARE_RTTI_OUTSIDE_CLASS(linkage, class_name) \
JPH_DECLARE_SERIALIZATION_FUNCTIONS(linkage, extern, class_name) \
// JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS
#define JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS(class_name) \
JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(class_name) \
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(class_name) \
//////////////////////////////////////////////////////////////////////////////////////////
// Same as above, but for classes that have virtual functions
//////////////////////////////////////////////////////////////////////////////////////////
// JPH_DECLARE_SERIALIZABLE_VIRTUAL - Use for concrete, non-base classes
#define JPH_DECLARE_SERIALIZABLE_VIRTUAL(linkage, class_name) \
public: \
JPH_DECLARE_RTTI_VIRTUAL(linkage, class_name) \
JPH_DECLARE_SERIALIZATION_FUNCTIONS(linkage, friend, class_name) \
// JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL
#define JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(class_name) \
JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(class_name) \
JPH_IMPLEMENT_RTTI_VIRTUAL(class_name) \
// JPH_DECLARE_SERIALIZABLE_ABSTRACT - Use for abstract, non-base classes
#define JPH_DECLARE_SERIALIZABLE_ABSTRACT(linkage, class_name) \
public: \
JPH_DECLARE_RTTI_ABSTRACT(linkage, class_name) \
JPH_DECLARE_SERIALIZATION_FUNCTIONS(linkage, friend, class_name) \
// JPH_IMPLEMENT_SERIALIZABLE_ABSTRACT
#define JPH_IMPLEMENT_SERIALIZABLE_ABSTRACT(class_name) \
JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(class_name) \
JPH_IMPLEMENT_RTTI_ABSTRACT(class_name) \
// JPH_DECLARE_SERIALIZABLE_VIRTUAL_BASE - Use for concrete base classes
#define JPH_DECLARE_SERIALIZABLE_VIRTUAL_BASE(linkage, class_name) \
public: \
JPH_DECLARE_RTTI_VIRTUAL_BASE(linkage, class_name) \
JPH_DECLARE_SERIALIZATION_FUNCTIONS(linkage, friend, class_name) \
// JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL_BASE
#define JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL_BASE(class_name) \
JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(class_name) \
JPH_IMPLEMENT_RTTI_VIRTUAL_BASE(class_name) \
// JPH_DECLARE_SERIALIZABLE_ABSTRACT_BASE - Use for abstract base class
#define JPH_DECLARE_SERIALIZABLE_ABSTRACT_BASE(linkage, class_name) \
public: \
JPH_DECLARE_RTTI_ABSTRACT_BASE(linkage, class_name) \
JPH_DECLARE_SERIALIZATION_FUNCTIONS(linkage, friend, class_name) \
// JPH_IMPLEMENT_SERIALIZABLE_ABSTRACT_BASE
#define JPH_IMPLEMENT_SERIALIZABLE_ABSTRACT_BASE(class_name) \
JPH_IMPLEMENT_SERIALIZATION_FUNCTIONS(class_name) \
JPH_IMPLEMENT_RTTI_ABSTRACT_BASE(class_name)
/// Classes must be derived from SerializableObject if you want to be able to save pointers or
/// reference counting pointers to objects of this or derived classes. The type will automatically
/// be determined during serialization and upon deserialization it will be restored correctly.
class JPH_EXPORT SerializableObject
{
JPH_DECLARE_SERIALIZABLE_ABSTRACT_BASE(JPH_EXPORT, SerializableObject)
public:
/// Destructor
virtual ~SerializableObject() = default;
protected:
/// Don't allow (copy) constructing this base class, but allow derived classes to (copy) construct themselves
SerializableObject() = default;
SerializableObject(const SerializableObject &) = default;
SerializableObject & operator = (const SerializableObject &) = default;
};
JPH_NAMESPACE_END

View File

@ -0,0 +1,70 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/ObjectStream/TypeDeclarations.h>
JPH_NAMESPACE_BEGIN
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(uint8) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(uint16) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(int) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(uint32) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(uint64) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(float) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(double) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(bool) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(String) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(Float3) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(Float4) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(Double3) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(Vec3) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(DVec3) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(Vec4) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(UVec4) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(Quat) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(Mat44) { }
JPH_IMPLEMENT_RTTI_OUTSIDE_CLASS(DMat44) { }
JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS(Color)
{
JPH_ADD_ATTRIBUTE(Color, r)
JPH_ADD_ATTRIBUTE(Color, g)
JPH_ADD_ATTRIBUTE(Color, b)
JPH_ADD_ATTRIBUTE(Color, a)
}
JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS(AABox)
{
JPH_ADD_ATTRIBUTE(AABox, mMin)
JPH_ADD_ATTRIBUTE(AABox, mMax)
}
JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS(Triangle)
{
JPH_ADD_ATTRIBUTE(Triangle, mV)
JPH_ADD_ATTRIBUTE(Triangle, mMaterialIndex)
JPH_ADD_ATTRIBUTE(Triangle, mUserData)
}
JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS(IndexedTriangleNoMaterial)
{
JPH_ADD_ATTRIBUTE(IndexedTriangleNoMaterial, mIdx)
}
JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS(IndexedTriangle)
{
JPH_ADD_BASE_CLASS(IndexedTriangle, IndexedTriangleNoMaterial)
JPH_ADD_ATTRIBUTE(IndexedTriangle, mMaterialIndex)
JPH_ADD_ATTRIBUTE(IndexedTriangle, mUserData)
}
JPH_IMPLEMENT_SERIALIZABLE_OUTSIDE_CLASS(Plane)
{
JPH_ADD_ATTRIBUTE(Plane, mNormalAndConstant)
}
JPH_NAMESPACE_END

View File

@ -0,0 +1,45 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/ObjectStream/SerializableObject.h>
#include <Jolt/Core/Color.h>
#include <Jolt/Geometry/AABox.h>
#include <Jolt/Geometry/Triangle.h>
#include <Jolt/Geometry/IndexedTriangle.h>
JPH_NAMESPACE_BEGIN
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, uint8);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, uint16);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, int);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, uint32);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, uint64);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, float);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, double);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, bool);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, String);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, Float3);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, Float4);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, Double3);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, Vec3);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, DVec3);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, Vec4);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, UVec4);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, Quat);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, Mat44);
JPH_DECLARE_RTTI_OUTSIDE_CLASS(JPH_EXPORT, DMat44);
JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS(JPH_EXPORT, Color);
JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS(JPH_EXPORT, AABox);
JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS(JPH_EXPORT, Triangle);
JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS(JPH_EXPORT, IndexedTriangleNoMaterial);
JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS(JPH_EXPORT, IndexedTriangle);
JPH_DECLARE_SERIALIZABLE_OUTSIDE_CLASS(JPH_EXPORT, Plane);
JPH_NAMESPACE_END
// These need to be added after all types have been registered or else clang under linux will not find GetRTTIOfType for the type
#include <Jolt/ObjectStream/SerializableAttributeTyped.h>
#include <Jolt/ObjectStream/SerializableAttributeEnum.h>