summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMegaMech <MegaMech@users.noreply.github.com>2024-03-23 01:57:53 -0600
committerGitHub <noreply@github.com>2024-03-23 01:57:53 -0600
commitcd7dd6f59a9b0ffb867fcd7b80a6c05def701088 (patch)
tree8c07c17342f850dbad89dd77f215f179572e6db6
parent5c6fa9c1f6ad4b07426a6f360ccf2d54b0c94cb8 (diff)
Add Mtx, float, and mk64 Factories (#43)
* Create MtxFactory.cpp * Add mtx factory * Implement mtx output * Changed implementation * Update comment * Finish Mtx factory * Add float factory * Add runtime error for untested code * Add DrivingBehaviour factory & fix bug * Remove limit * Add mk64 graphics * Changes * fix * Update * Improve error checking
-rw-r--r--lib/n64graphics/n64graphics.c7
-rw-r--r--src/Companion.cpp6
-rw-r--r--src/factories/BaseFactory.h6
-rw-r--r--src/factories/FloatFactory.cpp102
-rw-r--r--src/factories/FloatFactory.h37
-rw-r--r--src/factories/MtxFactory.cpp207
-rw-r--r--src/factories/MtxFactory.h41
-rw-r--r--src/factories/ResourceType.h2
-rw-r--r--src/factories/mk64/DrivingBehaviour.cpp98
-rw-r--r--src/factories/mk64/DrivingBehaviour.h46
10 files changed, 545 insertions, 7 deletions
diff --git a/lib/n64graphics/n64graphics.c b/lib/n64graphics/n64graphics.c
index 0ff7bc7..39db002 100644
--- a/lib/n64graphics/n64graphics.c
+++ b/lib/n64graphics/n64graphics.c
@@ -509,7 +509,7 @@ rgba* png2rgba(unsigned char* png_input, int size_input, int* width, int* height
}
rgb* png2rgb(unsigned char* png_input, int size_input, int* width, int* height) {
- rgba* img = NULL;
+ rgb* img = NULL;
int w = 0;
int h = 0;
int channels = 0;
@@ -538,11 +538,6 @@ rgb* png2rgb(unsigned char* png_input, int size_input, int* width, int* height)
img[idx].red = data[channels * idx];
img[idx].green = data[channels * idx + 1];
img[idx].blue = data[channels * idx + 2];
- if (channels == 4) {
- img[idx].alpha = data[channels * idx + 3];
- } else {
- img[idx].alpha = 0xFF;
- }
}
}
break;
diff --git a/src/Companion.cpp b/src/Companion.cpp
index 3d9d2b6..687941c 100644
--- a/src/Companion.cpp
+++ b/src/Companion.cpp
@@ -13,6 +13,8 @@
#include "factories/SampleFactory.h"
#include "factories/SequenceFactory.h"
#include "factories/VtxFactory.h"
+#include "factories/MtxFactory.h"
+#include "factories/FloatFactory.h"
#include "factories/TextureFactory.h"
#include "factories/DisplayListFactory.h"
#include "factories/DisplayListOverrides.h"
@@ -23,6 +25,7 @@
#include "factories/mk64/Waypoints.h"
#include "factories/mk64/TrackSections.h"
#include "factories/mk64/SpawnData.h"
+#include "factories/mk64/DrivingBehaviour.h"
#include "spdlog/spdlog.h"
#include "hj/sha1.h"
@@ -59,6 +62,8 @@ void Companion::Init(const ExportType type) {
this->RegisterFactory("BLOB", std::make_shared<BlobFactory>());
this->RegisterFactory("TEXTURE", std::make_shared<TextureFactory>());
this->RegisterFactory("VTX", std::make_shared<VtxFactory>());
+ this->RegisterFactory("MTX", std::make_shared<MtxFactory>());
+ this->RegisterFactory("F32", std::make_shared<FloatFactory>());
this->RegisterFactory("LIGHTS", std::make_shared<LightsFactory>());
this->RegisterFactory("GFX", std::make_shared<DListFactory>());
this->RegisterFactory("AUDIO:HEADER", std::make_shared<AudioHeaderFactory>());
@@ -79,6 +84,7 @@ void Companion::Init(const ExportType type) {
this->RegisterFactory("MK64:TRACK_WAYPOINTS", std::make_shared<MK64::WaypointsFactory>());
this->RegisterFactory("MK64:TRACK_SECTIONS", std::make_shared<MK64::TrackSectionsFactory>());
this->RegisterFactory("MK64:SPAWN_DATA", std::make_shared<MK64::SpawnDataFactory>());
+ this->RegisterFactory("MK64:DRIVING_BEHAVIOUR", std::make_shared<MK64::DrivingBehaviourFactory>());
// SF64 specific
this->RegisterFactory("SF64:ANIM", std::make_shared<SF64::AnimFactory>());
diff --git a/src/factories/BaseFactory.h b/src/factories/BaseFactory.h
index 1246c91..18c03ef 100644
--- a/src/factories/BaseFactory.h
+++ b/src/factories/BaseFactory.h
@@ -52,7 +52,11 @@ std::optional<T> GetNode(YAML::Node& node, const std::string& key) {
template<typename T>
T GetSafeNode(YAML::Node& node, const std::string& key) {
if(!node[key]) {
- throw std::runtime_error("Failed to find " + key + " in yaml");
+ if (node["symbol"]) {
+ throw std::runtime_error("Yaml asset missing the '" + key + "' node for '" + node["symbol"].as<std::string>() + "'");
+ } else {
+ throw std::runtime_error("Yaml asset missing the '" + key + "' node");
+ }
}
return node[key].as<T>();
diff --git a/src/factories/FloatFactory.cpp b/src/factories/FloatFactory.cpp
new file mode 100644
index 0000000..dfaf5a3
--- /dev/null
+++ b/src/factories/FloatFactory.cpp
@@ -0,0 +1,102 @@
+#include "FloatFactory.h"
+#include "spdlog/spdlog.h"
+
+#include "Companion.h"
+#include "utils/Decompressor.h"
+
+#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x
+#define COL(c) std::dec << std::setfill(' ') << std::setw(3) << c
+
+ExportResult FloatHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> 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 f32 " << symbol << "[];\n";
+ return std::nullopt;
+}
+
+ExportResult FloatCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto f = std::static_pointer_cast<FloatData>(raw)->mFloats;
+ const auto symbol = GetSafeNode(node, "symbol", entryName);
+ auto offset = GetSafeNode<uint32_t>(node, "offset");
+
+ if (IS_SEGMENTED(offset)) {
+ offset = SEGMENT_OFFSET(offset);
+ }
+
+ if (Companion::Instance->IsDebug()) {
+ if (IS_SEGMENTED(offset)) {
+ offset = SEGMENT_OFFSET(offset);
+ }
+ write << "// 0x" << std::hex << std::uppercase << offset << "\n";
+ }
+
+ write << "f32 " << symbol << "[] = {";
+
+ /**
+ * f32 sym[] = {
+ * 0.1, 0.2, 0.3,
+ * };
+ *
+ */
+ for (int i = 0; i < f.size(); ++i) {
+
+ // Make a new line every fourth iteration
+ if ((i % 4) == 0) {
+ write << "\n" << fourSpaceTab;
+ }
+
+ write << f[i] << ", ";
+
+ // if(i <= f.size() - 1) {
+ // write << fourSpaceTab;
+ // }
+ }
+
+ write << "\n};\n";
+
+ if (Companion::Instance->IsDebug()) {
+ write << "// count: " << std::to_string(f.size()) << " f32s\n";
+ write << "// 0x" << std::hex << std::uppercase << (offset + (sizeof(float) * f.size())) << "\n";
+ }
+
+ write << "\n";
+
+ return offset + f.size() * sizeof(float);
+}
+
+ExportResult FloatBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto f = std::static_pointer_cast<FloatData>(raw);
+ auto writer = LUS::BinaryWriter();
+
+ WriteHeader(writer, LUS::ResourceType::Float, 0);
+ writer.Write((uint32_t) f->mFloats.size());
+ for(auto fl : f->mFloats) {
+ writer.Write(fl);
+ }
+ throw std::runtime_error("Float factory untested for otr/o2r exporter");
+ writer.Finish(write);
+ return std::nullopt;
+}
+
+std::optional<std::shared_ptr<IParsedData>> FloatFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto count = GetSafeNode<size_t>(node, "count");
+
+ auto [_, segment] = Decompressor::AutoDecode(node, buffer);
+ LUS::BinaryReader reader(segment.data, count * sizeof(float));
+
+ reader.SetEndianness(LUS::Endianness::Big);
+ std::vector<float> floats;
+
+ for(size_t i = 0; i < count; i++) {
+ auto f = reader.ReadFloat();
+
+ floats.push_back(f);
+ }
+
+ return std::make_shared<FloatData>(floats);
+} \ No newline at end of file
diff --git a/src/factories/FloatFactory.h b/src/factories/FloatFactory.h
new file mode 100644
index 0000000..acd8525
--- /dev/null
+++ b/src/factories/FloatFactory.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "BaseFactory.h"
+
+class FloatData : public IParsedData {
+public:
+ std::vector<float> mFloats;
+
+ explicit FloatData(std::vector<float> floats) : mFloats(floats) {}
+};
+
+class FloatHeaderExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class FloatBinaryExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class FloatCodeExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class FloatFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
+ return std::nullopt;
+ }
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Code, FloatCodeExporter)
+ REGISTER(Header, FloatHeaderExporter)
+ REGISTER(Binary, FloatBinaryExporter)
+ };
+ }
+}; \ No newline at end of file
diff --git a/src/factories/MtxFactory.cpp b/src/factories/MtxFactory.cpp
new file mode 100644
index 0000000..cce6f99
--- /dev/null
+++ b/src/factories/MtxFactory.cpp
@@ -0,0 +1,207 @@
+#include "MtxFactory.h"
+#include "spdlog/spdlog.h"
+
+#include "Companion.h"
+#include "utils/Decompressor.h"
+
+#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x
+#define COL(c) std::dec << std::setfill(' ') << std::setw(3) << c
+
+ExportResult MtxHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> 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 Mtx " << symbol << "[];\n";
+ return std::nullopt;
+}
+
+ExportResult MtxCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto m = std::static_pointer_cast<MtxData>(raw)->mMtxs;
+ const auto symbol = GetSafeNode(node, "symbol", entryName);
+ auto offset = GetSafeNode<uint32_t>(node, "offset");
+
+ if (IS_SEGMENTED(offset)) {
+ offset = SEGMENT_OFFSET(offset);
+ }
+
+ if (Companion::Instance->IsDebug()) {
+ if (IS_SEGMENTED(offset)) {
+ offset = SEGMENT_OFFSET(offset);
+ }
+ write << "// 0x" << std::hex << std::uppercase << offset << "\n";
+ }
+
+ #define fiveFourSpaceTabs fourSpaceTab << fourSpaceTab << fourSpaceTab << fourSpaceTab << fourSpaceTab << " "
+
+ /**
+ * toFixedPointMatrix(1.0, 0.0, 0.0, 0.0,
+ * 0.0, 1.0, 0.0, 0.0,
+ * 0.0, 0.0, 1.0, 0.0,
+ * 0.0, 0.0, 0.0, 1.0);
+ */
+
+ write << "Mtx " << symbol << "[] = {\n";
+
+ for (int i = 0; i < m.size(); ++i) {
+
+ write << fourSpaceTab << "toFixedPointMatrix(";
+
+ for (int j = 0; j < 16; ++j) {
+
+ // Turn 1, 3, and 6 into 1.0, 3.0, and 6.0. Unless it has a decimal number then leave it alone.
+ if (std::abs(m[i].mtx[j] - static_cast<int>(m[i].mtx[j])) < 1e-6) {
+ write << std::fixed << std::setprecision(1) << m[i].mtx[j];
+ } else {
+ write << std::fixed << std::setprecision(6) << m[i].mtx[j];
+ }
+
+ // Add comma for all but the last arg
+ if (j < 15) {
+ write << ", ";
+ }
+
+ // Add closing bracket for last arg in matrix
+ if (j == 15) {
+ write << "),\n";
+
+ // Do not add an extra \n on the last iteration.
+ if (i < m.size() - 1) {
+ write << "\n";
+ }
+ break;
+ }
+
+ // Add lots of spaces for start of a new line
+ if ((j + 1) % 4 == 0) {
+ write << "\n" << fiveFourSpaceTabs;
+ }
+ }
+ }
+
+ write << "};\n";
+
+ if (Companion::Instance->IsDebug()) {
+ write << "// count: " << std::to_string(m.size()) << " Mtxs\n";
+ write << "// 0x" << std::hex << std::uppercase << (offset + (sizeof(MtxRaw) * m.size())) << "\n";
+ }
+
+ write << "\n";
+
+ #undef fiveFourSpaceTabs
+
+ return offset + m.size() * sizeof(MtxRaw);
+}
+
+ExportResult MtxBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto mtx = std::static_pointer_cast<MtxData>(raw);
+ auto writer = LUS::BinaryWriter();
+
+ WriteHeader(writer, LUS::ResourceType::Matrix, 0);
+ writer.Write((uint32_t) mtx->mMtxs.size());
+ for(auto m : mtx->mMtxs) {
+ writer.Write(m.mtx[0]);
+ writer.Write(m.mtx[1]);
+ writer.Write(m.mtx[2]);
+ writer.Write(m.mtx[3]);
+ writer.Write(m.mtx[4]);
+ writer.Write(m.mtx[5]);
+ writer.Write(m.mtx[6]);
+ writer.Write(m.mtx[7]);
+ writer.Write(m.mtx[8]);
+ writer.Write(m.mtx[9]);
+ writer.Write(m.mtx[10]);
+ writer.Write(m.mtx[11]);
+ writer.Write(m.mtx[12]);
+ writer.Write(m.mtx[13]);
+ writer.Write(m.mtx[14]);
+ writer.Write(m.mtx[15]);
+ }
+ throw std::runtime_error("Mtx not tested for otr/o2r.");
+ writer.Finish(write);
+ return std::nullopt;
+}
+
+std::optional<std::shared_ptr<IParsedData>> MtxFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto count = GetSafeNode<size_t>(node, "count");
+
+ auto [_, segment] = Decompressor::AutoDecode(node, buffer);
+ LUS::BinaryReader reader(segment.data, count * sizeof(MtxRaw));
+
+ reader.SetEndianness(LUS::Endianness::Big);
+ std::vector<MtxRaw> matrix;
+
+ #define FIXTOF(x) ((double)((x) / 65536.0))
+
+ // Reads the inteer portion, the fractional portion, puts each together into a fixed-point value, and finally converts to float.
+ for(size_t i = 0; i < count; i++) {
+ // Read the integer portion of the fixed-point value (ex. 4)
+ auto i1 = reader.ReadInt16();
+ auto i2 = reader.ReadInt16();
+ auto i3 = reader.ReadInt16();
+ auto i4 = reader.ReadInt16();
+ auto i5 = reader.ReadInt16();
+ auto i6 = reader.ReadInt16();
+ auto i7 = reader.ReadInt16();
+ auto i8 = reader.ReadInt16();
+ auto i9 = reader.ReadInt16();
+ auto i10 = reader.ReadInt16();
+ auto i11 = reader.ReadInt16();
+ auto i12 = reader.ReadInt16();
+ auto i13 = reader.ReadInt16();
+ auto i14 = reader.ReadInt16();
+ auto i15 = reader.ReadInt16();
+ auto i16 = reader.ReadInt16();
+
+ // Read the fractional portion of the fixed-point value (ex. 0.45)
+ auto f1 = reader.ReadUInt16();
+ auto f2 = reader.ReadUInt16();
+ auto f3 = reader.ReadUInt16();
+ auto f4 = reader.ReadUInt16();
+ auto f5 = reader.ReadUInt16();
+ auto f6 = reader.ReadUInt16();
+ auto f7 = reader.ReadUInt16();
+ auto f8 = reader.ReadUInt16();
+ auto f9 = reader.ReadUInt16();
+ auto f10 = reader.ReadUInt16();
+ auto f11 = reader.ReadUInt16();
+ auto f12 = reader.ReadUInt16();
+ auto f13 = reader.ReadUInt16();
+ auto f14 = reader.ReadUInt16();
+ auto f15 = reader.ReadUInt16();
+ auto f16 = reader.ReadUInt16();
+
+ // Place the integer and fractional portions together (ex 4.45) and convert to floating-point
+ auto m1 = FIXTOF( (int32_t) ( (i1 << 16) | f1 ) );
+ auto m2 = FIXTOF( (int32_t) ( (i2 << 16) | f2 ) );
+ auto m3 = FIXTOF( (int32_t) ( (i3 << 16) | f3 ) );
+ auto m4 = FIXTOF( (int32_t) ( (i4 << 16) | f4 ) );
+ auto m5 = FIXTOF( (int32_t) ( (i5 << 16) | f5 ) );
+ auto m6 = FIXTOF( (int32_t) ( (i6 << 16) | f6 ) );
+ auto m7 = FIXTOF( (int32_t) ( (i7 << 16) | f7 ) );
+ auto m8 = FIXTOF( (int32_t) ( (i8 << 16) | f8 ) );
+ auto m9 = FIXTOF( (int32_t) ( (i9 << 16) | f9 ) );
+ auto m10 = FIXTOF( (int32_t) ( (i10 << 16) | f10 ) );
+ auto m11 = FIXTOF( (int32_t) ( (i11 << 16) | f11 ) );
+ auto m12 = FIXTOF( (int32_t) ( (i12 << 16) | f12 ) );
+ auto m13 = FIXTOF( (int32_t) ( (i13 << 16) | f13 ) );
+ auto m14 = FIXTOF( (int32_t) ( (i14 << 16) | f14 ) );
+ auto m15 = FIXTOF( (int32_t) ( (i15 << 16) | f15 ) );
+ auto m16 = FIXTOF( (int32_t) ( (i16 << 16) | f16 ) );
+
+
+ matrix.push_back(MtxRaw({
+ m1, m2, m3, m4,
+ m5, m6, m7, m8,
+ m9, m10, m11, m12,
+ m13, m14, m15, m16,
+ }));
+ }
+
+ #undef FIXTOF
+
+ return std::make_shared<MtxData>(matrix);
+}
diff --git a/src/factories/MtxFactory.h b/src/factories/MtxFactory.h
new file mode 100644
index 0000000..cad0ed2
--- /dev/null
+++ b/src/factories/MtxFactory.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "BaseFactory.h"
+
+struct MtxRaw {
+ double mtx[16];
+};
+
+class MtxData : public IParsedData {
+public:
+ std::vector<MtxRaw> mMtxs;
+
+ explicit MtxData(std::vector<MtxRaw> mtxs) : mMtxs(mtxs) {}
+};
+
+class MtxHeaderExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class MtxBinaryExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class MtxCodeExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class MtxFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
+ return std::nullopt;
+ }
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Code, MtxCodeExporter)
+ REGISTER(Header, MtxHeaderExporter)
+ REGISTER(Binary, MtxBinaryExporter)
+ };
+ }
+}; \ No newline at end of file
diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h
index 85acd48..a10dde0 100644
--- a/src/factories/ResourceType.h
+++ b/src/factories/ResourceType.h
@@ -11,6 +11,7 @@ enum class ResourceType {
DisplayList = 0x4F444C54, // ODLT
Vertex = 0x4F565458, // OVTX
Matrix = 0x4F4D5458, // OMTX
+ Float = 0x4F464C54, // OFLT
Array = 0x4F415252, // OARR
Blob = 0x4F424C42, // OBLB
Texture = 0x4F544558, // OTEX
@@ -31,6 +32,7 @@ enum class ResourceType {
Waypoints = 0x57505453, // WPTS
Metadata = 0x4D444154, // MDAT
SpawnData = 0x53444154, // SDAT
+ DrivingBehaviour = 0x44424856, // DBHV
// SF64
AnimData = 0x414E494D, // ANIM
diff --git a/src/factories/mk64/DrivingBehaviour.cpp b/src/factories/mk64/DrivingBehaviour.cpp
new file mode 100644
index 0000000..76e355a
--- /dev/null
+++ b/src/factories/mk64/DrivingBehaviour.cpp
@@ -0,0 +1,98 @@
+#include "DrivingBehaviour.h"
+#include "spdlog/spdlog.h"
+
+#include "Companion.h"
+#include "utils/Decompressor.h"
+
+#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x
+#define COL(c) std::dec << std::setfill(' ') << std::setw(3) << c
+
+ExportResult MK64::DrivingBehaviourHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> 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 DrivingBehaviour " << symbol << "[];\n";
+ return std::nullopt;
+}
+
+ExportResult MK64::DrivingBehaviourCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto bhv = std::static_pointer_cast<DrivingData>(raw);
+ const auto symbol = GetSafeNode(node, "symbol", entryName);
+ auto offset = GetSafeNode<uint32_t>(node, "offset");
+
+ if (IS_SEGMENTED(offset)) {
+ offset = SEGMENT_OFFSET(offset);
+ }
+
+ if (Companion::Instance->IsDebug()) {
+ if (IS_SEGMENTED(offset)) {
+ offset = SEGMENT_OFFSET(offset);
+ }
+ write << "// 0x" << std::hex << std::uppercase << offset << "\n";
+ }
+
+ write << "DrivingBehaviour " << symbol << "[] = {\n";
+
+
+ for(auto b : bhv->mBhvs) {
+ auto w1 = b.waypoint1;
+ auto w2 = b.waypoint2;
+ auto id = b.bhv;
+
+ // { w1, w2, bhvId}
+ write << fourSpaceTab << "{" << NUM(w1) << ", " << NUM(w2) << ", " << NUM(id) << "},\n";
+ }
+
+ write << "};\n";
+
+ if (Companion::Instance->IsDebug()) {
+ write << "// count: " << std::to_string(bhv->mBhvs.size()) << " Entries\n";
+ write << "// 0x" << std::hex << std::uppercase << (offset + (sizeof(BhvRaw) * bhv->mBhvs.size())) << "\n";
+ }
+
+ write << "\n";
+ return offset + bhv->mBhvs.size() * sizeof(BhvRaw);
+}
+
+ExportResult MK64::DrivingBehaviourBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto bhv = std::static_pointer_cast<DrivingData>(raw);
+ auto writer = LUS::BinaryWriter();
+
+ WriteHeader(writer, LUS::ResourceType::DrivingBehaviour, 0);
+ writer.Write((uint32_t) bhv->mBhvs.size());
+ for(auto b : bhv->mBhvs) {
+ writer.Write(b.waypoint1);
+ writer.Write(b.waypoint2);
+ writer.Write(b.bhv);
+ }
+
+ writer.Finish(write);
+ return std::nullopt;
+}
+
+std::optional<std::shared_ptr<IParsedData>> MK64::DrivingBehaviourFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto [_, segment] = Decompressor::AutoDecode(node, buffer);
+ LUS::BinaryReader reader(segment.data, segment.size);
+
+ reader.SetEndianness(LUS::Endianness::Big);
+ std::vector<BhvRaw> behaviours;
+
+ while(1) {
+ auto w1 = reader.ReadInt16();
+ auto w2 = reader.ReadInt16();
+ auto id = reader.ReadInt32();
+
+ behaviours.push_back( BhvRaw( {w1, w2, id} ) );
+
+ // Magic number for ending of array
+ if ((w1 == -1) && (w2 == -1)) {
+ break;
+ }
+ }
+
+ return std::make_shared<DrivingData>(behaviours);
+} \ No newline at end of file
diff --git a/src/factories/mk64/DrivingBehaviour.h b/src/factories/mk64/DrivingBehaviour.h
new file mode 100644
index 0000000..c4fd46e
--- /dev/null
+++ b/src/factories/mk64/DrivingBehaviour.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "../BaseFactory.h"
+
+namespace MK64 {
+
+ struct BhvRaw {
+ int16_t waypoint1;
+ int16_t waypoint2;
+ int32_t bhv;
+ };
+
+ class DrivingData : public IParsedData {
+ public:
+ std::vector<BhvRaw> mBhvs;
+
+ explicit DrivingData(std::vector<BhvRaw> bhvs) : mBhvs(bhvs) {}
+ };
+
+ class DrivingBehaviourHeaderExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class DrivingBehaviourBinaryExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class DrivingBehaviourCodeExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class DrivingBehaviourFactory : public BaseFactory {
+ public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ std::optional<std::shared_ptr<IParsedData>> parse_modding(std::vector<uint8_t>& buffer, YAML::Node& data) override {
+ return std::nullopt;
+ }
+ inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Code, DrivingBehaviourCodeExporter)
+ REGISTER(Header, DrivingBehaviourHeaderExporter)
+ REGISTER(Binary, DrivingBehaviourBinaryExporter)
+ };
+ }
+ };
+} \ No newline at end of file