mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-05-25 16:51:38 +00:00
Added support for omitting unused animations from paks (needs work to not crash)
This commit is contained in:
parent
a18655da00
commit
3942c09e89
@ -80,7 +80,7 @@ inline THexSerialParameter<ValType> MakeHexSerialParameter(const char *pkName, V
|
|||||||
#define SERIAL_HEX(ParamName, ParamValue) MakeHexSerialParameter(ParamName, ParamValue)
|
#define SERIAL_HEX(ParamName, ParamValue) MakeHexSerialParameter(ParamName, ParamValue)
|
||||||
#define SERIAL_HEX_AUTO(ParamValue) MakeHexSerialParameter(#ParamValue, ParamValue)
|
#define SERIAL_HEX_AUTO(ParamValue) MakeHexSerialParameter(#ParamValue, ParamValue)
|
||||||
|
|
||||||
// TAbstractSerialParameter - name/value pair for polymorphic objects a pointer to a factory
|
// TAbstractSerialParameter - name/value pair for polymorphic objects with a pointer to a factory
|
||||||
template<typename ValType, typename FactoryType>
|
template<typename ValType, typename FactoryType>
|
||||||
struct TAbstractSerialParameter
|
struct TAbstractSerialParameter
|
||||||
{
|
{
|
||||||
|
@ -36,18 +36,10 @@ void CDependencyTree::Serialize(IArchive& rArc)
|
|||||||
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/)
|
void CDependencyTree::AddChild(IDependencyNode *pNode)
|
||||||
{
|
{
|
||||||
if (!pRes) return;
|
ASSERT(pNode);
|
||||||
AddDependency(pRes->ID(), AvoidDuplicates);
|
mChildren.push_back(pNode);
|
||||||
}
|
|
||||||
|
|
||||||
void CDependencyTree::AddEventDependency(const CAssetID& rkID, u32 CharIndex)
|
|
||||||
{
|
|
||||||
// Note: No duplicate check because there might be multiple events using the same asset ID with different character indices
|
|
||||||
if (!rkID.IsValid()) return;
|
|
||||||
CAnimEventDependency *pDepend = new CAnimEventDependency(rkID, CharIndex);
|
|
||||||
mChildren.push_back(pDepend);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/)
|
void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/)
|
||||||
@ -57,6 +49,12 @@ void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /
|
|||||||
mChildren.push_back(pDepend);
|
mChildren.push_back(pDepend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/)
|
||||||
|
{
|
||||||
|
if (!pRes) return;
|
||||||
|
AddDependency(pRes->ID(), AvoidDuplicates);
|
||||||
|
}
|
||||||
|
|
||||||
// ************ CResourceDependency ************
|
// ************ CResourceDependency ************
|
||||||
EDependencyNodeType CResourceDependency::Type() const
|
EDependencyNodeType CResourceDependency::Type() const
|
||||||
{
|
{
|
||||||
@ -180,39 +178,28 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CAnimEventDependency ************
|
// ************ CSetCharacterDependency ************
|
||||||
EDependencyNodeType CAnimEventDependency::Type() const
|
EDependencyNodeType CSetCharacterDependency::Type() const
|
||||||
{
|
{
|
||||||
return eDNT_AnimEvent;
|
return eDNT_SetCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAnimEventDependency::Serialize(IArchive& rArc)
|
void CSetCharacterDependency::Serialize(IArchive& rArc)
|
||||||
{
|
{
|
||||||
CResourceDependency::Serialize(rArc);
|
rArc << SERIAL("SetIndex", mSetIndex)
|
||||||
rArc << SERIAL("CharacterIndex", mCharIndex);
|
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CAnimSetDependencyTree ************
|
CSetCharacterDependency* CSetCharacterDependency::BuildTree(const CAnimSet *pkOwnerSet, u32 CharIndex)
|
||||||
EDependencyNodeType CAnimSetDependencyTree::Type() const
|
|
||||||
{
|
{
|
||||||
return eDNT_AnimSet;
|
CSetCharacterDependency *pTree = new CSetCharacterDependency(CharIndex);
|
||||||
}
|
const SSetCharacter *pkChar = pkOwnerSet->Character(CharIndex);
|
||||||
|
|
||||||
void CAnimSetDependencyTree::Serialize(IArchive& rArc)
|
if (pkChar)
|
||||||
{
|
{
|
||||||
CDependencyTree::Serialize(rArc);
|
pTree->AddDependency(pkChar->pModel);
|
||||||
rArc << SERIAL_CONTAINER("CharacterOffsets", mCharacterOffsets, "Offset");
|
pTree->AddDependency(pkChar->pSkeleton);
|
||||||
}
|
pTree->AddDependency(pkChar->pSkin);
|
||||||
|
|
||||||
void CAnimSetDependencyTree::AddCharacter(const SSetCharacter *pkChar, const std::set<CAssetID>& rkBaseUsedSet)
|
|
||||||
{
|
|
||||||
mCharacterOffsets.push_back( NumChildren() );
|
|
||||||
if (!pkChar) return;
|
|
||||||
|
|
||||||
std::set<CAssetID> UsedSet = rkBaseUsedSet;
|
|
||||||
AddCharDependency(pkChar->pModel, UsedSet);
|
|
||||||
AddCharDependency(pkChar->pSkeleton, UsedSet);
|
|
||||||
AddCharDependency(pkChar->pSkin, UsedSet);
|
|
||||||
|
|
||||||
const std::vector<CAssetID> *pkParticleVectors[5] = {
|
const std::vector<CAssetID> *pkParticleVectors[5] = {
|
||||||
&pkChar->GenericParticles, &pkChar->ElectricParticles,
|
&pkChar->GenericParticles, &pkChar->ElectricParticles,
|
||||||
@ -223,26 +210,66 @@ void CAnimSetDependencyTree::AddCharacter(const SSetCharacter *pkChar, const std
|
|||||||
for (u32 iVec = 0; iVec < 5; iVec++)
|
for (u32 iVec = 0; iVec < 5; iVec++)
|
||||||
{
|
{
|
||||||
for (u32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
|
for (u32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
|
||||||
AddCharDependency(pkParticleVectors[iVec]->at(iPart), UsedSet);
|
pTree->AddDependency(pkParticleVectors[iVec]->at(iPart));
|
||||||
}
|
}
|
||||||
|
|
||||||
AddCharDependency(pkChar->IceModel, UsedSet);
|
pTree->AddDependency(pkChar->IceModel);
|
||||||
AddCharDependency(pkChar->IceSkin, UsedSet);
|
pTree->AddDependency(pkChar->IceSkin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAnimSetDependencyTree::AddCharDependency(const CAssetID& rkID, std::set<CAssetID>& rUsedSet)
|
return pTree;
|
||||||
{
|
|
||||||
if (rkID.IsValid() && rUsedSet.find(rkID) == rUsedSet.end())
|
|
||||||
{
|
|
||||||
rUsedSet.insert(rkID);
|
|
||||||
AddDependency(rkID, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAnimSetDependencyTree::AddCharDependency(CResource *pRes, std::set<CAssetID>& rUsedSet)
|
// ************ CSetAnimationDependency ************
|
||||||
|
EDependencyNodeType CSetAnimationDependency::Type() const
|
||||||
{
|
{
|
||||||
if (!pRes) return;
|
return eDNT_SetAnimation;
|
||||||
AddCharDependency(pRes->ID(), rUsedSet);
|
}
|
||||||
|
|
||||||
|
void CSetAnimationDependency::Serialize(IArchive& rArc)
|
||||||
|
{
|
||||||
|
rArc << SERIAL_CONTAINER("CharacterIndices", mCharacterIndices, "Index")
|
||||||
|
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, u32 AnimIndex)
|
||||||
|
{
|
||||||
|
const SSetAnimation *pkAnim = pkOwnerSet->Animation(AnimIndex);
|
||||||
|
CSetAnimationDependency *pTree = new CSetAnimationDependency;
|
||||||
|
|
||||||
|
// Find relevant character indices
|
||||||
|
for (u32 iChar = 0; iChar < pkOwnerSet->NumCharacters(); iChar++)
|
||||||
|
{
|
||||||
|
const SSetCharacter *pkChar = pkOwnerSet->Character(iChar);
|
||||||
|
|
||||||
|
if ( pkChar->UsedAnimationIndices.find(AnimIndex) != pkChar->UsedAnimationIndices.end() )
|
||||||
|
pTree->mCharacterIndices.insert(iChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add dependencies. In MP2 animation event data is not a standalone resource.
|
||||||
|
pTree->AddDependency(pkAnim->pAnim);
|
||||||
|
|
||||||
|
if (pkAnim->pEventData)
|
||||||
|
{
|
||||||
|
if (pkAnim->pEventData->Entry())
|
||||||
|
pTree->AddDependency(pkAnim->pEventData);
|
||||||
|
else
|
||||||
|
pkAnim->pEventData->AddDependenciesToTree(pTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ CAnimEventDependency ************
|
||||||
|
EDependencyNodeType CAnimEventDependency::Type() const
|
||||||
|
{
|
||||||
|
return eDNT_AnimEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimEventDependency::Serialize(IArchive& rArc)
|
||||||
|
{
|
||||||
|
CResourceDependency::Serialize(rArc);
|
||||||
|
rArc << SERIAL("CharacterIndex", mCharIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CAreaDependencyTree ************
|
// ************ CAreaDependencyTree ************
|
||||||
|
@ -9,7 +9,9 @@
|
|||||||
class CScriptLayer;
|
class CScriptLayer;
|
||||||
class CScriptObject;
|
class CScriptObject;
|
||||||
class CPropertyStruct;
|
class CPropertyStruct;
|
||||||
|
class CAnimSet;
|
||||||
struct SSetCharacter;
|
struct SSetCharacter;
|
||||||
|
struct SSetAnimation;
|
||||||
|
|
||||||
// Group of node classes forming a tree of cached resource dependencies.
|
// Group of node classes forming a tree of cached resource dependencies.
|
||||||
enum EDependencyNodeType
|
enum EDependencyNodeType
|
||||||
@ -19,8 +21,9 @@ enum EDependencyNodeType
|
|||||||
eDNT_ScriptInstance = FOURCC_CONSTEXPR('S', 'C', 'I', 'N'),
|
eDNT_ScriptInstance = FOURCC_CONSTEXPR('S', 'C', 'I', 'N'),
|
||||||
eDNT_ScriptProperty = FOURCC_CONSTEXPR('S', 'C', 'P', 'R'),
|
eDNT_ScriptProperty = FOURCC_CONSTEXPR('S', 'C', 'P', 'R'),
|
||||||
eDNT_CharacterProperty = FOURCC_CONSTEXPR('C', 'R', 'P', 'R'),
|
eDNT_CharacterProperty = FOURCC_CONSTEXPR('C', 'R', 'P', 'R'),
|
||||||
|
eDNT_SetCharacter = FOURCC_CONSTEXPR('S', 'C', 'H', 'R'),
|
||||||
|
eDNT_SetAnimation = FOURCC_CONSTEXPR('S', 'A', 'N', 'M'),
|
||||||
eDNT_AnimEvent = FOURCC_CONSTEXPR('E', 'V', 'N', 'T'),
|
eDNT_AnimEvent = FOURCC_CONSTEXPR('E', 'V', 'N', 'T'),
|
||||||
eDNT_AnimSet = FOURCC_CONSTEXPR('A', 'N', 'C', 'S'),
|
|
||||||
eDNT_Area = FOURCC_CONSTEXPR('A', 'R', 'E', 'A'),
|
eDNT_Area = FOURCC_CONSTEXPR('A', 'R', 'E', 'A'),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,9 +57,9 @@ public:
|
|||||||
virtual EDependencyNodeType Type() const;
|
virtual EDependencyNodeType Type() const;
|
||||||
virtual void Serialize(IArchive& rArc);
|
virtual void Serialize(IArchive& rArc);
|
||||||
|
|
||||||
|
void AddChild(IDependencyNode *pNode);
|
||||||
void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true);
|
void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true);
|
||||||
void AddDependency(CResource *pRes, bool AvoidDuplicates = true);
|
void AddDependency(CResource *pRes, bool AvoidDuplicates = true);
|
||||||
void AddEventDependency(const CAssetID& rkID, u32 CharIndex);
|
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline void SetID(const CAssetID& rkID) { mRootID = rkID; }
|
inline void SetID(const CAssetID& rkID) { mRootID = rkID; }
|
||||||
@ -147,7 +150,46 @@ protected:
|
|||||||
static void ParseStructDependencies(CScriptInstanceDependency *pTree, CPropertyStruct *pStruct);
|
static void ParseStructDependencies(CScriptInstanceDependency *pTree, CPropertyStruct *pStruct);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing an animation event.
|
// Node representing an animset character. Indicates what index the character is within the animset.
|
||||||
|
class CSetCharacterDependency : public CDependencyTree
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
u32 mSetIndex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CSetCharacterDependency() : CDependencyTree() {}
|
||||||
|
CSetCharacterDependency(u32 SetIndex) : CDependencyTree(), mSetIndex(SetIndex) {}
|
||||||
|
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Serialize(IArchive& rArc);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline u32 SetIndex() const { return mSetIndex; }
|
||||||
|
|
||||||
|
// Static
|
||||||
|
static CSetCharacterDependency* BuildTree(const CAnimSet *pkOwnerSet, u32 CharIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node representing a character animation. Indicates which character indices use this animation.
|
||||||
|
class CSetAnimationDependency : public CDependencyTree
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::set<u32> mCharacterIndices;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CSetAnimationDependency() : CDependencyTree() {}
|
||||||
|
|
||||||
|
virtual EDependencyNodeType Type() const;
|
||||||
|
virtual void Serialize(IArchive& rArc);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline bool IsUsedByCharacter(u32 CharIdx) const { return mCharacterIndices.find(CharIdx) != mCharacterIndices.end(); }
|
||||||
|
|
||||||
|
// Static
|
||||||
|
static CSetAnimationDependency* BuildTree(const CAnimSet *pkOwnerSet, u32 AnimIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node representing an animation event. Indicates which character index uses this event.
|
||||||
class CAnimEventDependency : public CResourceDependency
|
class CAnimEventDependency : public CResourceDependency
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -165,27 +207,6 @@ public:
|
|||||||
inline u32 CharIndex() const { return mCharIndex; }
|
inline u32 CharIndex() const { return mCharIndex; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing an animset resource; allows for lookup of dependencies of a particular character in the set.
|
|
||||||
class CAnimSetDependencyTree : public CDependencyTree
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
std::vector<u32> mCharacterOffsets;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CAnimSetDependencyTree() : CDependencyTree() {}
|
|
||||||
CAnimSetDependencyTree(const CAssetID& rkID) : CDependencyTree(rkID) {}
|
|
||||||
virtual EDependencyNodeType Type() const;
|
|
||||||
virtual void Serialize(IArchive& rArc);
|
|
||||||
|
|
||||||
void AddCharacter(const SSetCharacter *pkChar, const std::set<CAssetID>& rkBaseUsedSet);
|
|
||||||
void AddCharDependency(const CAssetID& rkID, std::set<CAssetID>& rUsedSet);
|
|
||||||
void AddCharDependency(CResource *pRes, std::set<CAssetID>& rUsedSet);
|
|
||||||
|
|
||||||
// Accessors
|
|
||||||
inline u32 NumCharacters() const { return mCharacterOffsets.size(); }
|
|
||||||
inline u32 CharacterOffset(u32 CharIdx) const { return mCharacterOffsets[CharIdx]; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Node representing an area. Tracks dependencies on a per-instance basis and can separate dependencies of different script layers.
|
// Node representing an area. Tracks dependencies on a per-instance basis and can separate dependencies of different script layers.
|
||||||
class CAreaDependencyTree : public CDependencyTree
|
class CAreaDependencyTree : public CDependencyTree
|
||||||
{
|
{
|
||||||
@ -220,8 +241,9 @@ public:
|
|||||||
case eDNT_ScriptInstance: return new CScriptInstanceDependency;
|
case eDNT_ScriptInstance: return new CScriptInstanceDependency;
|
||||||
case eDNT_ScriptProperty: return new CPropertyDependency;
|
case eDNT_ScriptProperty: return new CPropertyDependency;
|
||||||
case eDNT_CharacterProperty: return new CCharPropertyDependency;
|
case eDNT_CharacterProperty: return new CCharPropertyDependency;
|
||||||
|
case eDNT_SetCharacter: return new CSetCharacterDependency;
|
||||||
|
case eDNT_SetAnimation: return new CSetAnimationDependency;
|
||||||
case eDNT_AnimEvent: return new CAnimEventDependency;
|
case eDNT_AnimEvent: return new CAnimEventDependency;
|
||||||
case eDNT_AnimSet: return new CAnimSetDependencyTree;
|
|
||||||
case eDNT_Area: return new CAreaDependencyTree;
|
case eDNT_Area: return new CAreaDependencyTree;
|
||||||
default: ASSERT(false); return nullptr;
|
default: ASSERT(false); return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,21 @@ bool CCharacterUsageMap::IsCharacterUsed(const CAssetID& rkID, u32 CharacterInde
|
|||||||
else return rkUsageList[CharacterIndex];
|
else return rkUsageList[CharacterIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CCharacterUsageMap::IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const
|
||||||
|
{
|
||||||
|
auto Find = mUsageMap.find(rkID);
|
||||||
|
if (Find == mUsageMap.end()) return false;
|
||||||
|
const std::vector<bool>& rkUsageList = Find->second;
|
||||||
|
|
||||||
|
for (u32 iChar = 0; iChar < rkUsageList.size(); iChar++)
|
||||||
|
{
|
||||||
|
if (rkUsageList[iChar] && pAnim->IsUsedByCharacter(iChar))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry)
|
void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry)
|
||||||
{
|
{
|
||||||
ASSERT(pEntry->ResourceType() == eArea);
|
ASSERT(pEntry->ResourceType() == eArea);
|
||||||
@ -76,10 +91,10 @@ void CCharacterUsageMap::DebugPrintContents()
|
|||||||
std::vector<bool>& rUsedList = Iter->second;
|
std::vector<bool>& rUsedList = Iter->second;
|
||||||
CAnimSet *pSet = (CAnimSet*) gpResourceStore->LoadResource(ID, "ANCS");
|
CAnimSet *pSet = (CAnimSet*) gpResourceStore->LoadResource(ID, "ANCS");
|
||||||
|
|
||||||
for (u32 iChar = 0; iChar < pSet->NumNodes(); iChar++)
|
for (u32 iChar = 0; iChar < pSet->NumCharacters(); iChar++)
|
||||||
{
|
{
|
||||||
bool Used = (rUsedList.size() > iChar && rUsedList[iChar]);
|
bool Used = (rUsedList.size() > iChar && rUsedList[iChar]);
|
||||||
TString CharName = pSet->NodeName(iChar);
|
TString CharName = pSet->Character(iChar)->Name;
|
||||||
Log::Write(ID.ToString() + " : Char " + TString::FromInt32(iChar, 0, 10) + " : " + CharName + " : " + (Used ? "USED" : "UNUSED"));
|
Log::Write(ID.ToString() + " : Char " + TString::FromInt32(iChar, 0, 10) + " : " + CharName + " : " + (Used ? "USED" : "UNUSED"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,43 +245,16 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
|||||||
void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut)
|
void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut)
|
||||||
{
|
{
|
||||||
EDependencyNodeType Type = pNode->Type();
|
EDependencyNodeType Type = pNode->Type();
|
||||||
|
bool ParseChildren = false;
|
||||||
|
|
||||||
if (Type == eDNT_AnimSet)
|
// Straight resource dependencies should just be added to the tree directly
|
||||||
{
|
if (Type == eDNT_ResourceDependency || Type == eDNT_ScriptProperty || Type == eDNT_CharacterProperty)
|
||||||
// Add base dependencies, then only add dependencies from used characters
|
|
||||||
CAnimSetDependencyTree *pTree = static_cast<CAnimSetDependencyTree*>(pNode);
|
|
||||||
u32 BaseEnd = (pTree->NumCharacters() > 0 ? pTree->CharacterOffset(0) : pTree->NumChildren());
|
|
||||||
|
|
||||||
for (u32 iDep = 0; iDep < BaseEnd; iDep++)
|
|
||||||
{
|
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
|
||||||
ASSERT(pDep->Type() == eDNT_ResourceDependency);
|
|
||||||
AddDependency(pCurEntry, pDep->ID(), rOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 iChar = 0; iChar < pTree->NumCharacters(); iChar++)
|
|
||||||
{
|
|
||||||
if (mCharacterUsageMap.IsCharacterUsed(pCurEntry->ID(), iChar) || mGame > eEchoes || mIsPlayerActor)
|
|
||||||
{
|
|
||||||
u32 StartIdx = pTree->CharacterOffset(iChar);
|
|
||||||
u32 EndIdx = (iChar == pTree->NumCharacters() - 1 ? pTree->NumChildren() : pTree->CharacterOffset(iChar + 1));
|
|
||||||
|
|
||||||
for (u32 iDep = StartIdx; iDep < EndIdx; iDep++)
|
|
||||||
{
|
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
|
||||||
ASSERT(pDep->Type() == eDNT_ResourceDependency);
|
|
||||||
AddDependency(pCurEntry, pDep->ID(), rOut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (Type == eDNT_ResourceDependency || Type == eDNT_ScriptProperty || Type == eDNT_CharacterProperty)
|
|
||||||
{
|
{
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode);
|
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode);
|
||||||
AddDependency(pCurEntry, pDep->ID(), rOut);
|
AddDependency(pCurEntry, pDep->ID(), rOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Anim events should be added if either they apply to characters, or their character index is used
|
||||||
else if (Type == eDNT_AnimEvent)
|
else if (Type == eDNT_AnimEvent)
|
||||||
{
|
{
|
||||||
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode);
|
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode);
|
||||||
@ -276,7 +264,25 @@ void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurE
|
|||||||
AddDependency(pCurEntry, pDep->ID(), rOut);
|
AddDependency(pCurEntry, pDep->ID(), rOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set characters should only be added if their character index is used
|
||||||
|
else if (Type == eDNT_SetCharacter)
|
||||||
|
{
|
||||||
|
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
||||||
|
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->SetIndex()) || mIsPlayerActor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set animations should only be added if they're being used by at least one used character
|
||||||
|
else if (Type == eDNT_SetAnimation)
|
||||||
|
{
|
||||||
|
CSetAnimationDependency *pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
||||||
|
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || mIsPlayerActor; // todo - should maybe omit completely unused animations on PlayerActors?
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
ParseChildren = true;
|
||||||
|
|
||||||
|
// Analyze this node's children
|
||||||
|
if (ParseChildren)
|
||||||
{
|
{
|
||||||
if (Type == eDNT_ScriptInstance)
|
if (Type == eDNT_ScriptInstance)
|
||||||
{
|
{
|
||||||
@ -371,7 +377,8 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
|
|||||||
// If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
|
// If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
|
||||||
if (mGame <= ePrime && ResType == eAudioGroup)
|
if (mGame <= ePrime && ResType == eAudioGroup)
|
||||||
{
|
{
|
||||||
if (pAudioGroupsOut) pAudioGroupsOut->insert(rkID);
|
if (pAudioGroupsOut)
|
||||||
|
pAudioGroupsOut->insert(rkID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,86 +389,71 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
|
|||||||
if (mBaseUsedAssets.find(rkID) != mBaseUsedAssets.end() || mLayerUsedAssets.find(rkID) != mLayerUsedAssets.end())
|
if (mBaseUsedAssets.find(rkID) != mBaseUsedAssets.end() || mLayerUsedAssets.find(rkID) != mLayerUsedAssets.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Dependency is valid! Evaluate sub-dependencies
|
// Dependency is valid! Evaluate the node tree (except for SCAN and DGRP)
|
||||||
// For animsets, only add used character indices
|
if (ResType != eScan && ResType != eDependencyGroup)
|
||||||
if (ResType == eAnimSet && mGame <= eEchoes)
|
|
||||||
{
|
{
|
||||||
mCurrentAnimSetID = rkID;
|
if (ResType == eAnimSet)
|
||||||
|
|
||||||
// Add base dependencies first, then character-specific ones
|
|
||||||
CAnimSetDependencyTree *pTree = static_cast<CAnimSetDependencyTree*>(pEntry->Dependencies());
|
|
||||||
u32 BaseEndIdx = (pTree->NumCharacters() > 0 ? pTree->CharacterOffset(0) : pTree->NumChildren());
|
|
||||||
|
|
||||||
for (u32 iDep = 0; iDep < BaseEndIdx; iDep++)
|
|
||||||
{
|
{
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
ASSERT(!mCurrentAnimSetID.IsValid());
|
||||||
EDependencyNodeType Type = pDep->Type();
|
mCurrentAnimSetID = pEntry->ID();
|
||||||
ASSERT(Type == eDNT_ResourceDependency || Type == eDNT_AnimEvent);
|
|
||||||
|
|
||||||
if (Type == eDNT_ResourceDependency)
|
|
||||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CAnimEventDependency *pEvent = static_cast<CAnimEventDependency*>(pDep);
|
|
||||||
u32 CharIdx = pEvent->CharIndex();
|
|
||||||
|
|
||||||
if (CharIdx == -1 || mCharacterUsageMap.IsCharacterUsed(rkID, CharIdx))
|
|
||||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 iChar = 0; iChar < pTree->NumCharacters(); iChar++)
|
EvaluateDependencyNode(pEntry, pEntry->Dependencies(), rOut, pAudioGroupsOut);
|
||||||
|
|
||||||
|
if (ResType == eAnimSet)
|
||||||
{
|
{
|
||||||
// Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one
|
ASSERT(mCurrentAnimSetID.IsValid());
|
||||||
const u32 kEmptySuitIndex = (mGame >= eEchoesDemo ? 3 : 5);
|
|
||||||
bool IsUsed = (mIsPlayerActor ? iChar == kEmptySuitIndex : mCharacterUsageMap.IsCharacterUsed(rkID, iChar));
|
|
||||||
if (!IsUsed) continue;
|
|
||||||
|
|
||||||
u32 StartIdx = pTree->CharacterOffset(iChar);
|
|
||||||
u32 EndIdx = (iChar == pTree->NumCharacters() - 1 ? pTree->NumChildren() : pTree->CharacterOffset(iChar + 1));
|
|
||||||
|
|
||||||
for (u32 iDep = StartIdx; iDep < EndIdx; iDep++)
|
|
||||||
{
|
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
|
||||||
ASSERT(pDep->Type() == eDNT_ResourceDependency);
|
|
||||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mCurrentAnimSetID = CAssetID::InvalidID(mGame);
|
mCurrentAnimSetID = CAssetID::InvalidID(mGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For EVNT, only add events for used character indices
|
|
||||||
else if (ResType == eAnimEventData)
|
|
||||||
{
|
|
||||||
CDependencyTree *pTree = pEntry->Dependencies();
|
|
||||||
|
|
||||||
for (u32 iDep = 0; iDep < pTree->NumChildren(); iDep++)
|
|
||||||
{
|
|
||||||
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pTree->ChildByIndex(iDep));
|
|
||||||
ASSERT(pDep->Type() == eDNT_AnimEvent);
|
|
||||||
u32 CharIdx = pDep->CharIndex();
|
|
||||||
|
|
||||||
if (CharIdx == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIdx))
|
|
||||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For other resource types (except SCAN and DGRP), evaluate all sub-dependencies
|
|
||||||
else if (ResType != eScan && ResType != eDependencyGroup)
|
|
||||||
{
|
|
||||||
CDependencyTree *pTree = pEntry->Dependencies();
|
|
||||||
|
|
||||||
for (u32 iDep = 0; iDep < pTree->NumChildren(); iDep++)
|
|
||||||
{
|
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
|
||||||
ASSERT(pDep->Type() == eDNT_ResourceDependency);
|
|
||||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't add CSNGs to the output dependency list (we parse them because we need their AGSC dependencies in the output AudioGroup set)
|
// Don't add CSNGs to the output dependency list (we parse them because we need their AGSC dependencies in the output AudioGroup set)
|
||||||
if (ResType != eMidi)
|
if (ResType != eMidi)
|
||||||
rOut.push_back(rkID);
|
rOut.push_back(rkID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CAreaDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
|
||||||
|
{
|
||||||
|
EDependencyNodeType Type = pNode->Type();
|
||||||
|
bool ParseChildren = false;
|
||||||
|
|
||||||
|
if (Type == eDNT_ResourceDependency || Type == eDNT_ScriptProperty || Type == eDNT_CharacterProperty)
|
||||||
|
{
|
||||||
|
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode);
|
||||||
|
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (Type == eDNT_AnimEvent)
|
||||||
|
{
|
||||||
|
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode);
|
||||||
|
u32 CharIndex = pDep->CharIndex();
|
||||||
|
|
||||||
|
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
|
||||||
|
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (Type == eDNT_SetCharacter)
|
||||||
|
{
|
||||||
|
// Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one
|
||||||
|
const u32 kEmptySuitIndex = (mGame >= eEchoesDemo ? 3 : 5);
|
||||||
|
|
||||||
|
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
||||||
|
u32 SetIndex = pChar->SetIndex();
|
||||||
|
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->SetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (Type == eDNT_SetAnimation)
|
||||||
|
{
|
||||||
|
CSetAnimationDependency *pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
||||||
|
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
ParseChildren = true;
|
||||||
|
|
||||||
|
if (ParseChildren)
|
||||||
|
{
|
||||||
|
for (u32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
||||||
|
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut, pAudioGroupsOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ class CCharacterUsageMap
|
|||||||
public:
|
public:
|
||||||
CCharacterUsageMap() : mLayerIndex(-1), mIsInitialArea(true), mCurrentAreaAllowsDupes(false) {}
|
CCharacterUsageMap() : mLayerIndex(-1), mIsInitialArea(true), mCurrentAreaAllowsDupes(false) {}
|
||||||
bool IsCharacterUsed(const CAssetID& rkID, u32 CharacterIndex) const;
|
bool IsCharacterUsed(const CAssetID& rkID, u32 CharacterIndex) const;
|
||||||
|
bool IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const;
|
||||||
void FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry);
|
void FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry);
|
||||||
void FindUsagesForArea(CWorld *pWorld, u32 AreaIndex);
|
void FindUsagesForArea(CWorld *pWorld, u32 AreaIndex);
|
||||||
void FindUsagesForLayer(CResourceEntry *pAreaEntry, u32 LayerIndex);
|
void FindUsagesForLayer(CResourceEntry *pAreaEntry, u32 LayerIndex);
|
||||||
@ -76,6 +77,7 @@ public:
|
|||||||
|
|
||||||
void BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut, std::set<CAssetID> *pAudioGroupsOut = nullptr);
|
void BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut, std::set<CAssetID> *pAudioGroupsOut = nullptr);
|
||||||
void AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut);
|
void AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut);
|
||||||
|
void EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEPENDENCYLISTBUILDERS
|
#endif // DEPENDENCYLISTBUILDERS
|
||||||
|
@ -22,14 +22,23 @@ public:
|
|||||||
CDependencyTree* BuildDependencyTree() const
|
CDependencyTree* BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree(ID());
|
CDependencyTree *pTree = new CDependencyTree(ID());
|
||||||
|
AddDependenciesToTree(pTree);
|
||||||
|
return pTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddDependenciesToTree(CDependencyTree *pTree) const
|
||||||
|
{
|
||||||
for (u32 iEvt = 0; iEvt < mEvents.size(); iEvt++)
|
for (u32 iEvt = 0; iEvt < mEvents.size(); iEvt++)
|
||||||
{
|
{
|
||||||
const SEvent& rkEvent = mEvents[iEvt];
|
const SEvent& rkEvent = mEvents[iEvt];
|
||||||
pTree->AddEventDependency(rkEvent.mAssetRef, rkEvent.mCharacterIndex);
|
CAssetID ID = rkEvent.mAssetRef;
|
||||||
}
|
|
||||||
|
|
||||||
return pTree;
|
if (ID.IsValid() && !pTree->HasDependency(ID))
|
||||||
|
{
|
||||||
|
CAnimEventDependency *pDep = new CAnimEventDependency(ID, rkEvent.mCharacterIndex);
|
||||||
|
pTree->AddChild(pDep);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 NumEvents() const { return mEvents.size(); }
|
inline u32 NumEvents() const { return mEvents.size(); }
|
||||||
|
@ -27,6 +27,14 @@ struct SSetCharacter
|
|||||||
std::vector<CAssetID> EffectParticles;
|
std::vector<CAssetID> EffectParticles;
|
||||||
CAssetID IceModel;
|
CAssetID IceModel;
|
||||||
CAssetID IceSkin;
|
CAssetID IceSkin;
|
||||||
|
std::set<u32> UsedAnimationIndices;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SSetAnimation
|
||||||
|
{
|
||||||
|
TString Name;
|
||||||
|
TResPtr<CAnimation> pAnim;
|
||||||
|
TResPtr<CAnimEventData> pEventData;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CAnimSet : public CResource
|
class CAnimSet : public CResource
|
||||||
@ -35,73 +43,54 @@ class CAnimSet : public CResource
|
|||||||
friend class CAnimSetLoader;
|
friend class CAnimSetLoader;
|
||||||
|
|
||||||
std::vector<SSetCharacter> mCharacters;
|
std::vector<SSetCharacter> mCharacters;
|
||||||
|
std::vector<SSetAnimation> mAnimations;
|
||||||
struct SAnimation
|
|
||||||
{
|
|
||||||
TString Name;
|
|
||||||
TResPtr<CAnimation> pAnim;
|
|
||||||
};
|
|
||||||
std::vector<SAnimation> mAnims;
|
|
||||||
std::vector<CAnimEventData*> mEventDependencies;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAnimSet(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
|
CAnimSet(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
|
||||||
|
|
||||||
~CAnimSet()
|
~CAnimSet()
|
||||||
{
|
{
|
||||||
for (u32 iEvnt = 0; iEvnt < mEventDependencies.size(); iEvnt++)
|
// note: in MP2, event data isn't a standalone resource, so it's owned by the animset; therefore we need to delete it manually
|
||||||
|
if (Game() >= eEchoesDemo)
|
||||||
{
|
{
|
||||||
ASSERT(!mEventDependencies[iEvnt]->Entry());
|
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||||
delete mEventDependencies[iEvnt];
|
{
|
||||||
|
SSetAnimation& rAnim = mAnimations[iAnim];
|
||||||
|
CAnimEventData *pEvents = rAnim.pEventData;
|
||||||
|
ASSERT(pEvents && !pEvents->Entry());
|
||||||
|
rAnim.pEventData = nullptr; // make sure TResPtr destructor doesn't attempt to access
|
||||||
|
delete pEvents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 NumNodes() const { return mCharacters.size(); }
|
|
||||||
TString NodeName(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].Name; }
|
|
||||||
CModel* NodeModel(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].pModel; }
|
|
||||||
CSkin* NodeSkin(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].pSkin; }
|
|
||||||
CSkeleton* NodeSkeleton(u32 Index) { if (Index >= mCharacters.size()) Index = 0; return mCharacters[Index].pSkeleton; }
|
|
||||||
|
|
||||||
u32 NumAnims() const { return mAnims.size(); }
|
|
||||||
CAnimation* Animation(u32 Index) { if (Index >= mAnims.size()) Index = 0; return mAnims[Index].pAnim; }
|
|
||||||
TString AnimName(u32 Index) { if (Index >= mAnims.size()) Index = 0; return mAnims[Index].Name; }
|
|
||||||
|
|
||||||
CDependencyTree* BuildDependencyTree() const
|
CDependencyTree* BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
CAnimSetDependencyTree *pTree = new CAnimSetDependencyTree(ID());
|
CDependencyTree *pTree = new CDependencyTree(ID());
|
||||||
std::set<CAssetID> BaseUsedSet;
|
|
||||||
|
|
||||||
// Base dependencies
|
|
||||||
for (u32 iAnim = 0; iAnim < mAnims.size(); iAnim++)
|
|
||||||
{
|
|
||||||
CAnimation *pAnim = mAnims[iAnim].pAnim;
|
|
||||||
|
|
||||||
if (pAnim)
|
|
||||||
{
|
|
||||||
pTree->AddDependency(mAnims[iAnim].pAnim);
|
|
||||||
BaseUsedSet.insert(pAnim->ID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 iEvnt = 0; iEvnt < mEventDependencies.size(); iEvnt++)
|
|
||||||
{
|
|
||||||
CAnimEventData *pData = mEventDependencies[iEvnt];
|
|
||||||
|
|
||||||
for (u32 iEvt = 0; iEvt < pData->NumEvents(); iEvt++)
|
|
||||||
{
|
|
||||||
CAssetID ID = pData->EventAssetRef(iEvt);
|
|
||||||
u32 CharIdx = pData->EventCharacterIndex(iEvt);
|
|
||||||
pTree->AddEventDependency(ID, CharIdx);
|
|
||||||
BaseUsedSet.insert(ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Character dependencies
|
// Character dependencies
|
||||||
for (u32 iNode = 0; iNode < mCharacters.size(); iNode++)
|
for (u32 iChar = 0; iChar < mCharacters.size(); iChar++)
|
||||||
pTree->AddCharacter(&mCharacters[iNode], BaseUsedSet);
|
{
|
||||||
|
CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree(this, iChar);
|
||||||
|
ASSERT(pCharTree);
|
||||||
|
pTree->AddChild(pCharTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||||
|
{
|
||||||
|
CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
|
||||||
|
ASSERT(pAnimTree);
|
||||||
|
pTree->AddChild(pAnimTree);
|
||||||
|
}
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline u32 NumCharacters() const { return mCharacters.size(); }
|
||||||
|
inline u32 NumAnimations() const { return mAnimations.size(); }
|
||||||
|
inline const SSetCharacter* Character(u32 Index) const { ASSERT(Index >= 0 && Index < NumCharacters()); return &mCharacters[Index]; }
|
||||||
|
inline const SSetAnimation* Animation(u32 Index) const { ASSERT(Index >= 0 && Index < NumAnimations()); return &mAnimations[Index]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CCHARACTERSET_H
|
#endif // CCHARACTERSET_H
|
||||||
|
@ -145,8 +145,8 @@ CModel* CAnimationParameters::GetCurrentModel(s32 NodeIndex /*= -1*/)
|
|||||||
if (pSet->Type() != eAnimSet) return nullptr;
|
if (pSet->Type() != eAnimSet) return nullptr;
|
||||||
if (NodeIndex == -1) NodeIndex = mCharIndex;
|
if (NodeIndex == -1) NodeIndex = mCharIndex;
|
||||||
|
|
||||||
if (pSet->NumNodes() <= (u32) NodeIndex) return nullptr;
|
if (pSet->NumCharacters() <= (u32) NodeIndex) return nullptr;
|
||||||
return pSet->NodeModel(NodeIndex);
|
return pSet->Character(NodeIndex)->pModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
|
TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
|
||||||
@ -158,8 +158,8 @@ TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
|
|||||||
if (pSet->Type() != eAnimSet) return "";
|
if (pSet->Type() != eAnimSet) return "";
|
||||||
if (NodeIndex == -1) NodeIndex = mCharIndex;
|
if (NodeIndex == -1) NodeIndex = mCharIndex;
|
||||||
|
|
||||||
if (pSet->NumNodes() <= (u32) NodeIndex) return "";
|
if (pSet->NumCharacters() <= (u32) NodeIndex) return "";
|
||||||
return pSet->NodeName((u32) NodeIndex);
|
return pSet->Character(NodeIndex)->Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ ACCESSORS ************
|
// ************ ACCESSORS ************
|
||||||
|
@ -107,9 +107,7 @@ void CAnimSetLoader::LoadPrimitive(IInputStream& rANCS)
|
|||||||
u32 AnimIndex = rANCS.ReadLong();
|
u32 AnimIndex = rANCS.ReadLong();
|
||||||
TString AnimName = rANCS.ReadString();
|
TString AnimName = rANCS.ReadString();
|
||||||
rANCS.Seek(0x8, SEEK_CUR);
|
rANCS.Seek(0x8, SEEK_CUR);
|
||||||
|
ASSERT(AnimIndex < mAnimPrimitives.size());
|
||||||
if (mAnimPrimitives.size() < (AnimIndex + 1))
|
|
||||||
mAnimPrimitives.resize(AnimIndex + 1);
|
|
||||||
|
|
||||||
if (!mAnimPrimitives[AnimIndex].Loaded)
|
if (!mAnimPrimitives[AnimIndex].Loaded)
|
||||||
{
|
{
|
||||||
@ -319,8 +317,13 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
|||||||
pChar->IceModel = CAssetID(rANCS, e32Bit);
|
pChar->IceModel = CAssetID(rANCS, e32Bit);
|
||||||
pChar->IceSkin = CAssetID(rANCS, e32Bit);
|
pChar->IceSkin = CAssetID(rANCS, e32Bit);
|
||||||
|
|
||||||
u32 UnknownCount = rANCS.ReadLong();
|
u32 AnimIndexCount = rANCS.ReadLong();
|
||||||
rANCS.Seek(UnknownCount * 4, SEEK_CUR);
|
|
||||||
|
for (u32 iAnim = 0; iAnim < AnimIndexCount; iAnim++)
|
||||||
|
{
|
||||||
|
u32 AnimIndex = rANCS.ReadLong();
|
||||||
|
pChar->UsedAnimationIndices.insert(AnimIndex);
|
||||||
|
}
|
||||||
|
|
||||||
if (Loader.mVersion == eEchoes)
|
if (Loader.mVersion == eEchoes)
|
||||||
{
|
{
|
||||||
@ -335,6 +338,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
|||||||
SetStart = SetStart;
|
SetStart = SetStart;
|
||||||
u16 InfoCount = rANCS.ReadShort();
|
u16 InfoCount = rANCS.ReadShort();
|
||||||
u32 NumAnims = rANCS.ReadLong();
|
u32 NumAnims = rANCS.ReadLong();
|
||||||
|
Loader.mAnimPrimitives.resize(NumAnims);
|
||||||
|
|
||||||
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||||
Loader.LoadAnimation(rANCS);
|
Loader.LoadAnimation(rANCS);
|
||||||
@ -361,16 +365,18 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add anims to set
|
// Add anims to set
|
||||||
|
Loader.pSet->mAnimations.resize(Loader.mAnimPrimitives.size());
|
||||||
|
|
||||||
for (u32 iPrim = 0; iPrim < Loader.mAnimPrimitives.size(); iPrim++)
|
for (u32 iPrim = 0; iPrim < Loader.mAnimPrimitives.size(); iPrim++)
|
||||||
{
|
{
|
||||||
SPrimitive& rPrim = Loader.mAnimPrimitives[iPrim];
|
SPrimitive& rPrim = Loader.mAnimPrimitives[iPrim];
|
||||||
|
|
||||||
if (rPrim.Loaded)
|
if (rPrim.Loaded)
|
||||||
{
|
{
|
||||||
CAnimSet::SAnimation Anim;
|
SSetAnimation Anim;
|
||||||
Anim.Name = rPrim.Name;
|
Anim.Name = rPrim.Name;
|
||||||
Anim.pAnim = gpResourceStore->LoadResource(rPrim.AnimID, "ANIM");
|
Anim.pAnim = gpResourceStore->LoadResource(rPrim.AnimID, "ANIM");
|
||||||
Loader.pSet->mAnims.push_back(Anim);
|
Loader.pSet->mAnimations[iPrim] = Anim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,12 +384,10 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
|||||||
if (Loader.pSet->Game() >= eEchoesDemo)
|
if (Loader.pSet->Game() >= eEchoesDemo)
|
||||||
{
|
{
|
||||||
u32 EventDataCount = rANCS.ReadLong();
|
u32 EventDataCount = rANCS.ReadLong();
|
||||||
|
ASSERT(EventDataCount == NumAnims);
|
||||||
|
|
||||||
for (u32 iEvnt = 0; iEvnt < EventDataCount; iEvnt++)
|
for (u32 iEvnt = 0; iEvnt < EventDataCount; iEvnt++)
|
||||||
{
|
Loader.pSet->mAnimations[iEvnt].pEventData = CAnimEventLoader::LoadAnimSetEvents(rANCS);
|
||||||
CAnimEventData *pData = CAnimEventLoader::LoadAnimSetEvents(rANCS);
|
|
||||||
Loader.pSet->mEventDependencies.push_back(pData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Loader.pSet;
|
return Loader.pSet;
|
||||||
|
@ -19,8 +19,8 @@ void CCharacterNode::PostLoad()
|
|||||||
{
|
{
|
||||||
if (mpCharacter)
|
if (mpCharacter)
|
||||||
{
|
{
|
||||||
for (u32 iChar = 0; iChar < mpCharacter->NumNodes(); iChar++)
|
for (u32 iChar = 0; iChar < mpCharacter->NumCharacters(); iChar++)
|
||||||
mpCharacter->NodeModel(iChar)->BufferGL();
|
mpCharacter->Character(iChar)->pModel->BufferGL();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +31,8 @@ void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkView
|
|||||||
if (!mpCharacter) return;
|
if (!mpCharacter) return;
|
||||||
UpdateTransformData();
|
UpdateTransformData();
|
||||||
|
|
||||||
CModel *pModel = mpCharacter->NodeModel(mActiveCharSet);
|
CModel *pModel = mpCharacter->Character(mActiveCharSet)->pModel;
|
||||||
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
|
CSkeleton *pSkel = mpCharacter->Character(mActiveCharSet)->pSkeleton;
|
||||||
|
|
||||||
if (pModel && rkViewInfo.ShowFlags.HasFlag(eShowObjectGeometry))
|
if (pModel && rkViewInfo.ShowFlags.HasFlag(eShowObjectGeometry))
|
||||||
AddModelToRenderer(pRenderer, pModel, 0);
|
AddModelToRenderer(pRenderer, pModel, 0);
|
||||||
@ -46,7 +46,7 @@ void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkView
|
|||||||
|
|
||||||
void CCharacterNode::Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo)
|
void CCharacterNode::Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo)
|
||||||
{
|
{
|
||||||
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
|
CSkeleton *pSkel = mpCharacter->Character(mActiveCharSet)->pSkeleton;
|
||||||
|
|
||||||
// Draw skeleton
|
// Draw skeleton
|
||||||
if (ComponentIndex == 0)
|
if (ComponentIndex == 0)
|
||||||
@ -73,7 +73,7 @@ void CCharacterNode::Draw(FRenderOptions Options, int ComponentIndex, ERenderCom
|
|||||||
else
|
else
|
||||||
CGraphics::LoadIdentityBoneTransforms();
|
CGraphics::LoadIdentityBoneTransforms();
|
||||||
|
|
||||||
CModel *pModel = mpCharacter->NodeModel(mActiveCharSet);
|
CModel *pModel = mpCharacter->Character(mActiveCharSet)->pModel;
|
||||||
DrawModelParts(pModel, Options, 0, Command);
|
DrawModelParts(pModel, Options, 0, Command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ SRayIntersection CCharacterNode::RayNodeIntersectTest(const CRay& rkRay, u32 /*A
|
|||||||
// Check for bone under ray. Doesn't check for model intersections atm
|
// Check for bone under ray. Doesn't check for model intersections atm
|
||||||
if (mpCharacter && rkViewInfo.ShowFlags.HasFlag(eShowSkeletons))
|
if (mpCharacter && rkViewInfo.ShowFlags.HasFlag(eShowSkeletons))
|
||||||
{
|
{
|
||||||
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
|
CSkeleton *pSkel = mpCharacter->Character(mActiveCharSet)->pSkeleton;
|
||||||
|
|
||||||
if (pSkel)
|
if (pSkel)
|
||||||
{
|
{
|
||||||
@ -109,7 +109,7 @@ SRayIntersection CCharacterNode::RayNodeIntersectTest(const CRay& rkRay, u32 /*A
|
|||||||
CVector3f CCharacterNode::BonePosition(u32 BoneID)
|
CVector3f CCharacterNode::BonePosition(u32 BoneID)
|
||||||
{
|
{
|
||||||
UpdateTransformData();
|
UpdateTransformData();
|
||||||
CSkeleton *pSkel = (mpCharacter ? mpCharacter->NodeSkeleton(mActiveCharSet) : nullptr);
|
CSkeleton *pSkel = (mpCharacter ? mpCharacter->Character(mActiveCharSet)->pSkeleton : nullptr);
|
||||||
CBone *pBone = (pSkel ? pSkel->BoneByID(BoneID) : nullptr);
|
CBone *pBone = (pSkel ? pSkel->BoneByID(BoneID) : nullptr);
|
||||||
|
|
||||||
CVector3f Out = AbsolutePosition();
|
CVector3f Out = AbsolutePosition();
|
||||||
@ -121,6 +121,7 @@ void CCharacterNode::SetCharSet(CAnimSet *pChar)
|
|||||||
{
|
{
|
||||||
mpCharacter = pChar;
|
mpCharacter = pChar;
|
||||||
SetActiveChar(0);
|
SetActiveChar(0);
|
||||||
|
SetActiveAnim(0);
|
||||||
ConditionalSetDirty();
|
ConditionalSetDirty();
|
||||||
|
|
||||||
if (!mpCharacter)
|
if (!mpCharacter)
|
||||||
@ -134,8 +135,8 @@ void CCharacterNode::SetActiveChar(u32 CharIndex)
|
|||||||
|
|
||||||
if (mpCharacter)
|
if (mpCharacter)
|
||||||
{
|
{
|
||||||
CModel *pModel = mpCharacter->NodeModel(CharIndex);
|
CModel *pModel = mpCharacter->Character(CharIndex)->pModel;
|
||||||
mTransformData.ResizeToSkeleton(mpCharacter->NodeSkeleton(CharIndex));
|
mTransformData.ResizeToSkeleton(mpCharacter->Character(CharIndex)->pSkeleton);
|
||||||
mLocalAABox = pModel ? pModel->AABox() : CAABox::skZero;
|
mLocalAABox = pModel ? pModel->AABox() : CAABox::skZero;
|
||||||
MarkTransformChanged();
|
MarkTransformChanged();
|
||||||
}
|
}
|
||||||
@ -152,7 +153,7 @@ void CCharacterNode::UpdateTransformData()
|
|||||||
{
|
{
|
||||||
if (mTransformDataDirty)
|
if (mTransformDataDirty)
|
||||||
{
|
{
|
||||||
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
|
CSkeleton *pSkel = mpCharacter->Character(mActiveCharSet)->pSkeleton;
|
||||||
if (pSkel) pSkel->UpdateTransform(mTransformData, CurrentAnim(), mAnimTime, false);
|
if (pSkel) pSkel->UpdateTransform(mTransformData, CurrentAnim(), mAnimTime, false);
|
||||||
mTransformDataDirty = false;
|
mTransformDataDirty = false;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
inline CAnimSet* Character() const { return mpCharacter; }
|
inline CAnimSet* Character() const { return mpCharacter; }
|
||||||
inline u32 ActiveCharIndex() const { return mActiveCharSet; }
|
inline u32 ActiveCharIndex() const { return mActiveCharSet; }
|
||||||
inline u32 ActiveAnimIndex() const { return mActiveAnim; }
|
inline u32 ActiveAnimIndex() const { return mActiveAnim; }
|
||||||
inline CAnimation* CurrentAnim() const { return (mAnimated && mpCharacter ? mpCharacter->Animation(mActiveAnim) : nullptr); }
|
inline CAnimation* CurrentAnim() const { return (mAnimated && mpCharacter ? mpCharacter->Animation(mActiveAnim)->pAnim : nullptr); }
|
||||||
inline bool IsAnimated() const { return (mAnimated && CurrentAnim() != nullptr); }
|
inline bool IsAnimated() const { return (mAnimated && CurrentAnim() != nullptr); }
|
||||||
|
|
||||||
void SetAnimated(bool Animated) { mAnimated = Animated; SetDirty(); }
|
void SetAnimated(bool Animated) { mAnimated = Animated; SetDirty(); }
|
||||||
|
@ -655,7 +655,7 @@ CModel* CScriptNode::ActiveModel() const
|
|||||||
if (mpDisplayAsset->Type() == eModel)
|
if (mpDisplayAsset->Type() == eModel)
|
||||||
return static_cast<CModel*>(mpDisplayAsset.RawPointer());
|
return static_cast<CModel*>(mpDisplayAsset.RawPointer());
|
||||||
else if (mpDisplayAsset->Type() == eAnimSet)
|
else if (mpDisplayAsset->Type() == eAnimSet)
|
||||||
return static_cast<CAnimSet*>(mpDisplayAsset.RawPointer())->NodeModel(mCharIndex);
|
return static_cast<CAnimSet*>(mpDisplayAsset.RawPointer())->Character(mCharIndex)->pModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -672,14 +672,14 @@ CAnimSet* CScriptNode::ActiveAnimSet() const
|
|||||||
CSkeleton* CScriptNode::ActiveSkeleton() const
|
CSkeleton* CScriptNode::ActiveSkeleton() const
|
||||||
{
|
{
|
||||||
CAnimSet *pSet = ActiveAnimSet();
|
CAnimSet *pSet = ActiveAnimSet();
|
||||||
if (pSet) return pSet->NodeSkeleton(mCharIndex);
|
if (pSet) return pSet->Character(mCharIndex)->pSkeleton;
|
||||||
else return nullptr;
|
else return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAnimation* CScriptNode::ActiveAnimation() const
|
CAnimation* CScriptNode::ActiveAnimation() const
|
||||||
{
|
{
|
||||||
CAnimSet *pSet = ActiveAnimSet();
|
CAnimSet *pSet = ActiveAnimSet();
|
||||||
if (pSet) return pSet->Animation(mAnimIndex);
|
if (pSet) return pSet->Animation(mAnimIndex)->pAnim;
|
||||||
else return nullptr;
|
else return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ void CCharacterEditor::UpdateCameraOrbit()
|
|||||||
CSkeleton* CCharacterEditor::CurrentSkeleton() const
|
CSkeleton* CCharacterEditor::CurrentSkeleton() const
|
||||||
{
|
{
|
||||||
if (mpSet)
|
if (mpSet)
|
||||||
return mpSet->NodeSkeleton(mCurrentChar);
|
return mpSet->Character(mCurrentChar)->pSkeleton;
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ CSkeleton* CCharacterEditor::CurrentSkeleton() const
|
|||||||
CAnimation* CCharacterEditor::CurrentAnimation() const
|
CAnimation* CCharacterEditor::CurrentAnimation() const
|
||||||
{
|
{
|
||||||
if (mpSet)
|
if (mpSet)
|
||||||
return mpSet->Animation(mCurrentAnim);
|
return mpSet->Animation(mCurrentAnim)->pAnim;
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -188,8 +188,8 @@ void CCharacterEditor::SetActiveAnimSet(CAnimSet *pSet)
|
|||||||
mpCharComboBox->blockSignals(true);
|
mpCharComboBox->blockSignals(true);
|
||||||
mpCharComboBox->clear();
|
mpCharComboBox->clear();
|
||||||
|
|
||||||
for (u32 iChar = 0; iChar < mpSet->NumNodes(); iChar++)
|
for (u32 iChar = 0; iChar < mpSet->NumCharacters(); iChar++)
|
||||||
mpCharComboBox->addItem( TO_QSTRING(mpSet->NodeName(iChar)) );
|
mpCharComboBox->addItem( TO_QSTRING(mpSet->Character(iChar)->Name) );
|
||||||
|
|
||||||
SetActiveCharacterIndex(0);
|
SetActiveCharacterIndex(0);
|
||||||
mpCharComboBox->blockSignals(false);
|
mpCharComboBox->blockSignals(false);
|
||||||
@ -198,14 +198,14 @@ void CCharacterEditor::SetActiveAnimSet(CAnimSet *pSet)
|
|||||||
mpAnimComboBox->blockSignals(true);
|
mpAnimComboBox->blockSignals(true);
|
||||||
mpAnimComboBox->clear();
|
mpAnimComboBox->clear();
|
||||||
|
|
||||||
for (u32 iAnim = 0; iAnim < mpSet->NumAnims(); iAnim++)
|
for (u32 iAnim = 0; iAnim < mpSet->NumAnimations(); iAnim++)
|
||||||
mpAnimComboBox->addItem( TO_QSTRING(mpSet->AnimName(iAnim)) );
|
mpAnimComboBox->addItem( TO_QSTRING(mpSet->Animation(iAnim)->Name) );
|
||||||
|
|
||||||
SetActiveAnimation(0);
|
SetActiveAnimation(0);
|
||||||
mpAnimComboBox->blockSignals(false);
|
mpAnimComboBox->blockSignals(false);
|
||||||
|
|
||||||
// Set up skeleton tree view
|
// Set up skeleton tree view
|
||||||
CSkeleton *pSkel = mpSet->NodeSkeleton(mCurrentChar);
|
CSkeleton *pSkel = mpSet->Character(mCurrentChar)->pSkeleton;
|
||||||
mSkeletonModel.SetSkeleton(pSkel);
|
mSkeletonModel.SetSkeleton(pSkel);
|
||||||
ui->SkeletonHierarchyTreeView->expandAll();
|
ui->SkeletonHierarchyTreeView->expandAll();
|
||||||
ui->SkeletonHierarchyTreeView->resizeColumnToContents(0);
|
ui->SkeletonHierarchyTreeView->resizeColumnToContents(0);
|
||||||
@ -304,13 +304,13 @@ void CCharacterEditor::OnViewportHoverBoneChanged(u32 BoneID)
|
|||||||
if (BoneID == 0xFFFFFFFF)
|
if (BoneID == 0xFFFFFFFF)
|
||||||
ui->StatusBar->clearMessage();
|
ui->StatusBar->clearMessage();
|
||||||
else
|
else
|
||||||
ui->StatusBar->showMessage(QString("Bone %1: %2").arg(BoneID).arg( TO_QSTRING(mpSet->NodeSkeleton(mCurrentChar)->BoneByID(BoneID)->Name()) ));
|
ui->StatusBar->showMessage(QString("Bone %1: %2").arg(BoneID).arg( TO_QSTRING(mpSet->Character(mCurrentChar)->pSkeleton->BoneByID(BoneID)->Name()) ));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCharacterEditor::OnViewportClick()
|
void CCharacterEditor::OnViewportClick()
|
||||||
{
|
{
|
||||||
u32 HoverBoneID = ui->Viewport->HoverBoneID();
|
u32 HoverBoneID = ui->Viewport->HoverBoneID();
|
||||||
CSkeleton *pSkel = (mpSet ? mpSet->NodeSkeleton(mCurrentChar) : nullptr);
|
CSkeleton *pSkel = (mpSet ? mpSet->Character(mCurrentChar)->pSkeleton : nullptr);
|
||||||
CBone *pBone = (pSkel ? pSkel->BoneByID(HoverBoneID) : nullptr);
|
CBone *pBone = (pSkel ? pSkel->BoneByID(HoverBoneID) : nullptr);
|
||||||
|
|
||||||
if (!pBone || !pBone->IsSelected())
|
if (!pBone || !pBone->IsSelected())
|
||||||
@ -362,7 +362,7 @@ void CCharacterEditor::PrevAnim()
|
|||||||
|
|
||||||
void CCharacterEditor::NextAnim()
|
void CCharacterEditor::NextAnim()
|
||||||
{
|
{
|
||||||
u32 MaxAnim = (mpSet ? mpSet->NumAnims() - 1 : 0);
|
u32 MaxAnim = (mpSet ? mpSet->NumAnimations() - 1 : 0);
|
||||||
if (mCurrentAnim < MaxAnim) SetActiveAnimation(mCurrentAnim + 1);
|
if (mCurrentAnim < MaxAnim) SetActiveAnimation(mCurrentAnim + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ void CCharacterEditor::SetAnimTime(float Time)
|
|||||||
|
|
||||||
mpCharNode->SetAnimTime(Time);
|
mpCharNode->SetAnimTime(Time);
|
||||||
|
|
||||||
CAnimation *pAnim = (mpSet ? mpSet->Animation(mCurrentAnim) : nullptr);
|
CAnimation *pAnim = (mpSet ? mpSet->Animation(mCurrentAnim)->pAnim : nullptr);
|
||||||
u32 NumKeys = 1, CurKey = 0;
|
u32 NumKeys = 1, CurKey = 0;
|
||||||
|
|
||||||
if (pAnim)
|
if (pAnim)
|
||||||
|
@ -617,8 +617,8 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
|
|||||||
|
|
||||||
if (pAnimSet)
|
if (pAnimSet)
|
||||||
{
|
{
|
||||||
for (u32 iChr = 0; iChr < pAnimSet->NumNodes(); iChr++)
|
for (u32 iChr = 0; iChr < pAnimSet->NumCharacters(); iChr++)
|
||||||
pComboBox->addItem(TO_QSTRING(pAnimSet->NodeName(iChr)));
|
pComboBox->addItem(TO_QSTRING(pAnimSet->Character(iChr)->Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
|
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user