summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--00f.glsl (renamed from 1f.glsl)0
-rw-r--r--00v.glsl (renamed from 1v.glsl)0
-rw-r--r--filesystem-posix.c90
-rw-r--r--filesystem-win.c89
-rw-r--r--filesystem.h41
-rw-r--r--main.c193
-rw-r--r--util.c7
7 files changed, 367 insertions, 53 deletions
diff --git a/1f.glsl b/00f.glsl
index a3e8d18..a3e8d18 100644
--- a/1f.glsl
+++ b/00f.glsl
diff --git a/1v.glsl b/00v.glsl
index d5286df..d5286df 100644
--- a/1v.glsl
+++ b/00v.glsl
diff --git a/filesystem-posix.c b/filesystem-posix.c
new file mode 100644
index 0000000..8af0bf2
--- /dev/null
+++ b/filesystem-posix.c
@@ -0,0 +1,90 @@
+#include "filesystem.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+
+FsType fs_path_type(char const *path) {
+ struct stat statbuf = {0};
+ if (stat(path, &statbuf) != 0)
+ return FS_NON_EXISTENT;
+ if (S_ISREG(statbuf.st_mode))
+ return FS_FILE;
+ if (S_ISDIR(statbuf.st_mode))
+ return FS_DIRECTORY;
+ return FS_OTHER;
+}
+
+FsPermission fs_path_permission(char const *path) {
+ int bits = access(path, R_OK | W_OK);
+ FsPermission perm = 0;
+ if (!(bits & R_OK)) perm |= FS_PERMISSION_READ;
+ if (!(bits & W_OK)) perm |= FS_PERMISSION_WRITE;
+ return perm;
+}
+
+bool fs_file_exists(char const *path) {
+ return fs_path_type(path) == FS_FILE;
+}
+
+char **fs_list_directory(char const *dirname) {
+ char **ret = NULL;
+ DIR *dir = opendir(dirname);
+ if (dir) {
+ struct dirent *ent;
+ char **filenames = NULL;
+ size_t nentries = 0;
+ size_t filename_idx = 0;
+
+ while (readdir(dir)) ++nentries;
+ rewinddir(dir);
+ filenames = (char **)calloc(nentries+1, sizeof *filenames);
+
+ while ((ent = readdir(dir))) {
+ char const *filename = ent->d_name;
+ size_t len = strlen(filename);
+ char *filename_copy = (char *)malloc(len+1);
+ if (!filename_copy) break;
+ strcpy(filename_copy, filename);
+ if (filename_idx < nentries) // this could actually fail if someone creates files between calculating nentries and here.
+ filenames[filename_idx++] = filename_copy;
+ }
+ ret = filenames;
+ closedir(dir);
+ }
+ return ret;
+}
+
+int fs_mkdir(char const *path) {
+ if (mkdir(path, 0755) == 0) {
+ // directory created successfully
+ return 1;
+ } else if (errno == EEXIST) {
+ struct stat statbuf = {0};
+ if (stat(path, &statbuf) == 0) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ // already exists, and it's a directory
+ return 0;
+ } else {
+ // already exists, but not a directory
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+int fs_get_cwd(char *buf, size_t buflen) {
+ assert(buf && buflen);
+ if (getcwd(buf, buflen)) {
+ return 1;
+ } else if (errno == ERANGE) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
diff --git a/filesystem-win.c b/filesystem-win.c
new file mode 100644
index 0000000..c6c64dd
--- /dev/null
+++ b/filesystem-win.c
@@ -0,0 +1,89 @@
+#include "filesystem.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+FsType fs_path_type(char const *path) {
+ struct _stat statbuf = {0};
+ if (_stat(path, &statbuf) != 0)
+ return FS_NON_EXISTENT;
+ if (statbuf.st_mode & _S_IFREG)
+ return FS_FILE;
+ if (statbuf.st_mode & _S_IFDIR)
+ return FS_DIRECTORY;
+ return FS_OTHER;
+}
+
+FsPermission fs_path_permission(char const *path) {
+ FsPermission permission = 0;
+ if (_access(path, 04) == 0) permission |= FS_PERMISSION_READ;
+ if (_access(path, 02) == 0) permission |= FS_PERMISSION_WRITE;
+ return permission;
+}
+
+bool fs_file_exists(char const *path) {
+ return fs_path_type(path) == FS_FILE;
+}
+
+char **fs_list_directory(char const *dirname) {
+ char file_pattern[256] = {0};
+ char **ret = NULL;
+ WIN32_FIND_DATA find_data;
+ HANDLE fhandle;
+ assert(*dirname);
+ sprintf_s(file_pattern, sizeof file_pattern, "%s%s*", dirname,
+ dirname[strlen(dirname) - 1] == PATH_SEPARATOR ? "" : PATH_SEPARATOR_STR);
+ fhandle = FindFirstFileA(file_pattern, &find_data);
+ if (fhandle != INVALID_HANDLE_VALUE) {
+ // first, figure out number of files
+ int nfiles = 1, idx = 0;
+ char **files;
+ while (FindNextFile(fhandle, &find_data)) {
+ ++nfiles;
+ }
+ FindClose(fhandle);
+ // now, fill out files array
+ files = malloc((nfiles + 1) * sizeof *files);
+ if (files) {
+ fhandle = FindFirstFileA(file_pattern, &find_data);
+ if (fhandle != INVALID_HANDLE_VALUE) {
+ do {
+ if (idx < nfiles) {
+ char *dup = _strdup(find_data.cFileName);
+ if (dup) {
+ files[idx++] = dup;
+ } else break; // stop now
+ }
+ } while (FindNextFile(fhandle, &find_data));
+ files[idx] = NULL;
+ FindClose(fhandle);
+ ret = files;
+ }
+ }
+ }
+ return ret;
+}
+
+int fs_mkdir(char const *path) {
+ if (CreateDirectoryA(path, NULL)) {
+ // directory created successfully
+ return 1;
+ } else {
+ if (GetLastError() == ERROR_ALREADY_EXISTS) // directory already exists
+ return 0;
+ else
+ return -1; // some other error
+ }
+}
+
+int fs_get_cwd(char *buf, size_t buflen) {
+ assert(buf && buflen);
+ DWORD pathlen = GetCurrentDirectory((DWORD)buflen, buf);
+ if (pathlen == 0) {
+ return -1;
+ } else if (pathlen < buflen) { // it's confusing, but this is < and not <=
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/filesystem.h b/filesystem.h
new file mode 100644
index 0000000..6325bd7
--- /dev/null
+++ b/filesystem.h
@@ -0,0 +1,41 @@
+#ifndef FILESYSTEM_H_
+#define FILESYSTEM_H_
+
+typedef enum {
+ FS_NON_EXISTENT,
+ FS_FILE,
+ FS_DIRECTORY,
+ FS_OTHER
+} FsType;
+
+enum {
+ FS_PERMISSION_READ = 0x01,
+ FS_PERMISSION_WRITE = 0x02,
+};
+typedef u8 FsPermission;
+
+// returns what kind of thing this is.
+FsType fs_path_type(char const *path);
+FsPermission fs_path_permission(char const *path);
+// Does this file exist? Returns false for directories.
+bool fs_file_exists(char const *path);
+// Returns a NULL-terminated array of the files/directories in this directory, or NULL if the directory does not exist.
+// When you're done with the file names, call free on each one, then on the array.
+// NOTE: The files aren't returned in any particular order!
+char **fs_list_directory(char const *dirname);
+// Create the directory specified by `path`
+// Returns:
+// 1 if the directory was created successfully
+// 0 if the directory already exists
+// -1 if the path already exists, but it's not a directory, or if there's another error (e.g. don't have permission to create directory).
+int fs_mkdir(char const *path);
+// Puts the current working directory into buf, including a null-terminator, writing at most buflen bytes.
+// Returns:
+// 1 if the working directory was inserted into buf successfully
+// 0 if buf is too short to hold the cwd
+// -1 if we can't get the cwd for whatever reason.
+int fs_get_cwd(char *buf, size_t buflen);
+
+
+#endif // FILESYSTEM_H_
+
diff --git a/main.c b/main.c
index e9835df..705c699 100644
--- a/main.c
+++ b/main.c
@@ -9,9 +9,15 @@
#include "gl.c"
#include "time.c"
#include "util.c"
+#if _WIN32
+#include "filesystem-win.c"
+#else
+#include "filesystem-posix.c"
+#endif
typedef struct {
GLuint program;
+ GLuint vbo, vao;
struct timespec last_modified;
char vfilename[64], ffilename[64];
} Shader;
@@ -43,9 +49,21 @@ static void shader_load(Shader *shader, char const *vfilename, char const *ffile
fread(vcode, 1, vsize, vfp);
fread(fcode, 1, fsize, ffp);
+
GLuint program = gl_compile_and_link_shaders(vcode, fcode);
- if (program)
+ if (program) {
shader->program = program;
+ if (shader->vbo) glDeleteBuffers(1, &shader->vbo);
+ if (shader->vao) glDeleteVertexArrays(1, &shader->vao);
+ GLuint vbo = 0;
+ glGenBuffers(1, &vbo);
+ GLuint vao = 0;
+ if (gl_version_major >= 3)
+ glGenVertexArrays(1, &vao);
+
+ shader->vbo = vbo;
+ shader->vao = vao;
+ }
} else print("Out of memory.\n");
free(vcode); free(fcode);
} else {
@@ -69,6 +87,54 @@ static void shader_check_for_changes(Shader *shader) {
}
}
+static double start_time;
+
+static void shader_draw(Shader *shader, Rect where) {
+ shader_check_for_changes(shader);
+ float x1, y1, x2, y2;
+ rect_coords(where, &x1, &y1, &x2, &y2);
+
+ if (shader->vao)
+ glBindVertexArray(shader->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, shader->vbo);
+ v2 buffer_data[] = {
+ // gl coordinates (v_render_pos)
+ {x1, y1},
+ {x2, y1},
+ {x1, y2},
+
+ {x2, y1},
+ {x2, y2},
+ {x1, y2},
+
+ // normalized coordinates (v_pos)
+ {0, 0},
+ {1, 0},
+ {0, 1},
+
+ {1, 0},
+ {1, 1},
+ {0, 1},
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof buffer_data, buffer_data, GL_STATIC_DRAW);
+ GLuint v_render_pos = gl_attrib_loc(shader->program, "v_render_pos");
+ GLuint v_pos = gl_attrib_loc(shader->program, "v_pos");
+ if (v_render_pos != (GLuint)-1) {
+ glVertexAttribPointer(v_render_pos, 2, GL_FLOAT, 0, sizeof(v2), NULL);
+ glEnableVertexAttribArray(v_render_pos);
+ }
+ if (v_pos != (GLuint)-1) {
+ glVertexAttribPointer(v_pos, 2, GL_FLOAT, 0, sizeof(v2), (void *)(6 * sizeof(v2)));
+ glEnableVertexAttribArray(v_pos);
+ }
+ glUseProgram(shader->program);
+ GLint u_time = gl_uniform_loc(shader->program, "u_time");
+ if (u_time >= 0)
+ glUniform1f(u_time, (float)fmod(time_get_seconds() - start_time, 10000));
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
static void die(char const *fmt, ...) {
char buf[256] = {0};
@@ -142,63 +208,70 @@ int main(void) {
SDL_GL_SetSwapInterval(1); // vsync
- Shader shader = {0};
- shader_load(&shader, "1v.glsl", "1f.glsl");
+ Shader *shaders = NULL;
- GLuint vbo = 0;
- glGenBuffers(1, &vbo);
- GLuint vao = 0;
- if (gl_version_major >= 3)
- glGenVertexArrays(1, &vao);
-
- v2 buffer_data[] = {
- // gl coordinates (v_render_pos)
- {-1, -1},
- {+1, -1},
- {-1, +1},
-
- {+1, -1},
- {+1, +1},
- {-1, +1},
-
- // normalized coordinates (v_pos)
- {0, 0},
- {1, 0},
- {0, 1},
-
- {1, 0},
- {1, 1},
- {0, 1},
- };
+ char **files = fs_list_directory(".");
+ size_t nfiles; for (nfiles = 0; files[nfiles]; ++nfiles);
+ qsort(files, nfiles, sizeof *files, str_qsort_case_insensitive_cmp);
- if (vao) glBindVertexArray(vao);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof buffer_data, buffer_data, GL_STATIC_DRAW);
- GLuint v_render_pos = gl_attrib_loc(shader.program, "v_render_pos");
- GLuint v_pos = gl_attrib_loc(shader.program, "v_pos");
- if (v_render_pos != (GLuint)-1) {
- glVertexAttribPointer(v_render_pos, 2, GL_FLOAT, 0, sizeof(v2), NULL);
- glEnableVertexAttribArray(v_render_pos);
+ u16 nshaders = 0;
+ for (size_t i = 0; i < nfiles; ++i) {
+ nshaders += str_is_suffix(files[i], "v.glsl");
}
- if (v_pos != (GLuint)-1) {
- glVertexAttribPointer(v_pos, 2, GL_FLOAT, 0, sizeof(v2), (void *)(6 * sizeof(v2)));
- glEnableVertexAttribArray(v_pos);
+
+ u16 shader_idx = 0;
+ for (size_t i = 0; i < nfiles; ++i) {
+ if (str_is_suffix(files[i], "v.glsl")) {
+ char const *vfilename = files[i];
+ char ffilename[64];
+ strbuf_cpy(ffilename, vfilename);
+ ffilename[strlen(ffilename) - 6] = 'f';
+ Shader shader = {0};
+ shader_load(&shader, vfilename, ffilename);
+ arr_add(shaders, shader);
+ ++shader_idx;
+ }
+ free(files[i]);
}
- bool quit = false;
- double start = time_get_seconds();
+ i32 viewing_shader = -1;
+
+ free(files);
+
+ bool quit = false, fullscreen = false;
+ start_time = time_get_seconds();
while (!quit) {
SDL_Event event = {0};
+ int window_width, window_height;
+ SDL_GetWindowSize(window, &window_width, &window_height);
+ v2 *mouse_clicks = NULL;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
quit = true;
break;
+ case SDL_MOUSEBUTTONDOWN: {
+ float x = -1 + 2 * (float)event.button.x / (float)window_width;
+ float y = +1 - 2 * (float)event.button.y / (float)window_height;
+ arr_add(mouse_clicks, V2(x, y));
+ } break;
+ case SDL_KEYDOWN:
+ switch (event.key.keysym.sym) {
+ case SDLK_ESCAPE:
+ if (viewing_shader == -1)
+ quit = true;
+ else
+ viewing_shader = -1;
+ break;
+ case SDLK_F11:
+ fullscreen = !fullscreen;
+ SDL_SetWindowFullscreen(window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
+ break;
+ }
+ break;
}
}
- int window_width, window_height;
- SDL_GetWindowSize(window, &window_width, &window_height);
// set up GL
glEnable(GL_BLEND);
@@ -207,18 +280,32 @@ int main(void) {
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
- shader_check_for_changes(&shader);
-
- if (shader.program) {
- if (vao) glBindVertexArray(vao);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glUseProgram(shader.program);
- GLint u_time = gl_uniform_loc(shader.program, "u_time");
- if (u_time >= 0)
- glUniform1f(u_time, (float)fmod(time_get_seconds() - start, 10000));
- glDrawArrays(GL_TRIANGLES, 0, 6);
+ if (viewing_shader >= 0) {
+ // one shader
+ Shader *shader = &shaders[viewing_shader];
+ shader_draw(shader, rect4(-1, -1, +1, +1));
+ } else {
+ // shader gallery
+ u16 idx = 0;
+ float w = 2 * 1.0f / 6;
+ float h = 2 * 1.0f / ((nshaders + 5) / 6);
+ h = minf(h, 1.0f / 3);
+ arr_foreach_ptr(shaders, Shader, shader) {
+ float x1 = -1 + (idx % 6) * w;
+ float y1 = 1 - h - (idx / 6) * h;
+ Rect r = rect(V2(x1, y1), V2(w, h));
+ r = rect_shrink(r, 0.02f);
+ arr_foreach_ptr(mouse_clicks, v2, click) {
+ if (rect_contains_point(r, *click))
+ viewing_shader = idx;
+ }
+ shader_draw(shader, r);
+ ++idx;
+ }
}
+
+ arr_clear(mouse_clicks);
SDL_GL_SwapWindow(window);
}
diff --git a/util.c b/util.c
index aa79ad5..31bc7de 100644
--- a/util.c
+++ b/util.c
@@ -61,6 +61,13 @@ static bool str_is_prefix(char const *str, char const *prefix) {
return strncmp(str, prefix, strlen(prefix)) == 0;
}
+static bool str_is_suffix(char const *str, char const *suffix) {
+ size_t str_len = strlen(str);
+ size_t suf_len = strlen(suffix);
+ if (str_len < suf_len) return false;
+ return memcmp(str + str_len - suf_len, suffix, suf_len) == 0;
+}
+
static bool streq(char const *a, char const *b) {
return strcmp(a, b) == 0;
}