From 2bd840a299ec0298e8eef57c0485eaaca57233ad Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 18 May 2020 23:03:04 +0300 Subject: [PATCH 1/5] (hopefully) fix the timing crap; add vsync option --- include/text_strings.h.in | 2 ++ src/game/options_menu.c | 27 ++++++++++++++------ src/pc/configfile.c | 4 ++- src/pc/configfile.h | 3 ++- src/pc/gfx/gfx_sdl2.c | 53 ++++++++++++--------------------------- 5 files changed, 43 insertions(+), 46 deletions(-) diff --git a/include/text_strings.h.in b/include/text_strings.h.in index 06173692..b77a51ca 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -27,6 +27,8 @@ #define TEXT_OPT_NEAREST _("Nearest") #define TEXT_OPT_LINEAR _("Linear") #define TEXT_OPT_MVOLUME _("Master Volume") +#define TEXT_OPT_VSYNC _("Vertical Sync") +#define TEXT_OPT_DOUBLE _("Double") #define TEXT_RESET_WINDOW _("Reset Window") #define TEXT_OPT_UNBOUND _("NONE") diff --git a/src/game/options_menu.c b/src/game/options_menu.c index b9033bee..7b8d9f74 100644 --- a/src/game/options_menu.c +++ b/src/game/options_menu.c @@ -72,7 +72,9 @@ static const u8 optsVideoStr[][32] = { { TEXT_OPT_TEXFILTER }, { TEXT_OPT_NEAREST }, { TEXT_OPT_LINEAR }, - { TEXT_RESET_WINDOW } + { TEXT_RESET_WINDOW }, + { TEXT_OPT_VSYNC }, + { TEXT_OPT_DOUBLE }, }; static const u8 optsAudioStr[][32] = { @@ -112,6 +114,12 @@ static const u8 *filterChoices[] = { optsVideoStr[3], }; +static const u8 *vsyncChoices[] = { + toggleStr[0], + toggleStr[1], + optsVideoStr[6], +}; + enum OptType { OPT_INVALID = 0, OPT_TOGGLE, @@ -178,8 +186,12 @@ static void optmenu_act_exit(UNUSED struct Option *self, s32 arg) { if (!arg) game_exit(); // only exit on A press and not directions } -static void optvide_reset_window(UNUSED struct Option *self, s32 arg) { - if (!arg) configWindow.reset = true;; // Restrict reset to A press and not directions +static void optvideo_reset_window(UNUSED struct Option *self, s32 arg) { + if (!arg) { + // Restrict reset to A press and not directions + configWindow.reset = true; + configWindow.settings_changed = true; + } } /* submenu option lists */ @@ -217,8 +229,9 @@ static struct Option optsControls[] = { static struct Option optsVideo[] = { DEF_OPT_TOGGLE( optsVideoStr[0], &configWindow.fullscreen ), + DEF_OPT_CHOICE( optsVideoStr[5], &configWindow.vsync, vsyncChoices ), DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ), - DEF_OPT_BUTTON( optsVideoStr[4], optvide_reset_window ), + DEF_OPT_BUTTON( optsVideoStr[4], optvideo_reset_window ), }; static struct Option optsAudio[] = { @@ -230,8 +243,8 @@ static struct Option optsCheats[] = { DEF_OPT_TOGGLE( optsCheatsStr[1], &Cheats.MoonJump ), DEF_OPT_TOGGLE( optsCheatsStr[2], &Cheats.GodMode ), DEF_OPT_TOGGLE( optsCheatsStr[3], &Cheats.InfiniteLives ), - DEF_OPT_TOGGLE( optsCheatsStr[4], &Cheats.SuperSpeed), - DEF_OPT_TOGGLE( optsCheatsStr[5], &Cheats.Responsive), + DEF_OPT_TOGGLE( optsCheatsStr[4], &Cheats.SuperSpeed ), + DEF_OPT_TOGGLE( optsCheatsStr[5], &Cheats.Responsive ), }; @@ -243,7 +256,7 @@ static struct SubMenu menuCamera = DEF_SUBMENU( menuStr[4], optsCamera ); static struct SubMenu menuControls = DEF_SUBMENU( menuStr[5], optsControls ); static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[6], optsVideo ); static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[7], optsAudio ); -static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[9], optsCheats ); +static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[9], optsCheats ); /* main options menu definition */ diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 0b6fe370..ce9a08ad 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -40,10 +40,11 @@ ConfigWindow configWindow = { .y = SDL_WINDOWPOS_CENTERED, .w = DESIRED_SCREEN_WIDTH, .h = DESIRED_SCREEN_HEIGHT, + .vsync = 1, .reset = false, - .vsync = false, .fullscreen = false, .exiting_fullscreen = false, + .settings_changed = false, }; unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME @@ -84,6 +85,7 @@ static const struct ConfigOption options[] = { {.name = "window_y", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.y}, {.name = "window_w", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.w}, {.name = "window_h", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.h}, + {.name = "vsync", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.vsync}, {.name = "texture_filtering", .type = CONFIG_TYPE_UINT, .uintValue = &configFiltering}, {.name = "master_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configMasterVolume}, {.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA}, diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 4343ebdc..5238b17c 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -9,10 +9,11 @@ typedef struct { unsigned int x, y, w, h; + unsigned int vsync; bool reset; - bool vsync; bool fullscreen; bool exiting_fullscreen; + bool settings_changed; } ConfigWindow; extern ConfigWindow configWindow; diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index 363d9209..cc660d79 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -39,9 +39,12 @@ # define FRAMERATE 30 #endif +static const Uint32 FRAME_TIME = 1000 / FRAMERATE; + static SDL_Window *wnd; static SDL_GLContext ctx = NULL; static int inverted_scancode_table[512]; +static Uint32 frame_start = 0; const SDL_Scancode windows_scancode_table[] = { @@ -110,9 +113,9 @@ static void gfx_sdl_set_fullscreen() { } static void gfx_sdl_reset_dimension_and_pos() { - if (configWindow.exiting_fullscreen) + if (configWindow.exiting_fullscreen) { configWindow.exiting_fullscreen = false; - else if (configWindow.reset) { + } else if (configWindow.reset) { configWindow.x = SDL_WINDOWPOS_CENTERED; configWindow.y = SDL_WINDOWPOS_CENTERED; configWindow.w = DESIRED_SCREEN_WIDTH; @@ -123,29 +126,14 @@ static void gfx_sdl_reset_dimension_and_pos() { configWindow.fullscreen = false; return; } - } else + } else if (!configWindow.settings_changed) { return; + } + configWindow.settings_changed = false; SDL_SetWindowSize(wnd, configWindow.w, configWindow.h); SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y); -} - -static bool test_vsync(void) { - // Even if SDL_GL_SetSwapInterval succeeds, it doesn't mean that VSync actually works. - // A 60 Hz monitor should have a swap interval of 16.67 milliseconds. - // If it takes less than 12 milliseconds, assume that VSync is not working. - // SDL_GetTicks() probably does not offer enough precision for this kind of shit. - Uint32 start, end; - - // do an extra swap, sometimes the first one takes longer (maybe creates buffers?) - SDL_GL_SwapWindow(wnd); - - SDL_GL_SwapWindow(wnd); - start = SDL_GetTicks(); - SDL_GL_SwapWindow(wnd); - end = SDL_GetTicks(); - - return (end - start >= 12); + SDL_GL_SetSwapInterval(configWindow.vsync); // in case vsync changed } static void gfx_sdl_init(void) { @@ -165,11 +153,9 @@ static void gfx_sdl_init(void) { if (gCLIOpts.FullScreen == 1) configWindow.fullscreen = true; - - if (gCLIOpts.FullScreen == 2) + else if (gCLIOpts.FullScreen == 2) configWindow.fullscreen = false; - const char* window_title = #ifndef USE_GLES "Super Mario 64 PC port (OpenGL)"; @@ -183,14 +169,11 @@ static void gfx_sdl_init(void) { SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE ); ctx = SDL_GL_CreateContext(wnd); - SDL_GL_SetSwapInterval(2); + + SDL_GL_SetSwapInterval(configWindow.vsync); gfx_sdl_set_fullscreen(); - configWindow.vsync = test_vsync(); - if (!configWindow.vsync) - printf("Warning: VSync is not enabled or not working. Falling back to timer for synchronization\n"); - for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) { inverted_scancode_table[windows_scancode_table[i]] = i; } @@ -275,23 +258,19 @@ static void gfx_sdl_handle_events(void) { } static bool gfx_sdl_start_frame(void) { + frame_start = SDL_GetTicks(); return true; } static void sync_framerate_with_timer(void) { - // Number of milliseconds a frame should take (30 fps) - const Uint32 FRAME_TIME = 1000 / FRAMERATE; - static Uint32 last_time; - - Uint32 elapsed = SDL_GetTicks() - last_time; + Uint32 elapsed = SDL_GetTicks() - frame_start; if (elapsed < FRAME_TIME) SDL_Delay(FRAME_TIME - elapsed); - - last_time = SDL_GetTicks(); } static void gfx_sdl_swap_buffers_begin(void) { - if (!configWindow.vsync) + // if vsync is set to 2, depend only on SwapInterval to sync + if (configWindow.vsync <= 1) sync_framerate_with_timer(); SDL_GL_SwapWindow(wnd); } From 952495ae085d900213f3f88d4bf7209733d06ab5 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Mon, 18 May 2020 23:31:19 +0300 Subject: [PATCH 2/5] clean up cliopts --- src/pc/cliopts.c | 93 +++++++++++++++++++++------------------------ src/pc/cliopts.h | 14 ++++--- src/pc/configfile.h | 2 + 3 files changed, 54 insertions(+), 55 deletions(-) diff --git a/src/pc/cliopts.c b/src/pc/cliopts.c index ee9bc13e..234660b2 100644 --- a/src/pc/cliopts.c +++ b/src/pc/cliopts.c @@ -1,4 +1,7 @@ #include "cliopts.h" +#include "configfile.h" +#include "pc_main.h" + #include #include #include @@ -6,53 +9,45 @@ struct PCCLIOptions gCLIOpts; -void parse_cli_opts(int argc, char* argv[]) -{ - // Initialize options with false values. - gCLIOpts.SkipIntro = 0; - gCLIOpts.FullScreen = 0; - gCLIOpts.ConfigFile = malloc(31); - strncpy(gCLIOpts.ConfigFile, "sm64config.txt", strlen("sm64config.txt")); - gCLIOpts.ConfigFile[strlen("sm64config.txt")] = '\0'; - - // Scan arguments for options - if (argc > 1) - { - int i; - for (i = 1; i < argc; i++) - { - if (strcmp(argv[i], "--skip-intro") == 0) // Skip Peach Intro - gCLIOpts.SkipIntro = 1; - - if (strcmp(argv[i], "--fullscreen") == 0) // Open game in fullscreen - gCLIOpts.FullScreen = 1; - - if (strcmp(argv[i], "--windowed") == 0) // Open game in windowed mode - gCLIOpts.FullScreen = 2; - - if (strcmp(argv[i], "--help") == 0) // Print help - { - printf("Super Mario 64 PC Port\n"); - printf("%-20s\tSkips the Peach and Castle intro when starting a new game.\n", "--skip-intro"); - printf("%-20s\tStarts the game in full screen mode.\n", "--fullscreen"); - printf("%-20s\tStarts the game in windowed mode.\n", "--windowed"); - printf("%-20s\tSaves the configuration file as CONFIGNAME.\n", "--configfile CONFIGNAME"); - exit(0); - } - - if (strncmp(argv[i], "--configfile", strlen("--configfile")) == 0) - { - if (i+1 < argc) - { - if (strlen(argv[i]) > 30) { - fprintf(stderr, "Configuration file supplied has a name too long.\n"); - } else { - memset(gCLIOpts.ConfigFile, 0, 30); - strncpy(gCLIOpts.ConfigFile, argv[i+1], strlen(argv[i+1])); - gCLIOpts.ConfigFile[strlen(argv[i+1])] = '\0'; - } - } - } - } - } +static void print_help(void) { + printf("Super Mario 64 PC Port\n"); + printf("%-20s\tSkips the Peach and Castle intro when starting a new game.\n", "--skip-intro"); + printf("%-20s\tStarts the game in full screen mode.\n", "--fullscreen"); + printf("%-20s\tStarts the game in windowed mode.\n", "--windowed"); + printf("%-20s\tSaves the configuration file as CONFIGNAME.\n", "--configfile CONFIGNAME"); +} + +void parse_cli_opts(int argc, char* argv[]) { + // Initialize options with false values. + memset(&gCLIOpts, 0, sizeof(gCLIOpts)); + strncpy(gCLIOpts.ConfigFile, CONFIGFILE_DEFAULT, sizeof(gCLIOpts.ConfigFile)); + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--skip-intro") == 0) // Skip Peach Intro + gCLIOpts.SkipIntro = 1; + + else if (strcmp(argv[i], "--fullscreen") == 0) // Open game in fullscreen + gCLIOpts.FullScreen = 1; + + else if (strcmp(argv[i], "--windowed") == 0) // Open game in windowed mode + gCLIOpts.FullScreen = 2; + + // Print help + else if (strcmp(argv[i], "--help") == 0) { + print_help(); + game_exit(); + } + + else if (strcmp(argv[i], "--configfile") == 0) { + if (i+1 < argc) { + const unsigned int arglen = strlen(argv[i+1]); + if (arglen >= sizeof(gCLIOpts.ConfigFile)) { + fprintf(stderr, "Configuration file supplied has a name too long.\n"); + } else { + strncpy(gCLIOpts.ConfigFile, argv[i+1], arglen); + gCLIOpts.ConfigFile[arglen] = '\0'; + } + } + } + } } diff --git a/src/pc/cliopts.h b/src/pc/cliopts.h index 1844c44c..d20dcb4f 100644 --- a/src/pc/cliopts.h +++ b/src/pc/cliopts.h @@ -1,12 +1,14 @@ -#include "sm64.h" +#ifndef _CLIOPTS_H +#define _CLIOPTS_H -struct PCCLIOptions -{ - u8 SkipIntro; - u8 FullScreen; - char * ConfigFile; +struct PCCLIOptions { + unsigned int SkipIntro; + unsigned int FullScreen; + char ConfigFile[1024]; }; extern struct PCCLIOptions gCLIOpts; void parse_cli_opts(int argc, char* argv[]); + +#endif // _CLIOPTS_H diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 5238b17c..cafd272f 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -3,6 +3,8 @@ #include +#define CONFIGFILE_DEFAULT "sm64config.txt" + #define MAX_BINDS 3 #define MAX_VOLUME 127 #define VOLUME_SHIFT 7 From 36cef2ef5d26b4738d9607cfff1c71ecf19ac565 Mon Sep 17 00:00:00 2001 From: Leon422 Date: Mon, 18 May 2020 22:10:37 +0100 Subject: [PATCH 3/5] Added the cheats menu to the list of features --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1ba69773..dadc0b7e 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm * An option to disable drawing distances. (Activate with `make NODRAWINGDISTANCE=1`.) * In-game control binding, currently available on the `testing` branch. * Skip introductory Peach & Lakitu cutscenes with the `--skip-intro` CLI option + * Cheats menu, accessible from the "Options" menu. Please note that if a cheat asks you to press "L" it's referring to the N64 button. Check your bindings and make sure you have the "L" button mapped to a button in your controller. ## Building For building instructions, please refer to the [wiki](https://github.com/sm64pc/sm64pc/wiki). From 7ad1b1f12bd7bbb914385c9accb703fce8452962 Mon Sep 17 00:00:00 2001 From: Leon422 Date: Mon, 18 May 2020 22:13:00 +0100 Subject: [PATCH 4/5] *commits in Spanish* --- README_es_ES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README_es_ES.md b/README_es_ES.md index 7426486c..02ac0b47 100644 --- a/README_es_ES.md +++ b/README_es_ES.md @@ -13,6 +13,7 @@ Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para borr * Opción para desactivar el límite de distancia de renderizado. (Se activa con `make NODRAWINGDISTANCE=1`.) * Configurar los controles desde el juego, actualmente solo en la rama `testing`. * Posibilidad de saltarte la intro con la opción de línea de comandos `--skip-intro`, actualmente solo en las ramas `testing` y `skip-intro`. + * Menú de trucos, al cual se accede a través del menú "Options". Ten en cuenta que si un cheat te pide pulsar el botón "L", se refiere al botón de N64, el cual tendrá que estar asignado a un botón de tu mando. Ve a los ajustes de control y asegúrate de que tienes "L" mapeado a un botón de tu mando. ## Compilar en Windows **No intentes compilar ejecutables para Windows bajo Linux usando `WINDOWS_BUILD=1`. No va a funcionar. Sigue la guía.** From 1d9398abb399c46814d7873a9df03a17ff6c7d4d Mon Sep 17 00:00:00 2001 From: Leon422 Date: Mon, 18 May 2020 22:15:06 +0100 Subject: [PATCH 5/5] *commits in Spanish again* Added the cheats menu to the feature list, and updated the feature list in general to match the English version. --- README_es_ES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README_es_ES.md b/README_es_ES.md index 02ac0b47..fa7ba3ca 100644 --- a/README_es_ES.md +++ b/README_es_ES.md @@ -11,8 +11,8 @@ Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para borr * Soporte nativo para mandos XInput. En Linux, se ha confirmado que el DualShock 4 funciona sin más. * Cámara analógica y cámara controlada con el ratón. (Se activa con `make BETTERCAMERA=1`.) * Opción para desactivar el límite de distancia de renderizado. (Se activa con `make NODRAWINGDISTANCE=1`.) - * Configurar los controles desde el juego, actualmente solo en la rama `testing`. - * Posibilidad de saltarte la intro con la opción de línea de comandos `--skip-intro`, actualmente solo en las ramas `testing` y `skip-intro`. + * Configurar los controles desde el juego. + * Posibilidad de saltarte la intro con la opción de línea de comandos `--skip-intro` * Menú de trucos, al cual se accede a través del menú "Options". Ten en cuenta que si un cheat te pide pulsar el botón "L", se refiere al botón de N64, el cual tendrá que estar asignado a un botón de tu mando. Ve a los ajustes de control y asegúrate de que tienes "L" mapeado a un botón de tu mando. ## Compilar en Windows