From b0da83a42fed93c870273876f9042b391fa34bb1 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Fri, 18 Apr 2025 23:27:11 -0600 Subject: [PATCH] Render custom track. Wip collision --- src/engine/courses/Course.cpp | 14 ++-- src/engine/courses/Course.h | 1 + src/port/ui/ContentBrowser.cpp | 2 +- src/racing/collision.c | 114 ++++++++++++++++++++++++++------- 4 files changed, 103 insertions(+), 28 deletions(-) diff --git a/src/engine/courses/Course.cpp b/src/engine/courses/Course.cpp index 3cccf0477..dc5ae1827 100644 --- a/src/engine/courses/Course.cpp +++ b/src/engine/courses/Course.cpp @@ -126,7 +126,7 @@ void Course::Load() { // Load from O2R if (!TrackSectionsPtr.empty()) { - + bIsMod = true; //auto res = std::dynamic_pointer_cast(ResourceLoad(TrackSectionsPtr.c_str())); TrackSectionsO2R* sections = (TrackSectionsO2R*) LOAD_ASSET_RAW(TrackSectionsPtr.c_str()); @@ -304,9 +304,13 @@ void Course::Waypoints(Player* player, int8_t playerId) { } void Course::Render(struct UnkStruct_800DC5EC* arg0) { - //if (!TrackSectionsPtr.empty()) { - // gSPDisplayList(gDisplayListHead++, (Gfx*)LOAD_ASSET_RAW(Props.TrackModel)); - //} + if (!TrackSectionsPtr.empty()) { + TrackSectionsO2R* sections = (TrackSectionsO2R*)LOAD_ASSET_RAW(TrackSectionsPtr.c_str()); + size_t size = ResourceGetSizeByName(TrackSectionsPtr.c_str()); + for (size_t i = 0; i < (size / sizeof(TrackSectionsO2R)); i++) { + gSPDisplayList(gDisplayListHead++, (Gfx*)LOAD_ASSET_RAW(sections[i].addr.c_str())); + } + } } void Course::RenderCredits() { @@ -341,7 +345,7 @@ void Course::Destroy() { } bool Course::IsMod() { - return false; + return bIsMod; } Course* currentCourse = nullptr; diff --git a/src/engine/courses/Course.h b/src/engine/courses/Course.h index cd25ec29b..25eef5539 100644 --- a/src/engine/courses/Course.h +++ b/src/engine/courses/Course.h @@ -234,6 +234,7 @@ public: bool bSpawnFinishline = true; std::optional FinishlineSpawnPoint; std::string TrackSectionsPtr; + bool bIsMod = false; virtual ~Course() = default; diff --git a/src/port/ui/ContentBrowser.cpp b/src/port/ui/ContentBrowser.cpp index 98c4de352..0bafcffbf 100644 --- a/src/port/ui/ContentBrowser.cpp +++ b/src/port/ui/ContentBrowser.cpp @@ -218,7 +218,7 @@ namespace Editor { void ContentBrowserWindow::FindTracks() { // ListFiles(whitelist, blacklist); - auto ptr2 = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->ListFiles({"*/tracks/*"}, {""}); + auto ptr2 = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->ListFiles({"tracks/*/scene.json"}, {""}); if (ptr2) { auto files = *ptr2; std::set uniqueTracks; diff --git a/src/racing/collision.c b/src/racing/collision.c index 751a49a03..b20a44760 100644 --- a/src/racing/collision.c +++ b/src/racing/collision.c @@ -1685,7 +1685,7 @@ void add_collision_triangle(Vtx* vtx1, Vtx* vtx2, Vtx* vtx3, s8 surfaceType, u16 void set_vtx_from_triangle(u32 triangle, s8 surfaceType, u16 sectionId) { u32 vert1 = ((triangle & 0x00FF0000) >> 16) / 2; u32 vert2 = ((triangle & 0x0000FF00) >> 8) / 2; - u32 vert3 = (triangle & 0x000000FF) / 2; + u32 vert3 = (triangle & 0x000000FF) / 2; Vtx* vtx1 = vtxBuffer[vert1]; Vtx* vtx2 = vtxBuffer[vert2]; @@ -1948,8 +1948,9 @@ u32 numTimes = 0; /** * Generate via a recursive search and set for vertex data. */ +bool is_cull_box(const char* filePath); void generate_collision_mesh(Gfx* addr, s8 surfaceType, u16 sectionId) { - s32 opcode; + int8_t opcode; uintptr_t lo; uintptr_t hi; s32 i; @@ -1973,41 +1974,110 @@ void generate_collision_mesh(Gfx* addr, s8 surfaceType, u16 sectionId) { for (i = 0; i < 0x1FFF; i++) { lo = gfx->words.w0; hi = gfx->words.w1; - opcode = GFX_GET_OPCODE(lo); + opcode = GFX_GET_OPCODE(lo) >> 24; // printf("ptr 0x%llX\n", &addr); // printf("op 0x%llX\n", opcode); // printf("w0 0x%llX\n", lo); // printf("w1 0x%llX\n", hi); - if (opcode == (G_DL << 24)) { - // G_DL's hi contains an addr to another DL. - generate_collision_mesh((Gfx*) hi, surfaceType, sectionId); + switch(opcode) { + case G_DL: + // G_DL's hi contains an addr to another DL. + generate_collision_mesh((Gfx*) hi, surfaceType, sectionId); + break; + case G_DL_OTR_FILEPATH: + generate_collision_mesh(ResourceGetDataByName((const char*)hi), surfaceType, sectionId); + break; + case G_VTX: + set_vtx_buffer((hi), (lo >> 10) & 0x3F, ((lo >> 16) & 0xFF) >> 1); + break; + case G_VTX_OTR_FILEPATH: { + const char* filePath = (const char*)hi; + // Fast64 outputs garbage data. Lets skip that... + if (is_cull_box(filePath)) { + printf("Skipped cull box\n"); + gfx++; + continue; + } + gfx++; + size_t count = gfx->words.w0; + size_t index = (gfx->words.w1 >> 16); + size_t vtxDataOff = gfx->words.w1 & 0xFFFF; + Vtx* vtx = ( (Vtx*)ResourceGetDataByName(filePath) ) + vtxDataOff; - } else if (opcode == (G_VTX << 24)) { - set_vtx_buffer((hi), (lo >> 10) & 0x3F, ((lo >> 16) & 0xFF) >> 1); + set_vtx_buffer(vtx, count, index); + break; + } + case G_TRI1: + D_8015F58C += 1; + set_vtx_from_triangle(hi, surfaceType, sectionId); + break; + case G_TRI1_OTR: { + uint32_t v1 = (lo & 0x0000FFFF) * 2; + uint32_t v2 = (hi >> 16) * 2; + uint32_t v3 = (hi & 0x0000FFFF) * 2; - } else if (opcode == (G_TRI1 << 24)) { - D_8015F58C += 1; - set_vtx_from_triangle(hi, surfaceType, sectionId); + // Repack into a format supported by f3dex + uint32_t repack = (v1 << 16) | (v2 << 8) | v3; - } else if (opcode == (G_TRI2 << 24)) { - D_8015F58C += 2; - - set_vtx_from_tri2(lo, hi, surfaceType, sectionId); - - } else if (opcode == (G_QUAD << 24)) { - D_8015F58C += 2; - set_vtx_from_quadrangle(hi, surfaceType, sectionId); - - } else if (opcode == (int32_t) (G_ENDDL << 24)) { - break; + D_8015F58C += 1; + set_vtx_from_triangle(repack, surfaceType, sectionId); + break; + } + case G_TRI2: + D_8015F58C += 2; + set_vtx_from_tri2(lo, hi, surfaceType, sectionId); + break; + case G_QUAD: + D_8015F58C += 2; + set_vtx_from_quadrangle(hi, surfaceType, sectionId); + break; + case G_ENDDL: + return; // end of loop } + + // if (opcode == (G_DL << 24)) { + // // G_DL's hi contains an addr to another DL. + // generate_collision_mesh((Gfx*) hi, surfaceType, sectionId); + + // } else if (opcode == (G_VTX << 24)) { + // set_vtx_buffer((hi), (lo >> 10) & 0x3F, ((lo >> 16) & 0xFF) >> 1); + + // } else if (opcode == (G_TRI1 << 24)) { + // D_8015F58C += 1; + // set_vtx_from_triangle(hi, surfaceType, sectionId); + + // } else if (opcode == (G_TRI2 << 24)) { + // D_8015F58C += 2; + + // set_vtx_from_tri2(lo, hi, surfaceType, sectionId); + + // } else if (opcode == (G_QUAD << 24)) { + // D_8015F58C += 2; + // set_vtx_from_quadrangle(hi, surfaceType, sectionId); + + // } else if (opcode == (int32_t) (G_ENDDL << 24)) { + // break; + // } + gfx++; } } +bool is_cull_box(const char* filePath) { + const char* suffix = "cull"; + size_t fileLen = strlen(filePath); + size_t suffixLen = strlen(suffix); + + if (fileLen < suffixLen) { + return false; + } + + return strcmp(filePath + fileLen - suffixLen, suffix) == 0; +} + /** * Search for G_SETTILESIZE and set its args. */