Compare commits
10 commits
85cf184935
...
76a70a787b
Author | SHA1 | Date | |
---|---|---|---|
76a70a787b | |||
ce381dec2a | |||
38e77ee6f7 | |||
53d2f9369a | |||
3a2d45fb93 | |||
ee22df9211 | |||
1ec5502d46 | |||
b65b742403 | |||
d521cc0e83 | |||
05e2f21d27 |
17 changed files with 326 additions and 64 deletions
13
Makefile
13
Makefile
|
@ -1,12 +1,17 @@
|
|||
all : glslview glslwrite
|
||||
|
||||
USE_INOTIFY = -DUSE_INOTIFY
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
USE_INOTIFY ?= -DUSE_INOTIFY
|
||||
endif
|
||||
|
||||
CFLAGS = -O3 -Wall $(USE_INOTIFY)
|
||||
LIBS = -lSDL2 -lGL -lGLEW -lm
|
||||
CFLAGS ?= -O3 -Wall
|
||||
LIBS := -lSDL2 -lGL -lGLEW -lm
|
||||
|
||||
glslview : glslview.c common.c common.h
|
||||
$(CC) $(CFLAGS) -o $@ glslview.c common.c $(LIBS)
|
||||
$(CC) $(CFLAGS) $(USE_INOTIFY) -o $@ glslview.c common.c $(LIBS)
|
||||
|
||||
glslwrite : glslwrite.c common.c common.h
|
||||
$(CC) $(CFLAGS) -o $@ glslwrite.c common.c $(LIBS) -lpng
|
||||
|
||||
clean :
|
||||
rm -f glslview glslwrite
|
||||
|
|
129
README.txt
Normal file
129
README.txt
Normal file
|
@ -0,0 +1,129 @@
|
|||
glslview
|
||||
========
|
||||
|
||||
glslview is a simple program to run GLSL fragment shaders and interact with them.
|
||||
|
||||
glslview will render a simple fullscreen rectangle, the shader will determine each
|
||||
pixel's color.
|
||||
|
||||
The glslwrite tool can be used to write the generated frames to PNG files
|
||||
(with transparency support!).
|
||||
|
||||
You will need a graphics adapter and drivers with modern OpenGL/GLSL support.
|
||||
|
||||
Building
|
||||
~~~~~~~~
|
||||
|
||||
glslview has been tested on Linux only, but it should work on other systems as well.
|
||||
If it doesn't, I'm happy to take patches.
|
||||
|
||||
glslview has the following dependencies:
|
||||
|
||||
* SDL2
|
||||
* libGL
|
||||
* libGLEW
|
||||
|
||||
glslwrite additionally depends on libpng.
|
||||
|
||||
On Linux, glslview will use inotify to watch the loaded shader file for changes.
|
||||
|
||||
|
||||
Running
|
||||
~~~~~~~
|
||||
|
||||
Shader
|
||||
------
|
||||
|
||||
glslview will supply the following uniform parameters to the shader:
|
||||
|
||||
vec2 res
|
||||
The current resolution of the window
|
||||
|
||||
float time
|
||||
Current time in milliseconds (by default since start of the program)
|
||||
|
||||
int param0, param1, param2
|
||||
Modifiable parameters, 0 by default
|
||||
|
||||
The shader must define an output vec4 called "fragColor" into which the fragment color
|
||||
is to be written.
|
||||
|
||||
See the examples provided with the source for more information. The "symmetry"
|
||||
example makes use of all parameters.
|
||||
|
||||
|
||||
Command line
|
||||
------------
|
||||
|
||||
glslview <options> <shader>
|
||||
glslwrite <options> <shader> <output directory>
|
||||
|
||||
|
||||
Common options:
|
||||
|
||||
-w <width>
|
||||
Initial window width (default: 800)
|
||||
|
||||
-h <height>
|
||||
Initial window height (default: 800)
|
||||
|
||||
-0, -1, -2 <param>
|
||||
Initial value for the shader parameters
|
||||
|
||||
|
||||
glslview options:
|
||||
|
||||
-s <speed>
|
||||
Initial speed factor (default: 1.0, negative values make time run backwards)
|
||||
|
||||
-t <time>
|
||||
Initial time value (default: 0.0)
|
||||
|
||||
|
||||
glslwrite options:
|
||||
|
||||
-s <step>
|
||||
Time step between frames (default: 20.0)
|
||||
|
||||
-f <frame>
|
||||
Number of frames to generate (default: run forever)
|
||||
|
||||
|
||||
glslview control
|
||||
----------------
|
||||
|
||||
+/-, scroll wheel
|
||||
Change speed
|
||||
|
||||
=
|
||||
Reset speed
|
||||
|
||||
<
|
||||
Run backwards
|
||||
|
||||
>
|
||||
Run forwards
|
||||
|
||||
r
|
||||
Reset time
|
||||
|
||||
R
|
||||
Reset parameters
|
||||
|
||||
l
|
||||
Reload shader (if you're using a system without inotify, or inotify fails)
|
||||
|
||||
Space
|
||||
Pause/continue
|
||||
|
||||
Page up/down
|
||||
Modify param0
|
||||
|
||||
Left/right
|
||||
Modify param1
|
||||
|
||||
Up/down
|
||||
Modify param2
|
||||
|
||||
Escape
|
||||
Quit
|
6
common.c
6
common.c
|
@ -36,9 +36,9 @@
|
|||
char *filename;
|
||||
float current_time = 0;
|
||||
|
||||
GLint param0 = 0;
|
||||
GLint param1 = 0;
|
||||
GLint param2 = 0;
|
||||
int param0 = 0;
|
||||
int param1 = 0;
|
||||
int param2 = 0;
|
||||
|
||||
|
||||
static GLint time_loc;
|
||||
|
|
11
common.h
11
common.h
|
@ -25,18 +25,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
|
||||
|
||||
extern char *filename;
|
||||
extern float current_time;
|
||||
|
||||
extern GLint param0;
|
||||
extern GLint param1;
|
||||
extern GLint param2;
|
||||
extern int param0;
|
||||
extern int param1;
|
||||
extern int param2;
|
||||
|
||||
|
||||
void load(void);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
@ -56,13 +56,13 @@ void main(void) {
|
|||
float k = param1;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
mat3 t = scale(0.3 + 0.02 * param2)
|
||||
* rot(-PI/2*(k*i/n + time/1500))
|
||||
* trans(0.5, 0.0)
|
||||
* rot(2*PI*i/n)
|
||||
* scale(1 / (1 + 0.03 * param2));
|
||||
mat3 t = scale(1 + 0.03 * param2)
|
||||
* rot(-2*PI*i/n)
|
||||
* trans(-0.5, 0.0)
|
||||
* rot(PI/2*(k*i/n + time/1500))
|
||||
* scale(1 / (0.3 + 0.02 * param2));
|
||||
|
||||
float c = square(p * inverse(t));
|
||||
float c = square(p * t);
|
||||
scene = abs(scene - c);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#version 330
|
||||
#version 130
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
|
|
127
glslview.c
127
glslview.c
|
@ -25,14 +25,20 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
|
||||
#ifdef USE_INOTIFY
|
||||
# include <sys/inotify.h>
|
||||
# include <sys/stat.h>
|
||||
|
@ -40,6 +46,13 @@
|
|||
#endif
|
||||
|
||||
|
||||
static int init_param0 = 0;
|
||||
static int init_param1 = 0;
|
||||
static int init_param2 = 0;
|
||||
static float init_time = 0;
|
||||
static float init_speed = 1.0;
|
||||
|
||||
static bool paused = false;
|
||||
static float speed = 1.0;
|
||||
static unsigned previous_ticks = 0;
|
||||
|
||||
|
@ -53,22 +66,20 @@ static int inotify_watch = -1;
|
|||
static void reset_watch(void) {
|
||||
if (inotify_watch >= 0) {
|
||||
if (inotify_rm_watch(inotify_fd, inotify_watch)) {
|
||||
fprintf(stderr, "unable to remove watch\n");
|
||||
fprintf(stderr, "unable to remove watch: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
inotify_watch = inotify_add_watch(inotify_fd, filename, IN_CLOSE_WRITE);
|
||||
if (inotify_watch < 0) {
|
||||
fprintf(stderr, "unable to watch '%s' for changes\n", filename);
|
||||
return;
|
||||
}
|
||||
if (inotify_watch < 0)
|
||||
fprintf(stderr, "unable to watch '%s' for changes: %s\n", filename, strerror(errno));
|
||||
}
|
||||
|
||||
static void init_watch(void) {
|
||||
inotify_fd = inotify_init();
|
||||
if (inotify_fd < 0) {
|
||||
fprintf(stderr, "unable to initialize inotify\n");
|
||||
fprintf(stderr, "unable to initialize inotify: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -94,9 +105,20 @@ static void check_reload(void) {}
|
|||
|
||||
static void update(void) {
|
||||
unsigned ticks = SDL_GetTicks();
|
||||
current_time += speed * (ticks - previous_ticks);
|
||||
previous_ticks = ticks;
|
||||
|
||||
if (!paused)
|
||||
current_time += speed * (ticks - previous_ticks);
|
||||
|
||||
previous_ticks = ticks;
|
||||
}
|
||||
|
||||
static void set_speed(float v) {
|
||||
speed = v;
|
||||
printf("speed: %f\n", v);
|
||||
}
|
||||
|
||||
static void print_params(void) {
|
||||
printf("params: %i %i %i\n", (int)param0, (int)param1, (int)param2);
|
||||
}
|
||||
|
||||
static void handle_input(const char *input) {
|
||||
|
@ -108,45 +130,98 @@ static void handle_input(const char *input) {
|
|||
break;
|
||||
|
||||
case 'r':
|
||||
current_time = 0;
|
||||
current_time = init_time;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
param0 = param1 = param2 = 0;
|
||||
param0 = init_param0;
|
||||
param1 = init_param1;
|
||||
param2 = init_param2;
|
||||
print_params();
|
||||
break;
|
||||
|
||||
case '+':
|
||||
speed *= 1.1;
|
||||
set_speed(speed * 1.1);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
speed /= 1.1;
|
||||
set_speed(speed / 1.1);
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (speed < 0)
|
||||
speed = -1.0;
|
||||
set_speed(-init_speed);
|
||||
else
|
||||
speed = 1.0;
|
||||
set_speed(init_speed);
|
||||
break;
|
||||
|
||||
case '<':
|
||||
if (speed > 0)
|
||||
speed = -speed;
|
||||
set_speed(-speed);
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (speed < 0)
|
||||
speed = -speed;
|
||||
set_speed(-speed);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
paused = !paused;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: glslview <shader>\n");
|
||||
static void usage(void) {
|
||||
fprintf(stderr, "Usage: glslview [-w <width>] [-h <height>] [-t <time>] [-s <speed>] [-0 <param0>] [-1 <param1>] [-2 <param2>] <shader>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int width = 800, height = 800;
|
||||
|
||||
while (true) {
|
||||
int c = getopt(argc, argv, "w:h:t:s:0:1:2:");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'w':
|
||||
width = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
height = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
current_time = init_time = atof(optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
speed = atof(optarg);
|
||||
init_speed = fabsf(speed);
|
||||
break;
|
||||
|
||||
case '0':
|
||||
param0 = init_param0 = atoi(optarg);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
param1 = init_param1 = atoi(optarg);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
param2 = init_param2 = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Invalid option '%c'\n", optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind != 1)
|
||||
usage();
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
|
@ -155,10 +230,10 @@ int main(int argc, char *argv[]) {
|
|||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
|
||||
|
||||
SDL_Window *window = SDL_CreateWindow("glslview", 0, 0, 800, 800, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
|
||||
SDL_Window *window = SDL_CreateWindow("glslview", 0, 0, width, height, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
|
||||
SDL_GLContext ctx = SDL_GL_CreateContext(window);
|
||||
|
||||
filename = argv[1];
|
||||
filename = argv[optind];
|
||||
|
||||
init_watch();
|
||||
init();
|
||||
|
@ -175,26 +250,32 @@ int main(int argc, char *argv[]) {
|
|||
switch (e.key.keysym.sym) {
|
||||
case SDLK_PAGEDOWN:
|
||||
param0++;
|
||||
print_params();
|
||||
break;
|
||||
|
||||
case SDLK_PAGEUP:
|
||||
param0--;
|
||||
print_params();
|
||||
break;
|
||||
|
||||
case SDLK_RIGHT:
|
||||
param1++;
|
||||
print_params();
|
||||
break;
|
||||
|
||||
case SDLK_LEFT:
|
||||
param1--;
|
||||
print_params();
|
||||
break;
|
||||
|
||||
case SDLK_DOWN:
|
||||
param2++;
|
||||
print_params();
|
||||
break;
|
||||
|
||||
case SDLK_UP:
|
||||
param2--;
|
||||
print_params();
|
||||
break;
|
||||
|
||||
case SDLK_ESCAPE:
|
||||
|
@ -207,7 +288,7 @@ int main(int argc, char *argv[]) {
|
|||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
speed /= pow(1.1, e.wheel.y);
|
||||
set_speed(speed / pow(1.1, e.wheel.y));
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
|
|
70
glslwrite.c
70
glslwrite.c
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <png.h>
|
||||
|
||||
|
@ -36,12 +37,17 @@
|
|||
#include <SDL2/SDL_opengl.h>
|
||||
|
||||
|
||||
static float step = 20;
|
||||
static unsigned frame = 0;
|
||||
static unsigned max_frame = 0;
|
||||
|
||||
|
||||
static void savePNG(int width, int height, const char *output_dir) {
|
||||
uint8_t pixels[width*height*4];
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, pixels);
|
||||
|
||||
char filename[strlen(output_dir) + 20];
|
||||
snprintf(filename, sizeof(filename), "%s/%010u.png", output_dir, (unsigned)current_time);
|
||||
snprintf(filename, sizeof(filename), "%s/%010u.png", output_dir, frame);
|
||||
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
|
@ -84,11 +90,56 @@ static void savePNG(int width, int height, const char *output_dir) {
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: glslwrite <shader> <output directory>\n");
|
||||
static void usage(void) {
|
||||
fprintf(stderr, "Usage: glslwrite [-w <width>] [-h <height>] [-s <step>] [-f <frames>] [-0 <param0>] [-1 <param1>] [-2 <param2>] <shader>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int width = 800, height = 800;
|
||||
|
||||
while (true) {
|
||||
int c = getopt(argc, argv, "w:h:s:f:0:1:2:");
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'w':
|
||||
width = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
height = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
step = atof(optarg);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
max_frame = atoi(optarg);
|
||||
break;
|
||||
|
||||
case '0':
|
||||
param0 = atoi(optarg);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
param1 = atoi(optarg);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
param2 = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Invalid option '%c'\n", optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind != 2)
|
||||
usage();
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
|
@ -97,14 +148,14 @@ int main(int argc, char *argv[]) {
|
|||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
|
||||
|
||||
SDL_Window *window = SDL_CreateWindow("glslwrite", 0, 0, 800, 800, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
|
||||
SDL_Window *window = SDL_CreateWindow("glslwrite", 0, 0, width, height, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
|
||||
SDL_GLContext ctx = SDL_GL_CreateContext(window);
|
||||
|
||||
filename = argv[1];
|
||||
filename = argv[optind];
|
||||
init();
|
||||
load();
|
||||
|
||||
while (true) {
|
||||
while (!max_frame || frame < max_frame) {
|
||||
SDL_Event e;
|
||||
|
||||
while (SDL_PollEvent(&e)) {
|
||||
|
@ -128,8 +179,9 @@ int main(int argc, char *argv[]) {
|
|||
render(width, height);
|
||||
SDL_GL_SwapWindow(window);
|
||||
|
||||
savePNG(width, height, argv[2]);
|
||||
current_time += 20;
|
||||
savePNG(width, height, argv[optind+1]);
|
||||
current_time += step;
|
||||
frame++;
|
||||
}
|
||||
|
||||
quit:
|
||||
|
|
Reference in a new issue