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:
MegaMech
2024-04-06 15:36:03 -06:00
committed by GitHub
co-authored by = <=>
parent ad667b705d
commit 24633ebd7c
22 changed files with 921 additions and 76 deletions
+2 -1
View File
@@ -13,4 +13,5 @@ headers/
build/
code/
.vscode/
tools/
tools/
modding/*
+111 -4
View File
@@ -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);
}
+7 -3
View File
@@ -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
View File
@@ -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;
}
+8
View File
@@ -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);
};
+21 -18
View File
@@ -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;
+21 -2
View File
@@ -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();
+2 -2
View File
@@ -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 {
+1 -1
View File
@@ -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";
+1 -1
View File
@@ -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";
}
+11 -5
View File
@@ -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++) {
+1 -1
View File
@@ -3,7 +3,7 @@
#include "BaseFactory.h"
struct MtxRaw {
double mtx[16];
float mtx[16];
};
class MtxData : public IParsedData {
+67 -32
View File
@@ -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:
+1 -1
View File
@@ -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";
}
+375
View File
@@ -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);
}
+70
View File
@@ -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; }
};
}
+2 -2
View File
@@ -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) {
+94
View File
@@ -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);
}
+42
View File
@@ -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; }
};
}
+17
View File
@@ -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