diff --git a/Makefile b/Makefile index fc1f710..e863817 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ all: wallpaper distance_field_generator wallpaper: src/wallpaper.c - gcc -O3 -Werror -Wall -Wextra -I./vendor/raylib-5.5_linux_amd64/include/ -o wallpaper src/wallpaper.c -L./vendor/raylib-5.5_linux_amd64/lib -l:libraylib.a -lm + gcc -O3 -Werror -Wall -Wextra -pedantic -I./vendor/raylib-5.5_linux_amd64/include/ -o wallpaper src/wallpaper.c -L./vendor/raylib-5.5_linux_amd64/lib -l:libraylib.a -lm distance_field_generator: src/distance_field_generator.c - gcc -Werror -Wall -Wextra -fopenmp -I./vendor/raylib-5.5_linux_amd64/include/ -o distance_field_generator src/distance_field_generator.c -L./vendor/raylib-5.5_linux_amd64/lib -l:libraylib.a -lm + gcc -Werror -Wall -Wextra -pedantic -fopenmp -I./vendor/raylib-5.5_linux_amd64/include/ -o distance_field_generator src/distance_field_generator.c -L./vendor/raylib-5.5_linux_amd64/lib -l:libraylib.a -lm install: wallpaper sudo install -D -m 755 wallpaper /usr/bin/wallpaper @@ -14,4 +14,4 @@ install: wallpaper clean: rm -f wallpaper distance_field_generator -.PHONY: all install clean \ No newline at end of file +.PHONY: all install clean diff --git a/resources/shaders/basic.vs b/assets/shaders/basic.vs similarity index 100% rename from resources/shaders/basic.vs rename to assets/shaders/basic.vs diff --git a/resources/shaders/distance_field.fs b/assets/shaders/distance_field.fs similarity index 100% rename from resources/shaders/distance_field.fs rename to assets/shaders/distance_field.fs diff --git a/resources/textures/background.png b/assets/textures/background.png similarity index 100% rename from resources/textures/background.png rename to assets/textures/background.png diff --git a/resources/textures/background_distance_field.png b/assets/textures/background_distance_field.png similarity index 100% rename from resources/textures/background_distance_field.png rename to assets/textures/background_distance_field.png diff --git a/resources/textures/background_mask.png b/assets/textures/background_mask.png similarity index 100% rename from resources/textures/background_mask.png rename to assets/textures/background_mask.png diff --git a/resources/textures/background_transparent.png b/assets/textures/background_transparent.png similarity index 86% rename from resources/textures/background_transparent.png rename to assets/textures/background_transparent.png index 8a760e2..912f21f 100644 Binary files a/resources/textures/background_transparent.png and b/assets/textures/background_transparent.png differ diff --git a/resources/textures/star_1.png b/assets/textures/star_1.png similarity index 100% rename from resources/textures/star_1.png rename to assets/textures/star_1.png diff --git a/resources/textures/star_2.png b/assets/textures/star_2.png similarity index 100% rename from resources/textures/star_2.png rename to assets/textures/star_2.png diff --git a/resources/textures/star_3.png b/assets/textures/star_3.png similarity index 100% rename from resources/textures/star_3.png rename to assets/textures/star_3.png diff --git a/resources/textures/star_4.png b/assets/textures/star_4.png similarity index 100% rename from resources/textures/star_4.png rename to assets/textures/star_4.png diff --git a/resources/textures/star_5.png b/assets/textures/star_5.png similarity index 100% rename from resources/textures/star_5.png rename to assets/textures/star_5.png diff --git a/resources/textures/background_no_stars.png b/resources/textures/background_no_stars.png deleted file mode 100644 index ed675c9..0000000 Binary files a/resources/textures/background_no_stars.png and /dev/null differ diff --git a/resources/textures/star_6.png b/resources/textures/star_6.png deleted file mode 100644 index 4d04765..0000000 Binary files a/resources/textures/star_6.png and /dev/null differ diff --git a/src/distance_field_generator.c b/src/distance_field_generator.c index 3924851..e5c8132 100644 --- a/src/distance_field_generator.c +++ b/src/distance_field_generator.c @@ -3,13 +3,11 @@ #include #include -bool is_inside_shape(Color pixel) -{ +static bool is_inside_shape(Color pixel) { return pixel.r == 255 && pixel.g == 255 && pixel.b == 255; } -Image generate_distance_field(Image input_texture, int search_radius) -{ +static Image generate_distance_field(Image input_texture, int search_radius) { int width = input_texture.width; int height = input_texture.height; @@ -20,25 +18,20 @@ Image generate_distance_field(Image input_texture, int search_radius) TraceLog(LOG_INFO, "Using %d threads for parallel processing", omp_get_max_threads()); #pragma omp parallel for schedule(dynamic, 64) - for (int y = 0; y < height; y++) - { - if (omp_get_thread_num() == 0 && y % (height / 10) == 0) - { + for (int y = 0; y < height; y += 1) { + if (omp_get_thread_num() == 0 && y % (height / 10) == 0) { TraceLog(LOG_INFO, "Progress: %d%%", (y * 100) / height); } - for (int x = 0; x < width; x++) - { + for (int x = 0; x < width; x += 1) { int index = y * width + x; bool is_inside = is_inside_shape(input_pixels[index]); float min_distance_sq = search_radius * search_radius; bool found_boundary = false; - for (int dy = -search_radius; dy <= search_radius; dy += 1) - { - for (int dx = -search_radius; dx <= search_radius; dx += 1) - { + for (int dy = -search_radius; dy <= search_radius; dy += 1) { + for (int dx = -search_radius; dx <= search_radius; dx += 1) { int sample_x = x + dx; int sample_y = y + dy; @@ -47,11 +40,9 @@ Image generate_distance_field(Image input_texture, int search_radius) int sample_index = sample_y * width + sample_x; bool sample_is_inside = is_inside_shape(input_pixels[sample_index]); - if (sample_is_inside != is_inside) - { + if (sample_is_inside != is_inside) { float distance_sq = dx * dx + dy * dy; - if (distance_sq < min_distance_sq) - { + if (distance_sq < min_distance_sq) { min_distance_sq = distance_sq; found_boundary = true; } @@ -62,22 +53,15 @@ Image generate_distance_field(Image input_texture, int search_radius) float distance = found_boundary ? sqrtf(min_distance_sq) : (float)search_radius; float normalized_distance = distance / (float)search_radius; - unsigned char distance_value; - if (is_inside) - { - distance_value = (unsigned char)(127.0f - 127.0f * normalized_distance); - } - else - { - distance_value = (unsigned char)(128.0f + 127.0f * normalized_distance); - } + unsigned char distance_value = is_inside ? + (unsigned char)(127.0f - 127.0f * normalized_distance) : + (unsigned char)(128.0f + 127.0f * normalized_distance); output_pixels[index] = (Color){distance_value, distance_value, distance_value, 255}; } } - for (int i = 0; i < width * height; i++) - { + for (int i = 0; i < width * height; i += 1) { ImageDrawPixel(&distance_field, i % width, i / width, output_pixels[i]); } @@ -89,8 +73,7 @@ Image generate_distance_field(Image input_texture, int search_radius) int main(int argc, char *argv[]) { - if (argc < 3) - { + if (argc < 3) { TraceLog(LOG_ERROR, "Usage: %s [search_radius]", argv[0]); return 1; } @@ -100,15 +83,13 @@ int main(int argc, char *argv[]) int search_radius = (argc >= 4) ? atoi(argv[3]) : 100; Image input_image = LoadImage(input_path); - if (input_image.data == NULL) - { + if (input_image.data == NULL) { TraceLog(LOG_ERROR, "Error: Failed to load input image '%s'", input_path); return 1; } Image distance_field_image = generate_distance_field(input_image, search_radius); - if (!ExportImage(distance_field_image, output_path)) - { + if (!ExportImage(distance_field_image, output_path)) { TraceLog(LOG_ERROR, "Failed to save output image '%s'", output_path); UnloadImage(input_image); UnloadImage(distance_field_image); @@ -121,4 +102,4 @@ int main(int argc, char *argv[]) UnloadImage(distance_field_image); return 0; -} \ No newline at end of file +} diff --git a/src/wallpaper.c b/src/wallpaper.c index 916b5e2..b0c65e6 100644 --- a/src/wallpaper.c +++ b/src/wallpaper.c @@ -6,41 +6,41 @@ #include #include #include -#include -#include +#include #include #define WIDTH 1920 #define HEIGHT 1080 +#define BALL_RADIUS 100.0f +#define INFLUENCE 200.0f + typedef struct { const char* name; - int x; - int y; - int cx; - int cy; + Vector2 pos; + Vector2 origin; float angle; float angle_step; } Star; static Star stars[] = { - { .name = "star_1.png", .x = 4, .y = 528, .cx = 165, .cy = 166, .angle = 90.0, .angle_step = -0.025 }, - { .name = "star_2.png", .x = 215, .y = 809, .cx = 82, .cy = 83, .angle = 90.0, .angle_step = 0.05 }, - { .name = "star_3.png", .x = 333, .y = 781, .cx = 25, .cy = 31, .angle = 90.0, .angle_step = 0.15 }, - { .name = "star_4.png", .x = 956, .y = 405, .cx = 166, .cy = 167, .angle = 90.0, .angle_step = -0.1 }, - { .name = "star_5.png", .x = 1164, .y = 570, .cx = 66, .cy = 70, .angle = 90.0, .angle_step = 0.075 }, + { .name = "star_1.png", .pos = { 4, 528 }, .origin = {165, 166}, .angle = 90.0, .angle_step = -0.025 }, + { .name = "star_2.png", .pos = { 215, 809 }, .origin = {82, 83}, .angle = 90.0, .angle_step = 0.05 }, + { .name = "star_3.png", .pos = { 333, 781 }, .origin = {25, 31}, .angle = 90.0, .angle_step = 0.15 }, + { .name = "star_4.png", .pos = { 956, 405 }, .origin = {166, 167}, .angle = 90.0, .angle_step = -0.1 }, + { .name = "star_5.png", .pos = { 1164, 570 }, .origin = {66, 70}, .angle = 90.0, .angle_step = 0.075 }, }; #define STARS_COUNT (int)(sizeof(stars) / sizeof(stars[0])) -char *hyprland_socket_path; +static char *hyprland_socket_path; -Vector2 hyprland_get_cursor_position() { - Vector2 pos = {0}; +static Vector2 hyprland_get_cursor_position() { + Vector2 pos = {0, 0}; int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (sock_fd == -1) { - perror("socket"); + TraceLog(LOG_ERROR, "socket: %s", strerror(errno)); return pos; } @@ -49,15 +49,14 @@ Vector2 hyprland_get_cursor_position() { strncpy(addr.sun_path, hyprland_socket_path, sizeof(addr.sun_path) - 1); if (connect(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - printf("Using hyprland socket: %s\n", hyprland_socket_path); - perror("connect"); + TraceLog(LOG_ERROR, "connect %s: %s", hyprland_socket_path, strerror(errno)); close(sock_fd); return pos; } const char *message = "/cursorpos"; if (send(sock_fd, message, strlen(message), 0) == -1) { - perror("send"); + TraceLog(LOG_ERROR, "send: %s", strerror(errno)); close(sock_fd); return pos; } @@ -65,7 +64,7 @@ Vector2 hyprland_get_cursor_position() { char buffer[256] = {0}; ssize_t bytes_received = recv(sock_fd, buffer, sizeof(buffer) - 1, 0); if (bytes_received == -1) { - perror("recv"); + TraceLog(LOG_ERROR, "recv: %s", strerror(errno)); close(sock_fd); return pos; } @@ -74,76 +73,66 @@ Vector2 hyprland_get_cursor_position() { buffer[bytes_received] = '\0'; if (sscanf(buffer, "%f, %f", &pos.x, &pos.y) != 2) { - fprintf(stderr, "Failed to parse cursor position\n"); + TraceLog(LOG_ERROR, "Failed to parse cursor position"); } close(sock_fd); return pos; } -Texture2D load_texture_from_file(const char *file_path) { - Texture2D texture = {0}; - - if (FileExists(file_path)) { - texture = LoadTexture(file_path); - } - else { - const char *system_path = TextFormat("/usr/share/wallpaper/%s", file_path); - if (FileExists(system_path)) { - texture = LoadTexture(system_path); - } - } +static const char *resolve_asset_path(const char *path) { + if (FileExists(path)) return path; + const char *system_path = TextFormat("/usr/share/wallpaper/%s", path); + if (FileExists(system_path)) return system_path; + return path; +} +static Texture2D load_texture_from_file(const char *file_path) { + Texture2D texture = LoadTexture(resolve_asset_path(file_path)); if (texture.id == 0) { TraceLog(LOG_ERROR, "Failed to load texture from file: %s", file_path); + abort(); } return texture; } -Shader load_shader_from_file(const char *vs_path, const char *fs_path) { - Shader shader = {0}; - - if (FileExists(vs_path) && FileExists(fs_path)) { - shader = LoadShader(vs_path, fs_path); - } - else { - const char *system_vs_path = TextFormat("/usr/share/wallpaper/%s", vs_path); - const char *system_fs_path = TextFormat("/usr/share/wallpaper/%s", fs_path); - if (FileExists(system_vs_path) && FileExists(system_fs_path)) { - shader = LoadShader(system_vs_path, system_fs_path); - } - } - +static Shader load_shader_from_file(const char *vs_path, const char *fs_path) { + Shader shader = LoadShader(resolve_asset_path(vs_path), resolve_asset_path(fs_path)); if (shader.id == 0) { TraceLog(LOG_ERROR, "Failed to load shader from files: %s, %s", vs_path, fs_path); + abort(); } return shader; } -const char* get_window_title() { +static const char* get_window_title() { return getenv("DEBUG") != NULL ? "pihkaal-wallpaper-debug" : "pihkaal-wallpaper"; } +static char* get_hyprland_socket_path() { + return strdup(TextFormat("%s/hypr/%s/.socket.sock", getenv("XDG_RUNTIME_DIR"), getenv("HYPRLAND_INSTANCE_SIGNATURE"))); +} + int main(void) { InitWindow(WIDTH, HEIGHT, get_window_title()); SetWindowState(FLAG_WINDOW_RESIZABLE); SetTargetFPS(60); // initialize hyprland socket path - hyprland_socket_path = strdup(TextFormat("%s/hypr/%s/.socket.sock", getenv("XDG_RUNTIME_DIR"), getenv("HYPRLAND_INSTANCE_SIGNATURE"))); + hyprland_socket_path = get_hyprland_socket_path(); // initialize textures - Texture2D distanceFieldTex = load_texture_from_file("resources/textures/background_distance_field.png"); - Texture2D backgroundTex = load_texture_from_file("resources/textures/background_no_stars.png"); - RenderTexture2D target = LoadRenderTexture(WIDTH, HEIGHT); - - Texture2D starTextures[STARS_COUNT]; + Texture2D distanceFieldTex = load_texture_from_file("assets/textures/background_distance_field.png"); + Texture2D backgroundTex = load_texture_from_file("assets/textures/background_transparent.png"); + Texture2D starTextures[STARS_COUNT] = {0}; for (int i = 0; i < STARS_COUNT; i++) { - starTextures[i] = load_texture_from_file(TextFormat("resources/textures/%s", stars[i].name)); + starTextures[i] = load_texture_from_file(TextFormat("assets/textures/%s", stars[i].name)); } + RenderTexture2D target = LoadRenderTexture(WIDTH, HEIGHT); + // initialize shader - Shader shader = load_shader_from_file("resources/shaders/basic.vs", "resources/shaders/distance_field.fs"); + Shader shader = load_shader_from_file("assets/shaders/basic.vs", "assets/shaders/distance_field.fs"); int resolutionLoc = GetShaderLocation(shader, "resolution"); int mousePosLoc = GetShaderLocation(shader, "mousePos"); @@ -154,10 +143,10 @@ int main(void) { Vector2 resolution = {WIDTH, HEIGHT}; SetShaderValue(shader, resolutionLoc, &resolution, SHADER_UNIFORM_VEC2); - float ballRadius = 100.0f; + float ballRadius = BALL_RADIUS; SetShaderValue(shader, ballRadiusLoc, &ballRadius, SHADER_UNIFORM_FLOAT); - float shapeInfluence = 200.0f; + float shapeInfluence = INFLUENCE; SetShaderValue(shader, shapeInfluenceLoc, &shapeInfluence, SHADER_UNIFORM_FLOAT); int textureUnit = 1; @@ -192,13 +181,13 @@ int main(void) { DrawTextureRec(backgroundTex, (Rectangle){0, 0, screenWidth, screenHeight}, (Vector2){0, 0}, WHITE); for (int i = 0; i < STARS_COUNT; i++) { - stars[i].angle = fmodf(stars[i].angle + stars[i].angle_step, 360.0f); + Star* star = &stars[i]; + star->angle = fmodf(star->angle + star->angle_step, 360.0f); Texture2D tex = starTextures[i]; Rectangle source = {0, 0, (float)tex.width, (float)tex.height}; - Rectangle dest = {stars[i].x, stars[i].y, (float)tex.width, (float)tex.height}; - Vector2 origin = {stars[i].cx, stars[i].cy}; - DrawTexturePro(tex, source, dest, origin, stars[i].angle, WHITE); + Rectangle dest = {star->pos.x, star->pos.y, (float)tex.width, (float)tex.height}; + DrawTexturePro(tex, source, dest, star->origin, star->angle, WHITE); } EndDrawing();