aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dynamic-array.h51
-rw-r--r--src/main.c264
2 files changed, 315 insertions, 0 deletions
diff --git a/src/dynamic-array.h b/src/dynamic-array.h
new file mode 100644
index 0000000..58d4e64
--- /dev/null
+++ b/src/dynamic-array.h
@@ -0,0 +1,51 @@
1#ifndef INCLUDED_DYNAMIC_ARRAY_H
2#define INCLUDED_DYNAMIC_ARRAY_H
3
4#include <assert.h>
5#define ASSERT assert
6
7#define MALLOC malloc
8#define REALLOC realloc
9#define FREE free
10
11#ifndef DYNAMIC_ARRAY_INIT_CAP
12#define DYNAMIC_ARRAY_INIT_CAP 256
13#endif
14
15#define DYNAMIC_ARRAY_ENSURE_CAPACITY(DYNAMIC_ARRAY, COUNT) \
16 ({ \
17 if ((DYNAMIC_ARRAY).count + (COUNT) > (DYNAMIC_ARRAY).capacity) { \
18 if ((DYNAMIC_ARRAY).capacity == 0) \
19 (DYNAMIC_ARRAY).capacity = DYNAMIC_ARRAY_INIT_CAP; \
20 while ((DYNAMIC_ARRAY).count + (COUNT) > (DYNAMIC_ARRAY).capacity) \
21 (DYNAMIC_ARRAY).capacity *= 2; \
22 (DYNAMIC_ARRAY).items = REALLOC( \
23 (DYNAMIC_ARRAY).items, \
24 (DYNAMIC_ARRAY).capacity*sizeof (*(DYNAMIC_ARRAY).items)); \
25 ASSERT((DYNAMIC_ARRAY).items); \
26 } \
27 })
28
29#define DYNAMIC_ARRAY_APPEND(DYNAMIC_ARRAY, ITEM) \
30 ({ \
31 DYNAMIC_ARRAY_ENSURE_CAPACITY((DYNAMIC_ARRAY), 1); \
32 (DYNAMIC_ARRAY).items[(DYNAMIC_ARRAY).count++] = (ITEM); \
33 })
34
35#define DYNAMIC_ARRAY_APPEND_MANY(DYNAMIC_ARRAY, NEW_ITEMS, NEW_ITEMS_COUNT) \
36 ({ \
37 DYNAMIC_ARRAY_ENSURE_CAPACITY((DYNAMIC_ARRAY), (NEW_ITEMS_COUNT)); \
38 memcpy ((DYNAMIC_ARRAY).items + (DYNAMIC_ARRAY).count, (NEW_ITEMS), \
39 (NEW_ITEMS_COUNT)*sizeof (*(DYNAMIC_ARRAY).items)); \
40 (DYNAMIC_ARRAY).count += (NEW_ITEMS_COUNT); \
41 })
42
43#define DYNAMIC_ARRAY_RESET(DYNAMIC_ARRAY) ({ (DYNAMIC_ARRAY).count = 0; })
44
45#define DYNAMIC_ARRAY_FREE(DYNAMIC_ARRAY) FREE((DYNAMIC_ARRAY).items)
46
47#define DYNAMIC_ARRAY_FOREACH(ITEM, DYNAMIC_ARRAY) for ( \
48 typeof ((DYNAMIC_ARRAY).items) ITEM = (DYNAMIC_ARRAY).items; \
49 ITEM < (DYNAMIC_ARRAY).items + (DYNAMIC_ARRAY).count; ++ITEM)
50
51#endif
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 @@
1#include <raylib.h>
2#include <rlgl.h>
3#include <raymath.h>
4#include <stdlib.h>
5#include <stdio.h>
6#include <string.h>
7#include <poll.h>
8#include <unistd.h>
9#include <sys/inotify.h>
10#include <dirent.h>
11#include "dynamic-array.h"
12
13#define ZOOM_SPEED 1
14
15#define FONT_COLOR WHITE
16#define FONT_SIZE 20
17#define TEXT_SPACING 5
18
19#if defined(PLATFORM_DESKTOP)
20#define GLSL_VERSION 330
21#else
22#define GLSL_VERSION 100
23#endif
24
25#define STRINGIFY(X) #X
26#define TO_STRING(X) STRINGIFY(X)
27
28#define DIRECTORY_SHADERS "./res/shaders/glsl" TO_STRING (GLSL_VERSION)
29
30#define INOTIFY_EVENT_BUFFER_SIZE 4096
31
32#define MOD(A, B) ((((A) % (B)) + (B)) % (B))
33#define MIN(A, B) ((A) < (B) ? (A) : (B))
34
35struct shader_info_da {
36 struct shader_info {
37 char *name;
38 Shader shader;
39 } *items;
40 uint32_t count;
41 uint32_t capacity;
42};
43
44int
45main (void)
46{
47 SetTraceLogLevel (LOG_ALL);
48
49 char inotify_event_buffer[INOTIFY_EVENT_BUFFER_SIZE]
50 __attribute__ ((aligned (__alignof__ (struct inotify_event))));
51 int inotify_fd = inotify_init ();
52 if (inotify_fd < 0) {
53 perror ("inotify_init");
54 exit (EXIT_FAILURE);
55 }
56
57 int inotify_wd = inotify_add_watch (inotify_fd, DIRECTORY_SHADERS,
58 IN_MODIFY |
59 IN_CREATE |
60 IN_DELETE |
61 IN_MOVED_FROM |
62 IN_MOVED_TO);
63 if (inotify_wd == -1) {
64 perror ("inotify_add_watch");
65 exit (EXIT_FAILURE);
66 } TraceLog (LOG_TRACE, "Watching "DIRECTORY_SHADERS" for changes");
67
68 const int screen_width = 800;
69 const int screen_height = 450;
70
71 SetConfigFlags (FLAG_WINDOW_RESIZABLE);
72 InitWindow (screen_width, screen_height, "shadertoy");
73 SetTargetFPS (60);
74
75 Font font = GetFontDefault ();
76
77 struct shader_info_da shader_info_da = {0};
78
79 DIR *shaders_dp = opendir (DIRECTORY_SHADERS);
80 if (shaders_dp == NULL) {
81 perror ("opendir");
82 exit (EXIT_FAILURE);
83 }
84
85 struct dirent *entry;
86 while ((entry = readdir (shaders_dp)) != NULL) {
87 if (entry->d_type == DT_REG &&
88 entry->d_name[0] != '.' &&
89 strlen (entry->d_name) > 3 &&
90 !strcmp (entry->d_name + strlen (entry->d_name) - 3, ".fs")) {
91 TraceLog (LOG_INFO, "Found shader %s", entry->d_name);
92
93 char *name = malloc (strlen (entry->d_name) - 2);
94 memcpy (name, entry->d_name, strlen (entry->d_name) - 3);
95 name[strlen (entry->d_name) - 3] = '\0';
96 Shader shader = LoadShader (NULL, TextFormat (DIRECTORY_SHADERS"/%s", entry->d_name));
97 DYNAMIC_ARRAY_APPEND (shader_info_da, ((struct shader_info) {
98 .name = name,
99 .shader = shader,
100 }));
101 }
102 } closedir (shaders_dp);
103
104 int32_t shader_idx = 0;
105 if (shader_info_da.count) {
106 SetWindowTitle (TextFormat ("shadertoy - %s", shader_info_da.items[shader_idx].name));
107 }
108
109 RenderTexture2D target = LoadRenderTexture (GetScreenWidth (), GetScreenHeight ());
110 float zoom_target = 1;
111 float zoom = 1;
112 while (!WindowShouldClose ()) {
113 fd_set read_fds;
114 FD_ZERO (&read_fds);
115 FD_SET (inotify_fd, &read_fds);
116 struct timeval notime = {0};
117 int activity = select (FD_SETSIZE, &read_fds, NULL, NULL, &notime);
118 if (activity < 0) {
119 perror ("select");
120 exit (EXIT_FAILURE);
121 }
122 if (FD_ISSET (inotify_fd, &read_fds)) {
123 int length = read (inotify_fd, inotify_event_buffer, INOTIFY_EVENT_BUFFER_SIZE);
124
125 if (length < 0) {
126 perror ("read");
127 exit (EXIT_FAILURE);
128 }
129
130 for (int i = 0; i + sizeof (struct inotify_event) < length; ) {
131 struct inotify_event *event = (struct inotify_event *) &inotify_event_buffer[i];
132 if (event->name[0] != '.' && !strcmp (&event->name[strlen (event->name) - 3], ".fs")) {
133 if (event->mask & IN_MODIFY) {
134 TraceLog (LOG_INFO, "Reloading shader %s", event->name);
135 DYNAMIC_ARRAY_FOREACH (shader_info, shader_info_da) {
136 if (!strncmp (event->name, shader_info->name,
137 strlen (shader_info->name))) {
138 UnloadShader (shader_info->shader);
139 shader_info->shader = LoadShader (NULL, TextFormat (DIRECTORY_SHADERS"/%s.fs", shader_info->name));
140 break;
141 }
142 }
143 } else if (event->mask & (IN_DELETE | IN_MOVED_FROM)) {
144 TraceLog (LOG_INFO, "Unloading shader %s", event->name);
145 DYNAMIC_ARRAY_FOREACH (shader_info, shader_info_da) {
146 if (!strncmp (event->name, shader_info->name,
147 strlen (shader_info->name))) {
148 free (shader_info->name);
149 UnloadShader (shader_info->shader);
150 int32_t i = shader_info - shader_info_da.items;
151 memmove (&shader_info_da.items[i], &shader_info_da.items[i + 1],
152 (shader_info_da.count - i)*sizeof (struct shader_info));
153 shader_info_da.count -= 1;
154 if (shader_info_da.count) {
155 shader_idx = MIN (shader_idx, shader_info_da.count - 1);
156 SetWindowTitle (TextFormat ("shadertoy - %s", shader_info_da.items[shader_idx].name));
157 } SetWindowTitle ("shadertoy");
158 break;
159 }
160 }
161 } else if (event->mask & (IN_CREATE | IN_MOVED_TO)) {
162 TraceLog (LOG_INFO, "Loading shader %s", event->name);
163 char *name = malloc (strlen (event->name) - 2);
164 memcpy (name, event->name, strlen (event->name) - 3);
165 name[strlen (event->name) - 3] = '\0';
166 Shader shader = LoadShader (NULL, TextFormat (DIRECTORY_SHADERS"/%s", event->name));
167 DYNAMIC_ARRAY_APPEND (shader_info_da, ((struct shader_info) {
168 .name = name,
169 .shader = shader,
170 }));
171 if (shader_info_da.count == 1)
172 SetWindowTitle (TextFormat ("shadertoy - %s", name));
173 }
174 } i += sizeof (struct inotify_event) + event->len;
175 }
176 }
177
178 if (shader_info_da.count && (IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_RIGHT))) {
179 int32_t c = shader_info_da.count;
180 if (IsKeyPressed(KEY_LEFT )) shader_idx = MOD (shader_idx - 1, c);
181 if (IsKeyPressed(KEY_RIGHT)) shader_idx = MOD (shader_idx + 1, c);
182 SetWindowTitle (TextFormat ("shadertoy - %s", shader_info_da.items[shader_idx].name));
183 }
184
185 zoom_target += GetMouseWheelMove()*ZOOM_SPEED;
186 zoom += Clamp (zoom_target - zoom,
187 -10*GetFrameTime (),
188 +10*GetFrameTime ());
189
190 if (shader_info_da.count) {
191 if (shader_info_da.items[shader_idx].shader.id != rlGetShaderIdDefault ()) {
192 Shader active_shader = shader_info_da.items[shader_idx].shader;
193
194 float time = GetTime ();
195 int shader_location_time = GetShaderLocation(active_shader, "time");
196 SetShaderValue (active_shader, shader_location_time, &time, SHADER_UNIFORM_FLOAT);
197
198 Vector2 resolution = { GetScreenWidth (), GetScreenHeight () };
199 int shader_location_resolution = GetShaderLocation(active_shader, "resolution");
200 SetShaderValue (active_shader, shader_location_resolution, &resolution, SHADER_UNIFORM_VEC2);
201
202 Vector2 mouse = GetMousePosition ();
203 mouse.y = GetScreenHeight () - mouse.y;
204 int shader_location_mouse = GetShaderLocation (active_shader, "mouse");
205 SetShaderValue (active_shader, shader_location_mouse, &mouse, SHADER_UNIFORM_VEC2);
206
207 int shader_location_zoom = GetShaderLocation (active_shader, "zoom");
208 SetShaderValue (active_shader, shader_location_zoom, &zoom, SHADER_UNIFORM_FLOAT);
209
210 if (GetScreenWidth () != target.texture.width ||
211 GetScreenHeight () != target.texture.height) {
212 UnloadRenderTexture (target);
213 target = LoadRenderTexture (GetScreenWidth (), GetScreenHeight ());
214 }
215
216 BeginTextureMode (target); {
217 ClearBackground (BLANK); // NOTE(cmmm): plugin code here
218 } EndTextureMode ();
219 BeginDrawing (); {
220 BeginShaderMode (active_shader);
221 {
222 DrawTextureV(target.texture, Vector2Zero(),
223 BLANK); // NOTE(cmmm): plugin code maybe here
224 }
225 EndShaderMode();
226 }
227 EndDrawing();
228
229 } else {
230 BeginDrawing (); {
231 ClearBackground (BLACK);
232 const char *note = "Unable to compile shader";
233 Vector2 note_size = MeasureTextEx (font, note, FONT_SIZE, TEXT_SPACING);
234 Vector2 note_pos = Vector2Scale (
235 Vector2Subtract ((Vector2) { GetScreenWidth (), GetScreenHeight () },
236 note_size), 0.5);
237 DrawTextEx (font, note, note_pos, FONT_SIZE, TEXT_SPACING, FONT_COLOR);
238 } EndDrawing ();
239 }
240 } else {
241 BeginDrawing (); {
242 ClearBackground (BLACK);
243 const char *note = "There are no shaders in "DIRECTORY_SHADERS;
244 Vector2 note_size = MeasureTextEx (font, note, FONT_SIZE, TEXT_SPACING);
245 Vector2 note_pos = Vector2Scale (
246 Vector2Subtract ((Vector2) { GetScreenWidth (), GetScreenHeight () },
247 note_size), 0.5);
248 DrawTextEx (font, note, note_pos, FONT_SIZE, TEXT_SPACING, FONT_COLOR);
249 } EndDrawing ();
250 }
251 }
252
253 inotify_rm_watch (inotify_fd, inotify_wd);
254 close (inotify_fd);
255
256 DYNAMIC_ARRAY_FOREACH(shader_info, shader_info_da) {
257 UnloadShader (shader_info->shader);
258 free (shader_info->name);
259 } DYNAMIC_ARRAY_FREE(shader_info_da);
260 UnloadRenderTexture (target);
261 CloseWindow ();
262
263 return EXIT_SUCCESS;
264}