From b6eab060ff1865bea62838d07486e40919a8fd21 Mon Sep 17 00:00:00 2001 From: inspectredc Date: Mon, 8 Apr 2024 11:47:11 +0100 Subject: movtex factories --- src/Companion.cpp | 4 + src/factories/ResourceType.h | 3 + src/factories/sm64/CollisionFactory.cpp | 3 +- src/factories/sm64/MovtexFactory.cpp | 156 +++++++++++++++++++++++++++++++ src/factories/sm64/MovtexFactory.h | 40 ++++++++ src/factories/sm64/MovtexQuadFactory.cpp | 106 +++++++++++++++++++++ src/factories/sm64/MovtexQuadFactory.h | 38 ++++++++ 7 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 src/factories/sm64/MovtexFactory.cpp create mode 100644 src/factories/sm64/MovtexFactory.h create mode 100644 src/factories/sm64/MovtexQuadFactory.cpp create mode 100644 src/factories/sm64/MovtexQuadFactory.h diff --git a/src/Companion.cpp b/src/Companion.cpp index 9a3c233..53c1fb8 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -34,6 +34,8 @@ #include "factories/sm64/DictionaryFactory.h" #include "factories/sm64/TextFactory.h" #include "factories/sm64/GeoLayoutFactory.h" +#include "factories/sm64/MovtexFactory.h" +#include "factories/sm64/MovtexQuadFactory.h" #include "factories/mk64/CourseVtx.h" #include "factories/mk64/Waypoints.h" @@ -91,6 +93,8 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("SM64:ANIM", std::make_shared()); this->RegisterFactory("SM64:COLLISION", std::make_shared()); this->RegisterFactory("SM64:GEO_LAYOUT", std::make_shared()); + this->RegisterFactory("SM64:MOVTEX_QUAD", std::make_shared()); + this->RegisterFactory("SM64:MOVTEX", std::make_shared()); // MK64 specific this->RegisterFactory("MK64:COURSE_VTX", std::make_shared()); diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h index 8388766..4cc2ee4 100644 --- a/src/factories/ResourceType.h +++ b/src/factories/ResourceType.h @@ -28,6 +28,9 @@ enum class ResourceType { SDialog = 0x53444C47, // SDLG Dictionary = 0x44494354, // DICT GeoLayout = 0x47454F20, // GEO + Collision = 0x434F4C20, // COL + Movtex = 0x4D4F5654, // MOVT + MovtexQuad = 0x4D4F5651, // MOVQ // MK64 CourseVertex = 0x43565458, // CVTX diff --git a/src/factories/sm64/CollisionFactory.cpp b/src/factories/sm64/CollisionFactory.cpp index 41fa0b1..53dd0f5 100644 --- a/src/factories/sm64/CollisionFactory.cpp +++ b/src/factories/sm64/CollisionFactory.cpp @@ -259,7 +259,6 @@ ExportResult SM64::CollisionBinaryExporter::Export(std::ostream &write, std::sha const auto collision = std::static_pointer_cast(data).get(); auto writer = LUS::BinaryWriter(); - writer.SetEndianness(LUS::Endianness::Big); writer.Write((int16_t)COL_INIT()); @@ -340,7 +339,7 @@ ExportResult SM64::CollisionBinaryExporter::Export(std::ostream &write, std::sha writer.Close(); LUS::BinaryWriter output = LUS::BinaryWriter(); - WriteHeader(output, LUS::ResourceType::Blob, 0); + WriteHeader(output, LUS::ResourceType::Collision, 0); output.Write(static_cast(buffer.size())); output.Write(buffer.data(), buffer.size()); diff --git a/src/factories/sm64/MovtexFactory.cpp b/src/factories/sm64/MovtexFactory.cpp new file mode 100644 index 0000000..c0babe6 --- /dev/null +++ b/src/factories/sm64/MovtexFactory.cpp @@ -0,0 +1,156 @@ +#include "MovtexFactory.h" +#include "spdlog/spdlog.h" + +#include "Companion.h" +#include "utils/Decompressor.h" +#include "utils/TorchUtils.h" +#include + +ExportResult SM64::MovtexHeaderExporter::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 std::nullopt; + } + + write << "extern Movtex " << symbol << "[];\n"; + return std::nullopt; +} + +ExportResult SM64::MovtexCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + const auto offset = GetSafeNode(node, "offset"); + + auto movtex = std::static_pointer_cast(raw); + + write << "static Movtex " << symbol << "[] = {"; + + if (movtex->mIsQuad) { + auto numLists = movtex->mMovtexData.at(0); + write << "MOV_TEX_INIT_LOAD(" << numLists << "),\n"; + for (int16_t i = 0; i < numLists; ++i) { + write << "MOV_TEX_ROT_SPEED(" << movtex->mMovtexData.at(i * 14 + 1) << "),\n"; + write << "MOV_TEX_ROT_SCALE(" << movtex->mMovtexData.at(i * 14 + 2) << "),\n"; + write << "MOV_TEX_4_BOX_TRIS(" << movtex->mMovtexData.at(i * 14 + 3) << ", " << movtex->mMovtexData.at(i * 14 + 4) << "),\n"; + write << "MOV_TEX_4_BOX_TRIS(" << movtex->mMovtexData.at(i * 14 + 5) << ", " << movtex->mMovtexData.at(i * 14 + 6) << "),\n"; + write << "MOV_TEX_4_BOX_TRIS(" << movtex->mMovtexData.at(i * 14 + 7) << ", " << movtex->mMovtexData.at(i * 14 + 8) << "),\n"; + write << "MOV_TEX_4_BOX_TRIS(" << movtex->mMovtexData.at(i * 14 + 9) << ", " << movtex->mMovtexData.at(i * 14 + 10) << "),\n"; + write << "MOV_TEX_ROT(" << movtex->mMovtexData.at(i * 14 + 11) << "),\n"; + write << "MOV_TEX_ALPHA(" << movtex->mMovtexData.at(i * 14 + 12) << "),\n"; + write << "MOV_TEX_DEFINE(" << movtex->mMovtexData.at(i * 14 + 13) << "),\n"; + write << "MOV_TEX_END(),\n"; + } + } else { + write << "MOV_TEX_SPEED(" << movtex->mMovtexData.at(0) << "),\n"; + if (movtex->mHasColor) { + for (uint32_t i = 0; i < movtex->mVertexCount; ++i) { + // There is also a MOV_TEX_LIGHT_TRIS macro, however this is identical in result to using MOV_TEX_ROT_TRIS and would require more params on the yaml + write << "MOV_TEX_ROT_TRIS("; + write << movtex->mMovtexData.at(i * 8 + 0 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 1 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 2 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 3 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 4 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 5 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 6 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 7 + 1) << "),\n"; + } + } else { + for (uint32_t i = 0; i < movtex->mVertexCount; ++i) { + write << "MOV_TEX_TRIS("; + write << movtex->mMovtexData.at(i * 8 + 0 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 1 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 2 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 3 + 1) << ", "; + write << movtex->mMovtexData.at(i * 8 + 4 + 1) << "),\n"; + } + } + write << "MOV_TEX_END(),\n"; + } + + write << "\n};\n"; + + size_t size = (movtex->mMovtexData.size() + 1) * sizeof(int16_t); + + return offset + size; +} + +ExportResult SM64::MovtexBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto movtex = std::static_pointer_cast(raw); + + WriteHeader(writer, LUS::ResourceType::Movtex, 0); + + // May want extra info, but importer should just be mMovtexData with an extra 0 (or 2) at the end + // if (movtex->mIsQuad) { + // writer.Write(0); + // writer.Write(0); + // } else { + // writer.Write(movtex->mVertexCount); + // writer.Write((uint32_t)(movtex->mHasColor ? 1 : 0)); + // } + + for (auto datum : movtex->mMovtexData) { + writer.Write(datum); + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional> SM64::MovtexFactory::parse(std::vector& buffer, YAML::Node& node) { + const auto offset = GetSafeNode(node, "offset"); + const auto symbol = GetSafeNode(node, "symbol"); + bool isQuad = false; + uint32_t count = 0; + bool hasColor = false; + + // If quad we can generate automatically + if (node["quad"]) { + isQuad = GetSafeNode(node, "quad"); + } + // Otherwise we need to know the count of vertices and the colour attribute + if (!isQuad) { + if (node["count"]) { + count = GetSafeNode(node, "quad"); + } else { + SPDLOG_WARN("Non quad movtex needs count field"); + } + if (node["has_color"]) { + hasColor = GetSafeNode(node, "has_color"); + } else { + SPDLOG_WARN("Non quad movtex needs has_color field"); + } + } + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + LUS::BinaryReader reader(segment.data, segment.size); + reader.SetEndianness(LUS::Endianness::Big); + + std::vector movtexData; + + if (isQuad) { + auto numLists = reader.ReadInt16(); + movtexData.emplace_back(numLists); + // movtex quad data has 14 elements + for (int16_t i = 0; i < numLists * 14; ++i) { + movtexData.emplace_back(reader.ReadInt16()); + } + if (reader.ReadInt16() != 0) { + SPDLOG_WARN("Incorrect end to movtex quad found at symbol: {}, offset: 0x{:X}", symbol, offset); + } + } else { + auto speed = reader.ReadInt16(); + movtexData.emplace_back(speed); + size_t triSize = hasColor ? 8 : 5; + for (size_t i = 0; i < count * triSize; ++i) { + movtexData.emplace_back(reader.ReadInt16()); + } + + if (reader.ReadInt16() != 0) { + SPDLOG_WARN("Incorrect end to movtex object found at symbol: {}, offset: 0x{:X}", symbol, offset); + } + } + + return std::make_shared(movtexData, isQuad, count, hasColor); +} diff --git a/src/factories/sm64/MovtexFactory.h b/src/factories/sm64/MovtexFactory.h new file mode 100644 index 0000000..219e189 --- /dev/null +++ b/src/factories/sm64/MovtexFactory.h @@ -0,0 +1,40 @@ +#pragma once + +#include "factories/BaseFactory.h" +#include "types/Vec3D.h" + +namespace SM64 { + +class MovtexData : public IParsedData { +public: + std::vector mMovtexData; + bool mIsQuad; + uint32_t mVertexCount; + bool mHasColor; + MovtexData(std::vector movtexData, bool isQuad, uint32_t count, bool hasColor) : mMovtexData(std::move(movtexData)), mIsQuad(isQuad), mVertexCount(count), mHasColor(hasColor) {} +}; + +class MovtexHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MovtexBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MovtexCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MovtexFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Code, MovtexCodeExporter) + REGISTER(Header, MovtexHeaderExporter) + REGISTER(Binary, MovtexBinaryExporter) + }; + } +}; +} diff --git a/src/factories/sm64/MovtexQuadFactory.cpp b/src/factories/sm64/MovtexQuadFactory.cpp new file mode 100644 index 0000000..3b8a2dd --- /dev/null +++ b/src/factories/sm64/MovtexQuadFactory.cpp @@ -0,0 +1,106 @@ +#include "MovtexQuadFactory.h" +#include "spdlog/spdlog.h" + +#include "Companion.h" +#include "utils/Decompressor.h" +#include "utils/TorchUtils.h" +#include + +ExportResult SM64::MovtexQuadHeaderExporter::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 std::nullopt; + } + + write << "extern MovtexQuadCollection " << symbol << "[];\n"; + return std::nullopt; +} + +ExportResult SM64::MovtexQuadCodeExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + const auto offset = GetSafeNode(node, "offset"); + + auto quadData = std::static_pointer_cast(raw); + + write << "const struct MovtexQuadCollection " << symbol << "[] = {"; + + for (auto &quad: quadData->mMovtexQuads) { + write << "{" << quad.first << ", "; + if (quad.second == 0) { + write << "NULL"; + } else { + auto dec = Companion::Instance->GetNodeByAddr(quad.second); + if (dec.has_value()) { + auto movtexNode = std::get<1>(dec.value()); + auto movtexSymbol = GetSafeNode(movtexNode, "symbol"); + write << movtexSymbol; + } else { + SPDLOG_WARN("Could not find movtex at 0x{:X}", quad.second); + write << "0x" << std::hex << std::uppercase << quad.second << std::nouppercase << std::dec; + } + } + write << "},\n"; + } + + write << "\n};\n"; + + if (Companion::Instance->IsDebug()) { + write << "// MovtexQuad count: " << quadData->mMovtexQuads.size() << "\n"; + } + + return offset + quadData->mMovtexQuads.size() * 4; +} + +ExportResult SM64::MovtexQuadBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto quadData = std::static_pointer_cast(raw); + + WriteHeader(writer, LUS::ResourceType::MovtexQuad, 0); + writer.Write((uint32_t) quadData->mMovtexQuads.size()); + + for (auto &quad: quadData->mMovtexQuads) { + writer.Write(quad.first); + if (quad.second == 0) { + writer.Write((uint64_t) quad.second); + } else { + auto dec = Companion::Instance->GetNodeByAddr(quad.second); + if (dec.has_value()) { + uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); + SPDLOG_INFO("Found movtex: 0x{:X} Hash: 0x{:X} Path: {}", quad.second, hash, std::get<0>(dec.value())); + writer.Write(hash); + } else { + SPDLOG_WARN("Could not find movtex at 0x{:X}", quad.second); + } + } + write << "},\n"; + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional> SM64::MovtexQuadFactory::parse(std::vector& buffer, YAML::Node& node) { + const auto offset = GetSafeNode(node, "offset"); + const auto symbol = GetSafeNode(node, "symbol"); + const auto count = GetSafeNode(node, "count"); + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + LUS::BinaryReader reader(segment.data, segment.size); + reader.SetEndianness(LUS::Endianness::Big); + std::vector> movtexQuads; + + for (size_t i = 0; i < count; ++i) { + auto id = reader.ReadInt16(); + auto movtexPtr = reader.ReadUInt32(); + movtexQuads.emplace_back(std::make_pair(id, movtexPtr)); + + YAML::Node movtexNode; + movtexNode["type"] = "SM64:MOVTEX"; + movtexNode["offset"] = movtexPtr; + movtexNode["quad"] = true; + Companion::Instance->AddAsset(movtexNode); + } + + return std::make_shared(movtexQuads); +} diff --git a/src/factories/sm64/MovtexQuadFactory.h b/src/factories/sm64/MovtexQuadFactory.h new file mode 100644 index 0000000..806c080 --- /dev/null +++ b/src/factories/sm64/MovtexQuadFactory.h @@ -0,0 +1,38 @@ +#pragma once + +#include "factories/BaseFactory.h" +#include "types/Vec3D.h" + +namespace SM64 { + +class MovtexQuadData : public IParsedData { +public: + std::vector> mMovtexQuads; + + MovtexQuadData(std::vector> movtexQuads) : mMovtexQuads(std::move(movtexQuads)) {} +}; + +class MovtexQuadHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MovtexQuadBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MovtexQuadCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class MovtexQuadFactory : public BaseFactory { +public: + std::optional> parse(std::vector& buffer, YAML::Node& data) override; + inline std::unordered_map> GetExporters() override { + return { + REGISTER(Code, MovtexQuadCodeExporter) + REGISTER(Header, MovtexQuadHeaderExporter) + REGISTER(Binary, MovtexQuadBinaryExporter) + }; + } +}; +} -- cgit v1.2.3