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
|
#include "OoTPlayerAnimationFactory.h"
#include "spdlog/spdlog.h"
#include "Companion.h"
#include "utils/Decompressor.h"
namespace OoT {
// ==================== OoT Player Animation Header Factory ====================
std::optional<std::shared_ptr<IParsedData>> OoTPlayerAnimationHeaderFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
// ROM layout: PlayerAnimationHeader (8 bytes)
// +0x00: int16 frameCount
// +0x02: int16 padding
// +0x04: uint32 segPtr (segment 7 pointer to link_animetion data)
auto [_, segment] = Decompressor::AutoDecode(node, buffer, 0x08);
LUS::BinaryReader reader(segment.data, segment.size);
reader.SetEndianness(Torch::Endianness::Big);
auto anim = std::make_shared<OoTPlayerAnimationHeaderData>();
anim->frameCount = reader.ReadInt16();
reader.ReadInt16(); // padding
uint32_t segPtr = reader.ReadUInt32();
// Resolve the segment pointer to a path in link_animetion
auto path = Companion::Instance->GetStringByAddr(segPtr);
if (path.has_value()) {
anim->animDataPath = path.value();
} else {
SPDLOG_WARN("PlayerAnimation: Could not resolve segment pointer 0x{:08X}", segPtr);
anim->animDataPath = "";
}
return anim;
}
ExportResult OoTPlayerAnimationHeaderBinaryExporter::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<OoTPlayerAnimationHeaderData>(raw);
WriteHeader(writer, Torch::ResourceType::OoTAnimation, 0);
writer.Write(static_cast<uint32_t>(OoTAnimationType::Link));
writer.Write(anim->frameCount);
writer.Write("__OTR__" + anim->animDataPath);
writer.Finish(write);
return std::nullopt;
}
// ==================== OoT Player Animation Data Factory ====================
std::optional<std::shared_ptr<IParsedData>> OoTPlayerAnimationDataFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
// Player animation data is a flat array of int16 limb rotation values.
// Size = (6 * 22 + 2) * frameCount bytes = 134 bytes per frame.
int32_t frameCount = GetSafeNode<int32_t>(node, "frame_count");
uint32_t dataSize = (6 * 22 + 2) * frameCount;
auto [_, segment] = Decompressor::AutoDecode(node, buffer, dataSize);
LUS::BinaryReader reader(segment.data, segment.size);
reader.SetEndianness(Torch::Endianness::Big);
auto anim = std::make_shared<OoTPlayerAnimationData>();
uint32_t numEntries = dataSize / 2;
anim->limbRotData.reserve(numEntries);
for (uint32_t i = 0; i < numEntries; i++) {
anim->limbRotData.push_back(reader.ReadInt16());
}
return anim;
}
ExportResult OoTPlayerAnimationDataBinaryExporter::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<OoTPlayerAnimationData>(raw);
WriteHeader(writer, Torch::ResourceType::OoTPlayerAnimation, 0);
writer.Write(static_cast<uint32_t>(anim->limbRotData.size()));
for (auto& val : anim->limbRotData) {
writer.Write(val);
}
writer.Finish(write);
return std::nullopt;
}
} // namespace OoT
|