From 5a5916fbd5c73f0fe2ab696e8f326c233f2daa14 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 8 Jan 2022 10:45:03 +0900 Subject: [PATCH] Make the window resizable We don't use SDL's rendering functions, so we have to scale the screen and translate the mouse positions ourselves. --- include/gfx/gfx.h | 4 ++-- include/gfx/private.h | 2 +- src/input.c | 14 ++++++++++-- src/video.c | 52 ++++++++++++++++++++++++++++++------------- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index 88b848e..14569e3 100644 --- a/include/gfx/gfx.h +++ b/include/gfx/gfx.h @@ -67,8 +67,8 @@ int gfx_init(void); void gfx_fini(void); Texture *gfx_main_surface(void); -void gfx_set_window_size(int w, int h); -void gfx_fullscreen(bool on); +void gfx_set_window_logical_size(int w, int h); +void gfx_update_screen_scale(void); void gfx_set_wait_vsync(bool wait); void gfx_load_shader(struct shader *dst, const char *vertex_shader_path, const char *fragment_shader_path); diff --git a/include/gfx/private.h b/include/gfx/private.h index 1c34f58..89dedb5 100644 --- a/include/gfx/private.h +++ b/include/gfx/private.h @@ -34,8 +34,8 @@ struct sdl_private { GLuint ibo; } gl; int w, h; + SDL_Rect viewport; bool ms_active; /* mouse is active */ - bool fs_on; }; extern struct sdl_private sdl; diff --git a/src/input.c b/src/input.c index fe8910d..ee2aebf 100644 --- a/src/input.c +++ b/src/input.c @@ -17,6 +17,7 @@ #include #include #include "system4.h" +#include "gfx/gfx.h" #include "gfx/private.h" #include "input.h" #include "scene.h" @@ -207,13 +208,18 @@ void joy_clear_flag(void) void mouse_get_pos(int *x, int *y) { + int wx, wy; SDL_PumpEvents(); - SDL_GetMouseState(x, y); + SDL_GetMouseState(&wx, &wy); + *x = (wx - sdl.viewport.x) * sdl.w / sdl.viewport.w; + *y = (wy - sdl.viewport.y) * sdl.h / sdl.viewport.h; } void mouse_set_pos(int x, int y) { - SDL_WarpMouseInWindow(sdl.window, x, y); + int wx = x * sdl.viewport.w / sdl.w + sdl.viewport.x; + int wy = y * sdl.viewport.h / sdl.h + sdl.viewport.y; + SDL_WarpMouseInWindow(sdl.window, wx, wy); } static int wheel_dir = 0; @@ -301,6 +307,10 @@ void handle_events(void) case SDL_WINDOWEVENT_FOCUS_LOST: keyboard_focus = false; break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + gfx_update_screen_scale(); + scene_flip(); + break; } break; case SDL_KEYDOWN: diff --git a/src/video.c b/src/video.c index 7ec9f9a..78a612b 100644 --- a/src/video.c +++ b/src/video.c @@ -203,7 +203,7 @@ int gfx_init(void) SDL_WINDOWPOS_UNDEFINED, config.view_width, config.view_height, - SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); + SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (!sdl.window) ERROR("SDL_CreateWindow failed: %s", SDL_GetError()); @@ -223,7 +223,7 @@ int gfx_init(void) SDL_GL_SetSwapInterval(0); gl_initialize(); gfx_draw_init(); - gfx_set_window_size(config.view_width, config.view_height); + gfx_set_window_logical_size(config.view_width, config.view_height); atexit(gfx_fini); gfx_clear(); return 0; @@ -242,17 +242,6 @@ Texture *gfx_main_surface(void) return &main_surface; } -void gfx_fullscreen(bool on) -{ - if (on && !sdl.fs_on) { - sdl.fs_on = true; - SDL_SetWindowFullscreen(sdl.window, SDL_WINDOW_FULLSCREEN_DESKTOP); - } else if (!on && sdl.fs_on) { - sdl.fs_on = false; - SDL_SetWindowFullscreen(sdl.window, 0); - } -} - static void main_surface_init(int w, int h) { gfx_delete_texture(&main_surface); @@ -275,16 +264,47 @@ static void main_surface_init(int w, int h) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, main_surface.handle, 0); } -void gfx_set_window_size(int w, int h) +void gfx_set_window_logical_size(int w, int h) { sdl.w = w; sdl.h = h; world_view_transform[0][0] = 2.0 / w; world_view_transform[1][1] = 2.0 / h; - SDL_SetWindowSize(sdl.window, w, h); + gfx_update_screen_scale(); main_surface_init(w, h); } +void gfx_update_screen_scale(void) +{ + int display_w, display_h; + SDL_GL_GetDrawableSize(sdl.window, &display_w, &display_h); + + if (display_w * sdl.h == display_h * sdl.w) { + // The aspect ratios are the same, just scale appropriately. + sdl.viewport.x = 0; + sdl.viewport.y = 0; + sdl.viewport.w = display_w; + sdl.viewport.h = display_h; + return; + } + + double logical_aspect = (double)sdl.w / sdl.h; + double display_aspect = (double)display_w / display_h; + if (logical_aspect > display_aspect) { + // letterbox + sdl.viewport.w = display_w; + sdl.viewport.h = sdl.h * display_w / sdl.w; + sdl.viewport.x = 0; + sdl.viewport.y = (display_h - sdl.viewport.h) / 2; + } else { + // pillarbox (side bars) + sdl.viewport.w = sdl.w * display_h / sdl.h; + sdl.viewport.h = display_h; + sdl.viewport.x = (display_w - sdl.viewport.w) / 2; + sdl.viewport.y = 0; + } +} + void gfx_set_wait_vsync(bool wait) { SDL_GL_SetSwapInterval(wait); @@ -307,6 +327,7 @@ void gfx_clear(void) void gfx_swap(void) { glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(sdl.viewport.x, sdl.viewport.y, sdl.viewport.w, sdl.viewport.h); glClear(GL_COLOR_BUFFER_BIT); static mat4 mw_transform = GLM_MAT4_IDENTITY_INIT; @@ -326,6 +347,7 @@ void gfx_swap(void) SDL_GL_SwapWindow(sdl.window); glBindFramebuffer(GL_FRAMEBUFFER, main_surface_fb); + glViewport(0, 0, sdl.w, sdl.h); } /*