summaryrefslogtreecommitdiff
path: root/src/factories/oot/OoTAnimationFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/factories/oot/OoTAnimationFactory.cpp')
-rw-r--r--src/factories/oot/OoTAnimationFactory.cpp118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/factories/oot/OoTAnimationFactory.cpp b/src/factories/oot/OoTAnimationFactory.cpp
new file mode 100644
index 0000000..a2e8edd
--- /dev/null
+++ b/src/factories/oot/OoTAnimationFactory.cpp
@@ -0,0 +1,118 @@
+#include "OoTAnimationFactory.h"
+#include "spdlog/spdlog.h"
+#include "Companion.h"
+#include "utils/Decompressor.h"
+
+namespace OoT {
+
+std::optional<std::shared_ptr<IParsedData>> OoTAnimationFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ // Check for legacy animation type (data stays in ROM segment, not extracted)
+ auto animType = GetSafeNode<std::string>(node, "anim_type", "normal");
+ if (animType == "legacy") {
+ auto anim = std::make_shared<OoTNormalAnimationData>();
+ anim->frameCount = 0;
+ anim->limit = 0;
+ anim->isLegacy = true;
+ return anim;
+ }
+
+ auto [_, segment] = Decompressor::AutoDecode(node, buffer, 0x10);
+ LUS::BinaryReader reader(segment.data, segment.size);
+ reader.SetEndianness(Torch::Endianness::Big);
+
+ // ROM layout: AnimationHeader (16 bytes)
+ // +0x00: int16 frameCount
+ // +0x02: int16 padding
+ // +0x04: segptr rotationValues
+ // +0x08: segptr rotationIndices
+ // +0x0C: int16 limit
+ // +0x0E: int16 padding
+ int16_t frameCount = reader.ReadInt16();
+ reader.ReadInt16(); // padding
+ uint32_t rawRotValues = reader.ReadUInt32();
+ uint32_t rawRotIndices = reader.ReadUInt32();
+ int16_t limit = reader.ReadInt16();
+
+ uint32_t rotValuesAddr = Companion::Instance->PatchVirtualAddr(rawRotValues);
+ uint32_t rotIndicesAddr = Companion::Instance->PatchVirtualAddr(rawRotIndices);
+
+ auto anim = std::make_shared<OoTNormalAnimationData>();
+ anim->frameCount = frameCount;
+ anim->limit = limit;
+
+ // Translate segmented addresses to file offsets
+ uint32_t rotValuesOffset = Decompressor::TranslateAddr(rotValuesAddr);
+ uint32_t rotIndicesOffset = Decompressor::TranslateAddr(rotIndicesAddr);
+ uint32_t animHeaderOffset = Decompressor::TranslateAddr(Companion::Instance->PatchVirtualAddr(GetSafeNode<uint32_t>(node, "offset")));
+
+ // Read rotation values: array of uint16 from rotValues to rotIndices
+ uint32_t rotValuesCount = (rotIndicesOffset - rotValuesOffset) / 2;
+ if (rotValuesCount > 0 && rotValuesOffset < rotIndicesOffset) {
+ YAML::Node rvNode;
+ rvNode["offset"] = rotValuesAddr;
+ auto rvRaw = Decompressor::AutoDecode(rvNode, buffer, rotValuesCount * 2);
+ LUS::BinaryReader rvReader(rvRaw.segment.data, rvRaw.segment.size);
+ rvReader.SetEndianness(Torch::Endianness::Big);
+
+ for (uint32_t i = 0; i < rotValuesCount; i++) {
+ anim->rotationValues.push_back(rvReader.ReadUInt16());
+ }
+ }
+
+ // Read rotation indices: array of {x,y,z} uint16 from rotIndices to animHeader
+ uint32_t rotIndicesCount = (animHeaderOffset - rotIndicesOffset) / 6;
+ if (rotIndicesCount > 0 && rotIndicesOffset < animHeaderOffset) {
+ YAML::Node riNode;
+ riNode["offset"] = rotIndicesAddr;
+ auto riRaw = Decompressor::AutoDecode(riNode, buffer, rotIndicesCount * 6);
+ LUS::BinaryReader riReader(riRaw.segment.data, riRaw.segment.size);
+ riReader.SetEndianness(Torch::Endianness::Big);
+
+ for (uint32_t i = 0; i < rotIndicesCount; i++) {
+ RotationIndex ri;
+ ri.x = riReader.ReadUInt16();
+ ri.y = riReader.ReadUInt16();
+ ri.z = riReader.ReadUInt16();
+ anim->rotationIndices.push_back(ri);
+ }
+ }
+
+ return anim;
+}
+
+ExportResult OoTAnimationBinaryExporter::Export(std::ostream& write, std::shared_ptr<IParsedData> raw,
+ std::string& entryName, YAML::Node& node,
+ std::string* replacement) {
+ auto writer = LUS::BinaryWriter();
+ auto anim = std::static_pointer_cast<OoTNormalAnimationData>(raw);
+
+ WriteHeader(writer, Torch::ResourceType::OoTAnimation, 0);
+
+ if (anim->isLegacy) {
+ writer.Write(static_cast<uint32_t>(OoTAnimationType::Legacy));
+ writer.Finish(write);
+ return std::nullopt;
+ }
+
+ writer.Write(static_cast<uint32_t>(OoTAnimationType::Normal));
+ writer.Write(anim->frameCount);
+
+ writer.Write(static_cast<uint32_t>(anim->rotationValues.size()));
+ for (auto& val : anim->rotationValues) {
+ writer.Write(val);
+ }
+
+ writer.Write(static_cast<uint32_t>(anim->rotationIndices.size()));
+ for (auto& ri : anim->rotationIndices) {
+ writer.Write(ri.x);
+ writer.Write(ri.y);
+ writer.Write(ri.z);
+ }
+
+ writer.Write(anim->limit);
+
+ writer.Finish(write);
+ return std::nullopt;
+}
+
+} // namespace OoT