summaryrefslogtreecommitdiff
path: root/src/factories/oot/OoTPlayerAnimationFactory.cpp
blob: 5e573bd32f1ec3aa75a06e6f88503fd01caa6140 (plain)
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