diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Companion.cpp | 25 | ||||
| -rw-r--r-- | src/Companion.h | 4 | ||||
| -rw-r--r-- | src/factories/BaseFactory.h | 4 | ||||
| -rw-r--r-- | src/factories/sm64/AnimationFactory.cpp | 37 | ||||
| -rw-r--r-- | src/factories/sm64/CollisionFactory.cpp | 116 | ||||
| -rw-r--r-- | src/factories/sm64/CollisionFactory.h | 36 | ||||
| -rw-r--r-- | src/utils/Decompressor.cpp | 25 | ||||
| -rw-r--r-- | src/utils/Decompressor.h | 6 |
8 files changed, 222 insertions, 31 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp index 1f95e63..477edeb 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -32,6 +32,7 @@ #include "factories/sm64/DictionaryFactory.h" #include "factories/sm64/TextFactory.h" #include "factories/sm64/GeoLayoutFactory.h" +#include "factories/sm64/CollisionFactory.h" #include "factories/mk64/CourseVtx.h" #include "factories/mk64/Waypoints.h" @@ -85,6 +86,7 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("SM64:DICTIONARY", std::make_shared<SM64::DictionaryFactory>()); this->RegisterFactory("SM64:ANIM", std::make_shared<SM64::AnimationFactory>()); this->RegisterFactory("SM64:GEO_LAYOUT", std::make_shared<SM64::GeoLayoutFactory>()); + this->RegisterFactory("SM64:COLLISION", std::make_shared<SM64::CollisionFactory>()); // MK64 specific this->RegisterFactory("MK64:COURSE_VTX", std::make_shared<MK64::CourseVtxFactory>()); @@ -395,6 +397,14 @@ void Companion::ParseCurrentFileConfig(YAML::Node node) { this->gCurrentVram = { addr, offset }; } + if(node["dependencies"]) { + auto deps = node["dependencies"]; + for(auto dep = deps.begin(); dep != deps.end(); ++dep) { + this->gDependencies + this->gFileHeader += line->as<std::string>() + "\n"; + } + } + this->gEnablePadGen = GetSafeNode<bool>(node, "autopads", true); } @@ -991,6 +1001,21 @@ std::optional<std::string> Companion::GetEnumFromValue(const std::string& key, i return this->gEnums[key][id]; } +std::optional<uint32_t> Companion::GetValueFromEnum(const std::string& key, const std::string& value) { + if(!this->gEnums.contains(key)){ + return std::nullopt; + } + + for(auto& [id, name] : this->gEnums[key]){ + if(name == value){ + return id; + } + } + + return std::nullopt; +} + + std::optional<std::uint32_t> Companion::GetFileOffsetFromSegmentedAddr(const uint8_t segment) const { auto segments = this->gConfig.segment; diff --git a/src/Companion.h b/src/Companion.h index 748efbb..7dd9f16 100644 --- a/src/Companion.h +++ b/src/Companion.h @@ -97,6 +97,7 @@ public: GBIVersion GetGBIVersion() const { return this->gConfig.gbi.version; } GBIMinorVersion GetGBIMinorVersion() const { return this->gConfig.gbi.subversion; } std::optional<std::string> GetEnumFromValue(const std::string& key, int id); + std::optional<uint32_t> GetValueFromEnum(const std::string& key, const std::string& value); std::optional<std::uint32_t> GetFileOffsetFromSegmentedAddr(uint8_t segment) const; std::optional<std::tuple<std::string, YAML::Node>> GetNodeByAddr(uint32_t addr); @@ -137,9 +138,10 @@ private: std::optional<VRAMEntry> gCurrentVram; CompressionType gCurrentCompressionType = CompressionType::None; std::vector<Table> gTables; + std::vector<std::string> gDependencies; + std::unordered_map<std::string, std::string> gModdedAssetPaths; std::variant<std::vector<std::string>, std::string> gWriteOrder; std::unordered_map<std::string, std::shared_ptr<BaseFactory>> gFactories; - std::unordered_map<std::string, std::string> gModdedAssetPaths; std::unordered_map<std::string, std::map<std::string, std::vector<WriteEntry>>> gWriteMap; std::unordered_map<std::string, std::map<std::string, std::pair<YAML::Node, bool>>> gAssetDependencies; std::unordered_map<std::string, std::unordered_map<uint32_t, std::tuple<std::string, YAML::Node>>> gAddrMap; diff --git a/src/factories/BaseFactory.h b/src/factories/BaseFactory.h index 18c03ef..c30bb92 100644 --- a/src/factories/BaseFactory.h +++ b/src/factories/BaseFactory.h @@ -81,12 +81,16 @@ public: class BaseExporter { public: + virtual ~BaseExporter() = default; + virtual ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) = 0; static void WriteHeader(LUS::BinaryWriter& write, LUS::ResourceType resType, int32_t version); }; class BaseFactory { public: + virtual ~BaseFactory() = default; + virtual std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) = 0; virtual std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) { return std::nullopt; diff --git a/src/factories/sm64/AnimationFactory.cpp b/src/factories/sm64/AnimationFactory.cpp index 1b4070d..3174cd5 100644 --- a/src/factories/sm64/AnimationFactory.cpp +++ b/src/factories/sm64/AnimationFactory.cpp @@ -1,6 +1,10 @@ #include "AnimationFactory.h" + +#include <utils/Decompressor.h> #include "spdlog/spdlog.h" +#define ANIM_INDEX_COUNT(boneCount) ((boneCount) + 1) * 2 * 6 + ExportResult SM64::AnimationBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { auto writer = LUS::BinaryWriter(); const auto anim = std::static_pointer_cast<AnimationData>(raw); @@ -29,11 +33,7 @@ ExportResult SM64::AnimationBinaryExporter::Export(std::ostream &write, std::sha } std::optional<std::shared_ptr<IParsedData>> SM64::AnimationFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { - auto headerNode = GetSafeNode<YAML::Node>(node, "header"); - auto valuesNode = GetSafeNode<YAML::Node>(node, "values"); - auto indexNode = GetSafeNode<YAML::Node>(node, "indices"); - - LUS::BinaryReader header(reinterpret_cast<char *>(buffer.data()) + GetSafeNode<uint32_t>(headerNode, "offset"), GetSafeNode<uint32_t>(headerNode, "size")); + auto header = Decompressor::AutoDecode(node, buffer).GetReader(); header.SetEndianness(LUS::Endianness::Big); auto flags = header.ReadInt16(); @@ -42,26 +42,27 @@ std::optional<std::shared_ptr<IParsedData>> SM64::AnimationFactory::parse(std::v auto loopStart = header.ReadInt16(); auto loopEnd = header.ReadInt16(); auto unusedBoneCount = header.ReadInt16(); - header.ReadUInt32(); - header.ReadUInt32(); + auto valuesAddr = header.ReadUInt32(); + auto indicesAddr = header.ReadUInt32(); auto length = header.ReadUInt32(); - LUS::BinaryReader indices(reinterpret_cast<char*>(buffer.data()) + GetSafeNode<uint32_t>(indexNode, "offset"), GetSafeNode<uint32_t>(indexNode, "size")); - indices.SetEndianness(LUS::Endianness::Big); - size_t indexLength = GetSafeNode<uint32_t>(indexNode, "size") / sizeof(int16_t); - std::vector<int16_t> indicesData; - for (size_t i = 0; i < indexLength; i++) { - indicesData.push_back(indices.ReadInt16()); - } + auto values = Decompressor::AutoDecodeByOffset(valuesAddr, indicesAddr - valuesAddr, buffer).GetReader(); + values.SetEndianness(LUS::Endianness::Big); - LUS::BinaryReader values(reinterpret_cast<char*>(buffer.data()) + GetSafeNode<uint32_t>(valuesNode, "offset"), GetSafeNode<uint32_t>(valuesNode, "size")); - values.SetEndianness(LUS::Endianness::Big); - size_t entries = GetSafeNode<uint32_t>(valuesNode, "size") / sizeof(uint16_t); std::vector<uint16_t> valuesData; - for (size_t i = 0; i < entries; i++) { + for (size_t i = 0; i < values.GetLength() / sizeof(uint16_t); i++) { valuesData.push_back(values.ReadUInt16()); } + auto indicesCount = ANIM_INDEX_COUNT(unusedBoneCount); + auto indices = Decompressor::AutoDecodeByOffset(indicesAddr, indicesCount * sizeof(int16_t), buffer).GetReader(); + indices.SetEndianness(LUS::Endianness::Big); + + std::vector<int16_t> indicesData; + for (size_t i = 0; i < indicesCount; i++) { + indicesData.push_back(indices.ReadInt16()); + } + SPDLOG_INFO("Flags: {}", flags); SPDLOG_INFO("Anim-Y Trans Divisor: {}", animYTransDivisor); SPDLOG_INFO("Start Frame: {}", startFrame); diff --git a/src/factories/sm64/CollisionFactory.cpp b/src/factories/sm64/CollisionFactory.cpp new file mode 100644 index 0000000..71b75d2 --- /dev/null +++ b/src/factories/sm64/CollisionFactory.cpp @@ -0,0 +1,116 @@ +#include "CollisionFactory.h" + +#include <Companion.h> +#include <utils/Decompressor.h> + +#define BASE(val, cmd, enumname) val == Companion::Instance->GetValueFromEnum(enumname, cmd) + +#define COL_INIT(v) BASE(v, "TERRAIN_LOAD_VERTICES", "TerrainLoadCommands") +#define COL_TRI_STOP(v) BASE(v, "TERRAIN_LOAD_END", "TerrainLoadCommands") +#define COL_TRI_INIT(surf) BASE(v, surf, "SurfaceTypes") + +#define SURFACE_TYPE(type) Companion::Instance->GetEnumFromValue("SurfaceTypes", type).value_or(std::to_string(type)) + +enum class ProcessingState { + None, + Vertex, + Triangle, + Special +}; + +ExportResult SM64::CollisionCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto symbol = GetSafeNode(node, "symbol", entryName); + auto collision = std::static_pointer_cast<CollisionData>(raw); + + size_t cmd_size = collision->mCommandList.size(); + ProcessingState state = ProcessingState::None; + + size_t vtxCount = 0; + + for(size_t i = 0; i < collision->mCommandList.size(); i++){ + auto cmd = collision->mCommandList[i]; + + if(COL_INIT(cmd)){ + vtxCount = collision->mCommandList[++i]; + write << "COL_INIT(),\n"; + write << "COL_VERTEX_INIT(" << vtxCount << "),\n"; + state = ProcessingState::Vertex; + continue; + } + + switch(state) { + case ProcessingState::Vertex: + if(vtxCount > 0){ + auto x = collision->mCommandList[i + 0]; + auto y = collision->mCommandList[i + 1]; + auto z = collision->mCommandList[i + 2]; + + write << "COL_VERTEX(" << x << ", " << y << ", " << z << "),\n"; + vtxCount--; + } else { + int32_t surf = collision->mCommandList[i]; + auto triCount = collision->mCommandList[++i]; + + write << "COL_TRI_INIT(" << SURFACE_TYPE(surf) << ", " << triCount << "),\n"; + state = ProcessingState::Triangle; + } + break; + case ProcessingState::Triangle: + if(!COL_TRI_STOP(cmd)){ + auto v1 = collision->mCommandList[i + 0]; + auto v2 = collision->mCommandList[i + 1]; + auto v3 = collision->mCommandList[i + 2]; + + write << "COL_TRI(" << v1 << ", " << v2 << ", " << v3 << "),\n"; + } else { + write << "COL_TRI_STOP(),\n"; + state = ProcessingState::None; + } + break; + } + + if(state == ProcessingState::Vertex){ + + continue; + } + + + } + + return offset + cmd_size * sizeof(int16_t); +} + + +ExportResult SM64::CollisionHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + auto collision = std::static_pointer_cast<CollisionData>(raw); + + return std::nullopt; +} + +ExportResult SM64::CollisionBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + auto collision = std::static_pointer_cast<CollisionData>(raw); + + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> SM64::CollisionFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto [root, segment] = Decompressor::AutoDecode(node, buffer); + + LUS::BinaryReader reader(segment.data, segment.size); + reader.SetEndianness(LUS::Endianness::Big); + std::vector<int16_t> commands; + bool processing = true; + + while(processing){ + auto cmd = reader.ReadInt16(); + + if(COL_TRI_STOP(cmd)){ + processing = false; + } + + commands.push_back(cmd); + } + + return std::nullopt; +}
\ No newline at end of file diff --git a/src/factories/sm64/CollisionFactory.h b/src/factories/sm64/CollisionFactory.h new file mode 100644 index 0000000..f4bfab4 --- /dev/null +++ b/src/factories/sm64/CollisionFactory.h @@ -0,0 +1,36 @@ +#pragma once + +#include "../BaseFactory.h" + +namespace SM64 { +class CollisionData : public IParsedData { +public: + std::vector<int16_t> mCommandList; + + CollisionData(std::vector<int16_t>& commandList) : mCommandList(commandList) {} +}; + +class CollisionCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class CollisionHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class CollisionBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class CollisionFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Code, CollisionCodeExporter) + REGISTER(Header, CollisionHeaderExporter) + REGISTER(Binary, CollisionBinaryExporter) + }; + } +}; +}
\ No newline at end of file diff --git a/src/utils/Decompressor.cpp b/src/utils/Decompressor.cpp index c59d867..7c63c09 100644 --- a/src/utils/Decompressor.cpp +++ b/src/utils/Decompressor.cpp @@ -43,12 +43,9 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector<uint8_t> auto offset = node["offset"].as<uint32_t>(); - CompressionType type = Companion::Instance->GetCurrCompressionType(); - - switch(type) { - case CompressionType::MIO0: - { - auto fileOffset = TranslateAddr(offset, true); + switch(Companion::Instance->GetCurrCompressionType()) { + case CompressionType::MIO0: { + const auto fileOffset = TranslateAddr(offset, true); offset = ASSET_PTR(offset); auto decoded = Decode(buffer, fileOffset, CompressionType::MIO0); @@ -60,15 +57,12 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector<uint8_t> } case CompressionType::YAY0: throw std::runtime_error("Found compressed yay0 segment.\nDecompression of yay0 has not been implemented yet."); - break; case CompressionType::YAZ0: throw std::runtime_error("Found compressed yaz0 segment.\nDecompression of yaz0 has not been implemented yet."); - break; - case CompressionType::None: - { - auto fileOffset = TranslateAddr(offset); + case CompressionType::None: { + const auto fileOffset = TranslateAddr(offset); - auto size = node["size"] ? node["size"].as<size_t>() : manualSize.value_or(buffer.size() - fileOffset); + const auto size = node["size"] ? node["size"].as<size_t>() : manualSize.value_or(buffer.size() - fileOffset); return { .root = nullptr, @@ -80,6 +74,13 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector<uint8_t> throw std::runtime_error("Auto decode could not find a compression type nor uncompressed segment.\nThis is one of those issues that should never really happen."); } +DecompressedData Decompressor::AutoDecodeByOffset(uint32_t offset, size_t size, std::vector<uint8_t>& buffer) { + YAML::Node node; + node["offset"] = offset; + node["size"] = size; + return AutoDecode(node, buffer); +} + uint32_t Decompressor::TranslateAddr(uint32_t addr, bool baseAddress){ if(IS_SEGMENTED(addr)){ const auto segment = Companion::Instance->GetFileOffsetFromSegmentedAddr(SEGMENT_NUMBER(addr)); diff --git a/src/utils/Decompressor.h b/src/utils/Decompressor.h index 0cb5a01..093b12c 100644 --- a/src/utils/Decompressor.h +++ b/src/utils/Decompressor.h @@ -1,5 +1,6 @@ #pragma once +#include <BinaryReader.h> #include <vector> #include <cstdint> #include <unordered_map> @@ -23,12 +24,17 @@ struct DataChunk { struct DecompressedData { DataChunk* root; DataChunk segment; + + LUS::BinaryReader GetReader() const { + return LUS::BinaryReader(segment.data, segment.size); + } }; class Decompressor { public: static DataChunk* Decode(const std::vector<uint8_t>& buffer, uint32_t offset, CompressionType type); static DecompressedData AutoDecode(YAML::Node& node, std::vector<uint8_t>& buffer, std::optional<size_t> size = std::nullopt); + static DecompressedData AutoDecodeByOffset(uint32_t offset, size_t size, std::vector<uint8_t>& buffer); static uint32_t TranslateAddr(uint32_t addr, bool baseAddress = false); static bool IsSegmented(uint32_t addr); |
