diff --git a/bin/segment2.c b/bin/segment2.c index 5d5398aa..d7e807fd 100644 --- a/bin/segment2.c +++ b/bin/segment2.c @@ -2107,7 +2107,7 @@ const Gfx dl_hud_img_load_tex_block[] = { gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD), gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 16 * 16 - 1, CALC_DXT(16, G_IM_SIZ_16b_BYTES)), - gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 4, G_TX_NOLOD, G_TX_CLAMP, 4, G_TX_NOLOD), + gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD), gsDPSetTileSize(0, 0, 0, (16 - 1) << G_TEXTURE_IMAGE_FRAC, (16 - 1) << G_TEXTURE_IMAGE_FRAC), gsSPEndDisplayList(), }; @@ -2144,7 +2144,7 @@ const Gfx dl_rgba16_load_tex_block[] = { gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD), gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 16 * 16 - 1, CALC_DXT(16, G_IM_SIZ_16b_BYTES)), - gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, 0, G_TX_RENDERTILE, 0, G_TX_CLAMP, 4, G_TX_NOLOD, G_TX_CLAMP, 4, G_TX_NOLOD), + gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD), gsDPSetTileSize(0, 0, 0, (16 - 1) << G_TEXTURE_IMAGE_FRAC, (16 - 1) << G_TEXTURE_IMAGE_FRAC), gsSPEndDisplayList(), }; 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 58b7d05c..d23223b0 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 01d657c2..cafd272f 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -11,10 +11,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 6ff6906d..e86a100c 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; } @@ -281,6 +264,7 @@ static void gfx_sdl_handle_events(void) { } static bool gfx_sdl_start_frame(void) { + frame_start = SDL_GetTicks(); return true; }