1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
|