From 46b1a8bbb9f6ece7a673a7123c2dd613c9c0c939 Mon Sep 17 00:00:00 2001 From: Isaac0-dev <62234577+Isaac0-dev@users.noreply.github.com> Date: Sat, 26 Jul 2025 09:56:14 +1000 Subject: [PATCH] auto framerate mode --- lang/Czech.ini | 2 ++ lang/Dutch.ini | 2 ++ lang/English.ini | 4 +++- lang/French.ini | 2 ++ lang/German.ini | 2 ++ lang/Italian.ini | 2 ++ lang/Japanese.ini | 2 ++ lang/Polish.ini | 2 ++ lang/Portuguese.ini | 2 ++ lang/Russian.ini | 2 ++ lang/Spanish.ini | 2 ++ src/pc/configfile.c | 5 +++-- src/pc/configfile.h | 9 +++++++- src/pc/djui/djui_panel_display.c | 16 ++++++++------ src/pc/pc_main.c | 38 +++++++++++++++++++++++++------- 15 files changed, 73 insertions(+), 19 deletions(-) diff --git a/lang/Czech.ini b/lang/Czech.ini index 04921974d..4142f9468 100644 --- a/lang/Czech.ini +++ b/lang/Czech.ini @@ -142,6 +142,8 @@ INVERT_RIGHT_X = "Inverze pravé páčky osy X" INVERT_RIGHT_Y = "Inverze pravé páčky osy Y" [DISPLAY] +MANUAL = "Manuální" +AUTO = "Auto" DISPLAY = "VIDEO" FULLSCREEN = "Celá obrazovka" FORCE_4BY3 = "Vždy 4:3" diff --git a/lang/Dutch.ini b/lang/Dutch.ini index 25d3c6a0b..151f9b410 100644 --- a/lang/Dutch.ini +++ b/lang/Dutch.ini @@ -142,6 +142,8 @@ INVERT_RIGHT_X = "Rechter joystick X-as omkeren" INVERT_RIGHT_Y = "Rechter joystick Y-as omkeren" [DISPLAY] +MANUAL = "Handmatig" +AUTO = "Auto" DISPLAY = "WEERGAVE" FULLSCREEN = "Volledig scherm" FORCE_4BY3 = "Forceer 4:3" diff --git a/lang/English.ini b/lang/English.ini index cc18a5cbb..36a0d813b 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -147,7 +147,9 @@ FULLSCREEN = "Fullscreen" FORCE_4BY3 = "Force 4:3" PRELOAD_TEXTURES = "Preload Textures" VSYNC = "VSync" -UNCAPPED_FRAMERATE = "Uncapped Framerate" +AUTO = "Auto" +MANUAL = "Manual" +UNCAPPED_FRAMERATE = "Uncapped" FRAME_LIMIT = "Frame Limit" FAST = "Fast" ACCURATE = "Accurate" diff --git a/lang/French.ini b/lang/French.ini index 29b567025..ac1a1687c 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -142,6 +142,8 @@ INVERT_RIGHT_X = "Inverser l'axe X du stick droit" INVERT_RIGHT_Y = "Inverser l'axe Y du stick droit" [DISPLAY] +MANUAL = "Manuel" +AUTO = "Voiture" DISPLAY = "AFFICHAGE" FULLSCREEN = "Plein Écran" FORCE_4BY3 = "Forcer l'affichage 4:3" diff --git a/lang/German.ini b/lang/German.ini index f5aa499fa..c0cf9e834 100644 --- a/lang/German.ini +++ b/lang/German.ini @@ -142,6 +142,8 @@ INVERT_RIGHT_X = "Rechter Stick X-Achse invertieren" INVERT_RIGHT_Y = "Rechter Stick Y-Achse invertieren" [DISPLAY] +MANUAL = "Handbuch" +AUTO = "Auto" DISPLAY = "ANZEIGE" FULLSCREEN = "Vollbildmodus" FORCE_4BY3 = "Erzwinge 4:3" diff --git a/lang/Italian.ini b/lang/Italian.ini index 08084d7e6..d1785b538 100644 --- a/lang/Italian.ini +++ b/lang/Italian.ini @@ -140,6 +140,8 @@ INVERT_RIGHT_X = "Invertire l'asse X dello stick destro" INVERT_RIGHT_Y = "Invertire l'asse Y dello stick destro" [DISPLAY] +MANUAL = "Manuale" +AUTO = "Auto" DISPLAY = "GRAFICA" FULLSCREEN = "Schermo intero" FORCE_4BY3 = "Force 4:3" diff --git a/lang/Japanese.ini b/lang/Japanese.ini index 1d192fded..7e6e751a6 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -143,6 +143,8 @@ INVERT_RIGHT_X = "右スティックX軸の反転" INVERT_RIGHT_Y = "右スティックY軸の反転" [DISPLAY] +MANUAL = "マニュアル" +AUTO = "車" DISPLAY = "DISPLAY" FULLSCREEN = "フルスクリーン" FORCE_4BY3 = "画面比を4:3に強制" diff --git a/lang/Polish.ini b/lang/Polish.ini index be3d99f38..93b7cee5d 100644 --- a/lang/Polish.ini +++ b/lang/Polish.ini @@ -142,6 +142,8 @@ INVERT_RIGHT_X = "Odwrócenie osi X prawego drążka" INVERT_RIGHT_Y = "Odwrócenie osi Y prawego drążka" [DISPLAY] +MANUAL = "Podręcznik" +AUTO = "Samochód" DISPLAY = "WYŚWIETLANIE" FULLSCREEN = "Pełny Ekran" FORCE_4BY3 = "Wymuś proporcję 4:3" diff --git a/lang/Portuguese.ini b/lang/Portuguese.ini index c0f2b1b96..e9129b2c6 100644 --- a/lang/Portuguese.ini +++ b/lang/Portuguese.ini @@ -142,6 +142,8 @@ INVERT_RIGHT_X = "Inverter eixo X do analógico direito" INVERT_RIGHT_Y = "Inverter eixo Y do analógico direito" [DISPLAY] +MANUAL = "Manual" +AUTO = "Automóvel" DISPLAY = "VÍDEO" FULLSCREEN = "Tela cheia" FORCE_4BY3 = "Forçar 4:3" diff --git a/lang/Russian.ini b/lang/Russian.ini index 9b9232980..6d9535c4c 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -141,6 +141,8 @@ INVERT_RIGHT_X = "Инвертировать правый стик оси X" INVERT_RIGHT_Y = "Инвертировать правый стик по оси Y" [DISPLAY] +MANUAL = "Руководство" +AUTO = "Автомобиль" DISPLAY = "DISPLAY" FULLSCREEN = "Полноэкранный режим" FORCE_4BY3 = "Экран 4:3" diff --git a/lang/Spanish.ini b/lang/Spanish.ini index 919a7b087..f66777d1a 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -142,6 +142,8 @@ INVERT_RIGHT_X = "Invertir Stick derecho eje X" INVERT_RIGHT_Y = "Invertir el eje Y del stick derecho" [DISPLAY] +MANUAL = "Manual" +AUTO = "Coche" DISPLAY = "PANTALLA" FULLSCREEN = "Pantalla completa" FORCE_4BY3 = "Forzar 4:3" diff --git a/src/pc/configfile.c b/src/pc/configfile.c index a557f8c57..74fdf878e 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -84,7 +84,7 @@ ConfigStick configStick = { 0 }; // display settings unsigned int configFiltering = 2; // 0 = Nearest, 1 = Bilinear, 2 = Trilinear bool configShowFPS = false; -bool configUncappedFramerate = true; +enum RefreshRateMode configFramerateMode = RRM_AUTO; unsigned int configFrameLimit = 60; unsigned int configInterpolationMode = 1; unsigned int configDrawDistance = 4; @@ -226,7 +226,7 @@ static const struct ConfigOption options[] = { // display settings {.name = "texture_filtering", .type = CONFIG_TYPE_UINT, .uintValue = &configFiltering}, {.name = "show_fps", .type = CONFIG_TYPE_BOOL, .boolValue = &configShowFPS}, - {.name = "uncapped_framerate", .type = CONFIG_TYPE_BOOL, .boolValue = &configUncappedFramerate}, + {.name = "framerate_mode", .type = CONFIG_TYPE_UINT, .uintValue = &configFramerateMode}, {.name = "frame_limit", .type = CONFIG_TYPE_UINT, .uintValue = &configFrameLimit}, {.name = "interpolation_mode", .type = CONFIG_TYPE_UINT, .uintValue = &configInterpolationMode}, {.name = "coop_draw_distance", .type = CONFIG_TYPE_UINT, .uintValue = &configDrawDistance}, @@ -776,6 +776,7 @@ NEXT_OPTION: fs_close(file); + if (configFramerateMode < 0 || configFramerateMode > RRM_MAX) { configFramerateMode = 0; } if (configFrameLimit < 30) { configFrameLimit = 30; } if (configFrameLimit > 3000) { configFrameLimit = 3000; } diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 1614da193..a63d374c8 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -36,6 +36,13 @@ typedef struct { bool invertRightY; } ConfigStick; +enum RefreshRateMode { + RRM_AUTO, + RRM_MANUAL, + RRM_UNLIMITED, + RRM_MAX +}; + extern char configSaveNames[4][MAX_SAVE_NAME_STRING]; // display settings @@ -43,7 +50,7 @@ extern ConfigWindow configWindow; extern ConfigStick configStick; extern unsigned int configFiltering; extern bool configShowFPS; -extern bool configUncappedFramerate; +extern enum RefreshRateMode configFramerateMode; extern unsigned int configFrameLimit; extern unsigned int configInterpolationMode; extern unsigned int configDrawDistance; diff --git a/src/pc/djui/djui_panel_display.c b/src/pc/djui/djui_panel_display.c index 36be26435..d4d9a603f 100644 --- a/src/pc/djui/djui_panel_display.c +++ b/src/pc/djui/djui_panel_display.c @@ -18,9 +18,9 @@ static void djui_panel_display_apply(UNUSED struct DjuiBase* caller) { configWindow.settings_changed = true; } -static void djui_panel_display_uncapped_change(UNUSED struct DjuiBase* caller) { - djui_base_set_enabled(&sFrameLimitInput->base, !configUncappedFramerate); - djui_base_set_enabled(&sInterpolationSelectionBox->base, (configFrameLimit > 30 || (configFrameLimit <= 30 && configUncappedFramerate))); +static void djui_panel_display_framerate_mode_change(UNUSED struct DjuiBase* caller) { + djui_base_set_enabled(&sFrameLimitInput->base, configFramerateMode == RRM_MANUAL); + djui_base_set_enabled(&sInterpolationSelectionBox->base, (configFrameLimit > 30 || configFramerateMode != RRM_MANUAL)); } static void djui_panel_display_frame_limit_text_change(struct DjuiBase* caller) { @@ -32,7 +32,7 @@ static void djui_panel_display_frame_limit_text_change(struct DjuiBase* caller) } else { djui_inputbox_set_text_color(inputbox1, 255, 0, 0, 255); } - djui_base_set_enabled(&sInterpolationSelectionBox->base, (configFrameLimit > 30 || (configFrameLimit <= 30 && configUncappedFramerate))); + djui_base_set_enabled(&sInterpolationSelectionBox->base, (configFrameLimit > 30 || configFramerateMode != RRM_MANUAL)); } static void djui_panel_display_msaa_change(UNUSED struct DjuiBase* caller) { @@ -64,7 +64,9 @@ void djui_panel_display_create(struct DjuiBase* caller) { djui_checkbox_create(body, DLANG(DISPLAY, FORCE_4BY3), &configForce4By3, djui_panel_display_apply); djui_checkbox_create(body, DLANG(DISPLAY, SHOW_FPS), &configShowFPS, NULL); djui_checkbox_create(body, DLANG(DISPLAY, VSYNC), &configWindow.vsync, djui_panel_display_apply); - djui_checkbox_create(body, DLANG(DISPLAY, UNCAPPED_FRAMERATE), &configUncappedFramerate, djui_panel_display_uncapped_change); + + char* framerateModeChoices[3] = { DLANG(DISPLAY, AUTO), DLANG(DISPLAY, MANUAL), DLANG(DISPLAY, UNCAPPED_FRAMERATE) }; + djui_selectionbox_create(body, DLANG(DISPLAY, Framerate Mode), framerateModeChoices, 3, &configFramerateMode, djui_panel_display_framerate_mode_change); struct DjuiRect* rect1 = djui_rect_container_create(body, 32); { @@ -85,13 +87,13 @@ void djui_panel_display_create(struct DjuiBase* caller) { snprintf(frameLimitString, 32, "%d", configFrameLimit); djui_inputbox_set_text(inputbox1, frameLimitString); djui_interactable_hook_value_change(&inputbox1->base, djui_panel_display_frame_limit_text_change); - djui_base_set_enabled(&inputbox1->base, !configUncappedFramerate); + djui_base_set_enabled(&inputbox1->base, configFramerateMode == RRM_MANUAL); sFrameLimitInput = inputbox1; } char* interpChoices[2] = { DLANG(DISPLAY, FAST), DLANG(DISPLAY, ACCURATE) }; struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(body, DLANG(DISPLAY, INTERPOLATION), interpChoices, 2, &configInterpolationMode, NULL); - djui_base_set_enabled(&selectionbox1->base, (configFrameLimit > 30 || (configFrameLimit <= 30 && configUncappedFramerate))); + djui_base_set_enabled(&selectionbox1->base, (configFrameLimit > 30 || configFramerateMode != RRM_MANUAL)); sInterpolationSelectionBox = selectionbox1; char* filterChoices[3] = { DLANG(DISPLAY, NEAREST), DLANG(DISPLAY, LINEAR), DLANG(DISPLAY, TRIPOINT) }; diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 5490dcdac..f527c0cb6 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -71,6 +71,10 @@ #include #endif +#ifdef HAVE_SDL2 +#include +#endif + extern Vp D_8032CF00; OSMesg D_80339BEC; @@ -187,24 +191,42 @@ static void compute_fps(f64 curTime) { sDrawnFrames = 0; } -static s32 get_num_frames_to_draw(f64 t) { - if (configFrameLimit % FRAMERATE == 0) { - return configFrameLimit / FRAMERATE; +static s32 get_num_frames_to_draw(f64 t, u32 frameLimit) { + if (frameLimit % FRAMERATE == 0) { + return frameLimit / FRAMERATE; } - s64 numFramesCurr = (s64) (t * (f64) configFrameLimit); - s64 numFramesNext = (s64) ((t + sFrameTime) * (f64) configFrameLimit); + s64 numFramesCurr = (s64) (t * (f64) frameLimit); + s64 numFramesNext = (s64) ((t + sFrameTime) * (f64) frameLimit); return (s32) MAX(1, numFramesNext - numFramesCurr); } +static u32 get_refresh_rate() { + if (configFramerateMode == RRM_MANUAL) { return configFrameLimit; } + if (configFramerateMode == RRM_UNLIMITED) { return 3000; } // Has no effect +#ifdef HAVE_SDL2 + static u32 refreshRate = 60; + if (!refreshRate) { + SDL_DisplayMode mode; + if (SDL_GetCurrentDisplayMode(0, &mode) == 0) { + refreshRate = (u32) mode.refresh_rate; + } + } + return refreshRate; +#else + return 60; +#endif +} + void produce_interpolation_frames_and_delay(void) { - bool is30Fps = (!configUncappedFramerate && configFrameLimit == FRAMERATE); + u32 refreshRate = get_refresh_rate(); + bool is30Fps = (refreshRate == FRAMERATE); gRenderingInterpolated = true; - f64 curTime = clock_elapsed_f64(); f64 targetTime = sFrameTimeStart + sFrameTime; - s32 numFramesToDraw = get_num_frames_to_draw(sFrameTimeStart); + s32 numFramesToDraw = get_num_frames_to_draw(sFrameTimeStart, refreshRate); + f64 curTime = clock_elapsed_f64(); f64 loopStartTime = curTime; f64 expectedTime = 0;