#include "ANIM.hpp" #include #include namespace Retro { namespace DNAMP3 { using ANIMOutStream = HECL::BlenderConnection::PyOutStream::ANIMOutStream; void ANIM::IANIM::sendANIMToBlender(HECL::BlenderConnection::PyOutStream& os, const CINF& cinf) const { os.format("act.hecl_fps = round(%f)\n", (1.0f / mainInterval)); auto kit = chanKeys.begin() + 1; for (const std::pair>& bone : bones) { const std::string* bName = cinf.getBoneNameFromId(bone.first); if (!bName) { if (std::get<0>(bone.second)) ++kit; if (std::get<1>(bone.second)) ++kit; if (std::get<2>(bone.second)) ++kit; continue; } os.format("bone_string = '%s'\n", bName->c_str()); os << "action_group = act.groups.new(bone_string)\n" "\n"; if (std::get<0>(bone.second)) os << "rotCurves = []\n" "rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=0, action_group=bone_string))\n" "rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=1, action_group=bone_string))\n" "rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=2, action_group=bone_string))\n" "rotCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_quaternion', index=3, action_group=bone_string))\n" "\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" "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" "scaleCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].scale', index=0, action_group=bone_string))\n" "scaleCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].scale', index=1, action_group=bone_string))\n" "scaleCurves.append(act.fcurves.new('pose.bones[\"'+bone_string+'\"].scale', index=2, action_group=bone_string))\n" "\n"; os << "crv = act.fcurves.new('pose.bones[\"'+bone_string+'\"].rotation_mode', action_group=bone_string)\n" "crv.keyframe_points.add()\n" "crv.keyframe_points[-1].co = (0, 0)\n" "crv.keyframe_points[-1].interpolation = 'LINEAR'\n" "\n"; ANIMOutStream ao = os.beginANIMCurve(); if (std::get<0>(bone.second)) { const std::vector& rotKeys = *kit++; for (int c=0 ; c<4 ; ++c) { auto frameit = frames.begin(); ao.changeCurve(ANIMOutStream::CurveRotate, c, rotKeys.size()); for (const DNAANIM::Value& val : rotKeys) ao.write(*frameit++, val.v4.vec[c]); } } if (std::get<1>(bone.second)) { const std::vector& transKeys = *kit++; for (int c=0 ; c<3 ; ++c) { auto frameit = frames.begin(); ao.changeCurve(ANIMOutStream::CurveTranslate, c, transKeys.size()); for (const DNAANIM::Value& val : transKeys) ao.write(*frameit++, val.v3.vec[c]); } } if (std::get<2>(bone.second)) { const std::vector& scaleKeys = *kit++; for (int c=0 ; c<3 ; ++c) { auto frameit = frames.begin(); ao.changeCurve(ANIMOutStream::CurveScale, c, scaleKeys.size()); for (const DNAANIM::Value& val : scaleKeys) ao.write(*frameit++, val.v3.vec[c]); } } } } void ANIM::ANIM0::read(Athena::io::IStreamReader& reader) { Header head; head.read(reader); mainInterval = head.interval; frames.clear(); frames.reserve(head.keyCount); for (size_t k=0 ; k boneMap; for (size_t b=0 ; b(bones.back().second) = true; } boneCount = reader.readUint32Big(); for (size_t b=0 ; b(bones[b].second) = true; } boneCount = reader.readUint32Big(); for (size_t b=0 ; b(bones[b].second) = true; } channels.clear(); chanKeys.clear(); channels.emplace_back(); channels.back().type = DNAANIM::Channel::KF_HEAD; chanKeys.emplace_back(); for (const std::pair>& bone : bones) { if (std::get<0>(bone.second)) { channels.emplace_back(); DNAANIM::Channel& chan = channels.back(); chan.type = DNAANIM::Channel::ROTATION; chanKeys.emplace_back(); } if (std::get<1>(bone.second)) { channels.emplace_back(); DNAANIM::Channel& chan = channels.back(); chan.type = DNAANIM::Channel::TRANSLATION; chanKeys.emplace_back(); } if (std::get<2>(bone.second)) { channels.emplace_back(); DNAANIM::Channel& chan = channels.back(); chan.type = DNAANIM::Channel::SCALE; chanKeys.emplace_back(); } } reader.readUint32Big(); auto kit = chanKeys.begin() + 1; for (const std::pair>& bone : bones) { if (std::get<0>(bone.second)) ++kit; if (std::get<1>(bone.second)) ++kit; if (std::get<2>(bone.second)) { std::vector& keys = *kit++; for (size_t k=0 ; k>& bone : bones) { if (std::get<0>(bone.second)) { std::vector& keys = *kit++; for (size_t k=0 ; k(bone.second)) ++kit; if (std::get<2>(bone.second)) ++kit; } reader.readUint32Big(); kit = chanKeys.begin() + 1; for (const std::pair>& bone : bones) { if (std::get<0>(bone.second)) ++kit; if (std::get<1>(bone.second)) { std::vector& keys = *kit++; for (size_t k=0 ; k(bone.second)) ++kit; } } void ANIM::ANIM0::write(Athena::io::IStreamWriter& writer) const { Header head; head.unk0 = 0; head.unk1 = 0; head.unk2 = 0; head.keyCount = frames.size(); head.duration = head.keyCount * mainInterval; head.interval = mainInterval; atUint32 maxId = 0; for (const std::pair>& bone : bones) maxId = std::max(maxId, bone.first); head.boneSlotCount = maxId + 1; head.write(writer); for (size_t s=0 ; s>& bone : bones) { if (s == bone.first) { writer.writeUByte(boneIdx); found = true; break; } ++boneIdx; } if (!found) writer.writeUByte(0xff); } writer.writeUint32Big(bones.size()); size_t boneIdx = 0; size_t rotKeyCount = 0; for (const std::pair>& bone : bones) { if (std::get<0>(bone.second)) { writer.writeUByte(boneIdx); ++rotKeyCount; } else writer.writeUByte(0xff); ++boneIdx; } writer.writeUint32Big(bones.size()); boneIdx = 0; size_t transKeyCount = 0; for (const std::pair>& bone : bones) { if (std::get<1>(bone.second)) { writer.writeUByte(boneIdx); ++transKeyCount; } else writer.writeUByte(0xff); ++boneIdx; } writer.writeUint32Big(bones.size()); boneIdx = 0; size_t scaleKeyCount = 0; for (const std::pair>& bone : bones) { if (std::get<2>(bone.second)) { writer.writeUByte(boneIdx); ++scaleKeyCount; } else writer.writeUByte(0xff); ++boneIdx; } writer.writeUint32Big(scaleKeyCount * head.keyCount); auto cit = chanKeys.begin(); for (const std::pair>& bone : bones) { if (std::get<0>(bone.second)) ++cit; if (std::get<1>(bone.second)) ++cit; if (std::get<2>(bone.second)) { const std::vector& keys = *cit++; auto kit = keys.begin(); for (size_t k=0 ; k>& bone : bones) { if (std::get<0>(bone.second)) { const std::vector& keys = *cit++; auto kit = keys.begin(); for (size_t k=0 ; k(bone.second)) ++cit; if (std::get<2>(bone.second)) ++cit; } writer.writeUint32Big(transKeyCount * head.keyCount); cit = chanKeys.begin(); for (const std::pair>& bone : bones) { if (std::get<0>(bone.second)) ++cit; if (std::get<1>(bone.second)) { const std::vector& keys = *cit++; auto kit = keys.begin(); for (size_t k=0 ; k(bone.second)) ++cit; } } static float ComputeFrames(const std::vector& keyTimes, std::vector& framesOut) { if (keyTimes.size() <= 1) return 0.0; float mainInterval = FLT_MAX; float lastTime = keyTimes[0]; for (auto it=keyTimes.begin() + 1 ; it != keyTimes.end() ; ++it) { float diff = *it - lastTime; if (diff < mainInterval) mainInterval = diff; lastTime = *it; } mainInterval = 1.0 / round(1.0 / mainInterval); framesOut.clear(); framesOut.reserve(keyTimes.size()); atUint32 frameAccum = 0; for (float time : keyTimes) { while (frameAccum * mainInterval < time) ++frameAccum; framesOut.push_back(frameAccum); } return mainInterval; } void ANIM::ANIM1::read(Athena::io::IStreamReader& reader) { Header head; head.read(reader); std::vector keyTimes; keyTimes.reserve(head.keyCount); for (size_t k=0 ; k initBlock; initBlock.reserve(head.initBlockSize/2); for (size_t i=0 ; i chanBitCounts; chanBitCounts.reserve(rawChannelCount); for (size_t c=0 ; c>& bone : bones) { if (std::get<0>(bone.second)) { channels.emplace_back(); DNAANIM::Channel& chan = channels.back(); chan.type = DNAANIM::Channel::ROTATION_MP3; chan.i[0] = *initsIt++; chan.q[0] = *bitsIt++; chan.i[1] = *initsIt++; chan.q[1] = *bitsIt++; chan.i[2] = *initsIt++; chan.q[2] = *bitsIt++; chan.i[3] = *initsIt++; chan.q[3] = *bitsIt++; } if (std::get<1>(bone.second)) { channels.emplace_back(); DNAANIM::Channel& chan = channels.back(); chan.type = DNAANIM::Channel::TRANSLATION; chan.i[0] = *initsIt++; chan.q[0] = *bitsIt++; chan.i[1] = *initsIt++; chan.q[1] = *bitsIt++; chan.i[2] = *initsIt++; chan.q[2] = *bitsIt++; } if (std::get<2>(bone.second)) { channels.emplace_back(); DNAANIM::Channel& chan = channels.back(); chan.type = DNAANIM::Channel::SCALE; chan.i[0] = *initsIt++; chan.q[0] = *bitsIt++; chan.i[1] = *initsIt++; chan.q[1] = *bitsIt++; chan.i[2] = *initsIt++; chan.q[2] = *bitsIt++; } } size_t bsSize = DNAANIM::ComputeBitstreamSize(head.keyCount-1, channels); std::unique_ptr bsData = reader.readUBytes(bsSize); DNAANIM::BitstreamReader bsReader; chanKeys = bsReader.read(bsData.get(), head.keyCount-1, channels, 32767, head.translationMult); } void ANIM::ANIM1::write(Athena::io::IStreamWriter& writer) const { } } }