mandelbrot

Mandelbrot viewer written in C and GLSL
git clone anongit@rnpnr.xyz:mandelbrot.git
Log | Files | Refs | Feed | LICENSE

Commit: 80000759cf0be58e8c8288ba802842a0ab6ce9e9
Parent: 0bf15dc5e7dca2380ac36205fc781de8cc034872
Author: Randy Palamar
Date:   Wed, 22 May 2024 20:10:57 -0600

add shader hot reloading

Also move file reading to platform specific file.

Diffstat:
Mmain.c | 57+++++++++++++++++++++++++++++----------------------------
Aos_unix.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+), 28 deletions(-)

diff --git a/main.c b/main.c @@ -1,10 +1,8 @@ /* see LICENSE for licensing details */ -#include <fcntl.h> #include <stddef.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> -#include <unistd.h> #include <GL/gl.h> #include <GLES3/gl32.h> @@ -18,6 +16,12 @@ typedef ptrdiff_t size; typedef struct { size len; u8 *data; } s8; +#ifdef __unix__ +#include "os_unix.c" +#else +#error Unsupported Platform! +#endif + typedef union { struct { u8 a, b, g, r; }; u32 rgba; @@ -137,29 +141,6 @@ spawn_window(void) return 0; } -static s8 -read_whole_file(char *file) -{ - s8 ret = {0}; - i32 fd = open(file, O_RDONLY); - if (fd < 0) - return ret; - ret.len = lseek(fd, 0L, SEEK_END); - ret.data = malloc(ret.len); - lseek(fd, 0L, SEEK_SET); - if (ret.data == NULL) { - ret.len = 0; - close(fd); - return ret; - } - if (ret.len != read(fd, ret.data, ret.len)) { - ret.len = 0; - free(ret.data); - } - close(fd); - return ret; -} - static u32 compile_shader(u32 type, s8 s) { @@ -188,8 +169,8 @@ compile_shader(u32 type, s8 s) static i32 program_from_files(char *vert, char *frag) { - s8 vertex = read_whole_file(vert); - s8 fragment = read_whole_file(frag); + s8 vertex = os_read_file(vert); + s8 fragment = os_read_file(frag); if (vertex.len == 0 || fragment.len == 0) return -1; i32 pid = glCreateProgram(); @@ -217,6 +198,21 @@ program_from_files(char *vert, char *frag) return pid; } +static os_file_stats +check_and_update_shader(os_file_stats test_stats, char *test_file) +{ + os_file_stats new_stats = os_get_file_stats(test_file); + if (os_compare_filetime(test_stats.timestamp, new_stats.timestamp)) { + i32 pid = program_from_files("vert.glsl", "frag.glsl"); + if (pid > 0) { + glDeleteProgram(g_glctx.pid); + g_glctx.pid = pid; + glUseProgram(g_glctx.pid); + } + } + return new_stats; +} + int main(void) { @@ -231,6 +227,8 @@ main(void) return -1; } + os_file_stats vert_stats = os_get_file_stats("vert.glsl"); + os_file_stats frag_stats = os_get_file_stats("frag.glsl"); g_glctx.pid = program_from_files("vert.glsl", "frag.glsl"); if (g_glctx.pid == -1) { glfwTerminate(); @@ -250,7 +248,10 @@ main(void) 1 / dt, dt * 1e3); fcount = 0; } - + + vert_stats = check_and_update_shader(vert_stats, "vert.glsl"); + frag_stats = check_and_update_shader(frag_stats, "frag.glsl"); + clear_colour(g_glctx.clear_colour); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glfwSwapBuffers(g_glctx.window); diff --git a/os_unix.c b/os_unix.c @@ -0,0 +1,52 @@ +/* see LICENSE for licensing details */ +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +typedef struct timespec os_filetime; + +typedef struct { + size filesize; + os_filetime timestamp; +} os_file_stats; + +static os_file_stats +os_get_file_stats(char *file) +{ + struct stat sb; + if (stat(file, &sb) < 0) + return (os_file_stats){0}; + return (os_file_stats){ + .filesize = sb.st_size, + .timestamp = sb.st_mtim, + }; +} + +static s8 +os_read_file(char *file) +{ + s8 ret = {0}; + i32 fd = open(file, O_RDONLY); + if (fd < 0) + return ret; + ret.len = lseek(fd, 0L, SEEK_END); + ret.data = malloc(ret.len); + lseek(fd, 0L, SEEK_SET); + if (ret.data == NULL) { + ret.len = 0; + close(fd); + return ret; + } + if (ret.len != read(fd, ret.data, ret.len)) { + ret.len = 0; + free(ret.data); + } + close(fd); + return ret; +} + +static i32 +os_compare_filetime(os_filetime a, os_filetime b) +{ + return (a.tv_sec - b.tv_sec) + (a.tv_nsec - b.tv_nsec); +}