#include "ZCkeyFrameAnim.h" #include "ZCKeyFrame.h" #include "Globals.h" #include "Utils/BitConverter.h" REGISTER_ZFILENODE(KeyFrameAnimation, ZKeyFrameAnim); ZKeyFrameAnim::ZKeyFrameAnim(ZFile* nParent) : ZResource(nParent) { RegisterRequiredAttribute("Skel"); genOTRDef = true; } ZKeyFrameAnim::~ZKeyFrameAnim() { } void ZKeyFrameAnim::ParseXML(tinyxml2::XMLElement* reader) { ZResource::ParseXML(reader); std::string skelAddrStr = registeredAttributes.at("Skel").value; skelOffset = (offset_t)StringHelper::StrToL(skelAddrStr, 16); } void ZKeyFrameAnim::DeclareReferencesLate(const std::string& prefix) { std::string defaultPrefix = name; std::string declaration; if (defaultPrefix == "") defaultPrefix = prefix; ZResource::DeclareReferences(defaultPrefix); declaration += "\t"; if (skel->limbType == ZKeyframeSkelType::Normal) { for (const auto b : bitFlags) { declaration += StringHelper::Sprintf("0x%02X, ", b); parent->AddDeclarationArray( GETSEGOFFSET(bitFlagsAddr), DeclarationAlignment::Align4, bitFlags.size(), "u8", StringHelper::Sprintf("%s_bitFlags_%06X", prefix.c_str(), rawDataIndex), bitFlags.size(), declaration); } } else { for (const auto b : bitFlagsFlex) { declaration += StringHelper::Sprintf("0x%04X, ", b); parent->AddDeclarationArray( GETSEGOFFSET(bitFlagsAddr), DeclarationAlignment::Align4, bitFlagsFlex.size() * 2, "u16", StringHelper::Sprintf("%s_flexBitFlags_%06X", prefix.c_str(), rawDataIndex), bitFlagsFlex.size(), declaration); } } declaration.clear(); for (const auto kf : keyFrames) { declaration += StringHelper::Sprintf(" \t { %i, %i, %i, },\n", kf.frame, kf.value, kf.velocity); } // Remove last new line to prevent an extra line after the last element declaration = declaration.substr(0, declaration.length() - 1); parent->AddDeclarationArray( GETSEGOFFSET(keyFramesAddr), DeclarationAlignment::Align4, keyFrames.size() * 6, "KeyFrame", StringHelper::Sprintf("%s_KeyFrame_%06X", prefix.c_str(), rawDataIndex), keyFrames.size(), declaration); declaration.clear(); declaration += "\t"; for (const auto kfNum : kfNums) { declaration += StringHelper::Sprintf("0x%04X, ", kfNum); } parent->AddDeclarationArray( GETSEGOFFSET(kfNumsAddr), DeclarationAlignment::Align4, kfNums.size() * 2, "s16", StringHelper::Sprintf("%s_kfNums_%06X", prefix.c_str(), rawDataIndex), kfNums.size(), declaration); declaration += "\n"; declaration.clear(); declaration += "\t"; for (const auto pv : presetValues) { declaration += StringHelper::Sprintf("0x%04X, ", pv); } declaration += "\n"; parent->AddDeclarationArray( GETSEGOFFSET(presentValuesAddr), DeclarationAlignment::Align4, presetValues.size() * 2, "s16", StringHelper::Sprintf("%s_presetValues_%06X", prefix.c_str(), rawDataIndex), presetValues.size(), declaration); } // ParseRawDataLate is used because we need to make sure the flex skel has been processed first. void ZKeyFrameAnim::ParseRawDataLate() { const auto& rawData = parent->GetRawData(); skel = static_cast(parent->FindResource(skelOffset)); size_t numLimbs = skel->limbCount; bitFlagsAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x0); keyFramesAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x4); kfNumsAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0x8); presentValuesAddr = BitConverter::ToUInt32BE(rawData, rawDataIndex + 0xC); uint32_t kfNumsSize = 0; uint32_t presetValuesSize = 0; uint32_t keyFramesCount = 0; if (skel->limbType == ZKeyframeSkelType::Normal) { bitFlags.reserve(numLimbs); for (size_t i = 0; i < numLimbs; i++) { uint8_t e = BitConverter::ToUInt8BE(rawData, GETSEGOFFSET(bitFlagsAddr) + i); bitFlags.push_back(e); kfNumsSize += GetSetBits((uint8_t)(e & 0b111111)); presetValuesSize += GetSetBits((uint8_t)((e ^ 0xFF) & 0b111111)); } } else { bitFlagsFlex.reserve(numLimbs); for (size_t i = 0; i < numLimbs; i++) { uint16_t e = BitConverter::ToUInt16BE(rawData, GETSEGOFFSET(bitFlagsAddr) + (i * 2)); bitFlagsFlex.push_back(e); kfNumsSize += GetSetBits((uint16_t)(e & 0b111111111)); presetValuesSize += GetSetBits((uint16_t)((e ^ 0xFFFF) & 0b111111111)); } } kfNums.reserve(kfNumsSize); for (uint32_t i = 0; i < kfNumsSize; i++) { int16_t kfNum = BitConverter::ToUInt16BE(rawData, GETSEGOFFSET(kfNumsAddr) + (i * 2)); keyFramesCount += kfNum; kfNums.push_back(kfNum); } keyFrames.reserve(keyFramesCount); for (uint32_t i = 0; i < keyFramesCount; i++) { KeyFrame kf; kf.frame = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 0) + (i * 6)); kf.value = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 2) + (i * 6)); kf.velocity = BitConverter::ToInt16BE(rawData, (GETSEGOFFSET(keyFramesAddr) + 4) + (i * 6)); keyFrames.push_back(kf); } presetValues.reserve(presetValuesSize); for (uint32_t i = 0; i < presetValuesSize; i++) { presetValues.push_back( BitConverter::ToInt16BE(rawData, GETSEGOFFSET(presentValuesAddr) + (i * 2))); } unk_10 = BitConverter::ToInt16BE(rawData, GETSEGOFFSET(rawDataIndex) + 0x10); duration = BitConverter::ToInt16BE(rawData, GETSEGOFFSET(rawDataIndex) + 0x12); } std::string ZKeyFrameAnim::GetBodySourceCode() const { std::string declaration; std::string bitFlagsStr; std::string keyFrameStr; std::string kfNumsStr; std::string presetValuesStr; Globals::Instance->GetSegmentedPtrName(bitFlagsAddr, parent, "", bitFlagsStr, parent->workerID); Globals::Instance->GetSegmentedPtrName(keyFramesAddr, parent, "", keyFrameStr, parent->workerID); Globals::Instance->GetSegmentedPtrName(kfNumsAddr, parent, "", kfNumsStr, parent->workerID); Globals::Instance->GetSegmentedPtrName(presentValuesAddr, parent, "", presetValuesStr, parent->workerID); return StringHelper::Sprintf("\n\t%s, %s, %s, %s, 0x%04X, 0x%04X\n", bitFlagsStr.c_str(), keyFrameStr.c_str(), kfNumsStr.c_str(), presetValuesStr.c_str(), unk_10, duration); } std::string ZKeyFrameAnim::GetSourceTypeName() const { return "KeyFrameAnimation"; } ZResourceType ZKeyFrameAnim::GetResourceType() const { return ZResourceType::KeyFrameAnimation; } size_t ZKeyFrameAnim::GetRawDataSize() const { return 0x14; } template uint32_t ZKeyFrameAnim::GetSetBits(T data) const { uint32_t num = 0; for (size_t i = 0; i < sizeof(T) * 8; i++) { if ((data >> i) & 1) num++; } return num; }