Over engineered a solution to a problem that doesn't exist

Signed-off-by: Taggerung <tyler.taggerung@email.com>
This commit is contained in:
Taggerung 2023-09-30 14:09:04 -04:00
parent 525d521ff2
commit 8a77ec0871
1 changed files with 131 additions and 70 deletions

View File

@ -3,21 +3,35 @@
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "libmio0.h"
typedef struct {
struct mk64_Vtx{
short ob[3]; /* x, y, z */
short tc[2]; /* texture coord */
unsigned char ca[4]; /* color & alpha */
};
std::istream & operator >> (std::istream &in, mk64_Vtx &vtx) {
// This is highly dependent on the `mk64_Vtx` type having no padding between its elements
// And that is the case, but its worth noting that its kind of brittle
in.read(reinterpret_cast<char*>(&vtx), sizeof(mk64_Vtx));
return in;
}
struct model_location{
std::string course_name;
uint32_t model_rom_offset;
uint32_t packed_dl_rom_offset;
std::map<uint32_t, std::string> textures;
} model_location;
};
std::vector<model_location> all_models = {
{ "mario_raceway", 0x88fa10, 0x899104,
{ "mario_raceway", 0x88fa10, 0x899104,
// This works, but is very painful to setup
// We'd probably have to create a master material file
// that all courses would reference, rather than one-per-course
@ -54,43 +68,68 @@ std::vector<model_location> all_models = {
{ 0x15800, "sign_koopa_air_1" },
}
},
// { 0x89b510, 0x8A55C4, "choco_mountain" },
// { 0x8a7640, 0x8B59A8, "bowsers_castle" },
// { 0x8b9630, 0x8BFF18, "banshee_boardwalk" },
// { 0x8c2510, 0x8CA2A0, "yoshi_valley" },
// { 0x8cc900, 0x8D6624, "frappe_snowland" },
// { 0x8d8e50, 0x8E8BC8, "koopa_troopa_beach" },
// { 0x8ec390, 0x8FAFF0, "royal_raceway" },
// { 0x8fe640, 0x907E40, "luigi_raceway" },
// { 0x90b3e0, 0x918ECC, "moo_moo_farm" },
// { 0x91b980, 0x925F50, "toads_turnpike" },
// { 0x928c70, 0x934004, "kalimari_desert" },
// { 0x936fd0, 0x93B9C8, "sherbet_land" },
// { 0x93cc60, 0x9426BC, "rainbow_road" },
// { 0x9438c0, 0x94E28C, "wario_stadium" },
// { 0x951780, 0x953058, "block_fort" },
// { 0x953890, 0x954F08, "skyscraper" },
// { 0x955620, 0x9562F4, "double_deck" },
// { "choco_mountain", 0x89b510, 0x8A55C4, },
// { "bowsers_castle", 0x8a7640, 0x8B59A8, },
// { "banshee_boardwalk", 0x8b9630, 0x8BFF18, },
// { "yoshi_valley", 0x8c2510, 0x8CA2A0, },
// { "frappe_snowland", 0x8cc900, 0x8D6624, },
// { "koopa_troopa_beach", 0x8d8e50, 0x8E8BC8, },
// { "royal_raceway", 0x8ec390, 0x8FAFF0, },
// { "luigi_raceway", 0x8fe640, 0x907E40, },
// { "moo_moo_farm", 0x90b3e0, 0x918ECC, },
// { "toads_turnpike", 0x91b980, 0x925F50, },
// { "kalimari_desert", 0x928c70, 0x934004, },
// { "sherbet_land", 0x936fd0, 0x93B9C8, },
// { "rainbow_road", 0x93cc60, 0x9426BC, },
// { "wario_stadium", 0x9438c0, 0x94E28C, },
// { "block_fort", 0x951780, 0x953058, },
// { "skyscraper", 0x953890, 0x954F08, },
{ "double_deck", 0x955620, 0x9562F4,
{
{ 0x00000, "gray_cobblestone" },
{ 0x00800, "texture_642978" },
}
},
// { 0x956670, 0x960ACC, "dks_jungle_parkway" },
// { 0x963ef0, 0x965A74, "big_donut" },
};
typedef struct {
short ob[3]; /* x, y, z */
short tc[2]; /* texture coord */
unsigned char ca[4]; /* color & alpha */
} mk64_Vtx;
std::istream & operator >> (std::istream &in, mk64_Vtx &vtx) {
// This is highly dependent on the `mk64_Vtx` type having no padding between its elements
// And that is the case, but its worth noting that its kind of brittle
in.read(reinterpret_cast<char*>(&vtx), sizeof(mk64_Vtx));
return in;
}
typedef struct {
struct uv{
float u, v;
} uv;
} ;
struct node{
uint32_t address = 0;
std::shared_ptr<node> parent = nullptr;
std::vector<std::shared_ptr<node>> children;
// There's no byte stream, so a stringstream will
// have to do instead
std::stringstream face_string;
};
// Emit leaf nodes in tree in DFS order
void parse_tree(std::shared_ptr<node> root, std::stringstream &face_string) {
// Doing this silly check as a way to differentiate
// leaf nodes from traversal nodes.
if (!root->children.empty()) {
/*
Children "top to bottom" in dl file
*/
face_string << "o object" << std::to_string(root->address) << std::endl;
for (auto child : root->children) {
parse_tree(child, face_string);
}
/*
Children "bottom to top" in dl file
for (auto child = std::rbegin(root->children); child != std::rend(root->children); child++) {
parse_tree(*child, face_string);
}
*/
} else {
// face_string << "o object" << std::to_string(root->address) << std::endl;
face_string << root->face_string.str();
}
}
inline short bswap(short in) {
return ((in & 0xFF) << 8) | ((in >> 8) & 0xFF);
@ -102,14 +141,12 @@ int main(int argc, char **argv) {
int num_tris;
uint8_t opcode, data_byte;
uint16_t data_short;
uint32_t texture_addr;
uint32_t dl_count, texture_addr;
float texture_height, texture_width, texture_extra_multi;
short vtx_index;
short v1, v2, v3;
int object_num = 0;
int face_group_num = 0;
std::vector<mk64_Vtx> vtx_list;
std::map<short, uv> uv_list;
std::ofstream vtx_obj;
std::ofstream model_inc;
std::ifstream model_bytes;
@ -126,6 +163,10 @@ int main(int argc, char **argv) {
std::stringstream vtx_tc_string;
std::stringstream model_string;
std::stringstream face_string;
std::map<short, uv> uv_list;
std::map<uint32_t, std::shared_ptr<node>> node_map;
std::vector<mk64_Vtx> vtx_list;
std::shared_ptr<node> anode;
vtx_obj_path = "./courses/" + model.course_name + "/course.obj";
model_inc_path = "./courses/" + model.course_name + "/course.vtx";
@ -172,7 +213,9 @@ int main(int argc, char **argv) {
// Should probably confirm that the file open actually worked
model_bytes.open(argv[1], std::ios::in | std::ios::binary);
model_bytes.seekg(model.packed_dl_rom_offset);
face_string << "o object" << std::to_string(object_num++) << std::endl;
dl_count = 0;
anode = std::make_shared<node>();
while(model_bytes.read(reinterpret_cast<char*>(&opcode), 1)) {
if (opcode == 0xFF) {
break;
@ -186,11 +229,13 @@ int main(int argc, char **argv) {
**/
if ((0x33 <= opcode) && (opcode <= 0x52)) { // unpack_vtx2, gsSPVertex
// 3 bytes including opcode
dl_count += 1;
model_bytes.read(reinterpret_cast<char*>(&data_short), 2);
vtx_index = data_short + 1;
face_string << "g face_group" << std::to_string(face_group_num++) << std::endl;
anode->face_string << "g face_group" << std::to_string(face_group_num++) << std::endl;
} else if (opcode == 0x28) { // unpack_vtx1, gsSPVertex
// 5 bytes including the opcode
dl_count += 1;
model_bytes.read(reinterpret_cast<char*>(&data_short), 2);
vtx_index = data_short + 1;
// Only need the vertex "address", skip the other 2 bytes
@ -202,6 +247,7 @@ int main(int argc, char **argv) {
* 0x58: unpack_quadrangle, gsSP2Triangles
* 5 bytes including opcode
**/
dl_count += 1;
if (opcode == 0x29) {
num_tris = 1;
} else {
@ -219,39 +265,38 @@ int main(int argc, char **argv) {
v1 += vtx_index;
v2 += vtx_index;
v3 += vtx_index;
face_string << "f ";
// v index / vt index /
face_string << std::to_string(v1) << "/" << std::to_string(v1) << "/" << " ";
face_string << std::to_string(v2) << "/" << std::to_string(v2) << "/" << " ";
face_string << std::to_string(v3) << "/" << std::to_string(v3) << "/" << " ";
face_string << std::endl;
anode->face_string << "f ";
// v index / vt index /
anode->face_string << std::to_string(v1) << "/" << std::to_string(v1) << "/" << " ";
anode->face_string << std::to_string(v2) << "/" << std::to_string(v2) << "/" << " ";
anode->face_string << std::to_string(v3) << "/" << std::to_string(v3) << "/" << " ";
anode->face_string << std::endl;
/**
* Supposedly, the tc values need to be scaled down into the range 0.0 to 1.0
* However, doing the expected scaling will leave several u/v values well outside that range
* Blender doesn't care however. For some reason.
**/
uv_list[v1 - 1].u = (bswap(vtx_list[v1 - 1].tc[0] * texture_extra_multi) / 32.0f) / texture_height;
uv_list[v2 - 1].u = (bswap(vtx_list[v2 - 1].tc[0] * texture_extra_multi) / 32.0f) / texture_height;
uv_list[v3 - 1].u = (bswap(vtx_list[v3 - 1].tc[0] * texture_extra_multi) / 32.0f) / texture_height;
uv_list[v1 - 1].v = 1.0 - ((bswap(vtx_list[v1 - 1].tc[1] * texture_extra_multi) / 32.0f) / texture_width);
uv_list[v2 - 1].v = 1.0 - ((bswap(vtx_list[v2 - 1].tc[1] * texture_extra_multi) / 32.0f) / texture_width);
uv_list[v3 - 1].v = 1.0 - ((bswap(vtx_list[v3 - 1].tc[1] * texture_extra_multi) / 32.0f) / texture_width);
uv_list[v1 - 1].u = ((bswap(vtx_list[v1 - 1].tc[0]) * texture_extra_multi) / 32.0f) / texture_height;
uv_list[v2 - 1].u = ((bswap(vtx_list[v2 - 1].tc[0]) * texture_extra_multi) / 32.0f) / texture_height;
uv_list[v3 - 1].u = ((bswap(vtx_list[v3 - 1].tc[0]) * texture_extra_multi) / 32.0f) / texture_height;
uv_list[v1 - 1].v = 1.0 - (((bswap(vtx_list[v1 - 1].tc[1]) * texture_extra_multi) / 32.0f) / texture_width);
uv_list[v2 - 1].v = 1.0 - (((bswap(vtx_list[v2 - 1].tc[1]) * texture_extra_multi) / 32.0f) / texture_width);
uv_list[v3 - 1].v = 1.0 - (((bswap(vtx_list[v3 - 1].tc[1]) * texture_extra_multi) / 32.0f) / texture_width);
}
} else if (opcode == 0x2A) { // unpack_end_displaylist,
// Only 1 byte, the opcode
face_string << "o object" << std::to_string(object_num++) << std::endl;
} else if ((opcode == 0x26) || (opcode == 0x27)) {
/**
* 0x26: unpack_texture_on,
* 0x27: unpack_texture_off,
**/
dl_count += 1;
node_map[anode->address] = std::move(anode);
anode = std::make_shared<node>();
anode->address = dl_count * 8;
} else if (opcode == 0x26) { // unpack_texture_on,
// Only 1 byte, the opcode
if (opcode == 0x26) {
texture_extra_multi = 0xFFFF / 65536.0f;
} else {
texture_extra_multi = 0x0001 / 65536.0f;
}
std::cout << std::to_string(texture_extra_multi) << std::endl;
dl_count += 1;
texture_extra_multi = 1.0f;
} else if(opcode == 0x27) { // unpack_texture_off,
// Only 1 byte, the opcode
dl_count += 1;
texture_extra_multi = 0.0f;
} else if (
((0x00 <= opcode) && (opcode <= 0x19)) ||
((0x2D <= opcode) && (opcode <= 0x2F)) ||
@ -273,18 +318,27 @@ int main(int argc, char **argv) {
* 0x57: unpack_clear_geometry_mode,
**/
// Only 1 byte, the opcode
;
} else if (
((0x1A <= opcode) && (opcode <= 0x1F)) ||
(opcode == 0x2B) || (opcode == 0x2C)) {
if ((0x00 <= opcode) && (opcode <= 0x14)) {
dl_count += 3;
} else {
dl_count += 1;
}
} else if (opcode == 0x2B) { // unpack_displaylist,
// 3 bytes including the opcode
dl_count += 1;
model_bytes.read(reinterpret_cast<char*>(&data_short), 2);
node_map[data_short * 8]->parent = anode;
anode->children.push_back(node_map[data_short * 8]);
} else if (((0x1A <= opcode) && (opcode <= 0x1F)) || (opcode == 0x2C)) {
/**
* 0x1A - 0x1F, 0x2C: unpack_tile_sync,
* 0x2B: unpack_displaylist,
**/
// 3 bytes including the opcode
dl_count += 3;
model_bytes.seekg(2, std::ios_base::cur);
} else if ((0x20 <= opcode) && (opcode <= 0x25)) { // unpack_tile_load_sync,
// 4 bytes including the opcode
dl_count += 5;
switch (opcode) {
case 0x20:
texture_height = 32.0f;
@ -314,10 +368,11 @@ int main(int argc, char **argv) {
model_bytes.read(reinterpret_cast<char*>(&data_byte), 1);
texture_addr = data_byte;
texture_addr <<= 11;
face_string << "usemtl " << model.textures[texture_addr] << std::endl;
anode->face_string << "usemtl " << model.textures[texture_addr] << std::endl;
model_bytes.seekg(2, std::ios_base::cur);
} else if (opcode == 0x30) { // unpack_spline_3D
// 4 bytes including the opcode
dl_count += 1;
model_bytes.seekg(3, std::ios_base::cur);
} else {
std::cout << "WARNING UNEXPECTED opcode: " << std::to_string(opcode) << std::endl;
@ -326,6 +381,12 @@ int main(int argc, char **argv) {
}
model_bytes.close();
for (auto bnode : node_map) {
if (bnode.second->parent == nullptr) {
parse_tree(bnode.second, face_string);
}
}
for (auto tc : uv_list) {
vtx_tc_string << "vt " << std::to_string(tc.second.u) << " " << std::to_string(tc.second.v) << std::endl;
}