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/Cooker/CResourceCooker.h \
Resource/CAudioMacro.h \
Resource/Animation/CCharacter.h \
CompressionUtil.h
CompressionUtil.h \
Resource/Animation/CSourceAnimData.h
# Source Files
SOURCES += \

View File

@ -5,6 +5,7 @@
#include "Core/Resource/CFont.h"
#include "Core/Resource/CScan.h"
#include "Core/Resource/CWorld.h"
#include "Core/Resource/Animation/CAnimSet.h"
#include "Core/Resource/Script/CScriptLayer.h"
#include <Math/MathUtil.h>
@ -398,19 +399,44 @@ void GenerateAssetNames(CGameProject *pProj)
if (pkChar->pSkeleton) ApplyGeneratedName(pkChar->pSkeleton->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);
ApplyGeneratedName(pIceModelEntry, SetDir, IceName);
TWideString AnimDataName = TString::Format(L"%s_animdata", *CharName);
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);
ApplyGeneratedName(pIceSkinEntry, SetDir, IceName);
TWideString TypeName = (
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 "Core/GameProject/CGameProject.h"
#include "Core/Resource/Animation/CAnimSet.h"
#include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Resource/Script/CScriptObject.h"
@ -199,34 +200,35 @@ void CSetCharacterDependency::Serialize(IArchive& rArc)
<< 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);
const SSetCharacter *pkChar = pkOwnerSet->Character(CharIndex);
CSetCharacterDependency *pTree = new CSetCharacterDependency(rkChar.ID);
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);
pTree->AddDependency(pkChar->pSkeleton);
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 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
pTree->AddDependency(pkParticleVectors[iVec]->at(iPart));
}
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;
}

View File

@ -160,7 +160,7 @@ public:
inline u32 CharSetIndex() const { return mCharSetIndex; }
// 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.

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include "CAnimEventData.h"
#include "CSkeleton.h"
#include "CSkin.h"
#include "CSourceAnimData.h"
#include "IMetaAnimation.h"
#include "IMetaTransition.h"
#include "Core/Resource/CDependencyGroup.h"
@ -43,20 +44,38 @@ struct SHalfTransition
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
{
u32 ID;
TString Name;
TResPtr<CModel> pModel;
TResPtr<CSkin> pSkin;
TResPtr<CSkeleton> pSkeleton;
std::vector<SOverlayModel> OverlayModels;
CAssetID AnimDataID;
std::vector<CAssetID> GenericParticles;
std::vector<CAssetID> ElectricParticles;
std::vector<CAssetID> SwooshParticles;
std::vector<CAssetID> SpawnParticles;
std::vector<CAssetID> EffectParticles;
CAssetID IceModel;
CAssetID IceSkin;
std::vector<CAssetID> SoundEffects;
CAssetID SpatialPrimitives;
std::set<u32> UsedAnimationIndices;
};
@ -114,16 +133,49 @@ public:
// Character dependencies
for (u32 iChar = 0; iChar < mCharacters.size(); iChar++)
{
CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree(this, iChar);
CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree( mCharacters[iChar] );
ASSERT(pCharTree);
pTree->AddChild(pCharTree);
}
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
// Animation dependencies
if (Game() <= eEchoes)
{
CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
ASSERT(pAnimTree);
pTree->AddChild(pAnimTree);
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
{
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;

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*/)
{
if (!mCharacterID.IsValid()) return 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;
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
return pkChar ? pkChar->pModel : nullptr;
}
TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
{
if (!mCharacterID.IsValid()) return "";
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;
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
return pkChar ? pkChar->Name : "";
}
// ************ ACCESSORS ************

View File

@ -1,7 +1,6 @@
#ifndef CANIMATIONPARAMETERS_H
#define CANIMATIONPARAMETERS_H
#include "CAnimSet.h"
#include "Core/Resource/TResPtr.h"
#include "Core/Resource/Model/CModel.h"
#include <Common/EGame.h>
@ -22,6 +21,7 @@ public:
CAnimationParameters(IInputStream& rSCLY, EGame Game);
void Write(IOutputStream& rSCLY);
const SSetCharacter* GetCurrentSetCharacter(s32 NodeIndex = -1);
CModel* GetCurrentModel(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 gMetaAnimFactory;
IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput)
IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game)
{
EMetaAnimationType Type = (EMetaAnimationType) rInput.ReadLong();
switch (Type)
{
case eMAT_Play:
return new CMetaAnimPlay(rInput);
return new CMetaAnimPlay(rInput, Game);
case eMAT_Blend:
case eMAT_PhaseBlend:
return new CMetaAnimBlend(Type, rInput);
return new CMetaAnimBlend(Type, rInput, Game);
case eMAT_Random:
return new CMetaAnimRandom(rInput);
return new CMetaAnimRandom(rInput, Game);
case eMAT_Sequence:
return new CMetaAnimSequence(rInput);
return new CMetaAnimSequence(rInput, Game);
default:
Log::Error("Unrecognized meta-animation type: " + TString::FromInt32(Type, 0, 10));
@ -29,9 +29,9 @@ IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput)
}
// ************ CMetaAnimationPlay ************
CMetaAnimPlay::CMetaAnimPlay(IInputStream& rInput)
CMetaAnimPlay::CMetaAnimPlay(IInputStream& rInput, EGame Game)
{
mPrimitive = CAnimPrimitive(rInput);
mPrimitive = CAnimPrimitive(rInput, Game);
mUnknownA = rInput.ReadFloat();
mUnknownB = rInput.ReadLong();
}
@ -47,12 +47,12 @@ void CMetaAnimPlay::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) cons
}
// ************ CMetaAnimBlend ************
CMetaAnimBlend::CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput)
CMetaAnimBlend::CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput, EGame Game)
{
ASSERT(Type == eMAT_Blend || Type == eMAT_PhaseBlend);
mType = Type;
mpMetaAnimA = gMetaAnimFactory.LoadFromStream(rInput);
mpMetaAnimB = gMetaAnimFactory.LoadFromStream(rInput);
mpMetaAnimA = gMetaAnimFactory.LoadFromStream(rInput, Game);
mpMetaAnimB = gMetaAnimFactory.LoadFromStream(rInput, Game);
mUnknownA = rInput.ReadFloat();
mUnknownB = rInput.ReadBool();
}
@ -75,7 +75,7 @@ void CMetaAnimBlend::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) con
}
// ************ CMetaAnimRandom ************
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput)
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
{
u32 NumPairs = rInput.ReadLong();
mProbabilityPairs.reserve(NumPairs);
@ -83,7 +83,7 @@ CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput)
for (u32 iAnim = 0; iAnim < NumPairs; iAnim++)
{
SAnimProbabilityPair Pair;
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput);
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
Pair.Probability = rInput.ReadLong();
mProbabilityPairs.push_back(Pair);
}
@ -107,14 +107,14 @@ void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) co
}
// ************ CMetaAnimSequence ************
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput)
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput, EGame Game)
{
u32 NumAnims = rInput.ReadLong();
mAnimations.reserve(NumAnims);
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
{
IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput);
IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
mAnimations.push_back(pAnim);
}
}

View File

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

View File

@ -4,21 +4,24 @@
// ************ CMetaTransFactory ************
CMetaTransFactory gMetaTransFactory;
IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput)
IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game)
{
EMetaTransitionType Type = (EMetaTransitionType) rInput.ReadLong();
switch (Type)
{
case eMTT_MetaAnim:
return new CMetaTransMetaAnim(rInput);
return new CMetaTransMetaAnim(rInput, Game);
case eMTT_Trans:
case eMTT_PhaseTrans:
return new CMetaTransTrans(Type, rInput);
return new CMetaTransTrans(Type, rInput, Game);
case eMTT_Snap:
return new CMetaTransSnap(rInput);
return new CMetaTransSnap(rInput, Game);
case eMTT_Type4:
return new CMetaTransType4(rInput, Game);
default:
Log::Error("Unrecognized meta-transition type: " + TString::FromInt32(Type, 0, 10));
@ -27,9 +30,9 @@ IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput)
}
// ************ CMetaTransMetaAnim ************
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput)
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput, EGame Game)
{
mpAnim = gMetaAnimFactory.LoadFromStream(rInput);
mpAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
}
CMetaTransMetaAnim::~CMetaTransMetaAnim()
@ -48,15 +51,23 @@ void CMetaTransMetaAnim::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet)
}
// ************ CMetaTransTrans ************
CMetaTransTrans::CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput)
CMetaTransTrans::CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput, EGame Game)
{
ASSERT(Type == eMTT_Trans || Type == eMTT_PhaseTrans);
mType = Type;
mUnknownA = rInput.ReadFloat();
mUnknownB = rInput.ReadLong();
mUnknownC = rInput.ReadBool();
mUnknownD = rInput.ReadBool();
mUnknownE = rInput.ReadLong();
if (Game <= eEchoes)
{
mUnknownA = rInput.ReadFloat();
mUnknownB = rInput.ReadLong();
mUnknownC = rInput.ReadBool();
mUnknownD = rInput.ReadBool();
mUnknownE = rInput.ReadLong();
}
else
{
rInput.Skip(0x13);
}
}
EMetaTransitionType CMetaTransTrans::Type() const
@ -69,7 +80,7 @@ void CMetaTransTrans::GetUniquePrimitives(std::set<CAnimPrimitive>&) const
}
// ************ CMetaTransSnap ************
CMetaTransSnap::CMetaTransSnap(IInputStream&)
CMetaTransSnap::CMetaTransSnap(IInputStream&, EGame)
{
}
@ -81,3 +92,18 @@ EMetaTransitionType CMetaTransSnap::Type() 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_Trans = 1,
eMTT_PhaseTrans = 2, // note: structure shared with eMTT_Trans
eMTT_Snap = 3
eMTT_Snap = 3,
eMTT_Type4 = 4 // MP3 only
};
// Factory class
class CMetaTransFactory
{
public:
class IMetaTransition* LoadFromStream(IInputStream& rInput);
class IMetaTransition* LoadFromStream(IInputStream& rInput, EGame Game);
};
extern CMetaTransFactory gMetaTransFactory;
@ -38,7 +39,7 @@ class CMetaTransMetaAnim : public IMetaTransition
IMetaAnimation *mpAnim;
public:
CMetaTransMetaAnim(IInputStream& rInput);
CMetaTransMetaAnim(IInputStream& rInput, EGame Game);
~CMetaTransMetaAnim();
virtual EMetaTransitionType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
@ -55,7 +56,7 @@ class CMetaTransTrans : public IMetaTransition
u32 mUnknownE;
public:
CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput);
CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput, EGame Game);
virtual EMetaTransitionType Type() const;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
};
@ -64,7 +65,16 @@ public:
class CMetaTransSnap : public IMetaTransition
{
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 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");
AddExtension(pType, "SAND", eCorruptionProto, eCorruption);
pType->mHidden = true;
pType->mCanHaveDependencies = false; // all dependencies are added to the CHAR dependency tree
}
{
CResTypeInfo *pType = new CResTypeInfo(eSpatialPrimitive, "Spatial Primitive");

View File

@ -52,6 +52,9 @@ private:
CAnimationParameters mUnknownAnimParams;
std::vector<SScanInfoSecondaryModel> mSecondaryModels;
// MP3
std::vector<CAssetID> mDependencyList;
public:
CScan(CResourceEntry *pEntry = 0)
: CResource(pEntry)
@ -63,12 +66,20 @@ public:
CDependencyTree* BuildDependencyTree() const
{
// note: not handling Corruption yet
if (Game() >= eCorruptionProto)
Log::Warning("CScan::BuildDependencyTree not handling Corruption dependencies");
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)
pTree->AddDependency(mFrameID);

View File

@ -2,7 +2,7 @@
#include "Core/CAudioManager.h"
#include "Core/GameProject/CGameProject.h"
void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
void CAnimEventLoader::LoadEvents(IInputStream& rEVNT)
{
u32 Version = rEVNT.ReadLong();
ASSERT(Version == 1 || Version == 2);
@ -12,9 +12,7 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iLoop = 0; iLoop < NumLoopEvents; iLoop++)
{
rEVNT.Seek(0x2, SEEK_CUR);
rEVNT.ReadString();
rEVNT.Seek(0x1C, SEEK_CUR);
LoadLoopEvent(rEVNT);
}
// User Events
@ -22,10 +20,7 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iUser = 0; iUser < NumUserEvents; iUser++)
{
rEVNT.Seek(0x2, SEEK_CUR);
rEVNT.ReadString();
rEVNT.Seek(0x1F, SEEK_CUR);
rEVNT.ReadString();
LoadUserEvent(rEVNT);
}
// Effect Events
@ -33,20 +28,7 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iFX = 0; iFX < NumEffectEvents; iFX++)
{
rEVNT.Seek(0x2, SEEK_CUR);
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);
LoadEffectEvent(rEVNT);
}
// Sound Events
@ -56,21 +38,92 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes)
for (u32 iSound = 0; iSound < NumSoundEvents; iSound++)
{
rEVNT.Seek(0x2, SEEK_CUR);
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);
LoadSoundEvent(rEVNT);
}
}
}
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);
if (SoundInfo.pAudioGroup)
mpEventData->AddEvent(CharIndex, SoundInfo.pAudioGroup->ID());
rEVNT.Skip(4);
}
else if (StructType == 2)
{
// 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;
Loader.mpEventData = new CAnimEventData(pEntry);
Loader.LoadEvents(rEVNT, false);
Loader.mGame = ePrime;
Loader.LoadEvents(rEVNT);
return Loader.mpEventData;
}
@ -89,6 +143,38 @@ CAnimEventData* CAnimEventLoader::LoadAnimSetEvents(IInputStream& rANCS)
{
CAnimEventLoader Loader;
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;
}

View File

@ -7,13 +7,20 @@
class CAnimEventLoader
{
TResPtr<CAnimEventData> mpEventData;
EGame mGame;
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:
static CAnimEventData* LoadEVNT(IInputStream& rEVNT, CResourceEntry *pEntry);
static CAnimEventData* LoadAnimSetEvents(IInputStream& rANCS);
static CAnimEventData* LoadCorruptionCharacterEventSet(IInputStream& rCHAR);
};
#endif // CANIMEVENTLOADER_H

View File

@ -9,13 +9,89 @@ CAnimSetLoader::CAnimSetLoader()
CAnimSet* CAnimSetLoader::LoadCorruptionCHAR(IInputStream& rCHAR)
{
// For now, we only read enough to fetch the model
rCHAR.Seek(0x1, SEEK_CUR);
pSet->mCharacters.resize(1);
SSetCharacter& rNode = pSet->mCharacters[0];
pSet->mCharacters.emplace_back( SSetCharacter() );;
SSetCharacter& rChar = pSet->mCharacters.back();
// 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;
}
@ -23,22 +99,25 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
{
// For now, we only read enough to fetch the model
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.ReadString();
rNode.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL");
rChar.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong(), "CMDL");
return pSet;
}
void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4)
{
// 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();
rPAS4.Seek(0x4, SEEK_CUR); // Skipping default anim state
ASSERT(Magic == FOURCC('PAS4'));
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)
{
u16 Version = rANCS.ReadShort();
@ -84,7 +198,7 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
{
SAnimation Anim;
Anim.Name = rANCS.ReadString();
Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rANCS);
Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rANCS, mGame);
pSet->mAnimations.push_back(Anim);
}
@ -98,11 +212,11 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
Trans.Unknown = rANCS.ReadLong();
Trans.AnimIdA = rANCS.ReadLong();
Trans.AnimIdB = rANCS.ReadLong();
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS);
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS, mGame);
pSet->mTransitions.push_back(Trans);
}
pSet->mpDefaultTransition = gMetaTransFactory.LoadFromStream(rANCS);
pSet->mpDefaultTransition = gMetaTransFactory.LoadFromStream(rANCS, mGame);
// Additive Animations
u32 NumAdditive = rANCS.ReadLong();
@ -130,14 +244,14 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
{
SHalfTransition Trans;
Trans.AnimID = rANCS.ReadLong();
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS);
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS, mGame);
pSet->mHalfTransitions.push_back(Trans);
}
}
// Skipping MP1 ANIM asset list
// Events
if (mVersion >= eEchoesDemo)
if (mGame >= eEchoesDemo)
{
u32 EventDataCount = rANCS.ReadLong();
pSet->mAnimEvents.reserve(EventDataCount);
@ -260,20 +374,6 @@ void CAnimSetLoader::ProcessPrimitives()
}
// ************ 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)
{
if (!rANCS.IsValid()) return nullptr;
@ -287,7 +387,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
CAnimSetLoader Loader;
Loader.pSet = new CAnimSet(pEntry);
Loader.mVersion = pEntry->Game();
Loader.mGame = pEntry->Game();
u32 NodeCount = rANCS.ReadLong();
Loader.pSet->mCharacters.resize(NodeCount);
@ -296,11 +396,11 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
{
SSetCharacter *pChar = &Loader.pSet->mCharacters[iNode];
rANCS.Seek(0x4, SEEK_CUR); // Skipping node self-index
u16 Unknown1 = rANCS.ReadShort();
if (iNode == 0 && Loader.mVersion == eUnknownGame)
pChar->ID = rANCS.ReadLong();
u16 CharVersion = rANCS.ReadShort();
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->pModel = gpResourceStore->LoadResource(rANCS.ReadLong(), "CMDL");
@ -315,7 +415,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
for (u32 iAnim = 0; iAnim < AnimCount; iAnim++)
{
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();
}
@ -323,37 +423,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
Loader.LoadPASDatabase(rANCS);
// Particles
u32 ParticleCount = rANCS.ReadLong();
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);
Loader.LoadParticleResourceData(rANCS, pChar, CharVersion);
u32 AnimCount2 = rANCS.ReadLong();
for (u32 iAnim = 0; iAnim < AnimCount2; iAnim++)
@ -375,13 +445,17 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
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);
if (Loader.mGame == ePrime) rANCS.ReadString();
if (Loader.mGame == eEchoes) rANCS.Seek(0x4, 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();
@ -391,7 +465,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
pChar->UsedAnimationIndices.insert(AnimIndex);
}
if (Loader.mVersion == eEchoes)
if (Loader.mGame == eEchoes)
{
pChar->SpatialPrimitives = rANCS.ReadLong();
rANCS.Seek(0x1, SEEK_CUR);
@ -416,14 +490,14 @@ CAnimSet* CAnimSetLoader::LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry)
if (Check == 0x5 || Check == 0x3)
{
Loader.mVersion = eCorruption;
Loader.mGame = eCorruption;
Loader.pSet = new CAnimSet(pEntry);
return Loader.LoadCorruptionCHAR(rCHAR);
}
if (Check == 0x59)
{
Loader.mVersion = eReturns;
Loader.mGame = eReturns;
Loader.pSet = new CAnimSet(pEntry);
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));
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
#include "Core/Resource/Animation/CAnimSet.h"
#include "Core/Resource/Animation/CSourceAnimData.h"
#include <Common/EGame.h>
class CAnimSetLoader
{
TResPtr<CAnimSet> pSet;
EGame mVersion;
EGame mGame;
CAnimSetLoader();
CAnimSet* LoadCorruptionCHAR(IInputStream& rCHAR);
CAnimSet* LoadReturnsCHAR(IInputStream& rCHAR);
void LoadPASDatabase(IInputStream& rPAS4);
void LoadParticleResourceData(IInputStream& rFile, SSetCharacter *pChar, u16 Version);
void LoadAnimationSet(IInputStream& rANCS);
void ProcessPrimitives();
public:
static CAnimSet* LoadANCSOrCHAR(IInputStream& rFile, CResourceEntry *pEntry);
static CAnimSet* LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry);
static CAnimSet* LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry);
static CSourceAnimData* LoadSAND(IInputStream& rSAND, CResourceEntry *pEntry);
};
#endif // CCHARACTERLOADER_H

View File

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

View File

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

View File

@ -44,7 +44,10 @@ CScan* CScanLoader::LoadScanMP2(IInputStream& rSCAN)
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();
if (NumConnections > 0) {
Log::FileWarning(rSCAN.GetSourceString(), ScanInfoStart, "SNFO object in SCAN has connections");
@ -68,6 +71,7 @@ CScan* CScanLoader::LoadScanMP2(IInputStream& rSCAN)
LoadParamsMP2(rSCAN, NumProperties);
break;
case 0x12:
case 0x15:
case 0x16:
mpScan = new CScan(mpEntry);
LoadParamsMP3(rSCAN, NumProperties);
@ -77,6 +81,20 @@ CScan* CScanLoader::LoadScanMP2(IInputStream& rSCAN)
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;
}

View File

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

View File

@ -5,9 +5,13 @@
CSkin* CSkinLoader::LoadCSKR(IInputStream& rCSKR, CResourceEntry *pEntry)
{
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();
CSkin *pSkin = new CSkin(pEntry);
pSkin->mVertGroups.resize(NumVertexGroups);
for (u32 iGrp = 0; iGrp < NumVertexGroups; iGrp++)

View File

@ -179,7 +179,8 @@ CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32&
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();
}
}

View File

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

View File

@ -9,6 +9,7 @@
#include "Editor/Widgets/WDraggableSpinBox.h"
#include "Editor/Widgets/WIntegralSpinBox.h"
#include <Core/Resource/Animation/CAnimSet.h>
#include <Core/Resource/Script/IProperty.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++)
WriteByte(rkVal[i]);
if ((rkVal.empty()) || (rkVal.back() != '\0'))
if (rkVal.empty() || rkVal.back() != '\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++)
WriteByte(rkVal[iChr]);
if (Terminate && (rkVal[Count-1] != '\0'))
if (Terminate && (Count == 0 || rkVal[Count-1] != '\0'))
WriteByte(0);
}
@ -80,7 +80,7 @@ void IOutputStream::WriteWideString(const std::wstring& rkVal)
for (unsigned int iChr = 0; iChr < rkVal.size(); iChr++)
WriteShort(rkVal[iChr]);
if ((!rkVal.empty()) && (rkVal.back() != '\0'))
if (rkVal.empty() || rkVal.back() != '\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++)
WriteShort(rkVal[iChr]);
if (Terminate && (rkVal[Count-1] != 0))
if (Terminate && (Count == 0 || rkVal[Count-1] != 0))
WriteShort(0);
}
@ -99,7 +99,6 @@ void IOutputStream::WriteSizedWideString(const std::wstring& rkVal)
WriteBytes(rkVal.data(), rkVal.size() * 2);
}
bool IOutputStream::GoTo(long Address)
{
return Seek(Address, SEEK_SET);