summaryrefslogtreecommitdiff
path: root/src/engine/courses/Course.cpp
diff options
context:
space:
mode:
authorcoco875 <59367621+coco875@users.noreply.github.com>2025-12-07 15:34:53 +0100
committerGitHub <noreply@github.com>2025-12-07 07:34:53 -0700
commit02ad54ca72f5baf4614cb9b7c30f8dd780764d90 (patch)
treebd2719a154830d4c538e0caf91eb845ddb45552d /src/engine/courses/Course.cpp
parenteec7d650482134352b7cde4801b979ce1ed2044e (diff)
Refactor yaml and remove segment (#531)
* move yaml (still need to fix header path) * fix header * change kart to karts and add migration * fix include * Update migration.py * fix common_texture_debug_font extraction * Update torch * update torch and header * unduplicate texture for tumble * Update torch * Update migration.py * put the sort by default * fix replace_segmented_textures_with_o2r_textures * Update torch * fix yamls * add manual_segments in data of course * comment out replace_segmented_textures_with_o2r_textures and segment 3 * remove segment 5 * (wip) remove segment 6 still plenty of thing to do * more vtx * more change * Update torch * small fix * Update BansheeBoardwalk.cpp * fix blockFort * Delete test.yaml * fix bowser castle and simplify track sections * fix choco mountain * clean banshee * fix dk jungle * fix double deck * fix macos * fix error * fix macos ci * Update torch * Update torch * fix frappe snowland * fix kalimari desert * fix koopa troopa beach * fix luigi raceway * fix mario raceway and simplify thing * fix moo moo farm * fix rainbow road * Update torch * Update torch * hopefully fix windows error * fix a small error * fix royal raceway (and podium in theory) * fix sherbet_land * fix skyscraper * fix toads turnpike * fix wario stadium * fix yoshi valley * update torch * more clang tidy rules * REMOVE totally SEGMENT (sorry for the PR) * remove unused field in course and props and unused packed asset * fix kart texture * fix particle * fix track section and transparency * try fix mode extra * fix macos build and render * fix collision in extra * small change and try fix windows error * a little of clean * more cleanup * forget header and more clean up * Update Makefile * fix credits * fix kart texture offset * remove LoadTextures and add Unload * fix definitevely mirror mode * add unload but it's not perfect * revert a bad fix * clean no longer used python script * fix crash with player * being able to load the same course twice * add a comment on DrawWater * fix render of transparent object * better hack * add a proper migration instruction * fix number * add basic modsmanager * add meta/mods.toml * Update EditorMath.h * Update ModsManager.cpp * basic modManager (maybe I should rename it ModLoader) * use range on dependencies * add information about mods.toml * fix coment * some rename around * Delete beta-to-v1.md * Update migrations.md * Update textures-pack.md * Update modding.md * Update modding.md * clean yamls_old * move to mods in engine * rename ModsManger to ModManager * move init and unload at the top * rename ModsMetadata to ModMetadata * fix header * Update ModManager.cpp * put core mods at top
Diffstat (limited to 'src/engine/courses/Course.cpp')
-rw-r--r--src/engine/courses/Course.cpp279
1 files changed, 219 insertions, 60 deletions
diff --git a/src/engine/courses/Course.cpp b/src/engine/courses/Course.cpp
index 3ad991f0a..2cc812d9f 100644
--- a/src/engine/courses/Course.cpp
+++ b/src/engine/courses/Course.cpp
@@ -1,4 +1,7 @@
#include <libultraship.h>
+#include <unordered_set>
+#include <string>
+#include <cstring>
#include "Course.h"
#include "MarioRaceway.h"
@@ -8,6 +11,8 @@
#include "port/resource/type/TrackSections.h"
#include "engine/editor/SceneManager.h"
#include "Registry.h"
+#include "resourcebridge.h"
+#include "align_asset_macro.h"
extern "C" {
#include "main.h"
@@ -17,7 +22,7 @@ extern "C" {
#include "some_data.h"
#include "code_8006E9C0.h"
#include "code_8003DC40.h"
-#include "assets/common_data.h"
+#include "assets/models/common_data.h"
#include "render_objects.h"
#include "save.h"
#include "replays.h"
@@ -40,6 +45,204 @@ void ResizeMinimap(MinimapProps* minimap) {
}
}
+static std::unordered_set<std::string> gModifiedGfxSet;
+
+static void SwapTriangleVertices(Gfx* cmd) {
+ int8_t opcode = cmd->words.w0 >> 24;
+
+ if (opcode == G_TRI1) {
+ uint32_t w1 = cmd->words.w1;
+ uint8_t v0 = (w1 >> 16) & 0xFF;
+ uint8_t v1 = (w1 >> 8) & 0xFF;
+ uint8_t v2 = w1 & 0xFF;
+
+ cmd->words.w1 = (v0 << 16) | (v2 << 8) | v1;
+ }
+ else if (opcode == G_TRI1_OTR) {
+ uint32_t w0 = cmd->words.w0;
+ uint32_t w1 = cmd->words.w1;
+ uint16_t v0 = w0 & 0xFFFF;
+ uint16_t v1 = (w1 >> 16) & 0xFFFF;
+ uint16_t v2 = w1 & 0xFFFF;
+
+ cmd->words.w0 = (opcode << 24) | v0;
+ cmd->words.w1 = (v2 << 16) | v1;
+ }
+ else if (opcode == G_TRI2 || opcode == G_QUAD) {
+ uint32_t w0 = cmd->words.w0;
+ uint8_t v0_a = (w0 >> 16) & 0xFF;
+ uint8_t v1_a = (w0 >> 8) & 0xFF;
+ uint8_t v2_a = w0 & 0xFF;
+
+ uint32_t w1 = cmd->words.w1;
+ uint8_t v0_b = (w1 >> 16) & 0xFF;
+ uint8_t v1_b = (w1 >> 8) & 0xFF;
+ uint8_t v2_b = w1 & 0xFF;
+
+ cmd->words.w0 = (opcode << 24) | (v0_a << 16) | (v2_a << 8) | v1_a;
+ cmd->words.w1 = (v0_b << 16) | (v2_b << 8) | v1_b;
+ }
+}
+
+static void InvertTriangleWindingInternal(Gfx* gfx, const char* gfxName, bool shouldSwap) {
+ if (gfx == nullptr) {
+ return;
+ }
+
+ if (GameEngine_OTRSigCheck((char*)gfx)) {
+ gfx = (Gfx*)LOAD_ASSET(gfx);
+ }
+
+ if (gfxName != nullptr) {
+ std::string nameStr(gfxName);
+ if (gModifiedGfxSet.find(nameStr) != gModifiedGfxSet.end()) {
+ return;
+ }
+ gModifiedGfxSet.insert(nameStr);
+ }
+
+ Gfx* cmd = gfx;
+
+ for (int i = 0; i < 0x1FFF; i++) {
+ int8_t opcode = cmd->words.w0 >> 24;
+
+ switch (opcode) {
+ case G_TRI1:
+ case G_TRI1_OTR:
+ case G_TRI2:
+ case G_QUAD:
+ if (shouldSwap) {
+ SwapTriangleVertices(cmd);
+ }
+ break;
+ case G_DL: {
+ Gfx* subDL = (Gfx*)(uintptr_t)cmd->words.w1;
+ InvertTriangleWindingInternal(subDL, nullptr, shouldSwap);
+ break;
+ }
+ case G_DL_OTR_HASH: {
+ cmd++;
+ i++;
+ uint64_t hash = ((uint64_t)cmd->words.w0 << 32) | cmd->words.w1;
+ const char* name = ResourceGetNameByCrc(hash);
+ if (name != nullptr) {
+ bool subShouldSwap = (strstr(name, "packed") != nullptr);
+ Gfx* subDL = (Gfx*)ResourceGetDataByCrc(hash);
+ InvertTriangleWindingInternal(subDL, name, subShouldSwap);
+ }
+ break;
+ }
+ case G_DL_OTR_FILEPATH: {
+ const char* name = (const char*)(uintptr_t)cmd->words.w1;
+ if (name != nullptr) {
+ bool subShouldSwap = (strstr(name, "packed") != nullptr);
+ Gfx* subDL = (Gfx*)ResourceGetDataByName(name);
+ InvertTriangleWindingInternal(subDL, name, subShouldSwap);
+ }
+ break;
+ }
+ case G_VTX_OTR_FILEPATH:
+ case G_VTX_OTR_HASH:
+ cmd++;
+ i++;
+ break;
+ case G_MARKER: {
+ cmd++;
+ i++;
+ uint64_t hash = ((uint64_t)cmd->words.w0 << 32) | cmd->words.w1;
+ const char* name = ResourceGetNameByCrc(hash);
+ if (name != nullptr && gfxName == nullptr) {
+ std::string nameStr(name);
+ if (gModifiedGfxSet.find(nameStr) != gModifiedGfxSet.end()) {
+ return;
+ }
+ gModifiedGfxSet.insert(nameStr);
+ shouldSwap = (strstr(name, "packed") != nullptr);
+ }
+ break;
+ }
+ case G_MTX_OTR:
+ case G_SETTIMG_OTR_HASH:
+ cmd++;
+ i++;
+ break;
+ case G_ENDDL:
+ return;
+ default:
+ break;
+ }
+
+ cmd++;
+ }
+}
+
+void InvertTriangleWinding(Gfx* gfx) {
+ InvertTriangleWindingInternal(gfx, nullptr, false);
+}
+
+void InvertTriangleWindingByName(const char* name) {
+ if (name == nullptr) {
+ return;
+ }
+ Gfx* gfx = (Gfx*)ResourceGetDataByName(name);
+ bool shouldSwap = (strstr(name, "packed") != nullptr);
+ InvertTriangleWindingInternal(gfx, name, shouldSwap);
+}
+
+void RestoreTriangleWinding() {
+ for (const std::string& name : gModifiedGfxSet) {
+ if (strstr(name.c_str(), "packed") == nullptr) {
+ continue;
+ }
+
+ Gfx* gfx = (Gfx*)ResourceGetDataByName(name.c_str());
+ if (gfx == nullptr) {
+ continue;
+ }
+
+ Gfx* cmd = gfx;
+
+ for (int i = 0; i < 0x1FFF; i++) {
+ int8_t opcode = cmd->words.w0 >> 24;
+
+ switch (opcode) {
+ case G_TRI1:
+ case G_TRI1_OTR:
+ case G_TRI2:
+ case G_QUAD:
+ SwapTriangleVertices(cmd);
+ break;
+
+ case G_DL_OTR_HASH:
+ case G_VTX_OTR_FILEPATH:
+ case G_VTX_OTR_HASH:
+ case G_MARKER:
+ case G_MTX_OTR:
+ case G_SETTIMG_OTR_HASH:
+ cmd++;
+ i++;
+ break;
+
+ case G_ENDDL:
+ goto next_gfx;
+
+ default:
+ break;
+ }
+
+ cmd++;
+ }
+ next_gfx:;
+ }
+
+ gModifiedGfxSet.clear();
+}
+
+bool IsTriangleWindingInverted() {
+ return !gModifiedGfxSet.empty();
+}
+
+
Course::Course() {
Props.SetText(Props.Name, "Blank Track", sizeof(Props.Name));
Props.SetText(Props.DebugName, "blnktrck", sizeof(Props.DebugName));
@@ -111,12 +314,12 @@ Course::Course() {
// Load custom track from code
void Course::Load(Vtx* vtx, Gfx* gfx) {
- gSegmentTable[4] = reinterpret_cast<uintptr_t>(&vtx[0]);
- gSegmentTable[7] = reinterpret_cast<uintptr_t>(&gfx[0]);
-
Course::Init();
}
+void Course::UnLoad() {
+}
+
void Course::LoadO2R(std::string trackPath) {
if (!trackPath.empty()) {
SceneFilePtr = (trackPath + "/scene.json");
@@ -161,7 +364,7 @@ void Course::Load() {
bIsMod = true;
// auto res = std::dynamic_pointer_cast<MK64::TrackSectionsO2RClass>(ResourceLoad(TrackSectionsPtr.c_str()));
- TrackSectionsO2R* sections = (TrackSectionsO2R*) LOAD_ASSET_RAW(TrackSectionsPtr.c_str());
+ TrackSections* sections = (TrackSections*) LOAD_ASSET_RAW(TrackSectionsPtr.c_str());
size_t size = ResourceGetSizeByName(TrackSectionsPtr.c_str());
if (sections != nullptr) {
@@ -178,55 +381,13 @@ void Course::Load() {
return;
}
- // Stock
- size_t vtxSize = (ResourceGetSizeByName(this->vtx) / sizeof(CourseVtx)) * sizeof(Vtx);
- size_t texSegSize;
-
- // Convert course vtx to vtx
- Vtx* vtx = reinterpret_cast<Vtx*>(allocate_memory(vtxSize));
- gSegmentTable[4] = reinterpret_cast<uintptr_t>(&vtx[0]);
- func_802A86A8(reinterpret_cast<CourseVtx*>(LOAD_ASSET_RAW(this->vtx)), vtx, vtxSize / sizeof(Vtx));
-
- // Load and allocate memory for course textures
- const course_texture* asset = this->Props.textures;
- u8* freeMemory = NULL;
- u8* texture = NULL;
- size_t size = 0;
- texSegSize = 0;
- while (asset->addr) {
- size = ResourceGetTexSizeByName(asset->addr);
- freeMemory = (u8*) allocate_memory(size);
-
- texture = (u8*) (asset->addr);
- if (texture) {
- if (asset == &this->Props.textures[0]) {
- gSegmentTable[5] = reinterpret_cast<uintptr_t>(&freeMemory[0]);
- }
- strcpy(reinterpret_cast<char*>(freeMemory), asset->addr);
- // memcpy(freeMemory, texture, size);
- texSegSize += size;
- // printf("Texture Addr: 0x%llX, size 0x%X\n", &freeMemory[0], size);
- }
- asset++;
- }
-
- // Extract packed DLs
- u8* packed = reinterpret_cast<u8*>(LOAD_ASSET_RAW(this->gfx));
- Gfx* gfx = (Gfx*) allocate_memory(sizeof(Gfx) * this->gfxSize); // Size of unpacked DLs
- if (gfx == NULL) {
- printf("Failed to allocate course displaylist memory\n");
- }
-
- gSegmentTable[7] = reinterpret_cast<uintptr_t>(&gfx[0]);
- displaylist_unpack(reinterpret_cast<uintptr_t*>(gfx), reinterpret_cast<uintptr_t>(packed), 0);
-
Course::Init();
}
// C++ version of parse_course_displaylists()
-void Course::ParseCourseSections(TrackSectionsO2R* sections, size_t size) {
+void Course::ParseCourseSections(TrackSections* sections, size_t size) {
printf("\n[Track] Generating Collision Meshes...\n");
- for (size_t i = 0; i < (size / sizeof(TrackSectionsO2R)); i++) {
+ for (size_t i = 0; i < (size / sizeof(TrackSections)); i++) {
if (sections[i].flags & 0x8000) {
D_8015F59C = 1; // single-sided wall
} else {
@@ -242,8 +403,9 @@ void Course::ParseCourseSections(TrackSectionsO2R* sections, size_t size) {
} else {
D_8015F5A4 = 0;
}
- printf(" %s\n", sections[i].addr.c_str());
- generate_collision_mesh((Gfx*) LOAD_ASSET_RAW(sections[i].addr.c_str()), sections[i].surfaceType,
+ const char* name = ResourceGetNameByCrc(sections[i].crc);
+ printf(" %s\n", name);
+ generate_collision_mesh((Gfx*) ResourceGetDataByCrc(sections[i].crc), sections[i].surfaceType,
sections[i].sectionId);
}
printf("[Track] Collision Mesh Generation Complete!\n\n");
@@ -268,7 +430,7 @@ void Course::TestPath() {
}
f32 height = spawn_actor_on_surface(x, 2000.0f, z);
- Vec3f itemPos = { x, height, z };
+ Vec3f itemPos = { (f32) x, height, (f32) z };
add_actor_to_empty_slot(itemPos, rot, vel, ACTOR_ITEM_BOX);
}
}
@@ -293,9 +455,6 @@ void Course::Init() {
D_800DC5C8 = 0;
}
-void Course::LoadTextures() {
-}
-
void Course::BeginPlay() {
printf("[Track] BeginPlay\n");
TestPath();
@@ -388,10 +547,10 @@ void Course::Render(struct UnkStruct_800DC5EC* arg0) {
// d_course_big_donut_packed_dl_DE8
}
- TrackSectionsO2R* sections = (TrackSectionsO2R*) LOAD_ASSET_RAW(TrackSectionsPtr.c_str());
+ TrackSections* sections = (TrackSections*) 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()));
+ for (size_t i = 0; i < (size / sizeof(TrackSections)); i++) {
+ gSPDisplayList(gDisplayListHead++, (Gfx*) ResourceGetDataByCrc(sections[i].crc));
}
}
}
@@ -403,7 +562,7 @@ f32 Course::GetWaterLevel(FVector pos, Collision* collision) {
float highestWater = -FLT_MAX;
bool found = false;
- for (const auto& volume : gWorldInstance.CurrentCourse->WaterVolumes) {
+ for (const auto& volume : gWorldInstance.GetCurrentCourse()->WaterVolumes) {
if (pos.x >= volume.MinX && pos.x <= volume.MaxX && pos.z >= volume.MinZ && pos.z <= volume.MaxZ) {
// Choose the highest water volume the player is over
if (!found || volume.Height > highestWater) {
@@ -414,7 +573,7 @@ f32 Course::GetWaterLevel(FVector pos, Collision* collision) {
}
// If player is not over-top of a water volume then return the courses default water level
- return found ? highestWater : gWorldInstance.CurrentCourse->Props.WaterLevel;
+ return found ? highestWater : gWorldInstance.GetCurrentCourse()->Props.WaterLevel;
}
void Course::ScrollingTextures() {