PrimeWorldEditor/Resource/factory/CAnimSetLoader.cpp

200 lines
6.0 KiB
C++

#include "CAnimSetLoader.h"
#include <Core/CResCache.h>
#include <Core/Log.h>
CAnimSetLoader::CAnimSetLoader()
{
}
CAnimSet* CAnimSetLoader::LoadCorruptionCHAR(CInputStream& CHAR)
{
// For now, we only read enough to fetch the model
CHAR.Seek(0x1, SEEK_CUR);
set->nodes.resize(1);
CAnimSet::SNode& node = set->nodes[0];
node.name = CHAR.ReadString();
node.model = (CModel*) gResCache.GetResource(CHAR.ReadLongLong(), "CMDL");
node.ModelToken = CToken(node.model);
return set;
}
CAnimSet* CAnimSetLoader::LoadReturnsCHAR(CInputStream& CHAR)
{
// For now, we only read enough to fetch the model
CHAR.Seek(0x16, SEEK_CUR);
set->nodes.resize(1);
CAnimSet::SNode& node = set->nodes[0];
node.name = CHAR.ReadString();
CHAR.Seek(0x14, SEEK_CUR);
CHAR.ReadString();
node.model = (CModel*) gResCache.GetResource(CHAR.ReadLongLong(), "CMDL");
node.ModelToken = CToken(node.model);
return set;
}
void CAnimSetLoader::LoadPASDatabase(CInputStream& PAS4)
{
// For now, just parse the data; don't store it
PAS4.Seek(0x4, SEEK_CUR); // Skipping PAS4 FourCC
u32 anim_state_count = PAS4.ReadLong();
PAS4.Seek(0x4, SEEK_CUR); // Skipping default anim state
for (u32 s = 0; s < anim_state_count; s++)
{
PAS4.Seek(0x4, SEEK_CUR); // Skipping unknown value
u32 parm_info_count = PAS4.ReadLong();
u32 anim_info_count = PAS4.ReadLong();
u32 skip = 0;
for (u32 p = 0; p < parm_info_count; p++)
{
u32 type = PAS4.ReadLong();
PAS4.Seek(0x8, SEEK_CUR);
switch (type) {
case 0: // Int32
case 1: // Uint32
case 2: // Real32
case 4: // Enum
PAS4.Seek(0x8, SEEK_CUR);
skip += 4;
break;
case 3: // Bool
PAS4.Seek(0x2, SEEK_CUR);
skip++;
break;
}
}
for (u32 a = 0; a < anim_info_count; a++)
PAS4.Seek(0x4 + skip, SEEK_CUR);
}
}
// ************ STATIC ************
CAnimSet* CAnimSetLoader::LoadANCS(CInputStream& ANCS)
{
if (!ANCS.IsValid()) return nullptr;
Log::Write("Loading " + ANCS.GetSourceString());
u32 magic = ANCS.ReadLong();
if (magic != 0x00010001)
{
Log::FileError(ANCS.GetSourceString(), "Invalid ANCS magic: " + StringUtil::ToHexString(magic));
return nullptr;
}
CAnimSetLoader loader;
loader.set = new CAnimSet;
u32 node_count = ANCS.ReadLong();
loader.set->nodes.resize(node_count);
for (u32 n = 0; n < node_count; n++)
{
CAnimSet::SNode *node = &loader.set->nodes[n];
ANCS.Seek(0x4, SEEK_CUR); // Skipping node self-index
u16 unknown1 = ANCS.ReadShort();
if (n == 0) loader.mVersion = (unknown1 == 0xA) ? eEchoes : ePrime; // Best version indicator we know of unfortunately
node->name = ANCS.ReadString();
node->model = (CModel*) gResCache.GetResource(ANCS.ReadLong(), "CMDL");
node->skinID = ANCS.ReadLong();
node->skelID = ANCS.ReadLong();
node->ModelToken = CToken(node->model);
// 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
u32 anim_count = ANCS.ReadLong();
for (u32 a = 0; a < anim_count; a++)
{
ANCS.Seek(0x4, SEEK_CUR);
if (loader.mVersion == ePrime) ANCS.Seek(0x1, SEEK_CUR);
ANCS.ReadString();
}
// PAS Database
loader.LoadPASDatabase(ANCS);
// Particles
u32 particle_count = ANCS.ReadLong();
ANCS.Seek(particle_count * 4, SEEK_CUR);
u32 swoosh_count = ANCS.ReadLong();
ANCS.Seek(swoosh_count * 4, SEEK_CUR);
if (unknown1 != 5) ANCS.Seek(0x4, SEEK_CUR);
u32 electric_count = ANCS.ReadLong();
ANCS.Seek(electric_count * 4, SEEK_CUR);
if (loader.mVersion == eEchoes) {
u32 spsc_count = ANCS.ReadLong();
ANCS.Seek(spsc_count * 4, SEEK_CUR);
}
ANCS.Seek(0x4, SEEK_CUR);
if (loader.mVersion == eEchoes) ANCS.Seek(0x4, SEEK_CUR);
u32 anim_count2 = ANCS.ReadLong();
for (u32 a = 0; a < anim_count2; a++)
{
ANCS.ReadString();
ANCS.Seek(0x18, SEEK_CUR);
}
u32 EffectGroupCount = ANCS.ReadLong();
for (u32 g = 0; g < EffectGroupCount; g++)
{
ANCS.ReadString();
u32 EffectCount = ANCS.ReadLong();
for (u32 e = 0; e < EffectCount; e++)
{
ANCS.ReadString();
ANCS.Seek(0x8, SEEK_CUR);
if (loader.mVersion == ePrime) ANCS.ReadString();
if (loader.mVersion == eEchoes) ANCS.Seek(0x4, SEEK_CUR);
ANCS.Seek(0xC, SEEK_CUR);
}
}
ANCS.Seek(0x8, SEEK_CUR);
u32 unknown_count = ANCS.ReadLong();
ANCS.Seek(unknown_count * 4, SEEK_CUR);
if (loader.mVersion == eEchoes)
{
ANCS.Seek(0x5, SEEK_CUR);
u32 unknown_count2 = ANCS.ReadLong();
ANCS.Seek(unknown_count2 * 0x1C, SEEK_CUR);
}
// Lots of work for data I'm not even using x.x
}
return loader.set;
}
CAnimSet* CAnimSetLoader::LoadCHAR(CInputStream &CHAR)
{
if (!CHAR.IsValid()) return nullptr;
Log::Write("Loading " + CHAR.GetSourceString());
CAnimSetLoader loader;
u8 check = CHAR.ReadByte();
if (check == 0x5)
{
loader.mVersion = eCorruption;
loader.set = new CAnimSet();
return loader.LoadCorruptionCHAR(CHAR);
}
if (check == 0x59)
{
loader.mVersion = eReturns;
loader.set = new CAnimSet();
return loader.LoadReturnsCHAR(CHAR);
}
Log::FileError(CHAR.GetSourceString(), "CHAR has invalid first byte: " + StringUtil::ToHexString(check));
return nullptr;
}