diff --git a/src/Companion.cpp b/src/Companion.cpp index b95566c4..55da3255 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -63,6 +63,9 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("MK64:TRACKSECTIONS", std::make_shared()); this->RegisterFactory("MK64:SPAWNDATA", std::make_shared()); + // SF64 specific + this->RegisterFactory("ANIM", std::make_shared()); + this->Process(); } diff --git a/src/factories/sf64/AnimFactory.cpp b/src/factories/sf64/AnimFactory.cpp new file mode 100644 index 00000000..c100328f --- /dev/null +++ b/src/factories/sf64/AnimFactory.cpp @@ -0,0 +1,180 @@ +#include "AnimFactory.h" +#include "spdlog/spdlog.h" + +#include "Companion.h" +#include "utils/Decompressor.h" + +#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x +#define HEX(x) std::hex << std::setfill(' ') << std::setw(6) << x +// #define COL(c) std::dec << std::setfill(' ') << std::setw(3) << c + +AnimData::AnimData(int16_t frameCount, int16_t limbCount, uint32_t dataOffset, std::vector frameData, uint32_t keyOffset, std::vector jointKeys): mFrameCount(frameCount), mLimbCount(limbCount), mDataOffset(dataOffset), mFrameData(std::move(frameData)), mKeyOffset(keyOffset), mJointKeys(std::move(jointKeys)) { + if((mDataOffset + sizeof(mFrameData) > mKeyOffset) && (mKeyOffset + sizeof(mJointKeys) > mDataOffset)) { + // error 1 + } + if(mJointKeys.size() != limbCount) { + // error 2 + } +} + +void AnimHeaderExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return; + } + + write << "extern Animation " << symbol << ";\n"; +} + +void AnimCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + // auto limbCount = std::static_pointer_cast(raw)->mLimbCount; + // auto frameCount = std::static_pointer_cast(raw)->mFrameCount; + // auto jointKeys = std::static_pointer_cast(raw)->mJointKeys; + // auto frameData = std::static_pointer_cast(raw)->mFrameData; + auto anim = std::static_pointer_cast(raw); + const auto symbol = GetSafeNode(node, "symbol", entryName); + // auto dataName = GetSafeNode(node, "data_symbol", entryName); + // auto keyName = GetSafeNode(node, "key_symbol", entryName); + auto dataOffset = anim->mDataOffset; + auto keyOffset = anim->mKeyOffset; + auto dataSegment = 0; + auto keySegment = 0; + std::ostringstream dataDefaultName; + std::ostringstream keyDefaultName; + + if (IS_SEGMENTED(dataOffset)) { + dataSegment = SEGMENT_NUMBER(dataOffset); + dataOffset = SEGMENT_OFFSET(dataOffset); + } + dataDefaultName << symbol << "_frame_data_" << std::hex << dataOffset; + auto dataName = GetSafeNode(node, "data_symbol", dataDefaultName.str()); + + if (IS_SEGMENTED(keyOffset)) { + keySegment = SEGMENT_NUMBER(keyOffset); + keyOffset = SEGMENT_OFFSET(keyOffset); + } + keyDefaultName << symbol << "_joint_key_" << std::hex << keyOffset; + auto keyName = GetSafeNode(node, "data_symbol", keyDefaultName.str()); + + + // if (Companion::Instance->IsDebug()) { + // write << "// 0x" << std::hex << std::uppercase << offset << "\n"; + // } + + write << "u16 " << dataName << "[] = {"; + for(int i = 0; i < anim->mFrameData.size(); i++) { + + if((i % 12) == 0) { + write << "\n" << fourSpaceTab; + } + // if(i < 3) { + write << NUM(anim->mFrameData[i]) << ", "; + // } else { + // write << HEX(anim->mFrameData[i]) << ", "; + // } + } + write << "\n};\n"; + + write << "\n"; + + write << "JointKey " << keyName << "[] = {\n"; + for(auto joint : anim->mJointKeys) { + write << fourSpaceTab << "{"; + for(int i = 0; i < 6; i++) { + write << NUM(joint.keys[i]) << ", "; + } + write << "},\n"; + } + write << "};\n"; + + write << "\n"; + + + + + + write << "Animation " << symbol << " = {\n"; + write << fourSpaceTab << NUM(anim->mFrameCount) << ", " << NUM(anim->mLimbCount) << ", " << dataName << ", " << keyName << ",\n"; + write << "};\n"; + + write << "\n"; + +} + +void AnimBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto anim = std::static_pointer_cast(raw); + auto writer = LUS::BinaryWriter(); + + WriteHeader(writer, LUS::ResourceType::Vertex, 0); + writer.Write(anim->mFrameCount); + writer.Write(anim->mLimbCount); + writer.Write(anim->mFrameData.size()); + writer.Write(anim->mJointKeys.size()); + + for(auto joint : anim->mJointKeys) { + for (int i = 0; i < 6; i++) { + writer.Write(joint.keys[i]); + } + } + for(auto data : anim->mFrameData) { + writer.Write(data); + } + writer.Finish(write); +} + +std::optional> AnimFactory::parse(std::vector& buffer, YAML::Node& node) { + // uint32_t offset = GetSafeNode(node, "offset"); + YAML::Node dataNode; + YAML::Node keyNode; + std::vector jointKeys; + std::vector frameData; + auto dataCount = 0; + auto [_, segment] = Decompressor::AutoDecode(node, buffer, 0xC); + LUS::BinaryReader reader(segment.data, segment.size); + + reader.SetEndianness(LUS::Endianness::Big); + // reader.Seek(offset, Start); + int16_t frameCount = reader.ReadInt16(); + int16_t limbCount = reader.ReadInt16(); + uint32_t dataOffset = reader.ReadUInt32(); + uint32_t keyOffset = reader.ReadUInt32(); + + keyNode["offset"] = keyOffset; + dataNode["offset"] = dataOffset; + + auto [__, keySegment] = Decompressor::AutoDecode(keyNode, buffer, sizeof(JointKey) * (limbCount + 1)); + LUS::BinaryReader keyReader(keySegment.data, keySegment.size); + keyReader.SetEndianness(LUS::Endianness::Big); + + for(int i = 0; i <= limbCount; i++) { + auto xLen = keyReader.ReadUInt16(); + auto x = keyReader.ReadUInt16(); + auto yLen = keyReader.ReadUInt16(); + auto y = keyReader.ReadUInt16(); + auto zLen = keyReader.ReadUInt16(); + auto z = keyReader.ReadUInt16(); + + jointKeys.push_back(JointKey({xLen, x, yLen, y, zLen, z})); + if(i == 0 || x != 0) { + dataCount += (xLen < 1) ? 1 : (xLen > frameCount) ? frameCount : xLen; + } + if(i == 0 || y != 0) { + dataCount += (yLen < 1) ? 1 : (yLen > frameCount) ? frameCount : yLen; + } + if(i == 0 || z != 0) { + dataCount += (zLen < 1) ? 1 : (zLen > frameCount) ? frameCount : zLen; + } + } + + auto [___, dataSegment] = Decompressor::AutoDecode(dataNode, buffer, sizeof(uint16_t) * dataCount); + LUS::BinaryReader dataReader(dataSegment.data, dataSegment.size); + dataReader.SetEndianness(LUS::Endianness::Big); + + for(int i = 0; i < dataCount; i++) { + frameData.push_back(dataReader.ReadInt16()); + } + + return std::make_shared(frameCount, limbCount, dataOffset, frameData, keyOffset, jointKeys); +} \ No newline at end of file diff --git a/src/factories/sf64/AnimFactory.h b/src/factories/sf64/AnimFactory.h new file mode 100644 index 00000000..28f88d80 --- /dev/null +++ b/src/factories/sf64/AnimFactory.h @@ -0,0 +1,48 @@ +#pragma once + +#include "../BaseFactory.h" + +struct JointKey { + uint16_t keys[6]; +}; + +class AnimData : public IParsedData { +public: + int16_t mFrameCount; + int16_t mLimbCount; + uint32_t mDataOffset; + uint32_t mKeyOffset; + std::vector mFrameData; + std::vector mJointKeys; + + + AnimData(int16_t frameCount, int16_t limbCount, uint32_t dataOffset, std::vector frameData, uint32_t keyOffset, std::vector jointKeys); +}; + +class AnimHeaderExporter : public BaseExporter { + void Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class AnimBinaryExporter : public BaseExporter { + void Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class AnimCodeExporter : public BaseExporter { + void Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class AnimFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + std::optional> parse_modding(std::vector& buffer, YAML::Node& data) override { + return std::nullopt; + } + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Code, AnimCodeExporter) + REGISTER(Header, AnimHeaderExporter) + REGISTER(Binary, AnimBinaryExporter) + }; + } + bool SupportModdedAssets() override { return false; } +}; \ No newline at end of file