From b1b35966486b91f82726cbf9c7e6ccc3357851f4 Mon Sep 17 00:00:00 2001 From: anth64 Date: Wed, 22 Apr 2026 22:02:06 +0200 Subject: [PATCH] feat: add borderless fullscreen option --- include/client/video.h | 7 +++ src/platform/client/video/gl.c | 52 ++++++++++++++++++---- src/platform/client/video/sdl.c | 79 ++++++++++++++++++++++----------- 3 files changed, 104 insertions(+), 34 deletions(-) diff --git a/include/client/video.h b/include/client/video.h index 7893443..6c02c6e 100644 --- a/include/client/video.h +++ b/include/client/video.h @@ -11,10 +11,16 @@ extern "C" { #define SKELE_VIDEO_BORDERLESS 0x02 #define SKELE_VIDEO_RESIZABLE 0x04 #define SKELE_VIDEO_HIGHDPI 0x08 +#define SKELE_VIDEO_FULLSCREEN_EXCLUSIVE 0x10 #define SKELE_DEFAULT_RENDER_WIDTH 320 #define SKELE_DEFAULT_RENDER_HEIGHT 200 +typedef enum { + SKELE_FULLSCREEN_BORDERLESS, + SKELE_FULLSCREEN_EXCLUSIVE +} skele_fullscreen_kind_t; + typedef struct { uint16_t render_width; uint16_t render_height; @@ -28,6 +34,7 @@ void skele_video_shutdown(void); void skele_video_present(void); void skele_video_set_title(const char *title); void skele_video_toggle_fullscreen(void); +void skele_video_set_fullscreen_kind(skele_fullscreen_kind_t kind); void skele_video_cycle_scale(void); void skele_video_set_mouse_grab(uint8_t grab); diff --git a/src/platform/client/video/gl.c b/src/platform/client/video/gl.c index bd53ce6..edb9404 100644 --- a/src/platform/client/video/gl.c +++ b/src/platform/client/video/gl.c @@ -8,7 +8,9 @@ static SDL_GLContext gl_ctx = NULL; static uint16_t vid_w = 0; static uint16_t vid_h = 0; static uint8_t cur_scale = 1; -static uint8_t fullscreen = 0; +static uint8_t is_fullscreen = 0; +static skele_fullscreen_kind_t last_fullscreen_kind = + SKELE_FULLSCREEN_EXCLUSIVE; static uint8_t max_scale(uint16_t rw, uint16_t rh) { @@ -42,16 +44,23 @@ static void set_scale(uint8_t scale) SDL_WINDOWPOS_CENTERED_DISPLAY(display)); } -static void toggle_fullscreen(void) +static void apply_fullscreen_kind(skele_fullscreen_kind_t kind) { - fullscreen = !fullscreen; - SDL_SetWindowFullscreen(window, fullscreen); + if (kind == SKELE_FULLSCREEN_EXCLUSIVE) { + SDL_DisplayID display; + const SDL_DisplayMode *mode; + display = SDL_GetDisplayForWindow(window); + mode = SDL_GetCurrentDisplayMode(display); + SDL_SetWindowFullscreenMode(window, mode); + } else { + SDL_SetWindowFullscreenMode(window, NULL); + } } static void cycle_scale(void) { uint8_t next; - if (fullscreen) + if (is_fullscreen) return; next = cur_scale + 1; if (next > max_scale(vid_w, vid_h)) @@ -88,6 +97,11 @@ uint8_t skele_video_init(skele_video_config_t cfg) if (cfg.flags & SKELE_VIDEO_HIGHDPI) flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY; + if (cfg.flags & SKELE_VIDEO_FULLSCREEN_EXCLUSIVE) + last_fullscreen_kind = SKELE_FULLSCREEN_EXCLUSIVE; + else + last_fullscreen_kind = SKELE_FULLSCREEN_BORDERLESS; + display = SDL_GetPrimaryDisplay(); vid_w = cfg.render_width ? cfg.render_width : SKELE_DEFAULT_RENDER_WIDTH; @@ -131,8 +145,10 @@ uint8_t skele_video_init(skele_video_config_t cfg) SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display)); - if (cfg.flags & SKELE_VIDEO_FULLSCREEN) - fullscreen = 1; + if (cfg.flags & SKELE_VIDEO_FULLSCREEN) { + apply_fullscreen_kind(last_fullscreen_kind); + is_fullscreen = 1; + } gl_ctx = SDL_GL_CreateContext(window); if (!gl_ctx) { @@ -160,13 +176,31 @@ void skele_video_shutdown(void) vid_w = 0; vid_h = 0; cur_scale = 1; - fullscreen = 0; + is_fullscreen = 0; } void skele_video_present(void) { SDL_GL_SwapWindow(window); } -void skele_video_toggle_fullscreen(void) { toggle_fullscreen(); } void skele_video_cycle_scale(void) { cycle_scale(); } +void skele_video_toggle_fullscreen(void) +{ + if (is_fullscreen) { + SDL_SetWindowFullscreen(window, false); + is_fullscreen = 0; + } else { + apply_fullscreen_kind(last_fullscreen_kind); + SDL_SetWindowFullscreen(window, true); + is_fullscreen = 1; + } +} + +void skele_video_set_fullscreen_kind(skele_fullscreen_kind_t kind) +{ + last_fullscreen_kind = kind; + if (is_fullscreen) + apply_fullscreen_kind(kind); +} + void skele_video_set_mouse_grab(uint8_t grab) { SDL_SetWindowMouseGrab(window, grab ? true : false); diff --git a/src/platform/client/video/sdl.c b/src/platform/client/video/sdl.c index 3682aae..af1be49 100644 --- a/src/platform/client/video/sdl.c +++ b/src/platform/client/video/sdl.c @@ -17,7 +17,9 @@ static uint16_t vid_w = 0; static uint16_t vid_h = 0; static uint32_t vid_total = 0; static uint8_t cur_scale = 1; -static uint8_t fullscreen = 0; +static uint8_t is_fullscreen = 0; +static skele_fullscreen_kind_t last_fullscreen_kind = + SKELE_FULLSCREEN_EXCLUSIVE; static uint8_t max_scale(uint16_t rw, uint16_t rh) { @@ -51,16 +53,23 @@ static void set_scale(uint8_t scale) SDL_WINDOWPOS_CENTERED_DISPLAY(display)); } -static void toggle_fullscreen(void) +static void apply_fullscreen_kind(skele_fullscreen_kind_t kind) { - fullscreen = !fullscreen; - SDL_SetWindowFullscreen(window, fullscreen); + if (kind == SKELE_FULLSCREEN_EXCLUSIVE) { + SDL_DisplayID display; + const SDL_DisplayMode *mode; + display = SDL_GetDisplayForWindow(window); + mode = SDL_GetCurrentDisplayMode(display); + SDL_SetWindowFullscreenMode(window, mode); + } else { + SDL_SetWindowFullscreenMode(window, NULL); + } } static void cycle_scale(void) { uint8_t next; - if (fullscreen) + if (is_fullscreen) return; next = cur_scale + 1; if (next > max_scale(vid_w, vid_h)) @@ -74,7 +83,6 @@ uint8_t skele_video_init(skele_video_config_t cfg) SDL_WindowFlags flags = 0; const SDL_DisplayMode *mode; uint16_t window_w, window_h, aw, ah; - uint16_t i; if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { stk_log(STK_LOG_ERROR, "video: SDL_Init failed: %s", @@ -91,6 +99,11 @@ uint8_t skele_video_init(skele_video_config_t cfg) if (cfg.flags & SKELE_VIDEO_HIGHDPI) flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY; + if (cfg.flags & SKELE_VIDEO_FULLSCREEN_EXCLUSIVE) + last_fullscreen_kind = SKELE_FULLSCREEN_EXCLUSIVE; + else + last_fullscreen_kind = SKELE_FULLSCREEN_BORDERLESS; + display = SDL_GetPrimaryDisplay(); vid_w = cfg.render_width ? cfg.render_width : SKELE_DEFAULT_RENDER_WIDTH; @@ -123,11 +136,6 @@ uint8_t skele_video_init(skele_video_config_t cfg) window_h = vid_h * cur_scale; } - /* default palette: all black */ - memset(palette, 0, sizeof(palette)); - for (i = 0; i < SKELE_PALETTE_COLORS; i++) - palette[i] = 0xFF000000; - rgba_buf = malloc(vid_total * sizeof(uint32_t)); if (!rgba_buf) { stk_log(STK_LOG_ERROR, "video: out of memory"); @@ -150,8 +158,10 @@ uint8_t skele_video_init(skele_video_config_t cfg) SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display)); - if (cfg.flags & SKELE_VIDEO_FULLSCREEN) - fullscreen = 1; + if (cfg.flags & SKELE_VIDEO_FULLSCREEN) { + apply_fullscreen_kind(last_fullscreen_kind); + is_fullscreen = 1; + } renderer = SDL_CreateRenderer(window, NULL); if (!renderer) { @@ -179,6 +189,7 @@ uint8_t skele_video_init(skele_video_config_t cfg) SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST); SDL_SetRenderVSync(renderer, 1); + memset(palette, 0, sizeof(palette)); SDL_ShowWindow(window); return SKELE_INIT_SUCCESS; } @@ -206,13 +217,41 @@ void skele_video_shutdown(void) vid_h = 0; vid_total = 0; cur_scale = 1; - fullscreen = 0; + is_fullscreen = 0; +} + +void skele_video_blit(uint8_t *pixels) +{ + uint32_t i; + for (i = 0; i < vid_total; i++) + rgba_buf[i] = palette[pixels[i]]; + SDL_UpdateTexture(texture, NULL, rgba_buf, + vid_w * (int)sizeof(uint32_t)); + SDL_RenderTexture(renderer, texture, NULL, NULL); } void skele_video_present(void) { SDL_RenderPresent(renderer); } -void skele_video_toggle_fullscreen(void) { toggle_fullscreen(); } void skele_video_cycle_scale(void) { cycle_scale(); } +void skele_video_toggle_fullscreen(void) +{ + if (is_fullscreen) { + SDL_SetWindowFullscreen(window, false); + is_fullscreen = 0; + } else { + apply_fullscreen_kind(last_fullscreen_kind); + SDL_SetWindowFullscreen(window, true); + is_fullscreen = 1; + } +} + +void skele_video_set_fullscreen_kind(skele_fullscreen_kind_t kind) +{ + last_fullscreen_kind = kind; + if (is_fullscreen) + apply_fullscreen_kind(kind); +} + void skele_video_set_mouse_grab(uint8_t grab) { SDL_SetWindowMouseGrab(window, grab ? true : false); @@ -235,13 +274,3 @@ void skele_palette_set_index(uint8_t index, uint32_t color) { palette[index] = color | 0xFF000000; } - -void skele_video_blit(uint8_t *pixels) -{ - uint32_t i; - for (i = 0; i < vid_total; i++) - rgba_buf[i] = palette[pixels[i]]; - SDL_UpdateTexture(texture, NULL, rgba_buf, - vid_w * (int)sizeof(uint32_t)); - SDL_RenderTexture(renderer, texture, NULL, NULL); -}