From ffbb9d54380dd51e9d4d6e6b0c7d8d6f46b49b85 Mon Sep 17 00:00:00 2001 From: MegaMech Date: Sun, 6 Jul 2025 18:06:24 -0600 Subject: [PATCH] [Enhancement] Implement Digital Speedometer (#431) * Fix crash * Poorly document camera * Fix harder cpu items * Fix item * Prevent Rare Infinite Loop * Impl Digital Speedometer * Update PortMenu.cpp --------- Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com> --- src/code_80057C60.c | 5 +++- src/menu_items.c | 53 ++++++++++++++++++++++++++++++++++++++++ src/menu_items.h | 2 ++ src/port/ui/PortMenu.cpp | 4 +++ src/render_objects.c | 15 ++++++++++-- src/render_objects.h | 3 ++- 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/code_80057C60.c b/src/code_80057C60.c index 80fe9126e..08586698a 100644 --- a/src/code_80057C60.c +++ b/src/code_80057C60.c @@ -951,7 +951,10 @@ void func_80058F78(void) { draw_simplified_lap_count(PLAYER_ONE); func_8004EB38(0); if (D_801657E6 != false) { - func_8004ED40(0); + if (CVarGetInteger("gEnableDigitalSpeedometer", false) == true) { + render_digital_speedometer(PLAYER_ONE); + } + render_speedometer(PLAYER_ONE); } } } diff --git a/src/menu_items.c b/src/menu_items.c index 17a53d7df..f1039c5f3 100644 --- a/src/menu_items.c +++ b/src/menu_items.c @@ -2285,6 +2285,55 @@ void print_text2(s32 column, s32 row, char* text, s32 tracking, f32 scaleX, f32 FrameInterpolation_ShouldInterpolateFrame(true); } +void print_text2_wide(s32 column, s32 row, char* text, s32 tracking, f32 scaleX, f32 scaleY, s32 arg6) { + MenuTexture* glyphTexture; + s32 characterWidth; + s32 glyphIndex; + + if (text == NULL) { + // @port if invalid text is loaded it will skip rendering it. + return; + } + + // @port Skip Interpolation, if interpolated later remove this tag + FrameInterpolation_ShouldInterpolateFrame(false); + + gSPDisplayList(gDisplayListHead++, D_020077A8); + if (*text != 0) { + do { + glyphIndex = char_to_glyph_index(text); + if (glyphIndex >= 0) { + glyphTexture = (MenuTexture*) segmented_to_virtual_dupe((const void*) gGlyphTextureLUT[glyphIndex]); + load_menu_img(glyphTexture); + gDisplayListHead = + print_letter_wide_right(gDisplayListHead, glyphTexture, column - (gGlyphDisplayWidth[glyphIndex] / 2), row, + arg6, scaleX, scaleY); + if ((glyphIndex >= 0xD5) && (glyphIndex < 0xE0)) { + characterWidth = 0x20; + } else { + characterWidth = 0xC; + } + column = column + (s32) ((characterWidth + tracking) * scaleX); + } else if ((glyphIndex != -2) && (glyphIndex == -1)) { + column = column + (s32) ((tracking + 7) * scaleX); + } else { + gSPDisplayList(gDisplayListHead++, D_020077D8); + return; + } + if (glyphIndex >= 0x30) { + text += 2; + } else { + text += 1; + } + } while (*text != 0); + } + + gSPDisplayList(gDisplayListHead++, D_020077D8); + + // @port Resume Interpolation, if interpolated later remove this tag + FrameInterpolation_ShouldInterpolateFrame(true); +} + void func_800939C8(s32 column, s32 row, char* text, s32 tracking, f32 scaleX, f32 scaleY) { print_text2(column, row, text, tracking, scaleX, scaleY, 1); } @@ -2293,6 +2342,10 @@ void text_draw(s32 column, s32 row, char* text, s32 tracking, f32 scaleX, f32 sc print_text2(column, row, text, tracking, scaleX, scaleY, 2); } +void text_draw_wide(s32 column, s32 row, char* text, s32 tracking, f32 scaleX, f32 scaleY) { + print_text2_wide(column, row, text, tracking, scaleX, scaleY, 2); +} + void func_80093A30(s32 arg0) { func_8009E2A8(D_800F0B1C[arg0]); } diff --git a/src/menu_items.h b/src/menu_items.h index ab5066649..7ba35d1e6 100644 --- a/src/menu_items.h +++ b/src/menu_items.h @@ -377,8 +377,10 @@ void print_text1_center_mode_1(s32, s32, char*, s32, f32, f32); void print_text1_right(s32, s32, char*, s32, f32, f32); void print_text1_center_mode_2(s32, s32, char*, s32, f32, f32); void print_text2(s32, s32, char*, s32, f32, f32, s32); +void print_text2_wide(s32, s32, char*, s32, f32, f32, s32); void func_800939C8(s32, s32, char*, s32, f32, f32); void text_draw(s32, s32, char*, s32, f32, f32); +void text_draw_wide(s32, s32, char*, s32, f32, f32); void func_80093A30(s32); void func_80093A5C(u32); void func_80093B70(u32); diff --git a/src/port/ui/PortMenu.cpp b/src/port/ui/PortMenu.cpp index 686574d93..65f169a8c 100644 --- a/src/port/ui/PortMenu.cpp +++ b/src/port/ui/PortMenu.cpp @@ -367,6 +367,10 @@ void PortMenu::AddEnhancements() { .PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger("gEnableCustomCC", 0); }) .Options(FloatSliderOptions().Min(0.0f).Max(1000.0f).DefaultValue(150.0f).Step(10.0f)); + AddWidget(path, "Enable Digital Speedometer", WIDGET_CVAR_CHECKBOX) + .CVar("gEnableDigitalSpeedometer") + .Options(CheckboxOptions().Tooltip("Welcome to the modern era")); + AddWidget(path, "Harder CPU", WIDGET_CVAR_CHECKBOX).CVar("gHarderCPU"); path = { "Enhancements", "Cheats", SECTION_COLUMN_1 }; diff --git a/src/render_objects.c b/src/render_objects.c index b30eeb91d..13238bae9 100644 --- a/src/render_objects.c +++ b/src/render_objects.c @@ -2698,13 +2698,24 @@ void func_8004EB38(s32 playerId) { } } +void render_digital_speedometer(s32 playerIdx) { + char str[16]; + f32 speed = (gPlayers[playerIdx].speed / 18.0f) * 216.0f; + set_text_color(TEXT_YELLOW); + + sprintf(str, "%.2f", speed); + + text_draw_wide(270, 224, str, 0, 0.5f, 0.5f); +} + // render the speedometer for the player -void func_8004ED40(s32 arg0) { +void render_speedometer(s32 playerIdx) { gSPClearGeometryMode(gDisplayListHead++, G_ZBUFFER); - func_8004A2F4(playerHUD[arg0].speedometerX, playerHUD[arg0].speedometerY, 0U, 1.0f, + func_8004A2F4(playerHUD[playerIdx].speedometerX, playerHUD[playerIdx].speedometerY, 0U, 1.0f, // RGBA CM_GetProps()->Minimap.Colour.r, CM_GetProps()->Minimap.Colour.g, CM_GetProps()->Minimap.Colour.b, 0xFF, LOAD_ASSET(common_texture_speedometer), LOAD_ASSET(D_0D0064B0), 64, 96, 64, 48); + // x, y, needle rot func_8004A258(D_8018CFEC, D_8018CFF4, D_8016579E, 1.0f, common_texture_speedometer_needle, D_0D005FF0, 0x40, 0x20, 0x40, 0x20); } diff --git a/src/render_objects.h b/src/render_objects.h index 9ad238eef..1a1604d3d 100644 --- a/src/render_objects.h +++ b/src/render_objects.h @@ -292,7 +292,8 @@ void func_8004E800(s32); void func_8004E998(s32); void func_8004EB30(s32); void func_8004EB38(s32); -void func_8004ED40(s32); +void render_digital_speedometer(s32 playerIdx); +void render_speedometer(s32); void func_8004EE54(s32); void func_8004EF9C(s32);