From 3bfff85a11a06bcd3823b8e3ea3f89a5544b4756 Mon Sep 17 00:00:00 2001 From: Martin Michalec Date: Wed, 11 Feb 2026 07:50:28 +0300 Subject: add sources --- src/main.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 src/main.c (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0495677 --- /dev/null +++ b/src/main.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic-array.h" + +#define ZOOM_SPEED 1 + +#define FONT_COLOR WHITE +#define FONT_SIZE 20 +#define TEXT_SPACING 5 + +#if defined(PLATFORM_DESKTOP) +#define GLSL_VERSION 330 +#else +#define GLSL_VERSION 100 +#endif + +#define STRINGIFY(X) #X +#define TO_STRING(X) STRINGIFY(X) + +#define DIRECTORY_SHADERS "./res/shaders/glsl" TO_STRING (GLSL_VERSION) + +#define INOTIFY_EVENT_BUFFER_SIZE 4096 + +#define MOD(A, B) ((((A) % (B)) + (B)) % (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) + +struct shader_info_da { + struct shader_info { + char *name; + Shader shader; + } *items; + uint32_t count; + uint32_t capacity; +}; + +int +main (void) +{ + SetTraceLogLevel (LOG_ALL); + + char inotify_event_buffer[INOTIFY_EVENT_BUFFER_SIZE] + __attribute__ ((aligned (__alignof__ (struct inotify_event)))); + int inotify_fd = inotify_init (); + if (inotify_fd < 0) { + perror ("inotify_init"); + exit (EXIT_FAILURE); + } + + int inotify_wd = inotify_add_watch (inotify_fd, DIRECTORY_SHADERS, + IN_MODIFY | + IN_CREATE | + IN_DELETE | + IN_MOVED_FROM | + IN_MOVED_TO); + if (inotify_wd == -1) { + perror ("inotify_add_watch"); + exit (EXIT_FAILURE); + } TraceLog (LOG_TRACE, "Watching "DIRECTORY_SHADERS" for changes"); + + const int screen_width = 800; + const int screen_height = 450; + + SetConfigFlags (FLAG_WINDOW_RESIZABLE); + InitWindow (screen_width, screen_height, "shadertoy"); + SetTargetFPS (60); + + Font font = GetFontDefault (); + + struct shader_info_da shader_info_da = {0}; + + DIR *shaders_dp = opendir (DIRECTORY_SHADERS); + if (shaders_dp == NULL) { + perror ("opendir"); + exit (EXIT_FAILURE); + } + + struct dirent *entry; + while ((entry = readdir (shaders_dp)) != NULL) { + if (entry->d_type == DT_REG && + entry->d_name[0] != '.' && + strlen (entry->d_name) > 3 && + !strcmp (entry->d_name + strlen (entry->d_name) - 3, ".fs")) { + TraceLog (LOG_INFO, "Found shader %s", entry->d_name); + + char *name = malloc (strlen (entry->d_name) - 2); + memcpy (name, entry->d_name, strlen (entry->d_name) - 3); + name[strlen (entry->d_name) - 3] = '\0'; + Shader shader = LoadShader (NULL, TextFormat (DIRECTORY_SHADERS"/%s", entry->d_name)); + DYNAMIC_ARRAY_APPEND (shader_info_da, ((struct shader_info) { + .name = name, + .shader = shader, + })); + } + } closedir (shaders_dp); + + int32_t shader_idx = 0; + if (shader_info_da.count) { + SetWindowTitle (TextFormat ("shadertoy - %s", shader_info_da.items[shader_idx].name)); + } + + RenderTexture2D target = LoadRenderTexture (GetScreenWidth (), GetScreenHeight ()); + float zoom_target = 1; + float zoom = 1; + while (!WindowShouldClose ()) { + fd_set read_fds; + FD_ZERO (&read_fds); + FD_SET (inotify_fd, &read_fds); + struct timeval notime = {0}; + int activity = select (FD_SETSIZE, &read_fds, NULL, NULL, ¬ime); + if (activity < 0) { + perror ("select"); + exit (EXIT_FAILURE); + } + if (FD_ISSET (inotify_fd, &read_fds)) { + int length = read (inotify_fd, inotify_event_buffer, INOTIFY_EVENT_BUFFER_SIZE); + + if (length < 0) { + perror ("read"); + exit (EXIT_FAILURE); + } + + for (int i = 0; i + sizeof (struct inotify_event) < length; ) { + struct inotify_event *event = (struct inotify_event *) &inotify_event_buffer[i]; + if (event->name[0] != '.' && !strcmp (&event->name[strlen (event->name) - 3], ".fs")) { + if (event->mask & IN_MODIFY) { + TraceLog (LOG_INFO, "Reloading shader %s", event->name); + DYNAMIC_ARRAY_FOREACH (shader_info, shader_info_da) { + if (!strncmp (event->name, shader_info->name, + strlen (shader_info->name))) { + UnloadShader (shader_info->shader); + shader_info->shader = LoadShader (NULL, TextFormat (DIRECTORY_SHADERS"/%s.fs", shader_info->name)); + break; + } + } + } else if (event->mask & (IN_DELETE | IN_MOVED_FROM)) { + TraceLog (LOG_INFO, "Unloading shader %s", event->name); + DYNAMIC_ARRAY_FOREACH (shader_info, shader_info_da) { + if (!strncmp (event->name, shader_info->name, + strlen (shader_info->name))) { + free (shader_info->name); + UnloadShader (shader_info->shader); + int32_t i = shader_info - shader_info_da.items; + memmove (&shader_info_da.items[i], &shader_info_da.items[i + 1], + (shader_info_da.count - i)*sizeof (struct shader_info)); + shader_info_da.count -= 1; + if (shader_info_da.count) { + shader_idx = MIN (shader_idx, shader_info_da.count - 1); + SetWindowTitle (TextFormat ("shadertoy - %s", shader_info_da.items[shader_idx].name)); + } SetWindowTitle ("shadertoy"); + break; + } + } + } else if (event->mask & (IN_CREATE | IN_MOVED_TO)) { + TraceLog (LOG_INFO, "Loading shader %s", event->name); + char *name = malloc (strlen (event->name) - 2); + memcpy (name, event->name, strlen (event->name) - 3); + name[strlen (event->name) - 3] = '\0'; + Shader shader = LoadShader (NULL, TextFormat (DIRECTORY_SHADERS"/%s", event->name)); + DYNAMIC_ARRAY_APPEND (shader_info_da, ((struct shader_info) { + .name = name, + .shader = shader, + })); + if (shader_info_da.count == 1) + SetWindowTitle (TextFormat ("shadertoy - %s", name)); + } + } i += sizeof (struct inotify_event) + event->len; + } + } + + if (shader_info_da.count && (IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_RIGHT))) { + int32_t c = shader_info_da.count; + if (IsKeyPressed(KEY_LEFT )) shader_idx = MOD (shader_idx - 1, c); + if (IsKeyPressed(KEY_RIGHT)) shader_idx = MOD (shader_idx + 1, c); + SetWindowTitle (TextFormat ("shadertoy - %s", shader_info_da.items[shader_idx].name)); + } + + zoom_target += GetMouseWheelMove()*ZOOM_SPEED; + zoom += Clamp (zoom_target - zoom, + -10*GetFrameTime (), + +10*GetFrameTime ()); + + if (shader_info_da.count) { + if (shader_info_da.items[shader_idx].shader.id != rlGetShaderIdDefault ()) { + Shader active_shader = shader_info_da.items[shader_idx].shader; + + float time = GetTime (); + int shader_location_time = GetShaderLocation(active_shader, "time"); + SetShaderValue (active_shader, shader_location_time, &time, SHADER_UNIFORM_FLOAT); + + Vector2 resolution = { GetScreenWidth (), GetScreenHeight () }; + int shader_location_resolution = GetShaderLocation(active_shader, "resolution"); + SetShaderValue (active_shader, shader_location_resolution, &resolution, SHADER_UNIFORM_VEC2); + + Vector2 mouse = GetMousePosition (); + mouse.y = GetScreenHeight () - mouse.y; + int shader_location_mouse = GetShaderLocation (active_shader, "mouse"); + SetShaderValue (active_shader, shader_location_mouse, &mouse, SHADER_UNIFORM_VEC2); + + int shader_location_zoom = GetShaderLocation (active_shader, "zoom"); + SetShaderValue (active_shader, shader_location_zoom, &zoom, SHADER_UNIFORM_FLOAT); + + if (GetScreenWidth () != target.texture.width || + GetScreenHeight () != target.texture.height) { + UnloadRenderTexture (target); + target = LoadRenderTexture (GetScreenWidth (), GetScreenHeight ()); + } + + BeginTextureMode (target); { + ClearBackground (BLANK); // NOTE(cmmm): plugin code here + } EndTextureMode (); + BeginDrawing (); { + BeginShaderMode (active_shader); + { + DrawTextureV(target.texture, Vector2Zero(), + BLANK); // NOTE(cmmm): plugin code maybe here + } + EndShaderMode(); + } + EndDrawing(); + + } else { + BeginDrawing (); { + ClearBackground (BLACK); + const char *note = "Unable to compile shader"; + Vector2 note_size = MeasureTextEx (font, note, FONT_SIZE, TEXT_SPACING); + Vector2 note_pos = Vector2Scale ( + Vector2Subtract ((Vector2) { GetScreenWidth (), GetScreenHeight () }, + note_size), 0.5); + DrawTextEx (font, note, note_pos, FONT_SIZE, TEXT_SPACING, FONT_COLOR); + } EndDrawing (); + } + } else { + BeginDrawing (); { + ClearBackground (BLACK); + const char *note = "There are no shaders in "DIRECTORY_SHADERS; + Vector2 note_size = MeasureTextEx (font, note, FONT_SIZE, TEXT_SPACING); + Vector2 note_pos = Vector2Scale ( + Vector2Subtract ((Vector2) { GetScreenWidth (), GetScreenHeight () }, + note_size), 0.5); + DrawTextEx (font, note, note_pos, FONT_SIZE, TEXT_SPACING, FONT_COLOR); + } EndDrawing (); + } + } + + inotify_rm_watch (inotify_fd, inotify_wd); + close (inotify_fd); + + DYNAMIC_ARRAY_FOREACH(shader_info, shader_info_da) { + UnloadShader (shader_info->shader); + free (shader_info->name); + } DYNAMIC_ARRAY_FREE(shader_info_da); + UnloadRenderTexture (target); + CloseWindow (); + + return EXIT_SUCCESS; +} -- cgit v1.3