Add in-game option to switch fullscreen monitor (#1700)

* Add in-game option to switch fullscreen monitor

* mmm undefined memory :)

* Fix type consistency

* Optimize get_monitor and get_monitor_count since they're called often

* Address PR feedback

* Track fullscreen mode and minimized state to reduce GLFW calls per frame
This commit is contained in:
Ethan Lafrenais
2022-07-31 13:31:17 -04:00
committed by GitHub
parent 329bde229e
commit 88856ba5e0
19 changed files with 315 additions and 95 deletions
+4
View File
@@ -1481,6 +1481,8 @@
(subtitle-enabled #x1040)
(subtitle-disabled #x1041)
(text-language #x1042)
(display #x1043)
(display-fmt #x1044)
(msaa #x1050)
(x-times-fmt #x1051)
(2-times #x1052)
@@ -15736,6 +15738,7 @@
(flava-player)
(memcard-disable-auto-save)
(memcard-auto-save-disabled)
(monitor)
;; the last one!
(max)
@@ -15769,6 +15772,7 @@
(button-music)
(button-flava)
(cheat-toggle)
(monitor)
)
(defenum game-option-menu
+4 -1
View File
@@ -104,6 +104,10 @@
"SUBTITLES DISABLED")
(#x1042 "TEXT LANGUAGE"
"TEXT LANGUAGE")
(#x1043 "DISPLAY"
"DISPLAY")
(#x1044 "DISPLAY ~D"
"DISPLAY ~D")
(#x1050 "MSAA"
"MSAA")
@@ -334,7 +338,6 @@
(#x1116 "NORSK"
"NORSK")
;; -----------------
;; test
-6
View File
@@ -61,12 +61,6 @@ int GfxDisplay::height() {
return h;
}
void GfxDisplay::backup_params() {
get_size(&m_width, &m_height);
get_position(&m_xpos, &m_ypos);
fmt::print("backed up window: {},{} {}x{}\n", m_xpos, m_ypos, m_width, m_height);
}
/*
********************************
* DISPLAY
+27 -25
View File
@@ -19,21 +19,23 @@
class GfxDisplay {
const char* m_title;
// NOT actual size! just backups
int m_width;
int m_height;
// same here
int m_xpos;
int m_ypos;
int m_fullscreen_screen;
int m_fullscreen_target_screen;
int m_fullscreen_screen = -1;
int m_fullscreen_target_screen = -1;
bool m_imgui_visible;
protected:
bool m_main;
// next mode
GfxDisplayMode m_fullscreen_target_mode = GfxDisplayMode::Windowed;
GfxDisplayMode m_last_fullscreen_mode;
// current mode (start as -1 to force an initial fullscreen update)
GfxDisplayMode m_fullscreen_mode = (GfxDisplayMode)-1;
// previous mode (last frame)
GfxDisplayMode m_last_fullscreen_mode = GfxDisplayMode::Windowed;
int m_last_windowed_xpos = 0;
int m_last_windowed_ypos = 0;
int m_last_windowed_width = 640;
int m_last_windowed_height = 480;
public:
virtual ~GfxDisplay() {}
@@ -45,37 +47,37 @@ class GfxDisplay {
virtual int get_screen_vmode_count() = 0;
virtual void get_screen_size(int vmode_idx, s32* w, s32* h) = 0;
virtual int get_screen_rate(int vmode_idx) = 0;
virtual int get_monitor_count() = 0;
virtual void get_position(int* x, int* y) = 0;
virtual void get_size(int* w, int* h) = 0;
virtual GfxDisplayMode get_fullscreen() = 0;
virtual void render() = 0;
virtual void set_lock(bool lock) = 0;
virtual bool minimized() = 0;
virtual bool fullscreen_pending() {
return fullscreen_mode() != m_fullscreen_target_mode ||
m_fullscreen_screen != m_fullscreen_target_screen;
}
virtual void fullscreen_flush() {
update_fullscreen(m_fullscreen_target_mode, m_fullscreen_target_screen);
m_fullscreen_mode = m_fullscreen_target_mode;
m_fullscreen_screen = m_fullscreen_target_screen;
}
bool is_active() const { return get_window() != nullptr; }
void set_title(const char* title);
const char* title() const { return m_title; }
bool fullscreen_pending() { return get_fullscreen() != m_fullscreen_target_mode; }
void fullscreen_flush() {
update_fullscreen(m_fullscreen_target_mode, m_fullscreen_target_screen);
// TODO no
m_fullscreen_screen = m_fullscreen_target_screen;
}
void set_fullscreen(GfxDisplayMode mode, int screen) {
m_fullscreen_target_mode = mode;
m_fullscreen_target_screen = screen;
}
void update_last_fullscreen_mode() { m_last_fullscreen_mode = get_fullscreen(); }
void update_last_fullscreen_mode() { m_last_fullscreen_mode = fullscreen_mode(); }
GfxDisplayMode last_fullscreen_mode() const { return m_last_fullscreen_mode; }
GfxDisplayMode fullscreen_mode() { return m_fullscreen_mode; }
int fullscreen_screen() const { return m_fullscreen_screen; }
void set_imgui_visible(bool visible) { m_imgui_visible = visible; }
bool is_imgui_visible() const { return m_imgui_visible; }
bool windowed() { return get_fullscreen() == GfxDisplayMode::Windowed; }
void backup_params();
int width_backup() const { return m_width; }
int height_backup() const { return m_height; }
int xpos_backup() const { return m_xpos; }
int ypos_backup() const { return m_ypos; }
bool windowed() { return fullscreen_mode() == GfxDisplayMode::Windowed; }
int width();
int height();
+8 -1
View File
@@ -223,7 +223,7 @@ void get_window_scale(float* x, float* y) {
GfxDisplayMode get_fullscreen() {
if (Display::GetMainDisplay()) {
return Display::GetMainDisplay()->get_fullscreen();
return Display::GetMainDisplay()->fullscreen_mode();
} else {
return GfxDisplayMode::Windowed;
}
@@ -243,6 +243,13 @@ int get_screen_rate(s64 vmode_idx) {
return 0;
}
int get_monitor_count() {
if (Display::GetMainDisplay()) {
return Display::GetMainDisplay()->get_monitor_count();
}
return 0;
}
void get_screen_size(s64 vmode_idx, s32* w, s32* h) {
if (Display::GetMainDisplay()) {
Display::GetMainDisplay()->get_screen_size(vmode_idx, w, h);
+1
View File
@@ -138,6 +138,7 @@ void get_window_scale(float* x, float* y);
GfxDisplayMode get_fullscreen();
int get_screen_vmode_count();
int get_screen_rate(s64 vmode_idx);
int get_monitor_count();
void get_screen_size(s64 vmode_idx, s32* w, s32* h);
void set_frame_rate(int rate);
void set_vsync(bool vsync);
+174 -54
View File
@@ -78,24 +78,37 @@ struct GraphicsData {
std::unique_ptr<GraphicsData> g_gfx_data;
void SetDisplayCallbacks(GLFWwindow* d) {
glfwSetKeyCallback(
d, [](GLFWwindow* window, int key, int /*scancode*/, int action, int /*mods*/) {
if (action == GlfwKeyAction::Press) {
// lg::debug("KEY PRESS: key: {} scancode: {} mods: {:X}", key, scancode, mods);
Pad::OnKeyPress(key);
} else if (action == GlfwKeyAction::Release) {
// lg::debug("KEY RELEASE: key: {} scancode: {} mods: {:X}", key, scancode, mods);
Pad::OnKeyRelease(key);
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
if (display != NULL) { // toggle ImGui when pressing Alt
if ((key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT) &&
glfwGetWindowAttrib(window, GLFW_FOCUSED)) {
display->set_imgui_visible(!display->is_imgui_visible());
}
}
}
});
struct {
bool callbacks_registered = false;
GLFWmonitor** monitors;
int monitor_count;
} g_glfw_state;
void SetGlobalGLFWCallbacks() {
if (g_glfw_state.callbacks_registered) {
lg::warn("Global GLFW callbacks were already registered!");
}
// Get initial state
g_glfw_state.monitors = glfwGetMonitors(&g_glfw_state.monitor_count);
// Listen for events
glfwSetMonitorCallback([](GLFWmonitor* /*monitor*/, int /*event*/) {
// Reload monitor list
g_glfw_state.monitors = glfwGetMonitors(&g_glfw_state.monitor_count);
});
g_glfw_state.callbacks_registered = true;
}
void ClearGlobalGLFWCallbacks() {
if (!g_glfw_state.callbacks_registered) {
return;
}
glfwSetMonitorCallback(NULL);
g_glfw_state.callbacks_registered = false;
}
void ErrorCallback(int err, const char* msg) {
@@ -141,6 +154,7 @@ static int gl_init(GfxSettings& settings) {
}
static void gl_exit() {
ClearGlobalGLFWCallbacks();
g_gfx_data.reset();
glfwTerminate();
glfwSetErrorCallback(NULL);
@@ -186,7 +200,7 @@ static std::shared_ptr<GfxDisplay> gl_make_display(int width,
lg::error("Could not load icon for OpenGL window");
}
SetDisplayCallbacks(window);
SetGlobalGLFWCallbacks();
Pad::initialize();
if (HasError()) {
@@ -228,13 +242,43 @@ static std::shared_ptr<GfxDisplay> gl_make_display(int width,
GLDisplay::GLDisplay(GLFWwindow* window, bool is_main) : m_window(window) {
m_main = is_main;
// Get initial state
get_position(&m_last_windowed_xpos, &m_last_windowed_ypos);
get_size(&m_last_windowed_width, &m_last_windowed_height);
// Listen for window-specific GLFW events
glfwSetWindowUserPointer(window, reinterpret_cast<void*>(this));
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
display->on_key(window, key, scancode, action, mods);
});
glfwSetWindowPosCallback(window, [](GLFWwindow* window, int xpos, int ypos) {
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
display->on_window_pos(window, xpos, ypos);
});
glfwSetWindowSizeCallback(window, [](GLFWwindow* window, int width, int height) {
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
display->on_window_size(window, width, height);
});
glfwSetWindowIconifyCallback(window, [](GLFWwindow* window, int iconified) {
GLDisplay* display = reinterpret_cast<GLDisplay*>(glfwGetWindowUserPointer(window));
display->on_iconify(window, iconified);
});
}
GLDisplay::~GLDisplay() {
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = nullptr;
io.LogFilename = nullptr;
glfwSetKeyCallback(m_window, NULL);
glfwSetWindowPosCallback(m_window, NULL);
glfwSetWindowSizeCallback(m_window, NULL);
glfwSetWindowIconifyCallback(m_window, NULL);
glfwSetWindowUserPointer(m_window, nullptr);
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
@@ -245,6 +289,38 @@ GLDisplay::~GLDisplay() {
}
}
void GLDisplay::on_key(GLFWwindow* window, int key, int /*scancode*/, int action, int /*mods*/) {
if (action == GlfwKeyAction::Press) {
// lg::debug("KEY PRESS: key: {} scancode: {} mods: {:X}", key, scancode, mods);
Pad::OnKeyPress(key);
} else if (action == GlfwKeyAction::Release) {
// lg::debug("KEY RELEASE: key: {} scancode: {} mods: {:X}", key, scancode, mods);
Pad::OnKeyRelease(key);
if ((key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT) &&
glfwGetWindowAttrib(window, GLFW_FOCUSED)) {
set_imgui_visible(!is_imgui_visible());
}
}
}
void GLDisplay::on_window_pos(GLFWwindow* /*window*/, int xpos, int ypos) {
if (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) {
m_last_windowed_width = width;
m_last_windowed_height = height;
}
}
void GLDisplay::on_iconify(GLFWwindow* window, int iconified) {
m_minimized = iconified == GLFW_TRUE;
}
namespace {
std::string make_output_file_name(const std::string& file_name) {
file_util::create_dir_if_needed(file_util::get_file_path({"gfx_dumps"}));
@@ -353,25 +429,52 @@ void GLDisplay::get_scale(float* xs, float* ys) {
void GLDisplay::set_size(int width, int height) {
glfwSetWindowSize(m_window, width, height);
if (windowed()) {
m_last_windowed_width = width;
m_last_windowed_height = height;
}
}
void GLDisplay::update_fullscreen(GfxDisplayMode mode, int /*screen*/) {
GLFWmonitor* monitor = glfwGetPrimaryMonitor(); // todo
void GLDisplay::update_fullscreen(GfxDisplayMode mode, int screen) {
GLFWmonitor* monitor = get_monitor(screen);
switch (mode) {
case GfxDisplayMode::Windowed: {
// windowed
int x, y, width, height;
if (m_last_fullscreen_mode == GfxDisplayMode::Windowed) {
// windowed -> windowed, keep position and size
width = m_last_windowed_width;
height = m_last_windowed_height;
x = m_last_windowed_xpos;
y = m_last_windowed_ypos;
} else {
// fullscreen -> windowed, use last windowed size but on the monitor previously fullscreened
int monitorX, monitorY, monitorWidth, monitorHeight;
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
width = m_last_windowed_width;
height = m_last_windowed_height;
x = monitorX + (monitorWidth / 2) - (width / 2);
y = monitorY + (monitorHeight / 2) - (height / 2);
}
glfwSetWindowAttrib(m_window, GLFW_DECORATED, GLFW_TRUE);
glfwSetWindowFocusCallback(m_window, NULL);
glfwSetWindowAttrib(m_window, GLFW_FLOATING, GLFW_FALSE);
glfwSetWindowMonitor(m_window, NULL, xpos_backup(), ypos_backup(), width_backup(),
height_backup(), GLFW_DONT_CARE);
glfwSetWindowMonitor(m_window, NULL, x, y, width, height, GLFW_DONT_CARE);
set_imgui_visible(true);
// these might have changed
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
if (windowed()) {
backup_params();
}
const GLFWvidmode* vmode = glfwGetVideoMode(monitor);
glfwSetWindowAttrib(m_window, GLFW_DECORATED, GLFW_FALSE);
glfwSetWindowFocusCallback(m_window, NULL);
@@ -381,9 +484,6 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int /*screen*/) {
} break;
case GfxDisplayMode::Borderless: {
// borderless fullscreen
if (windowed()) {
backup_params();
}
int x, y;
glfwGetMonitorPos(monitor, &x, &y);
const GLFWvidmode* vmode = glfwGetVideoMode(monitor);
@@ -400,31 +500,20 @@ void GLDisplay::update_fullscreen(GfxDisplayMode mode, int /*screen*/) {
}
}
GfxDisplayMode GLDisplay::get_fullscreen() {
GLFWmonitor* monitor = glfwGetPrimaryMonitor(); // todo
const GLFWvidmode* vmode = glfwGetVideoMode(monitor);
if (glfwGetWindowMonitor(m_window) != NULL) {
return GfxDisplayMode::Fullscreen;
} else if (width() >= vmode->width && height() >= vmode->height) {
return GfxDisplayMode::Borderless;
} else {
return GfxDisplayMode::Windowed;
}
}
int GLDisplay::get_screen_vmode_count() {
int count = 0;
glfwGetVideoModes(glfwGetPrimaryMonitor(), &count);
glfwGetVideoModes(get_monitor(fullscreen_screen()), &count);
return count;
}
void GLDisplay::get_screen_size(int vmode_idx, s32* w_out, s32* h_out) {
auto vmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
GLFWmonitor* monitor = get_monitor(fullscreen_screen());
auto vmode = glfwGetVideoMode(monitor);
int count = 0;
auto vmodes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count);
auto vmodes = glfwGetVideoModes(monitor, &count);
if (vmode_idx >= 0) {
vmode = &vmodes[vmode_idx];
} else if (get_fullscreen() == GfxDisplayMode::Fullscreen) {
} else if (fullscreen_mode() == GfxDisplayMode::Fullscreen) {
for (int i = 0; i < count; ++i) {
if (!vmode || vmode->height < vmodes[i].height) {
vmode = &vmodes[i];
@@ -440,12 +529,13 @@ void GLDisplay::get_screen_size(int vmode_idx, s32* w_out, s32* h_out) {
}
int GLDisplay::get_screen_rate(int vmode_idx) {
auto vmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
GLFWmonitor* monitor = get_monitor(fullscreen_screen());
auto vmode = glfwGetVideoMode(monitor);
int count = 0;
auto vmodes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count);
auto vmodes = glfwGetVideoModes(monitor, &count);
if (vmode_idx >= 0) {
vmode = &vmodes[vmode_idx];
} else if (get_fullscreen() == GfxDisplayMode::Fullscreen) {
} else if (fullscreen_mode() == GfxDisplayMode::Fullscreen) {
for (int i = 0; i < count; ++i) {
if (!vmode || vmode->refreshRate < vmodes[i].refreshRate) {
vmode = &vmodes[i];
@@ -455,14 +545,45 @@ int GLDisplay::get_screen_rate(int vmode_idx) {
return vmode->refreshRate;
}
GLFWmonitor* GLDisplay::get_monitor(int index) {
if (index < 0 || index >= g_glfw_state.monitor_count) {
// out of bounds, default to primary monitor
index = 0;
}
return g_glfw_state.monitors[index];
}
int GLDisplay::get_monitor_count() {
return g_glfw_state.monitor_count;
}
bool GLDisplay::minimized() {
return glfwGetWindowAttrib(m_window, GLFW_ICONIFIED);
return m_minimized;
}
void GLDisplay::set_lock(bool lock) {
glfwSetWindowAttrib(m_window, GLFW_RESIZABLE, lock ? GLFW_TRUE : GLFW_FALSE);
}
bool GLDisplay::fullscreen_pending() {
GLFWmonitor* monitor = get_monitor(fullscreen_screen());
auto vmode = glfwGetVideoMode(monitor);
return GfxDisplay::fullscreen_pending() ||
(vmode->width != m_last_video_mode.width || vmode->height != m_last_video_mode.height ||
vmode->refreshRate != m_last_video_mode.refreshRate);
}
void GLDisplay::fullscreen_flush() {
GfxDisplay::fullscreen_flush();
GLFWmonitor* monitor = get_monitor(fullscreen_screen());
auto vmode = glfwGetVideoMode(monitor);
m_last_video_mode = *vmode;
}
void update_global_profiler() {
if (g_gfx_data->debug_gui.dump_events) {
prof().set_enable(false);
@@ -567,15 +688,14 @@ void GLDisplay::render() {
g_gfx_data->sync_cv.notify_all();
}
// update fullscreen mode, if requested
{
auto p = scoped_prof("fullscreen-update");
// slow, takes ~0.15 ms on linux
auto current_fullscreen_mode = get_fullscreen();
// checking minimized also takes ~0.1 ms, only check if we need to update fullscreen modes
if (current_fullscreen_mode != m_fullscreen_target_mode && !minimized()) {
update_last_fullscreen_mode();
if (fullscreen_pending() && !minimized()) {
fullscreen_flush();
}
m_last_fullscreen_mode = current_fullscreen_mode;
}
// reboot whole game, if requested
+14 -3
View File
@@ -19,8 +19,6 @@ enum GlfwKeyAction {
};
class GLDisplay : public GfxDisplay {
GLFWwindow* m_window;
public:
GLDisplay(GLFWwindow* window, bool is_main);
virtual ~GLDisplay();
@@ -32,12 +30,25 @@ class GLDisplay : public GfxDisplay {
void get_screen_size(int vmode_idx, s32* w, s32* h);
int get_screen_rate(int vmode_idx);
int get_screen_vmode_count();
GfxDisplayMode get_fullscreen();
int get_monitor_count();
void set_size(int w, int h);
void update_fullscreen(GfxDisplayMode mode, int screen);
void render();
bool minimized();
bool fullscreen_pending() override;
void fullscreen_flush() override;
void set_lock(bool lock);
void on_key(GLFWwindow* window, int key, int scancode, int action, int mods);
void on_window_pos(GLFWwindow* window, int xpos, int ypos);
void on_window_size(GLFWwindow* window, int width, int height);
void on_iconify(GLFWwindow* window, int iconified);
private:
GLFWwindow* m_window;
bool m_minimized = false;
GLFWvidmode m_last_video_mode = {0, 0, 0, 0, 0, 0};
GLFWmonitor* get_monitor(int index);
};
extern const GfxRendererModule gRendererOpenGL;
+7
View File
@@ -404,6 +404,13 @@ s64 get_screen_vmode_count() {
return Gfx::get_screen_vmode_count();
}
/*!
* Returns the number of available monitors.
*/
int get_monitor_count() {
return Gfx::get_monitor_count();
}
void mkdir_path(u32 filepath) {
auto filepath_str = std::string(Ptr<String>(filepath).c()->data());
file_util::create_dir_if_needed_for_file(filepath_str);
+2 -1
View File
@@ -63,6 +63,7 @@ void get_window_scale(u32 x_ptr, u32 y_ptr);
void get_screen_size(s64 vmode_idx, u32 w_ptr, u32 h_ptr);
s64 get_screen_rate(s64 vmode_idx);
s64 get_screen_vmode_count();
int get_monitor_count();
void mkdir_path(u32 filepath);
u64 filepath_exists(u32 filepath);
void prof_event(u32 name, u32 kind);
@@ -74,4 +75,4 @@ void set_collision_wireframe(u32 symptr);
void set_collision_mask(GfxGlobalSettings::CollisionRendererMode mode, int mask, u32 symptr);
u32 get_collision_mask(GfxGlobalSettings::CollisionRendererMode mode, int mask);
u32 offset_of_s7();
void vif_interrupt_callback();
void vif_interrupt_callback();
+1
View File
@@ -622,6 +622,7 @@ void InitMachine_PCPort() {
make_function_symbol_from_c("pc-get-screen-size", (void*)get_screen_size);
make_function_symbol_from_c("pc-get-screen-rate", (void*)get_screen_rate);
make_function_symbol_from_c("pc-get-screen-vmode-count", (void*)get_screen_vmode_count);
make_function_symbol_from_c("pc-get-monitor-count", (void*)get_monitor_count);
make_function_symbol_from_c("pc-set-window-size", (void*)Gfx::set_window_size);
make_function_symbol_from_c("pc-set-fullscreen", (void*)set_fullscreen);
make_function_symbol_from_c("pc-set-frame-rate", (void*)set_frame_rate);
@@ -122,6 +122,7 @@
(flava-player)
(memcard-disable-auto-save)
(memcard-auto-save-disabled)
(monitor)
;; the last one!
(max)
@@ -155,6 +156,7 @@
(button-music)
(button-flava)
(cheat-toggle)
(monitor)
)
)
)
@@ -842,6 +842,7 @@
(= v1-2 (progress-screen cheats))
(= v1-2 (progress-screen music-player))
(= v1-2 (progress-screen flava-player))
(= v1-2 (progress-screen monitor))
)
)
)
+2
View File
@@ -631,6 +631,8 @@
(subtitle-enabled #x1040)
(subtitle-disabled #x1041)
(text-language #x1042)
(display #x1043)
(display-fmt #x1044)
(msaa #x1050)
(x-times-fmt #x1051)
(2-times #x1052)
+1
View File
@@ -337,6 +337,7 @@
(define-extern pc-get-screen-size (function int (pointer int32) (pointer int32) none))
(define-extern pc-get-screen-rate (function int int))
(define-extern pc-get-screen-vmode-count (function int))
(define-extern pc-get-monitor-count (function int))
(define-extern pc-get-os (function symbol))
(define-extern pc-get-window-size (function (pointer int32) (pointer int32) none))
(define-extern pc-get-window-scale (function (pointer float) (pointer float) none))
+2
View File
@@ -219,6 +219,7 @@
(vsync? symbol) ;; vsync.
(font-scale float) ;; font scaling.
(window-lock? symbol) ;; whether the window can be resized by the user or not.
(monitor int32) ;; index of which monitor to use when fullscreen or borderless
;; debug settings
(os symbol) ;; windows, linux, macos
@@ -330,6 +331,7 @@
(set-aspect-ratio! (_type_ float) none)
(set-window-lock! (_type_ symbol) symbol)
(set-frame-rate! (_type_ int) int)
(set-monitor! (_type_ int) none)
(read-from-file (_type_ string) symbol)
(write-to-file (_type_ string) symbol)
(update-cheats (_type_) int)
+16 -1
View File
@@ -122,6 +122,11 @@
rate)
(defmethod set-monitor! pc-settings ((obj pc-settings) (monitor int))
"set the monitor to use when in fullscreen/borderless"
(set! (-> obj monitor) monitor)
(none))
(defmethod commit-to-file pc-settings ((obj pc-settings))
"commits the current settings to the file"
;; auto load settings if available
@@ -187,8 +192,16 @@
)
)
;; if monitor selection is out of bounds (e.g. if a monitor got disconnected),
;; then default to the primary monitor
(when (>= (-> obj monitor) (pc-get-monitor-count))
(format 0 "Monitor selection out of bounds, defaulting to primary monitor.~%")
(set! (-> obj monitor) 0)
)
;; set fullscreen to what we want
(pc-set-fullscreen (-> obj display-mode) 0)
(pc-set-fullscreen (-> obj display-mode) (-> obj monitor))
;; set window size and fps automatically if the window lock is enabled.
(when (-> obj window-lock?)
(pc-set-vsync (-> obj vsync?))
@@ -786,6 +799,7 @@
)
)
(("display-mode") (set-display-mode! obj (file-stream-read-symbol file)))
(("monitor") (set-monitor! obj (file-stream-read-int file)))
(("letterbox") (set! (-> obj letterbox?) (file-stream-read-symbol file)))
(("vsync") (set! (-> obj vsync?) (file-stream-read-symbol file)))
(("font-scale") (set! (-> obj font-scale) (file-stream-read-float file)))
@@ -903,6 +917,7 @@
(-> obj aspect-custom-x) (-> obj aspect-custom-y)
(-> obj aspect-ratio-auto?))
(format file " (display-mode ~A)~%" (-> obj display-mode))
(format file " (monitor ~D)~%" (-> obj monitor))
(format file " (letterbox ~A)~%" (-> obj letterbox?))
(format file " (vsync ~A)~%" (-> obj vsync?))
(format file " (font-scale ~f)~%" (-> obj font-scale))
+44 -2
View File
@@ -138,6 +138,7 @@
(define *graphic-options-pc* (new 'static 'boxed-array :type game-option
(new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id game-resolution) :scale #t :param3 (game-option-menu resolution))
(new 'static 'game-option :option-type (game-option-type display-mode) :name (game-text-id display-mode) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id display) :scale #t :param3 (game-option-menu monitor))
(new 'static 'game-option :option-type (game-option-type on-off) :name (game-text-id vsync) :scale #t)
(new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id aspect-ratio) :scale #t :param3 (game-option-menu aspect-ratio))
(new 'static 'game-option :option-type (game-option-type msaa) :name (game-text-id msaa) :scale #t)
@@ -502,6 +503,22 @@
*temp-options*
)
(defun build-monitor-options ()
(set! (-> *temp-options* length) 0)
(dotimes (i (pc-get-monitor-count))
(let ((option (-> *temp-options* (length *temp-options*))))
(set! (-> option option-type) (game-option-type monitor))
(set! (-> option name) (game-text-id display-fmt))
(set! (-> option param1) (the float i))
(set! (-> option scale) #t)
(1+! (-> *temp-options* length))
)
)
(add-back-option)
)
@@ -681,6 +698,7 @@
(set! (-> *options-remap* (progress-screen flava-player)) *temp-options*)
(set! (-> *options-remap* (progress-screen memcard-disable-auto-save)) *yes-no-options*)
(set! (-> *options-remap* (progress-screen memcard-auto-save-disabled)) *ok-options*)
(set! (-> *options-remap* (progress-screen monitor)) *temp-options*)
;; set default params
(set! (-> *progress-state* aspect-ratio-choice) (get-aspect-ratio))
@@ -710,9 +728,10 @@
(set! (-> *game-options-pc* 6 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *game-options-pc* 7 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 1 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 2 value-to-modify) (&-> *pc-settings* vsync?))
(set! (-> *graphic-options-pc* 4 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 2 value-to-modify) (&-> *pc-settings* monitor))
(set! (-> *graphic-options-pc* 3 value-to-modify) (&-> *pc-settings* vsync?))
(set! (-> *graphic-options-pc* 5 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-pc* 6 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-no-frame-rate-pc* 1 value-to-modify) (&-> *progress-carousell* int-backup))
(set! (-> *graphic-options-no-frame-rate-pc* 2 value-to-modify) (&-> *pc-settings* vsync?))
(set! (-> *graphic-options-no-frame-rate-pc* 4 value-to-modify) (&-> *progress-carousell* int-backup))
@@ -772,6 +791,9 @@
(set! (-> *options-remap* (-> obj display-state)) *secrets-title*)
(set! (-> *options-remap* (-> obj display-state)) *secrets*))
)
(((progress-screen monitor))
(build-monitor-options)
)
)
;; run nav code
(let ((options (-> *options-remap* (-> obj display-state))))
@@ -1174,6 +1196,17 @@
(set! (-> obj next-display-state) (progress-screen invalid))
(commit-to-file *pc-settings*)
)
((= (-> options (-> obj option-index) option-type) (game-option-type monitor))
;; monitor button
(let ((monitor (the int (-> options (-> obj option-index) param1))))
(set-monitor! *pc-settings* monitor)
)
(cpad-clear! 0 x)
(cpad-clear! 0 circle)
(sound-play "cursor-options")
(set! (-> obj next-display-state) (progress-screen invalid))
(commit-to-file *pc-settings*)
)
((= (-> options (-> obj option-index) option-type) (game-option-type aspect-new))
;; aspect ratio button.
(let ((newx (the int (-> options (-> obj option-index) param1)))
@@ -1725,6 +1758,14 @@
(set! option-str (string-format (lookup-text! *common-text* (-> options index name) #f)
(the int (-> options index param1)) (the int (-> options index param2))))
)
(((game-option-type monitor))
;; monitor list
(set! option-str
(string-format (lookup-text! *common-text* (-> options index name) #f)
(+ 1 (the int (-> options index param1)))
)
)
)
(else
(cond
((and (-> obj selected-option) (= (-> obj option-index) index))
@@ -2143,6 +2184,7 @@
(progress-screen aspect-ratio)
(progress-screen secrets)
(progress-screen cheats)
(progress-screen monitor)
)
(hide-progress-icons)
(draw-options self 115 25 0.82)
+5 -1
View File
@@ -197,8 +197,12 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
io.AddInputCharacter(c);
}
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackMonitor != NULL)
bd->PrevUserCallbackMonitor(monitor, event);
// Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
}