summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Companion.cpp25
-rw-r--r--src/Companion.h4
-rw-r--r--src/factories/BaseFactory.h4
-rw-r--r--src/factories/sm64/AnimationFactory.cpp37
-rw-r--r--src/factories/sm64/CollisionFactory.cpp116
-rw-r--r--src/factories/sm64/CollisionFactory.h36
-rw-r--r--src/utils/Decompressor.cpp25
-rw-r--r--src/utils/Decompressor.h6
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);