From be9093655d6f520b63efbe4d18e1bd1d921055d8 Mon Sep 17 00:00:00 2001 From: Aditya Gupta Date: Sun, 24 May 2026 11:00:21 +0530 Subject: [PATCH] feat: Add render mode options for image display in gsplash --- Makefile | 2 +- README.md | 18 ++++++++-- src/gsplash.c | 99 +++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 106 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 9e84cb2..f1719fb 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ SDL_CFLAGS := $(shell $(PKG_CONFIG) --cflags sdl2 SDL2_image) SDL_LIBS := $(shell $(PKG_CONFIG) --libs sdl2 SDL2_image) ALL_CFLAGS := $(CFLAGS) $(SDL_CFLAGS) -ALL_LIBS := $(LIBS) $(SDL_LIBS) +ALL_LIBS := $(LIBS) $(SDL_LIBS) -lm TARGET = gsplash SRC = src/gsplash.c diff --git a/README.md b/README.md index c9ca8cd..7f05a83 100644 --- a/README.md +++ b/README.md @@ -49,11 +49,25 @@ make check ## Usage ```bash -./gsplash [game_arguments...] +gsplash [game_arguments...] ``` Example: ```bash -./gsplash assets/splash.jpg /path/to/game --fullscreen --profile=default +gsplash assets/splash.jpg /path/to/game --fullscreen --profile=default ``` + +Gsplash allows you to configure how the image is displayed with 3 modes: + +- `center` (default): letterbox +- `crop`: fill screen by cropping +- `stretch`: Distort to fill screen + +You can set these by using the `-m` or `--mode` flag: + +```bash +gsplash [--mode=stretch|center|crop] [args...] + +gsplash -m stretch|center|crop [args...] +``` \ No newline at end of file diff --git a/src/gsplash.c b/src/gsplash.c index 2263c92..dbb9f31 100644 --- a/src/gsplash.c +++ b/src/gsplash.c @@ -7,6 +7,7 @@ #include #include #include +#include static void log_info(const char *fmt, ...) { @@ -30,15 +31,53 @@ static void log_error(const char *fmt, ...) fflush(stderr); } +typedef enum RenderMode +{ + RENDER_STRETCH = 0, + RENDER_CENTER, + RENDER_CROP +} RenderMode; + +static RenderMode parse_render_mode(const char *value) +{ + if (strcmp(value, "center") == 0) + { + return RENDER_CENTER; + } + if (strcmp(value, "crop") == 0) + { + return RENDER_CROP; + } + return RENDER_STRETCH; +} + int main(int argc, char *argv[]) { - if (argc < 3) + RenderMode render_mode = RENDER_CENTER; + int arg_index = 1; + + if (argc >= 3 && strncmp(argv[1], "--mode=", 7) == 0) { - log_error("Usage: %s [args...]", argv[0]); + render_mode = parse_render_mode(argv[1] + 7); + arg_index += 1; + } + else if (argc >= 4 && strcmp(argv[1], "-m") == 0) + { + render_mode = parse_render_mode(argv[2]); + arg_index += 2; + } + + if (argc - arg_index < 2) + { + log_error("Usage: %s [--mode=stretch|center|crop] [args...]", argv[0]); + log_error(" %s -m stretch|center|crop [args...]", argv[0]); return 1; } - log_info("Starting splash: image='%s', game='%s'", argv[1], argv[2]); + const char *image_path = argv[arg_index]; + const char *game_path = argv[arg_index + 1]; + + log_info("Starting splash: image='%s', game='%s'", image_path, game_path); // Initialize SDL2 Video subsystems if (SDL_Init(SDL_INIT_VIDEO) < 0) @@ -81,11 +120,11 @@ int main(int argc, char *argv[]) { log_info("Renderer created (accelerated)"); } - SDL_Texture *texture = IMG_LoadTexture(renderer, argv[1]); + SDL_Texture *texture = IMG_LoadTexture(renderer, image_path); if (!texture) { - log_error("Failed to load splash image '%s': %s; showing black screen", argv[1], IMG_GetError()); + log_error("Failed to load splash image '%s': %s; showing black screen", image_path, IMG_GetError()); // Fallback: Clear to solid black if image file is broken SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); @@ -95,8 +134,48 @@ int main(int argc, char *argv[]) { log_info("Splash image loaded"); SDL_RenderClear(renderer); - // Automatically scales your image to perfectly match the monitor aspect ratio - SDL_RenderCopy(renderer, texture, NULL, NULL); + + SDL_Rect dst_rect = {0, 0, 0, 0}; + int tex_w = 0; + int tex_h = 0; + int out_w = 0; + int out_h = 0; + + if (SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h) == 0 && + SDL_GetRendererOutputSize(renderer, &out_w, &out_h) == 0 && + tex_w > 0 && tex_h > 0 && out_w > 0 && out_h > 0) + { + if (render_mode == RENDER_CENTER) + { + float scale = fminf((float)out_w / (float)tex_w, (float)out_h / (float)tex_h); + dst_rect.w = (int)(tex_w * scale); + dst_rect.h = (int)(tex_h * scale); + dst_rect.x = (out_w - dst_rect.w) / 2; + dst_rect.y = (out_h - dst_rect.h) / 2; + } + else if (render_mode == RENDER_CROP) + { + float scale = fmaxf((float)out_w / (float)tex_w, (float)out_h / (float)tex_h); + dst_rect.w = (int)(tex_w * scale); + dst_rect.h = (int)(tex_h * scale); + dst_rect.x = (out_w - dst_rect.w) / 2; + dst_rect.y = (out_h - dst_rect.h) / 2; + } + else + { + dst_rect.w = out_w; + dst_rect.h = out_h; + } + } + + if (dst_rect.w > 0 && dst_rect.h > 0) + { + SDL_RenderCopy(renderer, texture, NULL, &dst_rect); + } + else + { + SDL_RenderCopy(renderer, texture, NULL, NULL); + } SDL_RenderPresent(renderer); } @@ -106,9 +185,9 @@ int main(int argc, char *argv[]) if (pid == 0) { // Inside Child Process: Hand over execution directly to the game binary - log_info("Execing game: %s", argv[2]); - execvp(argv[2], &argv[2]); - log_error("Failed to launch target game executable '%s': %s", argv[2], strerror(errno)); + log_info("Execing game: %s", game_path); + execvp(game_path, &argv[arg_index + 1]); + log_error("Failed to launch target game executable '%s': %s", game_path, strerror(errno)); _exit(1); } else if (pid < 0)