Initial commit

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
This commit is contained in:
David Oberhollenzer 2022-07-16 22:01:12 +02:00
commit acaef93bd8
11 changed files with 1182 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.o
*~
shadermeh

12
Makefile Normal file
View file

@ -0,0 +1,12 @@
CFLAGS = -ansi -pedantic -Wall -Wextra -O2 -Ofast -D_DEFAULT_SOURCE
LDFLAGS = -lX11 -lGL -lGLEW -lm -lrt
shadermeh: shadermeh.o window.o shader.o
window.o: window.c shadermeh.h
shader.o: shader.c shadermeh.h
shadermeh.o: shadermeh.c shadermeh.h
.PHONY: clean
clean:
$(RM) shadermeh *.o

181
shader.c Normal file
View file

@ -0,0 +1,181 @@
#include "shadermeh.h"
/* stub vertex shader */
static const char *vert_src =
"#version 140\n"
"\n"
"in vec4 V_POSITION;\n"
"in vec4 V_COLOR;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = V_POSITION;\n"
"}\n";
/* stub fragment shader */
static const char *frag_src_pre =
"#version 330\n"
"\n"
"uniform vec3 iResolution;\n"
"uniform float iTime;\n"
"uniform float iTimeDelta;\n"
"uniform float iFrame;\n"
"uniform float iChannelTime[4];\n"
"uniform vec4 iMouse;\n"
"uniform vec4 iDate;\n"
"uniform float iSampleRate;\n"
"uniform vec3 iChannelResolution[4];\n"
"\n";
static const char *frag_src_post =
"\n"
"void main()\n"
"{\n"
" mainImage(gl_FragColor, gl_FragCoord.xy);\n"
"}\n"
"\n";
static char* load_file(const char *path)
{
size_t size, pre_len, post_len;
char *buffer;
FILE *f;
if (!path)
return NULL;
/* try to open the file */
f = fopen(path, "r");
if (!f) {
perror(path);
return NULL;
}
/* get file size */
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
pre_len = strlen(frag_src_pre);
post_len = strlen(frag_src_post);
/* try to allocate buffer for file contents */
buffer = calloc(1, pre_len + size + post_len + 1);
if (!buffer) {
fclose(f);
return NULL;
}
/* read file contents into buffer */
memcpy(buffer, frag_src_pre, pre_len);
fread(buffer + pre_len, 1, size, f);
memcpy(buffer + pre_len + size, frag_src_post, post_len);
/* cleanup */
fclose(f);
return buffer;
}
/****************************************************************************/
GLuint shader_program_load(const char *fsrc)
{
GLuint vsh = 0, fsh = 0, prog = 0;
char *fs = NULL;
if (!fsrc)
return 0;
fs = load_file(fsrc);
if (!fs)
goto done;
vsh = glCreateShader(GL_VERTEX_SHADER);
fsh = glCreateShader(GL_FRAGMENT_SHADER);
if (!vsh || !fsh)
goto done;
prog = glCreateProgram();
if (!prog)
goto done;
glShaderSource(vsh, 1, (const GLchar **)&vert_src, NULL);
glShaderSource(fsh, 1, (const GLchar **)&fs, NULL);
glCompileShader(vsh);
glCompileShader(fsh);
glAttachShader(prog, vsh);
glAttachShader(prog, fsh);
glLinkProgram(prog);
done:
if (vsh)
glDeleteShader(vsh);
if (fsh)
glDeleteShader(fsh);
free(fs);
return prog;
}
int shader_program_get_build_status(GLuint prog)
{
GLuint shaders[3];
GLsizei i, count;
GLint v;
glGetProgramiv(prog, GL_LINK_STATUS, &v);
if (!v)
return 0;
glGetAttachedShaders(prog, 3, &count, shaders);
for (i = 0; i < count; ++i) {
glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &v);
if (!v)
return 0;
}
return 1;
}
void shader_program_print_info_log(GLuint prog)
{
GLsizei i, count, len;
char *buffer = NULL;
int buffersize = 0;
GLuint shaders[3];
GLint v;
glGetAttachedShaders(prog, 3, &count, shaders);
for (i = 0; i < count; ++i) {
glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &v);
if ((v + 1) > buffersize) {
buffer = realloc(buffer, v + 1);
buffersize = v + 1;
}
glGetShaderInfoLog(shaders[i], buffersize,
&len, (GLchar *)buffer);
buffer[len] = '\0';
printf("-------------\n%s\n-------------\n", buffer);
}
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &v);
if ((v + 1) > buffersize) {
buffer = realloc(buffer, v + 1);
buffersize = v + 1;
}
glGetProgramInfoLog(prog, buffersize, &len, (GLchar *)buffer);
buffer[len] = '\0';
printf("-------------\n%s\n-------------\n", buffer);
free(buffer);
}

179
shadermeh.c Normal file
View file

@ -0,0 +1,179 @@
#include "shadermeh.h"
static GLfloat vertex_buffer[] = {
-1.0f, -1.0f, 0.0f, /* lower left corner */
1.0f, 1.0f, 1.0f,
+1.0f, -1.0f, 0.0f, /* lower right corner */
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, /* uper left corner */
1.0f, 1.0f, 1.0f,
+1.0f, +1.0f, 0.0f, /* upper right corner */
1.0f, 1.0f, 1.0f,
};
static double diff_timespec(const struct timespec *time1,
const struct timespec *time0)
{
return (time1->tv_sec - time0->tv_sec)
+ (time1->tv_nsec - time0->tv_nsec) / 1000000000.0;
}
static const struct option long_opts[] = {
{ "width", required_argument, NULL, 'w' },
{ "height", required_argument, NULL, 'h' },
{ "shader", required_argument, NULL, 's' },
{ NULL, 0, NULL, 0 },
};
static const char *short_opts = "w:h:s:";
static const char *usage_str =
"shadermeh OPTIONS...\n"
"\n"
"Possible options:\n"
"\n"
" --width, -w <pixels>\n"
" --height, -h <pixels>\n"
"\n"
" --shader, -s <shader file>\n"
"\n";
int main(int argc, char **argv)
{
GLuint u_iResolution, u_iTime, u_iTimeDelta, u_iFrame;
struct timespec start, frame_start, frame_end;
unsigned int width, height, iFrame = 0;
const char *shader_file = NULL;
GLint major, minor, prog;
float iTime, iTimeDelta;
GLuint vao, vbo;
window *wnd;
int i;
/******************** parse options ************************/
width = 800;
height = 450;
for (;;) {
i = getopt_long(argc, argv, short_opts, long_opts, NULL);
if (i == -1)
break;
switch (i) {
case 'w':
width = strtol(optarg, NULL, 10);
break;
case 'h':
height = strtol(optarg, NULL, 10);
break;
case 's':
shader_file = optarg;
break;
default:
fputs(usage_str, stderr);
return EXIT_FAILURE;
}
}
if (!shader_file) {
fputs(usage_str, stderr);
fputs("No shader file specified!\n", stderr);
return EXIT_FAILURE;
}
/********** create window and make context current **********/
wnd = window_create(width, height, "shader meh...");
if (!wnd) {
fputs("failed to create window", stderr);
return EXIT_FAILURE;
}
window_make_current(wnd);
window_set_vsync(wnd, 1);
/******************** load entry points ********************/
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
fputs("glewInit() error", stderr);
window_destroy(wnd);
return EXIT_FAILURE;
}
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
printf("OpenGL version %d.%d\n", major, minor);
/******************** initialization ********************/
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/* vertex buffer object & vertex array object */
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_buffer),
vertex_buffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6,
(GLvoid *)(3 * sizeof(GLfloat)));
/* shader */
prog = shader_program_load(shader_file);
if (!shader_program_get_build_status(prog)) {
shader_program_print_info_log(prog);
}
glUseProgram(prog);
/* uniforms */
u_iResolution = glGetUniformLocation(prog, "iResolution");
u_iTime = glGetUniformLocation(prog, "iTime");
u_iTimeDelta = glGetUniformLocation(prog, "iTimeDelta");
u_iFrame = glGetUniformLocation(prog, "iFrame;");
glUniform3f(u_iResolution, width, height, 0.0f);
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
/******************** drawing loop ********************/
while (window_handle_events()) {
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_start);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
window_swap_buffers(wnd);
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_end);
iFrame += 1;
iTimeDelta = diff_timespec(&frame_end, &frame_start);
iTime = diff_timespec(&frame_end, &start);
glUniform1f(u_iTimeDelta, iTimeDelta);
glUniform1f(u_iTime, iTime);
glUniform1ui(u_iFrame, iFrame);
}
/******************** cleanup ********************/
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &vbo);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(prog);
window_make_current(NULL);
window_destroy(wnd);
return EXIT_SUCCESS;
}

45
shadermeh.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef SHADERMEH_H
#define SHADERMEH_H
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
typedef struct {
Window wnd;
GLXContext gl;
} window;
window *window_create(unsigned int width, unsigned int height,
const char *caption);
void window_make_current(window *wnd);
void window_swap_buffers(window *wnd);
void window_set_vsync(window *wnd, int enable);
void window_destroy(window *wnd);
int window_handle_events(void);
GLuint shader_program_load(const char *fsh);
int shader_program_get_build_status(GLuint prog);
void shader_program_print_info_log(GLuint prog);
#endif /* SHADERMEH_H */

158
shaders/cyber.frag Normal file
View file

@ -0,0 +1,158 @@
float sun(vec2 uv, float battery)
{
float val = smoothstep(0.3, 0.29, length(uv));
float bloom = smoothstep(0.7, 0.0, length(uv));
float cut = 3.0 * sin((uv.y + iTime * 0.2 * (battery + 0.02)) * 100.0)
+ clamp(uv.y * 14.0 + 1.0, -6.0, 6.0);
cut = clamp(cut, 0.0, 1.0);
return clamp(val * cut, 0.0, 1.0) + bloom * 0.6;
}
float grid(vec2 uv, float battery)
{
vec2 size = vec2(uv.y, uv.y * uv.y * 0.2) * 0.01;
uv += vec2(0.0, iTime * 4.0 * (battery + 0.05));
uv = abs(fract(uv) - 0.5);
vec2 lines = smoothstep(size, vec2(0.0), uv);
lines += smoothstep(size * 5.0, vec2(0.0), uv) * 0.4 * battery;
return clamp(lines.x + lines.y, 0.0, 3.0);
}
float dot2(in vec2 v ) { return dot(v,v); }
float sdTrapezoid( in vec2 p, in float r1, float r2, float he )
{
vec2 k1 = vec2(r2,he);
vec2 k2 = vec2(r2-r1,2.0*he);
p.x = abs(p.x);
vec2 ca = vec2(p.x-min(p.x,(p.y<0.0)?r1:r2), abs(p.y)-he);
vec2 cb = p - k1 + k2*clamp( dot(k1-p,k2)/dot2(k2), 0.0, 1.0 );
float s = (cb.x<0.0 && ca.y<0.0) ? -1.0 : 1.0;
return s*sqrt( min(dot2(ca),dot2(cb)) );
}
float sdLine( in vec2 p, in vec2 a, in vec2 b )
{
vec2 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba*h );
}
float sdBox( in vec2 p, in vec2 b )
{
vec2 d = abs(p)-b;
return length(max(d,vec2(0))) + min(max(d.x,d.y),0.0);
}
float opSmoothUnion(float d1, float d2, float k){
float h = clamp(0.5 + 0.5 * (d2 - d1) /k,0.0,1.0);
return mix(d2, d1 , h) - k * h * ( 1.0 - h);
}
float sdCloud(in vec2 p, in vec2 a1, in vec2 b1, in vec2 a2, in vec2 b2, float w)
{
//float lineVal1 = smoothstep(w - 0.0001, w, sdLine(p, a1, b1));
float lineVal1 = sdLine(p, a1, b1);
float lineVal2 = sdLine(p, a2, b2);
vec2 ww = vec2(w*1.5, 0.0);
vec2 left = max(a1 + ww, a2 + ww);
vec2 right = min(b1 - ww, b2 - ww);
vec2 boxCenter = (left + right) * 0.5;
//float boxW = right.x - left.x;
float boxH = abs(a2.y - a1.y) * 0.5;
//float boxVal = sdBox(p - boxCenter, vec2(boxW, boxH)) + w;
float boxVal = sdBox(p - boxCenter, vec2(0.04, boxH)) + w;
float uniVal1 = opSmoothUnion(lineVal1, boxVal, 0.05);
float uniVal2 = opSmoothUnion(lineVal2, boxVal, 0.05);
return min(uniVal1, uniVal2);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (2.0 * fragCoord.xy - iResolution.xy)/iResolution.y;
float battery = 1.0;
//if (iMouse.x > 1.0 && iMouse.y > 1.0) battery = iMouse.y / iResolution.y;
//else battery = 0.8;
//if (abs(uv.x) < (9.0 / 16.0))
{
// Grid
float fog = smoothstep(0.1, -0.02, abs(uv.y + 0.2));
vec3 col = vec3(0.0, 0.1, 0.2);
if (uv.y < -0.2)
{
uv.y = 3.0 / (abs(uv.y + 0.2) + 0.05);
uv.x *= uv.y * 1.0;
float gridVal = grid(uv, battery);
col = mix(col, vec3(1.0, 0.5, 1.0), gridVal);
}
else
{
float fujiD = min(uv.y * 4.5 - 0.5, 1.0);
uv.y -= battery * 1.1 - 0.51;
vec2 sunUV = uv;
vec2 fujiUV = uv;
// Sun
sunUV += vec2(0.75, 0.2);
//uv.y -= 1.1 - 0.51;
col = vec3(1.0, 0.2, 1.0);
float sunVal = sun(sunUV, battery);
col = mix(col, vec3(1.0, 0.4, 0.1), sunUV.y * 2.0 + 0.2);
col = mix(vec3(0.0, 0.0, 0.0), col, sunVal);
// fuji
float fujiVal = sdTrapezoid( uv + vec2(-0.75+sunUV.y * 0.0, 0.5), 1.75 + pow(uv.y * uv.y, 2.1), 0.2, 0.5);
float waveVal = uv.y + sin(uv.x * 20.0 + iTime * 2.0) * 0.05 + 0.2;
float wave_width = smoothstep(0.0,0.01,(waveVal));
// fuji color
col = mix( col, mix(vec3(0.0, 0.0, 0.25), vec3(1.0, 0.0, 0.5), fujiD), step(fujiVal, 0.0));
// fuji top snow
col = mix( col, vec3(1.0, 0.5, 1.0), wave_width * step(fujiVal, 0.0));
// fuji outline
col = mix( col, vec3(1.0, 0.5, 1.0), 1.0-smoothstep(0.0,0.01,abs(fujiVal)) );
//col = mix( col, vec3(1.0, 1.0, 1.0), 1.0-smoothstep(0.03,0.04,abs(fujiVal)) );
//col = vec3(1.0, 1.0, 1.0) *(1.0-smoothstep(0.03,0.04,abs(fujiVal)));
// horizon color
col += mix( col, mix(vec3(1.0, 0.12, 0.8), vec3(0.0, 0.0, 0.2), clamp(uv.y * 3.5 + 3.0, 0.0, 1.0)), step(0.0, fujiVal) );
// cloud
vec2 cloudUV = uv;
cloudUV.x = mod(cloudUV.x + iTime * 0.1, 4.0) - 2.0;
float cloudTime = iTime * 0.5;
float cloudY = -0.5;
float cloudVal1 = sdCloud(cloudUV,
vec2(0.1 + sin(cloudTime + 140.5)*0.1,cloudY),
vec2(1.05 + cos(cloudTime * 0.9 - 36.56) * 0.1, cloudY),
vec2(0.2 + cos(cloudTime * 0.867 + 387.165) * 0.1,0.25+cloudY),
vec2(0.5 + cos(cloudTime * 0.9675 - 15.162) * 0.09, 0.25+cloudY), 0.075);
cloudY = -0.6;
float cloudVal2 = sdCloud(cloudUV,
vec2(-0.9 + cos(cloudTime * 1.02 + 541.75) * 0.1,cloudY),
vec2(-0.5 + sin(cloudTime * 0.9 - 316.56) * 0.1, cloudY),
vec2(-1.5 + cos(cloudTime * 0.867 + 37.165) * 0.1,0.25+cloudY),
vec2(-0.6 + sin(cloudTime * 0.9675 + 665.162) * 0.09, 0.25+cloudY), 0.075);
float cloudVal = min(cloudVal1, cloudVal2);
//col = mix(col, vec3(1.0,1.0,0.0), smoothstep(0.0751, 0.075, cloudVal));
col = mix(col, vec3(0.0, 0.0, 0.2), 1.0 - smoothstep(0.075 - 0.0001, 0.075, cloudVal));
col += vec3(1.0, 1.0, 1.0)*(1.0 - smoothstep(0.0,0.01,abs(cloudVal - 0.075)));
}
col += fog * fog * fog;
col = mix(vec3(col.r, col.r, col.r) * 0.5, col, battery * 0.7);
fragColor = vec4(col,1.0);
}
//else fragColor = vec4(0.0);
}

66
shaders/fractal.frag Normal file
View file

@ -0,0 +1,66 @@
vec3 palette(float d){
return mix(vec3(0.2,0.7,0.9),vec3(1.,0.,1.),d);
}
vec2 rotate(vec2 p,float a){
float c = cos(a);
float s = sin(a);
return p*mat2(c,s,-s,c);
}
float map(vec3 p){
for( int i = 0; i<8; ++i){
float t = iTime*0.2;
p.xz =rotate(p.xz,t);
p.xy =rotate(p.xy,t*1.89);
p.xz = abs(p.xz);
p.xz-=.5;
}
return dot(sign(p),p)/5.;
}
vec4 rm (vec3 ro, vec3 rd){
float t = 0.;
vec3 col = vec3(0.);
float d;
for(float i =0.; i<64.; i++){
vec3 p = ro + rd*t;
d = map(p)*.5;
if(d<0.02){
break;
}
if(d>100.){
break;
}
//col+=vec3(0.6,0.8,0.8)/(400.*(d));
col+=palette(length(p)*.1)/(400.*(d));
t+=d;
}
return vec4(col,1./(d*100.));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord-(iResolution.xy/2.))/iResolution.x;
vec3 ro = vec3(0.,0.,-50.);
ro.xz = rotate(ro.xz,iTime);
vec3 cf = normalize(-ro);
vec3 cs = normalize(cross(cf,vec3(0.,1.,0.)));
vec3 cu = normalize(cross(cf,cs));
vec3 uuv = ro+cf*3. + uv.x*cs + uv.y*cu;
vec3 rd = normalize(uuv-ro);
vec4 col = rm(ro,rd);
fragColor = col;
}
/** SHADERDATA
{
"title": "fractal pyramid",
"description": "",
"model": "car"
}
*/

26
shaders/mandelbrot.frag Normal file
View file

@ -0,0 +1,26 @@
#define MAX_ITERATIONS 1024
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
float s = exp(-iTime / 2.0);
vec2 c = vec2(-0.770007,0.100001);
vec2 z = vec2(0.0);
vec2 del = (2.0 * fragCoord/iResolution.xy - 1.0) * s;
del.x /= (iResolution.y / iResolution.x);
vec2 eps = vec2(0.0);
int iterations = 0;
while (length(z + eps) < 2.0 && iterations < MAX_ITERATIONS) {
eps = 2.0*vec2(z.x*eps.x - z.y*eps.y, z.x*eps.y + z.y*eps.x) + vec2(eps.x*eps.x - eps.y*eps.y, 2.0*eps.x*eps.y) + del;
z = vec2(z.x*z.x - z.y*z.y, 2.0*z.x*z.y) + c;
if (length(eps) > 100.0) {
z += eps;
eps = vec2(0.0);
}
iterations += 1;
}
// Output to screen
fragColor = vec4(vec3(float(iterations) / float(MAX_ITERATIONS)), 1.0);
}

204
shaders/seascape.frag Normal file
View file

@ -0,0 +1,204 @@
/*
* "Seascape" by Alexander Alekseev aka TDM - 2014
* License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
* Contact: tdmaav@gmail.com
*/
const int NUM_STEPS = 8;
const float PI = 3.141592;
const float EPSILON = 1e-3;
#define EPSILON_NRM (0.1 / iResolution.x)
#define AA
// sea
const int ITER_GEOMETRY = 3;
const int ITER_FRAGMENT = 5;
const float SEA_HEIGHT = 0.6;
const float SEA_CHOPPY = 4.0;
const float SEA_SPEED = 0.8;
const float SEA_FREQ = 0.16;
const vec3 SEA_BASE = vec3(0.0,0.09,0.18);
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6)*0.6;
#define SEA_TIME (1.0 + iTime * SEA_SPEED)
const mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
// math
mat3 fromEuler(vec3 ang) {
vec2 a1 = vec2(sin(ang.x),cos(ang.x));
vec2 a2 = vec2(sin(ang.y),cos(ang.y));
vec2 a3 = vec2(sin(ang.z),cos(ang.z));
mat3 m;
m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
return m;
}
float hash( vec2 p ) {
float h = dot(p,vec2(127.1,311.7));
return fract(sin(h)*43758.5453123);
}
float noise( in vec2 p ) {
vec2 i = floor( p );
vec2 f = fract( p );
vec2 u = f*f*(3.0-2.0*f);
return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ),
hash( i + vec2(1.0,0.0) ), u.x),
mix( hash( i + vec2(0.0,1.0) ),
hash( i + vec2(1.0,1.0) ), u.x), u.y);
}
// lighting
float diffuse(vec3 n,vec3 l,float p) {
return pow(dot(n,l) * 0.4 + 0.6,p);
}
float specular(vec3 n,vec3 l,vec3 e,float s) {
float nrm = (s + 8.0) / (PI * 8.0);
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
// sky
vec3 getSkyColor(vec3 e) {
e.y = (max(e.y,0.0)*0.8+0.2)*0.8;
return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4) * 1.1;
}
// sea
float sea_octave(vec2 uv, float choppy) {
uv += noise(uv);
vec2 wv = 1.0-abs(sin(uv));
vec2 swv = abs(cos(uv));
wv = mix(wv,swv,wv);
return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
}
float map(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_GEOMETRY; i++) {
d = sea_octave((uv+SEA_TIME)*freq,choppy);
d += sea_octave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
float map_detailed(vec3 p) {
float freq = SEA_FREQ;
float amp = SEA_HEIGHT;
float choppy = SEA_CHOPPY;
vec2 uv = p.xz; uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < ITER_FRAGMENT; i++) {
d = sea_octave((uv+SEA_TIME)*freq,choppy);
d += sea_octave((uv-SEA_TIME)*freq,choppy);
h += d * amp;
uv *= octave_m; freq *= 1.9; amp *= 0.22;
choppy = mix(choppy,1.0,0.2);
}
return p.y - h;
}
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0);
fresnel = pow(fresnel,3.0) * 0.5;
vec3 reflected = getSkyColor(reflect(eye,n));
vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;
vec3 color = mix(refracted,reflected,fresnel);
float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
color += vec3(specular(n,l,eye,60.0));
return color;
}
// tracing
vec3 getNormal(vec3 p, float eps) {
vec3 n;
n.y = map_detailed(p);
n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
n.y = eps;
return normalize(n);
}
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
float tm = 0.0;
float tx = 1000.0;
float hx = map(ori + dir * tx);
if(hx > 0.0) {
p = ori + dir * tx;
return tx;
}
float hm = map(ori + dir * tm);
float tmid = 0.0;
for(int i = 0; i < NUM_STEPS; i++) {
tmid = mix(tm,tx, hm/(hm-hx));
p = ori + dir * tmid;
float hmid = map(p);
if(hmid < 0.0) {
tx = tmid;
hx = hmid;
} else {
tm = tmid;
hm = hmid;
}
}
return tmid;
}
vec3 getPixel(in vec2 coord, float time) {
vec2 uv = coord / iResolution.xy;
uv = uv * 2.0 - 1.0;
uv.x *= iResolution.x / iResolution.y;
// ray
vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time);
vec3 ori = vec3(0.0,3.5,time*5.0);
vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.14;
dir = normalize(dir) * fromEuler(ang);
// tracing
vec3 p;
heightMapTracing(ori,dir,p);
vec3 dist = p - ori;
vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);
vec3 light = normalize(vec3(0.0,1.0,0.8));
// color
return mix(
getSkyColor(dir),
getSeaColor(p,n,light,dir,dist),
pow(smoothstep(0.0,-0.02,dir.y),0.2));
}
// main
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
float time = iTime * 0.3 + iMouse.x*0.01;
#ifdef AA
vec3 color = vec3(0.0);
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
vec2 uv = fragCoord+vec2(i,j)/3.0;
color += getPixel(uv, time);
}
}
color /= 9.0;
#else
vec3 color = getPixel(fragCoord, time);
#endif
// post
fragColor = vec4(pow(color,vec3(0.65)), 1.0);
}

71
shaders/tiling.frag Normal file
View file

@ -0,0 +1,71 @@
#define sqrt25 0.6324555320 //sqrt(2./5.)
#define sqrt35 0.7745966692 //sqrt(3./5.)
//edge distance of a Cube
float cubeDist(vec3 uvw) {
vec3 d = abs(uvw); //mirroring along axis
return min(d.x, min(d.y, d.z))*2.; //*2. for 0-1 range
}
// Cube Tiling
vec4 cubeTile(vec3 uvw) {
vec3 grid = fract(uvw)-.5; // centered UVW coords
float edist = cubeDist(grid); // edge distance
//float cdist = dot(grid,grid); //squared center distance
//vec3 id = uvw-grid; // Cells IDs
return vec4(grid, edist);
}
// scaled with offset cube tiling
vec4 cubeCell(vec3 uvw, vec3 offset, float gridRes) {
vec4 cubeTiling = cubeTile(uvw*gridRes + offset);
vec3 tiledUV = (cubeTiling.xyz - offset)/gridRes; //cube pixaltion
return vec4(tiledUV,cubeTiling.w);
}
// rotates a vetor from SirBelfer4 (https://www.shadertoy.com/view/ssc3z4)
vec3 rotate(vec3 v, vec3 a)
{
// https://math.stackexchange.com/questions/2975109/how-to-convert-euler-angles-to-quaternions-and-get-the-same-euler-angles-back-fr
vec4 q;
vec3 c = cos(a * 0.5), s = sin(a * 0.5);
q.x = s.x * c.y * c.z - c.x * s.y * s.z;
q.y = c.x * s.y * c.z + s.x * c.y * s.z;
q.z = c.x * c.y * s.z - s.x * s.y * c.z;
q.w = c.x * c.y * c.z + s.x * s.y * s.z;
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
vec3 qt = 2.0 * cross(q.xyz, v);
return v + q.w * qt + cross(q.xyz, qt);
}
// makes RdYlBu_r colormap with polynimal 6 https://www.shadertoy.com/view/Nd3fR2
vec3 RdYlBu_r(float t) {
const vec3 c0 = vec3(0.207621,0.196195,0.618832);
const vec3 c1 = vec3(-0.088125,3.196170,-0.353302);
const vec3 c2 = vec3(8.261232,-8.366855,14.368787);
const vec3 c3 = vec3(-2.922476,33.244294,-43.419173);
const vec3 c4 = vec3(-34.085327,-74.476041,37.159352);
const vec3 c5 = vec3(50.429790,67.145621,-1.750169);
const vec3 c6 = vec3(-21.188828,-20.935464,-6.501427);
return c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*c6)))));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord/iResolution.y; //square UV pattern
float time = (0.05*iTime); // used as z dimension
float gridRes = 2.5; //size of cubes
vec3 point = vec3(uv, time); //uvw cords
//cosmetic rotate for fun triangles otherwise it looks so square
point = rotate(point, (vec3(sqrt25,sqrt35,0.))); //vec3 must be normalized
vec4 a = cubeCell(point, vec3(0.), gridRes);
vec3 col = RdYlBu_r(a.w); // cosmetic Colormap
fragColor = vec4(col, 1.);
}

237
window.c Normal file
View file

@ -0,0 +1,237 @@
#include "shadermeh.h"
#ifndef GLX_ARB_create_context
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#endif
#ifndef GLX_ARB_create_context_profile
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#endif
typedef GLXContext (*CREATECONTEXTATTRIBSPROC)(Display *, GLXFBConfig,
GLXContext, Bool,
const int *);
typedef void (*SWAPINTERVALEXTPROC)(Display *, GLXDrawable, int);
static int glversions[][2] = { {4,5}, {4,4}, {4,3}, {4,2}, {4,1}, {4,0},
{3,3}, {3,2}, {3,1}, {3,0} };
static Display *dpy;
static int dpy_ref = 0;
static Atom atom_wm_delete;
static XContext xctx;
static int xlib_swallow_errors(Display *display, XErrorEvent *event)
{
(void)display; (void)event;
return 0;
}
/****************************************************************************/
window *window_create(unsigned int width, unsigned int height,
const char *caption)
{
CREATECONTEXTATTRIBSPROC CreateContextAttribs;
XSetWindowAttributes swa;
int fbcount, attr[20];
GLXFBConfig fbc, *fbl;
unsigned int i = 0;
XSizeHints hints;
XVisualInfo *vi;
window *this;
this = calloc(1, sizeof(*this));
if (!this)
return NULL;
if (dpy) {
++dpy_ref;
} else {
dpy = XOpenDisplay(0);
dpy_ref = 1;
if (!dpy) {
free(this);
return NULL;
}
XSetErrorHandler(xlib_swallow_errors);
atom_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
xctx = XUniqueContext();
}
attr[ 0] = GLX_BUFFER_SIZE; attr[ 1] = 32;
attr[ 2] = GLX_RED_SIZE; attr[ 3] = 8;
attr[ 4] = GLX_GREEN_SIZE; attr[ 5] = 8;
attr[ 6] = GLX_BLUE_SIZE; attr[ 7] = 8;
attr[ 8] = GLX_ALPHA_SIZE; attr[ 9] = 8;
attr[10] = GLX_DEPTH_SIZE; attr[11] = 24;
attr[12] = GLX_STENCIL_SIZE; attr[13] = 8;
attr[14] = GLX_DOUBLEBUFFER; attr[15] = True;
attr[16] = None;
fbl = glXChooseFBConfig(dpy, DefaultScreen(dpy), attr, &fbcount);
if (!fbl || !fbcount) {
window_destroy(this);
return NULL;
}
fbc = fbl[0];
vi = glXGetVisualFromFBConfig(dpy, fbl[0]);
XFree(fbl);
if (!vi) {
window_destroy(this);
return NULL;
}
swa.colormap = XCreateColormap(dpy, RootWindow(dpy,vi->screen),
vi->visual, AllocNone);
if (!swa.colormap) {
XFree(vi);
window_destroy(this);
return NULL;
}
swa.border_pixel = 0;
this->wnd = XCreateWindow(dpy, RootWindow(dpy,vi->screen), 0, 0,
width, height, 0, vi->depth, InputOutput,
vi->visual, CWBorderPixel|CWColormap, &swa);
XFree(vi);
if (!this->wnd) {
window_destroy(this);
return NULL;
}
CreateContextAttribs = (CREATECONTEXTATTRIBSPROC)
glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
if (CreateContextAttribs) {
attr[0] = GLX_CONTEXT_MAJOR_VERSION_ARB;
attr[1] = 0;
attr[2] = GLX_CONTEXT_MINOR_VERSION_ARB;
attr[3] = 0;
attr[4] = GLX_CONTEXT_PROFILE_MASK_ARB;
attr[5] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
attr[6] = GLX_CONTEXT_FLAGS_ARB;
attr[7] = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
attr[8] = None;
for (i = 0; !this->gl && i < sizeof(glversions) /
sizeof(glversions[0]); ++i) {
attr[1] = glversions[i][0];
attr[3] = glversions[i][1];
this->gl = CreateContextAttribs(dpy, fbc, 0,
True, attr);
}
}
if (!this->gl) {
this->gl = glXCreateNewContext(dpy, fbc, GLX_RGBA_TYPE,
0, GL_TRUE);
}
if (!this->gl) {
window_destroy(this);
return NULL;
}
hints.flags = PSize | PMinSize | PMaxSize;
hints.min_width = hints.max_width = hints.base_width = width;
hints.min_height = hints.max_height = hints.base_height = height;
XSetWMNormalHints(dpy, this->wnd, &hints);
XSelectInput(dpy, this->wnd, StructureNotifyMask |
KeyPressMask | KeyReleaseMask |
PointerMotionMask | PropertyChangeMask |
ButtonPressMask | ButtonReleaseMask);
XSetWMProtocols(dpy, this->wnd, &atom_wm_delete, 1);
XFlush(dpy);
XStoreName(dpy, this->wnd, caption);
XMapWindow(dpy, this->wnd);
XSaveContext(dpy, this->wnd, xctx, (XPointer)this);
XFlush(dpy);
return this;
}
void window_make_current(window *this)
{
if (this) {
glXMakeContextCurrent(dpy, this->wnd, this->wnd, this->gl);
} else {
glXMakeContextCurrent(dpy, 0, 0, 0);
}
}
void window_swap_buffers(window *this)
{
glXSwapBuffers(dpy, this->wnd);
}
void window_set_vsync(window *this, int enable)
{
SWAPINTERVALEXTPROC SwapIntervalEXT;
SwapIntervalEXT = (SWAPINTERVALEXTPROC)
glXGetProcAddress((const GLubyte *)"glXSwapIntervalEXT");
if (SwapIntervalEXT)
SwapIntervalEXT(dpy, this->wnd, enable ? 1 : 0);
}
void window_destroy(window *this)
{
if (this->gl) {
glXMakeContextCurrent(dpy, 0, 0, 0);
glXDestroyContext(dpy, this->gl);
}
if (this->wnd) {
XDeleteContext(dpy, this->wnd, xctx);
XDestroyWindow(dpy, this->wnd);
}
if ((--dpy_ref) <= 0) {
XCloseDisplay(dpy);
dpy_ref = 0;
dpy = NULL;
}
free(this);
}
int window_handle_events(void)
{
window *this;
XEvent e;
if (XPending(dpy)) {
XNextEvent(dpy, &e);
XFindContext(dpy, e.xany.window, xctx, (XPointer *)&this);
switch (e.type) {
case ClientMessage:
if (e.xclient.data.l[0] == (long)atom_wm_delete) {
XUnmapWindow(dpy, e.xany.window);
--dpy_ref;
}
break;
}
}
return (dpy_ref > 0);
}