From dec7da2110eaee4afc351a76f9521541bb8977b0 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Sun, 21 Aug 2022 18:13:27 -0400 Subject: [PATCH] game: windowed mode related fixes (#1778) * game: restore windowed mode settings properly * game: use the game version for saving settings/saves * game: prevent windowed mode from being auto-centered on initial init * game: save and restore window coordinates * lint: formatting --- common/util/FileUtil.cpp | 14 +++++----- common/util/FileUtil.h | 5 ++-- game/graphics/display.cpp | 41 ++++++++++++++++++++++++++++++ game/graphics/display.h | 15 ++++++++--- game/graphics/gfx.h | 2 +- game/graphics/pipelines/opengl.cpp | 23 ++++++++++++----- game/graphics/pipelines/opengl.h | 5 ++-- game/kernel/common/kmemcard.cpp | 21 ++++++++------- game/kernel/jak1/kmachine.cpp | 3 +-- game/kernel/jak2/kmachine.cpp | 3 +-- goal_src/jak1/pc/pckernel.gc | 17 ++++++++----- 11 files changed, 107 insertions(+), 42 deletions(-) diff --git a/common/util/FileUtil.cpp b/common/util/FileUtil.cpp index ffc8412baa..0234383710 100644 --- a/common/util/FileUtil.cpp +++ b/common/util/FileUtil.cpp @@ -33,8 +33,8 @@ #include #include #endif +#include "common/log/log.h" #include "common/util/Assert.h" -#include namespace file_util { fs::path get_user_home_dir() { @@ -66,14 +66,14 @@ fs::path get_user_config_dir() { return config_base_path / "OpenGOAL"; } -fs::path get_user_settings_dir() { - // TODO - jak2 - return get_user_config_dir() / "jak1" / "settings"; +fs::path get_user_settings_dir(GameVersion game_version) { + auto game_version_name = game_version_names[game_version]; + return get_user_config_dir() / game_version_name / "settings"; } -fs::path get_user_memcard_dir() { - // TODO - jak2 - return get_user_config_dir() / "jak1" / "saves"; +fs::path get_user_memcard_dir(GameVersion game_version) { + auto game_version_name = game_version_names[game_version]; + return get_user_config_dir() / game_version_name / "saves"; } struct { diff --git a/common/util/FileUtil.h b/common/util/FileUtil.h index a830b4c185..99c7fa6e23 100644 --- a/common/util/FileUtil.h +++ b/common/util/FileUtil.h @@ -22,14 +22,15 @@ #include #include "common/common_types.h" +#include "common/versions.h" namespace fs = ghc::filesystem; namespace file_util { fs::path get_user_home_dir(); fs::path get_user_config_dir(); -fs::path get_user_settings_dir(); -fs::path get_user_memcard_dir(); +fs::path get_user_settings_dir(GameVersion game_version); +fs::path get_user_memcard_dir(GameVersion game_version); fs::path get_jak_project_dir(); bool create_dir_if_needed(const fs::path& path); diff --git a/game/graphics/display.cpp b/game/graphics/display.cpp index 5e75124175..652f2e4a62 100644 --- a/game/graphics/display.cpp +++ b/game/graphics/display.cpp @@ -5,9 +5,17 @@ #include "display.h" +#include + #include "gfx.h" #include "common/log/log.h" +#include "common/util/FileUtil.h" +#include "common/util/json_util.h" + +#include "game/runtime.h" + +#include "third-party/json.hpp" /* ******************************** @@ -61,6 +69,35 @@ int GfxDisplay::height() { return h; } +void GfxDisplay::save_display_settings() { + nlohmann::json json; + json["window_xpos"] = m_last_windowed_xpos; + json["window_ypos"] = m_last_windowed_ypos; + std::string file_path = + (file_util::get_user_settings_dir(g_game_version) / "display-settings.json").string(); + file_util::write_text_file(file_path, json.dump(2)); +} + +void GfxDisplay::restore_display_settings() { + try { + std::string file_path = + (file_util::get_user_settings_dir(g_game_version) / "display-settings.json").string(); + if (!file_util::file_exists(file_path)) { + return; + } + auto raw = file_util::read_text_file(file_path); + auto json = parse_commented_json(raw, "display-settings.json"); + if (json.contains("window_xpos")) { + m_last_windowed_xpos = json.at("window_xpos").get(); + } + if (json.contains("window_ypos")) { + m_last_windowed_ypos = json.at("window_ypos").get(); + } + } catch (std::exception& e) { + // do nothing + } +} + /* ******************************** * DISPLAY @@ -93,6 +130,8 @@ int InitMainDisplay(int width, return 1; } set_main_display(display); + // Restore window settings + display->restore_display_settings(); return 0; } @@ -108,6 +147,8 @@ void KillDisplay(std::shared_ptr display) { } if (GetMainDisplay() == display) { + // Save the main display's position to a file so it can be restored upon re-opening + display->save_display_settings(); // killing the main display, kill all children displays too! while (g_displays.size() > 1) { KillDisplay(g_displays.at(1)); diff --git a/game/graphics/display.h b/game/graphics/display.h index 91e9833e22..aca9a4821b 100644 --- a/game/graphics/display.h +++ b/game/graphics/display.h @@ -28,12 +28,13 @@ class GfxDisplay { // next mode GfxDisplayMode m_fullscreen_target_mode = GfxDisplayMode::Windowed; // current mode (start as -1 to force an initial fullscreen update) - GfxDisplayMode m_fullscreen_mode = (GfxDisplayMode)-1; + GfxDisplayMode m_fullscreen_mode = GfxDisplayMode::ForceUpdate; // previous mode (last frame) GfxDisplayMode m_last_fullscreen_mode = GfxDisplayMode::Windowed; - int m_last_windowed_xpos = 0; - int m_last_windowed_ypos = 0; + // move it a bit away from the top, or the title bar can be hidden + int m_last_windowed_xpos = 50; + int m_last_windowed_ypos = 50; int m_last_windowed_width = 640; int m_last_windowed_height = 480; @@ -84,6 +85,14 @@ class GfxDisplay { int width(); int height(); + + struct DisplaySettings { + int window_xpos; + int window_ypos; + }; + + void save_display_settings(); + void restore_display_settings(); }; namespace Display { diff --git a/game/graphics/gfx.h b/game/graphics/gfx.h index 4ec8f72ce6..df76cb5f4f 100644 --- a/game/graphics/gfx.h +++ b/game/graphics/gfx.h @@ -21,7 +21,7 @@ class GfxDisplay; // enum for rendering pipeline enum class GfxPipeline { Invalid = 0, OpenGL }; -enum GfxDisplayMode { Windowed = 0, Fullscreen = 1, Borderless = 2 }; +enum GfxDisplayMode { ForceUpdate = -1, Windowed = 0, Fullscreen = 1, Borderless = 2 }; // module for the different rendering pipelines struct GfxRendererModule { diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index fcb13a29d8..e2877b2ee1 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -371,14 +371,18 @@ void GLDisplay::on_cursor_position(GLFWwindow* window, double xposition, double } void GLDisplay::on_window_pos(GLFWwindow* /*window*/, int xpos, int ypos) { - if (m_fullscreen_target_mode == GfxDisplayMode::Windowed) { + // only change them on a legit change, not on the initial update + if (m_fullscreen_mode != GfxDisplayMode::ForceUpdate && + m_fullscreen_target_mode == GfxDisplayMode::Windowed) { m_last_windowed_xpos = xpos; m_last_windowed_ypos = ypos; } } void GLDisplay::on_window_size(GLFWwindow* /*window*/, int width, int height) { - if (m_fullscreen_target_mode == GfxDisplayMode::Windowed) { + // only change them on a legit change, not on the initial update + if (m_fullscreen_mode != GfxDisplayMode::ForceUpdate && + m_fullscreen_target_mode == GfxDisplayMode::Windowed) { m_last_windowed_width = width; m_last_windowed_height = height; } @@ -556,11 +560,13 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int screen) { glfwSetWindowMonitor(m_window, NULL, x, y, width, height, GLFW_DONT_CARE); - // these might have changed - m_last_windowed_width = width; - m_last_windowed_height = height; - m_last_windowed_xpos = x; - m_last_windowed_ypos = y; + // these might have changed, only store them on a legit change, not on the initial update + if (m_last_fullscreen_mode != GfxDisplayMode::ForceUpdate) { + m_last_windowed_width = width; + m_last_windowed_height = height; + m_last_windowed_xpos = x; + m_last_windowed_ypos = y; + } } break; case GfxDisplayMode::Fullscreen: { // fullscreen @@ -584,6 +590,9 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int screen) { glfwSetWindowMonitor(m_window, NULL, x, y, vmode->width, vmode->height, GLFW_DONT_CARE); #endif } break; + default: { + break; + } } } diff --git a/game/graphics/pipelines/opengl.h b/game/graphics/pipelines/opengl.h index 37f983dc7f..6b655ca52e 100644 --- a/game/graphics/pipelines/opengl.h +++ b/game/graphics/pipelines/opengl.h @@ -69,8 +69,9 @@ class GLDisplay : public GfxDisplay { }; struct DisplayState { - s32 window_pos_x = 0; - s32 window_pos_y = 0; + // move it a bit away from the top by default + s32 window_pos_x = 50; + s32 window_pos_y = 50; int window_size_width = 640, window_size_height = 480; float window_scale_x = 1.f, window_scale_y = 1.f; diff --git a/game/kernel/common/kmemcard.cpp b/game/kernel/common/kmemcard.cpp index 39d84092f4..e915af2ea2 100644 --- a/game/kernel/common/kmemcard.cpp +++ b/game/kernel/common/kmemcard.cpp @@ -116,7 +116,7 @@ u32 mc_checksum(Ptr data, s32 size) { * PC port function that returns whether a given bank ID's file exists or not. */ bool file_is_present(int id, int bank = 0) { - auto bankname = file_util::get_user_memcard_dir() / filename[4 + id * 2 + bank]; + auto bankname = file_util::get_user_memcard_dir(g_game_version) / filename[4 + id * 2 + bank]; if (!fs::exists(bankname) || fs::file_size(bankname) < BANK_TOTAL_SIZE) { // file doesn't exist, or size is bad. we do not want to open files that will crash on read! return false; @@ -146,13 +146,14 @@ void pc_update_card() { // int highest_save_count = 0; mc_last_file = -1; for (s32 file = 0; file < 4; file++) { - auto bankname = file_util::get_user_memcard_dir() / filename[4 + file * 2]; + auto bankname = file_util::get_user_memcard_dir(g_game_version) / filename[4 + file * 2]; mc_files[file].present = file_is_present(file); if (mc_files[file].present) { auto bankdata = file_util::read_binary_file(bankname.string()); auto header1 = reinterpret_cast(bankdata.data()); if (file_is_present(file, 1)) { - auto bankname2 = file_util::get_user_memcard_dir() / filename[1 + 4 + file * 2]; + auto bankname2 = + file_util::get_user_memcard_dir(g_game_version) / filename[1 + 4 + file * 2]; auto bankdata2 = file_util::read_binary_file(bankname2.string()); auto header2 = reinterpret_cast(bankdata2.data()); @@ -189,7 +190,7 @@ void pc_game_save_synch() { Timer mc_timer; mc_timer.start(); pc_update_card(); - auto path = file_util::get_user_memcard_dir() / filename[0]; + auto path = file_util::get_user_memcard_dir(g_game_version) / filename[0]; file_util::create_dir_if_needed_for_file(path.string()); // cd_reprobe_save // @@ -211,7 +212,8 @@ void pc_game_save_synch() { // file*2 + p4 is the bank (2 banks per file, p4 is 0 or 1 to select the bank) // 4 is the first bank file mc_print("open {} for saving", filename[op.param2 * 2 + 4 + p4]); - auto save_path = file_util::get_user_memcard_dir() / filename[op.param2 * 2 + 4 + p4]; + auto save_path = + file_util::get_user_memcard_dir(g_game_version) / filename[op.param2 * 2 + 4 + p4]; file_util::create_dir_if_needed_for_file(save_path.string()); auto fd = file_util::open_file(save_path.string().c_str(), "wb"); mc_print("synchronous save file open took {:.2f}ms\n", mc_timer.getMs()); @@ -281,11 +283,12 @@ void pc_game_load_open_file(FILE* fd) { if (fclose(fd) == 0) { // cb_closedload // // added : check if aux bank exists - if (p2 < 1 && - fs::exists(file_util::get_user_memcard_dir() / filename[op.param2 * 2 + 4 + p2 + 1])) { + if (p2 < 1 && fs::exists(file_util::get_user_memcard_dir(g_game_version) / + filename[op.param2 * 2 + 4 + p2 + 1])) { p2++; mc_print("reading next save bank {}", filename[op.param2 * 2 + 4 + p2]); - auto new_bankname = file_util::get_user_memcard_dir() / filename[op.param2 * 2 + 4 + p2]; + auto new_bankname = + file_util::get_user_memcard_dir(g_game_version) / filename[op.param2 * 2 + 4 + p2]; auto new_fd = file_util::open_file(new_bankname.string().c_str(), "rb"); pc_game_load_open_file(new_fd); } else { @@ -402,7 +405,7 @@ void pc_game_load_synch() { p2 = 0; mc_print("opening save file {}", filename[op.param2 * 2 + 4]); - auto path = file_util::get_user_memcard_dir() / filename[op.param2 * 2 + 4]; + auto path = file_util::get_user_memcard_dir(g_game_version) / filename[op.param2 * 2 + 4]; auto fd = file_util::open_file(path.string().c_str(), "rb"); pc_game_load_open_file(fd); diff --git a/game/kernel/jak1/kmachine.cpp b/game/kernel/jak1/kmachine.cpp index 50dbd93fe1..8d4330020e 100644 --- a/game/kernel/jak1/kmachine.cpp +++ b/game/kernel/jak1/kmachine.cpp @@ -677,8 +677,7 @@ void InitMachine_PCPort() { auto user_dir_path = file_util::get_user_config_dir(); intern_from_c("*pc-user-dir-base-path*")->value = make_string_from_c(user_dir_path.string().c_str()); - // TODO - we will eventually need a better way to know what game we are playing - auto settings_path = file_util::get_user_settings_dir(); + auto settings_path = file_util::get_user_settings_dir(g_game_version); intern_from_c("*pc-settings-folder*")->value = make_string_from_c(settings_path.string().c_str()); intern_from_c("*pc-settings-built-sha*")->value = make_string_from_c(GIT_VERSION); } diff --git a/game/kernel/jak2/kmachine.cpp b/game/kernel/jak2/kmachine.cpp index f9ec84c603..6cc370b12b 100644 --- a/game/kernel/jak2/kmachine.cpp +++ b/game/kernel/jak2/kmachine.cpp @@ -521,8 +521,7 @@ void InitMachine_PCPort() { auto user_dir_path = file_util::get_user_config_dir(); intern_from_c("*pc-user-dir-base-path*")->value() = make_string_from_c(user_dir_path.string().c_str()); - // TODO - we will eventually need a better way to know what game we are playing - auto settings_path = file_util::get_user_settings_dir(); + auto settings_path = file_util::get_user_settings_dir(g_game_version); intern_from_c("*pc-settings-folder*")->value() = make_string_from_c(settings_path.string().c_str()); intern_from_c("*pc-settings-built-sha*")->value() = make_string_from_c(GIT_VERSION); diff --git a/goal_src/jak1/pc/pckernel.gc b/goal_src/jak1/pc/pckernel.gc index 2a124fbf27..68658a7102 100644 --- a/goal_src/jak1/pc/pckernel.gc +++ b/goal_src/jak1/pc/pckernel.gc @@ -48,18 +48,18 @@ ;;;; updates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - (defmethod set-display-mode! pc-settings ((obj pc-settings) (mode symbol)) "sets the game's display mode" - ;; change the display mode. (set! (-> obj display-mode) mode) + ;; if windowed mode, set the size properly + (when (= (-> obj display-mode) 'windowed) + (pc-set-window-size (max PC_MIN_WIDTH (-> obj win-width)) (max PC_MIN_HEIGHT (-> obj win-height)))) 0) (defmethod set-size! pc-settings ((obj pc-settings) (width int) (height int)) "sets the size of the display window" - (format #t "Setting size to ~D x ~D~%" width height) + (format 0 "Setting ~A size to ~D x ~D~%" (-> obj display-mode) width height) (cond ((= 'windowed (-> obj display-mode)) (set! (-> obj win-width) width) @@ -73,7 +73,6 @@ ) (none)) - (defmethod set-aspect! pc-settings ((obj pc-settings) (aw int) (ah int)) "set the aspect ratio used for rendering. this forces native widescreen and takes width and height ratios." (let ((aspect (/ (the float aw) (the float ah)))) @@ -916,6 +915,10 @@ (format 0 "pc settings file read: ~A~%" filename) + ;; restore the windowed mode resolution properly + (when (= (-> obj display-mode) 'windowed) + (pc-set-window-size (max PC_MIN_WIDTH (-> obj win-width)) (max PC_MIN_HEIGHT (-> obj win-height)))) + #t ) @@ -932,13 +935,13 @@ (format file "(settings #x~X~%" (-> obj version)) (format file " (fps ~D)~%" (-> obj target-fps)) - (format file " (game-size ~D ~D)~%" (-> obj width) (-> obj height)) (format file " (msaa ~D)~%" (-> obj gfx-msaa)) - (format file " (window-size ~D ~D)~%" (-> obj win-width) (-> obj win-height)) (format file " (aspect-state ~A ~D ~D ~A)~%" (-> *setting-control* default aspect-ratio) (-> obj aspect-custom-x) (-> obj aspect-custom-y) (-> obj aspect-ratio-auto?)) (format file " (display-mode ~A)~%" (-> obj display-mode)) + (format file " (window-size ~D ~D)~%" (-> obj win-width) (-> obj win-height)) + (format file " (game-size ~D ~D)~%" (-> obj width) (-> obj height)) (format file " (monitor ~D)~%" (-> obj monitor)) (format file " (letterbox ~A)~%" (-> obj letterbox?)) (format file " (vsync ~A)~%" (-> obj vsync?))