Compare commits
2 Commits
9986fafa80
...
a395470d88
| Author | SHA1 | Date | |
|---|---|---|---|
| a395470d88 | |||
| 176f33f6de |
@@ -15,12 +15,12 @@ Of course it is not without usage, I will prepare the app to be hooked in Hyprla
|
|||||||
#### macOS
|
#### macOS
|
||||||
- `brew install sdl3`
|
- `brew install sdl3`
|
||||||
- clone this repo and navigate into it
|
- clone this repo and navigate into it
|
||||||
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror -o3 $(pkg-config --cflags --libs sdl3)` or with `clang`
|
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror $(pkg-config --cflags --libs sdl3)` or with `clang`
|
||||||
- additional compiler arguments for ide: `-I/opt/homebrew/include -L/opt/homebrew/lib -Wl,-rpath,/opt/homebrew/lib -lSDL3 `
|
- additional compiler arguments for ide: `-I/opt/homebrew/include -L/opt/homebrew/lib -Wl,-rpath,/opt/homebrew/lib -lSDL3 `
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
- `sudo pacman -S sdl3 --noconfirm`
|
- `sudo pacman -S sdl3 --noconfirm`
|
||||||
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror -o3 $(pkg-config --cflags --libs sdl3) -lm` or with `clang`
|
- `gcc SimpleImageViewer.c -o SimpleImageViewer -Wall -Werror $(pkg-config --cflags --libs sdl3) -lm` or with `clang`
|
||||||
- when using Hyprland, move the scripts folder into your `~/.config/hypr/`
|
- when using Hyprland, move the scripts folder into your `~/.config/hypr/`
|
||||||
- in `simple-image-viewer-clipboard.sh`: set `viewer`, I placed my binary beside this script
|
- in `simple-image-viewer-clipboard.sh`: set `viewer`, I placed my binary beside this script
|
||||||
- move the `hypr_simpleimageviewer.lua` file into `~/.config/hypr/`
|
- move the `hypr_simpleimageviewer.lua` file into `~/.config/hypr/`
|
||||||
|
|||||||
+110
-48
@@ -1,3 +1,5 @@
|
|||||||
|
#include <SDL3/SDL_keycode.h>
|
||||||
|
#include <SDL3/SDL_pixels.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
@@ -5,12 +7,13 @@
|
|||||||
#include <SDL3/SDL_mouse.h>
|
#include <SDL3/SDL_mouse.h>
|
||||||
#include <SDL3/SDL_keyboard.h>
|
#include <SDL3/SDL_keyboard.h>
|
||||||
#include <SDL3/SDL_events.h>
|
#include <SDL3/SDL_events.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#define DESIRED_IMAGE_CHANNELS 4
|
#define DESIRED_IMAGE_CHANNELS 4
|
||||||
|
#define MAX_IMAGE_SCALE 10
|
||||||
|
#define MIN_IMAGE_SCALE 0.01
|
||||||
|
|
||||||
typedef struct Image{
|
typedef struct Image{
|
||||||
int x;
|
int x;
|
||||||
@@ -19,14 +22,20 @@ typedef struct Image{
|
|||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
} Image;
|
} Image;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int w;
|
||||||
|
int h;
|
||||||
|
} window_size_delta;
|
||||||
|
|
||||||
Image load_image(const char* filepath){
|
Image load_image(const char* filepath){
|
||||||
Image image;
|
Image image;
|
||||||
image.pixels = stbi_load(filepath, &image.x, &image.y, &image.channels, DESIRED_IMAGE_CHANNELS);
|
image.pixels = stbi_load(filepath, &image.x, &image.y, &image.channels, DESIRED_IMAGE_CHANNELS);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_image(Image* image){
|
void free_image_buffer(Image* image){
|
||||||
if(image->pixels) stbi_image_free(image->pixels);
|
if(image->pixels) stbi_image_free(image->pixels);
|
||||||
|
image->pixels = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Window* create_window(const char* title, int w, int h){
|
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;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface* get_surface_from_window(SDL_Window* window){
|
SDL_Surface* create_image_surface(SDL_Surface* surface, Image* image){
|
||||||
return SDL_GetWindowSurface(window);
|
SDL_Surface* image_surface = SDL_CreateSurface(image->x, image->y, SDL_PIXELFORMAT_RGBA32);
|
||||||
}
|
|
||||||
|
|
||||||
void draw_image(SDL_Surface* surface, Image* image){
|
|
||||||
SDL_Rect pixel = { 0, 0, 1, 1 };
|
SDL_Rect pixel = { 0, 0, 1, 1 };
|
||||||
|
|
||||||
int center_x = ((surface->w + 1) / 2 - 1);
|
int center_x = ((surface->w + 1) / 2 - 1);
|
||||||
int center_y = ((surface->h + 1) / 2 - 1);
|
int center_y = ((surface->h + 1) / 2 - 1);
|
||||||
|
|
||||||
int dst_x = center_x - image->x / 2;
|
int dst_x = (center_x - image->x / 2);
|
||||||
int dst_y = center_y - image->y / 2;
|
int dst_y = (center_y - image->y / 2);
|
||||||
|
|
||||||
for(int x = 0; x < image->x; x++){
|
for(int x = 0; x < image->x; x++){
|
||||||
pixel.x = dst_x + x;
|
pixel.x = dst_x + x;
|
||||||
@@ -76,15 +82,36 @@ void draw_image(SDL_Surface* surface, Image* image){
|
|||||||
pixel.y = dst_y + y;
|
pixel.y = dst_y + y;
|
||||||
const int current_pixel_idx = (y * image->x + x) * DESIRED_IMAGE_CHANNELS;
|
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 + 0],
|
||||||
image->pixels[current_pixel_idx + 1],
|
image->pixels[current_pixel_idx + 1],
|
||||||
image->pixels[current_pixel_idx + 2],
|
image->pixels[current_pixel_idx + 2],
|
||||||
image->pixels[current_pixel_idx + 3]);
|
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){
|
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;
|
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;
|
int last_w, last_h;
|
||||||
SDL_GetWindowSize(window, &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_w = clamp_low(last_w + step, 50);
|
||||||
int new_h = new_w * last_h / last_w;
|
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);
|
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){
|
int main(int argc, char** argv){
|
||||||
if(argc < 2){
|
if(argc < 2){
|
||||||
printf("Usage: %s [image filepath]\n", argv[0]);
|
printf("Usage: %s [image filepath]\n", argv[0]);
|
||||||
@@ -141,50 +232,21 @@ int main(int argc, char** argv){
|
|||||||
exit(4);
|
exit(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface* surface = get_surface_from_window(window);
|
SDL_Surface* surface = SDL_GetWindowSurface(window);
|
||||||
if(!surface){
|
if(!surface){
|
||||||
printf("Failed to get surface!");
|
printf("Failed to get surface!");
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_image(surface, &image);
|
SDL_Surface* image_surface = create_image_surface(surface, &image);
|
||||||
|
free_image_buffer(&image);
|
||||||
|
|
||||||
free_image(&image);
|
draw_image(window, image_surface, &image, 1.0f);
|
||||||
|
|
||||||
SDL_UpdateWindowSurface(window);
|
SDL_UpdateWindowSurface(window);
|
||||||
|
|
||||||
bool drag_mouse = false;
|
loop(window, image_surface, &image);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
SDL_DestroySurface(image_surface);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user