summaryrefslogtreecommitdiff
path: root/src/factories/DisplayListFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/factories/DisplayListFactory.cpp')
-rw-r--r--src/factories/DisplayListFactory.cpp406
1 files changed, 226 insertions, 180 deletions
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 <gfxd.h>
#include <fstream>
#include <utils/TorchUtils.h>
+#include "n64/gbi-otr.h"
#define C0(pos, width) ((w0 >> (pos)) & ((1U << width) - 1))
+std::unordered_map<std::string, uint8_t> 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<std::string, uint8_t> 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<GBIVersion, std::unordered_map<std::string, uint8_t>> 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<IParsedData>
gfxd_endian(gfxd_endian_host, sizeof(uint32_t));
gfxd_macro_fn([] {
auto gfx = static_cast<const Gfx*>(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<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
@@ -134,95 +154,106 @@ void DListBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedDat
writer.Write(static_cast<uint32_t>(bhash >> 32));
writer.Write(static_cast<uint32_t>(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<std::shared_ptr<IParsedData>> DListFactory::parse(std::vector<uint
auto w1 = reader.ReadUInt32();
uint8_t opcode = w0 >> 24;
- gfxs.push_back(w0);
- gfxs.push_back(w1);
- switch (opcode) {
- case static_cast<uint8_t>(G_ENDDL):
- processing = false;
- break;
- case static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(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<DListData>(gfxs);