mirror of https://github.com/n64decomp/mk64.git
Over engineered a solution to a problem that doesn't exist
Signed-off-by: Taggerung <tyler.taggerung@email.com>
This commit is contained in:
parent
525d521ff2
commit
8a77ec0871
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue