From a395470d88624f573ba6ced570834a951be2aedc Mon Sep 17 00:00:00 2001 From: Ano-sys Date: Sat, 15 Aug 2026 17:44:43 +0200 Subject: [PATCH] + image scaling on mouse scroll + window resize redraws surface + moved window loop into own function - removed on_wheel call to resize window for now -> hyprland is not handling this + image is not initially drawn onto displayed surface anymore, a subsurface is used (image_surface) to allow scaling on the real surface without redrawing the image in buffer. + renamed free_image to free_image_buffer to be more clear about the functionallity + renamed draw_image to create_image_surface + draw_image is a new function which draws the image_surface with linear scale onto the windows surface --- SimpleImageViewer.c | 164 ++++++++++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 51 deletions(-) diff --git a/SimpleImageViewer.c b/SimpleImageViewer.c index 1cc9762..3d0a072 100644 --- a/SimpleImageViewer.c +++ b/SimpleImageViewer.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -5,12 +7,13 @@ #include #include #include -#include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define DESIRED_IMAGE_CHANNELS 4 +#define MAX_IMAGE_SCALE 10 +#define MIN_IMAGE_SCALE 0.01 typedef struct Image{ int x; @@ -19,14 +22,20 @@ typedef struct Image{ unsigned char* pixels; } Image; +typedef struct{ + int w; + int h; +} window_size_delta; + Image load_image(const char* filepath){ Image image; image.pixels = stbi_load(filepath, &image.x, &image.y, &image.channels, DESIRED_IMAGE_CHANNELS); return image; } -void free_image(Image* image){ +void free_image_buffer(Image* image){ if(image->pixels) stbi_image_free(image->pixels); + image->pixels = NULL; } SDL_Window* create_window(const char* title, int w, int h){ @@ -57,18 +66,15 @@ SDL_Window* create_window(const char* title, int w, int h){ return window; } -SDL_Surface* get_surface_from_window(SDL_Window* window){ - return SDL_GetWindowSurface(window); -} - -void draw_image(SDL_Surface* surface, Image* image){ +SDL_Surface* create_image_surface(SDL_Surface* surface, Image* image){ + SDL_Surface* image_surface = SDL_CreateSurface(image->x, image->y, SDL_PIXELFORMAT_RGBA32); SDL_Rect pixel = { 0, 0, 1, 1 }; int center_x = ((surface->w + 1) / 2 - 1); int center_y = ((surface->h + 1) / 2 - 1); - int dst_x = center_x - image->x / 2; - int dst_y = center_y - image->y / 2; + int dst_x = (center_x - image->x / 2); + int dst_y = (center_y - image->y / 2); for(int x = 0; x < image->x; x++){ pixel.x = dst_x + x; @@ -76,15 +82,36 @@ void draw_image(SDL_Surface* surface, Image* image){ pixel.y = dst_y + y; const int current_pixel_idx = (y * image->x + x) * DESIRED_IMAGE_CHANNELS; - Uint32 color = SDL_MapSurfaceRGBA(surface, + Uint32 color = SDL_MapSurfaceRGBA(image_surface, image->pixels[current_pixel_idx + 0], image->pixels[current_pixel_idx + 1], image->pixels[current_pixel_idx + 2], image->pixels[current_pixel_idx + 3]); - SDL_FillSurfaceRect(surface, &pixel, color); + SDL_FillSurfaceRect(image_surface, &pixel, color); } } + + return image_surface; +} + +void draw_image(SDL_Window* window, SDL_Surface* image_surface, Image* image, float pixel_size_delta){ + SDL_Surface* surface = SDL_GetWindowSurface(window); + + float pixel_size = pixel_size_delta; + + int center_x = ((surface->w + 1) / 2 - 1); + int center_y = ((surface->h + 1) / 2 - 1); + + Uint64 start = SDL_GetTicksNS(); + + SDL_Rect dst = { center_x - (image->x * pixel_size / 2), center_y - (image->y * pixel_size / 2), image->x * pixel_size, image->y * pixel_size }; + SDL_ClearSurface(surface, 0, 0, 0, 255); + SDL_BlitSurfaceScaled(image_surface, NULL, surface, &dst, SDL_SCALEMODE_LINEAR); + + printf("Redraw time: %.3fms\n", (SDL_GetTicksNS() - start) / 1000000.0); + + SDL_UpdateWindowSurface(window); } int clamp(const int in, const int low, const int high){ @@ -95,11 +122,20 @@ int clamp_low(const int in, const int low){ return in < low ? low : in; } -void on_wheel(SDL_Event* event, SDL_Window* window) { +window_size_delta get_window_size_delta(SDL_Window* window, int new_w, int new_h){ int last_w, last_h; SDL_GetWindowSize(window, &last_w, &last_h); - int step = event->wheel.y * 25; + window_size_delta delta = {new_w - last_w, new_h - last_h}; + return delta; +} + +void on_wheel(SDL_Event* event, SDL_Window* window){ + int last_w, last_h; + SDL_GetWindowSize(window, &last_w, &last_h); + + int multiplier = 25; + int step = event->wheel.y * multiplier; int new_w = clamp_low(last_w + step, 50); int new_h = new_w * last_h / last_w; @@ -116,6 +152,61 @@ void on_wheel(SDL_Event* event, SDL_Window* window) { SDL_SetWindowSize(window, new_w, new_h); } +void loop(SDL_Window* window, SDL_Surface* image_surface, Image* image){ + bool drag_mouse = false; + int last_pointer_x = 0; + int last_pointer_y = 0; + + SDL_Event event; + bool run = true; + + float pixel_size_delta = 1.0f; + + bool redraw = false; + + while(run){ + if(!SDL_WaitEvent(&event)) continue; + + do{ + if (event.type == SDL_EVENT_KEY_UP){ + switch(event.key.key){ + case SDLK_ESCAPE: case SDLK_SPACE: case SDLK_RETURN: + run = false; + break; + } + } + if(event.type == SDL_EVENT_QUIT || event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) run = false; + if(event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT){ + drag_mouse = true; + last_pointer_x = (int)event.button.x; + last_pointer_y = (int)event.button.y; + } + if(event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) drag_mouse = false; + if(event.type == SDL_EVENT_MOUSE_MOTION && drag_mouse){ + int last_x, last_y; + SDL_GetWindowPosition(window, &last_x, &last_y); + SDL_SetWindowPosition(window, last_x + (int)event.motion.x - last_pointer_x, last_y + (int)event.motion.y - last_pointer_y); + } + if(event.type == SDL_EVENT_MOUSE_WHEEL){ + float last_pixel_size_delta = pixel_size_delta; + pixel_size_delta += event.wheel.y * 0.1f * pixel_size_delta; + if(pixel_size_delta < MIN_IMAGE_SCALE) pixel_size_delta = MIN_IMAGE_SCALE; + else if(pixel_size_delta > MAX_IMAGE_SCALE) pixel_size_delta = MAX_IMAGE_SCALE; + + if(last_pixel_size_delta != pixel_size_delta) redraw = true; + + // on_wheel(&event, window); + } + if(event.type == SDL_EVENT_WINDOW_RESIZED) redraw = true; + } while(SDL_PollEvent(&event)); + + if(redraw){ + redraw = false; + draw_image(window, image_surface, image, pixel_size_delta); + } + } +} + int main(int argc, char** argv){ if(argc < 2){ printf("Usage: %s [image filepath]\n", argv[0]); @@ -141,50 +232,21 @@ int main(int argc, char** argv){ exit(4); } - SDL_Surface* surface = get_surface_from_window(window); + SDL_Surface* surface = SDL_GetWindowSurface(window); if(!surface){ printf("Failed to get surface!"); exit(5); } - draw_image(surface, &image); - - free_image(&image); + SDL_Surface* image_surface = create_image_surface(surface, &image); + free_image_buffer(&image); + draw_image(window, image_surface, &image, 1.0f); + SDL_UpdateWindowSurface(window); - - bool drag_mouse = false; - int last_pointer_x = 0; - int last_pointer_y = 0; - - SDL_Event event; - bool run = true; - while(run){ - while (SDL_PollEvent(&event)) { - if (event.type == SDL_EVENT_KEY_UP){ - switch(event.key.key){ - case SDLK_ESCAPE: case SDLK_SPACE: case SDLK_RETURN: - run = false; - break; - } - } - if(event.type == SDL_EVENT_QUIT || event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) run = false; - if(event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT){ - drag_mouse = true; - last_pointer_x = (int)event.button.x; - last_pointer_y = (int)event.button.y; - } - if(event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) drag_mouse = false; - if(event.type == SDL_EVENT_MOUSE_MOTION && drag_mouse){ - int last_x, last_y; - SDL_GetWindowPosition(window, &last_x, &last_y); - SDL_SetWindowPosition(window, last_x + (int)event.button.x - last_pointer_x, last_y + (int)event.button.y - last_pointer_y); - } - if(event.type == SDL_EVENT_MOUSE_WHEEL){ - on_wheel(&event, window); - } - } - } - + + loop(window, image_surface, &image); + + SDL_DestroySurface(image_surface); SDL_DestroyWindow(window); } \ No newline at end of file