From c54ef39005eabc17921436f3cc2482ef8efb0bcd Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Wed, 22 Nov 2023 10:49:30 -0600 Subject: Removed GBI, added GeoLayout and Lights extraction --- src/factories/DisplayListFactory.cpp | 406 +++++++++++++++++++---------------- 1 file changed, 226 insertions(+), 180 deletions(-) (limited to 'src/factories/DisplayListFactory.cpp') diff --git a/src/factories/DisplayListFactory.cpp b/src/factories/DisplayListFactory.cpp index 4f01f94..4d8d276 100644 --- a/src/factories/DisplayListFactory.cpp +++ b/src/factories/DisplayListFactory.cpp @@ -6,9 +6,42 @@ #include #include #include +#include "n64/gbi-otr.h" #define C0(pos, width) ((w0 >> (pos)) & ((1U << width) - 1)) +std::unordered_map gF3DTable = { + { "G_VTX", 0x04 }, + { "G_DL", 0x06 }, + { "G_ENDDL", 0xB8 }, + { "G_SETTIMG", 0xFD }, + { "G_MOVEMEM", 0x03 }, + { "G_MV_L0", 0x86 }, + { "G_MV_L1", 0x88 }, + { "G_MV_LIGHT", 0xA }, + { "G_TRI2", 0xB1 }, + { "G_QUAD", -1 } +}; + +std::unordered_map gF3DExTable = { + { "G_VTX", 0x04 }, + { "G_DL", 0x06 }, + { "G_ENDDL", 0xB8 }, + { "G_SETTIMG", 0xFD }, + { "G_MOVEMEM", 0x03 }, + { "G_MV_L0", 0x86 }, + { "G_MV_L1", 0x88 }, + { "G_MV_LIGHT", 0xA }, + { "G_TRI2", 0xB1 }, + { "G_QUAD", 0xB5 } +}; + +std::unordered_map> gGBITable = { + { GBIVersion::f3d, gF3DTable } +}; + +#define GBI(cmd) gGBITable[Companion::Instance->GetGBIVersion()][#cmd] + void GFXDSetGBIVersion(){ switch (Companion::Instance->GetGBIVersion()) { case GBIVersion::f3d: @@ -52,30 +85,18 @@ void DListCodeExporter::Export(std::ostream &write, std::shared_ptr gfxd_endian(gfxd_endian_host, sizeof(uint32_t)); gfxd_macro_fn([] { auto gfx = static_cast(gfxd_macro_data()); - auto opcode = (gfx->words.w0 >> 24) & 0xFF; + const uint8_t opcode = (gfx->words.w0 >> 24) & 0xFF; gfxd_puts(fourSpaceTab); - #define QUAD 0xB5 - #define TRI2 0xB1 - - switch(opcode) { - - // For mk64 only - case QUAD: - if (Companion::Instance->GetGBIMinorVersion() == GBIMinorVersion::Mk64) { - GFXDOverride::Quadrangle(gfx); - } else { - gfxd_macro_dflt(); - } - break; - // Prevents mix and matching of quadrangle commands. Forces 2TRI only. - case TRI2: - GFXDOverride::Triangle2(gfx); - break; - default: - gfxd_macro_dflt(); - break; + // For mk64 only + if(opcode == GBI(G_QUAD) && Companion::Instance->GetGBIMinorVersion() == GBIMinorVersion::Mk64) { + GFXDOverride::Quadrangle(gfx); + // Prevents mix and matching of quadrangle commands. Forces 2TRI only. + } else if(opcode == GBI(G_TRI2)) { + GFXDOverride::Triangle2(gfx); + } else { + gfxd_macro_dflt(); } gfxd_puts(",\n"); @@ -116,7 +137,6 @@ void DebugDisplayList(uint32_t w0, uint32_t w1){ //gfxd_light_callback(GFXDOverride::Light); GFXDSetGBIVersion(); gfxd_execute(); - int bp = 0; } void DListBinaryExporter::Export(std::ostream &write, std::shared_ptr raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { @@ -134,95 +154,106 @@ void DListBinaryExporter::Export(std::ostream &write, std::shared_ptr(bhash >> 32)); writer.Write(static_cast(bhash & 0xFFFFFFFF)); -#ifndef _WIN32 -#define case case (uint8_t) -#endif - for(size_t i = 0; i < cmds.size(); i+=2){ auto w0 = cmds[i]; auto w1 = cmds[i + 1]; uint8_t opcode = w0 >> 24; - switch (opcode) { - case G_VTX: { - auto nvtx = (C0(0, 16)) / sizeof(Vtx); - auto didx = C0(16, 4); - uint32_t ptr = SEGMENT_OFFSET(w1); - - if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); decl.has_value()){ - uint64_t hash = CRC64(std::get<0>(decl.value()).c_str()); - SPDLOG_INFO("Found vtx: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(decl.value())); - - // TODO: Find a better way to do this because its going to break on other games - Gfx value = gsSPVertexOTR(didx, nvtx, 0); + if(opcode == GBI(G_VTX)) { + auto nvtx = (C0(0, 16)) / sizeof(Vtx); + auto didx = C0(16, 4); + uint32_t ptr = SEGMENT_OFFSET(w1); - SPDLOG_INFO("gsSPVertex({}, {}, 0x{:X})", nvtx, didx, ptr); + if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); decl.has_value()){ + uint64_t hash = CRC64(std::get<0>(decl.value()).c_str()); + SPDLOG_INFO("Found vtx: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(decl.value())); - w0 = value.words.w0; - w1 = value.words.w1; + // TODO: Find a better way to do this because its going to break on other games + Gfx value = gsSPVertexOTR(didx, nvtx, 0); - writer.Write(w0); - writer.Write(w1); + SPDLOG_INFO("gsSPVertex({}, {}, 0x{:X})", nvtx, didx, ptr); - w0 = hash >> 32; - w1 = hash & 0xFFFFFFFF; - } else { - SPDLOG_WARN("Warning: Could not find vtx at 0x{:X}", ptr); - } - break; - } - case G_DL: { - auto ptr = SEGMENT_OFFSET(w1); - auto dec = Companion::Instance->GetNodeByAddr(ptr); - - Gfx value = gsSPDisplayListOTRHash(ptr); w0 = value.words.w0; w1 = value.words.w1; writer.Write(w0); writer.Write(w1); - if(dec.has_value()){ - uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); - SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value())); - w0 = hash >> 32; - w1 = hash & 0xFFFFFFFF; - } else { - SPDLOG_WARN("Warning: Could not find display list at 0x{:X}", ptr); - } - break; + w0 = hash >> 32; + w1 = hash & 0xFFFFFFFF; + } else { + SPDLOG_WARN("Warning: Could not find vtx at 0x{:X}", ptr); } - case G_SETTIMG: { - auto ptr = SEGMENT_OFFSET(w1); - auto dec = Companion::Instance->GetNodeByAddr(ptr); + } - Gfx value = gsDPSetTextureImage(C0(21, 3), C0(19, 2), C0(0, 10), ptr); - w0 = value.words.w0 & 0x00FFFFFF; - w0 += (G_SETTIMG_OTR_HASH << 24); - w1 = value.words.w1; + if(opcode == GBI(G_DL)) { + auto ptr = SEGMENT_OFFSET(w1); + auto dec = Companion::Instance->GetNodeByAddr(ptr); - writer.Write(w0); - writer.Write(w1); + Gfx value = gsSPDisplayListOTRHash(ptr); + w0 = value.words.w0; + w1 = value.words.w1; - if(dec.has_value()){ - uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); - SPDLOG_INFO("Found texture: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value())); - w0 = hash >> 32; - w1 = hash & 0xFFFFFFFF; - } else { - SPDLOG_WARN("Warning: Could not find texture at 0x{:X}", ptr); - } - break; + writer.Write(w0); + writer.Write(w1); + + if(dec.has_value()){ + uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); + SPDLOG_INFO("Found display list: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value())); + w0 = hash >> 32; + w1 = hash & 0xFFFFFFFF; + } else { + SPDLOG_WARN("Warning: Could not find display list at 0x{:X}", ptr); + } + } + + if(opcode == GBI(G_MOVEMEM)) { + uint32_t ptr = SEGMENT_OFFSET(w1); + + auto dec = Companion::Instance->GetNodeByAddr(ptr); + + w0 &= 0x00FFFFFF; + w0 += G_MOVEMEM_OTR_HASH << 24; + w1 = 0; + + writer.Write(w0); + writer.Write(w1); + + if(dec.has_value()){ + uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); + SPDLOG_INFO("Found movemem: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value())); + w0 = hash >> 32; + w1 = hash & 0xFFFFFFFF; + } else { + SPDLOG_WARN("Warning: Could not find movemem at 0x{:X}", ptr); + } + } + + if(opcode == GBI(G_SETTIMG)) { + auto ptr = SEGMENT_OFFSET(w1); + auto dec = Companion::Instance->GetNodeByAddr(ptr); + + Gfx value = gsDPSetTextureOTRImage(C0(21, 3), C0(19, 2), C0(0, 10), ptr); + w0 = value.words.w0; + w1 = value.words.w1; + + writer.Write(w0); + writer.Write(w1); + + if(dec.has_value()){ + uint64_t hash = CRC64(std::get<0>(dec.value()).c_str()); + SPDLOG_INFO("Found texture: 0x{:X} Hash: 0x{:X} Path: {}", ptr, hash, std::get<0>(dec.value())); + w0 = hash >> 32; + w1 = hash & 0xFFFFFFFF; + } else { + SPDLOG_WARN("Warning: Could not find texture at 0x{:X}", ptr); } - default: break; } writer.Write(w0); writer.Write(w1); } -#undef case - writer.Finish(write); } @@ -245,119 +276,134 @@ std::optional> DListFactory::parse(std::vector> 24; - gfxs.push_back(w0); - gfxs.push_back(w1); - switch (opcode) { - case static_cast(G_ENDDL): - processing = false; - break; - case static_cast(G_DL): { - auto ptr = SEGMENT_OFFSET(w1); - auto dec = Companion::Instance->GetNodeByAddr(ptr); - - if(!dec.has_value()){ - SPDLOG_INFO("Addr to Display list command at 0x{:X} not in yaml, autogenerating it", w1); - auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1)); - if(!addr.has_value()) { - SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1)); - break; - } + if(opcode == GBI(G_ENDDL)) { + processing = false; + } - auto rom = Companion::Instance->GetRomData(); - auto factory = Companion::Instance->GetFactory("GFX")->get(); - std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_dl_" + Torch::to_hex(w1, false)); - YAML::Node dl; - dl["type"] = "GFX"; - dl["mio0"] = addr.value(); - dl["offset"] = ptr; - dl["symbol"] = output; - auto result = factory->parse(rom, dl); - - if(!result.has_value()){ - break; - } + if(opcode == GBI(G_DL)) { + auto ptr = SEGMENT_OFFSET(w1); + auto dec = Companion::Instance->GetNodeByAddr(ptr); - Companion::Instance->RegisterAsset(output, dl); - } else { - SPDLOG_WARN("Warning: Could not find display list at 0x{:X}", ptr); + if(!dec.has_value()){ + SPDLOG_INFO("Addr to Display list command at 0x{:X} not in yaml, autogenerating it", w1); + auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1)); + if(!addr.has_value()) { + SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1)); + continue; } - break; - } - // Lights1 - case static_cast(G_MOVEMEM): { - uint32_t ptr = SEGMENT_OFFSET(w1); - // Ignore if not a Lights1 command - if ( ( (w0 >> 16) & 0xFF ) != G_MV_L1) { - break; + auto rom = Companion::Instance->GetRomData(); + auto factory = Companion::Instance->GetFactory("GFX")->get(); + std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_dl_" + Torch::to_hex(addr.value() + w1, false)); + YAML::Node dl; + dl["type"] = "GFX"; + dl["mio0"] = addr.value(); + dl["offset"] = ptr; + dl["symbol"] = output; + auto result = factory->parse(rom, dl); + + if(!result.has_value()){ + continue; } - if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); !decl.has_value()){ - SPDLOG_INFO("Addr to Lights1 command at 0x{:X} not in yaml, autogenerating it", w1); - auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1)); - if(!addr.has_value()) { - SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1)); - break; + Companion::Instance->RegisterAsset(output, dl); + } else { + SPDLOG_WARN("Warning: Could not find display list at 0x{:X}", ptr); + } + } + + if(opcode == GBI(G_MOVEMEM)) { + uint8_t index = 0; + uint8_t offset = 0; + uint32_t ptr = SEGMENT_OFFSET(w1); + + switch (Companion::Instance->GetGBIVersion()) { + case GBIVersion::f3d: + index = C0(16, 8); + + if(index < GBI(G_MV_L0)) { + continue; } - auto rom = Companion::Instance->GetRomData(); - auto factory = Companion::Instance->GetFactory("LIGHTS")->get(); - std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_lights1_" + Torch::to_hex(w1, false)); - YAML::Node light; - light["type"] = "lights"; - light["mio0"] = addr.value(); - light["offset"] = ptr; - light["symbol"] = output; - auto result = factory->parse(rom, light); - if(result.has_value()){ - Companion::Instance->RegisterAsset(output, light); + + break; + default: { + index = C0(0, 8); + offset = C0(8, 8) * 8; + + if(index != GBI(G_MV_LIGHT)) { + continue; } } - break; } - case static_cast(G_VTX): { - uint32_t nvtx; - - switch (gbi) { - case GBIVersion::f3dex2: - nvtx = C0(12, 8); - break; - case GBIVersion::f3dex: - case GBIVersion::f3dexb: - nvtx = C0(10, 6); - break; - default: - nvtx = (C0(0, 16)) / sizeof(Vtx); - break; + + + if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); !decl.has_value()){ + SPDLOG_INFO("Addr to Lights1 command at 0x{:X} not in yaml, autogenerating it", w1); + auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1)); + if(!addr.has_value()) { + SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1)); + continue; + } + auto rom = Companion::Instance->GetRomData(); + auto factory = Companion::Instance->GetFactory("LIGHTS")->get(); + std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_lights1_" + Torch::to_hex(addr.value() + w1, false)); + YAML::Node light; + light["type"] = "lights"; + light["mio0"] = addr.value(); + light["offset"] = ptr; + light["symbol"] = output; + auto result = factory->parse(rom, light); + if(result.has_value()){ + Companion::Instance->RegisterAsset(output, light); } + } + } - uint32_t ptr = SEGMENT_OFFSET(w1); + if(opcode == GBI(G_VTX)) { + uint32_t nvtx; - if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); !decl.has_value()){ - SPDLOG_INFO("Addr to Vtx array at 0x{:X} not in yaml, autogenerating it", w1); - auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1)); - if(!addr.has_value()) { - SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1)); - break; - } + switch (gbi) { + case GBIVersion::f3dex2: + nvtx = C0(12, 8); + break; + case GBIVersion::f3dex: + case GBIVersion::f3dexb: + nvtx = C0(10, 6); + break; + default: + nvtx = (C0(0, 16)) / sizeof(Vtx); + break; + } - auto rom = Companion::Instance->GetRomData(); - auto factory = Companion::Instance->GetFactory("VTX")->get(); - std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_vtx_" + Torch::to_hex(w1, false)); - YAML::Node vtx; - vtx["type"] = "VTX"; - vtx["mio0"] = addr.value(); - vtx["offset"] = ptr; - vtx["count"] = nvtx; - vtx["symbol"] = output; - auto result = factory->parse(rom, vtx); - if(result.has_value()){ - Companion::Instance->RegisterAsset(output, vtx); - } + uint32_t ptr = SEGMENT_OFFSET(w1); + + if(const auto decl = Companion::Instance->GetNodeByAddr(ptr); !decl.has_value()){ + SPDLOG_INFO("Addr to Vtx array at 0x{:X} not in yaml, autogenerating it", w1); + auto addr = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(w1)); + if(!addr.has_value()) { + SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(w1)); + break; + } + + auto rom = Companion::Instance->GetRomData(); + auto factory = Companion::Instance->GetFactory("VTX")->get(); + std::string output = Companion::Instance->NormalizeAsset("seg" + std::to_string(SEGMENT_NUMBER(w1)) +"_vtx_" + Torch::to_hex(addr.value() + w1, false)); + YAML::Node vtx; + vtx["type"] = "VTX"; + vtx["mio0"] = addr.value(); + vtx["offset"] = ptr; + vtx["count"] = nvtx; + vtx["symbol"] = output; + auto result = factory->parse(rom, vtx); + if(result.has_value()){ + Companion::Instance->RegisterAsset(output, vtx); } - break; } } + + gfxs.push_back(w0); + gfxs.push_back(w1); } return std::make_shared(gfxs); -- cgit v1.2.3