diff --git a/game/graphics/display.cpp b/game/graphics/display.cpp index 430ffade63..5ee154e846 100644 --- a/game/graphics/display.cpp +++ b/game/graphics/display.cpp @@ -16,10 +16,6 @@ namespace { -bool renderer_is_correct(const GfxRendererModule* renderer, GfxPipeline pipeline) { - return renderer->pipeline == pipeline; -} - void set_main_display(std::shared_ptr display) { if (Display::g_displays.size() > 0) { Display::g_displays[0] = display; @@ -36,66 +32,27 @@ void set_main_display(std::shared_ptr display) { ******************************** */ -GfxDisplay::GfxDisplay(GLFWwindow* a_window) { - set_renderer(GfxPipeline::OpenGL); - set_window(a_window); -} - -GfxDisplay::~GfxDisplay() { - m_renderer->kill_display(this); - // window_generic_ptr = nullptr; -} - -void GfxDisplay::set_renderer(GfxPipeline pipeline) { - if (is_active()) { - lg::error("Can't change display's renderer while window exists."); - return; - } - if (m_renderer != nullptr) { - lg::error("A display changed renderer unexpectedly."); - return; - } - - m_renderer = Gfx::GetRenderer(pipeline); -} - -void GfxDisplay::set_window(GLFWwindow* window) { - if (!renderer_is_correct(m_renderer, GfxPipeline::OpenGL)) { - lg::error("Can't set OpenGL window when using {}", m_renderer->name); - return; - } - if (is_active()) { - lg::error("Already have a window. Close window first."); - return; - } - - this->window_glfw = window; -} - void GfxDisplay::set_title(const char* title) { if (!is_active()) { lg::error("No window to set title `{}`.", title); return; } + // TODO set title? m_title = title; } -void GfxDisplay::render_graphics() { - m_renderer->render_display(this); -} - int GfxDisplay::width() { int w; - m_renderer->display_size(this, &w, NULL); + get_size(&w, NULL); return w; } int GfxDisplay::height() { int h; - m_renderer->display_size(this, NULL, &h); + get_size(NULL, &h); #ifdef _WIN32 - if (fullscreen_mode() == Gfx::DisplayMode::Borderless) { + if (last_fullscreen_mode() == GfxDisplayMode::Borderless) { // windows borderless hack h--; } @@ -104,8 +61,8 @@ int GfxDisplay::height() { } void GfxDisplay::backup_params() { - m_renderer->display_size(this, &m_width, &m_height); - m_renderer->display_position(this, &m_xpos, &m_ypos); + 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); } @@ -130,7 +87,7 @@ int InitMainDisplay(int width, int height, const char* title, GfxSettings& setti return 1; } - auto display = Gfx::GetCurrentRenderer()->make_main_display(width, height, title, settings); + auto display = Gfx::GetCurrentRenderer()->make_display(width, height, title, settings, true); if (display == NULL) { lg::error("Failed to make main display."); return 1; diff --git a/game/graphics/display.h b/game/graphics/display.h index d1983ac44f..c454a5894e 100644 --- a/game/graphics/display.h +++ b/game/graphics/display.h @@ -5,19 +5,22 @@ * Display for graphics. This is the game window, distinct from the runtime console. */ -#include "pipelines/opengl.h" -#include "gfx.h" #include #include +#include "common/util/Assert.h" +#include "gfx.h" + +// lol hax +#define __NYI_DEF \ + { ASSERT_MSG(false, "nyi"); } // a GfxDisplay class is equivalent to a window that displays stuff. This holds an actual internal // window pointer used by whichever renderer. It also contains functions for setting and // retrieving certain window parameters. +// Maybe this is better implemented as an abstract class and renderers would have overrides? class GfxDisplay { const char* m_title; - const GfxRendererModule* m_renderer = nullptr; - // NOT actual size! just backups int m_width; int m_height; @@ -25,56 +28,52 @@ class GfxDisplay { int m_xpos; int m_ypos; - Gfx::DisplayMode m_fullscreen_mode = Gfx::DisplayMode::Windowed; - Gfx::DisplayMode m_fullscreen_target_mode = Gfx::DisplayMode::Windowed; + GfxDisplayMode m_fullscreen_target_mode = GfxDisplayMode::Windowed; + GfxDisplayMode m_last_fullscreen_mode; int m_fullscreen_screen; int m_fullscreen_target_screen; + protected: + bool m_main; + public: - GfxDisplay(GLFWwindow* a_window); // OpenGL window constructor - ~GfxDisplay(); // destructor - this calls the renderer's function for getting rid of a window, - // and we can then get rid of the GfxDisplay itself + virtual ~GfxDisplay() {} - // all kinds of windows for the display - union { - void* window_generic_ptr = nullptr; - GLFWwindow* window_glfw; - }; - - bool is_active() const { return window_generic_ptr != nullptr; } - void set_renderer(GfxPipeline pipeline); - void set_window(GLFWwindow* window); + virtual void* get_window() const __NYI_DEF; + virtual void set_size(int w, int h) __NYI_DEF; + virtual void update_fullscreen(GfxDisplayMode mode, int screen) __NYI_DEF; + virtual void get_scale(float* x, float* y) __NYI_DEF; + virtual void get_screen_size(int vmode_idx, s32* w, s32* h, s32* c) __NYI_DEF; + virtual void get_position(int* x, int* y) __NYI_DEF; + virtual void get_size(int* w, int* h) __NYI_DEF; + virtual GfxDisplayMode get_fullscreen() __NYI_DEF; + virtual void render() __NYI_DEF; + bool is_active() const { return get_window() != nullptr; } void set_title(const char* title); - void set_size(int w, int h) { m_renderer->display_set_size(this, w, h); } - void get_scale(float* x, float* y) { m_renderer->display_scale(this, x, y); } - void get_screen_size(s64 vmode_idx, s32* w, s32* h, s32* c) { - m_renderer->screen_size(this, vmode_idx, 0, w, h, c); - } const char* title() const { return m_title; } - bool fullscreen_pending() const { return m_fullscreen_mode != m_fullscreen_target_mode; } + bool fullscreen_pending() { return get_fullscreen() != m_fullscreen_target_mode; } void fullscreen_flush() { - m_renderer->set_fullscreen(this, m_fullscreen_target_mode, m_fullscreen_target_screen); - m_fullscreen_mode = m_fullscreen_target_mode; + update_fullscreen(m_fullscreen_target_mode, m_fullscreen_target_screen); + // TODO no m_fullscreen_screen = m_fullscreen_target_screen; } - void set_fullscreen(Gfx::DisplayMode mode, int screen) { + void set_fullscreen(GfxDisplayMode mode, int screen) { m_fullscreen_target_mode = mode; m_fullscreen_target_screen = screen; } - int fullscreen_mode() const { return m_fullscreen_mode; } + void update_last_fullscreen_mode() { m_last_fullscreen_mode = get_fullscreen(); } + GfxDisplayMode last_fullscreen_mode() const { return m_last_fullscreen_mode; } int fullscreen_screen() const { return m_fullscreen_screen; } - bool windowed() const { return m_fullscreen_mode == Gfx::DisplayMode::Windowed; } + bool windowed() { return get_fullscreen() == GfxDisplayMode::Windowed; } void backup_params(); - int width_backup() { return m_width; } - int height_backup() { return m_height; } - int xpos_backup() { return m_xpos; } - int ypos_backup() { return m_ypos; } + 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; } int width(); int height(); - - void render_graphics(); }; namespace Display { diff --git a/game/graphics/gfx.cpp b/game/graphics/gfx.cpp index f7da0b88fd..889932c8b8 100644 --- a/game/graphics/gfx.cpp +++ b/game/graphics/gfx.cpp @@ -55,6 +55,7 @@ GfxSettings g_settings; void LoadSettings() { const auto filename = file_util::get_file_path({GAME_CONFIG_DIR_NAME, SETTINGS_GFX_FILE_NAME}); if (std::filesystem::exists(filename)) { + // this is just wrong LOL FILE* fp = fopen(filename.c_str(), "rb"); lg::info("Found graphics configuration file. Checking version."); u64 version; @@ -83,13 +84,12 @@ void SaveSettings() { const GfxRendererModule* GetRenderer(GfxPipeline pipeline) { switch (pipeline) { case GfxPipeline::Invalid: - lg::error("Requested invalid graphics pipeline!"); + lg::error("Requested invalid renderer", pipeline); return NULL; - break; case GfxPipeline::OpenGL: - return &moduleOpenGL; + return &gRendererOpenGL; default: - lg::error("Unknown graphics pipeline {}", (u64)pipeline); + lg::error("Requested unknown renderer {}", (u64)pipeline); return NULL; } } @@ -119,7 +119,7 @@ u32 Init() { } if (g_main_thread_id != std::this_thread::get_id()) { - lg::warn("Ran Gfx::Init outside main thread. Init display elsewhere?"); + lg::error("Ran Gfx::Init outside main thread. Init display elsewhere?"); } else { Display::InitMainDisplay(640, 480, "OpenGOAL GL Window", g_settings); } @@ -133,7 +133,7 @@ void Loop(std::function f) { // check if we have a display if (Display::GetMainDisplay()) { // lg::debug("run display"); - Display::GetMainDisplay()->render_graphics(); + Display::GetMainDisplay()->render(); } } } @@ -184,7 +184,9 @@ void set_levels(const std::vector& levels) { } void poll_events() { - GetCurrentRenderer()->poll_events(); + if (GetCurrentRenderer()) { + GetCurrentRenderer()->poll_events(); + } } u64 get_window_width() { @@ -215,11 +217,11 @@ void get_window_scale(float* x, float* y) { } } -int get_fullscreen() { +GfxDisplayMode get_fullscreen() { if (Display::GetMainDisplay()) { - return Display::GetMainDisplay()->fullscreen_mode(); + return Display::GetMainDisplay()->get_fullscreen(); } else { - return DisplayMode::Windowed; + return GfxDisplayMode::Windowed; } } @@ -234,7 +236,7 @@ void set_letterbox(int w, int h) { g_global_settings.lbox_h = h; } -void set_fullscreen(DisplayMode mode, int screen) { +void set_fullscreen(GfxDisplayMode mode, int screen) { if (Display::GetMainDisplay()) { Display::GetMainDisplay()->set_fullscreen(mode, screen); } diff --git a/game/graphics/gfx.h b/game/graphics/gfx.h index 7b8028337b..5556cd2689 100644 --- a/game/graphics/gfx.h +++ b/game/graphics/gfx.h @@ -19,20 +19,14 @@ class GfxDisplay; // enum for rendering pipeline enum class GfxPipeline { Invalid = 0, OpenGL }; +enum GfxDisplayMode { Windowed = 0, Fullscreen = 1, Borderless = 2 }; // module for the different rendering pipelines struct GfxRendererModule { std::function init; - std::function(int w, int h, const char* title, GfxSettings& settings)> - make_main_display; - std::function kill_display; - std::function render_display; - std::function display_position; - std::function display_size; - std::function display_set_size; - std::function display_scale; - std::function set_fullscreen; - std::function screen_size; + std::function(int width, int height, const char* title, GfxSettings& settings, bool is_main)> + make_display; std::function exit; std::function vsync; std::function sync_path; @@ -47,6 +41,7 @@ struct GfxRendererModule { }; // store settings related to the gfx systems +// TODO merge with globalsettings struct GfxSettings { // current version of the settings. this should be set up so that newer versions are always higher // than older versions @@ -98,13 +93,9 @@ namespace Gfx { extern GfxGlobalSettings g_global_settings; extern GfxSettings g_settings; -// extern const std::vector renderers; -const GfxRendererModule* GetRenderer(GfxPipeline pipeline); const GfxRendererModule* GetCurrentRenderer(); -enum DisplayMode { Windowed = 0, Fullscreen = 1, Borderless = 2 }; - u32 Init(); void Loop(std::function f); u32 Exit(); @@ -120,10 +111,10 @@ u64 get_window_width(); u64 get_window_height(); void set_window_size(u64 w, u64 h); void get_window_scale(float* x, float* y); -int get_fullscreen(); +GfxDisplayMode get_fullscreen(); void get_screen_size(s64 vmode_idx, s32* w, s32* h, s32* c); void set_letterbox(int w, int h); -void set_fullscreen(DisplayMode mode, int screen); +void set_fullscreen(GfxDisplayMode mode, int screen); void input_mode_set(u32 enable); void input_mode_save(); s64 get_mapped_button(s64 pad, s64 button); diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index bed2254ce0..7e48de3106 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -1,6 +1,6 @@ /*! * @file opengl.cpp - * Lower-level OpenGL implementation. + * Lower-level OpenGL interface. No actual rendering is performed here! */ #include @@ -139,24 +139,31 @@ static void gl_exit() { gl_inited = false; } -static std::shared_ptr gl_make_main_display(int width, - int height, - const char* title, - GfxSettings& settings) { +static std::shared_ptr gl_make_display(int width, + int height, + const char* title, + GfxSettings& settings, + bool is_main) { GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL); if (!window) { - lg::error("gl_make_main_display failed - Could not create display window"); + lg::error("gl_make_display failed - Could not create display window"); return NULL; } glfwMakeContextCurrent(window); - gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); - if (!gl_inited && !gladLoadGL()) { - lg::error("GL init fail"); - return NULL; + if (!gl_inited) { + gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); + if (!gladLoadGL()) { + lg::error("GL init fail"); + return NULL; + } + g_gfx_data = std::make_unique(); + + gl_inited = true; } + // window icon std::string image_path = (file_util::get_jak_project_dir() / "game" / "assets" / "appicon.png").string(); @@ -165,9 +172,6 @@ static std::shared_ptr gl_make_main_display(int width, stbi_load(image_path.c_str(), &images[0].width, &images[0].height, 0, 4); // rgba channels glfwSetWindowIcon(window, 1, images); stbi_image_free(images[0].pixels); - g_gfx_data = std::make_unique(); - - gl_inited = true; // init framerate settings GLFWmonitor* primary_monitor = glfwGetPrimaryMonitor(); @@ -201,11 +205,11 @@ static std::shared_ptr gl_make_main_display(int width, Pad::initialize(); if (HasError()) { - lg::error("gl_make_main_display error"); + lg::error("gl_make_display error"); return NULL; } - std::shared_ptr display = std::make_shared(window); + auto display = std::make_shared(window, is_main); // lg::debug("init display #x{:x}", (uintptr_t)display); // setup imgui @@ -225,16 +229,23 @@ static std::shared_ptr gl_make_main_display(int width, glfwGetError(NULL); // set up the renderer - ImGui_ImplOpenGL3_Init("#version 130"); + ImGui_ImplOpenGL3_Init("#version 430"); - return display; + return std::static_pointer_cast(display); } -static void gl_kill_display(GfxDisplay* display) { +GLDisplay::GLDisplay(GLFWwindow* window, bool is_main) : m_window(window) { + m_main = is_main; +} + +GLDisplay::~GLDisplay() { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); - glfwDestroyWindow(display->window_glfw); + glfwDestroyWindow(m_window); + if (m_main) { + gl_exit(); + } } namespace { @@ -304,69 +315,76 @@ void render_game_frame(int width, int height, int lbox_width, int lbox_height) { } } -static void gl_display_position(GfxDisplay* display, int* x, int* y) { - glfwGetWindowPos(display->window_glfw, x, y); +void GLDisplay::get_position(int* x, int* y) { + glfwGetWindowPos(m_window, x, y); } -static void gl_display_size(GfxDisplay* display, int* width, int* height) { - glfwGetFramebufferSize(display->window_glfw, width, height); +void GLDisplay::get_size(int* width, int* height) { + glfwGetFramebufferSize(m_window, width, height); } -static void gl_display_set_size(GfxDisplay* display, int width, int height) { - glfwSetWindowSize(display->window_glfw, width, height); +void GLDisplay::get_scale(float* xs, float* ys) { + glfwGetWindowContentScale(m_window, xs, ys); } -static void gl_display_scale(GfxDisplay* display, float* xs, float* ys) { - glfwGetWindowContentScale(display->window_glfw, xs, ys); +void GLDisplay::set_size(int width, int height) { + glfwSetWindowSize(m_window, width, height); } -static void gl_set_fullscreen(GfxDisplay* display, int mode, int /*screen*/) { +void GLDisplay::update_fullscreen(GfxDisplayMode mode, int /*screen*/) { GLFWmonitor* monitor = glfwGetPrimaryMonitor(); // todo - auto window = display->window_glfw; switch (mode) { - case Gfx::DisplayMode::Windowed: { + case GfxDisplayMode::Windowed: { // windowed - glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_TRUE); - glfwSetWindowFocusCallback(window, NULL); - glfwSetWindowAttrib(window, GLFW_FLOATING, GLFW_FALSE); - glfwSetWindowMonitor(window, NULL, display->xpos_backup(), display->ypos_backup(), - display->width_backup(), display->height_backup(), GLFW_DONT_CARE); + 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); } break; - case Gfx::DisplayMode::Fullscreen: { + case GfxDisplayMode::Fullscreen: { // fullscreen - if (display->windowed()) { - display->backup_params(); + if (windowed()) { + backup_params(); } const GLFWvidmode* vmode = glfwGetVideoMode(monitor); - glfwSetWindowMonitor(window, monitor, 0, 0, vmode->width, vmode->height, 60); - glfwSetWindowFocusCallback(window, FocusCallback); + glfwSetWindowAttrib(m_window, GLFW_DECORATED, GLFW_TRUE); + glfwSetWindowFocusCallback(m_window, NULL); + glfwSetWindowAttrib(m_window, GLFW_FLOATING, GLFW_FALSE); + glfwSetWindowMonitor(m_window, monitor, 0, 0, vmode->width, vmode->height, 60); } break; - case Gfx::DisplayMode::Borderless: { + case GfxDisplayMode::Borderless: { // borderless fullscreen - if (display->windowed()) { - display->backup_params(); + if (windowed()) { + backup_params(); } int x, y; glfwGetMonitorPos(monitor, &x, &y); const GLFWvidmode* vmode = glfwGetVideoMode(monitor); - glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE); - glfwSetWindowAttrib(window, GLFW_FLOATING, GLFW_TRUE); - glfwSetWindowFocusCallback(window, FocusCallback); + glfwSetWindowAttrib(m_window, GLFW_DECORATED, GLFW_FALSE); + // glfwSetWindowAttrib(m_window, GLFW_FLOATING, GLFW_TRUE); + // glfwSetWindowFocusCallback(m_window, FocusCallback); #ifdef _WIN32 - glfwSetWindowMonitor(window, NULL, x, y, vmode->width, vmode->height + 1, GLFW_DONT_CARE); + glfwSetWindowMonitor(m_window, NULL, x, y, vmode->width, vmode->height + 1, GLFW_DONT_CARE); #else - glfwSetWindowMonitor(window, NULL, x, y, vmode->width, vmode->height, GLFW_DONT_CARE); + glfwSetWindowMonitor(m_window, NULL, x, y, vmode->width, vmode->height, GLFW_DONT_CARE); #endif } break; } } -static void gl_screen_size(GfxDisplay* /*display*/, - int vmode_idx, - int /*screen*/, - s32* w_out, - s32* h_out, - s32* count_out) { +GfxDisplayMode GLDisplay::get_fullscreen() { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); // todo + const GLFWvidmode* vmode = glfwGetVideoMode(monitor); + if (width() >= vmode->width && height() >= vmode->height) { + return glfwGetWindowAttrib(m_window, GLFW_DECORATED) == GLFW_TRUE ? GfxDisplayMode::Fullscreen + : GfxDisplayMode::Borderless; + } else { + return GfxDisplayMode::Windowed; + } +} + +void GLDisplay::get_screen_size(int vmode_idx, s32* w_out, s32* h_out, s32* count_out) { int count = 0; auto vmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); auto vmodes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count); @@ -402,14 +420,12 @@ void update_global_profiler() { /*! * Main function called to render graphics frames. This is called in a loop. */ -static void gl_render_display(GfxDisplay* display) { - GLFWwindow* window = display->window_glfw; - +void GLDisplay::render() { // poll events { auto p = scoped_prof("poll-gamepads"); glfwPollEvents(); - glfwMakeContextCurrent(window); + glfwMakeContextCurrent(m_window); Pad::update_gamepads(); } @@ -425,9 +441,9 @@ static void gl_render_display(GfxDisplay* display) { int width = Gfx::g_global_settings.lbox_w; int height = Gfx::g_global_settings.lbox_h; int fbuf_w, fbuf_h; - glfwGetFramebufferSize(window, &fbuf_w, &fbuf_h); + glfwGetFramebufferSize(m_window, &fbuf_w, &fbuf_h); #ifdef _WIN32 - if (display->fullscreen_mode() == 2) { + if (last_fullscreen_mode() == GfxDisplayMode::Borderless) { // pretend the framebuffer is 1 pixel shorter on borderless. fullscreen issues! fbuf_h--; } @@ -437,7 +453,7 @@ static void gl_render_display(GfxDisplay* display) { // vertical letterbox size int lbox_h = (fbuf_h - height) / 2; #ifdef _WIN32 - if (display->fullscreen_mode() == 2) { + if (last_fullscreen_mode() == GfxDisplayMode::Borderless) { // add one pixel of vertical letterbox on borderless to make up for extra line lbox_h++; } @@ -476,7 +492,7 @@ static void gl_render_display(GfxDisplay* display) { g_gfx_data->debug_gui.finish_frame(); { auto p = scoped_prof("swap-buffers"); - glfwSwapBuffers(window); + glfwSwapBuffers(m_window); } if (g_gfx_data->debug_gui.framelimiter) { auto p = scoped_prof("frame-limiter"); @@ -488,9 +504,10 @@ static void gl_render_display(GfxDisplay* display) { prof().instant_event("ROOT"); update_global_profiler(); - if (display->fullscreen_pending()) { - display->fullscreen_flush(); + if (fullscreen_pending()) { + fullscreen_flush(); } + update_last_fullscreen_mode(); // toggle even odd and wake up engine waiting on vsync. { @@ -506,7 +523,7 @@ static void gl_render_display(GfxDisplay* display) { } // exit if display window was closed - if (glfwWindowShouldClose(window)) { + if (glfwWindowShouldClose(m_window)) { std::unique_lock lock(g_gfx_data->sync_mutex); MasterExit = RuntimeExitStatus::EXIT; g_gfx_data->sync_cv.notify_all(); @@ -602,17 +619,9 @@ void gl_set_pmode_alp(float val) { g_gfx_data->pmode_alp = val; } -const GfxRendererModule moduleOpenGL = { +const GfxRendererModule gRendererOpenGL = { gl_init, // init - gl_make_main_display, // make_main_display - gl_kill_display, // kill_display - gl_render_display, // render_display - gl_display_position, // display_position - gl_display_size, // display_size - gl_display_set_size, // display_set_size - gl_display_scale, // display_scale - gl_set_fullscreen, // set_fullscreen - gl_screen_size, // screen_size + gl_make_display, // make_display gl_exit, // exit gl_vsync, // vsync gl_sync_path, // sync_path diff --git a/game/graphics/pipelines/opengl.h b/game/graphics/pipelines/opengl.h index 404aca575e..318abc36f5 100644 --- a/game/graphics/pipelines/opengl.h +++ b/game/graphics/pipelines/opengl.h @@ -9,6 +9,7 @@ #include "third-party/glad/include/glad/glad.h" #include "third-party/glfw/include/GLFW/glfw3.h" +#include "game/graphics/display.h" #include "game/graphics/gfx.h" enum GlfwKeyAction { @@ -17,4 +18,22 @@ enum GlfwKeyAction { Repeat = GLFW_REPEAT // repeated input on hold e.g. when typing something }; -extern const GfxRendererModule moduleOpenGL; +class GLDisplay : public GfxDisplay { + GLFWwindow* m_window; + + public: + GLDisplay(GLFWwindow* window, bool is_main); + virtual ~GLDisplay(); + + void* get_window() const { return m_window; } + void get_position(int* x, int* y); + void get_size(int* w, int* h); + void get_scale(float* x, float* y); + void get_screen_size(int vmode_idx, s32* w, s32* h, s32* c); + GfxDisplayMode get_fullscreen(); + void set_size(int w, int h); + void update_fullscreen(GfxDisplayMode mode, int screen); + void render(); +}; + +extern const GfxRendererModule gRendererOpenGL; diff --git a/game/kernel/kmachine.cpp b/game/kernel/kmachine.cpp index 6db2ae4b60..574c55709c 100644 --- a/game/kernel/kmachine.cpp +++ b/game/kernel/kmachine.cpp @@ -945,22 +945,22 @@ void prof_event(u32 name, u32 kind) { u32 get_fullscreen() { switch (Gfx::get_fullscreen()) { default: - case Gfx::DisplayMode::Windowed: + case GfxDisplayMode::Windowed: return intern_from_c("windowed").offset; - case Gfx::DisplayMode::Borderless: + case GfxDisplayMode::Borderless: return intern_from_c("borderless").offset; - case Gfx::DisplayMode::Fullscreen: + case GfxDisplayMode::Fullscreen: return intern_from_c("fullscreen").offset; } } void set_fullscreen(u32 symptr, s64 screen) { if (symptr == intern_from_c("windowed").offset || symptr == s7.offset) { - Gfx::set_fullscreen(Gfx::DisplayMode::Windowed, screen); + Gfx::set_fullscreen(GfxDisplayMode::Windowed, screen); } else if (symptr == intern_from_c("borderless").offset) { - Gfx::set_fullscreen(Gfx::DisplayMode::Borderless, screen); + Gfx::set_fullscreen(GfxDisplayMode::Borderless, screen); } else if (symptr == intern_from_c("fullscreen").offset) { - Gfx::set_fullscreen(Gfx::DisplayMode::Fullscreen, screen); + Gfx::set_fullscreen(GfxDisplayMode::Fullscreen, screen); } } diff --git a/goal_src/pc/pckernel-h.gc b/goal_src/pc/pckernel-h.gc index 97792713ba..94156970c5 100644 --- a/goal_src/pc/pckernel-h.gc +++ b/goal_src/pc/pckernel-h.gc @@ -31,7 +31,7 @@ (defglobalconstant PC_KERNEL_VERSION_BUILD #x0001) (defglobalconstant PC_KERNEL_VERSION_REVISION #x0005) -(defglobalconstant PC_KERNEL_VERSION_MINOR #x0003) +(defglobalconstant PC_KERNEL_VERSION_MINOR #x0004) (defglobalconstant PC_KERNEL_VERSION_MAJOR #x0001) (defglobalconstant PC_KERNEL_VERSION (logior (ash PC_KERNEL_VERSION_MAJOR 48) @@ -191,10 +191,18 @@ ;; "generic" graphics settings (target-fps int16) ;; the target framerate of the game - (width int32) ;; the width of the rendering, may not match window + ;; game resolution? + (width int32) (height int32) - (win-width int32) ;; the width of the display window + ;; window size. resolution = window size in windowed mode. + (win-width int32) (win-height int32) + ;; real window size from OS + (real-width int32) + (real-height int32) + ;; letterboxed window size + (lbox-width int32) + (lbox-height int32) (dpi-x float) ;; DPI width scale (dpi-y float) ;; DPI height scale (aspect-ratio-auto? symbol) ;; if on, aspect ratio is calculated automatically based on game display size. diff --git a/goal_src/pc/pckernel.gc b/goal_src/pc/pckernel.gc index f171f71853..7f159e0793 100644 --- a/goal_src/pc/pckernel.gc +++ b/goal_src/pc/pckernel.gc @@ -53,19 +53,23 @@ (defmethod set-display-mode! pc-settings ((obj pc-settings) (mode symbol)) "sets the game's display mode" - ;; changing to same mode, no-op - (if (= (pc-get-fullscreen) mode) - (return 0)) - - ;; else change it and update it + ;; change the display mode. (set! (-> obj display-mode) mode) - (pc-set-fullscreen mode 0) 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) - (pc-set-window-size width height) + (cond + ((= 'windowed (-> obj display-mode)) + (set! (-> obj win-width) width) + (set! (-> obj win-height) height) + ) + (else + (format 0 "Nope! No changing fullscreen resolution for now!") + (format #t "Nope! No changing fullscreen resolution for now!") + ) + ) (none)) @@ -100,9 +104,8 @@ "Update settings from the C kernel to GOAL." (set! (-> obj os) (pc-get-os)) - (pc-get-window-size (&-> obj win-width) (&-> obj win-height)) + (pc-get-window-size (&-> obj real-width) (&-> obj real-height)) (pc-get-window-scale (&-> obj dpi-x) (&-> obj dpi-y)) - (set! (-> obj display-mode) 'windowed) (when (-> obj use-vis?) (if (= (-> *setting-control* default aspect-ratio) 'aspect4x3) @@ -111,28 +114,28 @@ ) ) - (let ((win-aspect (/ (the float (-> obj win-width)) (the float (-> obj win-height))))) + (let ((win-aspect (/ (the float (-> obj real-width)) (the float (-> obj real-height))))) (cond ((and (not (-> obj use-vis?)) (-> obj aspect-ratio-auto?)) ;; the window determines the resolution (set-aspect-ratio! obj win-aspect) - (set! (-> obj width) (-> obj win-width)) - (set! (-> obj height) (-> obj win-height)) + (set! (-> obj lbox-width) (-> obj real-width)) + (set! (-> obj lbox-height) (-> obj real-height)) ) ((> win-aspect (-> obj aspect-ratio)) ;; too wide - (set! (-> obj width) (the int (* (the float (-> obj win-height)) (-> obj aspect-ratio)))) - (set! (-> obj height) (-> obj win-height)) + (set! (-> obj lbox-width) (the int (* (the float (-> obj real-height)) (-> obj aspect-ratio)))) + (set! (-> obj lbox-height) (-> obj real-height)) ) ((< win-aspect (-> obj aspect-ratio)) ;; too tall - (set! (-> obj width) (-> obj win-width)) - (set! (-> obj height) (the int (/ (the float (-> obj win-width)) (-> obj aspect-ratio)))) + (set! (-> obj lbox-width) (-> obj real-width)) + (set! (-> obj lbox-height) (the int (/ (the float (-> obj real-width)) (-> obj aspect-ratio)))) ) (else ;; just right - (set! (-> obj width) (-> obj win-width)) - (set! (-> obj height) (-> obj win-height)) + (set! (-> obj lbox-width) (-> obj real-width)) + (set! (-> obj lbox-height) (-> obj real-height)) ) ) ) @@ -145,14 +148,17 @@ (cond ((-> obj letterbox?) - ;; AGH bad idea, this is meant for resolution! TODO fix this crap - (pc-set-letterbox (-> obj width) (-> obj height)) + (pc-set-letterbox (-> obj lbox-width) (-> obj lbox-height)) ) (else - (pc-set-letterbox (-> obj win-width) (-> obj win-height)) + (pc-set-letterbox (-> obj real-width) (-> obj real-height)) ) ) + (pc-set-fullscreen (-> obj display-mode) 0) + (if (= 'windowed (-> obj display-mode)) + (pc-set-window-size (max 320 (-> obj win-width)) (max 240 (-> obj win-height)))) + (pc-discord-rpc-set (if (-> obj discord-rpc?) 1 0)) (when #t ;; (not (-> obj ps2-lod-dist?)) @@ -459,8 +465,8 @@ (clear *pc-temp-string*) (format *pc-temp-string* "game resolution: ~D x ~D~%" (-> obj width) (-> obj height)) - (format *pc-temp-string* "window size: ~D x ~D (~,,1f x ~,,1f)~%" (-> obj win-width) (-> obj win-height) (-> obj dpi-x) (-> obj dpi-y)) - (format *pc-temp-string* "target aspect: ~,,3f/~,,3f A: ~A/~A L: ~A~%" (-> obj aspect-ratio) (/ (the float (-> obj win-width)) (the float (-> obj win-height))) (-> obj aspect-ratio-auto?) (-> obj use-vis?) (-> obj letterbox?)) + (format *pc-temp-string* "window size: ~D x ~D (~,,1f x ~,,1f)~%" (-> obj real-width) (-> obj real-height) (-> obj dpi-x) (-> obj dpi-y)) + (format *pc-temp-string* "target aspect: ~,,3f/~,,3f A: ~A/~A L: ~A~%" (-> obj aspect-ratio) (/ (the float (-> obj real-width)) (the float (-> obj real-height))) (-> obj aspect-ratio-auto?) (-> obj use-vis?) (-> obj letterbox?)) (format *pc-temp-string* "display-type: ~A ~A~%" (-> obj display-mode) (-> obj vsync?)) (draw-string-xy *pc-temp-string* buf 0 (- 224 (* 8 4)) (font-color default) (font-flags shadow kerning)) @@ -679,10 +685,13 @@ (dosettings (file) (case-str *pc-temp-string* (("fps") (set! (-> obj target-fps) (file-stream-read-int file))) - (("size") + (("window-size") + (set! (-> obj win-width) (file-stream-read-int file)) + (set! (-> obj win-height) (file-stream-read-int file)) + ) + (("game-size") (set! (-> obj width) (file-stream-read-int file)) (set! (-> obj height) (file-stream-read-int file)) - (set-size! obj (-> obj width) (-> obj height)) ) (("aspect") (set-aspect! obj (file-stream-read-int file) (file-stream-read-int file))) (("aspect-test") @@ -801,7 +810,8 @@ (format file "(settings #x~X~%" (-> obj version)) (format file " (fps ~D)~%" (-> obj target-fps)) - (format file " (size ~D ~D)~%" (-> obj win-width) (-> obj win-height)) + (format file " (game-size ~D ~D)~%" (-> obj width) (-> obj height)) + (format file " (window-size ~D ~D)~%" (-> obj win-width) (-> obj win-height)) (format file " (aspect ~D ~D)~%" (-> obj width) (-> obj height)) (format file " (aspect-test ~D ~D)~%" (-> obj aspect-custom-x) (-> obj aspect-custom-y)) (format file " (aspect-auto ~A)~%" (-> obj aspect-ratio-auto?))