Added support for CHAR, SAND, and SCAN dependencies in MP3

This commit is contained in:
Aruki 2017-04-30 22:28:37 -06:00
parent 11ccd23baf
commit 88c11555c0
29 changed files with 715 additions and 235 deletions

View File

@ -228,8 +228,8 @@ HEADERS += \
Resource/CResTypeInfo.h \ Resource/CResTypeInfo.h \
Resource/Cooker/CResourceCooker.h \ Resource/Cooker/CResourceCooker.h \
Resource/CAudioMacro.h \ Resource/CAudioMacro.h \
Resource/Animation/CCharacter.h \ CompressionUtil.h \
CompressionUtil.h Resource/Animation/CSourceAnimData.h
# Source Files # Source Files
SOURCES += \ SOURCES += \

View File

@ -5,6 +5,7 @@
#include "Core/Resource/CFont.h" #include "Core/Resource/CFont.h"
#include "Core/Resource/CScan.h" #include "Core/Resource/CScan.h"
#include "Core/Resource/CWorld.h" #include "Core/Resource/CWorld.h"
#include "Core/Resource/Animation/CAnimSet.h"
#include "Core/Resource/Script/CScriptLayer.h" #include "Core/Resource/Script/CScriptLayer.h"
#include <Math/MathUtil.h> #include <Math/MathUtil.h>
@ -398,19 +399,44 @@ void GenerateAssetNames(CGameProject *pProj)
if (pkChar->pSkeleton) ApplyGeneratedName(pkChar->pSkeleton->Entry(), SetDir, CharName); if (pkChar->pSkeleton) ApplyGeneratedName(pkChar->pSkeleton->Entry(), SetDir, CharName);
if (pkChar->pSkin) ApplyGeneratedName(pkChar->pSkin->Entry(), SetDir, CharName); if (pkChar->pSkin) ApplyGeneratedName(pkChar->pSkin->Entry(), SetDir, CharName);
if (pkChar->IceModel.IsValid() || pkChar->IceSkin.IsValid()) if (pProj->Game() >= eCorruptionProto && pProj->Game() <= eCorruption && pkChar->ID == 0)
{ {
TWideString IceName = TWideString::Format(L"%s_frozen", *CharName); CResourceEntry *pAnimDataEntry = gpResourceStore->FindEntry( pkChar->AnimDataID );
if (pkChar->IceModel.IsValid()) if (pAnimDataEntry)
{ {
CResourceEntry *pIceModelEntry = pStore->FindEntry(pkChar->IceModel); TWideString AnimDataName = TString::Format(L"%s_animdata", *CharName);
ApplyGeneratedName(pIceModelEntry, SetDir, IceName); ApplyGeneratedName(pAnimDataEntry, SetDir, AnimDataName);
} }
if (pkChar->IceSkin.IsValid()) }
for (u32 iOverlay = 0; iOverlay < pkChar->OverlayModels.size(); iOverlay++)
{
const SOverlayModel& rkOverlay = pkChar->OverlayModels[iOverlay];
if (rkOverlay.ModelID.IsValid() || rkOverlay.SkinID.IsValid())
{ {
CResourceEntry *pIceSkinEntry = pStore->FindEntry(pkChar->IceSkin); TWideString TypeName = (
ApplyGeneratedName(pIceSkinEntry, SetDir, IceName); rkOverlay.Type == eOT_Frozen ? L"frozen" :
rkOverlay.Type == eOT_Acid ? L"acid" :
rkOverlay.Type == eOT_Hypermode ? L"hypermode" :
rkOverlay.Type == eOT_XRay ? L"xray" :
L""
);
ASSERT(TypeName != L"");
TWideString OverlayName = TWideString::Format(L"%s_%s", *CharName, *TypeName);
if (rkOverlay.ModelID.IsValid())
{
CResourceEntry *pModelEntry = pStore->FindEntry(rkOverlay.ModelID);
ApplyGeneratedName(pModelEntry, SetDir, OverlayName);
}
if (rkOverlay.SkinID.IsValid())
{
CResourceEntry *pSkinEntry = pStore->FindEntry(rkOverlay.SkinID);
ApplyGeneratedName(pSkinEntry, SetDir, OverlayName);
}
} }
} }
} }

View File

@ -1,5 +1,6 @@
#include "CDependencyTree.h" #include "CDependencyTree.h"
#include "Core/GameProject/CGameProject.h" #include "Core/GameProject/CGameProject.h"
#include "Core/Resource/Animation/CAnimSet.h"
#include "Core/Resource/Script/CMasterTemplate.h" #include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/CScriptLayer.h" #include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Resource/Script/CScriptObject.h" #include "Core/Resource/Script/CScriptObject.h"
@ -199,34 +200,35 @@ void CSetCharacterDependency::Serialize(IArchive& rArc)
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory); << SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
} }
CSetCharacterDependency* CSetCharacterDependency::BuildTree(const CAnimSet *pkOwnerSet, u32 CharIndex) CSetCharacterDependency* CSetCharacterDependency::BuildTree(const SSetCharacter& rkChar)
{ {
CSetCharacterDependency *pTree = new CSetCharacterDependency(CharIndex); CSetCharacterDependency *pTree = new CSetCharacterDependency(rkChar.ID);
const SSetCharacter *pkChar = pkOwnerSet->Character(CharIndex); pTree->AddDependency(rkChar.pModel);
pTree->AddDependency(rkChar.pSkeleton);
pTree->AddDependency(rkChar.pSkin);
pTree->AddDependency(rkChar.AnimDataID);
if (pkChar) const std::vector<CAssetID> *pkParticleVectors[5] = {
&rkChar.GenericParticles, &rkChar.ElectricParticles,
&rkChar.SwooshParticles, &rkChar.SpawnParticles,
&rkChar.EffectParticles
};
for (u32 iVec = 0; iVec < 5; iVec++)
{ {
pTree->AddDependency(pkChar->pModel); for (u32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
pTree->AddDependency(pkChar->pSkeleton); pTree->AddDependency(pkParticleVectors[iVec]->at(iPart));
pTree->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++)
pTree->AddDependency(pkParticleVectors[iVec]->at(iPart));
}
pTree->AddDependency(pkChar->IceModel);
pTree->AddDependency(pkChar->IceSkin);
pTree->AddDependency(pkChar->SpatialPrimitives);
} }
for (u32 iOverlay = 0; iOverlay < rkChar.OverlayModels.size(); iOverlay++)
{
const SOverlayModel& rkOverlay = rkChar.OverlayModels[iOverlay];
pTree->AddDependency(rkOverlay.ModelID);
pTree->AddDependency(rkOverlay.SkinID);
}
pTree->AddDependency(rkChar.SpatialPrimitives);
return pTree; return pTree;
} }

View File

@ -160,7 +160,7 @@ public:
inline u32 CharSetIndex() const { return mCharSetIndex; } inline u32 CharSetIndex() const { return mCharSetIndex; }
// Static // Static
static CSetCharacterDependency* BuildTree(const CAnimSet *pkOwnerSet, u32 CharIndex); static CSetCharacterDependency* BuildTree(const SSetCharacter& rkChar);
}; };
// Node representing a character animation. Indicates which character indices use this animation. // Node representing a character animation. Indicates which character indices use this animation.

View File

@ -154,12 +154,9 @@ void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode)
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode); CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode);
CResourceEntry *pEntry = mpStore->FindEntry(pDep->ID()); CResourceEntry *pEntry = mpStore->FindEntry(pDep->ID());
if (pEntry) if (pEntry && pEntry->ResourceType() == eScan)
{ {
EResType ResType = pEntry->ResourceType(); ParseDependencyNode(pEntry->Dependencies());
if (ResType == eScan)
ParseDependencyNode(pEntry->Dependencies());
} }
} }

View File

@ -144,8 +144,8 @@ void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo)
void CRenderer::RenderBloom() void CRenderer::RenderBloom()
{ {
// Check to ensure bloom is enabled // Check to ensure bloom is enabled. Also don't render bloom in unlit mode.
if (mBloomMode == eNoBloom) return; if (mBloomMode == eNoBloom || CGraphics::sLightMode != CGraphics::eWorldLighting) return;
// Setup // Setup
static const float skHOffset[6] = { -0.008595f, -0.005470f, -0.002345f, static const float skHOffset[6] = { -0.008595f, -0.005470f, -0.002345f,

View File

@ -5,6 +5,7 @@
#include "CAnimEventData.h" #include "CAnimEventData.h"
#include "CSkeleton.h" #include "CSkeleton.h"
#include "CSkin.h" #include "CSkin.h"
#include "CSourceAnimData.h"
#include "IMetaAnimation.h" #include "IMetaAnimation.h"
#include "IMetaTransition.h" #include "IMetaTransition.h"
#include "Core/Resource/CDependencyGroup.h" #include "Core/Resource/CDependencyGroup.h"
@ -43,20 +44,38 @@ struct SHalfTransition
IMetaTransition *pMetaTrans; IMetaTransition *pMetaTrans;
}; };
// Character structures
enum EOverlayType
{
eOT_Frozen = FOURCC('FRZN'),
eOT_Hypermode = FOURCC('HYPR'),
eOT_Acid = FOURCC('ACID'),
eOT_XRay = FOURCC('XRAY')
};
struct SOverlayModel
{
EOverlayType Type;
CAssetID ModelID;
CAssetID SkinID;
};
struct SSetCharacter struct SSetCharacter
{ {
u32 ID;
TString Name; TString Name;
TResPtr<CModel> pModel; TResPtr<CModel> pModel;
TResPtr<CSkin> pSkin; TResPtr<CSkin> pSkin;
TResPtr<CSkeleton> pSkeleton; TResPtr<CSkeleton> pSkeleton;
std::vector<SOverlayModel> OverlayModels;
CAssetID AnimDataID;
std::vector<CAssetID> GenericParticles; std::vector<CAssetID> GenericParticles;
std::vector<CAssetID> ElectricParticles; std::vector<CAssetID> ElectricParticles;
std::vector<CAssetID> SwooshParticles; std::vector<CAssetID> SwooshParticles;
std::vector<CAssetID> SpawnParticles; std::vector<CAssetID> SpawnParticles;
std::vector<CAssetID> EffectParticles; std::vector<CAssetID> EffectParticles;
CAssetID IceModel; std::vector<CAssetID> SoundEffects;
CAssetID IceSkin;
CAssetID SpatialPrimitives; CAssetID SpatialPrimitives;
std::set<u32> UsedAnimationIndices; std::set<u32> UsedAnimationIndices;
}; };
@ -114,16 +133,49 @@ public:
// Character dependencies // Character dependencies
for (u32 iChar = 0; iChar < mCharacters.size(); iChar++) for (u32 iChar = 0; iChar < mCharacters.size(); iChar++)
{ {
CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree(this, iChar); CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree( mCharacters[iChar] );
ASSERT(pCharTree); ASSERT(pCharTree);
pTree->AddChild(pCharTree); pTree->AddChild(pCharTree);
} }
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++) // Animation dependencies
if (Game() <= eEchoes)
{ {
CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim); for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
ASSERT(pAnimTree); {
pTree->AddChild(pAnimTree); CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
ASSERT(pAnimTree);
pTree->AddChild(pAnimTree);
}
}
else
{
const SSetCharacter& rkChar = mCharacters[0];
std::set<CAnimPrimitive> PrimitiveSet;
// Animations
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
{
const SAnimation& rkAnim = mAnimations[iAnim];
rkAnim.pMetaAnim->GetUniquePrimitives(PrimitiveSet);
}
CSourceAnimData *pAnimData = (CSourceAnimData*) gpResourceStore->LoadResource(rkChar.AnimDataID, "SAND");
if (pAnimData)
pAnimData->AddTransitionDependencies(pTree);
// Event particles/sounds
for (auto Iter = PrimitiveSet.begin(); Iter != PrimitiveSet.end(); Iter++)
{
const CAnimPrimitive& rkPrim = *Iter;
pTree->AddDependency(rkPrim.Animation());
}
for (u32 iSound = 0; iSound < rkChar.SoundEffects.size(); iSound++)
{
pTree->AddDependency(rkChar.SoundEffects[iSound]);
}
} }
return pTree; return pTree;

View File

@ -136,30 +136,32 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
} }
} }
const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(s32 NodeIndex /*= -1*/)
{
CAnimSet *pSet = AnimSet();
if (pSet && pSet->Type() == eAnimSet)
{
if (NodeIndex == -1)
NodeIndex = mCharIndex;
if (mCharIndex != -1 && pSet->NumCharacters() > (u32) NodeIndex)
return pSet->Character(NodeIndex);
}
return nullptr;
}
CModel* CAnimationParameters::GetCurrentModel(s32 NodeIndex /*= -1*/) CModel* CAnimationParameters::GetCurrentModel(s32 NodeIndex /*= -1*/)
{ {
if (!mCharacterID.IsValid()) return nullptr; const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
return pkChar ? pkChar->pModel : nullptr;
CAnimSet *pSet = AnimSet();
if (!pSet) return nullptr;
if (pSet->Type() != eAnimSet) return nullptr;
if (NodeIndex == -1) NodeIndex = mCharIndex;
if (pSet->NumCharacters() <= (u32) NodeIndex) return nullptr;
return pSet->Character(NodeIndex)->pModel;
} }
TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/) TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
{ {
if (!mCharacterID.IsValid()) return ""; const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
return pkChar ? pkChar->Name : "";
CAnimSet *pSet = AnimSet();
if (!pSet) return "";
if (pSet->Type() != eAnimSet) return "";
if (NodeIndex == -1) NodeIndex = mCharIndex;
if (pSet->NumCharacters() <= (u32) NodeIndex) return "";
return pSet->Character(NodeIndex)->Name;
} }
// ************ ACCESSORS ************ // ************ ACCESSORS ************

View File

@ -1,7 +1,6 @@
#ifndef CANIMATIONPARAMETERS_H #ifndef CANIMATIONPARAMETERS_H
#define CANIMATIONPARAMETERS_H #define CANIMATIONPARAMETERS_H
#include "CAnimSet.h"
#include "Core/Resource/TResPtr.h" #include "Core/Resource/TResPtr.h"
#include "Core/Resource/Model/CModel.h" #include "Core/Resource/Model/CModel.h"
#include <Common/EGame.h> #include <Common/EGame.h>
@ -22,6 +21,7 @@ public:
CAnimationParameters(IInputStream& rSCLY, EGame Game); CAnimationParameters(IInputStream& rSCLY, EGame Game);
void Write(IOutputStream& rSCLY); void Write(IOutputStream& rSCLY);
const SSetCharacter* GetCurrentSetCharacter(s32 NodeIndex = -1);
CModel* GetCurrentModel(s32 NodeIndex = -1); CModel* GetCurrentModel(s32 NodeIndex = -1);
TString GetCurrentCharacterName(s32 NodeIndex = -1); TString GetCurrentCharacterName(s32 NodeIndex = -1);

View File

@ -0,0 +1,109 @@
#ifndef CSOURCEANIMDATA_H
#define CSOURCEANIMDATA_H
#include "Core/Resource/CResource.h"
#include "IMetaTransition.h"
class CSourceAnimData : public CResource
{
DECLARE_RESOURCE_TYPE(eSourceAnimData)
friend class CAnimSetLoader;
struct STransition
{
CAssetID AnimA;
CAssetID AnimB;
IMetaTransition *pTransition;
};
struct SHalfTransition
{
CAssetID Anim;
IMetaTransition *pTransition;
};
std::vector<STransition> mTransitions;
std::vector<SHalfTransition> mHalfTransitions;
IMetaTransition *mpDefaultTransition;
public:
CSourceAnimData(CResourceEntry *pEntry = 0)
: CResource(pEntry)
, mpDefaultTransition(nullptr)
{}
~CSourceAnimData()
{
for (u32 TransIdx = 0; TransIdx < mTransitions.size(); TransIdx++)
delete mTransitions[TransIdx].pTransition;
for (u32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++)
delete mHalfTransitions[HalfIdx].pTransition;
delete mpDefaultTransition;
}
CDependencyTree* BuildDependencyTree() const
{
// SAND normally has dependencies from meta-transitions and events
// However, all of these can be character-specific. To simplify things, all SAND
// dependencies are being added to the CHAR dependency tree instead. Therefore the
// SAND dependency tree is left empty.
return new CDependencyTree();
}
void AddTransitionDependencies(CDependencyTree *pTree)
{
// Note: All CHAR animations must have been added to the tree before this function is run
std::set<IMetaTransition*> UsedTransitions;
while (true)
{
// Find all relevant primitives
std::set<CAnimPrimitive> PrimSet;
if (UsedTransitions.find(mpDefaultTransition) == UsedTransitions.end())
{
mpDefaultTransition->GetUniquePrimitives(PrimSet);
UsedTransitions.insert(mpDefaultTransition);
}
for (u32 TransitionIdx = 0; TransitionIdx < mTransitions.size(); TransitionIdx++)
{
const STransition& rkTransition = mTransitions[TransitionIdx];
IMetaTransition *pTransition = rkTransition.pTransition;
if ( pTree->HasDependency(rkTransition.AnimA) &&
pTree->HasDependency(rkTransition.AnimB) &&
UsedTransitions.find(pTransition) == UsedTransitions.end() )
{
pTransition->GetUniquePrimitives(PrimSet);
UsedTransitions.insert(pTransition);
}
}
for (u32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++)
{
const SHalfTransition& rkHalfTrans = mHalfTransitions[HalfIdx];
IMetaTransition *pTransition = rkHalfTrans.pTransition;
if ( pTree->HasDependency(rkHalfTrans.Anim) &&
UsedTransitions.find(pTransition) == UsedTransitions.end() )
{
pTransition->GetUniquePrimitives(PrimSet);
UsedTransitions.insert(pTransition);
}
}
// If we have no new primitives then we've exhausted all usable transitions; break out
if (PrimSet.empty())
break;
// Add all transition primitives to the tree
for (auto Iter = PrimSet.begin(); Iter != PrimSet.end(); Iter++)
pTree->AddDependency(Iter->Animation());
}
}
};
#endif // CSOURCEANIMDATA_H

View File

@ -3,24 +3,24 @@
// ************ CMetaAnimFactory ************ // ************ CMetaAnimFactory ************
CMetaAnimFactory gMetaAnimFactory; CMetaAnimFactory gMetaAnimFactory;
IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput) IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game)
{ {
EMetaAnimationType Type = (EMetaAnimationType) rInput.ReadLong(); EMetaAnimationType Type = (EMetaAnimationType) rInput.ReadLong();
switch (Type) switch (Type)
{ {
case eMAT_Play: case eMAT_Play:
return new CMetaAnimPlay(rInput); return new CMetaAnimPlay(rInput, Game);
case eMAT_Blend: case eMAT_Blend:
case eMAT_PhaseBlend: case eMAT_PhaseBlend:
return new CMetaAnimBlend(Type, rInput); return new CMetaAnimBlend(Type, rInput, Game);
case eMAT_Random: case eMAT_Random:
return new CMetaAnimRandom(rInput); return new CMetaAnimRandom(rInput, Game);
case eMAT_Sequence: case eMAT_Sequence:
return new CMetaAnimSequence(rInput); return new CMetaAnimSequence(rInput, Game);
default: default:
Log::Error("Unrecognized meta-animation type: " + TString::FromInt32(Type, 0, 10)); Log::Error("Unrecognized meta-animation type: " + TString::FromInt32(Type, 0, 10));
@ -29,9 +29,9 @@ IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput)
} }
// ************ CMetaAnimationPlay ************ // ************ CMetaAnimationPlay ************
CMetaAnimPlay::CMetaAnimPlay(IInputStream& rInput) CMetaAnimPlay::CMetaAnimPlay(IInputStream& rInput, EGame Game)
{ {
mPrimitive = CAnimPrimitive(rInput); mPrimitive = CAnimPrimitive(rInput, Game);
mUnknownA = rInput.ReadFloat(); mUnknownA = rInput.ReadFloat();
mUnknownB = rInput.ReadLong(); mUnknownB = rInput.ReadLong();
} }
@ -47,12 +47,12 @@ void CMetaAnimPlay::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) cons
} }
// ************ CMetaAnimBlend ************ // ************ CMetaAnimBlend ************
CMetaAnimBlend::CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput) CMetaAnimBlend::CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput, EGame Game)
{ {
ASSERT(Type == eMAT_Blend || Type == eMAT_PhaseBlend); ASSERT(Type == eMAT_Blend || Type == eMAT_PhaseBlend);
mType = Type; mType = Type;
mpMetaAnimA = gMetaAnimFactory.LoadFromStream(rInput); mpMetaAnimA = gMetaAnimFactory.LoadFromStream(rInput, Game);
mpMetaAnimB = gMetaAnimFactory.LoadFromStream(rInput); mpMetaAnimB = gMetaAnimFactory.LoadFromStream(rInput, Game);
mUnknownA = rInput.ReadFloat(); mUnknownA = rInput.ReadFloat();
mUnknownB = rInput.ReadBool(); mUnknownB = rInput.ReadBool();
} }
@ -75,7 +75,7 @@ void CMetaAnimBlend::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) con
} }
// ************ CMetaAnimRandom ************ // ************ CMetaAnimRandom ************
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput) CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
{ {
u32 NumPairs = rInput.ReadLong(); u32 NumPairs = rInput.ReadLong();
mProbabilityPairs.reserve(NumPairs); mProbabilityPairs.reserve(NumPairs);
@ -83,7 +83,7 @@ CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput)
for (u32 iAnim = 0; iAnim < NumPairs; iAnim++) for (u32 iAnim = 0; iAnim < NumPairs; iAnim++)
{ {
SAnimProbabilityPair Pair; SAnimProbabilityPair Pair;
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput); Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
Pair.Probability = rInput.ReadLong(); Pair.Probability = rInput.ReadLong();
mProbabilityPairs.push_back(Pair); mProbabilityPairs.push_back(Pair);
} }
@ -107,14 +107,14 @@ void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) co
} }
// ************ CMetaAnimSequence ************ // ************ CMetaAnimSequence ************
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput) CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput, EGame Game)
{ {
u32 NumAnims = rInput.ReadLong(); u32 NumAnims = rInput.ReadLong();
mAnimations.reserve(NumAnims); mAnimations.reserve(NumAnims);
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++) for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
{ {
IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput); IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
mAnimations.push_back(pAnim); mAnimations.push_back(pAnim);
} }
} }

View File

@ -18,7 +18,7 @@ enum EMetaAnimationType
class CMetaAnimFactory class CMetaAnimFactory
{ {
public: public:
class IMetaAnimation* LoadFromStream(IInputStream& rInput); class IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game);
}; };
extern CMetaAnimFactory gMetaAnimFactory; extern CMetaAnimFactory gMetaAnimFactory;
@ -32,9 +32,9 @@ class CAnimPrimitive
public: public:
CAnimPrimitive() : mID(0) {} CAnimPrimitive() : mID(0) {}
CAnimPrimitive(IInputStream& rInput) CAnimPrimitive(IInputStream& rInput, EGame Game)
{ {
mpAnim = gpResourceStore->LoadResource(rInput.ReadLong(), "ANIM"); mpAnim = gpResourceStore->LoadResource( CAssetID(rInput, Game), "ANIM" );
mID = rInput.ReadLong(); mID = rInput.ReadLong();
mName = rInput.ReadString(); mName = rInput.ReadString();
} }
@ -58,7 +58,7 @@ public:
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
// Static // Static
static IMetaAnimation* LoadFromStream(IInputStream& rInput); static IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game);
}; };
// CMetaAnimPlay - plays an animation // CMetaAnimPlay - plays an animation
@ -70,7 +70,7 @@ protected:
u32 mUnknownB; u32 mUnknownB;
public: public:
CMetaAnimPlay(IInputStream& rInput); CMetaAnimPlay(IInputStream& rInput, EGame Game);
virtual EMetaAnimationType Type() const; virtual EMetaAnimationType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
@ -91,7 +91,7 @@ protected:
bool mUnknownB; bool mUnknownB;
public: public:
CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput); CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput, EGame Game);
~CMetaAnimBlend(); ~CMetaAnimBlend();
virtual EMetaAnimationType Type() const; virtual EMetaAnimationType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
@ -117,7 +117,7 @@ protected:
std::vector<SAnimProbabilityPair> mProbabilityPairs; std::vector<SAnimProbabilityPair> mProbabilityPairs;
public: public:
CMetaAnimRandom(IInputStream& rInput); CMetaAnimRandom(IInputStream& rInput, EGame Game);
~CMetaAnimRandom(); ~CMetaAnimRandom();
virtual EMetaAnimationType Type() const; virtual EMetaAnimationType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
@ -130,7 +130,7 @@ protected:
std::vector<IMetaAnimation*> mAnimations; std::vector<IMetaAnimation*> mAnimations;
public: public:
CMetaAnimSequence(IInputStream& rInput); CMetaAnimSequence(IInputStream& rInput, EGame Game);
~CMetaAnimSequence(); ~CMetaAnimSequence();
virtual EMetaAnimationType Type() const; virtual EMetaAnimationType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;

View File

@ -4,21 +4,24 @@
// ************ CMetaTransFactory ************ // ************ CMetaTransFactory ************
CMetaTransFactory gMetaTransFactory; CMetaTransFactory gMetaTransFactory;
IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput) IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game)
{ {
EMetaTransitionType Type = (EMetaTransitionType) rInput.ReadLong(); EMetaTransitionType Type = (EMetaTransitionType) rInput.ReadLong();
switch (Type) switch (Type)
{ {
case eMTT_MetaAnim: case eMTT_MetaAnim:
return new CMetaTransMetaAnim(rInput); return new CMetaTransMetaAnim(rInput, Game);
case eMTT_Trans: case eMTT_Trans:
case eMTT_PhaseTrans: case eMTT_PhaseTrans:
return new CMetaTransTrans(Type, rInput); return new CMetaTransTrans(Type, rInput, Game);
case eMTT_Snap: case eMTT_Snap:
return new CMetaTransSnap(rInput); return new CMetaTransSnap(rInput, Game);
case eMTT_Type4:
return new CMetaTransType4(rInput, Game);
default: default:
Log::Error("Unrecognized meta-transition type: " + TString::FromInt32(Type, 0, 10)); Log::Error("Unrecognized meta-transition type: " + TString::FromInt32(Type, 0, 10));
@ -27,9 +30,9 @@ IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput)
} }
// ************ CMetaTransMetaAnim ************ // ************ CMetaTransMetaAnim ************
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput) CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput, EGame Game)
{ {
mpAnim = gMetaAnimFactory.LoadFromStream(rInput); mpAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
} }
CMetaTransMetaAnim::~CMetaTransMetaAnim() CMetaTransMetaAnim::~CMetaTransMetaAnim()
@ -48,15 +51,23 @@ void CMetaTransMetaAnim::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet)
} }
// ************ CMetaTransTrans ************ // ************ CMetaTransTrans ************
CMetaTransTrans::CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput) CMetaTransTrans::CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput, EGame Game)
{ {
ASSERT(Type == eMTT_Trans || Type == eMTT_PhaseTrans); ASSERT(Type == eMTT_Trans || Type == eMTT_PhaseTrans);
mType = Type; mType = Type;
mUnknownA = rInput.ReadFloat();
mUnknownB = rInput.ReadLong(); if (Game <= eEchoes)
mUnknownC = rInput.ReadBool(); {
mUnknownD = rInput.ReadBool(); mUnknownA = rInput.ReadFloat();
mUnknownE = rInput.ReadLong(); mUnknownB = rInput.ReadLong();
mUnknownC = rInput.ReadBool();
mUnknownD = rInput.ReadBool();
mUnknownE = rInput.ReadLong();
}
else
{
rInput.Skip(0x13);
}
} }
EMetaTransitionType CMetaTransTrans::Type() const EMetaTransitionType CMetaTransTrans::Type() const
@ -69,7 +80,7 @@ void CMetaTransTrans::GetUniquePrimitives(std::set<CAnimPrimitive>&) const
} }
// ************ CMetaTransSnap ************ // ************ CMetaTransSnap ************
CMetaTransSnap::CMetaTransSnap(IInputStream&) CMetaTransSnap::CMetaTransSnap(IInputStream&, EGame)
{ {
} }
@ -81,3 +92,18 @@ EMetaTransitionType CMetaTransSnap::Type() const
void CMetaTransSnap::GetUniquePrimitives(std::set<CAnimPrimitive>&) const void CMetaTransSnap::GetUniquePrimitives(std::set<CAnimPrimitive>&) const
{ {
} }
// ************ CMetaTransType4 ************
CMetaTransType4::CMetaTransType4(IInputStream& rInput, EGame)
{
rInput.Skip(0x14);
}
EMetaTransitionType CMetaTransType4::Type() const
{
return eMTT_Type4;
}
void CMetaTransType4::GetUniquePrimitives(std::set<CAnimPrimitive>&) const
{
}

View File

@ -11,14 +11,15 @@ enum EMetaTransitionType
eMTT_MetaAnim = 0, eMTT_MetaAnim = 0,
eMTT_Trans = 1, eMTT_Trans = 1,
eMTT_PhaseTrans = 2, // note: structure shared with eMTT_Trans eMTT_PhaseTrans = 2, // note: structure shared with eMTT_Trans
eMTT_Snap = 3 eMTT_Snap = 3,
eMTT_Type4 = 4 // MP3 only
}; };
// Factory class // Factory class
class CMetaTransFactory class CMetaTransFactory
{ {
public: public:
class IMetaTransition* LoadFromStream(IInputStream& rInput); class IMetaTransition* LoadFromStream(IInputStream& rInput, EGame Game);
}; };
extern CMetaTransFactory gMetaTransFactory; extern CMetaTransFactory gMetaTransFactory;
@ -38,7 +39,7 @@ class CMetaTransMetaAnim : public IMetaTransition
IMetaAnimation *mpAnim; IMetaAnimation *mpAnim;
public: public:
CMetaTransMetaAnim(IInputStream& rInput); CMetaTransMetaAnim(IInputStream& rInput, EGame Game);
~CMetaTransMetaAnim(); ~CMetaTransMetaAnim();
virtual EMetaTransitionType Type() const; virtual EMetaTransitionType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
@ -55,7 +56,7 @@ class CMetaTransTrans : public IMetaTransition
u32 mUnknownE; u32 mUnknownE;
public: public:
CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput); CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput, EGame Game);
virtual EMetaTransitionType Type() const; virtual EMetaTransitionType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
}; };
@ -64,7 +65,16 @@ public:
class CMetaTransSnap : public IMetaTransition class CMetaTransSnap : public IMetaTransition
{ {
public: public:
CMetaTransSnap(IInputStream& rInput); CMetaTransSnap(IInputStream& rInput, EGame Game);
virtual EMetaTransitionType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
};
// CMetaTransType4
class CMetaTransType4 : public IMetaTransition
{
public:
CMetaTransType4(IInputStream& rInput, EGame Game);
virtual EMetaTransitionType Type() const; virtual EMetaTransitionType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
}; };

View File

@ -351,6 +351,7 @@ void CResTypeInfo::CResTypeInfoFactory::InitTypes()
CResTypeInfo *pType = new CResTypeInfo(eSourceAnimData, "Source Animation Data"); CResTypeInfo *pType = new CResTypeInfo(eSourceAnimData, "Source Animation Data");
AddExtension(pType, "SAND", eCorruptionProto, eCorruption); AddExtension(pType, "SAND", eCorruptionProto, eCorruption);
pType->mHidden = true; pType->mHidden = true;
pType->mCanHaveDependencies = false; // all dependencies are added to the CHAR dependency tree
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eSpatialPrimitive, "Spatial Primitive"); CResTypeInfo *pType = new CResTypeInfo(eSpatialPrimitive, "Spatial Primitive");

View File

@ -52,6 +52,9 @@ private:
CAnimationParameters mUnknownAnimParams; CAnimationParameters mUnknownAnimParams;
std::vector<SScanInfoSecondaryModel> mSecondaryModels; std::vector<SScanInfoSecondaryModel> mSecondaryModels;
// MP3
std::vector<CAssetID> mDependencyList;
public: public:
CScan(CResourceEntry *pEntry = 0) CScan(CResourceEntry *pEntry = 0)
: CResource(pEntry) : CResource(pEntry)
@ -63,12 +66,20 @@ public:
CDependencyTree* BuildDependencyTree() const CDependencyTree* BuildDependencyTree() const
{ {
// note: not handling Corruption yet
if (Game() >= eCorruptionProto)
Log::Warning("CScan::BuildDependencyTree not handling Corruption dependencies");
CDependencyTree *pTree = new CDependencyTree(); CDependencyTree *pTree = new CDependencyTree();
// Corruption's SCAN has a list of all assets - just grab that
if (Game() >= eCorruptionProto)
{
for (u32 iDep = 0; iDep < mDependencyList.size(); iDep++)
{
pTree->AddDependency(mDependencyList[iDep]);
}
return pTree;
}
// Otherwise add all the dependencies we need from the properties
if (Game() <= ePrime) if (Game() <= ePrime)
pTree->AddDependency(mFrameID); pTree->AddDependency(mFrameID);

View File

@ -2,7 +2,7 @@
#include "Core/CAudioManager.h" #include "Core/CAudioManager.h"
#include "Core/GameProject/CGameProject.h" #include "Core/GameProject/CGameProject.h"
void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes) void CAnimEventLoader::LoadEvents(IInputStream& rEVNT)
{ {
u32 Version = rEVNT.ReadLong(); u32 Version = rEVNT.ReadLong();
ASSERT(Version == 1 || Version == 2); ASSERT(Version == 1 || Version == 2);
@ -12,9 +12,7 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iLoop = 0; iLoop < NumLoopEvents; iLoop++) for (u32 iLoop = 0; iLoop < NumLoopEvents; iLoop++)
{ {
rEVNT.Seek(0x2, SEEK_CUR); LoadLoopEvent(rEVNT);
rEVNT.ReadString();
rEVNT.Seek(0x1C, SEEK_CUR);
} }
// User Events // User Events
@ -22,10 +20,7 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iUser = 0; iUser < NumUserEvents; iUser++) for (u32 iUser = 0; iUser < NumUserEvents; iUser++)
{ {
rEVNT.Seek(0x2, SEEK_CUR); LoadUserEvent(rEVNT);
rEVNT.ReadString();
rEVNT.Seek(0x1F, SEEK_CUR);
rEVNT.ReadString();
} }
// Effect Events // Effect Events
@ -33,20 +28,7 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iFX = 0; iFX < NumEffectEvents; iFX++) for (u32 iFX = 0; iFX < NumEffectEvents; iFX++)
{ {
rEVNT.Seek(0x2, SEEK_CUR); LoadEffectEvent(rEVNT);
rEVNT.ReadString();
rEVNT.Seek(0x13, SEEK_CUR);
u32 CharIndex = rEVNT.ReadLong();
rEVNT.Seek(0xC, SEEK_CUR);
CAssetID ParticleID = rEVNT.ReadLong();
mpEventData->AddEvent(CharIndex, ParticleID);
if (IsEchoes)
rEVNT.Seek(0x4, SEEK_CUR);
else
rEVNT.ReadString();
rEVNT.Seek(0x8, SEEK_CUR);
} }
// Sound Events // Sound Events
@ -56,21 +38,92 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iSound = 0; iSound < NumSoundEvents; iSound++) for (u32 iSound = 0; iSound < NumSoundEvents; iSound++)
{ {
rEVNT.Seek(0x2, SEEK_CUR); LoadSoundEvent(rEVNT);
rEVNT.ReadString(); }
rEVNT.Seek(0x13, SEEK_CUR); }
u32 CharIndex = rEVNT.ReadLong(); }
rEVNT.Seek(0x4, SEEK_CUR);
u32 SoundID = rEVNT.ReadLong() & 0xFFFF;
rEVNT.Seek(0x8, SEEK_CUR);
if (IsEchoes) rEVNT.Seek(0xC, SEEK_CUR);
if (SoundID != 0xFFFF) s32 CAnimEventLoader::LoadEventBase(IInputStream& rEVNT)
{
rEVNT.Skip(0x2);
rEVNT.ReadString();
rEVNT.Skip(mGame < eCorruptionProto ? 0x13 : 0x17);
s32 CharacterIndex = rEVNT.ReadLong();
rEVNT.Skip(mGame < eCorruptionProto ? 0x4 : 0x18);
return CharacterIndex;
}
void CAnimEventLoader::LoadLoopEvent(IInputStream& rEVNT)
{
LoadEventBase(rEVNT);
rEVNT.Skip(0x1);
}
void CAnimEventLoader::LoadUserEvent(IInputStream& rEVNT)
{
LoadEventBase(rEVNT);
rEVNT.Skip(0x4);
rEVNT.ReadString();
}
void CAnimEventLoader::LoadEffectEvent(IInputStream& rEVNT)
{
s32 CharIndex = LoadEventBase(rEVNT);
rEVNT.Skip(mGame < eCorruptionProto ? 0x8 : 0x4);
CAssetID ParticleID(rEVNT, mGame);
mpEventData->AddEvent(CharIndex, ParticleID);
if (mGame <= ePrime)
rEVNT.ReadString();
else if (mGame <= eEchoes)
rEVNT.Skip(0x4);
rEVNT.Skip(0x8);
}
void CAnimEventLoader::LoadSoundEvent(IInputStream& rEVNT)
{
s32 CharIndex = LoadEventBase(rEVNT);
// Metroid Prime 1/2
if (mGame <= eEchoes)
{
u32 SoundID = rEVNT.ReadLong() & 0xFFFF;
rEVNT.Skip(0x8);
if (mGame >= eEchoes) rEVNT.Skip(0xC);
if (SoundID != 0xFFFF)
{
SSoundInfo SoundInfo = gpResourceStore->Project()->AudioManager()->GetSoundInfo(SoundID);
if (SoundInfo.pAudioGroup)
mpEventData->AddEvent(CharIndex, SoundInfo.pAudioGroup->ID());
}
}
// Metroid Prime 3
else
{
CAssetID SoundID(rEVNT, mGame);
mpEventData->AddEvent(CharIndex, SoundID);
rEVNT.Skip(0x8);
for (u32 StructIdx = 0; StructIdx < 2; StructIdx++)
{
u32 StructType = rEVNT.ReadLong();
ASSERT(StructType <= 2);
if (StructType == 1)
{ {
SSoundInfo SoundInfo = gpResourceStore->Project()->AudioManager()->GetSoundInfo(SoundID); rEVNT.Skip(4);
}
if (SoundInfo.pAudioGroup) else if (StructType == 2)
mpEventData->AddEvent(CharIndex, SoundInfo.pAudioGroup->ID()); {
// This is a maya spline
rEVNT.Skip(2);
u32 KnotCount = rEVNT.ReadLong();
rEVNT.Skip(0xA * KnotCount);
rEVNT.Skip(9);
} }
} }
} }
@ -81,7 +134,8 @@ CAnimEventData* CAnimEventLoader::LoadEVNT(IInputStream& rEVNT, CResourceEntry *
{ {
CAnimEventLoader Loader; CAnimEventLoader Loader;
Loader.mpEventData = new CAnimEventData(pEntry); Loader.mpEventData = new CAnimEventData(pEntry);
Loader.LoadEvents(rEVNT, false); Loader.mGame = ePrime;
Loader.LoadEvents(rEVNT);
return Loader.mpEventData; return Loader.mpEventData;
} }
@ -89,6 +143,38 @@ CAnimEventData* CAnimEventLoader::LoadAnimSetEvents(IInputStream& rANCS)
{ {
CAnimEventLoader Loader; CAnimEventLoader Loader;
Loader.mpEventData = new CAnimEventData(); Loader.mpEventData = new CAnimEventData();
Loader.LoadEvents(rANCS, true); Loader.mGame = eEchoes;
Loader.LoadEvents(rANCS);
return Loader.mpEventData;
}
CAnimEventData* CAnimEventLoader::LoadCorruptionCharacterEventSet(IInputStream& rCHAR)
{
CAnimEventLoader Loader;
Loader.mpEventData = new CAnimEventData();
Loader.mGame = eCorruption;
// Read event set header
rCHAR.Skip(0x4); // Skip animation ID
rCHAR.ReadString(); // Skip set name
// Read effect events
u32 NumEffectEvents = rCHAR.ReadLong();
for (u32 EventIdx = 0; EventIdx < NumEffectEvents; EventIdx++)
{
rCHAR.ReadString();
Loader.LoadEffectEvent(rCHAR);
}
// Read sound events
u32 NumSoundEvents = rCHAR.ReadLong();
for (u32 EventIdx = 0; EventIdx < NumSoundEvents; EventIdx++)
{
rCHAR.ReadString();
Loader.LoadSoundEvent(rCHAR);
}
return Loader.mpEventData; return Loader.mpEventData;
} }

View File

@ -7,13 +7,20 @@
class CAnimEventLoader class CAnimEventLoader
{ {
TResPtr<CAnimEventData> mpEventData; TResPtr<CAnimEventData> mpEventData;
EGame mGame;
CAnimEventLoader() {} CAnimEventLoader() {}
void LoadEvents(IInputStream& rEVNT, bool IsEchoes); void LoadEvents(IInputStream& rEVNT);
s32 LoadEventBase(IInputStream& rEVNT);
void LoadLoopEvent(IInputStream& rEVNT);
void LoadUserEvent(IInputStream& rEVNT);
void LoadEffectEvent(IInputStream& rEVNT);
void LoadSoundEvent(IInputStream& rEVNT);
public: public:
static CAnimEventData* LoadEVNT(IInputStream& rEVNT, CResourceEntry *pEntry); static CAnimEventData* LoadEVNT(IInputStream& rEVNT, CResourceEntry *pEntry);
static CAnimEventData* LoadAnimSetEvents(IInputStream& rANCS); static CAnimEventData* LoadAnimSetEvents(IInputStream& rANCS);
static CAnimEventData* LoadCorruptionCharacterEventSet(IInputStream& rCHAR);
}; };
#endif // CANIMEVENTLOADER_H #endif // CANIMEVENTLOADER_H

View File

@ -9,13 +9,89 @@ CAnimSetLoader::CAnimSetLoader()
CAnimSet* CAnimSetLoader::LoadCorruptionCHAR(IInputStream& rCHAR) CAnimSet* CAnimSetLoader::LoadCorruptionCHAR(IInputStream& rCHAR)
{ {
// For now, we only read enough to fetch the model pSet->mCharacters.emplace_back( SSetCharacter() );;
rCHAR.Seek(0x1, SEEK_CUR); SSetCharacter& rChar = pSet->mCharacters.back();
pSet->mCharacters.resize(1);
SSetCharacter& rNode = pSet->mCharacters[0]; // Character Header
rChar.ID = rCHAR.ReadByte();
rChar.Name = rCHAR.ReadString();
rChar.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL");
rChar.pSkin = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CSKR");
u32 NumOverlays = rCHAR.ReadLong();
for (u32 iOverlay = 0; iOverlay < NumOverlays; iOverlay++)
{
SOverlayModel Overlay;
Overlay.Type = (EOverlayType) rCHAR.ReadLong();
Overlay.ModelID = CAssetID(rCHAR, e64Bit);
Overlay.SkinID = CAssetID(rCHAR, e64Bit);
rChar.OverlayModels.push_back(Overlay);
}
rChar.pSkeleton = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CINF");
rChar.AnimDataID = CAssetID(rCHAR, e64Bit);
// PAS Database
LoadPASDatabase(rCHAR);
// Particle Resource Data
LoadParticleResourceData(rCHAR, &rChar, 10);
// Events
u32 NumEventSets = rCHAR.ReadLong();
for (u32 iSet = 0; iSet < NumEventSets; iSet++)
{
CAnimEventData *pEvents = CAnimEventLoader::LoadCorruptionCharacterEventSet(rCHAR);
pSet->mAnimEvents.push_back(pEvents);
}
// Animations
u32 NumAnimations = rCHAR.ReadLong();
for (u32 AnimIdx = 0; AnimIdx < NumAnimations; AnimIdx++)
{
SAnimation Anim;
Anim.Name = rCHAR.ReadString();
Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rCHAR, mGame);
pSet->mAnimations.push_back(Anim);
}
// Animation Bounds
u32 NumAnimationBounds = rCHAR.ReadLong();
rCHAR.Skip(NumAnimationBounds * 0x20);
rCHAR.Skip(1);
// Bool Array
u32 BoolArraySize = rCHAR.ReadLong();
rCHAR.Skip(BoolArraySize);
// Collision Primitives
u32 NumPrimitiveSets = rCHAR.ReadLong();
for (u32 SetIdx = 0; SetIdx < NumPrimitiveSets; SetIdx++)
{
rCHAR.ReadString();
u32 NumPrimitives = rCHAR.ReadLong();
for (u32 PrimIdx = 0; PrimIdx < NumPrimitives; PrimIdx++)
{
rCHAR.Skip(0x34);
rCHAR.ReadString();
rCHAR.Skip(4);
}
}
// Sound Resources
u32 NumSounds = rCHAR.ReadLong();
for (u32 SoundIdx = 0; SoundIdx < NumSounds; SoundIdx++)
{
CAssetID SoundID(rCHAR, e64Bit);
rChar.SoundEffects.push_back(SoundID);
}
rNode.Name = rCHAR.ReadString();
rNode.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL");
return pSet; return pSet;
} }
@ -23,22 +99,25 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
{ {
// For now, we only read enough to fetch the model // For now, we only read enough to fetch the model
rCHAR.Seek(0x16, SEEK_CUR); rCHAR.Seek(0x16, SEEK_CUR);
pSet->mCharacters.resize(1);
SSetCharacter& rNode = pSet->mCharacters[0];
rNode.Name = rCHAR.ReadString(); pSet->mCharacters.emplace_back( SSetCharacter() );;
SSetCharacter& rChar = pSet->mCharacters.back();
rChar.ID = 0;
rChar.Name = rCHAR.ReadString();
rCHAR.Seek(0x14, SEEK_CUR); rCHAR.Seek(0x14, SEEK_CUR);
rCHAR.ReadString(); rCHAR.ReadString();
rNode.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL"); rChar.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL");
return pSet; return pSet;
} }
void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4) void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4)
{ {
// For now, just parse the data; don't store it // For now, just parse the data; don't store it
rPAS4.Seek(0x4, SEEK_CUR); // Skipping PAS4 FourCC u32 Magic = rPAS4.ReadLong();
u32 AnimStateCount = rPAS4.ReadLong(); u32 AnimStateCount = rPAS4.ReadLong();
rPAS4.Seek(0x4, SEEK_CUR); // Skipping default anim state rPAS4.Seek(0x4, SEEK_CUR); // Skipping default anim state
ASSERT(Magic == FOURCC('PAS4'));
for (u32 iState = 0; iState < AnimStateCount; iState++) for (u32 iState = 0; iState < AnimStateCount; iState++)
{ {
@ -72,6 +151,41 @@ void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4)
} }
} }
void CAnimSetLoader::LoadParticleResourceData(IInputStream& rFile, SSetCharacter *pChar, u16 CharVersion)
{
u32 ParticleCount = rFile.ReadLong();
pChar->GenericParticles.reserve(ParticleCount);
for (u32 iPart = 0; iPart < ParticleCount; iPart++)
pChar->GenericParticles.push_back( CAssetID(rFile, mGame) );
u32 SwooshCount = rFile.ReadLong();
pChar->SwooshParticles.reserve(SwooshCount);
for (u32 iSwoosh = 0; iSwoosh < SwooshCount; iSwoosh++)
pChar->SwooshParticles.push_back( CAssetID(rFile, mGame) );
if (CharVersion >= 6 && mGame <= eEchoes) rFile.Seek(0x4, SEEK_CUR);
u32 ElectricCount = rFile.ReadLong();
pChar->ElectricParticles.reserve(ElectricCount);
for (u32 iElec = 0; iElec < ElectricCount; iElec++)
pChar->ElectricParticles.push_back( CAssetID(rFile, mGame) );
if (mGame >= eEchoes)
{
u32 SpawnCount = rFile.ReadLong();
pChar->SpawnParticles.reserve(SpawnCount);
for (u32 iSpawn = 0; iSpawn < SpawnCount; iSpawn++)
pChar->SpawnParticles.push_back( CAssetID(rFile, mGame) );
}
rFile.Seek(0x4, SEEK_CUR);
if (mGame >= eEchoes) rFile.Seek(0x4, SEEK_CUR);
}
void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS) void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
{ {
u16 Version = rANCS.ReadShort(); u16 Version = rANCS.ReadShort();
@ -84,7 +198,7 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
{ {
SAnimation Anim; SAnimation Anim;
Anim.Name = rANCS.ReadString(); Anim.Name = rANCS.ReadString();
Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rANCS); Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rANCS, mGame);
pSet->mAnimations.push_back(Anim); pSet->mAnimations.push_back(Anim);
} }
@ -98,11 +212,11 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
Trans.Unknown = rANCS.ReadLong(); Trans.Unknown = rANCS.ReadLong();
Trans.AnimIdA = rANCS.ReadLong(); Trans.AnimIdA = rANCS.ReadLong();
Trans.AnimIdB = rANCS.ReadLong(); Trans.AnimIdB = rANCS.ReadLong();
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS); Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS, mGame);
pSet->mTransitions.push_back(Trans); pSet->mTransitions.push_back(Trans);
} }
pSet->mpDefaultTransition = gMetaTransFactory.LoadFromStream(rANCS); pSet->mpDefaultTransition = gMetaTransFactory.LoadFromStream(rANCS, mGame);
// Additive Animations // Additive Animations
u32 NumAdditive = rANCS.ReadLong(); u32 NumAdditive = rANCS.ReadLong();
@ -130,14 +244,14 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
{ {
SHalfTransition Trans; SHalfTransition Trans;
Trans.AnimID = rANCS.ReadLong(); Trans.AnimID = rANCS.ReadLong();
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS); Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS, mGame);
pSet->mHalfTransitions.push_back(Trans); pSet->mHalfTransitions.push_back(Trans);
} }
} }
// Skipping MP1 ANIM asset list // Skipping MP1 ANIM asset list
// Events // Events
if (mVersion >= eEchoesDemo) if (mGame >= eEchoesDemo)
{ {
u32 EventDataCount = rANCS.ReadLong(); u32 EventDataCount = rANCS.ReadLong();
pSet->mAnimEvents.reserve(EventDataCount); pSet->mAnimEvents.reserve(EventDataCount);
@ -260,20 +374,6 @@ void CAnimSetLoader::ProcessPrimitives()
} }
// ************ STATIC ************ // ************ STATIC ************
CAnimSet* CAnimSetLoader::LoadANCSOrCHAR(IInputStream& rFile, CResourceEntry *pEntry)
{
if (!rFile.IsValid()) return nullptr;
u8 Test = rFile.PeekByte();
if (Test == 0x3 || Test == 0x5 || Test == 0x59)
return LoadCHAR(rFile, pEntry);
else if (Test == 0x0)
return LoadANCS(rFile, pEntry);
Log::Error("Failed to determine animset format for " + rFile.GetSourceString() + "; first byte is " + TString::HexString(Test, 2));
return nullptr;
}
CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry) CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
{ {
if (!rANCS.IsValid()) return nullptr; if (!rANCS.IsValid()) return nullptr;
@ -287,7 +387,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
CAnimSetLoader Loader; CAnimSetLoader Loader;
Loader.pSet = new CAnimSet(pEntry); Loader.pSet = new CAnimSet(pEntry);
Loader.mVersion = pEntry->Game(); Loader.mGame = pEntry->Game();
u32 NodeCount = rANCS.ReadLong(); u32 NodeCount = rANCS.ReadLong();
Loader.pSet->mCharacters.resize(NodeCount); Loader.pSet->mCharacters.resize(NodeCount);
@ -296,11 +396,11 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
{ {
SSetCharacter *pChar = &Loader.pSet->mCharacters[iNode]; SSetCharacter *pChar = &Loader.pSet->mCharacters[iNode];
rANCS.Seek(0x4, SEEK_CUR); // Skipping node self-index pChar->ID = rANCS.ReadLong();
u16 Unknown1 = rANCS.ReadShort(); u16 CharVersion = rANCS.ReadShort();
if (iNode == 0 && Loader.mVersion == eUnknownGame) if (iNode == 0 && Loader.mGame == eUnknownGame)
{ {
Loader.mVersion = (Unknown1 == 0xA) ? eEchoes : ePrime; // Best version indicator we know of unfortunately Loader.mGame = (CharVersion == 0xA) ? eEchoes : ePrime;
} }
pChar->Name = rANCS.ReadString(); pChar->Name = rANCS.ReadString();
pChar->pModel = gpResourceStore->LoadResource(rANCS.ReadLong(), "CMDL"); pChar->pModel = gpResourceStore->LoadResource(rANCS.ReadLong(), "CMDL");
@ -315,7 +415,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
for (u32 iAnim = 0; iAnim < AnimCount; iAnim++) for (u32 iAnim = 0; iAnim < AnimCount; iAnim++)
{ {
rANCS.Seek(0x4, SEEK_CUR); rANCS.Seek(0x4, SEEK_CUR);
if (Loader.mVersion == ePrime) rANCS.Seek(0x1, SEEK_CUR); if (Loader.mGame == ePrime) rANCS.Seek(0x1, SEEK_CUR);
rANCS.ReadString(); rANCS.ReadString();
} }
@ -323,37 +423,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
Loader.LoadPASDatabase(rANCS); Loader.LoadPASDatabase(rANCS);
// Particles // Particles
u32 ParticleCount = rANCS.ReadLong(); Loader.LoadParticleResourceData(rANCS, pChar, CharVersion);
pChar->GenericParticles.reserve(ParticleCount);
for (u32 iPart = 0; iPart < ParticleCount; iPart++)
pChar->GenericParticles.push_back( CAssetID(rANCS, e32Bit) );
u32 SwooshCount = rANCS.ReadLong();
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();
pChar->ElectricParticles.reserve(ElectricCount);
for (u32 iElec = 0; iElec < ElectricCount; iElec++)
pChar->ElectricParticles.push_back( CAssetID(rANCS, e32Bit) );
if (Loader.mVersion == eEchoes)
{
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);
if (Loader.mVersion == eEchoes) rANCS.Seek(0x4, SEEK_CUR);
u32 AnimCount2 = rANCS.ReadLong(); u32 AnimCount2 = rANCS.ReadLong();
for (u32 iAnim = 0; iAnim < AnimCount2; iAnim++) for (u32 iAnim = 0; iAnim < AnimCount2; iAnim++)
@ -375,13 +445,17 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
CAssetID ParticleID(rANCS, e32Bit); CAssetID ParticleID(rANCS, e32Bit);
if (ParticleID.IsValid()) pChar->EffectParticles.push_back(ParticleID); if (ParticleID.IsValid()) pChar->EffectParticles.push_back(ParticleID);
if (Loader.mVersion == ePrime) rANCS.ReadString(); if (Loader.mGame == ePrime) rANCS.ReadString();
if (Loader.mVersion == eEchoes) rANCS.Seek(0x4, SEEK_CUR); if (Loader.mGame == eEchoes) rANCS.Seek(0x4, SEEK_CUR);
rANCS.Seek(0xC, SEEK_CUR); rANCS.Seek(0xC, SEEK_CUR);
} }
} }
pChar->IceModel = CAssetID(rANCS, e32Bit);
pChar->IceSkin = CAssetID(rANCS, e32Bit); SOverlayModel Overlay;
Overlay.Type = eOT_Frozen;
Overlay.ModelID = CAssetID(rANCS, e32Bit);
Overlay.SkinID = CAssetID(rANCS, e32Bit);
pChar->OverlayModels.push_back(Overlay);
u32 AnimIndexCount = rANCS.ReadLong(); u32 AnimIndexCount = rANCS.ReadLong();
@ -391,7 +465,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
pChar->UsedAnimationIndices.insert(AnimIndex); pChar->UsedAnimationIndices.insert(AnimIndex);
} }
if (Loader.mVersion == eEchoes) if (Loader.mGame == eEchoes)
{ {
pChar->SpatialPrimitives = rANCS.ReadLong(); pChar->SpatialPrimitives = rANCS.ReadLong();
rANCS.Seek(0x1, SEEK_CUR); rANCS.Seek(0x1, SEEK_CUR);
@ -416,14 +490,14 @@ CAnimSet* CAnimSetLoader::LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry)
if (Check == 0x5 || Check == 0x3) if (Check == 0x5 || Check == 0x3)
{ {
Loader.mVersion = eCorruption; Loader.mGame = eCorruption;
Loader.pSet = new CAnimSet(pEntry); Loader.pSet = new CAnimSet(pEntry);
return Loader.LoadCorruptionCHAR(rCHAR); return Loader.LoadCorruptionCHAR(rCHAR);
} }
if (Check == 0x59) if (Check == 0x59)
{ {
Loader.mVersion = eReturns; Loader.mGame = eReturns;
Loader.pSet = new CAnimSet(pEntry); Loader.pSet = new CAnimSet(pEntry);
return Loader.LoadReturnsCHAR(rCHAR); return Loader.LoadReturnsCHAR(rCHAR);
} }
@ -431,3 +505,48 @@ CAnimSet* CAnimSetLoader::LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry)
Log::FileError(rCHAR.GetSourceString(), "CHAR has invalid first byte: " + TString::HexString(Check, 2)); Log::FileError(rCHAR.GetSourceString(), "CHAR has invalid first byte: " + TString::HexString(Check, 2));
return nullptr; return nullptr;
} }
CSourceAnimData* CAnimSetLoader::LoadSAND(IInputStream& rSAND, CResourceEntry *pEntry)
{
if (!rSAND.IsValid()) return nullptr;
// We only care about the transitions right now
CSourceAnimData *pData = new CSourceAnimData(pEntry);
u16 Unknown = rSAND.ReadShort(); // probably version
ASSERT(Unknown == 0);
// Transitions
u32 NumTransitions = rSAND.ReadLong();
for (u32 TransitionIdx = 0; TransitionIdx < NumTransitions; TransitionIdx++)
{
u8 UnkByte = rSAND.ReadByte();
ASSERT(UnkByte == 0);
CSourceAnimData::STransition Transition;
Transition.AnimA = CAssetID(rSAND, e64Bit);
Transition.AnimB = CAssetID(rSAND, e64Bit);
Transition.pTransition = gMetaTransFactory.LoadFromStream(rSAND, pEntry->Game());
pData->mTransitions.push_back(Transition);
}
// Half Transitions
u32 NumHalfTransitions = rSAND.ReadLong();
for (u32 HalfIdx = 0; HalfIdx < NumHalfTransitions; HalfIdx++)
{
u8 UnkByte = rSAND.ReadByte();
ASSERT(UnkByte == 0);
CSourceAnimData::SHalfTransition HalfTrans;
HalfTrans.Anim = CAssetID(rSAND, e64Bit);
HalfTrans.pTransition = gMetaTransFactory.LoadFromStream(rSAND, pEntry->Game());
pData->mHalfTransitions.push_back(HalfTrans);
}
// Default Transition
pData->mpDefaultTransition = gMetaTransFactory.LoadFromStream(rSAND, pEntry->Game());
return pData;
}

View File

@ -2,25 +2,27 @@
#define CCHARACTERLOADER_H #define CCHARACTERLOADER_H
#include "Core/Resource/Animation/CAnimSet.h" #include "Core/Resource/Animation/CAnimSet.h"
#include "Core/Resource/Animation/CSourceAnimData.h"
#include <Common/EGame.h> #include <Common/EGame.h>
class CAnimSetLoader class CAnimSetLoader
{ {
TResPtr<CAnimSet> pSet; TResPtr<CAnimSet> pSet;
EGame mVersion; EGame mGame;
CAnimSetLoader(); CAnimSetLoader();
CAnimSet* LoadCorruptionCHAR(IInputStream& rCHAR); CAnimSet* LoadCorruptionCHAR(IInputStream& rCHAR);
CAnimSet* LoadReturnsCHAR(IInputStream& rCHAR); CAnimSet* LoadReturnsCHAR(IInputStream& rCHAR);
void LoadPASDatabase(IInputStream& rPAS4); void LoadPASDatabase(IInputStream& rPAS4);
void LoadParticleResourceData(IInputStream& rFile, SSetCharacter *pChar, u16 Version);
void LoadAnimationSet(IInputStream& rANCS); void LoadAnimationSet(IInputStream& rANCS);
void ProcessPrimitives(); void ProcessPrimitives();
public: public:
static CAnimSet* LoadANCSOrCHAR(IInputStream& rFile, CResourceEntry *pEntry);
static CAnimSet* LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry); static CAnimSet* LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry);
static CAnimSet* LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry); static CAnimSet* LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry);
static CSourceAnimData* LoadSAND(IInputStream& rSAND, CResourceEntry *pEntry);
}; };
#endif // CCHARACTERLOADER_H #endif // CCHARACTERLOADER_H

View File

@ -466,7 +466,7 @@ CAnimation* CAnimationLoader::LoadANIM(IInputStream& rANIM, CResourceEntry *pEnt
{ {
// MP3/DKCR unsupported // MP3/DKCR unsupported
if (pEntry->Game() > eEchoes) if (pEntry->Game() > eEchoes)
return nullptr; return new CAnimation(pEntry);
u32 CompressionType = rANIM.ReadLong(); u32 CompressionType = rANIM.ReadLong();

View File

@ -49,6 +49,7 @@ public:
case eScan: return new CScan(pEntry); case eScan: return new CScan(pEntry);
case eSkeleton: return new CSkeleton(pEntry); case eSkeleton: return new CSkeleton(pEntry);
case eSkin: return new CSkin(pEntry); case eSkin: return new CSkin(pEntry);
case eSourceAnimData: return new CSourceAnimData(pEntry);
case eStaticGeometryMap: return new CPoiToWorld(pEntry); case eStaticGeometryMap: return new CPoiToWorld(pEntry);
case eStringList: return new CStringList(pEntry); case eStringList: return new CStringList(pEntry);
case eStringTable: return new CStringTable(pEntry); case eStringTable: return new CStringTable(pEntry);
@ -88,6 +89,7 @@ public:
case eScan: pRes = CScanLoader::LoadSCAN(rInput, pEntry); break; case eScan: pRes = CScanLoader::LoadSCAN(rInput, pEntry); break;
case eSkeleton: pRes = CSkeletonLoader::LoadCINF(rInput, pEntry); break; case eSkeleton: pRes = CSkeletonLoader::LoadCINF(rInput, pEntry); break;
case eSkin: pRes = CSkinLoader::LoadCSKR(rInput, pEntry); break; case eSkin: pRes = CSkinLoader::LoadCSKR(rInput, pEntry); break;
case eSourceAnimData: pRes = CAnimSetLoader::LoadSAND(rInput, pEntry); break;
case eStateMachine2: pRes = CUnsupportedFormatLoader::LoadFSM2(rInput, pEntry); break; case eStateMachine2: pRes = CUnsupportedFormatLoader::LoadFSM2(rInput, pEntry); break;
case eStaticGeometryMap: pRes = CPoiToWorldLoader::LoadEGMC(rInput, pEntry); break; case eStaticGeometryMap: pRes = CPoiToWorldLoader::LoadEGMC(rInput, pEntry); break;
case eStringList: pRes = CAudioGroupLoader::LoadSTLC(rInput, pEntry); break; case eStringList: pRes = CAudioGroupLoader::LoadSTLC(rInput, pEntry); break;

View File

@ -44,7 +44,10 @@ CScan* CScanLoader::LoadScanMP2(IInputStream& rSCAN)
return nullptr; return nullptr;
} }
rSCAN.Seek(0x6, SEEK_CUR); u16 InstanceSize = rSCAN.ReadShort();
u32 InstanceEnd = rSCAN.Tell() + InstanceSize;
rSCAN.Seek(0x4, SEEK_CUR);
u16 NumConnections = rSCAN.ReadShort(); u16 NumConnections = rSCAN.ReadShort();
if (NumConnections > 0) { if (NumConnections > 0) {
Log::FileWarning(rSCAN.GetSourceString(), ScanInfoStart, "SNFO object in SCAN has connections"); Log::FileWarning(rSCAN.GetSourceString(), ScanInfoStart, "SNFO object in SCAN has connections");
@ -68,6 +71,7 @@ CScan* CScanLoader::LoadScanMP2(IInputStream& rSCAN)
LoadParamsMP2(rSCAN, NumProperties); LoadParamsMP2(rSCAN, NumProperties);
break; break;
case 0x12: case 0x12:
case 0x15:
case 0x16: case 0x16:
mpScan = new CScan(mpEntry); mpScan = new CScan(mpEntry);
LoadParamsMP3(rSCAN, NumProperties); LoadParamsMP3(rSCAN, NumProperties);
@ -77,6 +81,20 @@ CScan* CScanLoader::LoadScanMP2(IInputStream& rSCAN)
return nullptr; return nullptr;
} }
// Load MP3 dependency list
if (mpScan->Game() == eCorruption)
{
rSCAN.GoTo(InstanceEnd);
u32 NumDeps = rSCAN.ReadLong();
for (u32 DepIdx = 0; DepIdx < NumDeps; DepIdx++)
{
rSCAN.Skip(4);
CAssetID ID(rSCAN, mpScan->Game());
mpScan->mDependencyList.push_back(ID);
}
}
return mpScan; return mpScan;
} }

View File

@ -32,6 +32,10 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF, CResourceEntry *pEntry
Loader.mpSkeleton = pSkel; Loader.mpSkeleton = pSkel;
EGame Game = pEntry->Game(); EGame Game = pEntry->Game();
// We don't support DKCR CINF right now
if (rCINF.PeekLong() == 0x9E220006)
return pSkel;
u32 NumBones = rCINF.ReadLong(); u32 NumBones = rCINF.ReadLong();
pSkel->mBones.reserve(NumBones); pSkel->mBones.reserve(NumBones);
@ -61,7 +65,7 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF, CResourceEntry *pEntry
u32 Check = rCINF.PeekLong(); u32 Check = rCINF.PeekLong();
Game = ((Check > 100 || Check == 0) ? eEchoes : ePrime); Game = ((Check > 100 || Check == 0) ? eEchoes : ePrime);
} }
if (Game == eEchoes) if (Game >= eEchoes)
{ {
pBone->mRotation = CQuaternion(rCINF); pBone->mRotation = CQuaternion(rCINF);
pBone->mLocalRotation = CQuaternion(rCINF); pBone->mLocalRotation = CQuaternion(rCINF);

View File

@ -5,9 +5,13 @@
CSkin* CSkinLoader::LoadCSKR(IInputStream& rCSKR, CResourceEntry *pEntry) CSkin* CSkinLoader::LoadCSKR(IInputStream& rCSKR, CResourceEntry *pEntry)
{ {
if (!rCSKR.IsValid()) return nullptr; if (!rCSKR.IsValid()) return nullptr;
CSkin *pSkin = new CSkin(pEntry);
// We don't support MP3/DKCR CSKR yet
if (rCSKR.PeekLong() == FOURCC('SKIN'))
return pSkin;
u32 NumVertexGroups = rCSKR.ReadLong(); u32 NumVertexGroups = rCSKR.ReadLong();
CSkin *pSkin = new CSkin(pEntry);
pSkin->mVertGroups.resize(NumVertexGroups); pSkin->mVertGroups.resize(NumVertexGroups);
for (u32 iGrp = 0; iGrp < NumVertexGroups; iGrp++) for (u32 iGrp = 0; iGrp < NumVertexGroups; iGrp++)

View File

@ -179,7 +179,8 @@ CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32&
if (pRes) if (pRes)
{ {
rOutCharIndex = (it->ForceNodeIndex >= 0 && it->ForceNodeIndex < (s32) static_cast<CAnimSet*>(pRes)->NumCharacters() ? it->ForceNodeIndex : pChar->Get().CharacterIndex()); u32 MaxNumChars = static_cast<CAnimSet*>(pRes)->NumCharacters();
rOutCharIndex = (it->ForceNodeIndex >= 0 && it->ForceNodeIndex < (s32) MaxNumChars ? it->ForceNodeIndex : pChar->Get().CharacterIndex());
rOutAnimIndex = pChar->Get().AnimIndex(); rOutAnimIndex = pChar->Get().AnimIndex();
} }
} }

View File

@ -4,6 +4,7 @@
#include "Core/Render/CDrawUtil.h" #include "Core/Render/CDrawUtil.h"
#include "Core/Render/CGraphics.h" #include "Core/Render/CGraphics.h"
#include "Core/Render/CRenderer.h" #include "Core/Render/CRenderer.h"
#include "Core/Resource/Animation/CAnimSet.h"
#include "Core/Resource/Script/CMasterTemplate.h" #include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/CScriptLayer.h" #include "Core/Resource/Script/CScriptLayer.h"
#include "Core/ScriptExtra/CScriptExtra.h" #include "Core/ScriptExtra/CScriptExtra.h"

View File

@ -9,6 +9,7 @@
#include "Editor/Widgets/WDraggableSpinBox.h" #include "Editor/Widgets/WDraggableSpinBox.h"
#include "Editor/Widgets/WIntegralSpinBox.h" #include "Editor/Widgets/WIntegralSpinBox.h"
#include <Core/Resource/Animation/CAnimSet.h>
#include <Core/Resource/Script/IProperty.h> #include <Core/Resource/Script/IProperty.h>
#include <Core/Resource/Script/IPropertyTemplate.h> #include <Core/Resource/Script/IPropertyTemplate.h>

View File

@ -56,7 +56,7 @@ void IOutputStream::WriteString(const std::string& rkVal)
for (unsigned int i = 0; i < rkVal.size(); i++) for (unsigned int i = 0; i < rkVal.size(); i++)
WriteByte(rkVal[i]); WriteByte(rkVal[i]);
if ((rkVal.empty()) || (rkVal.back() != '\0')) if (rkVal.empty() || rkVal.back() != '\0')
WriteByte(0); WriteByte(0);
} }
@ -65,7 +65,7 @@ void IOutputStream::WriteString(const std::string& rkVal, unsigned long Count, b
for (unsigned int iChr = 0; iChr < Count; iChr++) for (unsigned int iChr = 0; iChr < Count; iChr++)
WriteByte(rkVal[iChr]); WriteByte(rkVal[iChr]);
if (Terminate && (rkVal[Count-1] != '\0')) if (Terminate && (Count == 0 || rkVal[Count-1] != '\0'))
WriteByte(0); WriteByte(0);
} }
@ -80,7 +80,7 @@ void IOutputStream::WriteWideString(const std::wstring& rkVal)
for (unsigned int iChr = 0; iChr < rkVal.size(); iChr++) for (unsigned int iChr = 0; iChr < rkVal.size(); iChr++)
WriteShort(rkVal[iChr]); WriteShort(rkVal[iChr]);
if ((!rkVal.empty()) && (rkVal.back() != '\0')) if (rkVal.empty() || rkVal.back() != '\0')
WriteShort(0); WriteShort(0);
} }
@ -89,7 +89,7 @@ void IOutputStream::WriteWideString(const std::wstring& rkVal, unsigned long Cou
for (unsigned int iChr = 0; iChr < Count; iChr++) for (unsigned int iChr = 0; iChr < Count; iChr++)
WriteShort(rkVal[iChr]); WriteShort(rkVal[iChr]);
if (Terminate && (rkVal[Count-1] != 0)) if (Terminate && (Count == 0 || rkVal[Count-1] != 0))
WriteShort(0); WriteShort(0);
} }
@ -99,7 +99,6 @@ void IOutputStream::WriteSizedWideString(const std::wstring& rkVal)
WriteBytes(rkVal.data(), rkVal.size() * 2); WriteBytes(rkVal.data(), rkVal.size() * 2);
} }
bool IOutputStream::GoTo(long Address) bool IOutputStream::GoTo(long Address)
{ {
return Seek(Address, SEEK_SET); return Seek(Address, SEEK_SET);