Implemented serialization support and initial support for raw resource formats

This commit is contained in:
parax0 2016-08-09 21:58:27 -06:00
parent b582e7208e
commit 0f2c0d5b39
34 changed files with 1171 additions and 149 deletions

View File

@ -48,9 +48,9 @@ CAssetID::CAssetID(IInputStream& rInput, EIDLength Length)
TString CAssetID::ToString() const TString CAssetID::ToString() const
{ {
if (mLength == e32Bit) if (mLength == e32Bit)
return TString::FromInt32(ToLong(), 8, 16); return TString::HexString(ToLong(), 8, false, true);
else else
return TString::FromInt64(ToLongLong(), 8, 16); return TString::FromInt64(ToLongLong(), 8, 16).ToUpper();
} }
bool CAssetID::IsValid() const bool CAssetID::IsValid() const

View File

@ -25,7 +25,7 @@ public:
CAssetID(IInputStream& rInput, EIDLength Length); CAssetID(IInputStream& rInput, EIDLength Length);
TString ToString() const; TString ToString() const;
bool IsValid() const; bool IsValid() const;
\
// Operators // Operators
inline void operator=(const u64& rkInput) { *this = CAssetID(rkInput); } inline void operator=(const u64& rkInput) { *this = CAssetID(rkInput); }
inline void operator=(const char *pkInput) { *this = CAssetID(pkInput); } inline void operator=(const char *pkInput) { *this = CAssetID(pkInput); }

View File

@ -63,6 +63,11 @@ void CColor::Write(IOutputStream &rOutput, bool Integral /*= false*/) const
} }
} }
void CColor::Serialize(IArchive& rArc)
{
rArc << SERIAL_AUTO(R) << SERIAL_AUTO(G) << SERIAL_AUTO(B) << SERIAL_AUTO(A);
}
long CColor::ToLongRGBA() const long CColor::ToLongRGBA() const
{ {
u8 _R = (u8) (R * 255); u8 _R = (u8) (R * 255);

View File

@ -1,9 +1,11 @@
#ifndef CCOLOR_H #ifndef CCOLOR_H
#define CCOLOR_H #define CCOLOR_H
#include "Common/Serialization/IArchive.h"
#include "types.h"
#include <FileIO/IInputStream.h> #include <FileIO/IInputStream.h>
#include <FileIO/IOutputStream.h> #include <FileIO/IOutputStream.h>
#include "types.h"
class CColor class CColor
{ {
@ -17,6 +19,7 @@ public:
void SetIntegral(u8 RGBA); void SetIntegral(u8 RGBA);
void SetIntegral(u8 _R, u8 _G, u8 _B, u8 _A = 255); void SetIntegral(u8 _R, u8 _G, u8 _B, u8 _A = 255);
void Write(IOutputStream& rOutput, bool Integral = false) const; void Write(IOutputStream& rOutput, bool Integral = false) const;
void Serialize(IArchive& rArc);
long ToLongRGBA() const; long ToLongRGBA() const;
long ToLongARGB() const; long ToLongARGB() const;

View File

@ -4,6 +4,7 @@
#include "AssertMacro.h" #include "AssertMacro.h"
#include "types.h" #include "types.h"
#include "TString.h" #include "TString.h"
#include "Common/Serialization/IArchive.h"
#include <FileIO/IInputStream.h> #include <FileIO/IInputStream.h>
#include <FileIO/IOutputStream.h> #include <FileIO/IOutputStream.h>
@ -12,7 +13,12 @@
class CFourCC class CFourCC
{ {
u32 mFourCC; // Note: mFourCC_Chars isn't really used due to endian issues. It's mostly here for easier readability in the debugger.
union
{
u32 mFourCC;
char mFourCC_Chars[4];
};
public: public:
// Constructors // Constructors
@ -36,6 +42,13 @@ public:
rOutput.WriteLong(Val); rOutput.WriteLong(Val);
} }
inline void Serialize(IArchive& rArc)
{
TString Str = ToString();
rArc.SerializePrimitive(Str);
if (rArc.IsReader()) *this = CFourCC(Str);
}
inline u32 ToLong() const inline u32 ToLong() const
{ {
return mFourCC; return mFourCC;

View File

@ -24,7 +24,8 @@ CONFIG (debug, debug|release) {
# Debug Libs # Debug Libs
LIBS += -L$$BUILD_DIR/FileIO/ -lFileIOd \ LIBS += -L$$BUILD_DIR/FileIO/ -lFileIOd \
-L$$EXTERNALS_DIR/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-gd-1_56 -L$$EXTERNALS_DIR/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-gd-1_56 \
-L$$EXTERNALS_DIR/tinyxml2/lib/ -ltinyxml2d
# Debug Target Dependencies # Debug Target Dependencies
win32 { win32 {
@ -39,7 +40,8 @@ CONFIG (release, debug|release) {
# Release Libs # Release Libs
LIBS += -L$$BUILD_DIR/FileIO/ -lFileIO \ LIBS += -L$$BUILD_DIR/FileIO/ -lFileIO \
-L$$EXTERNALS_DIR/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-1_56 -L$$EXTERNALS_DIR/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-1_56 \
-L$$EXTERNALS_DIR/tinyxml2/lib/ -ltinyxml2
# Release Target Dependencies # Release Target Dependencies
win32 { win32 {
@ -55,6 +57,7 @@ LIBS += -L$$EXTERNALS_DIR/lzo-2.08/lib -llzo-2.08 \
INCLUDEPATH += $$PWE_MAIN_INCLUDE \ INCLUDEPATH += $$PWE_MAIN_INCLUDE \
$$EXTERNALS_DIR/boost_1_56_0 \ $$EXTERNALS_DIR/boost_1_56_0 \
$$EXTERNALS_DIR/lzo-2.08/include \ $$EXTERNALS_DIR/lzo-2.08/include \
$$EXTERNALS_DIR/tinyxml2/include \
$$EXTERNALS_DIR/zlib/include $$EXTERNALS_DIR/zlib/include
# Header Files # Header Files
@ -74,7 +77,10 @@ HEADERS += \
FileUtil.h \ FileUtil.h \
AssertMacro.h \ AssertMacro.h \
CScopedTimer.h \ CScopedTimer.h \
CAssetID.h CAssetID.h \
Serialization/IArchive.h \
Serialization/CXMLWriter.h \
Serialization/CXMLReader.h
# Source Files # Source Files
SOURCES += \ SOURCES += \

View File

@ -83,7 +83,7 @@ namespace CompressionUtil
else return true; else return true;
} }
bool DecompressLZO(u8 *pSrc, u32 SrcLen, u8 *pDst, u32& rTotalOut) bool DecompressLZO(u8 *pSrc, u32 SrcLen, u8 *pDst, lzo_uint& rTotalOut)
{ {
lzo_init(); lzo_init();
s32 Error = lzo1x_decompress(pSrc, SrcLen, pDst, &rTotalOut, LZO1X_MEM_DECOMPRESS); s32 Error = lzo1x_decompress(pSrc, SrcLen, pDst, &rTotalOut, LZO1X_MEM_DECOMPRESS);

View File

@ -1,7 +1,8 @@
#ifndef FLAGS_H #ifndef FLAGS_H
#define FLAGS_H #define FLAGS_H
#include <Common/types.h> #include "types.h"
#include "Common/Serialization/IArchive.h"
template<typename FlagEnum> template<typename FlagEnum>
class TFlags class TFlags
@ -36,6 +37,8 @@ public:
inline void SetFlag(TFlags Flags) { mValue |= Flags; } inline void SetFlag(TFlags Flags) { mValue |= Flags; }
inline void ClearFlag(FlagEnum Flag) { mValue &= ~Flag; } inline void ClearFlag(FlagEnum Flag) { mValue &= ~Flag; }
inline void ClearFlag(TFlags Flags) { mValue &= ~Flags; } inline void ClearFlag(TFlags Flags) { mValue &= ~Flags; }
inline void Serialize(IArchive& rArc) { rArc.SerializeHexPrimitive(mValue); }
}; };
#define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName; #define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName;

View File

@ -0,0 +1,121 @@
#ifndef CXMLREADER
#define CXMLREADER
#include "IArchive.h"
#include <tinyxml2.h>
class CXMLReader : public IArchive
{
tinyxml2::XMLDocument mDoc;
tinyxml2::XMLElement *mpCurElem; // Points to the next element being read
bool mJustEndedParam; // Indicates we just ended a primitive parameter
public:
CXMLReader(const TString& rkFileName)
: IArchive()
, mJustEndedParam(false)
{
// Load XML and set current element to the root element
mDoc.LoadFile(*rkFileName);
mpCurElem = mDoc.FirstChildElement();
}
protected:
// Interface Implementation
bool IsReader() const { return true; }
bool IsWriter() const { return false; }
protected:
virtual bool ParamBegin(const char *pkName)
{
// Push new parent if needed
if (!mJustEndedParam)
{
tinyxml2::XMLElement *pChild = mpCurElem->FirstChildElement();
if (!pChild) return false;
else mpCurElem = pChild;
}
// Verify the current element matches the name of the next serialized parameter.
if ( strcmp(mpCurElem->Name(), pkName) == 0)
{
mJustEndedParam = false;
return true;
}
// It didn't match, so we'll try to find a sibling element that does match.
// Iterate over all sibling elements - if we find a match we will continue
// reading from that point on. Otherwise we can't load this parameter.
tinyxml2::XMLElement *pSearchElem = mpCurElem->Parent()->FirstChildElement();
while (pSearchElem)
{
if ( strcmp(pSearchElem->Name(), pkName) == 0 )
{
mpCurElem = pSearchElem;
mJustEndedParam = false;
return true;
}
pSearchElem = pSearchElem->NextSiblingElement();
}
// We couldn't find a matching element, so we can't load this parameter.
return false;
}
virtual void ParamEnd()
{
if (mJustEndedParam)
mpCurElem = mpCurElem->Parent()->ToElement();
tinyxml2::XMLElement *pElem = mpCurElem->NextSiblingElement();
if (pElem)
mpCurElem = pElem;
mJustEndedParam = true;
}
TString ReadParam()
{
return TString(mpCurElem->GetText());
}
public:
virtual void SerializeContainerSize(u32& rSize)
{
rSize = TString(mpCurElem->Attribute("Size")).ToInt32(10);
}
virtual void SerializeAbstractObjectType(u32& rType)
{
rType = TString(mpCurElem->Attribute("Type")).ToInt32(10);
}
virtual void SerializePrimitive(bool& rValue) { rValue = (ReadParam() == "true" ? true : false); }
virtual void SerializePrimitive(char& rValue) { rValue = ReadParam().Front(); }
virtual void SerializePrimitive(s8& rValue) { rValue = (s8) ReadParam().ToInt32(10); }
virtual void SerializePrimitive(u8& rValue) { rValue = (u8) ReadParam().ToInt32(10); }
virtual void SerializePrimitive(s16& rValue) { rValue = (s16) ReadParam().ToInt32(10); }
virtual void SerializePrimitive(u16& rValue) { rValue = (u16) ReadParam().ToInt32(10); }
virtual void SerializePrimitive(s32& rValue) { rValue = (s32) ReadParam().ToInt32(10); }
virtual void SerializePrimitive(u32& rValue) { rValue = (u32) ReadParam().ToInt32(10); }
virtual void SerializePrimitive(s64& rValue) { rValue = (s64) ReadParam().ToInt64(10); }
virtual void SerializePrimitive(u64& rValue) { rValue = (u64) ReadParam().ToInt64(10); }
virtual void SerializePrimitive(float& rValue) { rValue = ReadParam().ToFloat(); }
virtual void SerializePrimitive(double& rValue) { rValue = (double) ReadParam().ToFloat(); }
virtual void SerializePrimitive(TString& rValue) { rValue = ReadParam(); }
virtual void SerializePrimitive(CAssetID& rValue) { rValue = CAssetID::FromString( ReadParam() ); }
virtual void SerializeHexPrimitive(s8& rValue) { rValue = (s8) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(u8& rValue) { rValue = (u8) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(s16& rValue) { rValue = (s16) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(u16& rValue) { rValue = (u16) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(s32& rValue) { rValue = (s32) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(u32& rValue) { rValue = (u32) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(s64& rValue) { rValue = (s64) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(u64& rValue) { rValue = (u64) ReadParam().ToInt32(16); }
};
#endif // CXMLREADER

View File

@ -0,0 +1,91 @@
#ifndef CXMLWRITER
#define CXMLWRITER
#include "IArchive.h"
#include <iostream>
#include <tinyxml2.h>
class CXMLWriter : public IArchive
{
tinyxml2::XMLDocument mDoc;
TString mOutFilename;
tinyxml2::XMLElement *mpCurElem;
public:
CXMLWriter(const TString& rkRootName, const TString& rkFileName)
: IArchive()
, mOutFilename(rkFileName)
{
// Create declaration and root node
tinyxml2::XMLDeclaration *pDecl = mDoc.NewDeclaration();
mDoc.LinkEndChild(pDecl);
mpCurElem = mDoc.NewElement(*rkRootName);
mDoc.LinkEndChild(mpCurElem);
}
~CXMLWriter()
{
mDoc.SaveFile(*mOutFilename);
}
// Interface Implementation
bool IsReader() const { return false; }
bool IsWriter() const { return true; }
protected:
virtual bool ParamBegin(const char *pkName)
{
tinyxml2::XMLElement *pElem = mDoc.NewElement(pkName);
mpCurElem->LinkEndChild(pElem);
mpCurElem = pElem;
return true;
}
virtual void ParamEnd()
{
mpCurElem = mpCurElem->Parent()->ToElement();
}
void WriteParam(const char *pkValue)
{
mpCurElem->SetText(pkValue);
}
public:
virtual void SerializeContainerSize(u32& rSize)
{
mpCurElem->SetAttribute("Size", (unsigned int) rSize);
}
virtual void SerializeAbstractObjectType(u32& rType)
{
mpCurElem->SetAttribute("Type", (unsigned int) rType);
}
virtual void SerializePrimitive(bool& rValue) { WriteParam(rValue ? "true" : "false"); }
virtual void SerializePrimitive(char& rValue) { WriteParam(*TString(rValue)); }
virtual void SerializePrimitive(s8& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); }
virtual void SerializePrimitive(u8& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); }
virtual void SerializePrimitive(s16& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); }
virtual void SerializePrimitive(u16& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); }
virtual void SerializePrimitive(s32& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); }
virtual void SerializePrimitive(u32& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); }
virtual void SerializePrimitive(s64& rValue) { WriteParam(*TString::FromInt64(rValue, 0, 10)); }
virtual void SerializePrimitive(u64& rValue) { WriteParam(*TString::FromInt64(rValue, 0, 10)); }
virtual void SerializePrimitive(float& rValue) { WriteParam(*TString::FromFloat(rValue)); }
virtual void SerializePrimitive(double& rValue) { WriteParam(*TString::FromFloat((float) rValue)); }
virtual void SerializePrimitive(TString& rValue) { WriteParam(*rValue); }
virtual void SerializePrimitive(CAssetID& rValue) { WriteParam(*rValue.ToString()); }
virtual void SerializeHexPrimitive(s8& rValue) { WriteParam(*TString::HexString((u8) rValue, 2)); }
virtual void SerializeHexPrimitive(u8& rValue) { WriteParam(*TString::HexString(rValue, 2)); }
virtual void SerializeHexPrimitive(s16& rValue) { WriteParam(*TString::HexString((u16) rValue, 4)); }
virtual void SerializeHexPrimitive(u16& rValue) { WriteParam(*TString::HexString(rValue, 4)); }
virtual void SerializeHexPrimitive(s32& rValue) { WriteParam(*TString::HexString((u32) rValue, 8)); }
virtual void SerializeHexPrimitive(u32& rValue) { WriteParam(*TString::HexString(rValue, 8)); }
virtual void SerializeHexPrimitive(s64& rValue) { WriteParam(*TString::HexString((u32) rValue, 16)); }
virtual void SerializeHexPrimitive(u64& rValue) { WriteParam(*TString::HexString((u32) rValue, 16)); }
};
#endif // CXMLWRITER

View File

@ -0,0 +1,490 @@
#ifndef IARCHIVE
#define IARCHIVE
#include "Common/AssertMacro.h"
#include "Common/CAssetID.h"
#include "Common/TString.h"
#include "Common/types.h"
/* This is a custom serialization implementation intended for saving editor-friendly game assets
* out to XML. Support for other output formats can be added by implementing new subclasses of
* IArchive.
*
* To use a class with the serialization system, it must have a Serialize function implemented.
* There are two ways this function can be defined:
* 1. As a member function with this signature: void Serialize(IArchive&)
* 2. As a global/friend function with this signature: void Serialize(IArchive&, YourClass&)
*
* Use the << operator to serialize data members to the archive. All data being serialized must be
* wrapped in one of the SERIAL macros. The SERIAL macro ensures that all serialized parameters are
* associated with a name. This name makes the output file more easily human-readable as well as helps
* ensure that files are easily backwards-compatible if parameters are moved or added/removed.
*
* Polymorphism is supported. There are two requirements for a polymorphic class to work with the
* serialization system. First, the base class must contain a virtual Type() parameter that returns
* an integral value (an enum or an integer). Second, there must be a factory class with a SpawnObject
* method that takes the same Type value and returns an object of the specified class.
*
* Containers are also supported. Containers require a different macro that allows you to specify the
* name of the elements in the container. The currently-supported containers are std::vector, std::list,
* and std::set. Support for more container types can be added to the bottom of this file.
*
* These are the available SERIAL macros:
* - SERIAL(ParamName, ParamValue) [generic parameter]
* - SERIAL_HEX(ParamName, ParamValue) [integral parameter serialized as a hex number for improved readability]
* - SERIAL_ABSTRACT(ParamName, ParamValue, Factory) [polymorphic parameter]
* - SERIAL_CONTAINER(ParamName, Container, ElementName) [container parameter]
* - SERIAL_ABSTRACT_CONTAINER(ParamName, Container, ElementName, Factory) [container of polymorphic objects parameter]
*
* Each of these has a variant with _AUTO at the end that allows you to exclude ParamName (the name of the
* variable will be used as the parameter name instead).
*/
// TSerialParameter - name/value pair for generic serial parameters
template<typename ValType>
struct TSerialParameter
{
const char *pkName;
ValType& rValue;
};
template<typename ValType>
inline TSerialParameter<ValType> MakeSerialParameter(const char *pkName, ValType& rValue)
{
return TSerialParameter<ValType> { pkName, rValue };
}
#define SERIAL(ParamName, ParamValue) MakeSerialParameter(ParamName, ParamValue)
#define SERIAL_AUTO(ParamValue) MakeSerialParameter(#ParamValue, ParamValue)
// THexSerialParameter - same as TSerialParameter but serialized in hex for improved readability
template<typename ValType>
struct THexSerialParameter
{
const char *pkName;
ValType& rValue;
};
template<typename ValType/*, class = typename std::enable_if<std::is_integral<ValType>::value, int>*/>
inline THexSerialParameter<ValType> MakeHexSerialParameter(const char *pkName, ValType& rValue)
{
return THexSerialParameter<ValType> { pkName, rValue };
}
#define SERIAL_HEX(ParamName, ParamValue) MakeHexSerialParameter(ParamName, ParamValue)
#define SERIAL_HEX_AUTO(ParamValue) MakeHexSerialParameter(#ParamValue, ParamValue)
// TAbstractSerialParameter - name/value pair for polymorphic objects a pointer to a factory
template<typename ValType, typename FactoryType>
struct TAbstractSerialParameter
{
const char *pkName;
ValType*& rValue;
FactoryType *pFactory;
};
template<typename ValType, typename FactoryType>
inline TAbstractSerialParameter<ValType, FactoryType> MakeAbstractSerialParameter(const char *pkName, ValType*& rValue, FactoryType *pFactory)
{
return TAbstractSerialParameter<ValType, FactoryType> { pkName, rValue, pFactory };
}
#define SERIAL_ABSTRACT(ParamName, ParamValue, Factory) MakeAbstractSerialParameter(ParamName, ParamValue, Factory)
#define SERIAL_ABSTRACT_AUTO(ParamValue, Factory) MakeAbstractSerialParameter(#ParamValue, ParamValue, Factory)
// TContainerSerialParameter - name/value pair for containers with a parameter name string
template<typename ValType>
struct TContainerSerialParameter
{
const char *pkName;
ValType& rContainer;
const char *pkElementName;
};
template<typename ValType>
inline TContainerSerialParameter<ValType> MakeSerialParameter(const char *pkName, ValType& rContainer, const char *pkElementName)
{
return TContainerSerialParameter<ValType> { pkName, rContainer, pkElementName };
}
#define SERIAL_CONTAINER(ParamName, Container, ElementName) MakeSerialParameter(ParamName, Container, ElementName)
#define SERIAL_CONTAINER_AUTO(Container, ElementName) MakeSerialParameter(#Container, Container, ElementName)
// TAbstractContainerSerialParameter - name/value pair for containers of polymorphic objects with a parameter name string and a pointer to a factory
template<typename ValType, typename FactoryType>
struct TAbstractContainerSerialParameter
{
const char *pkName;
ValType& rContainer;
const char *pkElementName;
FactoryType *pFactory;
};
template<typename ValType, typename FactoryType>
inline TAbstractContainerSerialParameter<ValType, FactoryType> MakeSerialParameter(const char *pkName, ValType& rContainer, const char *pkElementName, FactoryType *pFactory)
{
return TAbstractContainerSerialParameter<ValType, FactoryType> { pkName, rContainer, pkElementName, pFactory };
}
#define SERIAL_ABSTRACT_CONTAINER(ParamName, Container, ElementName, Factory) MakeSerialParameter(ParamName, Container, ElementName, Factory)
#define SERIAL_ABSTRACT_CONTAINER_AUTO(Container, ElementName, Factory) MakeSerialParameter(#Container, Container, ElementName, Factory)
// SFINAE serialize function type check
// https://jguegant.github.io/blogs/tech/sfinae-introduction.html
void Serialize(); // This needs to be here or else the global Serialize method handling causes a compiler error. Not sure of a better fix
void SerializeContainer();
template<class ValueType, class ArchiveType>
struct SerialType
{
public:
enum { Primitive, Member, Global, None };
// Helper struct to verify that function Func exists and matches the given function signature (FuncType)
template<typename FuncType, FuncType Func> struct FunctionExists;
// Check for ArcType::SerializePrimitive(ValType&) method
template<typename ValType, typename ArcType> static long long& Check(FunctionExists<void (ArcType::*)(ValType&), &ArcType::SerializePrimitive>*);
// Check for ValType::Serialize(ArcType&)
template<typename ValType, typename ArcType> static long& Check(FunctionExists<void (ValType::*)(ArcType&), &ValType::Serialize>*);
// Check for global Serialize(ArcType&,ValType&) function
template<typename ValType, typename ArcType> static short& Check(FunctionExists<void (*)(ArcType&, ValType&), &Serialize>*);
// Check for global SerializeContainer(ArcType&,ValType&,const TString&)
template<typename ValType, typename ArcType> static short& Check(FunctionExists<void (*)(ArcType&, ValType&, const TString&), &SerializeContainer>*);
// Fallback - no valid Serialize method exists
template<typename ValType, typename ArcType> static char& Check(...);
// Set Type enum to correspond to whichever function exists
static const int Type = (sizeof(Check<ValueType, ArchiveType>(0)) == sizeof(long long) ? Primitive :
sizeof(Check<ValueType, ArchiveType>(0)) == sizeof(long) ? Member :
sizeof(Check<ValueType, ArchiveType>(0)) == sizeof(short) ? Global :
None);
};
// Actual archive class
class IArchive
{
public:
IArchive() {}
virtual ~IArchive() {}
#define ENABLE_FOR_SERIAL_TYPE(SType) typename std::enable_if<SerialType<ValType, IArchive>::Type == SerialType<ValType, IArchive>::##SType, int>::type = 0
// Serialize primitives
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Primitive)>
inline IArchive& operator<<(TSerialParameter<ValType>& rParam)
{
if (ParamBegin(rParam.pkName))
{
SerializePrimitive(rParam.rValue);
ParamEnd();
}
return *this;
}
// Serialize pointers to primitives
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Primitive)>
inline IArchive& operator<<(TSerialParameter<ValType*>& rParam)
{
if (ParamBegin(rParam.pkName))
{
if (IsReader() && !rParam.rValue) rParam.rValue = new ValType;
SerializePrimitive(*rParam.rValue);
ParamEnd();
}
return *this;
}
// Serialize hex primitives
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Primitive)>
inline IArchive& operator<<(THexSerialParameter<ValType>& rParam)
{
if (ParamBegin(rParam.pkName))
{
SerializeHexPrimitive(rParam.rValue);
ParamEnd();
}
return *this;
}
// Serialize pointers to hex primitives
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Primitive)>
inline IArchive& operator<<(THexSerialParameter<ValType*>& rParam)
{
if (ParamBegin(rParam.pkName))
{
if (IsReader() && !rParam.rValue) rParam.rValue = new ValType;
SerializeHexPrimitive(*rParam.rValue);
ParamEnd();
}
return *this;
}
// Serialize objects with member Serialize methods
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Member)>
inline IArchive& operator<<(TSerialParameter<ValType>& rParam)
{
if (ParamBegin(rParam.pkName))
{
rParam.rValue.Serialize(*this);
ParamEnd();
}
return *this;
}
// Serialize pointers to objects with member Serialize methods
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Member)>
inline IArchive& operator<<(TSerialParameter<ValType*>& rParam)
{
if (ParamBegin(rParam.pkName))
{
if (IsReader() && !rParam.rValue) rParam.rValue = new ValType;
rParam.rValue->Serialize(*this);
ParamEnd();
}
return *this;
}
// Serialize objects with global Serialize functions
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Global)>
inline IArchive& operator<<(TSerialParameter<ValType>& rParam)
{
if (ParamBegin(rParam.pkName))
{
Serialize(*this, rParam.rValue);
ParamEnd();
}
return *this;
}
// Serialize pointers to objects with global Serialize functions
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Global)>
inline IArchive& operator<<(TSerialParameter<ValType*>& rParam)
{
if (ParamBegin(rParam.pkName))
{
if (IsReader() && !rParam.rValue) rParam.rValue = new ValType;
Serialize(*this, *rParam.rValue);
ParamEnd();
}
return *this;
}
// Serialize abstract objects (global methods for abstract objects not supported)
template<typename ValType, typename FactoryType, ENABLE_FOR_SERIAL_TYPE(Member)>
inline IArchive& operator<<(TAbstractSerialParameter<ValType, FactoryType>& rParam)
{
if (ParamBegin(rParam.pkName))
{
// Serialize object type
u32 Type = (IsWriter() ? (u32) rParam.rValue->Type() : 0);
SerializeAbstractObjectType(Type);
// Reader only - instantiate object
if (IsReader())
{
rParam.rValue = static_cast<ValType*>(rParam.pFactory->SpawnObject(Type));
ASSERT(rParam.rValue != nullptr);
}
// Finish serialize
rParam.rValue->Serialize(*this);
ParamEnd();
}
return *this;
}
// Serialize containers (member methods for containers not supported)
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(Global)>
inline IArchive& operator<<(TContainerSerialParameter<ValType>& rParam)
{
if (ParamBegin(rParam.pkName))
{
SerializeContainer(*this, rParam.rContainer, rParam.pkElementName);
ParamEnd();
}
return *this;
}
// Serialize abstract containers (member methods for containers not supported)
template<typename ValType, typename FactoryType, ENABLE_FOR_SERIAL_TYPE(Global)>
inline IArchive& operator<<(TAbstractContainerSerialParameter<ValType, FactoryType>& rParam)
{
if (ParamBegin(rParam.pkName))
{
SerializeContainer(*this, rParam.rContainer, rParam.pkElementName, rParam.pFactory);
ParamEnd();
}
return *this;
}
// Generate compiler errors for classes with no valid Serialize function defined
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(None)>
inline IArchive& operator<<(TSerialParameter<ValType>&)
{
static_assert(false, "Object being serialized has no valid Serialize method defined.");
}
template<typename ValType, typename FactoryType, ENABLE_FOR_SERIAL_TYPE(None)>
inline IArchive& operator<<(TAbstractSerialParameter<ValType, FactoryType>&)
{
static_assert(false, "Abstract object being serialized must have a virtual Serialize method defined.");
}
template<typename ValType, ENABLE_FOR_SERIAL_TYPE(None)>
inline IArchive& operator<<(TContainerSerialParameter<ValType>&)
{
static_assert(false, "Container being serialized has no valid Serialize method defined.");
}
template<typename ValType, typename FactoryType, ENABLE_FOR_SERIAL_TYPE(None)>
inline IArchive& operator<<(TAbstractContainerSerialParameter<ValType, FactoryType>&)
{
static_assert(false, "Container being serialized has no valid Serialize method defined.");
}
// Interface
virtual bool IsReader() const = 0;
virtual bool IsWriter() const = 0;
protected:
virtual bool ParamBegin(const char *pkName) = 0;
virtual void ParamEnd() = 0;
public:
virtual void SerializeContainerSize(u32& rSize) = 0;
virtual void SerializeAbstractObjectType(u32& rType) = 0;
virtual void SerializePrimitive(bool& rValue) = 0;
virtual void SerializePrimitive(char& rValue) = 0;
virtual void SerializePrimitive(s8& rValue) = 0;
virtual void SerializePrimitive(u8& rValue) = 0;
virtual void SerializePrimitive(s16& rValue) = 0;
virtual void SerializePrimitive(u16& rValue) = 0;
virtual void SerializePrimitive(s32& rValue) = 0;
virtual void SerializePrimitive(u32& rValue) = 0;
virtual void SerializePrimitive(s64& rValue) = 0;
virtual void SerializePrimitive(u64& rValue) = 0;
virtual void SerializePrimitive(float& rValue) = 0;
virtual void SerializePrimitive(double& rValue) = 0;
virtual void SerializePrimitive(TString& rValue) = 0;
virtual void SerializePrimitive(CAssetID& rValue) = 0;
virtual void SerializeHexPrimitive(s8& rValue) = 0;
virtual void SerializeHexPrimitive(u8& rValue) = 0;
virtual void SerializeHexPrimitive(s16& rValue) = 0;
virtual void SerializeHexPrimitive(u16& rValue) = 0;
virtual void SerializeHexPrimitive(s32& rValue) = 0;
virtual void SerializeHexPrimitive(u32& rValue) = 0;
virtual void SerializeHexPrimitive(s64& rValue) = 0;
virtual void SerializeHexPrimitive(u64& rValue) = 0;
};
// Container serialize methods
#include <list>
#include <set>
#include <vector>
template<typename Container>
inline void SerializeContainerSize(IArchive& rArc, Container& rContainer)
{
u32 Size = rContainer.size();
rArc.SerializeContainerSize(Size);
if (rArc.IsReader()) rContainer.resize(Size);
}
// std::vector
template<typename ValType>
inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const TString& rkElemName = "Item")
{
SerializeContainerSize(rArc, rVec);
for (u32 iElem = 0; iElem < rVec.size(); iElem++)
rArc << SERIAL(*rkElemName, rVec[iElem]);
}
template<typename ValType, typename FactoryType>
inline void SerializeContainer(IArchive& rArc, std::vector<ValType>& rVec, const TString& rkElemName, FactoryType *pFactory)
{
SerializeContainerSize(rArc, rVec);
for (u32 iElem = 0; iElem < rVec.size(); iElem++)
rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory);
}
// std::list
template<typename ValType>
inline void SerializeContainer(IArchive& rArc, std::list<ValType>& rList, const TString& rkElemName)
{
SerializeContainerSize(rArc, rList);
for (auto Iter = rList.begin(); Iter != rList.end(); Iter++)
rArc << SERIAL(*rkElemName, *Iter);
}
template<typename ValType, typename FactoryType>
inline void SerializeContainer(IArchive& rArc, std::list<ValType>& rList, const TString& rkElemName, FactoryType *pFactory)
{
SerializeContainerSize(rArc, rList);
for (auto Iter = rList.begin(); Iter != rList.end(); Iter++)
rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory);
}
// std::set
template<typename ValType>
inline void SerializeContainer(IArchive& rArc, std::set<ValType>& rSet, const TString& rkElemName)
{
u32 Size = rSet.size();
rArc.SerializeContainerSize(Size);
if (rArc.IsReader())
{
for (u32 iElem = 0; iElem < Size; iElem++)
{
ValType Val;
rArc << SERIAL(*rkElemName, Val);
rSet.insert(Val);
}
}
else
{
for (auto Iter = rSet.begin(); Iter != rSet.end(); Iter++)
{
ValType Val = *Iter;
rArc << SERIAL(*rkElemName, Val);
}
}
}
template<typename ValType, typename FactoryType>
inline void SerializeContainer(IArchive& rArc, std::set<ValType>& rSet, const TString& rkElemName, FactoryType *pFactory)
{
u32 Size = rSet.size();
rArc.SerializeContainerSize(Size);
if (rArc.IsReader())
{
for (u32 iElem = 0; iElem < Size; iElem++)
{
ValType Val;
rArc << SERIAL_ABSTRACT(*rkElemName, Val, pFactory);
rSet.insert(Val);
}
}
else
{
for (auto Iter = rSet.begin(); Iter != rSet.end(); Iter++)
{
ValType Val = *Iter;
rArc << SERIAL_ABSTRACT(*rkElemName, Val, pFactory);
}
}
}
#endif // IARCHIVE

View File

@ -255,6 +255,18 @@ public:
Remove(Idx, 1); Remove(Idx, 1);
} }
inline void RemoveWhitespace()
{
for (u32 Idx = 0; Idx < Size(); Idx++)
{
if (IsWhitespace(At(Idx)))
{
Remove(Idx, 1);
Idx--;
}
}
}
inline void Replace(const CharType* pkStr, const CharType *pkReplacement, bool CaseSensitive = false) inline void Replace(const CharType* pkStr, const CharType *pkReplacement, bool CaseSensitive = false)
{ {
u32 Offset = 0; u32 Offset = 0;
@ -846,16 +858,43 @@ public:
static TBasicString<CharType> FromFloat(float Value, int MinDecimals = 1) static TBasicString<CharType> FromFloat(float Value, int MinDecimals = 1)
{ {
// Initial float -> string conversion
std::basic_stringstream<CharType> SStream; std::basic_stringstream<CharType> SStream;
if (MinDecimals > 0) SStream.setf(std::ios_base::showpoint);
SStream.setf(std::ios_base::fixed, std::ios_base::floatfield);
SStream << Value; SStream << Value;
_TString Out = SStream.str(); _TString Out = SStream.str();
int NumZeroes = Out.Size() - (Out.IndexOf(LITERAL(".")) + 1); // Make sure we have the right number of decimals
int DecIdx = Out.IndexOf(CHAR_LITERAL('.'));
while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals) if (DecIdx == -1 && MinDecimals > 0)
{ {
Out = Out.ChopBack(1); DecIdx = Out.Size();
NumZeroes--; Out.Append(CHAR_LITERAL('.'));
}
int NumZeroes = (DecIdx == -1 ? 0 : Out.Size() - (DecIdx + 1));
// Add extra zeroes to meet the minimum decimal count
if (NumZeroes < MinDecimals)
{
for (int iDec = 0; iDec < (MinDecimals - NumZeroes); iDec++)
Out.Append(CHAR_LITERAL('.'));
}
// Remove unnecessary trailing zeroes from the end of the string
else if (NumZeroes > MinDecimals)
{
while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals && NumZeroes > 0)
{
Out = Out.ChopBack(1);
NumZeroes--;
}
// Remove decimal point
if (NumZeroes == 0)
Out = Out.ChopBack(1);
} }
return Out; return Out;

View File

@ -130,7 +130,6 @@ HEADERS += \
Resource/EResType.h \ Resource/EResType.h \
Resource/ETevEnums.h \ Resource/ETevEnums.h \
Resource/ETexelFormat.h \ Resource/ETexelFormat.h \
Resource/SDependency.h \
Resource/TResPtr.h \ Resource/TResPtr.h \
Scene/CCollisionNode.h \ Scene/CCollisionNode.h \
Scene/CLightNode.h \ Scene/CLightNode.h \
@ -202,7 +201,9 @@ HEADERS += \
GameProject/CDependencyTree.h \ GameProject/CDependencyTree.h \
Resource/Factory/CUnsupportedFormatLoader.h \ Resource/Factory/CUnsupportedFormatLoader.h \
Resource/ParticleParameters.h \ Resource/ParticleParameters.h \
Resource/Factory/CUnsupportedParticleLoader.h Resource/Factory/CUnsupportedParticleLoader.h \
Resource/Resources.h \
Resource/Factory/CResourceFactory.h
# Source Files # Source Files
SOURCES += \ SOURCES += \

View File

@ -8,6 +8,7 @@
#include <Common/CompressionUtil.h> #include <Common/CompressionUtil.h>
#include <Common/CScopedTimer.h> #include <Common/CScopedTimer.h>
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <Common/Serialization/CXMLWriter.h>
#include <tinyxml2.h> #include <tinyxml2.h>
#define COPY_DISC_DATA 1 #define COPY_DISC_DATA 1
@ -15,7 +16,6 @@
#define SAVE_PACKAGE_DEFINITIONS 1 #define SAVE_PACKAGE_DEFINITIONS 1
#define EXPORT_WORLDS 1 #define EXPORT_WORLDS 1
#define EXPORT_COOKED 1 #define EXPORT_COOKED 1
#define EXPORT_CACHE 1
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir) CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
: mStore(this) : mStore(this)
@ -76,7 +76,7 @@ void CGameExporter::CopyDiscData()
TWideString RelPath = FullPath.ChopFront(mGameDir.Size()); TWideString RelPath = FullPath.ChopFront(mGameDir.Size());
// Exclude PakTool files and folders // Exclude PakTool files and folders
if (FullPath.GetFileName(false) == L"PakTool" || FullPath.GetFileName() == L"zlib1" || RelPath.Contains(L"-pak")) if (FullPath.GetFileName(false) == L"PakTool" || FullPath.GetFileName(false) == L"zlib1" || RelPath.Contains(L"-pak"))
continue; continue;
// Hack to determine game // Hack to determine game
@ -495,20 +495,19 @@ void CGameExporter::ExportCookedResources()
#endif #endif
mpProject->Save(); mpProject->Save();
} }
#if EXPORT_CACHE
{ {
SCOPED_TIMER(SaveCacheData); // Save raw versions of resources + resource cache data files
// Note this has to be done after all cooked resources are exported
// because we have to load the resource to build its dependency tree and
// some resources will fail to load if their dependencies don't exist
SCOPED_TIMER(SaveRawResources);
for (CResourceIterator It(&mStore); It; ++It) for (CResourceIterator It(&mStore); It; ++It)
{ {
if (!It->IsTransient()) if (!It->IsTransient())
{ It->Save();
It->UpdateDependencies();
It->SaveCacheData();
}
} }
} }
#endif
} }
void CGameExporter::ExportResource(SResourceInstance& rRes) void CGameExporter::ExportResource(SResourceInstance& rRes)
@ -535,18 +534,17 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
CResourceEntry *pEntry = mStore.RegisterResource(rRes.ResourceID, CResource::ResTypeForExtension(rRes.ResourceType), OutDir, OutName); CResourceEntry *pEntry = mStore.RegisterResource(rRes.ResourceID, CResource::ResTypeForExtension(rRes.ResourceType), OutDir, OutName);
#if EXPORT_COOKED #if EXPORT_COOKED
// Cooked (todo: save raw) // Save cooked asset
TWideString OutPath = pEntry->CookedAssetPath(); TWideString OutCookedPath = pEntry->CookedAssetPath();
FileUtil::CreateDirectory(OutPath.GetFileDirectory()); FileUtil::CreateDirectory(OutCookedPath.GetFileDirectory());
CFileOutStream Out(OutPath.ToUTF8().ToStdString(), IOUtil::eBigEndian); CFileOutStream Out(OutCookedPath.ToUTF8().ToStdString(), IOUtil::eBigEndian);
if (Out.IsValid()) if (Out.IsValid())
Out.WriteBytes(ResourceData.data(), ResourceData.size()); Out.WriteBytes(ResourceData.data(), ResourceData.size());
rRes.Exported = true;
ASSERT(pEntry->HasCookedVersion()); ASSERT(pEntry->HasCookedVersion());
#else
(void) pEntry; // Prevent "unused local variable" compiler warning
#endif #endif
rRes.Exported = true;
} }
} }

View File

@ -46,6 +46,9 @@ bool CGameProject::Load(const TWideString& rkPath)
mGame = CMasterTemplate::FindGameForName( pGame->GetText() ); mGame = CMasterTemplate::FindGameForName( pGame->GetText() );
mResourceDBPath = pResDB->GetText(); mResourceDBPath = pResDB->GetText();
mProjectRoot = rkPath.GetFileDirectory();
mProjectRoot.Replace(L"/", L"\\");
// Load packages // Load packages
XMLElement *pPkgElem = pPackages->FirstChildElement("Package"); XMLElement *pPkgElem = pPackages->FirstChildElement("Package");
@ -67,8 +70,6 @@ bool CGameProject::Load(const TWideString& rkPath)
} }
// All loaded! // All loaded!
mProjectRoot = rkPath.GetFileDirectory();
mProjectRoot.Replace(L"/", L"\\");
return true; return true;
} }

View File

@ -2,30 +2,12 @@
#include "CGameProject.h" #include "CGameProject.h"
#include "CResourceStore.h" #include "CResourceStore.h"
#include "Core/Resource/CResource.h" #include "Core/Resource/CResource.h"
#include "Core/Resource/Factory/CResourceFactory.h"
#include <FileIO/FileIO.h> #include <FileIO/FileIO.h>
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <Common/TString.h> #include <Common/TString.h>
#include <Common/Serialization/CXMLReader.h>
// Resource Loaders #include <Common/Serialization/CXMLWriter.h>
// todo: come up with a factory setup that doesn't suck
#include "Core/Resource/Factory/CAnimationLoader.h"
#include "Core/Resource/Factory/CAnimSetLoader.h"
#include "Core/Resource/Factory/CAreaLoader.h"
#include "Core/Resource/Factory/CCollisionLoader.h"
#include "Core/Resource/Factory/CDependencyGroupLoader.h"
#include "Core/Resource/Factory/CFontLoader.h"
#include "Core/Resource/Factory/CMaterialLoader.h"
#include "Core/Resource/Factory/CModelLoader.h"
#include "Core/Resource/Factory/CPoiToWorldLoader.h"
#include "Core/Resource/Factory/CScanLoader.h"
#include "Core/Resource/Factory/CScriptLoader.h"
#include "Core/Resource/Factory/CSkeletonLoader.h"
#include "Core/Resource/Factory/CSkinLoader.h"
#include "Core/Resource/Factory/CStringLoader.h"
#include "Core/Resource/Factory/CTextureDecoder.h"
#include "Core/Resource/Factory/CUnsupportedFormatLoader.h"
#include "Core/Resource/Factory/CUnsupportedParticleLoader.h"
#include "Core/Resource/Factory/CWorldLoader.h"
CResourceEntry::CResourceEntry(CResourceStore *pStore, const CAssetID& rkID, CResourceEntry::CResourceEntry(CResourceStore *pStore, const CAssetID& rkID,
const TWideString& rkDir, const TWideString& rkFilename, const TWideString& rkDir, const TWideString& rkFilename,
@ -137,6 +119,8 @@ void CResourceEntry::UpdateDependencies()
mpDependencies = nullptr; mpDependencies = nullptr;
} }
bool WasLoaded = IsLoaded();
if (!mpResource) if (!mpResource)
Load(); Load();
@ -147,7 +131,8 @@ void CResourceEntry::UpdateDependencies()
} }
mpDependencies = mpResource->BuildDependencyTree(); mpDependencies = mpResource->BuildDependencyTree();
gpResourceStore->DestroyUnreferencedResources(); if (!WasLoaded)
gpResourceStore->DestroyUnreferencedResources();
} }
TWideString CResourceEntry::CacheDataPath(bool Relative) const TWideString CResourceEntry::CacheDataPath(bool Relative) const
@ -229,69 +214,87 @@ void CResourceEntry::SetGame(EGame NewGame)
} }
} }
bool CResourceEntry::Save()
{
// For now, always save the resource when this function is called even if there's been no changes made to it in memory.
// In the future this might not be desired behavior 100% of the time.
// We also might want this function to trigger a cook for certain resource types eventually.
bool ShouldCollectGarbage = false;
// Save raw resource
if (ResourceSupportsSerialization(ResourceType()))
{
ShouldCollectGarbage = !IsLoaded();
Load();
if (!mpResource) return false;
// Note: We call Serialize directly for resources to avoid having a redundant resource root node in the output file.
TString Path = RawAssetPath();
TString Dir = Path.GetFileDirectory();
FileUtil::CreateDirectory(Dir.ToUTF16());
CXMLWriter Writer(GetResourceSerialName(ResourceType()), Path);
mpResource->Serialize(Writer);
}
// Resource has been saved, now update cache file
UpdateDependencies();
SaveCacheData();
if (ShouldCollectGarbage)
gpResourceStore->DestroyUnreferencedResources();
return true;
}
CResource* CResourceEntry::Load() CResource* CResourceEntry::Load()
{ {
// todo: load raw // Always try to load raw version as the raw version contains extra editor-only data.
// If there is no raw version (which will be the case for resource types that don't
// support serialization yet) then load the cooked version as a backup.
if (mpResource) return mpResource; if (mpResource) return mpResource;
if (!HasCookedVersion()) if (HasRawVersion())
{
mpResource = CResourceFactory::SpawnResource(this);
if (mpResource)
{
CXMLReader Reader(RawAssetPath());
mpResource->Serialize(Reader);
}
return mpResource;
}
else if (HasCookedVersion())
{
CFileInStream File(CookedAssetPath().ToStdString(), IOUtil::eBigEndian);
if (!File.IsValid())
{
Log::Error("Failed to open cooked resource: " + CookedAssetPath(true));
return nullptr;
}
return LoadCooked(File);
}
else
{ {
Log::Error("Couldn't locate resource: " + CookedAssetPath(true)); Log::Error("Couldn't locate resource: " + CookedAssetPath(true));
return nullptr; return nullptr;
} }
CFileInStream File(CookedAssetPath().ToStdString(), IOUtil::eBigEndian);
if (!File.IsValid())
{
Log::Error("Failed to open cooked resource: " + CookedAssetPath(true));
return nullptr;
}
return Load(File);
} }
CResource* CResourceEntry::Load(IInputStream& rInput) CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
{ {
// Overload to allow for load from an arbitrary input stream. // Overload to allow for load from an arbitrary input stream.
if (mpResource) return mpResource; if (mpResource) return mpResource;
if (!rInput.IsValid()) return nullptr; if (!rInput.IsValid()) return nullptr;
switch (mType) mpResource = CResourceFactory::LoadCookedResource(this, rInput);
{
case eAnimation: mpResource = CAnimationLoader::LoadANIM(rInput, this); break;
case eAnimEventData: mpResource = CUnsupportedFormatLoader::LoadEVNT(rInput, this); break;
case eAnimSet: mpResource = CAnimSetLoader::LoadANCSOrCHAR(rInput, this); break;
case eArea: mpResource = CAreaLoader::LoadMREA(rInput, this); break;
case eDependencyGroup: mpResource = CDependencyGroupLoader::LoadDGRP(rInput, this); break;
case eDynamicCollision: mpResource = CCollisionLoader::LoadDCLN(rInput, this); break;
case eFont: mpResource = CFontLoader::LoadFONT(rInput, this); break;
case eGuiFrame: mpResource = CUnsupportedFormatLoader::LoadFRME(rInput, this); break;
case eHintSystem: mpResource = CUnsupportedFormatLoader::LoadHINT(rInput, this); break;
case eMapWorld: mpResource = CUnsupportedFormatLoader::LoadMAPW(rInput, this); break;
case eMapUniverse: mpResource = CUnsupportedFormatLoader::LoadMAPU(rInput, this); break;
case eMidi: mpResource = CUnsupportedFormatLoader::LoadCSNG(rInput, this); break;
case eModel: mpResource = CModelLoader::LoadCMDL(rInput, this); break;
case eRuleSet: mpResource = CUnsupportedFormatLoader::LoadRULE(rInput, this); break;
case eScan: mpResource = CScanLoader::LoadSCAN(rInput, this); break;
case eSkeleton: mpResource = CSkeletonLoader::LoadCINF(rInput, this); break;
case eSkin: mpResource = CSkinLoader::LoadCSKR(rInput, this); break;
case eStaticGeometryMap: mpResource = CPoiToWorldLoader::LoadEGMC(rInput, this); break;
case eStringTable: mpResource = CStringLoader::LoadSTRG(rInput, this); break;
case eTexture: mpResource = CTextureDecoder::LoadTXTR(rInput, this); break;
case eWorld: mpResource = CWorldLoader::LoadMLVL(rInput, this); break;
case eParticle:
case eParticleElectric:
case eParticleSwoosh:
case eParticleDecal:
case eParticleWeapon:
case eParticleCollisionResponse:
mpResource = CUnsupportedParticleLoader::LoadParticle(rInput, this);
break;
default: mpResource = new CResource(this); break;
}
mpStore->TrackLoadedResource(this); mpStore->TrackLoadedResource(this);
return mpResource; return mpResource;
} }

View File

@ -56,8 +56,9 @@ public:
u64 Size() const; u64 Size() const;
bool NeedsRecook() const; bool NeedsRecook() const;
void SetGame(EGame NewGame); void SetGame(EGame NewGame);
bool Save();
CResource* Load(); CResource* Load();
CResource* Load(IInputStream& rInput); CResource* LoadCooked(IInputStream& rInput);
bool Unload(); bool Unload();
void Move(const TWideString& rkDir, const TWideString& rkName); void Move(const TWideString& rkDir, const TWideString& rkName);
void AddToProject(const TWideString& rkDir, const TWideString& rkName); void AddToProject(const TWideString& rkDir, const TWideString& rkName);

View File

@ -263,7 +263,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
CMemoryInStream MemStream(DataBuffer.data(), DataBuffer.size(), IOUtil::eBigEndian); CMemoryInStream MemStream(DataBuffer.data(), DataBuffer.size(), IOUtil::eBigEndian);
EResType Type = CResource::ResTypeForExtension(rkType); EResType Type = CResource::ResTypeForExtension(rkType);
CResourceEntry *pEntry = RegisterTransientResource(Type, rkID); CResourceEntry *pEntry = RegisterTransientResource(Type, rkID);
CResource *pRes = pEntry->Load(MemStream); CResource *pRes = pEntry->LoadCooked(MemStream);
return pRes; return pRes;
} }
@ -274,7 +274,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
CResourceEntry *pEntry = FindEntry(rkID); CResourceEntry *pEntry = FindEntry(rkID);
if (pEntry) return pEntry->Load(); if (pEntry) return pEntry->Load();
// Check in transient load directory // Check in transient load directory - this only works for cooked
EResType Type = CResource::ResTypeForExtension(rkType); EResType Type = CResource::ResTypeForExtension(rkType);
if (Type != eInvalidResType) if (Type != eInvalidResType)
@ -286,7 +286,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
TString Path = mTransientLoadDir.ToUTF8() + Name + "." + rkType.ToString(); TString Path = mTransientLoadDir.ToUTF8() + Name + "." + rkType.ToString();
CFileInStream File(Path.ToStdString(), IOUtil::eBigEndian); CFileInStream File(Path.ToStdString(), IOUtil::eBigEndian);
CResource *pRes = pEntry->Load(File); CResource *pRes = pEntry->LoadCooked(File);
if (!pRes) DeleteResourceEntry(pEntry); if (!pRes) DeleteResourceEntry(pEntry);
return pRes; return pRes;
@ -302,6 +302,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
CResource* CResourceStore::LoadResource(const TString& rkPath) CResource* CResourceStore::LoadResource(const TString& rkPath)
{ {
// todo - support loading raw resources from arbitrary directory
// Construct ID from string, check if resource is loaded already // Construct ID from string, check if resource is loaded already
TWideString Dir = FileUtil::MakeAbsolute(TWideString(rkPath.GetFileDirectory())); TWideString Dir = FileUtil::MakeAbsolute(TWideString(rkPath.GetFileDirectory()));
TString Name = rkPath.GetFileName(false); TString Name = rkPath.GetFileName(false);
@ -335,7 +336,7 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
mTransientLoadDir = Dir; mTransientLoadDir = Dir;
CResourceEntry *pEntry = RegisterTransientResource(Type, ID, Dir, Name); CResourceEntry *pEntry = RegisterTransientResource(Type, ID, Dir, Name);
CResource *pRes = pEntry->Load(File); CResource *pRes = pEntry->LoadCooked(File);
if (!pRes) DeleteResourceEntry(pEntry); if (!pRes) DeleteResourceEntry(pEntry);
mTransientLoadDir = OldTransientDir; mTransientLoadDir = OldTransientDir;
@ -414,8 +415,6 @@ void CResourceStore::DestroyUnreferencedResources()
DirIt = mTransientRoots.erase(DirIt); DirIt = mTransientRoots.erase(DirIt);
} }
} }
Log::Write(TString::FromInt32(mLoadedResources.size(), 0, 10) + " resources loaded");
} }
bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry) bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)

View File

@ -26,6 +26,17 @@ EResType CResource::ResTypeForExtension(CFourCC Extension)
} }
// ************ GLOBAL ************ // ************ GLOBAL ************
bool ResourceSupportsSerialization(EResType Type)
{
switch (Type)
{
case eWorld:
return true;
default:
return false;
}
}
TString GetResourceTypeName(EResType Type) TString GetResourceTypeName(EResType Type)
{ {
switch (Type) switch (Type)
@ -52,8 +63,8 @@ TString GetResourceTypeName(EResType Type)
case eDependencyGroup: return "Dependency Group"; case eDependencyGroup: return "Dependency Group";
case eDynamicCollision: return "Dynamic Collision"; case eDynamicCollision: return "Dynamic Collision";
case eFont: return "Font"; case eFont: return "Font";
case eGuiFrame: return "GUI Frame"; case eGuiFrame: return "Gui Frame";
case eGuiKeyFrame: return "GUI Keyframe"; case eGuiKeyFrame: return "Gui Keyframe";
case eHintSystem: return "Hint System"; case eHintSystem: return "Hint System";
case eMapArea: return "Area Map"; case eMapArea: return "Area Map";
case eMapWorld: return "World Map"; case eMapWorld: return "World Map";
@ -90,7 +101,7 @@ TString GetResourceTypeName(EResType Type)
case eStringTable: return "String Table"; case eStringTable: return "String Table";
case eTexture: return "Texture"; case eTexture: return "Texture";
case eTweak: return "Tweak Data"; case eTweak: return "Tweak Data";
case eUnknown_CAAD: return "Unknown (CAAD)"; case eUnknown_CAAD: return "CAAD";
case eUserEvaluatorData: return "User Evaluator Data"; case eUserEvaluatorData: return "User Evaluator Data";
case eVideo: return "Video"; case eVideo: return "Video";
case eWorld: return "World"; case eWorld: return "World";
@ -98,8 +109,16 @@ TString GetResourceTypeName(EResType Type)
} }
} }
TString GetResourceRawExtension(EResType /*Type*/, EGame /*Game*/) TString GetResourceSerialName(EResType Type)
{ {
TString Name = GetResourceTypeName(Type);
Name.RemoveWhitespace();
return Name;
}
TString GetResourceRawExtension(EResType Type, EGame /*Game*/)
{
if (Type == eWorld) return "mwld";
return ""; return "";
} }

View File

@ -9,6 +9,7 @@
#include <Common/CFourCC.h> #include <Common/CFourCC.h>
#include <Common/types.h> #include <Common/types.h>
#include <Common/TString.h> #include <Common/TString.h>
#include <Common/Serialization/IArchive.h>
// This macro creates functions that allow us to easily identify this resource type. // This macro creates functions that allow us to easily identify this resource type.
// Must be included on every CResource subclass. // Must be included on every CResource subclass.
@ -40,7 +41,8 @@ public:
} }
virtual ~CResource() {} virtual ~CResource() {}
virtual CDependencyTree* BuildDependencyTree() const { return new CDependencyTree(ID()); } virtual CDependencyTree* BuildDependencyTree() const { return new CDependencyTree(ID()); }
virtual void Serialize(IArchive& /*rArc*/) {}
inline CResourceEntry* Entry() const { return mpEntry; } inline CResourceEntry* Entry() const { return mpEntry; }
inline TString Source() const { return mpEntry ? mpEntry->CookedAssetPath(true).GetFileName() : ""; } inline TString Source() const { return mpEntry ? mpEntry->CookedAssetPath(true).GetFileName() : ""; }
@ -56,7 +58,9 @@ public:
}; };
// Global Functions // Global Functions
bool ResourceSupportsSerialization(EResType Type);
TString GetResourceTypeName(EResType Type); TString GetResourceTypeName(EResType Type);
TString GetResourceSerialName(EResType Type);
TString GetResourceRawExtension(EResType Type, EGame Game); TString GetResourceRawExtension(EResType Type, EGame Game);
TString GetResourceCookedExtension(EResType Type, EGame Game); TString GetResourceCookedExtension(EResType Type, EGame Game);

View File

@ -23,7 +23,7 @@ CDependencyTree* CWorld::BuildDependencyTree() const
for (u32 iArea = 0; iArea < mAreas.size(); iArea++) for (u32 iArea = 0; iArea < mAreas.size(); iArea++)
{ {
pTree->AddDependency(mAreas[iArea].FileID); pTree->AddDependency(mAreas[iArea].AreaResID);
pTree->AddDependency(mAreas[iArea].pAreaName); pTree->AddDependency(mAreas[iArea].pAreaName);
} }
@ -59,3 +59,69 @@ void CWorld::SetAreaLayerInfo(CGameArea *pArea)
pLayer->SetActive(rLayerInfo.EnabledByDefault); pLayer->SetActive(rLayerInfo.EnabledByDefault);
} }
} }
// ************ SERIALIZATION ************
void CWorld::Serialize(IArchive& rArc)
{
rArc << SERIAL("WorldNameSTRG", mpWorldName)
<< SERIAL("DarkWorldNameSTRG", mpDarkWorldName)
<< SERIAL("WorldSaveInfo", mpSaveWorld)
<< SERIAL("DefaultSkyCMDL", mpDefaultSkybox)
<< SERIAL("MapWorld", mpMapWorld)
<< SERIAL("Unknown1", mUnknown1)
<< SERIAL("UnknownAreas", mUnknownAreas)
<< SERIAL("UnknownAGSC", mUnknownAGSC)
<< SERIAL_CONTAINER("MemoryRelays", mMemoryRelays, "MemoryRelay")
<< SERIAL_CONTAINER("Areas", mAreas, "Area")
<< SERIAL_CONTAINER("AudioGroups", mAudioGrps, "AudioGroup");
}
void Serialize(IArchive& rArc, CWorld::SMemoryRelay& rMemRelay)
{
rArc << SERIAL_HEX("MemoryRelayID", rMemRelay.InstanceID)
<< SERIAL_HEX("TargetID", rMemRelay.TargetID)
<< SERIAL("Message", rMemRelay.Message)
<< SERIAL("Unknown", rMemRelay.Unknown);
}
void Serialize(IArchive& rArc, CWorld::SArea& rArea)
{
rArc << SERIAL("Name", rArea.InternalName)
<< SERIAL("NameSTRG", rArea.pAreaName)
<< SERIAL("Transform", rArea.Transform)
<< SERIAL("BoundingBox", rArea.AetherBox)
<< SERIAL("AreaMREA", rArea.AreaResID)
<< SERIAL_HEX("AreaID", rArea.AreaID)
<< SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex")
<< SERIAL_CONTAINER("Dependencies", rArea.Dependencies, "Dependency")
<< SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module")
<< SERIAL_CONTAINER("RelOffsets", rArea.RelOffsets, "Offset")
<< SERIAL("CommonDependsStart", rArea.CommonDependenciesStart)
<< SERIAL_CONTAINER("Docks", rArea.Docks, "Dock")
<< SERIAL_CONTAINER("Layers", rArea.Layers, "Layer");
}
void Serialize(IArchive& rArc, CWorld::SArea::SDock& rDock)
{
rArc << SERIAL_CONTAINER("ConnectingDocks", rDock.ConnectingDocks, "ConnectingDock")
<< SERIAL_CONTAINER("DockCoords", rDock.DockCoordinates, "Coord");
}
void Serialize(IArchive& rArc, CWorld::SArea::SDock::SConnectingDock& rDock)
{
rArc << SERIAL("AreaIndex", rDock.AreaIndex)
<< SERIAL("DockIndex", rDock.DockIndex);
}
void Serialize(IArchive& rArc, CWorld::SArea::SLayer& rLayer)
{
rArc << SERIAL("Name", rLayer.LayerName)
<< SERIAL("DefaultEnabled", rLayer.EnabledByDefault)
<< SERIAL("LayerDependsStart", rLayer.LayerDependenciesStart);
}
void Serialize(IArchive& rArc, CWorld::SAudioGrp& rAudioGrp)
{
rArc << SERIAL("StudioID", rAudioGrp.Unknown)
<< SERIAL("AGSC", rAudioGrp.ResID);
}

View File

@ -3,7 +3,6 @@
#include "CResource.h" #include "CResource.h"
#include "CStringTable.h" #include "CStringTable.h"
#include "SDependency.h"
#include "Core/Resource/Area/CGameArea.h" #include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Model/CModel.h" #include "Core/Resource/Model/CModel.h"
#include <Math/CTransform4f.h> #include <Math/CTransform4f.h>
@ -27,7 +26,7 @@ class CWorld : public CResource
u32 mUnknownAGSC; u32 mUnknownAGSC;
struct SAudioGrp struct SAudioGrp
{ {
u32 ResID; CAssetID ResID;
u32 Unknown; u32 Unknown;
}; };
std::vector<SAudioGrp> mAudioGrps; std::vector<SAudioGrp> mAudioGrps;
@ -47,11 +46,11 @@ class CWorld : public CResource
TResPtr<CStringTable> pAreaName; TResPtr<CStringTable> pAreaName;
CTransform4f Transform; CTransform4f Transform;
CAABox AetherBox; CAABox AetherBox;
u64 FileID; // Loading every single area as a CResource would be a very bad idea CAssetID AreaResID; // Loading every single area as a CResource would be a very bad idea
u64 AreaID; u64 AreaID;
std::vector<u16> AttachedAreaIDs; std::vector<u16> AttachedAreaIDs;
std::vector<SDependency> Dependencies; std::vector<CAssetID> Dependencies;
std::vector<TString> RelFilenames; std::vector<TString> RelFilenames;
std::vector<u32> RelOffsets; std::vector<u32> RelOffsets;
u32 CommonDependenciesStart; u32 CommonDependenciesStart;
@ -64,7 +63,7 @@ class CWorld : public CResource
u32 DockIndex; u32 DockIndex;
}; };
std::vector<SConnectingDock> ConnectingDocks; std::vector<SConnectingDock> ConnectingDocks;
CVector3f DockCoordinates[4]; std::vector<CVector3f> DockCoordinates;
}; };
std::vector<SDock> Docks; std::vector<SDock> Docks;
@ -79,7 +78,6 @@ class CWorld : public CResource
}; };
std::vector<SArea> mAreas; std::vector<SArea> mAreas;
public: public:
CWorld(CResourceEntry *pEntry = 0); CWorld(CResourceEntry *pEntry = 0);
~CWorld(); ~CWorld();
@ -87,6 +85,15 @@ public:
CDependencyTree* BuildDependencyTree() const; CDependencyTree* BuildDependencyTree() const;
void SetAreaLayerInfo(CGameArea *pArea); void SetAreaLayerInfo(CGameArea *pArea);
// Serialization
virtual void Serialize(IArchive& rArc);
friend void Serialize(IArchive& rArc, SMemoryRelay& rMemRelay);
friend void Serialize(IArchive& rArc, SArea& rArea);
friend void Serialize(IArchive& rArc, SArea::SDock& rDock);
friend void Serialize(IArchive& rArc, SArea::SDock::SConnectingDock& rDock);
friend void Serialize(IArchive& rArc, SArea::SLayer& rLayer);
friend void Serialize(IArchive& rArc, SAudioGrp& rAudioGrp);
// Accessors // Accessors
inline EGame Version() const { return mWorldVersion; } inline EGame Version() const { return mWorldVersion; }
inline CStringTable* WorldName() const { return mpWorldName; } inline CStringTable* WorldName() const { return mpWorldName; }
@ -96,7 +103,7 @@ public:
inline CResource* MapWorld() const { return mpMapWorld; } inline CResource* MapWorld() const { return mpMapWorld; }
inline u32 NumAreas() const { return mAreas.size(); } inline u32 NumAreas() const { return mAreas.size(); }
inline u64 AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].FileID; } inline u64 AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].AreaResID.ToLongLong(); }
inline u32 AreaAttachedCount(u32 AreaIndex) const { return mAreas[AreaIndex].AttachedAreaIDs.size(); } inline u32 AreaAttachedCount(u32 AreaIndex) const { return mAreas[AreaIndex].AttachedAreaIDs.size(); }
inline u32 AreaAttachedID(u32 AreaIndex, u32 AttachedIndex) const { return mAreas[AreaIndex].AttachedAreaIDs[AttachedIndex]; } inline u32 AreaAttachedID(u32 AreaIndex, u32 AttachedIndex) const { return mAreas[AreaIndex].AttachedAreaIDs[AttachedIndex]; }
inline TString AreaInternalName(u32 AreaIndex) const { return mAreas[AreaIndex].InternalName; } inline TString AreaInternalName(u32 AreaIndex) const { return mAreas[AreaIndex].InternalName; }

View File

@ -0,0 +1,103 @@
#ifndef CRESOURCEFACTORY
#define CRESOURCEFACTORY
#include "CAnimationLoader.h"
#include "CAnimSetLoader.h"
#include "CAreaLoader.h"
#include "CCollisionLoader.h"
#include "CDependencyGroupLoader.h"
#include "CFontLoader.h"
#include "CMaterialLoader.h"
#include "CModelLoader.h"
#include "CPoiToWorldLoader.h"
#include "CScanLoader.h"
#include "CScriptLoader.h"
#include "CSkeletonLoader.h"
#include "CSkinLoader.h"
#include "CStringLoader.h"
#include "CTextureDecoder.h"
#include "CUnsupportedFormatLoader.h"
#include "CUnsupportedParticleLoader.h"
#include "CWorldLoader.h"
#include "Core/Resource/Resources.h"
// Static helper class to allow spawning resources based on an EResType
class CResourceFactory
{
CResourceFactory() {}
public:
static CResource* SpawnResource(CResourceEntry *pEntry)
{
switch (pEntry->ResourceType())
{
case eAnimation: return new CAnimation(pEntry);
case eAnimSet: return new CAnimSet(pEntry);
case eArea: return new CGameArea(pEntry);
case eDynamicCollision: return new CCollisionMeshGroup(pEntry);
case eDependencyGroup: return new CDependencyGroup(pEntry);
case eFont: return new CFont(pEntry);
case eModel: return new CModel(pEntry);
case eScan: return new CScan(pEntry);
case eSkeleton: return new CSkeleton(pEntry);
case eSkin: return new CSkin(pEntry);
case eStaticGeometryMap: return new CPoiToWorld(pEntry);
case eStringTable: return new CStringTable(pEntry);
case eTexture: return new CTexture(pEntry);
case eWorld: return new CWorld(pEntry);
default: return nullptr; // should it return a CResource instead?
}
}
static CResource* LoadCookedResource(CResourceEntry *pEntry, IInputStream& rInput)
{
// Warning: It is the caller's responsibility to check if the required resource is already in memory before calling this function.
if (!rInput.IsValid()) return nullptr;
CResource *pRes = nullptr;
switch (pEntry->ResourceType())
{
case eAnimation: pRes = CAnimationLoader::LoadANIM(rInput, pEntry); break;
case eAnimEventData: pRes = CUnsupportedFormatLoader::LoadEVNT(rInput, pEntry); break;
case eAnimSet: pRes = CAnimSetLoader::LoadANCSOrCHAR(rInput, pEntry); break;
case eArea: pRes = CAreaLoader::LoadMREA(rInput, pEntry); break;
case eDependencyGroup: pRes = CDependencyGroupLoader::LoadDGRP(rInput, pEntry); break;
case eDynamicCollision: pRes = CCollisionLoader::LoadDCLN(rInput, pEntry); break;
case eFont: pRes = CFontLoader::LoadFONT(rInput, pEntry); break;
case eGuiFrame: pRes = CUnsupportedFormatLoader::LoadFRME(rInput, pEntry); break;
case eHintSystem: pRes = CUnsupportedFormatLoader::LoadHINT(rInput, pEntry); break;
case eMapWorld: pRes = CUnsupportedFormatLoader::LoadMAPW(rInput, pEntry); break;
case eMapUniverse: pRes = CUnsupportedFormatLoader::LoadMAPU(rInput, pEntry); break;
case eMidi: pRes = CUnsupportedFormatLoader::LoadCSNG(rInput, pEntry); break;
case eModel: pRes = CModelLoader::LoadCMDL(rInput, pEntry); break;
case eRuleSet: pRes = CUnsupportedFormatLoader::LoadRULE(rInput, pEntry); break;
case eScan: pRes = CScanLoader::LoadSCAN(rInput, pEntry); break;
case eSkeleton: pRes = CSkeletonLoader::LoadCINF(rInput, pEntry); break;
case eSkin: pRes = CSkinLoader::LoadCSKR(rInput, pEntry); break;
case eStaticGeometryMap: pRes = CPoiToWorldLoader::LoadEGMC(rInput, pEntry); break;
case eStringTable: pRes = CStringLoader::LoadSTRG(rInput, pEntry); break;
case eTexture: pRes = CTextureDecoder::LoadTXTR(rInput, pEntry); break;
case eWorld: pRes = CWorldLoader::LoadMLVL(rInput, pEntry); break;
case eParticle:
case eParticleElectric:
case eParticleSwoosh:
case eParticleDecal:
case eParticleWeapon:
case eParticleCollisionResponse:
pRes = CUnsupportedParticleLoader::LoadParticle(rInput, pEntry);
break;
default:
pRes = new CResource(pEntry);
break;
}
return pRes;
}
};
#endif // CRESOURCEFACTORY

View File

@ -67,13 +67,13 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
if (mVersion < eCorruptionProto) if (mVersion < eCorruptionProto)
{ {
pArea->FileID = rMLVL.ReadLong() & 0xFFFFFFFF; // This is the MREA ID; not actually loading it for obvious reasons pArea->AreaResID = rMLVL.ReadLong() & 0xFFFFFFFF;
pArea->AreaID = rMLVL.ReadLong() & 0xFFFFFFFF; pArea->AreaID = rMLVL.ReadLong() & 0xFFFFFFFF;
} }
else else
{ {
pArea->FileID = rMLVL.ReadLongLong(); pArea->AreaResID = rMLVL.ReadLongLong();
pArea->AreaID = rMLVL.ReadLongLong(); pArea->AreaID = rMLVL.ReadLongLong();
} }
@ -86,7 +86,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
if (mVersion < eCorruptionProto) if (mVersion < eCorruptionProto)
rMLVL.Seek(0x4, SEEK_CUR); // Skipping unknown value (always 0) rMLVL.Seek(0x4, SEEK_CUR); // Skipping unknown value (always 0)
// Depedencies // Dependencies
if (mVersion < eCorruptionProto) if (mVersion < eCorruptionProto)
{ {
u32 NumDependencies = rMLVL.ReadLong(); u32 NumDependencies = rMLVL.ReadLong();
@ -94,10 +94,8 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
for (u32 iDep = 0; iDep < NumDependencies; iDep++) for (u32 iDep = 0; iDep < NumDependencies; iDep++)
{ {
SDependency Dependency; pArea->Dependencies.push_back( CAssetID(rMLVL, e32Bit) );
Dependency.ResID = rMLVL.ReadLong() & 0xFFFFFFFF; rMLVL.Seek(0x4, SEEK_CUR);
Dependency.ResType = rMLVL.ReadLong();
pArea->Dependencies.push_back(Dependency);
} }
/** /**
@ -137,7 +135,8 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
} }
u32 NumCoordinates = rMLVL.ReadLong(); u32 NumCoordinates = rMLVL.ReadLong();
if (NumCoordinates != 4) Log::Error("Dock coordinate count not 4"); ASSERT(NumCoordinates == 4);
pDock->DockCoordinates.resize(NumCoordinates);
for (u32 iCoord = 0; iCoord < NumCoordinates; iCoord++) for (u32 iCoord = 0; iCoord < NumCoordinates; iCoord++)
pDock->DockCoordinates[iCoord] = CVector3f(rMLVL); pDock->DockCoordinates[iCoord] = CVector3f(rMLVL);
@ -245,7 +244,7 @@ void CWorldLoader::LoadReturnsMLVL(IInputStream& rMLVL)
pArea->pAreaName = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), "STRG"); pArea->pAreaName = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), "STRG");
pArea->Transform = CTransform4f(rMLVL); pArea->Transform = CTransform4f(rMLVL);
pArea->AetherBox = CAABox(rMLVL); pArea->AetherBox = CAABox(rMLVL);
pArea->FileID = rMLVL.ReadLongLong(); pArea->AreaResID = rMLVL.ReadLongLong();
pArea->AreaID = rMLVL.ReadLongLong(); pArea->AreaID = rMLVL.ReadLongLong();
rMLVL.Seek(0x4, SEEK_CUR); rMLVL.Seek(0x4, SEEK_CUR);

View File

@ -0,0 +1,21 @@
#ifndef RESOURCES_H
#define RESOURCES_H
#include "CAnimation.h"
#include "CAnimSet.h"
#include "CCollisionMeshGroup.h"
#include "CDependencyGroup.h"
#include "CFont.h"
#include "CPoiToWorld.h"
#include "CResource.h"
#include "CScan.h"
#include "CSkeleton.h"
#include "CSkin.h"
#include "CStringTable.h"
#include "CTexture.h"
#include "CWorld.h"
#include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Model/CModel.h"
#endif // RESOURCES_H

View File

@ -1,14 +0,0 @@
#ifndef SDEPENDENCY
#define SDEPENDENCY
#include <Common/CFourCC.h>
#include <Common/types.h>
struct SDependency
{
u64 ResID;
CFourCC ResType;
};
#endif // SDEPENDENCY

View File

@ -2,6 +2,7 @@
#define TRESPTR_H #define TRESPTR_H
#include "CResource.h" #include "CResource.h"
#include "Core/GameProject/CGameProject.h"
template <typename ResType> template <typename ResType>
class TResPtr class TResPtr
@ -30,6 +31,21 @@ public:
mpRes->Release(); mpRes->Release();
} }
inline void Serialize(IArchive& rArc)
{
bool IsReader = rArc.IsReader();
EGame ActiveGame = gpResourceStore->ActiveProject()->Game();
CAssetID ID = (mpRes && !IsReader ? mpRes->ID() : (ActiveGame <= eEchoes ? CAssetID::skInvalidID32 : CAssetID::skInvalidID64));
rArc.SerializePrimitive(ID);
if (IsReader)
{
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
*this = (pEntry ? pEntry->Load() : nullptr);
}
}
inline void Delete() inline void Delete()
{ {
// use with caution! this function exists because not all resources are cached currently // use with caution! this function exists because not all resources are cached currently

View File

@ -22,6 +22,12 @@ CAABox::CAABox(IInputStream& rInput)
{ {
} }
void CAABox::Serialize(IArchive& rArc)
{
rArc << SERIAL("Min", mMin)
<< SERIAL("Max", mMax);
}
void CAABox::Write(IOutputStream& rOutput) void CAABox::Write(IOutputStream& rOutput)
{ {
mMin.Write(rOutput); mMin.Write(rOutput);

View File

@ -2,6 +2,7 @@
#define CAABOX_H #define CAABOX_H
#include "CVector3f.h" #include "CVector3f.h"
#include <Common/Serialization/IArchive.h>
#include <FileIO/IInputStream.h> #include <FileIO/IInputStream.h>
#include <FileIO/IOutputStream.h> #include <FileIO/IOutputStream.h>
#include <utility> #include <utility>
@ -17,6 +18,7 @@ public:
CAABox(); CAABox();
CAABox(const CVector3f& rkMin, const CVector3f& rkMax); CAABox(const CVector3f& rkMin, const CVector3f& rkMax);
CAABox(IInputStream& rInput); CAABox(IInputStream& rInput);
void Serialize(IArchive& rArc);
void Write(IOutputStream& rOutput); void Write(IOutputStream& rOutput);
CVector3f Center() const; CVector3f Center() const;
CVector3f Size() const; CVector3f Size() const;

View File

@ -71,6 +71,13 @@ CTransform4f::CTransform4f(CVector3f Position, CVector3f Rotation, CVector3f Sca
Translate(Position); Translate(Position);
} }
void CTransform4f::Serialize(IArchive& rOut)
{
rOut << SERIAL("Row0Col0", m[0][0]) << SERIAL("Row0Col1", m[0][1]) << SERIAL("Row0Col2", m[0][2]) << SERIAL("Row0Col3", m[0][3])
<< SERIAL("Row1Col0", m[1][0]) << SERIAL("Row1Col1", m[1][1]) << SERIAL("Row1Col2", m[1][2]) << SERIAL("Row1Col3", m[1][3])
<< SERIAL("Row2Col0", m[2][0]) << SERIAL("Row2Col1", m[2][1]) << SERIAL("Row2Col2", m[2][2]) << SERIAL("Row2Col3", m[2][3]);
}
void CTransform4f::Write(IOutputStream& rOut) void CTransform4f::Write(IOutputStream& rOut)
{ {
for (int iFlt = 0; iFlt < 12; iFlt++) for (int iFlt = 0; iFlt < 12; iFlt++)

View File

@ -2,6 +2,7 @@
#define CTRANSFORM4F_H #define CTRANSFORM4F_H
#include <FileIO/FileIO.h> #include <FileIO/FileIO.h>
#include <Common/Serialization/IArchive.h>
#include "CMatrix4f.h" #include "CMatrix4f.h"
#include <glm.hpp> #include <glm.hpp>
@ -21,6 +22,7 @@ public:
float m20, float m21, float m22, float m23); float m20, float m21, float m22, float m23);
CTransform4f(CVector3f Position, CQuaternion Rotation, CVector3f Scale); CTransform4f(CVector3f Position, CQuaternion Rotation, CVector3f Scale);
CTransform4f(CVector3f Position, CVector3f Rotation, CVector3f Scale); CTransform4f(CVector3f Position, CVector3f Rotation, CVector3f Scale);
void Serialize(IArchive& rOut);
void Write(IOutputStream& rOut); void Write(IOutputStream& rOut);
// Math // Math

View File

@ -36,6 +36,11 @@ void CVector3f::Write(IOutputStream& rOutput) const
rOutput.WriteFloat(Z); rOutput.WriteFloat(Z);
} }
void CVector3f::Serialize(IArchive& rArc)
{
rArc << SERIAL_AUTO(X) << SERIAL_AUTO(Y) << SERIAL_AUTO(Z);
}
// ************ SWIZZLE ************ // ************ SWIZZLE ************
CVector2f CVector3f::XY() CVector2f CVector3f::XY()
{ {

View File

@ -3,6 +3,7 @@
#include <FileIO/IInputStream.h> #include <FileIO/IInputStream.h>
#include <FileIO/IOutputStream.h> #include <FileIO/IOutputStream.h>
#include <Common/Serialization/IArchive.h>
#include <ostream> #include <ostream>
class CMatrix4f; class CMatrix4f;
@ -20,6 +21,7 @@ public:
CVector3f(float _X, float _Y, float _Z); CVector3f(float _X, float _Y, float _Z);
CVector3f(IInputStream& rInput); CVector3f(IInputStream& rInput);
void Write(IOutputStream& rOutput) const; void Write(IOutputStream& rOutput) const;
void Serialize(IArchive& rArc);
// Swizzle // Swizzle
CVector2f XY(); CVector2f XY();

View File

@ -24,7 +24,8 @@ CONFIG (debug, debug|release) {
# Debug Libs # Debug Libs
LIBS += -L$$BUILD_DIR/FileIO/ -lFileIOd \ LIBS += -L$$BUILD_DIR/FileIO/ -lFileIOd \
-L$$BUILD_DIR/Common/ -lCommond -L$$BUILD_DIR/Common/ -lCommond \
-L$$EXTERNALS_DIR/tinyxml2/lib/ -ltinyxml2d
# Debug Target Dependencies # Debug Target Dependencies
win32 { win32 {
@ -40,7 +41,8 @@ CONFIG (release, debug|release) {
# Release Libs # Release Libs
LIBS += -L$$BUILD_DIR/FileIO/ -lFileIO \ LIBS += -L$$BUILD_DIR/FileIO/ -lFileIO \
-L$$BUILD_DIR/Common/ -lCommon -L$$BUILD_DIR/Common/ -lCommon \
-L$$EXTERNALS_DIR/tinyxml2/lib/ -ltinyxml2
# Release Target Dependencies # Release Target Dependencies
win32 { win32 {
@ -57,6 +59,7 @@ LIBS += -L$$EXTERNALS_DIR/lzo-2.08/lib -llzo-2.08 \
INCLUDEPATH += $$PWE_MAIN_INCLUDE \ INCLUDEPATH += $$PWE_MAIN_INCLUDE \
$$EXTERNALS_DIR/glm/glm \ $$EXTERNALS_DIR/glm/glm \
$$EXTERNALS_DIR/lzo-2.08/include \ $$EXTERNALS_DIR/lzo-2.08/include \
$$EXTERNALS_DIR/tinyxml2/include \
$$EXTERNALS_DIR/zlib/include $$EXTERNALS_DIR/zlib/include
# Header Files # Header Files