Added support for gathering dependencies of ANCS and FRME; changed CDependencyGroup to use a vector instead of a set

This commit is contained in:
parax0 2016-08-03 13:01:48 -06:00
parent 11a7b86120
commit 3bca8410b0
8 changed files with 262 additions and 42 deletions

View File

@ -154,6 +154,31 @@ void CAnimSetDependencyTree::Write(IOutputStream& rFile, EIDLength IDLength) con
rFile.WriteLong( mCharacterOffsets[iChar] );
}
void CAnimSetDependencyTree::AddCharacter(const SSetCharacter *pkChar)
{
mCharacterOffsets.push_back( NumDependencies() );
if (!pkChar) return;
AddDependency(pkChar->pModel);
AddDependency(pkChar->pSkeleton);
AddDependency(pkChar->pSkin);
const std::vector<CAssetID> *pkParticleVectors[5] = {
&pkChar->GenericParticles, &pkChar->ElectricParticles,
&pkChar->SwooshParticles, &pkChar->SpawnParticles,
&pkChar->EffectParticles
};
for (u32 iVec = 0; iVec < 5; iVec++)
{
for (u32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
AddDependency(pkParticleVectors[iVec]->at(iPart));
}
AddDependency(pkChar->IceModel);
AddDependency(pkChar->IceSkin);
}
// ************ CScriptInstanceDependencyTree ************
CScriptInstanceDependencyTree::~CScriptInstanceDependencyTree()
{

View File

@ -10,6 +10,7 @@ class CScriptLayer;
class CScriptObject;
class CPropertyStruct;
class TCharacterProperty;
struct SSetCharacter;
// Group of node classes forming a tree of cached resource dependencies.
enum EDependencyNodeType
@ -109,6 +110,8 @@ public:
virtual EDependencyNodeType Type() const;
virtual void Read(IInputStream& rFile, EIDLength IDLength);
virtual void Write(IOutputStream& rFile, EIDLength IDLength) const;
void AddCharacter(const SSetCharacter *pkChar);
};
// Node representing a script object. Indicates the type of object.

View File

@ -116,9 +116,12 @@ bool CResourceEntry::SaveCacheData()
u32 DepsStart = File.Tell();
if (mpDependencies) mpDependencies->Write(File, Game() <= eEchoes ? e32Bit : e64Bit);
u32 DepsSize = File.Tell() - DepsStart;
u32 DepsEnd = File.Tell();
u32 DepsSize = DepsEnd- DepsStart;
File.Seek(DepsSizeOffset, SEEK_SET);
File.WriteLong(DepsSize);
File.Seek(DepsEnd, SEEK_SET);
// Thumbnail
File.WriteLong(0); // Reserved Space (Thumbnail Size)
@ -262,6 +265,7 @@ CResource* CResourceEntry::Load(IInputStream& rInput)
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;

View File

@ -12,21 +12,28 @@
#include <vector>
// will expand later! this is where animation support will come in
class CAnimSet : public CResource
struct SSetCharacter
{
DECLARE_RESOURCE_TYPE(eAnimSet)
friend class CAnimSetLoader;
struct SNode
{
TString Name;
TResPtr<CModel> pModel;
TResPtr<CSkin> pSkin;
TResPtr<CSkeleton> pSkeleton;
SNode() { pModel = nullptr; }
};
std::vector<SNode> mNodes;
std::vector<CAssetID> GenericParticles;
std::vector<CAssetID> ElectricParticles;
std::vector<CAssetID> SwooshParticles;
std::vector<CAssetID> SpawnParticles;
std::vector<CAssetID> EffectParticles;
CAssetID IceModel;
CAssetID IceSkin;
};
class CAnimSet : public CResource
{
DECLARE_RESOURCE_TYPE(eAnimSet)
friend class CAnimSetLoader;
std::vector<SSetCharacter> mCharacters;
struct SAnimation
{
@ -38,15 +45,28 @@ class CAnimSet : public CResource
public:
CAnimSet(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
u32 NumNodes() const { return mNodes.size(); }
TString NodeName(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].Name; }
CModel* NodeModel(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].pModel; }
CSkin* NodeSkin(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].pSkin; }
CSkeleton* NodeSkeleton(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].pSkeleton; }
u32 NumNodes() const { return mCharacters.size(); }
TString NodeName(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].Name; }
CModel* NodeModel(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].pModel; }
CSkin* NodeSkin(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].pSkin; }
CSkeleton* NodeSkeleton(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].pSkeleton; }
u32 NumAnims() const { return mAnims.size(); }
CAnimation* Animation(u32 Index) { if (Index >= mAnims.size()) Index = 0; return mAnims[Index].pAnim; }
TString AnimName(u32 Index) { if (Index >= mAnims.size()) Index = 0; return mAnims[Index].Name; }
CDependencyTree* BuildDependencyTree() const
{
CAnimSetDependencyTree *pTree = new CAnimSetDependencyTree(ID());
for (u32 iAnim = 0; iAnim < mAnims.size(); iAnim++)
pTree->AddDependency(mAnims[iAnim].pAnim);
for (u32 iNode = 0; iNode < mCharacters.size(); iNode++)
pTree->AddCharacter(&mCharacters[iNode]);
return pTree;
}
};
#endif // CCHARACTERSET_H

View File

@ -6,17 +6,49 @@
class CDependencyGroup : public CResource
{
DECLARE_RESOURCE_TYPE(eDependencyGroup)
std::set<CAssetID> mDependencies;
std::vector<CAssetID> mDependencies;
public:
CDependencyGroup(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
inline void AddDependency(const CAssetID& rkID) { mDependencies.insert(rkID); }
inline void AddDependency(CResource *pRes) { if (pRes) mDependencies.insert(pRes->ID()); }
inline void RemoveDependency(const CAssetID& rkID) { mDependencies.erase(rkID); }
inline void Clear() { mDependencies.clear(); }
inline bool HasDependency(const CAssetID& rkID) const { return mDependencies.find(rkID) != mDependencies.end(); }
inline u32 NumDependencies() const { return mDependencies.size(); }
inline CAssetID DependencyByIndex(u32 Index) const { return *std::next(mDependencies.begin(), Index); }
inline CAssetID DependencyByIndex(u32 Index) const { return mDependencies[Index]; }
inline void AddDependency(const CAssetID& rkID)
{
if (!HasDependency(rkID))
mDependencies.push_back(rkID);
}
inline void AddDependency(CResource *pRes)
{
if ( pRes && !HasDependency(pRes->ID()) )
mDependencies.push_back(pRes->ID());
}
void RemoveDependency(const CAssetID& rkID)
{
for (auto Iter = mDependencies.begin(); Iter != mDependencies.end(); Iter++)
{
if (*Iter == rkID)
{
mDependencies.erase(Iter);
return;
}
}
}
bool HasDependency(const CAssetID &rkID) const
{
for (u32 iDep = 0; iDep < mDependencies.size(); iDep++)
{
if (mDependencies[iDep] == rkID)
return true;
}
return false;
}
CDependencyTree* BuildDependencyTree() const
{

View File

@ -10,11 +10,11 @@ CAnimSet* CAnimSetLoader::LoadCorruptionCHAR(IInputStream& rCHAR)
{
// For now, we only read enough to fetch the model
rCHAR.Seek(0x1, SEEK_CUR);
pSet->mNodes.resize(1);
CAnimSet::SNode& node = pSet->mNodes[0];
pSet->mCharacters.resize(1);
SSetCharacter& rNode = pSet->mCharacters[0];
node.Name = rCHAR.ReadString();
node.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL");
rNode.Name = rCHAR.ReadString();
rNode.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL");
return pSet;
}
@ -22,8 +22,8 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
{
// For now, we only read enough to fetch the model
rCHAR.Seek(0x16, SEEK_CUR);
pSet->mNodes.resize(1);
CAnimSet::SNode& rNode = pSet->mNodes[0];
pSet->mCharacters.resize(1);
SSetCharacter& rNode = pSet->mCharacters[0];
rNode.Name = rCHAR.ReadString();
rCHAR.Seek(0x14, SEEK_CUR);
@ -224,11 +224,11 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
Loader.mVersion = pEntry->Game();
u32 NodeCount = rANCS.ReadLong();
Loader.pSet->mNodes.resize(NodeCount);
Loader.pSet->mCharacters.resize(NodeCount);
for (u32 iNode = 0; iNode < NodeCount; iNode++)
{
CAnimSet::SNode *pNode = &Loader.pSet->mNodes[iNode];
SSetCharacter *pChar = &Loader.pSet->mCharacters[iNode];
rANCS.Seek(0x4, SEEK_CUR); // Skipping node self-index
u16 Unknown1 = rANCS.ReadShort();
@ -237,11 +237,11 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
Loader.mVersion = (Unknown1 == 0xA) ? eEchoes : ePrime; // Best version indicator we know of unfortunately
Loader.pSet->SetGame(Loader.mVersion);
}
pNode->Name = rANCS.ReadString();
pNode->pModel = gpResourceStore->LoadResource(rANCS.ReadLong(), "CMDL");
pNode->pSkin = gpResourceStore->LoadResource(rANCS.ReadLong(), "CSKR");
pNode->pSkeleton = gpResourceStore->LoadResource(rANCS.ReadLong(), "CINF");
if (pNode->pModel) pNode->pModel->SetSkin(pNode->pSkin);
pChar->Name = rANCS.ReadString();
pChar->pModel = gpResourceStore->LoadResource(rANCS.ReadLong(), "CMDL");
pChar->pSkin = gpResourceStore->LoadResource(rANCS.ReadLong(), "CSKR");
pChar->pSkeleton = gpResourceStore->LoadResource(rANCS.ReadLong(), "CINF");
if (pChar->pModel) pChar->pModel->SetSkin(pChar->pSkin);
// Unfortunately that's all that's actually supported at the moment. Hope to expand later.
// Since there's no size value I have to actually read the rest of the node to reach the next one
@ -259,17 +259,32 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
// Particles
u32 ParticleCount = rANCS.ReadLong();
rANCS.Seek(ParticleCount * 4, SEEK_CUR);
pChar->GenericParticles.reserve(ParticleCount);
for (u32 iPart = 0; iPart < ParticleCount; iPart++)
pChar->GenericParticles.push_back( CAssetID(rANCS, e32Bit) );
u32 SwooshCount = rANCS.ReadLong();
rANCS.Seek(SwooshCount * 4, SEEK_CUR);
pChar->SwooshParticles.reserve(SwooshCount);
for (u32 iSwoosh = 0; iSwoosh < SwooshCount; iSwoosh++)
pChar->SwooshParticles.push_back( CAssetID(rANCS, e32Bit) );
if (Unknown1 != 5) rANCS.Seek(0x4, SEEK_CUR);
u32 ElectricCount = rANCS.ReadLong();
rANCS.Seek(ElectricCount * 4, SEEK_CUR);
pChar->ElectricParticles.reserve(ElectricCount);
for (u32 iElec = 0; iElec < ElectricCount; iElec++)
pChar->ElectricParticles.push_back( CAssetID(rANCS, e32Bit) );
if (Loader.mVersion == eEchoes)
{
u32 SPSCCount = rANCS.ReadLong();
rANCS.Seek(SPSCCount * 4, SEEK_CUR);
u32 SpawnCount = rANCS.ReadLong();
pChar->SpawnParticles.reserve(SpawnCount);
for (u32 iSpawn = 0; iSpawn < SpawnCount; iSpawn++)
pChar->SpawnParticles.push_back( CAssetID(rANCS, e32Bit) );
}
rANCS.Seek(0x4, SEEK_CUR);
@ -291,13 +306,17 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
for (u32 iEffect = 0; iEffect < EffectCount; iEffect++)
{
rANCS.ReadString();
rANCS.Seek(0x8, SEEK_CUR);
rANCS.Seek(0x4, SEEK_CUR);
CAssetID ParticleID(rANCS, e32Bit);
if (ParticleID.IsValid()) pChar->EffectParticles.push_back(ParticleID);
if (Loader.mVersion == ePrime) rANCS.ReadString();
if (Loader.mVersion == eEchoes) rANCS.Seek(0x4, SEEK_CUR);
rANCS.Seek(0xC, SEEK_CUR);
}
}
rANCS.Seek(0x8, SEEK_CUR);
pChar->IceModel = CAssetID(rANCS, e32Bit);
pChar->IceSkin = CAssetID(rANCS, e32Bit);
u32 UnknownCount = rANCS.ReadLong();
rANCS.Seek(UnknownCount * 4, SEEK_CUR);

View File

@ -56,6 +56,122 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadEVNT(IInputStream& rEVNT, CResou
return pGroup;
}
CDependencyGroup* CUnsupportedFormatLoader::LoadFRME(IInputStream& rFRME, CResourceEntry *pEntry)
{
if (pEntry->Game() >= eEchoesDemo) return nullptr;
u32 Version = rFRME.ReadLong();
ASSERT(Version == 0 || Version == 1);
CDependencyGroup *pGroup = new CDependencyGroup(pEntry);
rFRME.Seek(0xC, SEEK_CUR);
u32 NumWidgets = rFRME.ReadLong();
for (u32 iWgt = 0; iWgt < NumWidgets; iWgt++)
{
// Widget Header
CFourCC WidgetType = rFRME.ReadLong();
rFRME.ReadString();
rFRME.ReadString();
rFRME.Seek(0x18, SEEK_CUR);
// Head Widget / Base Widget
if (WidgetType == "HWIG" || WidgetType == "BWIG")
{}
// Camera
else if (WidgetType == "CAMR")
{
u32 ProjectionType = rFRME.ReadLong();
if (ProjectionType == 0)
rFRME.Seek(0x10, SEEK_CUR);
else
rFRME.Seek(0x18, SEEK_CUR);
}
// Light
else if (WidgetType == "LITE")
{
u32 LightType = rFRME.ReadLong();
rFRME.Seek(0x1C, SEEK_CUR);
if (LightType == 0) rFRME.Seek(0x4, SEEK_CUR);
}
// Meter
else if (WidgetType == "METR")
rFRME.Seek(0xA, SEEK_CUR);
// Group
else if (WidgetType == "GRUP")
rFRME.Seek(0x3, SEEK_CUR);
// Table Group
else if (WidgetType == "TBGP")
rFRME.Seek(0x23, SEEK_CUR);
// Model
else if (WidgetType == "MODL")
{
pGroup->AddDependency( CAssetID(rFRME, e32Bit) ); // CMDL
rFRME.Seek(0x8, SEEK_CUR);
}
// Text Pane
else if (WidgetType == "TXPN")
{
rFRME.Seek(0x14, SEEK_CUR);
pGroup->AddDependency( CAssetID(rFRME, e32Bit) ); // FONT
rFRME.Seek(0x32, SEEK_CUR);
if (Version == 1)
{
pGroup->AddDependency( CAssetID(rFRME, e32Bit) ); // FONT
rFRME.Seek(0x8, SEEK_CUR);
}
}
// Image Pane
else if (WidgetType == "IMGP")
{
pGroup->AddDependency( CAssetID(rFRME, e32Bit) ); // TXTR
if (rFRME.ReadLong() != 0xFFFFFFFF) DEBUG_BREAK;
rFRME.Seek(0x4, SEEK_CUR);
u32 NumQuadCoords = rFRME.ReadLong();
rFRME.Seek(NumQuadCoords * 0xC, SEEK_CUR);
u32 NumUVCoords = rFRME.ReadLong();
rFRME.Seek(NumUVCoords * 8, SEEK_CUR);
}
// Energy Bar
else if (WidgetType == "ENRG")
{
pGroup->AddDependency( CAssetID(rFRME, e32Bit) ); // TXTR
}
// Slider Group
else if (WidgetType == "SLGP")
{
rFRME.Seek(0x10, SEEK_CUR);
}
else
{
Log::Error("Unrecognized FRME widget type: " + WidgetType.ToString());
DEBUG_BREAK;
}
// Widget Footer
if (rFRME.ReadByte() != 0)
rFRME.Seek(0x2, SEEK_CUR);
rFRME.Seek(0x42, SEEK_CUR);
}
return pGroup;
}
CDependencyGroup* CUnsupportedFormatLoader::LoadHINT(IInputStream& rHINT, CResourceEntry *pEntry)
{
u32 Magic = rHINT.ReadLong();

View File

@ -13,6 +13,7 @@ class CUnsupportedFormatLoader
public:
static CDependencyGroup* LoadCSNG(IInputStream& rCSNG, CResourceEntry *pEntry);
static CDependencyGroup* LoadEVNT(IInputStream& rEVNT, CResourceEntry *pEntry);
static CDependencyGroup* LoadFRME(IInputStream& rFRME, CResourceEntry *pEntry);
static CDependencyGroup* LoadHINT(IInputStream& rHINT, CResourceEntry *pEntry);
static CDependencyGroup* LoadMAPW(IInputStream& rMAPW, CResourceEntry *pEntry);
static CDependencyGroup* LoadMAPU(IInputStream& rMAPU, CResourceEntry *pEntry);