Added dependency tree system, methods for generating dependency trees from resources, and saving/loading dependency trees to the project cache folder
This commit is contained in:
parent
c1405bfac1
commit
9341c11ac8
|
@ -32,6 +32,10 @@ public:
|
||||||
inline bool HasFlag(FlagEnum Flag) const { return ((mValue & Flag) != 0); }
|
inline bool HasFlag(FlagEnum Flag) const { return ((mValue & Flag) != 0); }
|
||||||
inline bool HasAnyFlags(TFlags Flags) const { return ((mValue & Flags) != 0); }
|
inline bool HasAnyFlags(TFlags Flags) const { return ((mValue & Flags) != 0); }
|
||||||
inline bool HasAllFlags(TFlags Flags) const { return ((mValue & Flags) == Flags); }
|
inline bool HasAllFlags(TFlags Flags) const { return ((mValue & Flags) == Flags); }
|
||||||
|
inline void SetFlag(FlagEnum Flag) { mValue |= Flag; }
|
||||||
|
inline void SetFlag(TFlags Flags) { mValue |= Flags; }
|
||||||
|
inline void ClearFlag(FlagEnum Flag) { mValue &= ~Flag; }
|
||||||
|
inline void ClearFlag(TFlags Flags) { mValue &= ~Flags; }
|
||||||
};
|
};
|
||||||
#define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName;
|
#define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName;
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ public:
|
||||||
inline void Insert(u32 Pos, CharType Chr)
|
inline void Insert(u32 Pos, CharType Chr)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if (Size() <= Pos)
|
if (Size() < Pos)
|
||||||
throw std::out_of_range("Invalid position passed to TBasicString::Insert()");
|
throw std::out_of_range("Invalid position passed to TBasicString::Insert()");
|
||||||
#endif
|
#endif
|
||||||
mInternalString.insert(Pos, 1, Chr);
|
mInternalString.insert(Pos, 1, Chr);
|
||||||
|
@ -221,7 +221,7 @@ public:
|
||||||
inline void Insert(u32 Pos, const CharType* pkStr)
|
inline void Insert(u32 Pos, const CharType* pkStr)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if (Size() <= Pos)
|
if (Size() < Pos)
|
||||||
throw std::out_of_range("Invalid position passed to TBasicString::Insert()");
|
throw std::out_of_range("Invalid position passed to TBasicString::Insert()");
|
||||||
#endif
|
#endif
|
||||||
mInternalString.insert(Pos, pkStr);
|
mInternalString.insert(Pos, pkStr);
|
||||||
|
@ -846,7 +846,10 @@ public:
|
||||||
|
|
||||||
static TBasicString<CharType> FromFloat(float Value, int MinDecimals = 1)
|
static TBasicString<CharType> FromFloat(float Value, int MinDecimals = 1)
|
||||||
{
|
{
|
||||||
_TString Out = std::to_string(Value);
|
std::basic_stringstream<CharType> sstream;
|
||||||
|
sstream << Value;
|
||||||
|
_TString Out = sstream.str();
|
||||||
|
|
||||||
int NumZeroes = Out.Size() - (Out.IndexOf(LITERAL(".")) + 1);
|
int NumZeroes = Out.Size() - (Out.IndexOf(LITERAL(".")) + 1);
|
||||||
|
|
||||||
while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals)
|
while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals)
|
||||||
|
|
|
@ -196,7 +196,10 @@ HEADERS += \
|
||||||
GameProject/CResourceStore.h \
|
GameProject/CResourceStore.h \
|
||||||
GameProject/CVirtualDirectory.h \
|
GameProject/CVirtualDirectory.h \
|
||||||
GameProject/CResourceEntry.h \
|
GameProject/CResourceEntry.h \
|
||||||
GameProject/CResourceIterator.h
|
GameProject/CResourceIterator.h \
|
||||||
|
Resource/CDependencyGroup.h \
|
||||||
|
Resource/Factory/CDependencyGroupLoader.h \
|
||||||
|
GameProject/CDependencyTree.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -287,4 +290,6 @@ SOURCES += \
|
||||||
GameProject/CResourceStore.cpp \
|
GameProject/CResourceStore.cpp \
|
||||||
GameProject/CVirtualDirectory.cpp \
|
GameProject/CVirtualDirectory.cpp \
|
||||||
GameProject/CResourceEntry.cpp \
|
GameProject/CResourceEntry.cpp \
|
||||||
GameProject/CPackage.cpp
|
GameProject/CPackage.cpp \
|
||||||
|
Resource/Factory/CDependencyGroupLoader.cpp \
|
||||||
|
GameProject/CDependencyTree.cpp
|
||||||
|
|
|
@ -0,0 +1,320 @@
|
||||||
|
#include "CDependencyTree.h"
|
||||||
|
#include "Core/Resource/Script/CScriptLayer.h"
|
||||||
|
#include "Core/Resource/Script/CScriptObject.h"
|
||||||
|
|
||||||
|
// ************ CResourceDependency ************
|
||||||
|
EDependencyNodeType CResourceDependency::Type() const
|
||||||
|
{
|
||||||
|
return eDNT_ResourceDependency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceDependency::Read(IInputStream& rFile, EUIDLength IDLength)
|
||||||
|
{
|
||||||
|
mID = CUniqueID(rFile, IDLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceDependency::Write(IOutputStream& rFile, EUIDLength IDLength) const
|
||||||
|
{
|
||||||
|
if (IDLength == e32Bit)
|
||||||
|
rFile.WriteLong(mID.ToLong());
|
||||||
|
else
|
||||||
|
rFile.WriteLongLong(mID.ToLongLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ CAnimSetDependency ************
|
||||||
|
EDependencyNodeType CAnimSetDependency::Type() const
|
||||||
|
{
|
||||||
|
return eDNT_AnimSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetDependency::Read(IInputStream& rFile, EUIDLength IDLength)
|
||||||
|
{
|
||||||
|
CResourceDependency::Read(rFile, IDLength);
|
||||||
|
mUsedChar = rFile.ReadLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetDependency::Write(IOutputStream& rFile, EUIDLength IDLength) const
|
||||||
|
{
|
||||||
|
CResourceDependency::Write(rFile, IDLength);
|
||||||
|
rFile.WriteLong(mUsedChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static
|
||||||
|
CAnimSetDependency* CAnimSetDependency::BuildDependency(TCharacterProperty *pProp)
|
||||||
|
{
|
||||||
|
ASSERT(pProp && pProp->Type() == eCharacterProperty && pProp->Instance()->Area()->Game() <= eEchoes);
|
||||||
|
|
||||||
|
CAnimationParameters Params = pProp->Get();
|
||||||
|
if (!Params.ID().IsValid()) return nullptr;
|
||||||
|
|
||||||
|
CAnimSetDependency *pDepend = new CAnimSetDependency;
|
||||||
|
pDepend->SetID(Params.ID());
|
||||||
|
pDepend->SetUsedChar(Params.CharacterIndex());
|
||||||
|
return pDepend;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ CDependencyTree ************
|
||||||
|
CDependencyTree::~CDependencyTree()
|
||||||
|
{
|
||||||
|
for (u32 iRef = 0; iRef < mReferencedResources.size(); iRef++)
|
||||||
|
delete mReferencedResources[iRef];
|
||||||
|
}
|
||||||
|
|
||||||
|
EDependencyNodeType CDependencyTree::Type() const
|
||||||
|
{
|
||||||
|
return eDNT_Root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDependencyTree::Read(IInputStream& rFile, EUIDLength IDLength)
|
||||||
|
{
|
||||||
|
mID = CUniqueID(rFile, IDLength);
|
||||||
|
|
||||||
|
u32 NumDepends = rFile.ReadLong();
|
||||||
|
mReferencedResources.reserve(NumDepends);
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < NumDepends; iDep++)
|
||||||
|
{
|
||||||
|
CResourceDependency *pDepend = new CResourceDependency;
|
||||||
|
pDepend->Read(rFile, IDLength);
|
||||||
|
mReferencedResources.push_back(pDepend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDependencyTree::Write(IOutputStream& rFile, EUIDLength IDLength) const
|
||||||
|
{
|
||||||
|
if (IDLength == e32Bit)
|
||||||
|
rFile.WriteLong(mID.ToLong());
|
||||||
|
else
|
||||||
|
rFile.WriteLongLong(mID.ToLongLong());
|
||||||
|
|
||||||
|
rFile.WriteLong( mReferencedResources.size() );
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < mReferencedResources.size(); iDep++)
|
||||||
|
mReferencedResources[iDep]->Write(rFile, IDLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 CDependencyTree::NumDependencies() const
|
||||||
|
{
|
||||||
|
return mReferencedResources.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDependencyTree::HasDependency(const CUniqueID& rkID)
|
||||||
|
{
|
||||||
|
for (u32 iDep = 0; iDep < mReferencedResources.size(); iDep++)
|
||||||
|
{
|
||||||
|
if (mReferencedResources[iDep]->ID() == rkID)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUniqueID CDependencyTree::DependencyByIndex(u32 Index) const
|
||||||
|
{
|
||||||
|
ASSERT(Index >= 0 && Index < mReferencedResources.size());
|
||||||
|
return mReferencedResources[Index]->ID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDependencyTree::AddDependency(CResource *pRes)
|
||||||
|
{
|
||||||
|
if (!pRes || HasDependency(pRes->ResID())) return;
|
||||||
|
CResourceDependency *pDepend = new CResourceDependency(pRes->ResID());
|
||||||
|
mReferencedResources.push_back(pDepend);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDependencyTree::AddDependency(const CUniqueID& rkID)
|
||||||
|
{
|
||||||
|
if (!rkID.IsValid() || HasDependency(rkID)) return;
|
||||||
|
CResourceDependency *pDepend = new CResourceDependency(rkID);
|
||||||
|
mReferencedResources.push_back(pDepend);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ CAnimSetDependencyTree ************
|
||||||
|
EDependencyNodeType CAnimSetDependencyTree::Type() const
|
||||||
|
{
|
||||||
|
return eDNT_AnimSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetDependencyTree::Read(IInputStream& rFile, EUIDLength IDLength)
|
||||||
|
{
|
||||||
|
CDependencyTree::Read(rFile, IDLength);
|
||||||
|
u32 NumChars = rFile.ReadLong();
|
||||||
|
mCharacterOffsets.reserve(NumChars);
|
||||||
|
|
||||||
|
for (u32 iChar = 0; iChar < NumChars; iChar++)
|
||||||
|
mCharacterOffsets.push_back( rFile.ReadLong() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetDependencyTree::Write(IOutputStream& rFile, EUIDLength IDLength) const
|
||||||
|
{
|
||||||
|
CDependencyTree::Write(rFile, IDLength);
|
||||||
|
rFile.WriteLong(mCharacterOffsets.size());
|
||||||
|
|
||||||
|
for (u32 iChar = 0; iChar < mCharacterOffsets.size(); iChar++)
|
||||||
|
rFile.WriteLong( mCharacterOffsets[iChar] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ CScriptInstanceDependencyTree ************
|
||||||
|
CScriptInstanceDependencyTree::~CScriptInstanceDependencyTree()
|
||||||
|
{
|
||||||
|
for (u32 iDep = 0; iDep < mDependencies.size(); iDep++)
|
||||||
|
delete mDependencies[iDep];
|
||||||
|
}
|
||||||
|
|
||||||
|
EDependencyNodeType CScriptInstanceDependencyTree::Type() const
|
||||||
|
{
|
||||||
|
return eDNT_ScriptInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScriptInstanceDependencyTree::Read(IInputStream& rFile, EUIDLength IDLength)
|
||||||
|
{
|
||||||
|
mObjectType = rFile.ReadLong();
|
||||||
|
u32 NumDepends = rFile.ReadLong();
|
||||||
|
mDependencies.reserve(NumDepends);
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < NumDepends; iDep++)
|
||||||
|
{
|
||||||
|
CUniqueID ID(rFile, IDLength);
|
||||||
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
|
|
||||||
|
if (pEntry && pEntry->ResourceType() == eAnimSet && pEntry->Game() <= eEchoes)
|
||||||
|
{
|
||||||
|
CAnimSetDependency *pSet = new CAnimSetDependency();
|
||||||
|
pSet->SetID(ID);
|
||||||
|
pSet->SetUsedChar( rFile.ReadLong() );
|
||||||
|
mDependencies.push_back(pSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CResourceDependency *pRes = new CResourceDependency(ID);
|
||||||
|
mDependencies.push_back(pRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScriptInstanceDependencyTree::Write(IOutputStream& rFile, EUIDLength IDLength) const
|
||||||
|
{
|
||||||
|
rFile.WriteLong(mObjectType);
|
||||||
|
rFile.WriteLong(mDependencies.size());
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < mDependencies.size(); iDep++)
|
||||||
|
mDependencies[iDep]->Write(rFile, IDLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CScriptInstanceDependencyTree::HasDependency(const CUniqueID& rkID)
|
||||||
|
{
|
||||||
|
if (!rkID.IsValid()) return false;
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < mDependencies.size(); iDep++)
|
||||||
|
{
|
||||||
|
CResourceDependency *pDep = mDependencies[iDep];
|
||||||
|
if (pDep->ID() == rkID) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static
|
||||||
|
CScriptInstanceDependencyTree* CScriptInstanceDependencyTree::BuildTree(CScriptObject *pInstance)
|
||||||
|
{
|
||||||
|
CScriptInstanceDependencyTree *pTree = new CScriptInstanceDependencyTree();
|
||||||
|
pTree->mObjectType = pInstance->ObjectTypeID();
|
||||||
|
ParseStructDependencies(pTree, pInstance->Properties());
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScriptInstanceDependencyTree::ParseStructDependencies(CScriptInstanceDependencyTree *pTree, CPropertyStruct *pStruct)
|
||||||
|
{
|
||||||
|
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++)
|
||||||
|
{
|
||||||
|
IProperty *pProp = pStruct->PropertyByIndex(iProp);
|
||||||
|
|
||||||
|
if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
|
||||||
|
ParseStructDependencies(pTree, static_cast<CPropertyStruct*>(pProp));
|
||||||
|
|
||||||
|
else if (pProp->Type() == eFileProperty)
|
||||||
|
{
|
||||||
|
CUniqueID ID = static_cast<TFileProperty*>(pProp)->Get().ID();
|
||||||
|
|
||||||
|
if (ID.IsValid() && !pTree->HasDependency(ID))
|
||||||
|
{
|
||||||
|
CResourceDependency *pDep = new CResourceDependency(ID);
|
||||||
|
pTree->mDependencies.push_back(pDep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (pProp->Type() == eCharacterProperty)
|
||||||
|
{
|
||||||
|
TCharacterProperty *pChar = static_cast<TCharacterProperty*>(pProp);
|
||||||
|
CUniqueID ID = pChar->Get().ID();
|
||||||
|
|
||||||
|
if (ID.IsValid() && !pTree->HasDependency(ID))
|
||||||
|
pTree->mDependencies.push_back( CAnimSetDependency::BuildDependency(pChar) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ CAreaDependencyTree ************
|
||||||
|
CAreaDependencyTree::~CAreaDependencyTree()
|
||||||
|
{
|
||||||
|
for (u32 iInst = 0; iInst < mScriptInstances.size(); iInst++)
|
||||||
|
delete mScriptInstances[iInst];
|
||||||
|
}
|
||||||
|
|
||||||
|
EDependencyNodeType CAreaDependencyTree::Type() const
|
||||||
|
{
|
||||||
|
return eDNT_Area;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAreaDependencyTree::Read(IInputStream& rFile, EUIDLength IDLength)
|
||||||
|
{
|
||||||
|
// Base dependency list contains non-script dependencies (world geometry textures + PATH/PTLA/EGMC)
|
||||||
|
CDependencyTree::Read(rFile, IDLength);
|
||||||
|
u32 NumScriptInstances = rFile.ReadLong();
|
||||||
|
mScriptInstances.reserve(NumScriptInstances);
|
||||||
|
|
||||||
|
for (u32 iInst = 0; iInst < NumScriptInstances; iInst++)
|
||||||
|
{
|
||||||
|
CScriptInstanceDependencyTree *pInst = new CScriptInstanceDependencyTree;
|
||||||
|
pInst->Read(rFile, IDLength);
|
||||||
|
mScriptInstances.push_back(pInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 NumLayers = rFile.ReadLong();
|
||||||
|
mLayerOffsets.reserve(NumLayers);
|
||||||
|
|
||||||
|
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
|
||||||
|
mLayerOffsets.push_back( rFile.ReadLong() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAreaDependencyTree::Write(IOutputStream& rFile, EUIDLength IDLength) const
|
||||||
|
{
|
||||||
|
CDependencyTree::Write(rFile, IDLength);
|
||||||
|
rFile.WriteLong(mScriptInstances.size());
|
||||||
|
|
||||||
|
for (u32 iInst = 0; iInst < mScriptInstances.size(); iInst++)
|
||||||
|
mScriptInstances[iInst]->Write(rFile, IDLength);
|
||||||
|
|
||||||
|
rFile.WriteLong(mLayerOffsets.size());
|
||||||
|
|
||||||
|
for (u32 iLyr = 0; iLyr < mLayerOffsets.size(); iLyr++)
|
||||||
|
rFile.WriteLong(mLayerOffsets[iLyr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer)
|
||||||
|
{
|
||||||
|
if (!pLayer) return;
|
||||||
|
mLayerOffsets.push_back(mScriptInstances.size());
|
||||||
|
|
||||||
|
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
||||||
|
{
|
||||||
|
CScriptInstanceDependencyTree *pTree = CScriptInstanceDependencyTree::BuildTree( pLayer->InstanceByIndex(iInst) );
|
||||||
|
ASSERT(pTree != nullptr);
|
||||||
|
|
||||||
|
if (pTree->NumDependencies() > 0)
|
||||||
|
mScriptInstances.push_back(pTree);
|
||||||
|
else
|
||||||
|
delete pTree;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
#ifndef CDEPENDENCYTREE
|
||||||
|
#define CDEPENDENCYTREE
|
||||||
|
|
||||||
|
#include "CResourceEntry.h"
|
||||||
|
#include <FileIO/FileIO.h>
|
||||||
|
#include <Common/AssertMacro.h>
|
||||||
|
#include <Common/CUniqueID.h>
|
||||||
|
|
||||||
|
class CScriptLayer;
|
||||||
|
class CScriptObject;
|
||||||
|
class CPropertyStruct;
|
||||||
|
class TCharacterProperty;
|
||||||
|
|
||||||
|
// Group of node classes forming a tree of cached resource dependencies.
|
||||||
|
enum EDependencyNodeType
|
||||||
|
{
|
||||||
|
eDNT_Root,
|
||||||
|
eDNT_AnimSet,
|
||||||
|
eDNT_ScriptInstance,
|
||||||
|
eDNT_Area,
|
||||||
|
eDNT_ResourceDependency,
|
||||||
|
eDNT_AnimSetDependency
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class providing an interface for reading/writing to cache file and determining type.
|
||||||
|
class IDependencyNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IDependencyNode() {}
|
||||||
|
virtual EDependencyNodeType Type() const = 0;
|
||||||
|
virtual void Read(IInputStream& rFile, EUIDLength IDLength) = 0;
|
||||||
|
virtual void Write(IOutputStream& rFile, EUIDLength IDLength) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node representing a single resource dependency.
|
||||||
|
class CResourceDependency : public IDependencyNode
|
||||||
|
{
|
||||||
|
CUniqueID mID;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CResourceDependency() {}
|
||||||
|
CResourceDependency(const CUniqueID& rkID) : mID(rkID) {}
|
||||||
|
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Read(IInputStream& rFile, EUIDLength IDLength);
|
||||||
|
virtual void Write(IOutputStream& rFile, EUIDLength IDLength) const;
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline CUniqueID ID() const { return mID; }
|
||||||
|
inline void SetID(const CUniqueID& rkID) { mID = rkID; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node representing a single animset dependency contained in a script object. Indicates which character is being used.
|
||||||
|
class CAnimSetDependency : public CResourceDependency
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
u32 mUsedChar;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CAnimSetDependency() : CResourceDependency(), mUsedChar(-1) {}
|
||||||
|
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Read(IInputStream& rFile, EUIDLength IDLength);
|
||||||
|
virtual void Write(IOutputStream& rFile, EUIDLength IDLength) const;
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline u32 UsedChar() const { return mUsedChar; }
|
||||||
|
inline void SetUsedChar(u32 CharIdx) { mUsedChar = CharIdx; }
|
||||||
|
|
||||||
|
// Static
|
||||||
|
static CAnimSetDependency* BuildDependency(TCharacterProperty *pProp);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tree root node, representing a resource.
|
||||||
|
class CDependencyTree : public IDependencyNode
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
CUniqueID mID;
|
||||||
|
std::vector<CResourceDependency*> mReferencedResources;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CDependencyTree(const CUniqueID& rkID) : mID(rkID) {}
|
||||||
|
~CDependencyTree();
|
||||||
|
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Read(IInputStream& rFile, EUIDLength IDLength);
|
||||||
|
virtual void Write(IOutputStream& rFile, EUIDLength IDLength) const;
|
||||||
|
|
||||||
|
u32 NumDependencies() const;
|
||||||
|
bool HasDependency(const CUniqueID& rkID);
|
||||||
|
CUniqueID DependencyByIndex(u32 Index) const;
|
||||||
|
void AddDependency(const CUniqueID& rkID);
|
||||||
|
void AddDependency(CResource *pRes);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline void SetID(const CUniqueID& rkID) { mID = rkID; }
|
||||||
|
inline CUniqueID ID() const { return mID; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node representing an animset resource; allows for lookup of dependencies of a particular character in the set.
|
||||||
|
class CAnimSetDependencyTree : public CDependencyTree
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::vector<u32> mCharacterOffsets;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CAnimSetDependencyTree(const CUniqueID& rkID) : CDependencyTree(rkID) {}
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Read(IInputStream& rFile, EUIDLength IDLength);
|
||||||
|
virtual void Write(IOutputStream& rFile, EUIDLength IDLength) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node representing a script object. Indicates the type of object.
|
||||||
|
class CScriptInstanceDependencyTree : public IDependencyNode
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
u32 mObjectType;
|
||||||
|
std::vector<CResourceDependency*> mDependencies;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~CScriptInstanceDependencyTree();
|
||||||
|
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Read(IInputStream& rFile, EUIDLength IDLength);
|
||||||
|
virtual void Write(IOutputStream& rFile, EUIDLength IDLength) const;
|
||||||
|
bool HasDependency(const CUniqueID& rkID);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
u32 NumDependencies() const { return mDependencies.size(); }
|
||||||
|
|
||||||
|
// Static
|
||||||
|
static CScriptInstanceDependencyTree* BuildTree(CScriptObject *pInstance);
|
||||||
|
static void ParseStructDependencies(CScriptInstanceDependencyTree *pTree, CPropertyStruct *pStruct);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node representing an area. Tracks dependencies on a per-instance basis and can separate dependencies of different script layers.
|
||||||
|
class CAreaDependencyTree : public CDependencyTree
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::vector<CScriptInstanceDependencyTree*> mScriptInstances;
|
||||||
|
std::vector<u32> mLayerOffsets;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CAreaDependencyTree(const CUniqueID& rkID) : CDependencyTree(rkID) {}
|
||||||
|
~CAreaDependencyTree();
|
||||||
|
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Read(IInputStream& rFile, EUIDLength IDLength);
|
||||||
|
virtual void Write(IOutputStream& rFile, EUIDLength IDLength) const;
|
||||||
|
|
||||||
|
void AddScriptLayer(CScriptLayer *pLayer);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CDEPENDENCYTREE
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "CGameExporter.h"
|
#include "CGameExporter.h"
|
||||||
|
#include "Core/GameProject/CResourceIterator.h"
|
||||||
#include "Core/GameProject/CResourceStore.h"
|
#include "Core/GameProject/CResourceStore.h"
|
||||||
#include "Core/Resource/CWorld.h"
|
#include "Core/Resource/CWorld.h"
|
||||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
#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)
|
||||||
|
@ -476,7 +478,6 @@ void CGameExporter::ExportWorlds()
|
||||||
|
|
||||||
void CGameExporter::ExportCookedResources()
|
void CGameExporter::ExportCookedResources()
|
||||||
{
|
{
|
||||||
#if EXPORT_COOKED
|
|
||||||
{
|
{
|
||||||
SCOPED_TIMER(ExportCookedResources);
|
SCOPED_TIMER(ExportCookedResources);
|
||||||
FileUtil::CreateDirectory(mCookedDir);
|
FileUtil::CreateDirectory(mCookedDir);
|
||||||
|
@ -487,7 +488,6 @@ void CGameExporter::ExportCookedResources()
|
||||||
ExportResource(rRes);
|
ExportResource(rRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
SCOPED_TIMER(SaveResourceDatabase);
|
SCOPED_TIMER(SaveResourceDatabase);
|
||||||
#if EXPORT_COOKED
|
#if EXPORT_COOKED
|
||||||
|
@ -495,6 +495,20 @@ void CGameExporter::ExportCookedResources()
|
||||||
#endif
|
#endif
|
||||||
mpProject->Save();
|
mpProject->Save();
|
||||||
}
|
}
|
||||||
|
#if EXPORT_CACHE
|
||||||
|
{
|
||||||
|
SCOPED_TIMER(SaveCacheData);
|
||||||
|
|
||||||
|
for (CResourceIterator It(&mStore); It; ++It)
|
||||||
|
{
|
||||||
|
if (!It->IsTransient())
|
||||||
|
{
|
||||||
|
It->UpdateDependencies();
|
||||||
|
It->SaveCacheData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameExporter::ExportResource(SResourceInstance& rRes)
|
void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||||
|
@ -520,6 +534,7 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||||
// Register resource and write to file
|
// Register resource and write to file
|
||||||
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
|
||||||
// Cooked (todo: save raw)
|
// Cooked (todo: save raw)
|
||||||
TWideString OutPath = pEntry->CookedAssetPath();
|
TWideString OutPath = pEntry->CookedAssetPath();
|
||||||
FileUtil::CreateDirectory(OutPath.GetFileDirectory());
|
FileUtil::CreateDirectory(OutPath.GetFileDirectory());
|
||||||
|
@ -530,5 +545,8 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||||
|
|
||||||
rRes.Exported = true;
|
rRes.Exported = true;
|
||||||
ASSERT(pEntry->HasCookedVersion());
|
ASSERT(pEntry->HasCookedVersion());
|
||||||
|
#else
|
||||||
|
(void) pEntry; // Prevent "unused local variable" compiler warning
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ bool CGameProject::Load(const TWideString& rkPath)
|
||||||
|
|
||||||
// All loaded!
|
// All loaded!
|
||||||
mProjectRoot = rkPath.GetFileDirectory();
|
mProjectRoot = rkPath.GetFileDirectory();
|
||||||
|
mProjectRoot.Replace(L"/", L"\\");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,9 @@ public:
|
||||||
, mProjectName("Unnamed Project")
|
, mProjectName("Unnamed Project")
|
||||||
, mProjectRoot(rkProjRootDir)
|
, mProjectRoot(rkProjRootDir)
|
||||||
, mResourceDBPath(L"ResourceDB.rdb")
|
, mResourceDBPath(L"ResourceDB.rdb")
|
||||||
{}
|
{
|
||||||
|
mProjectRoot.Replace(L"/", L"\\");
|
||||||
|
}
|
||||||
|
|
||||||
~CGameProject();
|
~CGameProject();
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ public:
|
||||||
inline TWideString ProjectRoot() const { return mProjectRoot; }
|
inline TWideString ProjectRoot() const { return mProjectRoot; }
|
||||||
inline TWideString ResourceDBPath(bool Relative) const { return Relative ? mResourceDBPath : mProjectRoot + mResourceDBPath; }
|
inline TWideString ResourceDBPath(bool Relative) const { return Relative ? mResourceDBPath : mProjectRoot + mResourceDBPath; }
|
||||||
inline TWideString DiscDir(bool Relative) const { return Relative ? L"Disc\\" : mProjectRoot + L"Disc\\"; }
|
inline TWideString DiscDir(bool Relative) const { return Relative ? L"Disc\\" : mProjectRoot + L"Disc\\"; }
|
||||||
|
inline TWideString CacheDir(bool Relative) const { return Relative ? L"Cache\\" : mProjectRoot + L"Cache\\"; }
|
||||||
inline TWideString ContentDir(bool Relative) const { return Relative ? L"Content\\" : mProjectRoot + L"Content\\"; }
|
inline TWideString ContentDir(bool Relative) const { return Relative ? L"Content\\" : mProjectRoot + L"Content\\"; }
|
||||||
inline TWideString CookedDir(bool Relative) const { return Relative ? L"Cooked\\" : mProjectRoot + L"Cooked\\"; }
|
inline TWideString CookedDir(bool Relative) const { return Relative ? L"Cooked\\" : mProjectRoot + L"Cooked\\"; }
|
||||||
inline TWideString PackagesDir(bool Relative) const { return Relative ? L"Packages\\" : mProjectRoot + L"Packages\\"; }
|
inline TWideString PackagesDir(bool Relative) const { return Relative ? L"Packages\\" : mProjectRoot + L"Packages\\"; }
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "CGameProject.h"
|
#include "CGameProject.h"
|
||||||
#include "CResourceStore.h"
|
#include "CResourceStore.h"
|
||||||
#include "Core/Resource/CResource.h"
|
#include "Core/Resource/CResource.h"
|
||||||
|
#include <FileIO/FileIO.h>
|
||||||
#include <Common/FileUtil.h>
|
#include <Common/FileUtil.h>
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
#include "Core/Resource/Factory/CAnimSetLoader.h"
|
#include "Core/Resource/Factory/CAnimSetLoader.h"
|
||||||
#include "Core/Resource/Factory/CAreaLoader.h"
|
#include "Core/Resource/Factory/CAreaLoader.h"
|
||||||
#include "Core/Resource/Factory/CCollisionLoader.h"
|
#include "Core/Resource/Factory/CCollisionLoader.h"
|
||||||
|
#include "Core/Resource/Factory/CDependencyGroupLoader.h"
|
||||||
#include "Core/Resource/Factory/CFontLoader.h"
|
#include "Core/Resource/Factory/CFontLoader.h"
|
||||||
#include "Core/Resource/Factory/CMaterialLoader.h"
|
#include "Core/Resource/Factory/CMaterialLoader.h"
|
||||||
#include "Core/Resource/Factory/CModelLoader.h"
|
#include "Core/Resource/Factory/CModelLoader.h"
|
||||||
|
@ -26,19 +28,20 @@
|
||||||
CResourceEntry::CResourceEntry(CResourceStore *pStore, const CUniqueID& rkID,
|
CResourceEntry::CResourceEntry(CResourceStore *pStore, const CUniqueID& rkID,
|
||||||
const TWideString& rkDir, const TWideString& rkFilename,
|
const TWideString& rkDir, const TWideString& rkFilename,
|
||||||
EResType Type, bool Transient /*= false*/)
|
EResType Type, bool Transient /*= false*/)
|
||||||
: mpStore(pStore)
|
: mpResource(nullptr)
|
||||||
, mpResource(nullptr)
|
, mpStore(pStore)
|
||||||
|
, mpDependencies(nullptr)
|
||||||
, mID(rkID)
|
, mID(rkID)
|
||||||
, mName(rkFilename)
|
, mName(rkFilename)
|
||||||
, mType(Type)
|
, mType(Type)
|
||||||
, mNeedsRecook(false)
|
|
||||||
, mTransient(Transient)
|
|
||||||
, mCachedSize(-1)
|
, mCachedSize(-1)
|
||||||
, mCachedUppercaseName(rkFilename.ToUpper())
|
, mCachedUppercaseName(rkFilename.ToUpper())
|
||||||
{
|
{
|
||||||
|
if (Transient) mFlags |= eREF_Transient;
|
||||||
|
|
||||||
mpDirectory = mpStore->GetVirtualDirectory(rkDir, Transient, true);
|
mpDirectory = mpStore->GetVirtualDirectory(rkDir, Transient, true);
|
||||||
if (mpDirectory) mpDirectory->AddChild(L"", this);
|
if (mpDirectory) mpDirectory->AddChild(L"", this);
|
||||||
mGame = ((mTransient || !mpStore->ActiveProject()) ? eUnknownVersion : mpStore->ActiveProject()->Game());
|
mGame = ((Transient || !mpStore->ActiveProject()) ? eUnknownVersion : mpStore->ActiveProject()->Game());
|
||||||
}
|
}
|
||||||
|
|
||||||
CResourceEntry::~CResourceEntry()
|
CResourceEntry::~CResourceEntry()
|
||||||
|
@ -46,6 +49,104 @@ CResourceEntry::~CResourceEntry()
|
||||||
if (mpResource) delete mpResource;
|
if (mpResource) delete mpResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CResourceEntry::LoadCacheData()
|
||||||
|
{
|
||||||
|
ASSERT(!IsTransient());
|
||||||
|
|
||||||
|
TWideString Path = CacheDataPath(false);
|
||||||
|
CFileInStream File(Path.ToUTF8().ToStdString(), IOUtil::eLittleEndian);
|
||||||
|
|
||||||
|
if (!File.IsValid())
|
||||||
|
{
|
||||||
|
Log::Error("Unable to load cache data " + Path.ToUTF8() + "; couldn't open file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header
|
||||||
|
TString Magic = File.ReadString(4);
|
||||||
|
ASSERT(Magic == "CACH");
|
||||||
|
File.Seek(0x4, SEEK_CUR); // Skip Version
|
||||||
|
mFlags = File.ReadLong() & eREF_SavedFlags;
|
||||||
|
|
||||||
|
// Dependency Tree
|
||||||
|
u32 DepsTreeSize = File.ReadLong();
|
||||||
|
|
||||||
|
if (mpDependencies)
|
||||||
|
{
|
||||||
|
delete mpDependencies;
|
||||||
|
mpDependencies = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DepsTreeSize > 0)
|
||||||
|
{
|
||||||
|
mpDependencies = new CDependencyTree(mID);
|
||||||
|
mpDependencies->Read(File, Game() <= eEchoes ? e32Bit : e64Bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CResourceEntry::SaveCacheData()
|
||||||
|
{
|
||||||
|
ASSERT(!IsTransient());
|
||||||
|
|
||||||
|
TWideString Path = CacheDataPath(false);
|
||||||
|
TWideString Dir = Path.GetFileDirectory();
|
||||||
|
FileUtil::CreateDirectory(Dir);
|
||||||
|
CFileOutStream File(Path.ToUTF8().ToStdString(), IOUtil::eLittleEndian);
|
||||||
|
|
||||||
|
if (!File.IsValid())
|
||||||
|
{
|
||||||
|
Log::Error("Unable to save cache data " + TString(Path.GetFileName()) + "; couldn't open file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header
|
||||||
|
File.WriteString("CACH", 4);
|
||||||
|
File.WriteLong(0); // Reserved Space (Version)
|
||||||
|
File.WriteLong(mFlags & eREF_SavedFlags);
|
||||||
|
|
||||||
|
// Dependency Tree
|
||||||
|
if (!mpDependencies) UpdateDependencies();
|
||||||
|
|
||||||
|
u32 DepsSizeOffset = File.Tell();
|
||||||
|
File.WriteLong(0);
|
||||||
|
|
||||||
|
u32 DepsStart = File.Tell();
|
||||||
|
if (mpDependencies) mpDependencies->Write(File, Game() <= eEchoes ? e32Bit : e64Bit);
|
||||||
|
u32 DepsSize = File.Tell() - DepsStart;
|
||||||
|
File.Seek(DepsSizeOffset, SEEK_SET);
|
||||||
|
File.WriteLong(DepsSize);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceEntry::UpdateDependencies()
|
||||||
|
{
|
||||||
|
if (mpDependencies)
|
||||||
|
{
|
||||||
|
delete mpDependencies;
|
||||||
|
mpDependencies = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mpResource)
|
||||||
|
Load();
|
||||||
|
|
||||||
|
if (!mpResource)
|
||||||
|
{
|
||||||
|
Log::Error("Unable to update cached dependencies; failed to load resource");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpDependencies = mpResource->BuildDependencyTree();
|
||||||
|
gpResourceStore->DestroyUnreferencedResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
TWideString CResourceEntry::CacheDataPath(bool Relative) const
|
||||||
|
{
|
||||||
|
return mpStore->ActiveProject()->CacheDir(Relative) + mID.ToString().ToUTF16() + L".rcd";
|
||||||
|
}
|
||||||
|
|
||||||
bool CResourceEntry::HasRawVersion() const
|
bool CResourceEntry::HasRawVersion() const
|
||||||
{
|
{
|
||||||
return FileUtil::Exists(RawAssetPath());
|
return FileUtil::Exists(RawAssetPath());
|
||||||
|
@ -61,7 +162,7 @@ TString CResourceEntry::RawAssetPath(bool Relative) const
|
||||||
TWideString Ext = GetResourceRawExtension(mType, mGame).ToUTF16();
|
TWideString Ext = GetResourceRawExtension(mType, mGame).ToUTF16();
|
||||||
TWideString Path = mpDirectory ? mpDirectory->FullPath() : L"";
|
TWideString Path = mpDirectory ? mpDirectory->FullPath() : L"";
|
||||||
TWideString Name = mName + L"." + Ext;
|
TWideString Name = mName + L"." + Ext;
|
||||||
return ((mTransient || Relative) ? Path + Name : mpStore->ActiveProject()->ContentDir(false) + Path + Name);
|
return ((IsTransient() || Relative) ? Path + Name : mpStore->ActiveProject()->ContentDir(false) + Path + Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CResourceEntry::CookedAssetPath(bool Relative) const
|
TString CResourceEntry::CookedAssetPath(bool Relative) const
|
||||||
|
@ -69,7 +170,7 @@ TString CResourceEntry::CookedAssetPath(bool Relative) const
|
||||||
TWideString Ext = GetResourceCookedExtension(mType, mGame).ToUTF16();
|
TWideString Ext = GetResourceCookedExtension(mType, mGame).ToUTF16();
|
||||||
TWideString Path = mpDirectory ? mpDirectory->FullPath() : L"";
|
TWideString Path = mpDirectory ? mpDirectory->FullPath() : L"";
|
||||||
TWideString Name = mName + L"." + Ext;
|
TWideString Name = mName + L"." + Ext;
|
||||||
return ((mTransient || Relative) ? Path + Name : mpStore->ActiveProject()->CookedDir(false) + Path + Name);
|
return ((IsTransient() || Relative) ? Path + Name : mpStore->ActiveProject()->CookedDir(false) + Path + Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
|
bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
|
||||||
|
@ -101,11 +202,11 @@ u64 CResourceEntry::Size() const
|
||||||
bool CResourceEntry::NeedsRecook() const
|
bool CResourceEntry::NeedsRecook() const
|
||||||
{
|
{
|
||||||
// Assets that do not have a raw version can't be recooked since they will always just be saved cooked to begin with.
|
// Assets that do not have a raw version can't be recooked since they will always just be saved cooked to begin with.
|
||||||
// We will recook any asset where the raw version has been updated but not recooked yet. mNeedsRecook can also be
|
// We will recook any asset where the raw version has been updated but not recooked yet. eREF_NeedsRecook can also be
|
||||||
// toggled to arbitrarily flag any asset for recook.
|
// toggled to arbitrarily flag any asset for recook.
|
||||||
if (!HasRawVersion()) return false;
|
if (!HasRawVersion()) return false;
|
||||||
if (!HasCookedVersion()) return true;
|
if (!HasCookedVersion()) return true;
|
||||||
if (mNeedsRecook) return true;
|
if (mFlags.HasFlag(eREF_NeedsRecook)) return true;
|
||||||
return (FileUtil::LastModifiedTime(CookedAssetPath()) < FileUtil::LastModifiedTime(RawAssetPath()));
|
return (FileUtil::LastModifiedTime(CookedAssetPath()) < FileUtil::LastModifiedTime(RawAssetPath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +253,7 @@ CResource* CResourceEntry::Load(IInputStream& rInput)
|
||||||
case eAnimation: mpResource = CAnimationLoader::LoadANIM(rInput, this); break;
|
case eAnimation: mpResource = CAnimationLoader::LoadANIM(rInput, this); break;
|
||||||
case eAnimSet: mpResource = CAnimSetLoader::LoadANCSOrCHAR(rInput, this); break;
|
case eAnimSet: mpResource = CAnimSetLoader::LoadANCSOrCHAR(rInput, this); break;
|
||||||
case eArea: mpResource = CAreaLoader::LoadMREA(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 eDynamicCollision: mpResource = CCollisionLoader::LoadDCLN(rInput, this); break;
|
||||||
case eFont: mpResource = CFontLoader::LoadFONT(rInput, this); break;
|
case eFont: mpResource = CFontLoader::LoadFONT(rInput, this); break;
|
||||||
case eModel: mpResource = CModelLoader::LoadCMDL(rInput, this); break;
|
case eModel: mpResource = CModelLoader::LoadCMDL(rInput, this); break;
|
||||||
|
@ -185,7 +287,7 @@ void CResourceEntry::Move(const TWideString& rkDir, const TWideString& rkName)
|
||||||
|
|
||||||
// Set new directory and name
|
// Set new directory and name
|
||||||
bool HasDirectory = mpDirectory != nullptr;
|
bool HasDirectory = mpDirectory != nullptr;
|
||||||
CVirtualDirectory *pNewDir = mpStore->GetVirtualDirectory(rkDir, mTransient, true);
|
CVirtualDirectory *pNewDir = mpStore->GetVirtualDirectory(rkDir, IsTransient(), true);
|
||||||
|
|
||||||
if (pNewDir != mpDirectory)
|
if (pNewDir != mpDirectory)
|
||||||
{
|
{
|
||||||
|
@ -216,9 +318,9 @@ void CResourceEntry::Move(const TWideString& rkDir, const TWideString& rkName)
|
||||||
|
|
||||||
void CResourceEntry::AddToProject(const TWideString& rkDir, const TWideString& rkName)
|
void CResourceEntry::AddToProject(const TWideString& rkDir, const TWideString& rkName)
|
||||||
{
|
{
|
||||||
if (mTransient)
|
if (mFlags.HasFlag(eREF_Transient))
|
||||||
{
|
{
|
||||||
mTransient = false;
|
mFlags.ClearFlag(eREF_Transient);
|
||||||
Move(rkDir, rkName);
|
Move(rkDir, rkName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,10 +332,10 @@ void CResourceEntry::AddToProject(const TWideString& rkDir, const TWideString& r
|
||||||
|
|
||||||
void CResourceEntry::RemoveFromProject()
|
void CResourceEntry::RemoveFromProject()
|
||||||
{
|
{
|
||||||
if (!mTransient)
|
if (!mFlags.HasFlag(eREF_Transient))
|
||||||
{
|
{
|
||||||
TString Dir = CookedAssetPath().GetFileDirectory();
|
TString Dir = CookedAssetPath().GetFileDirectory();
|
||||||
mTransient = true;
|
mFlags.SetFlag(eREF_Transient);
|
||||||
Move(Dir, mName);
|
Move(Dir, mName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,31 +4,49 @@
|
||||||
#include "CVirtualDirectory.h"
|
#include "CVirtualDirectory.h"
|
||||||
#include "Core/Resource/EResType.h"
|
#include "Core/Resource/EResType.h"
|
||||||
#include <Common/CUniqueID.h>
|
#include <Common/CUniqueID.h>
|
||||||
|
#include <Common/Flags.h>
|
||||||
#include <Common/types.h>
|
#include <Common/types.h>
|
||||||
|
|
||||||
class CResource;
|
class CResource;
|
||||||
class CResourceStore;
|
class CResourceStore;
|
||||||
|
class CDependencyTree;
|
||||||
|
|
||||||
|
enum EResEntryFlag
|
||||||
|
{
|
||||||
|
eREF_NeedsRecook = 0x1,
|
||||||
|
eREF_Transient = 0x2,
|
||||||
|
eREF_HasThumbnail = 0x4,
|
||||||
|
// Flags that save to the cache file
|
||||||
|
eREF_SavedFlags = eREF_NeedsRecook | eREF_HasThumbnail
|
||||||
|
};
|
||||||
|
DECLARE_FLAGS(EResEntryFlag, FResEntryFlags)
|
||||||
|
|
||||||
class CResourceEntry
|
class CResourceEntry
|
||||||
{
|
{
|
||||||
CResourceStore *mpStore;
|
|
||||||
CResource *mpResource;
|
CResource *mpResource;
|
||||||
|
CResourceStore *mpStore;
|
||||||
|
CDependencyTree *mpDependencies;
|
||||||
CUniqueID mID;
|
CUniqueID mID;
|
||||||
EResType mType;
|
EResType mType;
|
||||||
EGame mGame;
|
EGame mGame;
|
||||||
CVirtualDirectory *mpDirectory;
|
CVirtualDirectory *mpDirectory;
|
||||||
TWideString mName;
|
TWideString mName;
|
||||||
bool mNeedsRecook;
|
FResEntryFlags mFlags;
|
||||||
bool mTransient;
|
|
||||||
|
|
||||||
mutable u64 mCachedSize;
|
mutable u64 mCachedSize;
|
||||||
mutable TWideString mCachedUppercaseName; // This is used to speed up case-insensitive sorting.
|
mutable TWideString mCachedUppercaseName; // This is used to speed up case-insensitive sorting and filtering.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResourceEntry(CResourceStore *pStore, const CUniqueID& rkID,
|
CResourceEntry(CResourceStore *pStore, const CUniqueID& rkID,
|
||||||
const TWideString& rkDir, const TWideString& rkFilename,
|
const TWideString& rkDir, const TWideString& rkFilename,
|
||||||
EResType Type, bool Transient = false);
|
EResType Type, bool Transient = false);
|
||||||
~CResourceEntry();
|
~CResourceEntry();
|
||||||
|
|
||||||
|
bool LoadCacheData();
|
||||||
|
bool SaveCacheData();
|
||||||
|
void UpdateDependencies();
|
||||||
|
TWideString CacheDataPath(bool Relative = false) const;
|
||||||
|
|
||||||
bool HasRawVersion() const;
|
bool HasRawVersion() const;
|
||||||
bool HasCookedVersion() const;
|
bool HasCookedVersion() const;
|
||||||
TString RawAssetPath(bool Relative = false) const;
|
TString RawAssetPath(bool Relative = false) const;
|
||||||
|
@ -45,17 +63,18 @@ public:
|
||||||
void RemoveFromProject();
|
void RemoveFromProject();
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
void SetDirty() { mNeedsRecook = true; }
|
void SetDirty() { mFlags.SetFlag(eREF_NeedsRecook); }
|
||||||
|
|
||||||
inline bool IsLoaded() const { return mpResource != nullptr; }
|
inline bool IsLoaded() const { return mpResource != nullptr; }
|
||||||
inline CResource* Resource() const { return mpResource; }
|
inline CResource* Resource() const { return mpResource; }
|
||||||
inline CUniqueID ID() const { return mID; }
|
inline CDependencyTree* Dependencies() const { return mpDependencies; }
|
||||||
inline EGame Game() const { return mGame; }
|
inline CUniqueID ID() const { return mID; }
|
||||||
inline CVirtualDirectory* Directory() const { return mpDirectory; }
|
inline EGame Game() const { return mGame; }
|
||||||
inline TWideString Name() const { return mName; }
|
inline CVirtualDirectory* Directory() const { return mpDirectory; }
|
||||||
inline TWideString UppercaseName() const { return mCachedUppercaseName; }
|
inline TWideString Name() const { return mName; }
|
||||||
inline EResType ResourceType() const { return mType; }
|
inline const TWideString& UppercaseName() const { return mCachedUppercaseName; }
|
||||||
inline bool IsTransient() const { return mTransient; }
|
inline EResType ResourceType() const { return mType; }
|
||||||
|
inline bool IsTransient() const { return mFlags.HasFlag(eREF_Transient); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CResource* InternalLoad(IInputStream& rInput);
|
CResource* InternalLoad(IInputStream& rInput);
|
||||||
|
|
|
@ -11,7 +11,7 @@ class CResourceIterator
|
||||||
CResourceEntry *mpCurEntry;
|
CResourceEntry *mpCurEntry;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResourceIterator(CResourceStore *pStore)
|
CResourceIterator(CResourceStore *pStore = gpResourceStore)
|
||||||
: mpStore(pStore)
|
: mpStore(pStore)
|
||||||
, mpCurEntry(nullptr)
|
, mpCurEntry(nullptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,6 +69,14 @@ void CResourceStore::LoadResourceDatabase(const TString& rkPath)
|
||||||
pRes = pRes->NextSiblingElement("Resource");
|
pRes = pRes->NextSiblingElement("Resource");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All resources registered - load cache data
|
||||||
|
for (auto It = mResourceEntries.begin(); It != mResourceEntries.end(); It++)
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry = It->second;
|
||||||
|
if (!pEntry->IsTransient())
|
||||||
|
pEntry->LoadCacheData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceStore::SaveResourceDatabase(const TString& rkPath) const
|
void CResourceStore::SaveResourceDatabase(const TString& rkPath) const
|
||||||
|
@ -108,10 +116,6 @@ void CResourceStore::SaveResourceDatabase(const TString& rkPath) const
|
||||||
XMLElement *pName = Doc.NewElement("FileName");
|
XMLElement *pName = Doc.NewElement("FileName");
|
||||||
pName->SetText(*pEntry->Name().ToUTF8());
|
pName->SetText(*pEntry->Name().ToUTF8());
|
||||||
pRes->LinkEndChild(pName);
|
pRes->LinkEndChild(pName);
|
||||||
|
|
||||||
XMLElement *pRecook = Doc.NewElement("NeedsRecook");
|
|
||||||
pRecook->SetText(pEntry->NeedsRecook() ? "true" : "false");
|
|
||||||
pRes->LinkEndChild(pRecook);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Doc.SaveFile(*rkPath);
|
Doc.SaveFile(*rkPath);
|
||||||
|
@ -231,10 +235,7 @@ CResourceEntry* CResourceStore::RegisterTransientResource(EResType Type, const C
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = FindEntry(rkID);
|
CResourceEntry *pEntry = FindEntry(rkID);
|
||||||
|
|
||||||
if (pEntry)
|
if (!pEntry)
|
||||||
Log::Error("Attempted to register transient resource that already exists: " + rkID.ToString() + " / Dir: " + rkDir.ToUTF8() + " / Name: " + rkFileName.ToUTF8());
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
pEntry = new CResourceEntry(this, rkID, rkDir, rkFileName, Type, true);
|
pEntry = new CResourceEntry(this, rkID, rkDir, rkFileName, Type, true);
|
||||||
mResourceEntries[rkID] = pEntry;
|
mResourceEntries[rkID] = pEntry;
|
||||||
|
|
|
@ -65,6 +65,8 @@ public:
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CGameProject* ActiveProject() const { return mpProj; }
|
inline CGameProject* ActiveProject() const { return mpProj; }
|
||||||
inline CVirtualDirectory* RootDirectory() const { return mpProjectRoot; }
|
inline CVirtualDirectory* RootDirectory() const { return mpProjectRoot; }
|
||||||
|
inline u32 NumTotalResources() const { return mResourceEntries.size(); }
|
||||||
|
inline u32 NumLoadedResources() const { return mLoadedResources.size(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CResourceStore *gpResourceStore;
|
extern CResourceStore *gpResourceStore;
|
||||||
|
|
|
@ -10,7 +10,7 @@ CGameArea::CGameArea(CResourceEntry *pEntry /*= 0*/)
|
||||||
, mTerrainMerged(false)
|
, mTerrainMerged(false)
|
||||||
, mOriginalWorldMeshCount(0)
|
, mOriginalWorldMeshCount(0)
|
||||||
, mUsesCompression(false)
|
, mUsesCompression(false)
|
||||||
, mMaterialSet(nullptr)
|
, mpMaterialSet(nullptr)
|
||||||
, mpGeneratorLayer(nullptr)
|
, mpGeneratorLayer(nullptr)
|
||||||
, mpCollision(nullptr)
|
, mpCollision(nullptr)
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,32 @@ CGameArea::~CGameArea()
|
||||||
delete mLightLayers[iLyr][iLight];
|
delete mLightLayers[iLyr][iLight];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDependencyTree* CGameArea::BuildDependencyTree() const
|
||||||
|
{
|
||||||
|
// Base dependencies
|
||||||
|
CAreaDependencyTree *pTree = new CAreaDependencyTree(ResID());
|
||||||
|
|
||||||
|
for (u32 iMat = 0; iMat < mpMaterialSet->NumMaterials(); iMat++)
|
||||||
|
{
|
||||||
|
CMaterial *pMat = mpMaterialSet->MaterialByIndex(iMat);
|
||||||
|
pTree->AddDependency(pMat->IndTexture());
|
||||||
|
|
||||||
|
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
||||||
|
pTree->AddDependency(pMat->Pass(iPass)->Texture());
|
||||||
|
}
|
||||||
|
|
||||||
|
pTree->AddDependency(mpPoiToWorldMap);
|
||||||
|
Log::Warning("CGameArea::FindDependencies not handling PATH/PTLA");
|
||||||
|
|
||||||
|
// Layer dependencies
|
||||||
|
for (u32 iLayer = 0; iLayer < mScriptLayers.size(); iLayer++)
|
||||||
|
pTree->AddScriptLayer(mScriptLayers[iLayer]);
|
||||||
|
|
||||||
|
pTree->AddScriptLayer(mpGeneratorLayer);
|
||||||
|
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
|
||||||
void CGameArea::AddWorldModel(CModel *pModel)
|
void CGameArea::AddWorldModel(CModel *pModel)
|
||||||
{
|
{
|
||||||
mWorldModels.push_back(pModel);
|
mWorldModels.push_back(pModel);
|
||||||
|
@ -52,7 +78,7 @@ void CGameArea::MergeTerrain()
|
||||||
for (u32 iSurf = 0; iSurf < SubmeshCount; iSurf++)
|
for (u32 iSurf = 0; iSurf < SubmeshCount; iSurf++)
|
||||||
{
|
{
|
||||||
SSurface *pSurf = pMdl->GetSurface(iSurf);
|
SSurface *pSurf = pMdl->GetSurface(iSurf);
|
||||||
CMaterial *pMat = mMaterialSet->MaterialByIndex(pSurf->MaterialID);
|
CMaterial *pMat = mpMaterialSet->MaterialByIndex(pSurf->MaterialID);
|
||||||
|
|
||||||
bool NewMat = true;
|
bool NewMat = true;
|
||||||
for (std::vector<CStaticModel*>::iterator it = mStaticWorldModels.begin(); it != mStaticWorldModels.end(); it++)
|
for (std::vector<CStaticModel*>::iterator it = mStaticWorldModels.begin(); it != mStaticWorldModels.end(); it++)
|
||||||
|
@ -93,7 +119,7 @@ void CGameArea::ClearTerrain()
|
||||||
delete mStaticWorldModels[iStatic];
|
delete mStaticWorldModels[iStatic];
|
||||||
mStaticWorldModels.clear();
|
mStaticWorldModels.clear();
|
||||||
|
|
||||||
if (mMaterialSet) delete mMaterialSet;
|
if (mpMaterialSet) delete mpMaterialSet;
|
||||||
|
|
||||||
mVertexCount = 0;
|
mVertexCount = 0;
|
||||||
mTriangleCount = 0;
|
mTriangleCount = 0;
|
||||||
|
|
|
@ -45,7 +45,7 @@ class CGameArea : public CResource
|
||||||
std::vector<SSectionNumber> mSectionNumbers;
|
std::vector<SSectionNumber> mSectionNumbers;
|
||||||
|
|
||||||
// Geometry
|
// Geometry
|
||||||
CMaterialSet *mMaterialSet;
|
CMaterialSet *mpMaterialSet;
|
||||||
std::vector<CModel*> mWorldModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor
|
std::vector<CModel*> mWorldModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor
|
||||||
std::vector<CStaticModel*> mStaticWorldModels; // StaticTerrainModels is the merged terrain for faster rendering in the world editor
|
std::vector<CStaticModel*> mStaticWorldModels; // StaticTerrainModels is the merged terrain for faster rendering in the world editor
|
||||||
// Script
|
// Script
|
||||||
|
@ -62,6 +62,7 @@ class CGameArea : public CResource
|
||||||
public:
|
public:
|
||||||
CGameArea(CResourceEntry *pEntry = 0);
|
CGameArea(CResourceEntry *pEntry = 0);
|
||||||
~CGameArea();
|
~CGameArea();
|
||||||
|
CDependencyTree* BuildDependencyTree() const;
|
||||||
|
|
||||||
void AddWorldModel(CModel *pModel);
|
void AddWorldModel(CModel *pModel);
|
||||||
void MergeTerrain();
|
void MergeTerrain();
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline EGame Version() const { return mGame; }
|
inline EGame Version() const { return mGame; }
|
||||||
|
inline CUniqueID ID() const { return mCharacter.ID(); }
|
||||||
inline CAnimSet* AnimSet() const { return (CAnimSet*) mCharacter.Load(); }
|
inline CAnimSet* AnimSet() const { return (CAnimSet*) mCharacter.Load(); }
|
||||||
inline u32 CharacterIndex() const { return mCharIndex; }
|
inline u32 CharacterIndex() const { return mCharIndex; }
|
||||||
inline u32 AnimIndex() const { return mAnimIndex; }
|
inline u32 AnimIndex() const { return mAnimIndex; }
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef CDEPENDENCYGROUP
|
||||||
|
#define CDEPENDENCYGROUP
|
||||||
|
|
||||||
|
#include "CResource.h"
|
||||||
|
|
||||||
|
class CDependencyGroup : public CResource
|
||||||
|
{
|
||||||
|
DECLARE_RESOURCE_TYPE(eDependencyGroup)
|
||||||
|
std::set<CUniqueID> mDependencies;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CDependencyGroup(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
|
||||||
|
inline void AddDependency(const CUniqueID& rkID) { mDependencies.insert(rkID); }
|
||||||
|
inline void AddDependency(CResource *pRes) { if (pRes) mDependencies.insert(pRes->ResID()); }
|
||||||
|
inline void RemoveDependency(const CUniqueID& rkID) { mDependencies.erase(rkID); }
|
||||||
|
inline void Clear() { mDependencies.clear(); }
|
||||||
|
inline bool HasDependency(const CUniqueID& rkID) const { return mDependencies.find(rkID) != mDependencies.end(); }
|
||||||
|
inline u32 NumDependencies() const { return mDependencies.size(); }
|
||||||
|
inline CUniqueID DependencyByIndex(u32 Index) const { return *std::next(mDependencies.begin(), Index); }
|
||||||
|
|
||||||
|
CDependencyTree* BuildDependencyTree() const
|
||||||
|
{
|
||||||
|
CDependencyTree *pTree = new CDependencyTree(ResID());
|
||||||
|
|
||||||
|
for (auto DepIt = mDependencies.begin(); DepIt != mDependencies.end(); DepIt++)
|
||||||
|
pTree->AddDependency(*DepIt);
|
||||||
|
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CDEPENDENCYGROUP
|
||||||
|
|
|
@ -22,6 +22,13 @@ inline float PtsToFloat(s32 Pt)
|
||||||
return 0.00208333f * Pt;
|
return 0.00208333f * Pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDependencyTree* CFont::BuildDependencyTree() const
|
||||||
|
{
|
||||||
|
CDependencyTree *pOut = new CDependencyTree(ResID());
|
||||||
|
pOut->AddDependency(mpFontTexture);
|
||||||
|
return pOut;
|
||||||
|
}
|
||||||
|
|
||||||
CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/, float /*AspectRatio*/,
|
CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/, float /*AspectRatio*/,
|
||||||
CVector2f /*Position*/, CColor FillColor, CColor StrokeColor, u32 FontSize)
|
CVector2f /*Position*/, CColor FillColor, CColor StrokeColor, u32 FontSize)
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,6 +60,7 @@ class CFont : public CResource
|
||||||
public:
|
public:
|
||||||
CFont(CResourceEntry *pEntry = 0);
|
CFont(CResourceEntry *pEntry = 0);
|
||||||
~CFont();
|
~CFont();
|
||||||
|
CDependencyTree* BuildDependencyTree() const;
|
||||||
CVector2f RenderString(const TString& rkString, CRenderer *pRenderer, float AspectRatio,
|
CVector2f RenderString(const TString& rkString, CRenderer *pRenderer, float AspectRatio,
|
||||||
CVector2f Position = CVector2f(0,0),
|
CVector2f Position = CVector2f(0,0),
|
||||||
CColor FillColor = CColor::skWhite, CColor StrokeColor = CColor::skBlack,
|
CColor FillColor = CColor::skWhite, CColor StrokeColor = CColor::skBlack,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CRESOURCE_H
|
#define CRESOURCE_H
|
||||||
|
|
||||||
#include "EResType.h"
|
#include "EResType.h"
|
||||||
|
#include "Core/GameProject/CDependencyTree.h"
|
||||||
#include "Core/GameProject/CResourceEntry.h"
|
#include "Core/GameProject/CResourceEntry.h"
|
||||||
#include "Core/GameProject/CResourceStore.h"
|
#include "Core/GameProject/CResourceStore.h"
|
||||||
#include <Common/CFourCC.h>
|
#include <Common/CFourCC.h>
|
||||||
|
@ -39,7 +40,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~CResource() {}
|
virtual ~CResource() {}
|
||||||
|
virtual CDependencyTree* BuildDependencyTree() const { return new CDependencyTree(ResID()); }
|
||||||
|
|
||||||
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() : ""; }
|
||||||
inline TString FullSource() const { return mpEntry ? mpEntry->CookedAssetPath(true) : ""; }
|
inline TString FullSource() const { return mpEntry ? mpEntry->CookedAssetPath(true) : ""; }
|
||||||
|
|
|
@ -40,6 +40,17 @@ public:
|
||||||
, mCategory(eNone)
|
, mCategory(eNone)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
CDependencyTree* BuildDependencyTree() const
|
||||||
|
{
|
||||||
|
if (Game() >= eEchoesDemo)
|
||||||
|
Log::Warning("CScan::BuildDependencyTree not handling Echoes/Corruption dependencies");
|
||||||
|
|
||||||
|
CDependencyTree *pTree = new CDependencyTree(ResID());
|
||||||
|
pTree->AddDependency(mpFrame);
|
||||||
|
pTree->AddDependency(mpStringTable);
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
|
||||||
EGame Version() const { return mVersion; }
|
EGame Version() const { return mVersion; }
|
||||||
CStringTable* ScanText() const { return mpStringTable; }
|
CStringTable* ScanText() const { return mpStringTable; }
|
||||||
bool IsImportant() const { return mIsImportant; }
|
bool IsImportant() const { return mIsImportant; }
|
||||||
|
|
|
@ -17,6 +17,28 @@ CWorld::~CWorld()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDependencyTree* CWorld::BuildDependencyTree() const
|
||||||
|
{
|
||||||
|
CDependencyTree *pTree = new CDependencyTree(ResID());
|
||||||
|
|
||||||
|
for (u32 iArea = 0; iArea < mAreas.size(); iArea++)
|
||||||
|
{
|
||||||
|
pTree->AddDependency(mAreas[iArea].FileID);
|
||||||
|
pTree->AddDependency(mAreas[iArea].pAreaName);
|
||||||
|
}
|
||||||
|
|
||||||
|
pTree->AddDependency(mpWorldName);
|
||||||
|
pTree->AddDependency(mpDarkWorldName);
|
||||||
|
pTree->AddDependency(mpSaveWorld);
|
||||||
|
pTree->AddDependency(mpDefaultSkybox);
|
||||||
|
pTree->AddDependency(mpMapWorld);
|
||||||
|
|
||||||
|
if (Game() <= ePrime)
|
||||||
|
Log::Warning("CWorld::BuildDependencyTree not handling audio groups");
|
||||||
|
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
|
||||||
void CWorld::SetAreaLayerInfo(CGameArea *pArea)
|
void CWorld::SetAreaLayerInfo(CGameArea *pArea)
|
||||||
{
|
{
|
||||||
// The AreaIndex parameter is a placeholder until an improved world loader is implemented.
|
// The AreaIndex parameter is a placeholder until an improved world loader is implemented.
|
||||||
|
|
|
@ -84,6 +84,7 @@ public:
|
||||||
CWorld(CResourceEntry *pEntry = 0);
|
CWorld(CResourceEntry *pEntry = 0);
|
||||||
~CWorld();
|
~CWorld();
|
||||||
|
|
||||||
|
CDependencyTree* BuildDependencyTree() const;
|
||||||
void SetAreaLayerInfo(CGameArea *pArea);
|
void SetAreaLayerInfo(CGameArea *pArea);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
|
|
|
@ -73,7 +73,7 @@ void CAreaLoader::ReadGeometryPrime()
|
||||||
mpSectionMgr->ToSection(mGeometryBlockNum);
|
mpSectionMgr->ToSection(mGeometryBlockNum);
|
||||||
|
|
||||||
// Materials
|
// Materials
|
||||||
mpArea->mMaterialSet = CMaterialLoader::LoadMaterialSet(*mpMREA, mVersion);
|
mpArea->mpMaterialSet = CMaterialLoader::LoadMaterialSet(*mpMREA, mVersion);
|
||||||
mpSectionMgr->ToNextSection();
|
mpSectionMgr->ToNextSection();
|
||||||
|
|
||||||
// Geometry
|
// Geometry
|
||||||
|
@ -81,7 +81,7 @@ void CAreaLoader::ReadGeometryPrime()
|
||||||
|
|
||||||
for (u32 iMesh = 0; iMesh < mNumMeshes; iMesh++)
|
for (u32 iMesh = 0; iMesh < mNumMeshes; iMesh++)
|
||||||
{
|
{
|
||||||
CModel *pModel = CModelLoader::LoadWorldModel(*mpMREA, *mpSectionMgr, *mpArea->mMaterialSet, mVersion);
|
CModel *pModel = CModelLoader::LoadWorldModel(*mpMREA, *mpSectionMgr, *mpArea->mpMaterialSet, mVersion);
|
||||||
FileModels.push_back(pModel);
|
FileModels.push_back(pModel);
|
||||||
|
|
||||||
if (mVersion <= ePrime)
|
if (mVersion <= ePrime)
|
||||||
|
@ -394,7 +394,7 @@ void CAreaLoader::ReadGeometryCorruption()
|
||||||
mpSectionMgr->ToSection(mGeometryBlockNum);
|
mpSectionMgr->ToSection(mGeometryBlockNum);
|
||||||
|
|
||||||
// Materials
|
// Materials
|
||||||
mpArea->mMaterialSet = CMaterialLoader::LoadMaterialSet(*mpMREA, mVersion);
|
mpArea->mpMaterialSet = CMaterialLoader::LoadMaterialSet(*mpMREA, mVersion);
|
||||||
mpSectionMgr->ToNextSection();
|
mpSectionMgr->ToNextSection();
|
||||||
|
|
||||||
// Geometry
|
// Geometry
|
||||||
|
@ -404,7 +404,7 @@ void CAreaLoader::ReadGeometryCorruption()
|
||||||
|
|
||||||
for (u32 iMesh = 0; iMesh < mNumMeshes; iMesh++)
|
for (u32 iMesh = 0; iMesh < mNumMeshes; iMesh++)
|
||||||
{
|
{
|
||||||
CModel *pWorldModel = CModelLoader::LoadCorruptionWorldModel(*mpMREA, *mpSectionMgr, *mpArea->mMaterialSet, CurWOBJSection, CurGPUSection, mVersion);
|
CModel *pWorldModel = CModelLoader::LoadCorruptionWorldModel(*mpMREA, *mpSectionMgr, *mpArea->mpMaterialSet, CurWOBJSection, CurGPUSection, mVersion);
|
||||||
FileModels.push_back(pWorldModel);
|
FileModels.push_back(pWorldModel);
|
||||||
|
|
||||||
CurWOBJSection += 4;
|
CurWOBJSection += 4;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "CDependencyGroupLoader.h"
|
||||||
|
#include <Common/AssertMacro.h>
|
||||||
|
|
||||||
|
EGame CDependencyGroupLoader::VersionTest(IInputStream& rDGRP, u32 DepCount)
|
||||||
|
{
|
||||||
|
// Only difference between versions is asset ID length. Just check for EOF with 32-bit ID length.
|
||||||
|
u32 Start = rDGRP.Tell();
|
||||||
|
rDGRP.Seek(DepCount * 4, SEEK_CUR);
|
||||||
|
u32 Remaining = rDGRP.Size() - Start;
|
||||||
|
|
||||||
|
EGame Game = ePrimeDemo;
|
||||||
|
|
||||||
|
if (Remaining < 32)
|
||||||
|
{
|
||||||
|
for (u32 iRem = 0; iRem < Remaining; iRem++)
|
||||||
|
{
|
||||||
|
if (rDGRP.ReadByte() != 0xFF)
|
||||||
|
{
|
||||||
|
Game = eCorruptionProto;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rDGRP.Seek(Start, SEEK_SET);
|
||||||
|
return Game;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDependencyGroup* CDependencyGroupLoader::LoadDGRP(IInputStream& rDGRP, CResourceEntry *pEntry)
|
||||||
|
{
|
||||||
|
if (!rDGRP.IsValid()) return nullptr;
|
||||||
|
|
||||||
|
u32 NumDependencies = rDGRP.ReadLong();
|
||||||
|
EGame Game = VersionTest(rDGRP, NumDependencies);
|
||||||
|
EUIDLength IDLength = (Game < eCorruptionProto ? e32Bit : e64Bit);
|
||||||
|
|
||||||
|
CDependencyGroup *pGroup = new CDependencyGroup(pEntry);
|
||||||
|
pGroup->SetGame(Game);
|
||||||
|
|
||||||
|
for (u32 iDep = 0; iDep < NumDependencies; iDep++)
|
||||||
|
{
|
||||||
|
rDGRP.Seek(0x4, SEEK_CUR); // Skip dependency type
|
||||||
|
CUniqueID AssetID(rDGRP, IDLength);
|
||||||
|
pGroup->AddDependency(AssetID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pGroup;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef CDEPENDENCYGROUPLOADER_H
|
||||||
|
#define CDEPENDENCYGROUPLOADER_H
|
||||||
|
|
||||||
|
#include "Core/Resource/CDependencyGroup.h"
|
||||||
|
#include "Core/Resource/EGame.h"
|
||||||
|
|
||||||
|
class CDependencyGroupLoader
|
||||||
|
{
|
||||||
|
CDependencyGroupLoader() {}
|
||||||
|
static EGame VersionTest(IInputStream& rDGRP, u32 DepCount);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static CDependencyGroup* LoadDGRP(IInputStream& rDGRP, CResourceEntry *pEntry);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CDEPENDENCYGROUPLOADER_H
|
|
@ -65,7 +65,7 @@ void CMaterialLoader::ReadPrimeMatSet()
|
||||||
{
|
{
|
||||||
mpSet->mMaterials[iMat] = ReadPrimeMaterial();
|
mpSet->mMaterials[iMat] = ReadPrimeMaterial();
|
||||||
mpSet->mMaterials[iMat]->mVersion = mVersion;
|
mpSet->mMaterials[iMat]->mVersion = mVersion;
|
||||||
mpSet->mMaterials[iMat]->mName = TString("Material #") + std::to_string(iMat + 1);
|
mpSet->mMaterials[iMat]->mName = TString("Material #") + TString::FromInt32(iMat + 1, 0, 10);
|
||||||
mpFile->Seek(MatsStart + Offsets[iMat], SEEK_SET);
|
mpFile->Seek(MatsStart + Offsets[iMat], SEEK_SET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +261,7 @@ void CMaterialLoader::ReadCorruptionMatSet()
|
||||||
u32 Next = mpFile->Tell() + Size;
|
u32 Next = mpFile->Tell() + Size;
|
||||||
mpSet->mMaterials[iMat] = ReadCorruptionMaterial();
|
mpSet->mMaterials[iMat] = ReadCorruptionMaterial();
|
||||||
mpSet->mMaterials[iMat]->mVersion = mVersion;
|
mpSet->mMaterials[iMat]->mVersion = mVersion;
|
||||||
mpSet->mMaterials[iMat]->mName = TString("Material #") + std::to_string(iMat + 1);
|
mpSet->mMaterials[iMat]->mName = TString("Material #") + TString::FromInt32(iMat + 1, 0, 10);
|
||||||
mpFile->Seek(Next, SEEK_SET);
|
mpFile->Seek(Next, SEEK_SET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,31 @@ CModel::~CModel()
|
||||||
delete mMaterialSets[iMat];
|
delete mMaterialSets[iMat];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CDependencyTree* CModel::BuildDependencyTree() const
|
||||||
|
{
|
||||||
|
CDependencyTree *pTree = new CDependencyTree(ResID());
|
||||||
|
|
||||||
|
for (u32 iSet = 0; iSet < mMaterialSets.size(); iSet++)
|
||||||
|
{
|
||||||
|
CMaterialSet *pSet = mMaterialSets[iSet];
|
||||||
|
|
||||||
|
for (u32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
|
||||||
|
{
|
||||||
|
CMaterial *pMat = pSet->MaterialByIndex(iMat);
|
||||||
|
pTree->AddDependency(pMat->IndTexture());
|
||||||
|
|
||||||
|
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
||||||
|
{
|
||||||
|
CMaterialPass *pPass = pMat->Pass(iPass);
|
||||||
|
pTree->AddDependency(pPass->Texture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
|
||||||
void CModel::BufferGL()
|
void CModel::BufferGL()
|
||||||
{
|
{
|
||||||
if (!mBuffered)
|
if (!mBuffered)
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
CModel(CMaterialSet *pSet, bool OwnsMatSet);
|
CModel(CMaterialSet *pSet, bool OwnsMatSet);
|
||||||
~CModel();
|
~CModel();
|
||||||
|
|
||||||
|
CDependencyTree* BuildDependencyTree() const;
|
||||||
void BufferGL();
|
void BufferGL();
|
||||||
void GenerateMaterialShaders();
|
void GenerateMaterialShaders();
|
||||||
void ClearGLBuffer();
|
void ClearGLBuffer();
|
||||||
|
|
|
@ -63,6 +63,7 @@ bool CScriptObject::IsEditorProperty(IProperty *pProp)
|
||||||
(pProp == mpRotation) ||
|
(pProp == mpRotation) ||
|
||||||
(pProp == mpScale) ||
|
(pProp == mpScale) ||
|
||||||
(pProp == mpActive) ||
|
(pProp == mpActive) ||
|
||||||
|
(pProp == mpLightParameters) ||
|
||||||
(pProp->Parent() == mpLightParameters)
|
(pProp->Parent() == mpLightParameters)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue