summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMegaMech <MegaMech@users.noreply.github.com>2024-04-06 15:36:03 -0600
committerGitHub <noreply@github.com>2024-04-06 15:36:03 -0600
commit24633ebd7cc6866da3e3d06fddc6f0f49a741f1d (patch)
tree357a563fae006b04ded941ee534b1d6522f3fc32
parentad667b705dad3476a1ae803f23588c55baab2ee4 (diff)
Introduce Metadata and ItemCurve Factories (#27)
* Introduce metadata * Metadata works now * Cleanup * Fixes * Cleanup 2 * yaml improvement * Comment update * Rename tables to metadata * Update * Fix warnings * Implement ItemCurve * Remove unused enum * Replace static with const * Fix bug * Add const * More fixes * Fix quote bug in IncludeFactory * Fix header in ItemCurve * Fixes * Fix texture factory * updates * Clearer debug info * Fixes * Working ci8 png * Fix size output * Fix * Add gitignore for modding * Fix precision for mtx * Remove header exporter from metadata * Remove hardcoded enum * Remove tabs * Remove tabs * tlut temp fix --------- Co-authored-by: = <=>
-rw-r--r--.gitignore3
-rw-r--r--lib/n64graphics/n64graphics.c115
-rw-r--r--lib/n64graphics/n64graphics.h10
-rw-r--r--src/Companion.cpp57
-rw-r--r--src/Companion.h8
-rw-r--r--src/factories/DisplayListFactory.cpp39
-rw-r--r--src/factories/GenericArrayFactory.cpp23
-rw-r--r--src/factories/GenericArrayFactory.h4
-rw-r--r--src/factories/IncludeFactory.cpp2
-rw-r--r--src/factories/LightsFactory.cpp2
-rw-r--r--src/factories/MtxFactory.cpp16
-rw-r--r--src/factories/MtxFactory.h2
-rw-r--r--src/factories/TextureFactory.cpp99
-rw-r--r--src/factories/VtxFactory.cpp2
-rw-r--r--src/factories/mk64/CourseMetadata.cpp375
-rw-r--r--src/factories/mk64/CourseMetadata.h70
-rw-r--r--src/factories/mk64/DrivingBehaviour.cpp4
-rw-r--r--src/factories/mk64/ItemCurve.cpp94
-rw-r--r--src/factories/mk64/ItemCurve.h42
-rw-r--r--src/types/Vec3D.cpp17
-rw-r--r--src/types/Vec3D.h11
-rw-r--r--src/utils/Decompressor.cpp2
22 files changed, 921 insertions, 76 deletions
diff --git a/.gitignore b/.gitignore
index be72f4d..6a42dc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,5 @@ headers/
build/
code/
.vscode/
-tools/ \ No newline at end of file
+tools/
+modding/* \ No newline at end of file
diff --git a/lib/n64graphics/n64graphics.c b/lib/n64graphics/n64graphics.c
index 39db002..9008bab 100644
--- a/lib/n64graphics/n64graphics.c
+++ b/lib/n64graphics/n64graphics.c
@@ -25,6 +25,8 @@
#define SCALE_3_8(VAL_) ((VAL_) * 0x24)
#define SCALE_8_3(VAL_) ((VAL_) / 0x24)
+unsigned short magicFiller = 0x07FE;
+
typedef struct {
enum {
IMG_FORMAT_RGBA,
@@ -125,8 +127,8 @@ ia* raw2ia(const uint8_t* raw, int width, int height, int depth) {
return img;
}
-ci* raw2ci_torch(const uint8_t* raw, int width, int height, int depth) {
- ci* img = NULL;
+ci *raw2ci_torch(const uint8_t* raw, int width, int height, int depth) {
+ ci *img = NULL;
int img_size;
img_size = width * height * sizeof(*img);
@@ -308,6 +310,79 @@ int ia2raw(uint8_t* raw, const ia* img, int width, int height, int depth) {
return size;
}
+
+/**
+ * Check 2 rgba structs for equality. 0 if unequal, 1 if equal
+**/
+int comp_rgba(const rgba left, const rgba right) {
+ if ((left.red != right.red) || (left.green != right.green) || (left.blue != right.blue) || (left.alpha != right.alpha)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ * Check if a given rgba (comp) is in a given palette (pal, represented as an array of rgba structs)
+ * If found, return the index in pal it was found out
+ * Otherwise, return -1
+**/
+int get_color_index(const rgba comp, const rgba *pal, int mask_value, int pal_size) {
+ int pal_idx;
+ // The starting values used here are super specific to MK64, they're not really portable to anything else
+ if (mask_value == 0) {
+ pal_idx = 0;
+ } else {
+ pal_idx = 0xC0;
+ }
+ for (; pal_idx < pal_size; pal_idx++) {
+ if (comp_rgba(comp, pal[pal_idx]) == 1) return pal_idx;
+ }
+ ERROR("Could not find a color in the palette\n");
+ ERROR("comp: %x%x%x%x\n", comp.red, comp.green, comp.blue, comp.alpha);
+ return -1;
+}
+
+/**
+ * Takes an image (img, an array of rgba structs) and a palette (pal, also an array of rgba structs)
+ * Sets the values of rawci (8 bit color index array) to the appropriate index in pal that each entry in img can be found at
+ * If a value in img is not found in pal, return 0, indicating an error
+ * Returns 1 if all values in img are found somewhere in pal
+**/
+int imgpal2rawci(uint8_t *rawci, const rgba *img, const rgba *pal, const uint8_t *wheel_mask, int raw_size, int ci_depth, int img_size, int pal_size) {
+ int img_idx;
+ int pal_idx;
+ int mask_value;
+ memset(rawci, 0, raw_size);
+
+ for (img_idx = 0; img_idx < img_size; img_idx++) {
+ if (wheel_mask != NULL) {
+ mask_value = wheel_mask[img_idx];
+ } else {
+ mask_value = 0;
+ }
+ pal_idx = get_color_index(img[img_idx], pal, mask_value, pal_size);
+ if (pal_idx != -1) {
+ switch (ci_depth) {
+ case 8:
+ rawci[img_idx] = pal_idx;
+ break;
+ case 4:
+ {
+ int byte_idx = img_idx / 2;
+ int nibble = 1 - (img_idx % 2);
+ uint8_t mask = 0xF << (4 * (1 - nibble));
+ rawci[byte_idx] = (rawci[byte_idx] & mask) | (pal_idx << (4 * nibble));
+ break;
+ }
+ }
+ } else {
+ return 0;
+ }
+ }
+ return 1;
+}
+
int i2raw(uint8_t* raw, const ia* img, int width, int height, int depth) {
int size = width * height * depth / 8;
INFO("Converting I%d %dx%d to raw\n", depth, width, height);
@@ -338,7 +413,7 @@ int i2raw(uint8_t* raw, const ia* img, int width, int height, int depth) {
return size;
}
-int ci2raw_torch(uint8_t* raw, const ci* img, int width, int height, int depth) {
+int ci2raw_torch(uint8_t *raw, const ci *img, int width, int height, int depth) {
int size = width * height * depth / 8;
INFO("Converting I%d %dx%d to raw\n", depth, width, height);
@@ -420,7 +495,7 @@ int ia2png(unsigned char** png_output, int* size_output, const ia* img, int widt
return ret;
}
-int ci2png(unsigned char** png_output, int* size_output, const ci* img, int width, int height) {
+int ci2png(unsigned char **png_output, int *size_output, const ci *img, int width, int height) {
int ret = 0;
// convert to format stb_image_write expects
@@ -743,4 +818,36 @@ const char* n64graphics_get_read_version(void) {
const char* n64graphics_get_write_version(void) {
return "stb_image_write 1.09";
+}
+
+/**
+ * Converts binary ci8 + palette to a single .png
+ */
+int convert_raw_to_ci8(unsigned char **png_output, int *size_output, uint8_t *texture, uint8_t *palette, int format, int width, int height, int depth) {
+FILE *pal_fp;
+ uint8_t *pal;
+ uint8_t *raw_fmt;
+ rgba *imgr;
+ ia *imgi;
+ int pal_size;
+ int res;
+
+ raw_fmt = ci2raw(texture, palette, width, height, depth);
+ switch (format) {
+ case IMG_FORMAT_RGBA:
+ INFO("Converting raw to RGBA16\n");
+ imgr = raw2rgba(raw_fmt, width, height, depth);
+ res = rgba2png(png_output, size_output, imgr, width, height);
+ break;
+ case IMG_FORMAT_IA:
+ INFO("Converting raw to IA16\n");
+ imgi = raw2ia(raw_fmt, width, height, depth);
+ //res = ia2png(name, imgi, width, height);
+ break;
+ default:
+ //ERROR("Unsupported palette format: %s\n", format2str(&config.pal_format));
+ return EXIT_FAILURE;
+ }
+ free(raw_fmt);
+ free(pal);
} \ No newline at end of file
diff --git a/lib/n64graphics/n64graphics.h b/lib/n64graphics/n64graphics.h
index 225169e..1488f79 100644
--- a/lib/n64graphics/n64graphics.h
+++ b/lib/n64graphics/n64graphics.h
@@ -51,7 +51,11 @@ ia *raw2ia(const uint8_t *raw, int width, int height, int depth);
ia *raw2i(const uint8_t *raw, int width, int height, int depth);
// N64 raw CI4/CI8 -> intermediate CI
-ci* raw2ci_torch(const uint8_t* raw, int width, int height, int depth);
+ci *raw2ci_torch(const uint8_t* raw, int width, int height, int depth);
+
+int convert_raw_to_ci8(unsigned char **png_output, int *size_output, uint8_t *texture, uint8_t *palette, int format, int width, int height, int depth);
+
+int imgpal2rawci(uint8_t *rawci, const rgba *img, const rgba *pal, const uint8_t *wheel_mask, int raw_size, int ci_depth, int img_size, int pal_size);
//---------------------------------------------------------
// intermediate RGBA/IA -> N64 RGBA/IA/I/CI
@@ -70,7 +74,6 @@ int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
// intermediate CI -> N64 raw CI4/CI8
int ci2raw_torch(uint8_t* raw, const ci* img, int width, int height, int depth);
-
//---------------------------------------------------------
// N64 CI <-> N64 RGBA16/IA16
//---------------------------------------------------------
@@ -93,7 +96,6 @@ int ia2png(unsigned char** png_output, int* size_output, const ia* img, int widt
int ci2png(unsigned char** png_output, int* size_output, const ci* img, int width, int height);
-
//---------------------------------------------------------
// PNG -> intermediate RGBA/IA
//---------------------------------------------------------
@@ -110,6 +112,8 @@ ia *png2ia(unsigned char* png_input, int size_input, int *width, int *height);
// PNG file -> intermediate CI
ci* png2ci(unsigned char* png_input, int size_input, int* width, int* height);
+// Adds colours to palette data
+static int pal_add_color(palette_t* pal, uint16_t val);
//---------------------------------------------------------
// version
diff --git a/src/Companion.cpp b/src/Companion.cpp
index 1ad9e64..9a3c233 100644
--- a/src/Companion.cpp
+++ b/src/Companion.cpp
@@ -40,6 +40,8 @@
#include "factories/mk64/TrackSections.h"
#include "factories/mk64/SpawnData.h"
#include "factories/mk64/DrivingBehaviour.h"
+#include "factories/mk64/ItemCurve.h"
+#include "factories/mk64/CourseMetadata.h"
#include "factories/sf64/ColPolyFactory.h"
#include "factories/sf64/MessageFactory.h"
@@ -96,6 +98,8 @@ void Companion::Init(const ExportType type) {
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>());
+ this->RegisterFactory("MK64:ITEM_CURVE", std::make_shared<MK64::ItemCurveFactory>()); // Item curve for decomp only
+ this->RegisterFactory("MK64:METADATA", std::make_shared<MK64::CourseMetadataFactory>());
// SF64 specific
this->RegisterFactory("SF64:ANIM", std::make_shared<SF64::AnimFactory>());
@@ -116,7 +120,7 @@ void Companion::ParseEnums(std::string& header) {
std::ifstream file(header);
if (!file.is_open()) {
- throw std::runtime_error("Failed to open file");
+ throw std::runtime_error("Failed to open header files for enums node in config");
}
std::regex enumRegex(R"(enum\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{)");
@@ -460,6 +464,47 @@ bool Companion::NodeHasChanges(const std::string& path) {
return true;
}
+void Companion::LoadYAMLRecursively(const std::string &dirPath, std::vector<YAML::Node> &result, bool skipRoot) {
+ for (const auto &entry : std::filesystem::directory_iterator(dirPath)) {
+ if (entry.is_directory()) {
+ // Skip the root directory if specified
+ if (skipRoot && entry.path() == dirPath) {
+ continue;
+ }
+
+ // Recursive call for subdirectories
+ LoadYAMLRecursively(entry.path(), result, false);
+ } else if (entry.path().extension() == ".yaml" || entry.path().extension() == ".yml") {
+ // Load YAML file and add it to the result vector
+ result.push_back(YAML::LoadFile(entry.path().string()));
+ }
+ }
+}
+
+/**
+ * Config yaml requires tables: [assets/courses]
+ * Activate the factory using a normal asset yaml with type, input_directory, and output_directory nodes.
+ */
+void Companion::ProcessTables(YAML::Node& rom) {
+ auto dirs = rom["metadata"].as<std::vector<std::string>>();
+
+ for (const auto &dir : dirs) {
+ std::vector<YAML::Node> configNodes;
+ LoadYAMLRecursively(dir, configNodes, true);
+ gCourseMetadata[dir] = configNodes;
+ }
+
+ // Write yaml data to console
+ if (this->IsDebug()) {
+ SPDLOG_INFO("------ Metadata ouptut ------");
+ for (auto &node : gCourseMetadata[dirs[0]]) {
+ std::cout << node << std::endl;
+ SPDLOG_INFO("------------");
+ }
+ SPDLOG_INFO("------ Metadata end ------");
+ }
+}
+
void Companion::Process() {
if(!fs::exists("config.yml")) {
@@ -491,6 +536,10 @@ void Companion::Process() {
return;
}
+ if (rom["metadata"]) {
+ ProcessTables(rom);
+ }
+
if(rom["segments"]) {
auto segments = rom["segments"].as<std::vector<uint32_t>>();
for (int i = 0; i < segments.size(); i++) {
@@ -1048,7 +1097,7 @@ CompressionType Companion::GetCompressionType(std::vector<uint8_t>& buffer, cons
std::optional<Table> Companion::SearchTable(uint32_t addr){
for(auto& table : this->gTables){
- if(addr >= table.start || addr <= table.end){
+ if(addr >= table.start && addr <= table.end){
return table;
}
}
@@ -1186,3 +1235,7 @@ std::optional<YAML::Node> Companion::AddAsset(YAML::Node asset) {
return std::nullopt;
}
+
+void Companion::AddTlutTextureMap(std::string index, std::shared_ptr<TextureData> entry) {
+ this->TlutTextureMap[index] = entry;
+} \ No newline at end of file
diff --git a/src/Companion.h b/src/Companion.h
index 4319587..8d9b9e8 100644
--- a/src/Companion.h
+++ b/src/Companion.h
@@ -10,6 +10,7 @@
#include "factories/BaseFactory.h"
#include "n64/Cartridge.h"
#include "utils/Decompressor.h"
+#include "factories/TextureFactory.h"
class SWrapper;
namespace fs = std::filesystem;
@@ -99,6 +100,7 @@ public:
GBIVersion GetGBIVersion() const { return this->gConfig.gbi.version; }
GBIMinorVersion GetGBIMinorVersion() const { return this->gConfig.gbi.subversion; }
+ std::unordered_map<std::string, std::vector<YAML::Node>> GetCourseMetadata() { return this->gCourseMetadata; }
std::optional<std::string> GetEnumFromValue(const std::string& key, int id);
std::optional<std::uint32_t> GetFileOffsetFromSegmentedAddr(uint8_t segment) const;
@@ -111,6 +113,8 @@ public:
CompressionType GetCurrCompressionType(void) const { return this->gCurrentCompressionType; };
CompressionType GetCompressionType(std::vector<uint8_t>& buffer, const uint32_t offset);
std::optional<VRAMEntry> GetCurrentVRAM(void) const { return this->gCurrentVram; };
+ std::unordered_map<std::string, std::shared_ptr<TextureData>> GetTlutTextureMap() { return this->TlutTextureMap; };
+ void AddTlutTextureMap(std::string index, std::shared_ptr<TextureData> entry);
std::optional<Table> SearchTable(uint32_t addr);
static std::string CalculateHash(const std::vector<uint8_t>& data);
@@ -132,6 +136,7 @@ private:
bool gNodeForceProcessing = false;
YAML::Node gHashNode;
std::shared_ptr<N64::Cartridge> gCartridge;
+ std::unordered_map<std::string, std::vector<YAML::Node>> gCourseMetadata;
std::unordered_map<std::string, std::unordered_map<int32_t, std::string>> gEnums;
SWrapper* gCurrentWrapper;
@@ -151,6 +156,7 @@ private:
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;
+ std::unordered_map<std::string, std::shared_ptr<TextureData>> TlutTextureMap;
void ParseEnums(std::string& file);
void ParseHash();
@@ -158,4 +164,6 @@ private:
void ParseCurrentFileConfig(YAML::Node node);
void RegisterFactory(const std::string& type, const std::shared_ptr<BaseFactory>& factory);
void ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary);
+ void ProcessTables(YAML::Node& rom);
+ void LoadYAMLRecursively(const std::string &dirPath, std::vector<YAML::Node> &result, bool skipRoot);
};
diff --git a/src/factories/DisplayListFactory.cpp b/src/factories/DisplayListFactory.cpp
index b5d71dd..965645e 100644
--- a/src/factories/DisplayListFactory.cpp
+++ b/src/factories/DisplayListFactory.cpp
@@ -313,32 +313,35 @@ std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint
}
if(opcode == GBI(G_DL)) {
+ if (SEGMENT_NUMBER(node["offset"].as<uint32_t>()) == SEGMENT_NUMBER(w1)) {
- std::optional<uint32_t> segment;
+ std::optional<uint32_t> segment;
- if ((w0 >> 16) & G_DL_NO_PUSH) {
- SPDLOG_INFO("Branch List Command Found");
- processing = false;
- }
+ if ((w0 >> 16) & G_DL_NO_PUSH) {
+ SPDLOG_INFO("Branch List Command Found");
+ processing = false;
+ }
- YAML::Node gfx;
- gfx["type"] = "GFX";
- gfx["offset"] = w1;
- Companion::Instance->AddAsset(gfx);
+ YAML::Node gfx;
+ gfx["type"] = "GFX";
+ gfx["offset"] = w1;
+
+ Companion::Instance->AddAsset(gfx);
+ }
}
- // This opcode is generally used as part of multiple macros such as gsSPSetLights1.
- // We need to process gsSPLight which is a subcommand inside G_MOVEMEM (0x03).
+ // This opcode is generally used as part of multiple macros such as gsSPSetLights1.
+ // We need to process gsSPLight which is a subcommand inside G_MOVEMEM (0x03).
if(opcode == GBI(G_MOVEMEM)) {
- // 0x03860000 or 0x03880000 subcommand will contain 0x86/0x88 for G_MV_L0 and G_MV_L1. Other subcommands also exist.
- uint8_t subcommand = (w0 >> 16) & 0xFF;
+ // 0x03860000 or 0x03880000 subcommand will contain 0x86/0x88 for G_MV_L0 and G_MV_L1. Other subcommands also exist.
+ uint8_t subcommand = (w0 >> 16) & 0xFF;
uint8_t index = 0;
uint8_t offset = 0;
bool light = false;
switch (Companion::Instance->GetGBIVersion()) {
- // If needing light generation on G_MV_L0 then we'll need to walk the DL ptr forward/backward to check for 0xBC
- // Otherwise mk64 will break.
+ // If needing light generation on G_MV_L0 then we'll need to walk the DL ptr forward/backward to check for 0xBC
+ // Otherwise mk64 will break.
// PD: Mega, this works for sm64 too, why you didn't implement it? >:(
// PD: Im jk, <3
case GBIVersion::f3d:
@@ -347,9 +350,9 @@ std::optional<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint
* Only generate lights on the second gsSPLight.
* gsSPSetLights1(name) outputs three macros:
*
- * gsSPNumLights(NUMLIGHTS_1)
- * gsSPLight(&name.l[0], G_MV_L0)
- * gsSPLight(&name.a, G_MV_L1) <-- This ptr is used to generate the lights
+ * gsSPNumLights(NUMLIGHTS_1)
+ * gsSPLight(&name.l[0], G_MV_L0)
+ * gsSPLight(&name.a, G_MV_L1) <-- This ptr is used to generate the lights
*/
if (subcommand == GBI(G_MV_L1)) {
light = true;
diff --git a/src/factories/GenericArrayFactory.cpp b/src/factories/GenericArrayFactory.cpp
index 81144f5..a8b502a 100644
--- a/src/factories/GenericArrayFactory.cpp
+++ b/src/factories/GenericArrayFactory.cpp
@@ -24,6 +24,7 @@ std::unordered_map<std::string, ArrayType> arrayTypeMap = {
{ "Vec3f", ArrayType::Vec3f },
{ "Vec3s", ArrayType::Vec3s },
{ "Vec3i", ArrayType::Vec3i },
+ { "Vec3iu", ArrayType::Vec3iu },
{ "Vec4f", ArrayType::Vec4f },
{ "Vec4s", ArrayType::Vec4s },
};
@@ -42,6 +43,7 @@ std::unordered_map<ArrayType, size_t> typeSizeMap = {
{ ArrayType::Vec3f, 12 },
{ ArrayType::Vec3s, 6 },
{ ArrayType::Vec3i, 12 },
+ { ArrayType::Vec3iu, 12 },
{ ArrayType::Vec4f, 16 },
{ ArrayType::Vec4s, 8 },
};
@@ -60,6 +62,7 @@ std::unordered_map<ArrayType, size_t> structCountMap = {
{ ArrayType::Vec3f, 3 },
{ ArrayType::Vec3s, 3 },
{ ArrayType::Vec3i, 3 },
+ { ArrayType::Vec3iu, 3 },
{ ArrayType::Vec4f, 4 },
{ ArrayType::Vec4s, 4 },
};
@@ -140,6 +143,10 @@ GenericArray::GenericArray(std::vector<ArrayDatum> data) : mData(std::move(data)
mMaxWidth = std::max(mMaxWidth, (uint32_t)std::get<Vec3i>(datum).width());
break;
}
+ case ArrayType::Vec3iu: {
+ mMaxWidth = std::max(mMaxWidth, (uint32_t)std::get<Vec3iu>(datum).width());
+ break;
+ }
case ArrayType::Vec4f: {
mMaxWidth = std::max(mMaxWidth,(uint32_t)std::get<Vec4f>(datum).width());
mMaxPrec = std::max(mMaxPrec, (uint32_t)std::get<Vec4f>(datum).precision());
@@ -230,6 +237,9 @@ ExportResult ArrayCodeExporter::Export(std::ostream &write, std::shared_ptr<IPar
case ArrayType::Vec3i:
write << FORMAT_INT(std::get<Vec3i>(datum), array->mMaxWidth) << ", ";
break;
+ case ArrayType::Vec3iu:
+ write << FORMAT_INT(std::get<Vec3iu>(datum), array->mMaxWidth) << ", ";
+ break;
case ArrayType::Vec4f:
write << FORMAT_FLOAT(std::get<Vec4f>(datum), array->mMaxWidth, array->mMaxPrec) << ", ";
break;
@@ -372,12 +382,13 @@ std::optional<std::shared_ptr<IParsedData>> GenericArrayFactory::parse(std::vect
for (int i = 0; i < count; i++) {
switch (arrayType) {
case ArrayType::u8: {
- auto x = reader.ReadUByte();
+ uint8_t x = reader.ReadUByte();
data.emplace_back(x);
+ SPDLOG_INFO("HERE");
break;
}
case ArrayType::s8: {
- auto x = reader.ReadInt8();
+ int8_t x = reader.ReadInt8();
data.emplace_back(x);
break;
}
@@ -447,6 +458,14 @@ std::optional<std::shared_ptr<IParsedData>> GenericArrayFactory::parse(std::vect
data.emplace_back(Vec3i(vx, vy, vz));
break;
}
+ case ArrayType::Vec3iu: {
+ auto vx = reader.ReadUInt32();
+ auto vy = reader.ReadUInt32();
+ auto vz = reader.ReadUInt32();
+
+ data.emplace_back(Vec3iu(vx, vy, vz));
+ break;
+ }
case ArrayType::Vec4f: {
auto vx = reader.ReadFloat();
auto vy = reader.ReadFloat();
diff --git a/src/factories/GenericArrayFactory.h b/src/factories/GenericArrayFactory.h
index 4f7688e..1781211 100644
--- a/src/factories/GenericArrayFactory.h
+++ b/src/factories/GenericArrayFactory.h
@@ -5,10 +5,10 @@
#include <variant>
#include <types/Vec3D.h>
-typedef std::variant<uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, float, double, Vec2f, Vec3f, Vec3s, Vec3i, Vec4f, Vec4s> ArrayDatum;
+typedef std::variant<uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, float, double, Vec2f, Vec3f, Vec3s, Vec3i, Vec3iu, Vec4f, Vec4s> ArrayDatum;
enum class ArrayType {
- u8, s8, u16, s16, u32, s32, u64, f32, f64, Vec2f, Vec3f, Vec3s, Vec3i, Vec4f, Vec4s,
+ u8, s8, u16, s16, u32, s32, u64, f32, f64, Vec2f, Vec3f, Vec3s, Vec3i, Vec3iu, Vec4f, Vec4s,
};
class GenericArray : public IParsedData {
diff --git a/src/factories/IncludeFactory.cpp b/src/factories/IncludeFactory.cpp
index bf3d268..ab38c28 100644
--- a/src/factories/IncludeFactory.cpp
+++ b/src/factories/IncludeFactory.cpp
@@ -27,7 +27,7 @@ ExportResult IncludeCodeExporter::Export(std::ostream &write, std::shared_ptr<IP
SPDLOG_INFO("writing INC");
write << ctype << " " << symbol << "[] = {\n";
- write << fourSpaceTab << "#include '" << file << "'\n";
+ write << fourSpaceTab << "#include \"" << file << "\"\n";
write << "};\n\n";
diff --git a/src/factories/LightsFactory.cpp b/src/factories/LightsFactory.cpp
index 83464c2..fd930aa 100644
--- a/src/factories/LightsFactory.cpp
+++ b/src/factories/LightsFactory.cpp
@@ -22,7 +22,7 @@ ExportResult LightsHeaderExporter::Export(std::ostream &write, std::shared_ptr<I
return std::nullopt;
}
- write << "extern Lights1" << name << "[];\n";
+ write << "extern Lights1 " << name << "[];\n";
} else {
write << "extern Lights1 " << symbol << ";\n";
}
diff --git a/src/factories/MtxFactory.cpp b/src/factories/MtxFactory.cpp
index cce6f99..15ca03b 100644
--- a/src/factories/MtxFactory.cpp
+++ b/src/factories/MtxFactory.cpp
@@ -15,7 +15,7 @@ ExportResult MtxHeaderExporter::Export(std::ostream &write, std::shared_ptr<IPar
return std::nullopt;
}
- write << "extern Mtx " << symbol << "[];\n";
+ write << "extern Mtx " << symbol << ";\n";
return std::nullopt;
}
@@ -44,7 +44,7 @@ ExportResult MtxCodeExporter::Export(std::ostream &write, std::shared_ptr<IParse
* 0.0, 0.0, 0.0, 1.0);
*/
- write << "Mtx " << symbol << "[] = {\n";
+ write << "Mtx " << symbol << " = {\n";
for (int i = 0; i < m.size(); ++i) {
@@ -53,10 +53,16 @@ ExportResult MtxCodeExporter::Export(std::ostream &write, std::shared_ptr<IParse
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.
+ SPDLOG_INFO(m[i].mtx[j]);
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];
+ // Stupid hack to get matching precision so this value outputs 0.0000153 instead.
+ if (std::fabs(m[i].mtx[j] - 0.000015) < 0.000001) {
+ write << std::fixed << std::setprecision(7) << m[i].mtx[j];
+ } else {
+ write << std::fixed << std::setprecision(6) << m[i].mtx[j];
+ }
}
// Add comma for all but the last arg
@@ -93,7 +99,7 @@ ExportResult MtxCodeExporter::Export(std::ostream &write, std::shared_ptr<IParse
#undef fiveFourSpaceTabs
- return offset + m.size() * sizeof(MtxRaw);
+ return offset + sizeof(MtxRaw);
}
ExportResult MtxBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
@@ -134,7 +140,7 @@ std::optional<std::shared_ptr<IParsedData>> MtxFactory::parse(std::vector<uint8_
reader.SetEndianness(LUS::Endianness::Big);
std::vector<MtxRaw> matrix;
- #define FIXTOF(x) ((double)((x) / 65536.0))
+ #define FIXTOF(x) ((float)((x) / 65536.0f))
// 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++) {
diff --git a/src/factories/MtxFactory.h b/src/factories/MtxFactory.h
index cad0ed2..cc3f7df 100644
--- a/src/factories/MtxFactory.h
+++ b/src/factories/MtxFactory.h
@@ -3,7 +3,7 @@
#include "BaseFactory.h"
struct MtxRaw {
- double mtx[16];
+ float mtx[16];
};
class MtxData : public IParsedData {
diff --git a/src/factories/TextureFactory.cpp b/src/factories/TextureFactory.cpp
index a293bfc..5d7ebc0 100644
--- a/src/factories/TextureFactory.cpp
+++ b/src/factories/TextureFactory.cpp
@@ -20,9 +20,9 @@ static const std::unordered_map <std::string, TextureFormat> gTextureFormats = {
{ "I4", { TextureType::Grayscale4bpp, 4 } },
{ "I8", { TextureType::Grayscale8bpp, 8 } },
{ "IA1", { TextureType::GrayscaleAlpha1bpp, 1 } },
- { "IA4", { TextureType::GrayscaleAlpha4bpp, 4 } },
- { "IA8", { TextureType::GrayscaleAlpha8bpp, 8 } },
- { "IA16", { TextureType::GrayscaleAlpha16bpp, 16 } },
+ { "IA4", { TextureType::GrayscaleAlpha4bpp, 4 } },
+ { "IA8", { TextureType::GrayscaleAlpha8bpp, 8 } },
+ { "IA16", { TextureType::GrayscaleAlpha16bpp, 16 } },
{ "TLUT", { TextureType::TLUT, 16 } },
};
@@ -156,7 +156,7 @@ ExportResult TextureCodeExporter::Export(std::ostream &write, std::shared_ptr<IP
}
if(start == offset){
- write << GetSafeNode<std::string>(node, "ctype", "static unsigned char") << " " << name << "[][" << (texture->mBuffer.size() / byteSize) << "] = {\n";
+ write << GetSafeNode<std::string>(node, "ctype", "u8") << " " << name << "[][" << (texture->mBuffer.size() / byteSize) << "] = {\n";
}
write << tab << "{\n";
@@ -170,7 +170,7 @@ ExportResult TextureCodeExporter::Export(std::ostream &write, std::shared_ptr<IP
}
}
} else {
- write << GetSafeNode<std::string>(node, "ctype", "static const u8") << " " << symbol << "[] = {\n";
+ write << GetSafeNode<std::string>(node, "ctype", "u8") << " " << symbol << "[] = {\n";
write << tab << "#include \"" << Companion::Instance->GetOutputPath() + "/" << *replacement << ".inc.c\"\n";
write << "};\n";
@@ -235,11 +235,21 @@ ExportResult TextureModdingExporter::Export(std::ostream&write, std::shared_ptr<
}
case TextureType::Palette8bpp:
case TextureType::Palette4bpp: {
- ci* imgi = raw2ci_torch(texture->mBuffer.data(), texture->mWidth, texture->mHeight, format.depth);
- if(ci2png(&raw, &size, imgi, texture->mWidth, texture->mHeight)) {
- throw std::runtime_error("Failed to convert texture to PNG");
+ // This check needed until sf64 has tluts fixed.
+ if (node["tlut_symbol"]) {
+ auto tlut = GetSafeNode<std::string>(node,"tlut_symbol");
+ auto tlutTextureMap = Companion::Instance->GetTlutTextureMap();
+ auto palettePtr = tlutTextureMap[tlut];
+
+ if (palettePtr) {
+ convert_raw_to_ci8(&raw, &size, texture->mBuffer.data(), (uint8_t *)palettePtr->mBuffer.data(), 0, texture->mWidth, texture->mHeight, palettePtr->mFormat.depth);
+
+ } else {
+ auto symbol = GetSafeNode<std::string>(node, "symbol");
+ throw std::runtime_error("Could not convert ci8 '"+symbol+"' the tlut symbol name is probably wrong for tlut_symbol node");
+ }
+ break;
}
- break;
}
case TextureType::Grayscale8bpp:
case TextureType::Grayscale4bpp: {
@@ -262,6 +272,7 @@ ExportResult TextureModdingExporter::Export(std::ostream&write, std::shared_ptr<
std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
auto offset = GetSafeNode<uint32_t>(node, "offset");
auto format = GetSafeNode<std::string>(node, "format");
+ auto symbol = GetSafeNode<std::string>(node, "symbol");
uint32_t width;
uint32_t height;
uint32_t size;
@@ -275,11 +286,11 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
return std::nullopt;
}
- if(!gTextureFormats.contains(format)) {
- return std::nullopt;
- }
+ if(!gTextureFormats.contains(format)) {
+ return std::nullopt;
+ }
- TextureFormat fmt = gTextureFormats.at(format);
+ TextureFormat fmt = gTextureFormats.at(format);
if(fmt.type == TextureType::TLUT){
width = GetSafeNode<uint32_t>(node, "colors");
@@ -292,13 +303,10 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
if((format == "CI4" || format == "CI8") && node["tlut"] && node["colors"]) {
YAML::Node tlutNode;
const auto tlutOffset = GetSafeNode<uint32_t>(node, "tlut");
- if(node["symbol"]) {
- const auto symbol = GetSafeNode<std::string>(node, "symbol");
- const auto tlutSymbol = GetSafeNode(node, "tlut_symbol", symbol + "_tlut");
- std::ostringstream offsetSeg;
- offsetSeg << std::uppercase << std::hex << tlutOffset;
- tlutNode["symbol"] = std::regex_replace(tlutSymbol, std::regex(R"(OFFSET)"), offsetSeg.str());
- }
+ const auto tlutSymbol = GetSafeNode(node, "tlut_symbol", symbol + "_tlut");
+ std::ostringstream offsetSeg;
+ offsetSeg << std::uppercase << std::hex << tlutOffset;
+ tlutNode["symbol"] = std::regex_replace(tlutSymbol, std::regex(R"(OFFSET)"), offsetSeg.str());
tlutNode["type"] = "TEXTURE";
tlutNode["format"] = "TLUT";
tlutNode["offset"] = tlutOffset;
@@ -325,13 +333,23 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse(std::vector<ui
SPDLOG_INFO("Width: {}", width);
SPDLOG_INFO("Height: {}", height);
}
- SPDLOG_INFO("Size: {}", size);
+ SPDLOG_INFO("Size: {}", size);
SPDLOG_INFO("Offset: 0x{:X}", offset);
if(result.size() == 0){
return std::nullopt;
}
+ if(result.size() == 0){
+ return std::nullopt;
+ }
+
+ if (fmt.type == TextureType::TLUT) {
+ auto textureData = std::make_shared<TextureData>(fmt, width, height, result);
+ Companion::Instance->AddTlutTextureMap(symbol, textureData);
+ return textureData;
+ }
+
return std::make_shared<TextureData>(fmt, width, height, result);
}
@@ -349,11 +367,11 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse_modding(std::v
return std::nullopt;
}
- if(!gTextureFormats.contains(format)) {
- return std::nullopt;
- }
+ if(!gTextureFormats.contains(format)) {
+ return std::nullopt;
+ }
- TextureFormat fmt = gTextureFormats.at(format);
+ TextureFormat fmt = gTextureFormats.at(format);
if(fmt.type == TextureType::TLUT){
width = GetSafeNode<uint32_t>(node, "colors");
height = 1;
@@ -389,14 +407,31 @@ std::optional<std::shared_ptr<IParsedData>> TextureFactory::parse_modding(std::v
}
case TextureType::Palette8bpp:
case TextureType::Palette4bpp: {
- SPDLOG_WARN("Converting PNG to CI texture is kind of broken, use at your own risk!");
- const auto imgi = png2ci(buffer.data(), buffer.size(), &width, &height);
- size = width * height * fmt.depth / 8;
- raw = new uint8_t[size];
+ // This implementation is not correct.
+ // The process should be:
+ // png2rgba --> imgpal2rawci
- if(ci2raw_torch(raw, imgi, width, height, fmt.depth) <= 0){
- throw std::runtime_error("Failed to convert PNG to texture");
- }
+ // todo: Add wheel palette input
+ // Implement so that it works.
+
+ // auto tlut = GetSafeNode<std::string>(node,"tlut_symbol");
+ // auto tlutTextureMap = Companion::Instance->GetTlutTextureMap();
+ // auto palettePtr = tlutTextureMap[tlut];
+
+ // if (palettePtr) {
+
+ // auto imgi = png2rgba(buffer.data(), buffer.size(), &width, &height);
+ // auto pal = png2rgba(palettePtr->mBuffer.data(), (palettePtr->mWidth * palettePtr->mWidth * palettePtr->mFormat.depth * 2), &width, &height);
+
+ // size = width * height * fmt.depth / 8;
+ // raw = new uint8_t[size];
+
+ // if(imgpal2rawci(raw, imgi, pal, 0, 0, width, height, fmt.depth) <= 0){
+ // throw std::runtime_error("Failed to convert PNG to texture");
+ // }
+ // } else {
+
+ // }
break;
}
case TextureType::Grayscale8bpp:
diff --git a/src/factories/VtxFactory.cpp b/src/factories/VtxFactory.cpp
index 000b274..450ad3c 100644
--- a/src/factories/VtxFactory.cpp
+++ b/src/factories/VtxFactory.cpp
@@ -26,7 +26,7 @@ ExportResult VtxHeaderExporter::Export(std::ostream &write, std::shared_ptr<IPar
return std::nullopt;
}
- write << "extern Vtx" << name << "[][" << vtx.size() << "];\n";
+ write << "extern Vtx " << name << "[][" << vtx.size() << "];\n";
} else {
write << "extern Vtx " << symbol << "[];\n";
}
diff --git a/src/factories/mk64/CourseMetadata.cpp b/src/factories/mk64/CourseMetadata.cpp
new file mode 100644
index 0000000..083f553
--- /dev/null
+++ b/src/factories/mk64/CourseMetadata.cpp
@@ -0,0 +1,375 @@
+#include "CourseMetadata.h"
+
+#include "Companion.h"
+#include "spdlog/spdlog.h"
+#include <algorithm>
+
+#define NUM(x) std::dec << std::setfill(' ') << std::setw(6) << x
+#define COL(c) "0x" << std::hex << std::setw(2) << std::setfill('0') << c
+
+ExportResult MK64::CourseMetadataCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto metadata = std::static_pointer_cast<MetadataData>(raw)->mMetadata;
+
+ if (metadata.empty()) {
+ throw std::runtime_error("Course metadata null");
+ }
+
+ // Sort the data by id, 0 to 20 and beyond.
+ std::sort(metadata.begin(), metadata.end(),
+ [this](const CourseMetadata& a, const CourseMetadata& b) {
+ return a.id < b.id;
+ });
+
+ std::ofstream file;
+ auto outDir = GetSafeNode<std::string>(node, "out_directory") + "/";
+
+ file.open(outDir+"gCourseNames.inc.c");
+ if (file.is_open()) {
+ // file << "char *gCourseNames[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ if (m.name == "null") { continue; }
+ // Remove debug line once proven that sort worked right (start at id 0 and go up)
+ SPDLOG_INFO("Processing Course Id: "+std::to_string(m.id));
+ file << '"' << m.name << "\", ";
+ }
+ // file << "\n};\n\n";
+ file.close();
+ } else if (file.fail()) {
+ throw std::runtime_error("Course metadata output folder is likely bad or the file is in-use");
+ }
+
+ file.open(outDir+"gCourseDebugNames.inc.c");
+ if (file.is_open()) {
+ // file << "char *gDebugCourseNames[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ if (m.name == "null") { continue; }
+ file << '"' << m.debugName << "\", ";
+ }
+ //file << "\n};\n\n";
+ file.close();
+ }
+
+ file.open(outDir+"gCupSelectionByCourseId.inc.c");
+ if (file.is_open()) {
+ //file << "char *gCupSelectionByCourseId[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ if (m.cup == "null") { continue; }
+ file << m.cup << ", ";
+ }
+ // file << "\n};\n\n";
+ file.close();
+ }
+
+ file.open(outDir+"gPerCupIndexByCourseId.inc.c");
+ if (file.is_open()) {
+ //file << "const u8 gPerCupIndexByCourseId[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ if (m.cupIndex == -1) { continue; }
+ file << m.cupIndex << ", ";
+ }
+ //file << "\n};\n\n";
+ file.close();
+ }
+
+ file.open(outDir+"sCourseLengths.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ if (m.courseLength == "null") { continue; }
+ file << '"' << m.courseLength << "\", ";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"gKartAIBehaviourLUT.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << m.kartAIBehaviourLUT << ", ";
+ }
+ file << 0; // @WARNING TRAILING ZERO IN ARRAY
+ file.close();
+ }
+
+ file.open(outDir+"gKartAICourseMaximumSeparation.inc.c");
+ if (file.is_open()) {
+ // file << "f32 gWaypointWidth[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ file << m.kartAIMaximumSeparation << ", ";
+ }
+ // file << "\n};\n\n";
+ file.close();
+ }
+
+ file.open(outDir+"gKartAICourseMinimumSeparation.inc.c");
+ if (file.is_open()) {
+ // file << "f32 gWaypointWidth2[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ file << m.kartAIMinimumSeparation << ", ";
+ }
+ // file << "\n};\n\n";
+ file.close();
+ }
+
+ file.open(outDir+"D_800DCBB4.inc.c");
+ if (file.is_open()) {
+ //file << "uintptr_t *D_800DCBB4[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ file << m.D_800DCBB4 << ", ";
+ }
+ //file << "\n};\n\n";
+ file.close();
+ }
+
+ file.open(outDir+"gCPUSteeringSensitivity.inc.c");
+
+ // @WARNING THIS FILE HAS A TRAILING ZERO
+ if (file.is_open()) {
+ //file << "u16 gCPUSteeringSensitivity[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ file << m.steeringSensitivity << ", ";
+ }
+ file << 0;
+ //file << "\n};\n\n";
+ file.close();
+ }
+
+ file.open(outDir+"gBombKartSpawns.inc.c");
+ if (file.is_open()) {
+ //file << "u16 gCPUSteeringSensitivity[] = {\n" << fourSpaceTab;
+ for (const auto& m : metadata) {
+ file << "{ // " << m.name << "\n";
+ for (const auto& bombKart : m.bombKartSpawns) {
+ file << "{ ";
+ file << bombKart.waypointIndex << ", ";
+ file << bombKart.startingState << ", ";
+ file << bombKart.unk_04 << ", ";
+ file << bombKart.x << ", ";
+ file << bombKart.z << ", ";
+ file << bombKart.unk10 << ", ";
+ file << bombKart.unk14;
+ file << " },\n";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"gCoursePathSizes.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.pathSizes) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"D_0D009418.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto size : m.D_0D009418) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"D_0D009568.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.D_0D009568) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"D_0D0096B8.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.D_0D0096B8) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"D_0D009808.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.D_0D009808) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"gCoursePathTable.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.pathTable) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"gCoursePathTableUnknown.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.pathTableUnknown) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"sSkyColors.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.skyColors) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+
+ file.open(outDir+"sSkyColors2.inc.c");
+ if (file.is_open()) {
+ for (const auto& m : metadata) {
+ file << "// " << m.name << "\n";
+ file << "{ ";
+ for (const auto& size : m.skyColors2) {
+ file << size << ", ";
+ }
+ file << "},\n";
+ }
+ file.close();
+ }
+ return std::nullopt;
+}
+
+ExportResult MK64::CourseMetadataBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ //auto metadata = std::static_pointer_cast<MetadataData>(raw)->mMetadata;
+ //auto writer = LUS::BinaryWriter();
+
+ throw std::runtime_error("CourseMetadata not implemented for OTR");
+
+ // WriteHeader(writer, LUS::ResourceType::Metadata, 0);
+ // writer.Write((uint32_t) metadata.size());
+ //writer.Finish(write);
+ return std::nullopt;
+}
+
+std::optional<std::shared_ptr<IParsedData>> MK64::CourseMetadataFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto dir = GetSafeNode<std::string>(node, "input_directory");
+
+ auto m = Companion::Instance->GetCourseMetadata();
+ SPDLOG_INFO("RUNNING");
+ std::vector<CourseMetadata> yamlData;
+ for (const auto &yamls : m[dir]) {
+
+ if (!yamls["course"]) {
+ for (auto &node : yamls) {
+ std::cout << node << std::endl;
+ }
+ throw std::runtime_error("Course yaml missing root label of course\nEx. course:");
+ }
+
+ auto metadata = yamls["course"];
+
+ CourseMetadata data;
+
+ data.id = GetSafeNode<uint32_t>(metadata, "id");
+ data.name = GetSafeNode<std::string>(metadata, "name");
+ data.debugName = GetSafeNode<std::string>(metadata, "debug_name");
+ data.cup = GetSafeNode<std::string>(metadata, "cup");
+ data.cupIndex = GetSafeNode<int32_t>(metadata, "cup_index");
+ data.courseLength = GetSafeNode<std::string>(metadata, "course_length");
+
+ data.kartAIBehaviourLUT = GetSafeNode<std::string>(metadata, "kart_ai_behaviour_ptr");
+ data.kartAIMaximumSeparation = GetSafeNode<std::string>(metadata, "kart_ai_maximum_separation");
+ data.kartAIMinimumSeparation = GetSafeNode<std::string>(metadata, "kart_ai_minimum_separation");
+
+ data.D_800DCBB4 = GetSafeNode<std::string>(metadata, "D_800DCBB4");
+ data.steeringSensitivity = GetSafeNode<uint32_t>(metadata, "cpu_steering_sensitivity");
+ SPDLOG_INFO("BEFORE");
+ for (const auto& bombKart : GetSafeNode<YAML::Node>(metadata, "bomb_kart_spawns")) {
+ data.bombKartSpawns.push_back(BombKartSpawns({
+ bombKart[0].as<uint16_t>(),
+ bombKart[1].as<uint16_t>(),
+ bombKart[2].as<std::string>(), // Parse as string because floating-point outputs incorrect values.
+ bombKart[3].as<float>(),
+ bombKart[4].as<float>(),
+ bombKart[5].as<float>(),
+ bombKart[6].as<float>(),
+ }));
+ }
+
+ for (const auto& size : GetSafeNode<YAML::Node>(metadata, "path_sizes")) {
+ data.pathSizes.push_back(size.as<uint16_t>());
+ }
+
+ for (const auto& value : GetSafeNode<YAML::Node>(metadata, "D_0D009418")) {
+ data.D_0D009418.push_back(value.as<std::string>());
+ }
+
+ for (const auto& value : GetSafeNode<YAML::Node>(metadata, "D_0D009568")) {
+ data.D_0D009568.push_back(value.as<std::string>());
+ }
+
+ for (const auto& value : GetSafeNode<YAML::Node>(metadata, "D_0D0096B8")) {
+ data.D_0D0096B8.push_back(value.as<std::string>());
+ }
+ SPDLOG_INFO("MIDDLE");
+ for (const auto& value : GetSafeNode<YAML::Node>(metadata, "D_0D009808")) {
+ data.D_0D009808.push_back(value.as<std::string>());
+ }
+
+ for (const auto& str : GetSafeNode<YAML::Node>(metadata, "path_table")) {
+ data.pathTable.push_back(str.as<std::string>());
+ }
+
+ for (const auto& str : GetSafeNode<YAML::Node>(metadata, "path_table_unknown")) {
+ data.pathTableUnknown.push_back(str.as<std::string>());
+ }
+ SPDLOG_INFO("BEFORE COLOUR");
+ for (const auto& value : GetSafeNode<YAML::Node>(metadata, "sky_colors")) {
+ data.skyColors.push_back(value.as<uint16_t>());
+ }
+ SPDLOG_INFO("BEFORE COLOUR2");
+ for (const auto& value : GetSafeNode<YAML::Node>(metadata, "sky_colors2")) {
+ data.skyColors2.push_back(value.as<uint16_t>());
+ }
+
+ yamlData.push_back(CourseMetadata(
+ {data}
+ ));
+ }
+ SPDLOG_INFO("END RUNNING");
+
+ return std::make_shared<MetadataData>(yamlData);
+} \ No newline at end of file
diff --git a/src/factories/mk64/CourseMetadata.h b/src/factories/mk64/CourseMetadata.h
new file mode 100644
index 0000000..05264ba
--- /dev/null
+++ b/src/factories/mk64/CourseMetadata.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include "../BaseFactory.h"
+
+namespace MK64 {
+
+ struct BombKartSpawns {
+ uint16_t waypointIndex;
+ uint16_t startingState;
+ std::string unk_04;
+ float x;
+ float z;
+ float unk10;
+ float unk14;
+ };
+
+ struct CourseMetadata {
+ uint32_t id;
+ std::string name;
+ std::string debugName;
+ std::string cup;
+ int32_t cupIndex;
+ std::string courseLength;
+ std::string kartAIBehaviourLUT;
+ std::string kartAIMaximumSeparation;
+ std::string kartAIMinimumSeparation;
+ std::string D_800DCBB4;
+ uint32_t steeringSensitivity;
+ std::vector<BombKartSpawns> bombKartSpawns;
+ std::vector<uint16_t> pathSizes;
+ std::vector<std::string> D_0D009418;
+ std::vector<std::string> D_0D009568;
+ std::vector<std::string> D_0D0096B8;
+ std::vector<std::string> D_0D009808;
+ std::vector<std::string> pathTable;
+ std::vector<std::string> pathTableUnknown;
+ std::vector<uint16_t> skyColors;
+ std::vector<uint16_t> skyColors2;
+ };
+
+ class MetadataData : public IParsedData {
+ public:
+ std::vector<CourseMetadata> mMetadata;
+
+ explicit MetadataData(std::vector<CourseMetadata> metadata) : mMetadata(metadata) {}
+ };
+
+ class CourseMetadataBinaryExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class CourseMetadataCodeExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class CourseMetadataFactory : 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, CourseMetadataCodeExporter)
+ REGISTER(Binary, CourseMetadataBinaryExporter)
+ };
+ }
+ bool SupportModdedAssets() override { return false; }
+ };
+} \ No newline at end of file
diff --git a/src/factories/mk64/DrivingBehaviour.cpp b/src/factories/mk64/DrivingBehaviour.cpp
index 76e355a..80d31d0 100644
--- a/src/factories/mk64/DrivingBehaviour.cpp
+++ b/src/factories/mk64/DrivingBehaviour.cpp
@@ -15,7 +15,7 @@ ExportResult MK64::DrivingBehaviourHeaderExporter::Export(std::ostream &write, s
return std::nullopt;
}
- write << "extern DrivingBehaviour " << symbol << "[];\n";
+ write << "extern CPUBehaviour " << symbol << "[];\n";
return std::nullopt;
}
@@ -35,7 +35,7 @@ ExportResult MK64::DrivingBehaviourCodeExporter::Export(std::ostream &write, std
write << "// 0x" << std::hex << std::uppercase << offset << "\n";
}
- write << "DrivingBehaviour " << symbol << "[] = {\n";
+ write << "CPUBehaviour " << symbol << "[] = {\n";
for(auto b : bhv->mBhvs) {
diff --git a/src/factories/mk64/ItemCurve.cpp b/src/factories/mk64/ItemCurve.cpp
new file mode 100644
index 0000000..99ba99c
--- /dev/null
+++ b/src/factories/mk64/ItemCurve.cpp
@@ -0,0 +1,94 @@
+#include "ItemCurve.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) "0x" << std::hex << std::setw(2) << std::setfill('0') << c
+
+ExportResult MK64::ItemCurveHeaderExporter::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 u8 " << symbol << "[][100];\n";
+ return std::nullopt;
+}
+
+ExportResult MK64::ItemCurveCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto items = std::static_pointer_cast<ItemCurveData>(raw)->mItems;
+ const auto symbol = GetSafeNode(node, "symbol", entryName);
+ const auto offset = GetSafeNode<uint32_t>(node, "offset");
+
+
+ const auto searchTable = Companion::Instance->SearchTable(offset);
+
+ if(searchTable.has_value()){
+ const auto [name, start, end, mode] = searchTable.value();
+
+ if(start == offset){
+ write << GetSafeNode<std::string>(node, "ctype", "u8") << " " << name << "[][" << items.size() << "] = {\n";
+ }
+
+ write << fourSpaceTab << "{";
+ for (size_t i = 0; i < items.size(); ++i) {
+ uint8_t value = items[i];
+ auto enumName = Companion::Instance->GetEnumFromValue("ITEMS", value).value_or(std::to_string(value));
+
+ if (i % 10 == 0) {
+ write << "\n" << fourSpaceTab << fourSpaceTab << enumName << ", ";
+ } else {
+ write << enumName << ", ";
+ }
+ }
+ write << "\n" << fourSpaceTab << "},\n";
+
+ if(end == offset){
+ write << "};\n\n";
+ }
+
+ } else {
+
+ write << "u8 " << symbol << "[][100] = {\n";
+ write << fourSpaceTab << "{";
+
+ for (size_t i = 0; i < items.size(); ++i) {
+ uint8_t value = items[i];
+ auto enumName = Companion::Instance->GetEnumFromValue("ITEMS", value).value_or(std::to_string(value));
+
+ if (i % 10 == 0) {
+ write << "\n" << fourSpaceTab << enumName << ", ";
+ } else {
+ write << enumName << ", ";
+ }
+ }
+ write << "\n" << fourSpaceTab << "},\n";
+ write << "};\n\n";
+ }
+
+ return offset + items.size() * sizeof(uint8_t);
+}
+
+ExportResult MK64::ItemCurveBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ throw std::runtime_error("Decomp ItemCurve is only implemented in decomp.\nuk64 and port use a new system for ease of modding and bug fixes.");
+ return std::nullopt;
+}
+
+std::optional<std::shared_ptr<IParsedData>> MK64::ItemCurveFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ auto [_, segment] = Decompressor::AutoDecode(node, buffer);
+ LUS::BinaryReader reader(segment.data, (10 * 10) * sizeof(uint8_t));
+
+ reader.SetEndianness(LUS::Endianness::Big);
+ std::vector<uint8_t> items;
+
+ // Each array is size of 10*10.
+ for(size_t i = 0; i < 10*10; i++) {
+ items.push_back(reader.ReadUByte());
+ }
+
+ return std::make_shared<ItemCurveData>(items);
+} \ No newline at end of file
diff --git a/src/factories/mk64/ItemCurve.h b/src/factories/mk64/ItemCurve.h
new file mode 100644
index 0000000..c58e825
--- /dev/null
+++ b/src/factories/mk64/ItemCurve.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "../BaseFactory.h"
+
+namespace MK64 {
+
+ class ItemCurveData : public IParsedData {
+ public:
+ std::vector<uint8_t> mItems;
+
+ explicit ItemCurveData(std::vector<uint8_t> items) : mItems(items) {}
+ };
+
+ class ItemCurveHeaderExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class ItemCurveBinaryExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class ItemCurveCodeExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+ };
+
+ class ItemCurveFactory : 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, ItemCurveCodeExporter)
+ REGISTER(Header, ItemCurveHeaderExporter)
+ REGISTER(Binary, ItemCurveBinaryExporter)
+ };
+ }
+ bool SupportModdedAssets() override { return false; }
+ };
+
+} \ No newline at end of file
diff --git a/src/types/Vec3D.cpp b/src/types/Vec3D.cpp
index c70e540..ab263f8 100644
--- a/src/types/Vec3D.cpp
+++ b/src/types/Vec3D.cpp
@@ -86,6 +86,23 @@ std::ostream& operator<< (std::ostream& stream, const Vec3i& vec) {
return stream;
}
+Vec3iu::Vec3iu(uint32_t xv, uint32_t yv, uint32_t zv) : x(xv), y(yv), z(zv) {}
+
+int Vec3iu::width() {
+ auto wx = GetMagnitude(this->x);
+ auto wy = GetMagnitude(this->y);
+ auto wz = GetMagnitude(this->z);
+
+ return std::max(wx, std::max(wy, wz));
+}
+
+std::ostream& operator<< (std::ostream& stream, const Vec3iu& vec) {
+ int width = stream.width();
+
+ stream << std::setw(0) << "{" << std::setw(width) << vec.x << ", " << std::setw(width) << vec.y << ", " << std::setw(width) << vec.z << "}";
+ return stream;
+}
+
Vec2f::Vec2f(float xv, float zv) : x(xv), z(zv) {}
int Vec2f::precision() {
diff --git a/src/types/Vec3D.h b/src/types/Vec3D.h
index acb6eea..76a8d5d 100644
--- a/src/types/Vec3D.h
+++ b/src/types/Vec3D.h
@@ -36,6 +36,17 @@ public:
friend std::ostream& operator<< (std::ostream& stream, const Vec3i& vec);
};
+class Vec3iu {
+public:
+ uint32_t x;
+ uint32_t y;
+ uint32_t z;
+
+ Vec3iu(uint32_t xv = 0, uint32_t yv = 0, uint32_t zv = 0);
+ int width();
+ friend std::ostream& operator<< (std::ostream& stream, const Vec3iu& vec);
+};
+
class Vec2f {
public:
float x;
diff --git a/src/utils/Decompressor.cpp b/src/utils/Decompressor.cpp
index 9570ab3..1dd326e 100644
--- a/src/utils/Decompressor.cpp
+++ b/src/utils/Decompressor.cpp
@@ -18,7 +18,7 @@ DataChunk* Decompressor::Decode(const std::vector<uint8_t>& buffer, const uint32
const unsigned char* in_buf = buffer.data() + offset;
- switch (type) {
+ switch (type) {
case CompressionType::MIO0: {
mio0_header_t head;
if(!mio0_decode_header(in_buf, &head)){