mirror of
https://github.com/open-goal/jak-project
synced 2026-08-21 14:54:53 -04:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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.
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user