diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | examples/polygon.frag | 54 | ||||
-rw-r--r-- | examples/snail.frag | 41 | ||||
-rw-r--r-- | examples/square-in-circle.frag | 66 | ||||
-rw-r--r-- | examples/square-in-square.frag | 74 | ||||
-rw-r--r-- | examples/square-ring.frag | 41 | ||||
-rw-r--r-- | examples/square-ring2.frag | 47 | ||||
-rw-r--r-- | examples/squares.frag | 42 | ||||
-rw-r--r-- | examples/supersnail.frag | 37 | ||||
-rw-r--r-- | examples/torus.frag | 41 | ||||
-rw-r--r-- | glslview.c | 10 | ||||
-rw-r--r-- | glslwrite.c | 204 |
13 files changed, 658 insertions, 5 deletions
@@ -1 +1,2 @@ glslview +glslwrite @@ -1,2 +1,7 @@ +all : glslview glslwrite + glslview : glslview.c gcc -o glslview glslview.c -lSDL2 -lGL -lGLEW -Wall + +glslwrite : glslwrite.c + gcc -o glslwrite glslwrite.c -lSDL2 -lpng -lGL -lGLEW -Wall diff --git a/examples/polygon.frag b/examples/polygon.frag new file mode 100644 index 0000000..20d5cdc --- /dev/null +++ b/examples/polygon.frag @@ -0,0 +1,54 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +const float PI = 3.14159265358979323846; + + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float poly(float n, vec2 m, float r, float rt, vec2 p) { + vec2 diff = (m - p) * rot(rt); + float d = length(diff); + float alpha = PI / n; + float gamma = mod(abs(atan(diff.x, diff.y)), alpha*2); + + if (gamma > alpha) + gamma -= 2*alpha; + + float r2 = r * cos(alpha) / cos(gamma); + + return clamp((r2 - d)*sharpness, 0.0, 1.0); +} + +float poly_d(float n, vec2 m, float r, float rt, vec2 p) { + return poly(n, m, r, rt, p) - poly(n, m, r - 1/sharpness, rt, p); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + float c; + + c = poly_d(5 - 3*cos(time/1000), vec2(0, 0), 0.5, PI * time/1000, p); + scene = abs(scene - c); + + c = poly_d(5 - 3*cos(time/1000), vec2(0, 0), 0.5, -PI * time/1000, p); + scene = abs(scene - c); + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/snail.frag b/examples/snail.frag new file mode 100644 index 0000000..491c53a --- /dev/null +++ b/examples/snail.frag @@ -0,0 +1,41 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float circle(vec2 m, float r, vec2 p) { + vec2 diff = m - p; + float d = sqrt(dot(diff, diff)); + + return clamp((r - d)*sharpness, 0.0, 1.0); +} + +float circle_d(vec2 m, float r, vec2 p) { + return circle(m, r, p) - circle(m, r - 1/sharpness, p); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + for (int i = 1; i <= 50; i++) { + float c = circle_d(vec2(0.5, 0) * rot(time/500/i), 0.1 + 0.005*i, p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/square-in-circle.frag b/examples/square-in-circle.frag new file mode 100644 index 0000000..ad6c615 --- /dev/null +++ b/examples/square-in-circle.frag @@ -0,0 +1,66 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +const float PI = 3.14159265358979323846; + + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float circle(vec2 m, float r, vec2 p) { + vec2 diff = m - p; + float d = sqrt(dot(diff, diff)); + + return clamp((r - d)*sharpness, 0.0, 1.0); +} + +float circle_d(vec2 m, float r, vec2 p) { + return circle(m, r, p) - circle(m, r - 1/sharpness, p); +} + +float square(vec2 m, float a, float r, vec2 p) { + vec2 diff = abs((m - p) * rot(r)); + float d = max(diff.x, diff.y); + + return clamp((a - d)*sharpness, 0.0, 1.0); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + int n = 20; + float b = 1; + float alpha = 0; + for (int i = 0; i < n; i++) { + float c; + + c = circle_d(vec2(0, 0), b, p); + scene = abs(scene - c); + + float delta = mod(time/5000, PI/2); + alpha = mod(alpha + delta, PI/2); + b /= sqrt(2); + + c = square(vec2(0, 0), b, alpha, p); + scene = abs(scene - c); + + c = square(vec2(0, 0), b, -alpha, p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/square-in-square.frag b/examples/square-in-square.frag new file mode 100644 index 0000000..cc00388 --- /dev/null +++ b/examples/square-in-square.frag @@ -0,0 +1,74 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +const float PI = 3.14159265358979323846; + + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float circle(vec2 m, float r, vec2 p) { + vec2 diff = m - p; + float d = sqrt(dot(diff, diff)); + + return clamp((r - d)*sharpness, 0.0, 1.0); +} + +float circle_d(vec2 m, float r, vec2 p) { + return circle(m, r, p) - circle(m, r - 1/sharpness, p); +} + +float square(vec2 m, float a, float r, vec2 p) { + vec2 diff = abs((m - p) * rot(r)); + float d = max(diff.x, diff.y); + + return clamp((a - d)*sharpness, 0.0, 1.0); +} + +float square_d(vec2 m, float a, float r, vec2 p) { + return square(m, a, r, p) - square(m, a - 1/sharpness, r, p); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + int n = 20; + float b = 1; + float alpha = 0; + for (int i = 0; i < n; i++) { + float delta = mod(time/5000, PI/2); + alpha = mod(alpha + delta, PI/2); + b /= (sin(delta) + cos(delta)); + + float c = square(vec2(0, 0), b, alpha, p); + scene = abs(scene - c); + } + + + b = 1; + alpha = 0; + for (int i = 0; i < n; i++) { + float delta = mod(-time/5000, PI/2); + alpha = mod(alpha + delta, PI/2); + b /= (sin(delta) + cos(delta)); + + float c = square(vec2(0, 0), b, alpha, p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/square-ring.frag b/examples/square-ring.frag new file mode 100644 index 0000000..1ef1c2c --- /dev/null +++ b/examples/square-ring.frag @@ -0,0 +1,41 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +const float PI = 3.14159265358979323846; + + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float square(vec2 m, float a, float r, vec2 p) { + vec2 diff = abs((m - p) * rot(r)); + float d = max(diff.x, diff.y); + + return clamp((a - d)*sharpness, 0.0, 1.0); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + int n = 10; + for (int i = 1; i <= n; i++) { + float c = square(vec2(0, 0), 0.5, PI/2*i/n - time/500, p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/square-ring2.frag b/examples/square-ring2.frag new file mode 100644 index 0000000..e90b633 --- /dev/null +++ b/examples/square-ring2.frag @@ -0,0 +1,47 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +const float PI = 3.14159265358979323846; + + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float square(vec2 m, float a, float r, vec2 p) { + vec2 diff = abs((m - p) * rot(r)); + float d = max(diff.x, diff.y); + + return clamp((a - d)*sharpness, 0.0, 1.0); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + int n = 5; + for (int i = 1; i <= n; i++) { + float c = square(vec2(0, 0), 0.5, PI/2*i/n - time/3000, p); + scene = abs(scene - c); + } + + n = 5; + for (int i = 1; i <= n; i++) { + float c = square(vec2(0, 0), 0.5, PI/2*i/n + time/3000, p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/squares.frag b/examples/squares.frag new file mode 100644 index 0000000..fd5dc94 --- /dev/null +++ b/examples/squares.frag @@ -0,0 +1,42 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 500; + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float square(vec2 m, float a, float r, vec2 p) { + vec2 diff = abs((m - p) * rot(r)); + float d = max(diff.x, diff.y); + + return clamp((a - d)*sharpness, 0.0, 1.0); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float a = atan(p.x, p.y); + + float x = mod(p.x, 0.1); + float y = mod(p.y, 0.1); + + float scene = 0; + + for (int i = 1; i <= 50; i++) { + float c = square(vec2(0.5, 0) * rot(time/500/i), 0.1 + 0.005*i, time/500/i + time/(100*i), p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/supersnail.frag b/examples/supersnail.frag new file mode 100644 index 0000000..154652a --- /dev/null +++ b/examples/supersnail.frag @@ -0,0 +1,37 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float circle(vec2 m, float r, vec2 p) { + vec2 diff = m - p; + float d = sqrt(dot(diff, diff)); + + return clamp((r - d)*sharpness, 0.0, 1.0); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + for (int i = 1; i <= 100; i++) { + float c = circle(vec2(0.5, 0) * rot(time/200/i), 0.1 + 0.002*i, p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} diff --git a/examples/torus.frag b/examples/torus.frag new file mode 100644 index 0000000..9758e1d --- /dev/null +++ b/examples/torus.frag @@ -0,0 +1,41 @@ +#version 330 + +out vec4 fragColor; + +uniform vec2 res; +uniform float time; + +const float sharpness = 300; + +const float PI = 3.14159265358979323846; + + +mat2 rot(float a) { + return mat2( + cos(a), -sin(a), + sin(a), cos(a) + ); +} + +float square(vec2 m, float a, float r, vec2 p) { + vec2 diff = abs((m - p) * rot(r)); + float d = max(diff.x, diff.y); + + return clamp((a - d)*sharpness, 0.0, 1.0); +} + +void main(void) { + vec2 m = res/2; + float s = min(m.x, m.y); + vec2 p = (gl_FragCoord.xy - m) / s; + + float scene = 0; + + int n = 48; + for (int i = 1; i <= n; i++) { + float c = square(vec2(0.5, 0) * rot(PI/2*(time/8000 + 4.0*i/n)) * vec2(1, 0.5), 0.1, PI/2*(24.0*i/n - time/800), p); + scene = abs(scene - c); + } + + fragColor = vec4(vec3(1, 1, 1) * scene, 1); +} @@ -13,7 +13,7 @@ static GLint time; static GLint res; -char * readfile(const char *filename) { +static char * readfile(const char *filename) { FILE *f = fopen(filename, "r"); if (!f) return NULL; @@ -39,7 +39,7 @@ char * readfile(const char *filename) { return buffer; } -void printShaderInfoLog(GLuint obj) { +static void printShaderInfoLog(GLuint obj) { GLint length = 0; glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length); @@ -52,7 +52,7 @@ void printShaderInfoLog(GLuint obj) { } } -void printProgramInfoLog(GLuint obj) { +static void printProgramInfoLog(GLuint obj) { GLint length = 0; glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &length); @@ -65,7 +65,7 @@ void printProgramInfoLog(GLuint obj) { } } -void init(char *filename) { +static void init(char *filename) { glewInit(); glDisable(GL_DEPTH_TEST); @@ -96,7 +96,7 @@ void init(char *filename) { } -void render(SDL_Window *window) { +static void render(SDL_Window *window) { int width, height; SDL_GetWindowSize(window, &width, &height); diff --git a/glslwrite.c b/glslwrite.c new file mode 100644 index 0000000..ebe81d4 --- /dev/null +++ b/glslwrite.c @@ -0,0 +1,204 @@ +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> + +#include <png.h> + +#include <GL/glew.h> + +#include <SDL2/SDL.h> +#include <SDL2/SDL_opengl.h> + + + +static unsigned frame_time = 0; + + +static GLint time_loc; +static GLint res_loc; + + +static char * readfile(const char *filename) { + FILE *f = fopen(filename, "r"); + if (!f) + return NULL; + + size_t size = 1024; + char *buffer = malloc(size+1); + size_t count = 0, r; + + do { + if (count == size) { + size *= 2; + buffer = realloc(buffer, size+1); + } + + r = fread(buffer+count, 1, size-count, f); + count += r; + } while (r); + + fclose(f); + + buffer[count] = 0; + + return buffer; +} + +static void printShaderInfoLog(GLuint obj) { + GLint length = 0; + + glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length); + + if(length > 0) { + char log[length]; + + glGetShaderInfoLog(obj, sizeof(log), NULL, log); + fprintf(stderr, "%s\n", log); + } +} + +static void printProgramInfoLog(GLuint obj) { + GLint length = 0; + + glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &length); + + if(length > 0) { + char log[length]; + + glGetProgramInfoLog(obj, sizeof(log), NULL, log); + fprintf(stderr, "%s\n", log); + } +} + +static void init(char *filename) { + glewInit(); + + glDisable(GL_DEPTH_TEST); + + char *shader = readfile(filename); + if (!shader) { + fprintf(stderr, "Error: unable to read '%s'\n", filename); + exit(1); + } + + GLuint frag = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(frag, 1, (const GLchar **)&shader, NULL); + glCompileShader(frag); + printShaderInfoLog(frag); + + GLuint program = glCreateProgram(); + glAttachShader(program, frag); + + glLinkProgram(program); + printProgramInfoLog(program); + + glBindFragDataLocation(program, 0, "fragColor"); + time_loc = glGetUniformLocation(program, "time"); + res_loc = glGetUniformLocation(program, "res"); + + glUseProgram(program); +} + +static void savePNG(uint8_t *pixels, int width, int height, const char *output_dir) { + char filename[strlen(output_dir) + 20]; + snprintf(filename, sizeof(filename), "%s/%010u.png", output_dir, frame_time); + + FILE *f = fopen(filename, "wb"); + if (!f) { + fprintf(stderr, "unable to open PNG file\n"); + exit(1); + } + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { + fprintf(stderr, "unable to open PNG file\n"); + exit(1); + } + + png_set_swap_alpha(png_ptr); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + fprintf(stderr, "unable to create PNG info struct\n"); + exit(1); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + fprintf(stderr, "unable to write PNG file\n"); + exit(1); + } + + png_init_io(png_ptr, f); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + uint8_t *row_pointers[height]; + for (size_t i = 0; i < height; i++) + row_pointers[i] = &pixels[4*i*width]; + + png_set_rows(png_ptr, info_ptr, row_pointers); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(f); +} + +static void render(SDL_Window *window, const char *output_dir) { + int width, height; + SDL_GetWindowSize(window, &width, &height); + + glViewport(0, 0, (GLsizei)width, (GLsizei)height); + + glUniform1f(time_loc, frame_time); + glUniform2f(res_loc, width, height); + + glBegin(GL_QUADS); + glVertex2f(-1, -1); + glVertex2f(1, -1); + glVertex2f(1, 1); + glVertex2f(-1, 1); + glEnd(); + + SDL_GL_SwapWindow(window); + + uint8_t pixels[width*height*4]; + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, pixels); + savePNG(pixels, width, height, output_dir); + + frame_time += 20; +} + + +int main(int argc, char *argv[]) { + bool running = true; + + if (argc != 3) { + fprintf(stderr, "Usage: glslwrite <shader> <output directory>\n"); + exit(1); + } + + SDL_Init(SDL_INIT_VIDEO); + + SDL_Window *window = SDL_CreateWindow("glslwrite", 0, 0, 800, 800, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); + SDL_GL_CreateContext(window); + + init(argv[1]); + + while (running) { + SDL_Event e; + + while( SDL_PollEvent(&e)) { + if(e.type == SDL_QUIT) { + running = false; + break; + } + } + + render(window, argv[2]); + //usleep(1); + } + + return 0; +} |