From 21d8b9dcd351f18652d4d495a827e41a8dd58d52 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 23 Sep 2015 14:59:36 -1000 Subject: [PATCH] Preparing for CHAR/ANIM implementation --- DataSpec/DNACommon/ANCS.hpp | 2 +- DataSpec/DNACommon/PAK.hpp | 46 +++++ DataSpec/DNAMP1/DNAMP1.hpp | 5 +- DataSpec/DNAMP1/DeafBabe.hpp | 2 +- DataSpec/DNAMP2/DNAMP2.hpp | 5 +- DataSpec/DNAMP3/ANIM.cpp | 0 DataSpec/DNAMP3/ANIM.hpp | 207 +++++++++++++++++++ DataSpec/DNAMP3/CHAR.cpp | 0 DataSpec/DNAMP3/CHAR.hpp | 363 +++++++++++++++++++++++++++++++++ DataSpec/DNAMP3/CINF.hpp | 6 +- DataSpec/DNAMP3/CMakeLists.txt | 4 + DataSpec/DNAMP3/DNAMP3.cpp | 5 + 12 files changed, 636 insertions(+), 9 deletions(-) create mode 100644 DataSpec/DNAMP3/ANIM.cpp create mode 100644 DataSpec/DNAMP3/ANIM.hpp create mode 100644 DataSpec/DNAMP3/CHAR.cpp create mode 100644 DataSpec/DNAMP3/CHAR.hpp diff --git a/DataSpec/DNACommon/ANCS.hpp b/DataSpec/DNACommon/ANCS.hpp index 01b580ef7..e8abe8d96 100644 --- a/DataSpec/DNACommon/ANCS.hpp +++ b/DataSpec/DNACommon/ANCS.hpp @@ -107,7 +107,7 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn, cinfsDone.insert(info.cinf); } else - os.format("arm_obj = bpy.data.objects['CINF_%08X']\n", info.cinf.toUint32()); + os.format("arm_obj = bpy.data.objects['CINF_%s']\n", info.cinf.toString().c_str()); os << "actor_subtype.linked_armature = arm_obj.name\n"; /* Link CMDL */ diff --git a/DataSpec/DNACommon/PAK.hpp b/DataSpec/DNACommon/PAK.hpp index fc32eda51..943f1eaf0 100644 --- a/DataSpec/DNACommon/PAK.hpp +++ b/DataSpec/DNACommon/PAK.hpp @@ -486,6 +486,52 @@ public: return nullptr; return &search->second; } + + HECL::ProjectPath getAreaLayerWorking(const IDType& areaId, int layerIdx) const + { + if (!m_bridges) + LogDNACommon.report(LogVisor::FatalError, + "PAKRouter::build() must be called before PAKRouter::getAreaLayerWorking()"); + auto bridgePathIt = m_bridgePaths.cbegin(); + for (const BRIDGETYPE& bridge : *m_bridges) + { + for (const auto& level : bridge.m_levelDeps) + for (const auto& area : level.second.areas) + if (area.first == areaId) + { + HECL::ProjectPath levelPath(bridgePathIt->first, level.second.name); + HECL::ProjectPath areaPath(levelPath, area.second.name); + if (layerIdx < 0) + return areaPath; + return HECL::ProjectPath(areaPath, area.second.layers.at(layerIdx).name); + } + ++bridgePathIt; + } + return HECL::ProjectPath(); + } + + HECL::ProjectPath getAreaLayerCooked(const IDType& areaId, int layerIdx) const + { + if (!m_bridges) + LogDNACommon.report(LogVisor::FatalError, + "PAKRouter::build() must be called before PAKRouter::getAreaLayerCooked()"); + auto bridgePathIt = m_bridgePaths.cbegin(); + for (const BRIDGETYPE& bridge : *m_bridges) + { + for (const auto& level : bridge.m_levelDeps) + for (const auto& area : level.second.areas) + if (area.first == areaId) + { + HECL::ProjectPath levelPath(bridgePathIt->second, level.second.name); + HECL::ProjectPath areaPath(levelPath, area.second.name); + if (layerIdx < 0) + return areaPath; + return HECL::ProjectPath(areaPath, area.second.layers.at(layerIdx).name); + } + ++bridgePathIt; + } + return HECL::ProjectPath(); + } }; } diff --git a/DataSpec/DNAMP1/DNAMP1.hpp b/DataSpec/DNAMP1/DNAMP1.hpp index 89327cbda..b87f78f7c 100644 --- a/DataSpec/DNAMP1/DNAMP1.hpp +++ b/DataSpec/DNAMP1/DNAMP1.hpp @@ -17,6 +17,8 @@ class PAKBridge HECL::Database::Project& m_project; const NOD::DiscBase::IPartition::Node& m_node; PAK m_pak; + UniqueResult uniqueCheck(const PAK::Entry& entry); +public: struct Level { HECL::SystemString name; @@ -35,8 +37,7 @@ class PAKBridge }; std::unordered_map m_levelDeps; HECL::SystemString m_levelString; - UniqueResult uniqueCheck(const PAK::Entry& entry); -public: + PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node); void build(); static ResExtractor LookupExtractor(const PAK::Entry& entry); diff --git a/DataSpec/DNAMP1/DeafBabe.hpp b/DataSpec/DNAMP1/DeafBabe.hpp index 95f0334f4..7e9b58ee6 100644 --- a/DataSpec/DNAMP1/DeafBabe.hpp +++ b/DataSpec/DNAMP1/DeafBabe.hpp @@ -47,7 +47,7 @@ void DeafBabeSendToBlender(HECL::BlenderConnection::PyOutStream& os, const DEAFB "face.material_index = select_material(0x%08X)\n" "face.smooth = False\n" "\n", - triMat.material); + atUint32(triMat.material)); } db.insertNoClimb(os); diff --git a/DataSpec/DNAMP2/DNAMP2.hpp b/DataSpec/DNAMP2/DNAMP2.hpp index 551b726a2..8b7cab86c 100644 --- a/DataSpec/DNAMP2/DNAMP2.hpp +++ b/DataSpec/DNAMP2/DNAMP2.hpp @@ -17,6 +17,8 @@ class PAKBridge HECL::Database::Project& m_project; const NOD::DiscBase::IPartition::Node& m_node; DNAMP1::PAK m_pak; + UniqueResult uniqueCheck(const DNAMP1::PAK::Entry& entry); +public: struct Level { HECL::SystemString name; @@ -35,8 +37,7 @@ class PAKBridge }; std::unordered_map m_levelDeps; HECL::SystemString m_levelString; - UniqueResult uniqueCheck(const DNAMP1::PAK::Entry& entry); -public: + PAKBridge(HECL::Database::Project& project, const NOD::DiscBase::IPartition::Node& node); void build(); static ResExtractor LookupExtractor(const DNAMP1::PAK::Entry& entry); diff --git a/DataSpec/DNAMP3/ANIM.cpp b/DataSpec/DNAMP3/ANIM.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/DataSpec/DNAMP3/ANIM.hpp b/DataSpec/DNAMP3/ANIM.hpp new file mode 100644 index 000000000..9f15eb385 --- /dev/null +++ b/DataSpec/DNAMP3/ANIM.hpp @@ -0,0 +1,207 @@ +#ifndef _DNAMP3_ANIM_HPP_ +#define _DNAMP3_ANIM_HPP_ + +#include "BlenderConnection.hpp" +#include "DNAMP3.hpp" +#include "../DNACommon/ANIM.hpp" +#include "CINF.hpp" + +namespace Retro +{ +namespace DNAMP3 +{ + +struct ANIM : BigDNA +{ + Delete expl; + + struct IANIM : BigDNA + { + Delete expl; + atUint32 m_version; + IANIM(atUint32 version) : m_version(version) {} + + std::vector>> bones; + std::vector frames; + std::vector channels; + std::vector> chanKeys; + float mainInterval = 0.0; + + void sendANIMToBlender(HECL::BlenderConnection::PyOutStream&, const CINF&) const; + }; + + struct ANIM0 : IANIM + { + DECL_EXPLICIT_DNA + ANIM0() : IANIM(0) {} + + struct Header : BigDNA + { + DECL_DNA + Value duration; + Value unk0; + Value interval; + Value unk1; + Value keyCount; + Value unk2; + Value boneSlotCount; + }; + }; + + struct ANIM2 : IANIM + { + DECL_EXPLICIT_DNA + ANIM2() : IANIM(2) {} + + struct Header : BigDNA + { + DECL_DNA + Value scratchSize; + Value unk1; + Value unk2; + Value duration; + Value interval; + Value unk3; + Value unk4; + Value rotDiv; + Value translationMult; + Value unk5; + Value boneChannelCount; + Value unk6; + Value keyBitmapBitCount; + }; + + struct ChannelDesc : BigDNA + { + Delete expl; + Value id = 0; + Value keyCount1 = 0; + Value initRX = 0; + Value qRX = 0; + Value initRY = 0; + Value qRY = 0; + Value initRZ = 0; + Value qRZ = 0; + Value keyCount2 = 0; + Value initTX = 0; + Value qTX = 0; + Value initTY = 0; + Value qTY = 0; + Value initTZ = 0; + Value qTZ = 0; + Value keyCount3 = 0; + Value initSX = 0; + Value qSX = 0; + Value initSY = 0; + Value qSY = 0; + Value initSZ = 0; + Value qSZ = 0; + + void read(Athena::io::IStreamReader& reader) + { + id = reader.readUByte(); + keyCount1 = reader.readUint16Big(); + if (keyCount1) + { + initRX = reader.readUint16Big(); + qRX = reader.readUByte(); + initRY = reader.readUint16Big(); + qRY = reader.readUByte(); + initRZ = reader.readUint16Big(); + qRZ = reader.readUByte(); + } + keyCount2 = reader.readUint16Big(); + if (keyCount2) + { + initTX = reader.readUint16Big(); + qTX = reader.readUByte(); + initTY = reader.readUint16Big(); + qTY = reader.readUByte(); + initTZ = reader.readUint16Big(); + qTZ = reader.readUByte(); + } + keyCount3 = reader.readUint16Big(); + if (keyCount3) + { + initSX = reader.readUint16Big(); + qSX = reader.readUByte(); + initSY = reader.readUint16Big(); + qSY = reader.readUByte(); + initSZ = reader.readUint16Big(); + qSZ = reader.readUByte(); + } + } + void write(Athena::io::IStreamWriter& writer) const + { + writer.writeUByte(id); + writer.writeUint16Big(keyCount1); + if (keyCount1) + { + writer.writeUint16Big(initRX); + writer.writeUByte(qRX); + writer.writeUint16Big(initRY); + writer.writeUByte(qRY); + writer.writeUint16Big(initRZ); + writer.writeUByte(qRZ); + } + writer.writeUint16Big(keyCount2); + if (keyCount2) + { + writer.writeUint16Big(initTX); + writer.writeUByte(qTX); + writer.writeUint16Big(initTY); + writer.writeUByte(qTY); + writer.writeUint16Big(initTZ); + writer.writeUByte(qTZ); + } + writer.writeUint16Big(keyCount3); + if (keyCount3) + { + writer.writeUint16Big(initSX); + writer.writeUByte(qSX); + writer.writeUint16Big(initSY); + writer.writeUByte(qSY); + writer.writeUint16Big(initSZ); + writer.writeUByte(qSZ); + } + } + }; + }; + + std::unique_ptr m_anim; + void read(Athena::io::IStreamReader& reader) + { + atUint32 version = reader.readUint32Big(); + switch (version) + { + case 0: + m_anim.reset(new struct ANIM0); + m_anim->read(reader); + break; + case 2: + m_anim.reset(new struct ANIM2); + m_anim->read(reader); + break; + default: + Log.report(LogVisor::FatalError, "unrecognized ANIM version"); + break; + } + } + + void write(Athena::io::IStreamWriter& writer) const + { + writer.writeUint32Big(m_anim->m_version); + m_anim->write(writer); + } + + void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const + { + m_anim->sendANIMToBlender(os, cinf); + } + +}; + +} +} + +#endif // _DNAMP3_ANIM_HPP_ diff --git a/DataSpec/DNAMP3/CHAR.cpp b/DataSpec/DNAMP3/CHAR.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/DataSpec/DNAMP3/CHAR.hpp b/DataSpec/DNAMP3/CHAR.hpp new file mode 100644 index 000000000..0e0eafa90 --- /dev/null +++ b/DataSpec/DNAMP3/CHAR.hpp @@ -0,0 +1,363 @@ +#ifndef _DNAMP3_CHAR_HPP_ +#define _DNAMP3_CHAR_HPP_ + +#include +#include "../DNACommon/DNACommon.hpp" +#include "../DNACommon/ANCS.hpp" +#include "CMDLMaterials.hpp" +#include "BlenderConnection.hpp" +#include "CINF.hpp" +#include "CSKR.hpp" +#include "ANIM.hpp" +#include "../DNAMP2/ANCS.hpp" + +namespace Retro +{ +namespace DNAMP3 +{ + +struct CHAR : BigYAML +{ + using CINFType = CINF; + using CSKRType = CSKR; + using ANIMType = ANIM; + + DECL_YAML + Delete expl; + atUint16 version; + + std::string name; + UniqueID64 cmdl; + UniqueID64 cskr; + atUint32 unk1; + atUint32 unk2; + UniqueID64 cmdl2; + UniqueID64 cskr2; + UniqueID64 cinf; + UniqueID64 sand; + + using MP1CharacterInfo = DNAMP1::ANCS::CharacterSet::CharacterInfo; + MP1CharacterInfo::PASDatabase pasDatabase; + + struct ParticleResData + { + std::vector part; + std::vector swhc; + std::vector unk; + std::vector elsc; + std::vector spsc; + std::vector unk2; + } partResData; + + struct AnimationSet : BigYAML + { + DECL_YAML + Delete expl; + + struct IMetaAnim : BigYAML + { + Delete expl; + enum Type + { + MAPrimitive = 0, + MABlend = 1, + MAPhaseBlend = 2, + MARandom = 3, + MASequence = 4 + } m_type; + const char* m_typeStr; + IMetaAnim(Type type, const char* typeStr) + : m_type(type), m_typeStr(typeStr) {} + virtual void gatherPrimitives(std::map>& out)=0; + }; + struct MetaAnimFactory : BigYAML + { + DECL_YAML + Delete expl; + std::unique_ptr m_anim; + }; + struct MetaAnimPrimitive : IMetaAnim + { + MetaAnimPrimitive() : IMetaAnim(MAPrimitive, "Primitive") {} + DECL_YAML + UniqueID64 animId; + Value animIdx; + String<-1> animName; + Value unk1; + Value unk2; + + void gatherPrimitives(std::map>& out) + { + out[animIdx] = std::make_pair(animName, animId); + } + }; + struct MetaAnimBlend : IMetaAnim + { + MetaAnimBlend() : IMetaAnim(MABlend, "Blend") {} + DECL_YAML + MetaAnimFactory animA; + MetaAnimFactory animB; + Value unkFloat; + Value unk; + + void gatherPrimitives(std::map>& out) + { + animA.m_anim->gatherPrimitives(out); + animB.m_anim->gatherPrimitives(out); + } + }; + struct MetaAnimPhaseBlend : IMetaAnim + { + MetaAnimPhaseBlend() : IMetaAnim(MAPhaseBlend, "PhaseBlend") {} + DECL_YAML + MetaAnimFactory animA; + MetaAnimFactory animB; + Value unkFloat; + Value unk; + + void gatherPrimitives(std::map>& out) + { + animA.m_anim->gatherPrimitives(out); + animB.m_anim->gatherPrimitives(out); + } + }; + struct MetaAnimRandom : IMetaAnim + { + MetaAnimRandom() : IMetaAnim(MARandom, "Random") {} + DECL_YAML + Value animCount; + struct Child : BigYAML + { + DECL_YAML + MetaAnimFactory anim; + Value probability; + }; + Vector children; + + void gatherPrimitives(std::map>& out) + { + for (const auto& child : children) + child.anim.m_anim->gatherPrimitives(out); + } + }; + struct MetaAnimSequence : IMetaAnim + { + MetaAnimSequence() : IMetaAnim(MASequence, "Sequence") {} + DECL_YAML + Value animCount; + Vector children; + + void gatherPrimitives(std::map>& out) + { + for (const auto& child : children) + child.m_anim->gatherPrimitives(out); + } + }; + + struct Animation : BigYAML + { + DECL_YAML + String<-1> name; + MetaAnimFactory metaAnim; + }; + std::vector animations; + + struct IMetaTrans : BigYAML + { + Delete expl; + enum Type + { + MTMetaAnim = 0, + MTTrans = 1, + MTPhaseTrans = 2, + MTNoTrans = 3, + } m_type; + const char* m_typeStr; + IMetaTrans(Type type, const char* typeStr) + : m_type(type), m_typeStr(typeStr) {} + }; + struct MetaTransFactory : BigYAML + { + DECL_YAML + Delete expl; + std::unique_ptr m_trans; + }; + struct MetaTransMetaAnim : IMetaTrans + { + MetaTransMetaAnim() : IMetaTrans(MTMetaAnim, "MetaAnim") {} + DECL_YAML + MetaAnimFactory anim; + }; + struct MetaTransTrans : IMetaTrans + { + MetaTransTrans() : IMetaTrans(MTTrans, "Trans") {} + DECL_YAML + Value time; + Value unk1; + Value unk2; + Value unk3; + Value unk4; + }; + struct MetaTransPhaseTrans : IMetaTrans + { + MetaTransPhaseTrans() : IMetaTrans(MTPhaseTrans, "PhaseTrans") {} + DECL_YAML + Value time; + Value unk1; + Value unk2; + Value unk3; + Value unk4; + }; + + struct Transition : BigYAML + { + DECL_YAML + Value unk; + Value animIdxA; + Value animIdxB; + MetaTransFactory metaTrans; + }; + std::vector transitions; + MetaTransFactory defaultTransition; + + struct AdditiveAnimationInfo : BigYAML + { + DECL_YAML + Value animIdx; + Value unk1; + Value unk2; + }; + std::vector additiveAnims; + + float floatA = 0.0; + float floatB = 0.0; + + struct HalfTransition : BigYAML + { + DECL_YAML + Value animIdx; + MetaTransFactory metaTrans; + }; + std::vector halfTransitions; + + struct AnimationResources : BigYAML + { + DECL_YAML + UniqueID64 animId; + UniqueID64 evntId; + }; + std::vector animResources; + } animationSet; + + struct ActionAABB : BigYAML + { + DECL_YAML + UniqueID64 animId; + Value aabb[2]; + }; + std::vector animAABBs; + + atUint32 unk3 = 0; + + + struct Effect : BigYAML + { + DECL_YAML + String<-1> name; + Value compCount; + struct EffectComponent : BigYAML + { + DECL_YAML + String<-1> name; + DNAFourCC type; + UniqueID32 id; + Value unkMP2; + Value unk1; + Value unk2; + Value unk3; + }; + Vector comps; + }; + std::vector effects; + + UniqueID32 cmdlOverride; + UniqueID32 cskrOverride; + + std::vector animIdxs; + + atUint32 unk4; + atUint8 unk5; + + struct Extents : BigYAML + { + DECL_YAML + Value animIdx; + Value aabb[2]; + }; + std::vector extents; + + + + + void getCharacterResInfo(std::vector>& out) const + { + out.clear(); + out.reserve(1); + out.emplace_back(); + DNAANCS::CharacterResInfo& chOut = out.back(); + chOut.name = name; + chOut.cmdl = cmdl; + chOut.cskr = cskr; + chOut.cinf = cinf; + } + + void getAnimationResInfo(std::map>& out) const + { + out.clear(); + for (const AnimationSet::Animation& ai : animationSet.animations) + ai.metaAnim.m_anim->gatherPrimitives(out); + } + + static bool Extract(const SpecBase& dataSpec, + PAKEntryReadStream& rs, + const HECL::ProjectPath& outPath, + PAKRouter& pakRouter, + const PAK::Entry& entry, + bool force, + std::function fileChanged) + { + HECL::ProjectPath yamlPath = outPath.getWithExtension(_S(".yaml")); + HECL::ProjectPath::PathType yamlType = yamlPath.getPathType(); + HECL::ProjectPath blendPath = outPath.getWithExtension(_S(".blend")); + HECL::ProjectPath::PathType blendType = blendPath.getPathType(); + + if (force || + yamlType == HECL::ProjectPath::PT_NONE || + blendType == HECL::ProjectPath::PT_NONE) + { + CHAR aChar; + aChar.read(rs); + + if (force || yamlType == HECL::ProjectPath::PT_NONE) + { + FILE* fp = HECL::Fopen(yamlPath.getAbsolutePath().c_str(), _S("wb")); + aChar.toYAMLFile(fp); + fclose(fp); + } + + if (force || blendType == HECL::ProjectPath::PT_NONE) + { + HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); + DNAANCS::ReadANCSToBlender, CHAR, MaterialSet, 4> + (conn, aChar, blendPath, pakRouter, entry, dataSpec, fileChanged, force); + } + } + + return true; + } +}; + +} +} + +#endif // _DNAMP3_CHAR_HPP_ diff --git a/DataSpec/DNAMP3/CINF.hpp b/DataSpec/DNAMP3/CINF.hpp index 9a0c53efc..d832a67d1 100644 --- a/DataSpec/DNAMP3/CINF.hpp +++ b/DataSpec/DNAMP3/CINF.hpp @@ -71,15 +71,15 @@ struct CINF : BigDNA } } - void sendCINFToBlender(HECL::BlenderConnection::PyOutStream& os, const UniqueID32& cinfId) const + void sendCINFToBlender(HECL::BlenderConnection::PyOutStream& os, const UniqueID64& cinfId) const { - os.format("arm = bpy.data.armatures.new('CINF_%08X')\n" + os.format("arm = bpy.data.armatures.new('CINF_%016" PRIX64 "')\n" "arm_obj = bpy.data.objects.new(arm.name, arm)\n" "bpy.context.scene.objects.link(arm_obj)\n" "bpy.context.scene.objects.active = arm_obj\n" "bpy.ops.object.mode_set(mode='EDIT')\n" "arm_bone_table = {}\n", - cinfId.toUint32()); + cinfId.toUint64()); for (const Bone& bone : bones) os.format("bone = arm.edit_bones.new('%s')\n" diff --git a/DataSpec/DNAMP3/CMakeLists.txt b/DataSpec/DNAMP3/CMakeLists.txt index 13f3454c4..dfbb205a2 100644 --- a/DataSpec/DNAMP3/CMakeLists.txt +++ b/DataSpec/DNAMP3/CMakeLists.txt @@ -1,6 +1,8 @@ make_dnalist(liblist PAK MLVL + ANIM + CHAR CMDLMaterials CINF CSKR @@ -9,6 +11,8 @@ add_library(DNAMP3 DNAMP3.hpp DNAMP3.cpp ${liblist} PAK.cpp + ANIM.cpp + CHAR.cpp CMDL.hpp CMDLMaterials.cpp STRG.hpp STRG.cpp diff --git a/DataSpec/DNAMP3/DNAMP3.cpp b/DataSpec/DNAMP3/DNAMP3.cpp index 864f7514c..6d1545265 100644 --- a/DataSpec/DNAMP3/DNAMP3.cpp +++ b/DataSpec/DNAMP3/DNAMP3.cpp @@ -5,6 +5,7 @@ #include "STRG.hpp" #include "MLVL.hpp" #include "CMDL.hpp" +#include "CHAR.hpp" #include "MREA.hpp" #include "../DNACommon/TXTR.hpp" @@ -308,6 +309,10 @@ ResExtractor PAKBridge::LookupExtractor(const PAK::Entry& entry) return {TXTR::Extract, nullptr, {_S(".png")}}; case SBIG('CMDL'): return {nullptr, CMDL::Extract, {_S(".blend")}, 1}; +#if 0 + case SBIG('CHAR'): + return {nullptr, CHAR::Extract, {_S(".yaml"), _S(".blend")}, 2}; +#endif case SBIG('MREA'): return {nullptr, MREA::Extract, {_S(".blend")}, 2}; case SBIG('MLVL'):