diff --git a/DataSpec/DNACommon/ANCS.hpp b/DataSpec/DNACommon/ANCS.hpp index 3b3c2c86d..8c85f6b2b 100644 --- a/DataSpec/DNACommon/ANCS.hpp +++ b/DataSpec/DNACommon/ANCS.hpp @@ -85,69 +85,56 @@ bool ReadANCSToBlender(hecl::BlenderConnection& conn, /* Establish ANCS blend */ if (!conn.createBlend(outPath, hecl::BlenderConnection::BlendType::Actor)) return false; - hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); - os.format("import bpy\n" - "from mathutils import Vector\n" - "bpy.context.scene.name = '%s'\n" - "bpy.context.scene.hecl_mesh_obj = bpy.context.scene.name\n" - "\n" - "# Using 'Blender Game'\n" - "bpy.context.scene.render.engine = 'BLENDER_GAME'\n" - "\n" - "# Clear Scene\n" - "for ob in bpy.data.objects:\n" - " if ob.type != 'LAMP':\n" - " bpy.context.scene.objects.unlink(ob)\n" - " bpy.data.objects.remove(ob)\n" - "\n" - "actor_data = bpy.context.scene.hecl_sact_data\n", - pakRouter.getBestEntryName(entry).c_str()); - - typename ANCSDNA::CINFType cinf; - std::unordered_set cinfsDone; - for (const auto& info : chResInfo) + std::string firstName; + typename ANCSDNA::CINFType firstCinf; { - /* Provide data to add-on */ - os.format("actor_subtype = actor_data.subtypes.add()\n" - "actor_subtype.name = '%s'\n\n", - info.name.c_str()); + hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); - /* Build CINF if needed */ - if (cinfsDone.find(info.cinf) == cinfsDone.end()) + os.format("import bpy\n" + "from mathutils import Vector\n" + "bpy.context.scene.name = '%s'\n" + "bpy.context.scene.hecl_mesh_obj = bpy.context.scene.name\n" + "\n" + "# Using 'Blender Game'\n" + "bpy.context.scene.render.engine = 'BLENDER_GAME'\n" + "\n" + "# Clear Scene\n" + "for ob in bpy.data.objects:\n" + " if ob.type != 'LAMP':\n" + " bpy.context.scene.objects.unlink(ob)\n" + " bpy.data.objects.remove(ob)\n" + "\n" + "actor_data = bpy.context.scene.hecl_sact_data\n", + pakRouter.getBestEntryName(entry).c_str()); + + std::unordered_set cinfsDone; + for (const auto& info : chResInfo) { - pakRouter.lookupAndReadDNA(info.cinf, cinf); - cinf.sendCINFToBlender(os, info.cinf); - cinfsDone.insert(info.cinf); - } - else - os.format("arm_obj = bpy.data.objects['CINF_%s']\n", info.cinf.toString().c_str()); - os << "actor_subtype.linked_armature = arm_obj.name\n"; + /* Provide data to add-on */ + os.format("actor_subtype = actor_data.subtypes.add()\n" + "actor_subtype.name = '%s'\n\n", + info.name.c_str()); - /* Link CMDL */ - const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(info.cmdl, nullptr, true, true); - if (cmdlE) - { - hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE); - os.linkBlend(cmdlPath.getAbsolutePathUTF8().c_str(), - pakRouter.getBestEntryName(*cmdlE).c_str(), true); - - /* Attach CMDL to CINF */ - os << "if obj.name not in bpy.context.scene.objects:\n" - " bpy.context.scene.objects.link(obj)\n" - "obj.parent = arm_obj\n" - "obj.parent_type = 'ARMATURE'\n" - "actor_subtype.linked_mesh = obj.name\n\n"; - } - - /* Link overlays */ - for (const auto& overlay : info.overlays) - { - os << "overlay = actor_subtype.overlays.add()\n"; - os.format("overlay.name = '%s'\n", overlay.first.toString().c_str()); + /* Build CINF if needed */ + if (cinfsDone.find(info.cinf) == cinfsDone.end()) + { + typename ANCSDNA::CINFType cinf; + pakRouter.lookupAndReadDNA(info.cinf, cinf); + cinf.sendCINFToBlender(os, info.cinf); + if (cinfsDone.empty()) + { + firstName = ANCSDNA::CINFType::GetCINFArmatureName(info.cinf); + firstCinf = cinf; + } + cinfsDone.insert(info.cinf); + } + else + 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 */ - const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(overlay.second.first, nullptr, true, true); + const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(info.cmdl, nullptr, true, true); if (cmdlE) { hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE); @@ -159,31 +146,62 @@ bool ReadANCSToBlender(hecl::BlenderConnection& conn, " bpy.context.scene.objects.link(obj)\n" "obj.parent = arm_obj\n" "obj.parent_type = 'ARMATURE'\n" - "overlay.linked_mesh = obj.name\n\n"; + "actor_subtype.linked_mesh = obj.name\n\n"; + } + + /* Link overlays */ + for (const auto& overlay : info.overlays) + { + os << "overlay = actor_subtype.overlays.add()\n"; + os.format("overlay.name = '%s'\n", overlay.first.toString().c_str()); + + /* Link CMDL */ + const typename PAKRouter::EntryType* cmdlE = pakRouter.lookupEntry(overlay.second.first, nullptr, true, true); + if (cmdlE) + { + hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE); + os.linkBlend(cmdlPath.getAbsolutePathUTF8().c_str(), + pakRouter.getBestEntryName(*cmdlE).c_str(), true); + + /* Attach CMDL to CINF */ + os << "if obj.name not in bpy.context.scene.objects:\n" + " bpy.context.scene.objects.link(obj)\n" + "obj.parent = arm_obj\n" + "obj.parent_type = 'ARMATURE'\n" + "overlay.linked_mesh = obj.name\n\n"; + } } } } - DNAANIM::RigInverter inverter(cinf); - - /* Get animation primitives */ - std::map> animResInfo; - ancs.getAnimationResInfo(animResInfo); - for (const auto& id : animResInfo) { - typename ANCSDNA::ANIMType anim; - if (pakRouter.lookupAndReadDNA(id.second.animId, anim, true)) + hecl::BlenderConnection::DataStream ds = conn.beginData(); + std::unordered_map matrices = ds.getBoneMatrices(firstName); + ds.close(); + DNAANIM::RigInverter inverter(firstCinf, matrices); + + hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); + os << "import bpy\n" + "actor_data = bpy.context.scene.hecl_sact_data\n"; + + /* Get animation primitives */ + std::map> animResInfo; + ancs.getAnimationResInfo(animResInfo); + for (const auto& id : animResInfo) { - os.format("act = bpy.data.actions.new('%s')\n" - "act.use_fake_user = True\n", id.second.name.c_str()); - anim.sendANIMToBlender(os, inverter, id.second.additive); + typename ANCSDNA::ANIMType anim; + 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.name.c_str()); + anim.sendANIMToBlender(os, inverter, id.second.additive); + } + + os.format("actor_action = actor_data.actions.add()\n" + "actor_action.name = '%s'\n", id.second.name.c_str()); } - - os.format("actor_action = actor_data.actions.add()\n" - "actor_action.name = '%s'\n", id.second.name.c_str()); } - - os.close(); conn.saveBlend(); return true; } diff --git a/DataSpec/DNACommon/RigInverter.cpp b/DataSpec/DNACommon/RigInverter.cpp index 2804499b1..4784eb1bb 100644 --- a/DataSpec/DNACommon/RigInverter.cpp +++ b/DataSpec/DNACommon/RigInverter.cpp @@ -52,8 +52,6 @@ RigInverter::Bone::Bone(const CINFType& cinf, const typename CINFType: m_tail /= float(actualChildren); if (m_tail.magSquared() < 0.001f) m_tail = naturalTail; - else - m_inverter = zeus::CQuaternion(m_tail, naturalTail); } else if (parentIdx != -1) { @@ -62,8 +60,6 @@ RigInverter::Bone::Bone(const CINFType& cinf, const typename CINFType: m_tail = zeus::CVector3f(origBone.origin) * 2.f - zeus::CVector3f(pBone.origin); if (m_tail.magSquared() < 0.001f) m_tail = naturalTail; - else - m_inverter = zeus::CQuaternion(m_tail, naturalTail); } else { @@ -81,13 +77,38 @@ RigInverter::RigInverter(const CINFType& cinf) m_bones.emplace_back(cinf, b); } +template +RigInverter::RigInverter(const CINFType& cinf, + const std::unordered_map& matrices) +: m_cinf(cinf) +{ + m_bones.reserve(cinf.bones.size()); + for (const typename CINFType::Bone& b : cinf.bones) + { + m_bones.emplace_back(cinf, b); + const std::string* name = cinf.getBoneNameFromId(b.id); + if (name) + { + auto search = matrices.find(*name); + if (search != matrices.cend()) + { + m_bones.back().m_inverter = zeus::CMatrix3f(search->second[0], + search->second[1], + search->second[2]); + m_bones.back().m_restorer = m_bones.back().m_inverter.transposed(); + } + } + } +} + template zeus::CQuaternion RigInverter::transformRotation(atUint32 boneId, const zeus::CQuaternion& origRot) const { for (const Bone& b : m_bones) if (b.m_origBone.id == boneId) - return b.m_inverter * origRot; + return b.m_inverter * zeus::CMatrix3f(origRot) * b.m_restorer; return origRot; } diff --git a/DataSpec/DNACommon/RigInverter.hpp b/DataSpec/DNACommon/RigInverter.hpp index 0c9afc71a..42a6550d3 100644 --- a/DataSpec/DNACommon/RigInverter.hpp +++ b/DataSpec/DNACommon/RigInverter.hpp @@ -2,7 +2,9 @@ #define __COMMON_RIGINVERTER_HPP__ #include "zeus/CVector3f.hpp" +#include "zeus/CMatrix3f.hpp" #include "zeus/CQuaternion.hpp" +#include "BlenderConnection.hpp" namespace DataSpec { @@ -18,7 +20,8 @@ public: struct Bone { const typename CINFType::Bone& m_origBone; - zeus::CQuaternion m_inverter; + zeus::CMatrix3f m_inverter; + zeus::CMatrix3f m_restorer; zeus::CVector3f m_tail; zeus::CVector3f m_parentDelta; Bone(const CINFType& cinf, const typename CINFType::Bone& origBone); @@ -28,6 +31,9 @@ private: std::vector m_bones; public: RigInverter(const CINFType& cinf); + RigInverter(const CINFType& cinf, + const std::unordered_map& matrices); const CINFType& getCINF() const {return m_cinf;} const std::vector& getBones() const {return m_bones;} zeus::CQuaternion transformRotation(atUint32 boneId, const zeus::CQuaternion& origRot) const; diff --git a/DataSpec/DNAMP1/ANIM.cpp b/DataSpec/DNAMP1/ANIM.cpp index 22f08077d..9eb531efc 100644 --- a/DataSpec/DNAMP1/ANIM.cpp +++ b/DataSpec/DNAMP1/ANIM.cpp @@ -13,6 +13,10 @@ void ANIM::IANIM::sendANIMToBlender(hecl::BlenderConnection::PyOutStream& os, co os.format("act.hecl_fps = round(%f)\n", (1.0f / mainInterval)); auto kit = chanKeys.begin(); + + std::vector fixedRotKeys; + std::vector fixedTransKeys; + for (const std::pair& bone : bones) { const std::string* bName = rig.getCINF().getBoneNameFromId(bone.first); @@ -45,13 +49,14 @@ void ANIM::IANIM::sendANIMToBlender(hecl::BlenderConnection::PyOutStream& os, co "crv.keyframe_points[-1].interpolation = 'LINEAR'\n" "\n"; + if (bone.first == 3) + printf(""); ANIMOutStream ao = os.beginANIMCurve(); { const std::vector& rotKeys = *kit++; - std::vector fixedRotKeys; + fixedRotKeys.clear(); fixedRotKeys.resize(rotKeys.size()); - fprintf(stderr, "alloc %d\n", rotKeys.size()); for (int c=0 ; c<4 ; ++c) { @@ -70,14 +75,12 @@ void ANIM::IANIM::sendANIMToBlender(hecl::BlenderConnection::PyOutStream& os, co for (const zeus::CQuaternion& val : fixedRotKeys) ao.write(*frameit++, val[c]); } - - fprintf(stderr, "size %d\n", fixedRotKeys.size()); } if (bone.second) { const std::vector& transKeys = *kit++; - std::vector fixedTransKeys; + fixedTransKeys.clear(); fixedTransKeys.resize(transKeys.size()); for (int c=0 ; c<3 ; ++c) diff --git a/DataSpec/DNAMP1/CINF.hpp b/DataSpec/DNAMP1/CINF.hpp index b65897f65..a47e6e290 100644 --- a/DataSpec/DNAMP1/CINF.hpp +++ b/DataSpec/DNAMP1/CINF.hpp @@ -87,7 +87,7 @@ struct CINF : BigDNA void sendCINFToBlender(hecl::BlenderConnection::PyOutStream& os, const UniqueID32& cinfId) const { DNAANIM::RigInverter inverter(*this); - + os.format("arm = bpy.data.armatures.new('CINF_%08X')\n" "arm_obj = bpy.data.objects.new(arm.name, arm)\n" "bpy.context.scene.objects.link(arm_obj)\n" @@ -114,6 +114,11 @@ struct CINF : BigDNA os << "bpy.ops.object.mode_set(mode='OBJECT')\n"; } + static std::string GetCINFArmatureName(const UniqueID32& cinfId) + { + return hecl::Format("CINF_%08X", cinfId.toUint32()); + } + CINF() = default; using Armature = hecl::BlenderConnection::DataStream::Actor::Armature; diff --git a/DataSpec/DNAMP2/CINF.hpp b/DataSpec/DNAMP2/CINF.hpp index bffe12d48..134c06e8d 100644 --- a/DataSpec/DNAMP2/CINF.hpp +++ b/DataSpec/DNAMP2/CINF.hpp @@ -109,6 +109,11 @@ struct CINF : BigDNA os << "bpy.ops.object.mode_set(mode='OBJECT')\n"; } + + static std::string GetCINFArmatureName(const UniqueID32& cinfId) + { + return hecl::Format("CINF_%08X", cinfId.toUint32()); + } }; } diff --git a/DataSpec/DNAMP3/CINF.hpp b/DataSpec/DNAMP3/CINF.hpp index a9a8fd2f2..41c92dd84 100644 --- a/DataSpec/DNAMP3/CINF.hpp +++ b/DataSpec/DNAMP3/CINF.hpp @@ -42,6 +42,11 @@ struct CINF : DNAMP2::CINF os << "bpy.ops.object.mode_set(mode='OBJECT')\n"; } + + static std::string GetCINFArmatureName(const UniqueID64& cinfId) + { + return hecl::Format("CINF_%016" PRIX64, cinfId.toUint64()); + } }; } diff --git a/hecl b/hecl index 71e97f724..76788ee29 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 71e97f724085893d27eaab6da71abf02aa37cb1b +Subproject commit 76788ee293a8e25131e6fae118b9337f70b8f371 diff --git a/specter b/specter index a1d60af72..38768581b 160000 --- a/specter +++ b/specter @@ -1 +1 @@ -Subproject commit a1d60af72c17c4df4152f36766ec9e39c9c56200 +Subproject commit 38768581b2fb0504a4e1043333176ebc9bc86d13