From 8a2167920e2d2d1bdf8805c3547529a24e83604e Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 4 Sep 2022 23:59:00 +0200 Subject: [PATCH] Add support for fullscreen + never grab mouse + resize window (#140) * Implement full-screen via ALT+ENTER * Never grab mouse * Allow resizable window + fix mouse when resizing/switching to full screen * Keep aspect ratio of gl viewport when resizing window * Fix mouse when resizing the window * Fix off by one error --- src/harness/io_platforms/sdl_gl.c | 64 +++++++++++++++++++++--- src/harness/renderers/gl/gl_renderer.c | 68 ++++++++++++++++++++------ src/harness/renderers/gl/gl_renderer.h | 4 ++ src/harness/renderers/null.h | 12 ++++- src/harness/renderers/renderer.h | 7 ++- 5 files changed, 130 insertions(+), 25 deletions(-) diff --git a/src/harness/io_platforms/sdl_gl.c b/src/harness/io_platforms/sdl_gl.c index 192ec931..e65eacd3 100644 --- a/src/harness/io_platforms/sdl_gl.c +++ b/src/harness/io_platforms/sdl_gl.c @@ -129,6 +129,7 @@ struct { float x; float y; } sdl_window_scale; +int is_full_screen = 0; tRenderer gl_renderer = { GLRenderer_Init, @@ -141,7 +142,11 @@ tRenderer gl_renderer = { GLRenderer_BufferTexture, GLRenderer_BufferMaterial, GLRenderer_BufferModel, - GLRenderer_FlushBuffers + GLRenderer_FlushBuffers, + GLRenderer_GetRenderSize, + GLRenderer_GetWindowSize, + GLRenderer_SetWindowSize, + GLRenderer_GetViewport }; tRenderer* Window_Create(char* title, int width, int height, int pRender_width, int pRender_height) { @@ -161,17 +166,12 @@ tRenderer* Window_Create(char* title, int width, int height, int pRender_width, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, - SDL_WINDOW_OPENGL); + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (window == NULL) { LOG_PANIC("Failed to create window"); } - // Don't grab the mouse when a debugger is present - if (!OS_IsDebuggerPresent()) { - SDL_SetRelativeMouseMode(SDL_TRUE); - } - sdl_window_scale.x = ((float)pRender_width) / width; sdl_window_scale.y = ((float)pRender_height) / height; @@ -192,14 +192,37 @@ tRenderer* Window_Create(char* title, int width, int height, int pRender_width, return &gl_renderer; } +// Checks whether the `flag_check` is the only modifier applied. +// e.g. is_only_modifier(event.key.keysym.mod, KMOD_ALT) returns true when only the ALT key was pressed +static int is_only_key_modifier(int modifier_flags, int flag_check) { + return (modifier_flags & flag_check) && (modifier_flags & (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_GUI)) == (modifier_flags & flag_check); +} + void Window_PollEvents() { SDL_Event event; int dethrace_key; + int w_w, w_h; + int vp_x, vp_y; + int vp_w, vp_h; + int r_w, r_h; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: case SDL_KEYUP: + if (event.key.keysym.sym == SDLK_RETURN) { + if (event.key.type == SDL_KEYDOWN) { + if ((event.key.keysym.mod & (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_GUI))) { + // Ignore keydown of RETURN when used together with some modifier + return; + } + } else if (event.key.type == SDL_KEYUP) { + if (is_only_key_modifier(event.key.keysym.mod, KMOD_ALT)) { + is_full_screen = !is_full_screen; + SDL_SetWindowFullscreen(window, is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + } + } + } dethrace_key = scancodes_sdl2dethrace[event.key.keysym.scancode]; if (dethrace_key == -1) { LOG_WARN("unexpected scan code %s (%d)", SDL_GetScancodeName(event.key.keysym.scancode), event.key.keysym.scancode); @@ -213,6 +236,18 @@ void Window_PollEvents() { sdl_key_state[3] = sdl_key_state[2]; break; + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_SIZE_CHANGED: + SDL_GetWindowSize(window, &w_w, &w_h); + gl_renderer.SetWindowSize(w_w, w_h); + gl_renderer.GetViewport(&vp_x, &vp_y, &vp_w, &vp_h); + gl_renderer.GetRenderSize(&r_w, &r_h); + sdl_window_scale.x = (float)r_w / vp_w; + sdl_window_scale.y = (float)r_h / vp_h; + break; + } + break; case SDL_QUIT: LOG_PANIC("QuitGame"); break; @@ -251,7 +286,22 @@ int Input_IsKeyDown(unsigned char scan_code) { } void Input_GetMousePosition(int* pX, int* pY) { + int vp_x, vp_y, vp_w, vp_h; + SDL_GetMouseState(pX, pY); + gl_renderer.GetViewport(&vp_x, &vp_y, &vp_w, &vp_h); + if (*pX < vp_x) { + *pX = vp_x; + } else if (*pX >= vp_x + vp_w) { + *pX = vp_x + vp_w - 1; + } + if (*pY < vp_y) { + *pY = vp_y; + } else if (*pY >= vp_y + vp_h) { + *pY = vp_y + vp_h - 1; + } + *pX -= vp_x; + *pY -= vp_y; *pX *= sdl_window_scale.x; *pY *= sdl_window_scale.y; } diff --git a/src/harness/renderers/gl/gl_renderer.c b/src/harness/renderers/gl/gl_renderer.c index 773a820d..19afe4ee 100644 --- a/src/harness/renderers/gl/gl_renderer.c +++ b/src/harness/renderers/gl/gl_renderer.c @@ -12,21 +12,21 @@ extern float gCamera_hither; extern float gCamera_yon; -GLuint screen_buffer_vao, screen_buffer_ebo; -GLuint screen_texture, palette_texture, depth_texture; +static GLuint screen_buffer_vao, screen_buffer_ebo; +static GLuint screen_texture, palette_texture, depth_texture; -GLuint shader_program_2d; -GLuint shader_program_3d; -GLuint framebuffer_id, framebuffer_texture = 0; -unsigned int rbo; -uint8_t gl_palette[4 * 256]; // RGBA -uint8_t* screen_buffer_flip_pixels; -uint16_t* depth_buffer_flip_pixels; +static GLuint shader_program_2d; +static GLuint shader_program_3d; +static GLuint framebuffer_id, framebuffer_texture = 0; +static uint8_t gl_palette[4 * 256]; // RGBA +static uint8_t* screen_buffer_flip_pixels; +static uint16_t* depth_buffer_flip_pixels; -int window_width, window_height, render_width, render_height; +static int window_width, window_height, render_width, render_height; +static int vp_x, vp_y, vp_width, vp_height; -br_pixelmap* last_shade_table = NULL; -int dirty_buffers = 0; +static br_pixelmap* last_shade_table = NULL; +static int dirty_buffers = 0; struct { GLuint pixels, pixels_transform; @@ -177,12 +177,29 @@ void SetupFullScreenRectGeometry() { glBindVertexArray(0); } -void GLRenderer_Init(int width, int height, int pRender_width, int pRender_height) { +static void update_viewport() { + const float target_aspect_ratio = (float)render_width / render_height; + const float aspect_ratio = (float)window_width / window_height; + vp_width = window_width; + vp_height = window_height; + if (aspect_ratio != target_aspect_ratio) { + if (aspect_ratio > target_aspect_ratio) { + vp_width = window_height * target_aspect_ratio + .5f; + } else { + vp_height = window_width / target_aspect_ratio + .5f; + } + } + vp_x = (window_width - vp_width) / 2; + vp_y = (window_height - vp_height) / 2; +} + +void GLRenderer_Init(int width, int height, int pRender_width, int pRender_height) { window_width = width; window_height = height; render_width = pRender_width; render_height = pRender_height; + update_viewport(); int maxTextureImageUnits; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits); @@ -339,7 +356,7 @@ void GLRenderer_EndScene() { } void GLRenderer_FullScreenQuad(uint8_t* screen_buffer, int width, int height) { - glViewport(0, 0, window_width, window_height); + glViewport(vp_x, vp_y, vp_width, vp_height); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_DEPTH_TEST); @@ -637,3 +654,26 @@ void GLRenderer_FlushBuffers(br_pixelmap* color_buffer, br_pixelmap* depth_buffe glClear(GL_COLOR_BUFFER_BIT); dirty_buffers = 0; } + +void GLRenderer_GetRenderSize(int* width, int* height) { + *width = render_width; + *height = render_height; +} + +void GLRenderer_GetWindowSize(int* width, int* height) { + *width = window_width; + *height = window_height; +} + +void GLRenderer_SetWindowSize(int width, int height) { + window_width = width; + window_height = height; + update_viewport(); +} + +void GLRenderer_GetViewport(int* x, int* y, int* width, int* height) { + *x = vp_x; + *y = vp_y; + *width = vp_width; + *height = vp_height; +} diff --git a/src/harness/renderers/gl/gl_renderer.h b/src/harness/renderers/gl/gl_renderer.h index cb85841b..2b8f2904 100644 --- a/src/harness/renderers/gl/gl_renderer.h +++ b/src/harness/renderers/gl/gl_renderer.h @@ -44,5 +44,9 @@ void GLRenderer_BufferMaterial(br_material* mat); void GLRenderer_BufferModel(br_model* model); void GLRenderer_ClearBuffers(); void GLRenderer_FlushBuffers(br_pixelmap* color_buffer, br_pixelmap* depth_buffer); +void GLRenderer_GetRenderSize(int* width, int* height); +void GLRenderer_GetWindowSize(int* width, int* height); +void GLRenderer_SetWindowSize(int width, int height); +void GLRenderer_GetViewport(int* x, int* y, int* width, int* height); #endif diff --git a/src/harness/renderers/null.h b/src/harness/renderers/null.h index d8f8a641..9e1b5c80 100644 --- a/src/harness/renderers/null.h +++ b/src/harness/renderers/null.h @@ -12,6 +12,10 @@ void Null_BufferTexture(br_pixelmap* pm) {} void Null_BufferMaterial(br_material* mat) {} void Null_BufferModel(br_model* model) {} void Null_FlushBuffers(br_pixelmap* color_buffer, br_pixelmap* depth_buffer) {} +void Null_GetRenderSize(int* width, int* height) { *width = 640; *height = 480; } +void Null_GetWindowSize(int* width, int* height) { *width = 640; *height = 480; } +void Null_SetWindowSize(int width, int height) {} +void Null_GetViewportSize(int* x, int* y, int* width, int* height) { *x = 0; *y = 0; *width = 640; *height = 480; } tRenderer null_renderer = { Null_Init, @@ -24,5 +28,9 @@ tRenderer null_renderer = { Null_BufferTexture, Null_BufferMaterial, Null_BufferModel, - Null_FlushBuffers -}; \ No newline at end of file + Null_FlushBuffers, + Null_GetRenderSize, + Null_GetWindowSize, + Null_SetWindowSize, + Null_GetViewportSize +}; diff --git a/src/harness/renderers/renderer.h b/src/harness/renderers/renderer.h index bf89705e..67491080 100644 --- a/src/harness/renderers/renderer.h +++ b/src/harness/renderers/renderer.h @@ -15,7 +15,10 @@ typedef struct tRenderer { void (*BufferMaterial)(br_material* mat); void (*BufferModel)(br_model* model); void (*FlushBuffers)(br_pixelmap* color_buffer, br_pixelmap* depth_buffer); - + void (*GetRenderSize)(int* width, int* height); + void (*GetWindowSize)(int* width, int* height); + void (*SetWindowSize)(int width, int height); + void (*GetViewport)(int* x, int* y, int* width, int* height); } tRenderer; -#endif \ No newline at end of file +#endif