From d075225c319460667ad6749e1f242a858318fd99 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Mon, 28 Sep 2015 16:00:28 -1000 Subject: [PATCH] Handling for additive ANIMs and MP3 skinning fix --- DataSpec/DNACommon/ANCS.hpp | 18 ++++-- DataSpec/DNACommon/CMDL.cpp | 1 - DataSpec/DNACommon/CMDL.hpp | 124 ++++++++++++++++++++++++++++++++---- DataSpec/DNAMP1/ANCS.hpp | 16 ++--- DataSpec/DNAMP1/ANIM.hpp | 2 +- DataSpec/DNAMP2/ANCS.hpp | 2 +- DataSpec/DNAMP2/ANIM.hpp | 2 +- DataSpec/DNAMP3/ANIM.cpp | 19 ++++-- DataSpec/DNAMP3/ANIM.hpp | 6 +- DataSpec/DNAMP3/CHAR.hpp | 18 +++--- hecl | 2 +- 11 files changed, 162 insertions(+), 48 deletions(-) diff --git a/DataSpec/DNACommon/ANCS.hpp b/DataSpec/DNACommon/ANCS.hpp index 3d4e6ac53..2196ca75c 100644 --- a/DataSpec/DNACommon/ANCS.hpp +++ b/DataSpec/DNACommon/ANCS.hpp @@ -21,6 +21,14 @@ struct CharacterResInfo std::vector>> overlays; }; +template +struct AnimationResInfo +{ + std::string name; + IDTYPE animId; + bool additive; +}; + template bool ReadANCSToBlender(HECL::BlenderConnection& conn, const ANCSDNA& ancs, @@ -150,20 +158,20 @@ bool ReadANCSToBlender(HECL::BlenderConnection& conn, } /* Get animation primitives */ - std::map> animResInfo; + std::map> animResInfo; ancs.getAnimationResInfo(animResInfo); for (const auto& id : animResInfo) { typename ANCSDNA::ANIMType anim; - if (pakRouter.lookupAndReadDNA(id.second.second, anim, true)) + if (pakRouter.lookupAndReadDNA(id.second.animId, anim, true)) { os.format("act = bpy.data.actions.new('%s')\n" - "act.use_fake_user = True\n", id.second.first.c_str()); - anim.sendANIMToBlender(os, cinf); + "act.use_fake_user = True\n", id.second.name.c_str()); + anim.sendANIMToBlender(os, cinf, id.second.additive); } os.format("actor_action = actor_data.actions.add()\n" - "actor_action.name = '%s'\n", id.second.first.c_str()); + "actor_action.name = '%s'\n", id.second.name.c_str()); } os.close(); diff --git a/DataSpec/DNACommon/CMDL.cpp b/DataSpec/DNACommon/CMDL.cpp index 5995cff1e..9e06545d3 100644 --- a/DataSpec/DNACommon/CMDL.cpp +++ b/DataSpec/DNACommon/CMDL.cpp @@ -29,7 +29,6 @@ void InitGeomBlenderContext(HECL::BlenderConnection::PyOutStream& os, " ret_mesh = bm\n" " vert_seq.ensure_lookup_table()\n" " verts = [vert_seq[i] for i in vert_indices]\n" - " #norms = [norm_seq[i] for i in norm_indices]\n" "\n" " # Make the face\n" " face = bm.faces.get(verts)\n" diff --git a/DataSpec/DNACommon/CMDL.hpp b/DataSpec/DNACommon/CMDL.hpp index 45d52782a..b8c106c63 100644 --- a/DataSpec/DNACommon/CMDL.hpp +++ b/DataSpec/DNACommon/CMDL.hpp @@ -20,10 +20,10 @@ struct Header : BigDNA { DECL_DNA Value flags; - inline bool shortNormals() const {return (flags & 0x2) != 0;} - inline void setShortNormals(bool val) {flags &= ~0x2; flags |= val << 1;} - inline bool shortUVs() const {return (flags & 0x4) != 0;} - inline void setShortUVs(bool val) {flags &= ~0x4; flags |= val << 2;} + bool shortNormals() const {return (flags & 0x2) != 0;} + void setShortNormals(bool val) {flags &= ~0x2; flags |= val << 1;} + bool shortUVs() const {return (flags & 0x4) != 0;} + void setShortUVs(bool val) {flags &= ~0x4; flags |= val << 2;} } flags; Value aabbMin; Value aabbMax; @@ -199,9 +199,77 @@ void ReadMaterialSetToBlender_3(HECL::BlenderConnection::PyOutStream& os, class DLReader { +public: + /* Class used for splitting verts with shared positions but different skinning matrices */ + class ExtraVertTracker + { + std::map>> m_extraVerts; + atUint16 m_maxBasePos = 0; + atUint16 m_nextOverPos = 1; + public: + atInt16 addPosSkinPair(atUint16 pos, atInt16 skin) + { + m_maxBasePos = std::max(m_maxBasePos, pos); + auto search = m_extraVerts.find(pos); + if (search == m_extraVerts.end()) + { + m_extraVerts[pos] = {std::make_pair(skin, 0)}; + return skin; + } + std::vector>& vertTrack = search->second; + for (const std::pair& s : vertTrack) + if (s.first == skin) + return vertTrack.front().first; + vertTrack.push_back(std::make_pair(skin, m_nextOverPos++)); + return vertTrack.front().first; + } + + template + void sendAdditionalVertsToBlender(HECL::BlenderConnection::PyOutStream& os, + const RigPair& rp) const + { + atUint32 nextVert = 1; + while (nextVert < m_nextOverPos) + { + for (const std::pair>>& ev : m_extraVerts) + { + for (const std::pair& se : ev.second) + { + if (se.second == nextVert) + { + os.format("bm.verts.ensure_lookup_table()\n" + "orig_vert = bm.verts[%u]\n" + "vert = bm.verts.new(orig_vert.co)\n", + ev.first); + rp.first->weightVertex(os, *rp.second, se.first); + ++nextVert; + } + } + } + } + } + + atUint16 lookupVertIdx(atUint16 pos, atInt16 skin) const + { + auto search = m_extraVerts.find(pos); + if (search == m_extraVerts.end()) + return -1; + const std::vector>& vertTrack = search->second; + if (vertTrack.front().first == skin) + return pos; + for (auto it=vertTrack.begin()+1 ; it!=vertTrack.end() ; ++it) + if (it->first == skin) + return m_maxBasePos + it->second; + return -1; + } + }; + +private: const VertexAttributes& m_va; std::unique_ptr m_dl; size_t m_dlSize; + ExtraVertTracker& m_evt; + const atInt16* m_bankIn; atUint8* m_cur; atUint16 readVal(GX::AttrType type) { @@ -226,31 +294,37 @@ class DLReader return retval; } public: - DLReader(const VertexAttributes& va, std::unique_ptr&& dl, size_t dlSize) - : m_va(va), m_dl(std::move(dl)), m_dlSize(dlSize) + DLReader(const VertexAttributes& va, std::unique_ptr&& dl, + size_t dlSize, ExtraVertTracker& evt, const atInt16* bankIn=nullptr) + : m_va(va), m_dl(std::move(dl)), m_dlSize(dlSize), m_evt(evt), m_bankIn(bankIn) { m_cur = m_dl.get(); } + operator bool() { return ((m_cur - m_dl.get()) < intptr_t(m_dlSize)) && *m_cur; } + GX::Primitive readPrimitive() { return GX::Primitive(*m_cur++ & 0xf8); } + GX::Primitive readPrimitiveAndVat(unsigned& vatOut) { atUint8 val = *m_cur++; vatOut = val & 0x7; return GX::Primitive(val & 0xf8); } + atUint16 readVertCount() { atUint16 retval = HECL::SBig(*(atUint16*)m_cur); m_cur += 2; return retval; } + struct DLPrimVert { atUint16 pos = 0; @@ -260,6 +334,7 @@ public: atUint8 pnMtxIdx = 0; atUint8 texMtxIdx[7] = {0}; }; + DLPrimVert readVert(bool peek=false) { atUint8* bakCur = m_cur; @@ -272,7 +347,17 @@ public: retval.texMtxIdx[4] = readVal(m_va.texMtxIdx[4]); retval.texMtxIdx[5] = readVal(m_va.texMtxIdx[5]); retval.texMtxIdx[6] = readVal(m_va.texMtxIdx[6]); - retval.pos = readVal(m_va.pos); + if (m_bankIn) + { + atUint16 posIdx = readVal(m_va.pos); + atUint8 mtxIdx = retval.pnMtxIdx / 3; + atInt16 skinIdx = -1; + if (mtxIdx < 10) + skinIdx = m_bankIn[mtxIdx]; + retval.pos = m_evt.lookupVertIdx(posIdx, skinIdx); + } + else + retval.pos = readVal(m_va.pos); retval.norm = readVal(m_va.norm); retval.color[0] = readVal(m_va.color0); retval.color[1] = readVal(m_va.color1); @@ -287,6 +372,7 @@ public: m_cur = bakCur; return retval; } + void preReadMaxIdxs(DLPrimVert& out) { atUint8* bakCur = m_cur; @@ -339,8 +425,9 @@ public: } m_cur = bakCur; } - void preReadMaxIdxs(DLPrimVert& out, std::vector& skinOut, - const atInt16 bankIn[10]) + + void preReadMaxIdxs(DLPrimVert& out, + std::vector& skinOut) { atUint8* bakCur = m_cur; while (*this) @@ -389,7 +476,8 @@ public: val = readVal(m_va.uvs[6]); out.uvs[6] = std::max(out.uvs[6], val); - skinOut[posVal] = bankIn[pnMtxVal/3]; + atInt16 skinIdx = m_bankIn[pnMtxVal/3]; + skinOut[posVal] = m_evt.addPosSkinPair(posVal, skinIdx); } } m_cur = bakCur; @@ -437,6 +525,7 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os, atUint64 afterHeaderPos = reader.position(); DLReader::DLPrimVert maxIdxs; std::vector skinIndices; + DLReader::ExtraVertTracker extraTracker; for (size_t s=0 ; sgetMatrixBank(sHead.skinMatrixBankIdx()); /* Do max index pre-read */ atUint32 realDlSize = secSizes[s] - (reader.position() - secStart); - DLReader dl(vertAttribs[sHead.matIdx], reader.readUBytes(realDlSize), realDlSize); + DLReader dl(vertAttribs[sHead.matIdx], reader.readUBytes(realDlSize), + realDlSize, extraTracker, bankIn); if (SurfaceHeader::UseMatrixSkinning() && rp.first) - dl.preReadMaxIdxs(maxIdxs, skinIndices, rp.first->getMatrixBank(sHead.skinMatrixBankIdx())); + dl.preReadMaxIdxs(maxIdxs, skinIndices); else dl.preReadMaxIdxs(maxIdxs); @@ -561,6 +654,8 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os, rp.first->weightVertex(os, *rp.second, i); } } + if (rp.first && SurfaceHeader::UseMatrixSkinning() && !skinIndices.empty()) + extraTracker.sendAdditionalVertsToBlender(os, rp); break; } case 1: @@ -652,6 +747,9 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os, VertexAttributes& curVA = vertAttribs[sHead.matIdx]; unsigned matUVCount = curVA.uvCount; bool matShortUVs = curVA.shortUVs; + const atInt16* bankIn = nullptr; + if (SurfaceHeader::UseMatrixSkinning() && rp.first) + bankIn = rp.first->getMatrixBank(sHead.skinMatrixBankIdx()); os.format("materials[%u].pass_index = %u\n", sHead.matIdx, surfIdx++); if (matUVCount > createdUVLayers) @@ -662,7 +760,7 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os, } atUint32 realDlSize = secSizes[s] - (reader.position() - secStart); - DLReader dl(vertAttribs[sHead.matIdx], reader.readUBytes(realDlSize), realDlSize); + DLReader dl(vertAttribs[sHead.matIdx], reader.readUBytes(realDlSize), realDlSize, extraTracker, bankIn); while (dl) { diff --git a/DataSpec/DNAMP1/ANCS.hpp b/DataSpec/DNAMP1/ANCS.hpp index 08e24752b..023181dcb 100644 --- a/DataSpec/DNAMP1/ANCS.hpp +++ b/DataSpec/DNAMP1/ANCS.hpp @@ -168,7 +168,7 @@ struct ANCS : BigYAML const char* m_typeStr; IMetaAnim(Type type, const char* typeStr) : m_type(type), m_typeStr(typeStr) {} - virtual void gatherPrimitives(std::map>& out)=0; + virtual void gatherPrimitives(std::map>& out)=0; }; struct MetaAnimFactory : BigYAML { @@ -186,9 +186,9 @@ struct ANCS : BigYAML Value unk1; Value unk2; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { - out[animIdx] = std::make_pair(animName, animId); + out[animIdx] = {animName, animId, false}; } }; struct MetaAnimBlend : IMetaAnim @@ -200,7 +200,7 @@ struct ANCS : BigYAML Value unkFloat; Value unk; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { animA.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out); @@ -215,7 +215,7 @@ struct ANCS : BigYAML Value unkFloat; Value unk; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { animA.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out); @@ -234,7 +234,7 @@ struct ANCS : BigYAML }; Vector children; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { for (const auto& child : children) child.anim.m_anim->gatherPrimitives(out); @@ -247,7 +247,7 @@ struct ANCS : BigYAML Value animCount; Vector children; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { for (const auto& child : children) child.m_anim->gatherPrimitives(out); @@ -367,7 +367,7 @@ struct ANCS : BigYAML } } - void getAnimationResInfo(std::map>& out) const + void getAnimationResInfo(std::map>& out) const { out.clear(); for (const AnimationSet::Animation& ai : animationSet.animations) diff --git a/DataSpec/DNAMP1/ANIM.hpp b/DataSpec/DNAMP1/ANIM.hpp index 8040f3a7a..100758426 100644 --- a/DataSpec/DNAMP1/ANIM.hpp +++ b/DataSpec/DNAMP1/ANIM.hpp @@ -161,7 +161,7 @@ struct ANIM : BigDNA m_anim->write(writer); } - void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const + void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf, bool) const { m_anim->sendANIMToBlender(os, cinf); } diff --git a/DataSpec/DNAMP2/ANCS.hpp b/DataSpec/DNAMP2/ANCS.hpp index 19ca999cc..fd206128d 100644 --- a/DataSpec/DNAMP2/ANCS.hpp +++ b/DataSpec/DNAMP2/ANCS.hpp @@ -204,7 +204,7 @@ struct ANCS : BigYAML } } - void getAnimationResInfo(std::map>& out) const + void getAnimationResInfo(std::map>& out) const { out.clear(); for (const DNAMP1::ANCS::AnimationSet::Animation& ai : animationSet.animations) diff --git a/DataSpec/DNAMP2/ANIM.hpp b/DataSpec/DNAMP2/ANIM.hpp index 7d26b18ad..5db0ece82 100644 --- a/DataSpec/DNAMP2/ANIM.hpp +++ b/DataSpec/DNAMP2/ANIM.hpp @@ -194,7 +194,7 @@ struct ANIM : BigDNA m_anim->write(writer); } - void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const + void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf, bool) const { m_anim->sendANIMToBlender(os, cinf); } diff --git a/DataSpec/DNAMP3/ANIM.cpp b/DataSpec/DNAMP3/ANIM.cpp index 04bab6306..7cdf169f4 100644 --- a/DataSpec/DNAMP3/ANIM.cpp +++ b/DataSpec/DNAMP3/ANIM.cpp @@ -9,9 +9,11 @@ namespace DNAMP3 using ANIMOutStream = HECL::BlenderConnection::PyOutStream::ANIMOutStream; -void ANIM::IANIM::sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const +void ANIM::IANIM::sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf, bool additive) const { - os.format("act.hecl_fps = round(%f)\n", (1.0f / mainInterval)); + os.format("act.hecl_fps = round(%f)\n" + "act.hecl_additive = %s\n", + 1.0f / mainInterval, additive ? "True" : "False"); auto kit = chanKeys.begin() + 1; for (const std::pair>& bone : bones) @@ -41,14 +43,19 @@ void ANIM::IANIM::sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, co "\n"; if (std::get<1>(bone.second)) - os << "bone_trans_head = (0.0,0.0,0.0)\n" - "if arm_obj.data.bones[bone_string].parent is not None:\n" - " bone_trans_head = Vector(arm_obj.data.bones[bone_string].head_local) - Vector(arm_obj.data.bones[bone_string].parent.head_local)\n" - "transCurves = []\n" + { + if (!additive) + os << "bone_trans_head = (0.0,0.0,0.0)\n" + "if arm_obj.data.bones[bone_string].parent is not None:\n" + " bone_trans_head = Vector(arm_obj.data.bones[bone_string].head_local) - Vector(arm_obj.data.bones[bone_string].parent.head_local)\n"; + else + os << "bone_trans_head = (0.0,0.0,0.0)\n"; + os << "transCurves = []\n" "transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=0, action_group=bone_string))\n" "transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=1, action_group=bone_string))\n" "transCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].location', index=2, action_group=bone_string))\n" "\n"; + } if (std::get<2>(bone.second)) os << "scaleCurves = []\n" diff --git a/DataSpec/DNAMP3/ANIM.hpp b/DataSpec/DNAMP3/ANIM.hpp index 74067f96e..c9bec742a 100644 --- a/DataSpec/DNAMP3/ANIM.hpp +++ b/DataSpec/DNAMP3/ANIM.hpp @@ -27,7 +27,7 @@ struct ANIM : BigDNA std::vector> chanKeys; float mainInterval = 0.0; - void sendANIMToBlender(HECL::BlenderConnection::PyOutStream&, const CINF&) const; + void sendANIMToBlender(HECL::BlenderConnection::PyOutStream&, const CINF&, bool additive) const; }; struct ANIM0 : IANIM @@ -105,9 +105,9 @@ struct ANIM : BigDNA m_anim->write(writer); } - void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const + void sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf, bool additive) const { - m_anim->sendANIMToBlender(os, cinf); + m_anim->sendANIMToBlender(os, cinf, additive); } }; diff --git a/DataSpec/DNAMP3/CHAR.hpp b/DataSpec/DNAMP3/CHAR.hpp index 6df0f877a..c53fff422 100644 --- a/DataSpec/DNAMP3/CHAR.hpp +++ b/DataSpec/DNAMP3/CHAR.hpp @@ -141,7 +141,7 @@ struct CHAR : BigYAML const char* m_typeStr; IMetaAnim(Type type, const char* typeStr) : m_type(type), m_typeStr(typeStr) {} - virtual void gatherPrimitives(std::map>& out)=0; + virtual void gatherPrimitives(std::map>& out)=0; }; struct MetaAnimFactory : BigYAML { @@ -159,9 +159,9 @@ struct CHAR : BigYAML Value unk1; Value unk2; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { - out[animIdx] = std::make_pair(animName, animId); + out[animIdx] = {animName, animId, false}; } }; struct MetaAnimBlend : IMetaAnim @@ -173,7 +173,7 @@ struct CHAR : BigYAML Value unkFloat; Value unk; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { animA.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out); @@ -188,7 +188,7 @@ struct CHAR : BigYAML Value unkFloat; Value unk; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { animA.m_anim->gatherPrimitives(out); animB.m_anim->gatherPrimitives(out); @@ -207,7 +207,7 @@ struct CHAR : BigYAML }; Vector children; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { for (const auto& child : children) child.anim.m_anim->gatherPrimitives(out); @@ -220,7 +220,7 @@ struct CHAR : BigYAML Value animCount; Vector children; - void gatherPrimitives(std::map>& out) + void gatherPrimitives(std::map>& out) { for (const auto& child : children) child.m_anim->gatherPrimitives(out); @@ -296,11 +296,13 @@ struct CHAR : BigYAML chOut.overlays.emplace_back(overlay.type, std::make_pair(overlay.cmdl, overlay.cskr)); } - void getAnimationResInfo(std::map>& out) const + void getAnimationResInfo(std::map>& out) const { out.clear(); for (const AnimationInfo::Animation& ai : animationInfo.animations) ai.metaAnim.m_anim->gatherPrimitives(out); + for (auto& animRes : out) + animRes.second.additive = animationInfo.additiveMap.at(animRes.first); } static bool Extract(const SpecBase& dataSpec, diff --git a/hecl b/hecl index daec614e8..5c36b9e5b 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit daec614e8af7aaebc9c81be2ac3eda97f50daa0d +Subproject commit 5c36b9e5bb0bc051e320477720eb3847154adfa5