From 0fa331d96101eb95f8b2fb51516724b2f594b4f7 Mon Sep 17 00:00:00 2001
From: Heaven Volkoff <vasconcellos.dev@gmail.com>
Date: Sun, 17 May 2020 16:17:47 -0300
Subject: [PATCH 1/3] Implement save/restore window dimensions/position  - Add
 an entry in options menu to reset window

---
 include/text_strings.h.in |  1 +
 src/game/options_menu.c   |  6 +++
 src/pc/configfile.c       | 13 +++++++
 src/pc/configfile.h       |  6 +++
 src/pc/gfx/gfx_sdl2.c     | 78 +++++++++++++++++++++------------------
 5 files changed, 68 insertions(+), 36 deletions(-)

diff --git a/include/text_strings.h.in b/include/text_strings.h.in
index 6065fb7d..06173692 100644
--- a/include/text_strings.h.in
+++ b/include/text_strings.h.in
@@ -27,6 +27,7 @@
 #define TEXT_OPT_NEAREST   _("Nearest")
 #define TEXT_OPT_LINEAR    _("Linear")
 #define TEXT_OPT_MVOLUME   _("Master Volume")
+#define TEXT_RESET_WINDOW  _("Reset Window")
 
 #define TEXT_OPT_UNBOUND   _("NONE")
 #define TEXT_OPT_PRESSKEY  _("...")
diff --git a/src/game/options_menu.c b/src/game/options_menu.c
index 89e6deb1..61b50b50 100644
--- a/src/game/options_menu.c
+++ b/src/game/options_menu.c
@@ -72,6 +72,7 @@ static const u8 optsVideoStr[][32] = {
     { TEXT_OPT_TEXFILTER },
     { TEXT_OPT_NEAREST },
     { TEXT_OPT_LINEAR },
+    { TEXT_RESET_WINDOW }
 };
 
 static const u8 optsAudioStr[][32] = {
@@ -177,6 +178,10 @@ 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
+}
+
 /* submenu option lists */
 
 #ifdef BETTERCAMERA
@@ -213,6 +218,7 @@ static struct Option optsControls[] = {
 static struct Option optsVideo[] = {
     DEF_OPT_TOGGLE( optsVideoStr[0], &configFullscreen ),
     DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ),
+    DEF_OPT_BUTTON( optsVideoStr[4], optvide_reset_window ),
 };
 
 static struct Option optsAudio[] = {
diff --git a/src/pc/configfile.c b/src/pc/configfile.c
index 3c2735c2..75f792f7 100644
--- a/src/pc/configfile.c
+++ b/src/pc/configfile.c
@@ -5,8 +5,10 @@
 #include <string.h>
 #include <assert.h>
 #include <ctype.h>
+#include <SDL2/SDL.h>
 
 #include "configfile.h"
+#include "gfx/gfx_screen_config.h"
 #include "controller/controller_api.h"
 
 #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
@@ -34,6 +36,13 @@ struct ConfigOption {
 
 // Video/audio stuff
 bool         configFullscreen   = false;
+ConfigWindow configWindow       = {
+    .x = SDL_WINDOWPOS_CENTERED,
+    .y = SDL_WINDOWPOS_CENTERED,
+    .w = DESIRED_SCREEN_WIDTH,
+    .h = DESIRED_SCREEN_HEIGHT,
+    .reset = false
+};
 unsigned int configFiltering    = 1;          // 0=force nearest, 1=linear, (TODO) 2=three-point
 unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME
 
@@ -69,6 +78,10 @@ unsigned int configSkipIntro     = 0;
 
 static const struct ConfigOption options[] = {
     {.name = "fullscreen",           .type = CONFIG_TYPE_BOOL, .boolValue = &configFullscreen},
+    {.name = "window_x",             .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.x},
+    {.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 = "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 49b48b93..d45a60ca 100644
--- a/src/pc/configfile.h
+++ b/src/pc/configfile.h
@@ -7,7 +7,13 @@
 #define MAX_VOLUME   127
 #define VOLUME_SHIFT 7
 
+typedef struct {
+    unsigned int x, y, w, h;
+    bool reset;
+} ConfigWindow;
+
 extern bool         configFullscreen;
+extern ConfigWindow configWindow;
 extern unsigned int configFiltering;
 extern unsigned int configMasterVolume;
 extern unsigned int configKeyA[];
diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c
index b73b6aeb..00529d41 100644
--- a/src/pc/gfx/gfx_sdl2.c
+++ b/src/pc/gfx/gfx_sdl2.c
@@ -40,10 +40,7 @@
 static SDL_Window *wnd;
 static SDL_GLContext ctx = NULL;
 static int inverted_scancode_table[512];
-
-static bool window_fullscreen;
 static bool window_vsync;
-static int window_width, window_height;
 
 const SDL_Scancode windows_scancode_table[] =
 {
@@ -96,22 +93,34 @@ const SDL_Scancode scancode_rmapping_nonextended[][2] = {
     {SDL_SCANCODE_KP_MULTIPLY, SDL_SCANCODE_PRINTSCREEN}
 };
 
-static void gfx_sdl_set_fullscreen(bool fullscreen) {
-    if (fullscreen == window_fullscreen) return;
+#define IS_FULLSCREEN (SDL_GetWindowFlags(wnd) & SDL_WINDOW_FULLSCREEN_DESKTOP)
 
-    if (fullscreen) {
+static void gfx_sdl_set_fullscreen() {
+    if (configFullscreen == IS_FULLSCREEN)
+        return;
+    if (configFullscreen) {
         SDL_SetWindowFullscreen(wnd, SDL_WINDOW_FULLSCREEN_DESKTOP);
         SDL_ShowCursor(SDL_DISABLE);
     } else {
         SDL_SetWindowFullscreen(wnd, 0);
         SDL_ShowCursor(SDL_ENABLE);
-        // reset back to small window just in case
-        window_width = DESIRED_SCREEN_WIDTH;
-        window_height = DESIRED_SCREEN_HEIGHT;
-        SDL_SetWindowSize(wnd, window_width, window_height);
+        SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
+        SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y);
     }
+}
 
-    window_fullscreen = fullscreen;
+static void gfx_sdl_reset_dimension_and_pos() {
+    if (!configWindow.reset) return;
+    configWindow.x = SDL_WINDOWPOS_CENTERED;
+    configWindow.y = SDL_WINDOWPOS_CENTERED;
+    configWindow.w = DESIRED_SCREEN_WIDTH;
+    configWindow.h = DESIRED_SCREEN_HEIGHT;
+    configWindow.reset = false;
+
+    if (!IS_FULLSCREEN) {
+        SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
+        SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y);
+    }
 }
 
 static bool test_vsync(void) {
@@ -157,25 +166,15 @@ static void gfx_sdl_init(void) {
     "Super Mario 64 PC port (OpenGL_ES2)";
     #endif
 
-    Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
-
-    window_fullscreen = configFullscreen;
-
-    if (configFullscreen) {
-        window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
-        SDL_ShowCursor(SDL_DISABLE);
-    } else {
-        SDL_ShowCursor(SDL_ENABLE);
-    }
-
-    wnd = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-            DESIRED_SCREEN_WIDTH, DESIRED_SCREEN_HEIGHT, window_flags);
-
+    wnd = SDL_CreateWindow(
+        window_title,
+        configWindow.x, configWindow.y, configWindow.w, configWindow.h,
+        SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
+    );
     ctx = SDL_GL_CreateContext(wnd);
     SDL_GL_SetSwapInterval(2);
 
-    // in case FULLSCREEN_DESKTOP set our size to god knows what
-    SDL_GetWindowSize(wnd, &window_width, &window_height);
+    gfx_sdl_set_fullscreen();
 
     window_vsync = test_vsync();
     if (!window_vsync)
@@ -201,8 +200,7 @@ static void gfx_sdl_main_loop(void (*run_one_game_iter)(void)) {
 }
 
 static void gfx_sdl_get_dimensions(uint32_t *width, uint32_t *height) {
-    *width = window_width;
-    *height = window_height;
+    SDL_GetWindowSize(wnd, width, height);
 }
 
 static int translate_scancode(int scancode) {
@@ -241,10 +239,18 @@ static void gfx_sdl_handle_events(void) {
                 gfx_sdl_onkeyup(event.key.keysym.scancode);
                 break;
 #endif
-            case SDL_WINDOWEVENT:
-                if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
-                    window_width = event.window.data1;
-                    window_height = event.window.data2;
+            case SDL_WINDOWEVENT: // FIX-ME: Check if this makes sense to be include in Web build
+                if (!IS_FULLSCREEN) {
+                    switch (event.window.event) {
+                        case SDL_WINDOWEVENT_MOVED:
+                            configWindow.x = event.window.data1;
+                            configWindow.y = event.window.data2;
+                            break;
+                        case SDL_WINDOWEVENT_SIZE_CHANGED:
+                            configWindow.w = event.window.data1;
+                            configWindow.h = event.window.data2;
+                            break;
+                    }
                 }
                 break;
             case SDL_QUIT:
@@ -252,9 +258,9 @@ static void gfx_sdl_handle_events(void) {
                 break;
         }
     }
-    // just check if the fullscreen value has changed and toggle fullscreen if it has
-    if (configFullscreen != window_fullscreen)
-        gfx_sdl_set_fullscreen(configFullscreen);
+
+    gfx_sdl_reset_dimension_and_pos();
+    gfx_sdl_set_fullscreen();
 }
 
 static bool gfx_sdl_start_frame(void) {

From 9927b3555dd481a0eea579272a9dc3dc0b052b09 Mon Sep 17 00:00:00 2001
From: Heaven Volkoff <vasconcellos.dev@gmail.com>
Date: Sun, 17 May 2020 23:08:12 -0300
Subject: [PATCH 2/3] Fix fullscreen exit resulting in a slightly lower Y
 position

---
 src/pc/configfile.c   |  4 +++-
 src/pc/configfile.h   |  2 ++
 src/pc/gfx/gfx_sdl2.c | 40 ++++++++++++++++++++++------------------
 3 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/src/pc/configfile.c b/src/pc/configfile.c
index 75f792f7..2b97c5f1 100644
--- a/src/pc/configfile.c
+++ b/src/pc/configfile.c
@@ -41,7 +41,9 @@ ConfigWindow configWindow       = {
     .y = SDL_WINDOWPOS_CENTERED,
     .w = DESIRED_SCREEN_WIDTH,
     .h = DESIRED_SCREEN_HEIGHT,
-    .reset = false
+    .reset = false,
+    .vsync = false,
+    .exiting_fullscreen = false,
 };
 unsigned int configFiltering    = 1;          // 0=force nearest, 1=linear, (TODO) 2=three-point
 unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME
diff --git a/src/pc/configfile.h b/src/pc/configfile.h
index d45a60ca..b2368c89 100644
--- a/src/pc/configfile.h
+++ b/src/pc/configfile.h
@@ -10,6 +10,8 @@
 typedef struct {
     unsigned int x, y, w, h;
     bool reset;
+    bool vsync;
+    bool exiting_fullscreen;
 } ConfigWindow;
 
 extern bool         configFullscreen;
diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c
index 00529d41..3c534d00 100644
--- a/src/pc/gfx/gfx_sdl2.c
+++ b/src/pc/gfx/gfx_sdl2.c
@@ -22,6 +22,8 @@
 
 #endif // End of OS-Specific GL defines
 
+#include <stdio.h>
+
 #include "gfx_window_manager_api.h"
 #include "gfx_screen_config.h"
 #include "../pc_main.h"
@@ -40,7 +42,6 @@
 static SDL_Window *wnd;
 static SDL_GLContext ctx = NULL;
 static int inverted_scancode_table[512];
-static bool window_vsync;
 
 const SDL_Scancode windows_scancode_table[] =
 {
@@ -104,23 +105,26 @@ static void gfx_sdl_set_fullscreen() {
     } else {
         SDL_SetWindowFullscreen(wnd, 0);
         SDL_ShowCursor(SDL_ENABLE);
-        SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
-        SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y);
+        configWindow.exiting_fullscreen = true;
     }
 }
 
 static void gfx_sdl_reset_dimension_and_pos() {
-    if (!configWindow.reset) return;
-    configWindow.x = SDL_WINDOWPOS_CENTERED;
-    configWindow.y = SDL_WINDOWPOS_CENTERED;
-    configWindow.w = DESIRED_SCREEN_WIDTH;
-    configWindow.h = DESIRED_SCREEN_HEIGHT;
-    configWindow.reset = false;
+    if (configWindow.exiting_fullscreen)
+        configWindow.exiting_fullscreen = false;
+    else if (configWindow.reset) {
+        configWindow.x = SDL_WINDOWPOS_CENTERED;
+        configWindow.y = SDL_WINDOWPOS_CENTERED;
+        configWindow.w = DESIRED_SCREEN_WIDTH;
+        configWindow.h = DESIRED_SCREEN_HEIGHT;
+        configWindow.reset = false;
 
-    if (!IS_FULLSCREEN) {
-        SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
-        SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y);
-    }
+        if (IS_FULLSCREEN) return;
+    } else
+        return;
+
+    SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
+    SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y);
 }
 
 static bool test_vsync(void) {
@@ -176,8 +180,8 @@ static void gfx_sdl_init(void) {
 
     gfx_sdl_set_fullscreen();
 
-    window_vsync = test_vsync();
-    if (!window_vsync)
+    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++) {
@@ -239,8 +243,8 @@ static void gfx_sdl_handle_events(void) {
                 gfx_sdl_onkeyup(event.key.keysym.scancode);
                 break;
 #endif
-            case SDL_WINDOWEVENT: // FIX-ME: Check if this makes sense to be include in Web build
-                if (!IS_FULLSCREEN) {
+            case SDL_WINDOWEVENT: // TODO: Check if this makes sense to be included in the Web build
+                if (!(IS_FULLSCREEN || configWindow.exiting_fullscreen)) {
                     switch (event.window.event) {
                         case SDL_WINDOWEVENT_MOVED:
                             configWindow.x = event.window.data1;
@@ -280,7 +284,7 @@ static void sync_framerate_with_timer(void) {
 }
 
 static void gfx_sdl_swap_buffers_begin(void) {
-    if (!window_vsync)
+    if (!configWindow.vsync)
         sync_framerate_with_timer();
     SDL_GL_SwapWindow(wnd);
 }

From 98efed7c51cca39758f8a5b7326c69206b4ab881 Mon Sep 17 00:00:00 2001
From: Heaven Volkoff <vasconcellos.dev@gmail.com>
Date: Sun, 17 May 2020 23:29:41 -0300
Subject: [PATCH 3/3] Reset Window now exit fullscreen Change configFullscreen
 to configWindow.fullscreen

---
 src/game/options_menu.c |  2 +-
 src/pc/configfile.c     |  4 ++--
 src/pc/configfile.h     |  2 +-
 src/pc/gfx/gfx_sdl2.c   | 17 ++++++++++-------
 4 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/src/game/options_menu.c b/src/game/options_menu.c
index 61b50b50..b9033bee 100644
--- a/src/game/options_menu.c
+++ b/src/game/options_menu.c
@@ -216,7 +216,7 @@ static struct Option optsControls[] = {
 };
 
 static struct Option optsVideo[] = {
-    DEF_OPT_TOGGLE( optsVideoStr[0], &configFullscreen ),
+    DEF_OPT_TOGGLE( optsVideoStr[0], &configWindow.fullscreen ),
     DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ),
     DEF_OPT_BUTTON( optsVideoStr[4], optvide_reset_window ),
 };
diff --git a/src/pc/configfile.c b/src/pc/configfile.c
index 2b97c5f1..0b6fe370 100644
--- a/src/pc/configfile.c
+++ b/src/pc/configfile.c
@@ -35,7 +35,6 @@ struct ConfigOption {
  */
 
 // Video/audio stuff
-bool         configFullscreen   = false;
 ConfigWindow configWindow       = {
     .x = SDL_WINDOWPOS_CENTERED,
     .y = SDL_WINDOWPOS_CENTERED,
@@ -43,6 +42,7 @@ ConfigWindow configWindow       = {
     .h = DESIRED_SCREEN_HEIGHT,
     .reset = false,
     .vsync = false,
+    .fullscreen = false,
     .exiting_fullscreen = false,
 };
 unsigned int configFiltering    = 1;          // 0=force nearest, 1=linear, (TODO) 2=three-point
@@ -79,7 +79,7 @@ bool         configCameraMouse   = false;
 unsigned int configSkipIntro     = 0;
 
 static const struct ConfigOption options[] = {
-    {.name = "fullscreen",           .type = CONFIG_TYPE_BOOL, .boolValue = &configFullscreen},
+    {.name = "fullscreen",           .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen},
     {.name = "window_x",             .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.x},
     {.name = "window_y",             .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.y},
     {.name = "window_w",             .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.w},
diff --git a/src/pc/configfile.h b/src/pc/configfile.h
index b2368c89..4343ebdc 100644
--- a/src/pc/configfile.h
+++ b/src/pc/configfile.h
@@ -11,10 +11,10 @@ typedef struct {
     unsigned int x, y, w, h;
     bool reset;
     bool vsync;
+    bool fullscreen;
     bool exiting_fullscreen;
 } ConfigWindow;
 
-extern bool         configFullscreen;
 extern ConfigWindow configWindow;
 extern unsigned int configFiltering;
 extern unsigned int configMasterVolume;
diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c
index 3c534d00..e34086bf 100644
--- a/src/pc/gfx/gfx_sdl2.c
+++ b/src/pc/gfx/gfx_sdl2.c
@@ -97,9 +97,9 @@ const SDL_Scancode scancode_rmapping_nonextended[][2] = {
 #define IS_FULLSCREEN (SDL_GetWindowFlags(wnd) & SDL_WINDOW_FULLSCREEN_DESKTOP)
 
 static void gfx_sdl_set_fullscreen() {
-    if (configFullscreen == IS_FULLSCREEN)
+    if (configWindow.fullscreen == IS_FULLSCREEN)
         return;
-    if (configFullscreen) {
+    if (configWindow.fullscreen) {
         SDL_SetWindowFullscreen(wnd, SDL_WINDOW_FULLSCREEN_DESKTOP);
         SDL_ShowCursor(SDL_DISABLE);
     } else {
@@ -119,7 +119,10 @@ static void gfx_sdl_reset_dimension_and_pos() {
         configWindow.h = DESIRED_SCREEN_HEIGHT;
         configWindow.reset = false;
 
-        if (IS_FULLSCREEN) return;
+        if (IS_FULLSCREEN) {
+            configWindow.fullscreen = false;
+            return;
+        }
     } else
         return;
 
@@ -161,7 +164,7 @@ static void gfx_sdl_init(void) {
     //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
 
     if (gCLIOpts.FullScreen)
-        configFullscreen = true;
+        configWindow.fullscreen = true;
 
     const char* window_title = 
     #ifndef USE_GLES
@@ -221,9 +224,9 @@ static void gfx_sdl_onkeydown(int scancode) {
     const Uint8 *state = SDL_GetKeyboardState(NULL);
 
     if (state[SDL_SCANCODE_LALT] && state[SDL_SCANCODE_RETURN])
-        configFullscreen = !configFullscreen;
-    else if (state[SDL_SCANCODE_ESCAPE] && configFullscreen)
-        configFullscreen = false;
+        configWindow.fullscreen = !configWindow.fullscreen;
+    else if (state[SDL_SCANCODE_ESCAPE] && configWindow.fullscreen)
+        configWindow.fullscreen = false;
 }
 
 static void gfx_sdl_onkeyup(int scancode) {