mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
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: = <=>
This commit is contained in:
+2
-1
@@ -13,4 +13,5 @@ headers/
|
||||
build/
|
||||
code/
|
||||
.vscode/
|
||||
tools/
|
||||
tools/
|
||||
modding/*
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+55
-2
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "BaseFactory.h"
|
||||
|
||||
struct MtxRaw {
|
||||
double mtx[16];
|
||||
float mtx[16];
|
||||
};
|
||||
|
||||
class MtxData : public IParsedData {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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; }
|
||||
};
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user