forked from goliath/shadermeh
Initial commit
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
This commit is contained in:
commit
acaef93bd8
11 changed files with 1182 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*~
|
||||
shadermeh
|
12
Makefile
Normal file
12
Makefile
Normal 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
181
shader.c
Normal 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
179
shadermeh.c
Normal 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
45
shadermeh.h
Normal 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
158
shaders/cyber.frag
Normal 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
66
shaders/fractal.frag
Normal 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
26
shaders/mandelbrot.frag
Normal 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
204
shaders/seascape.frag
Normal 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
71
shaders/tiling.frag
Normal 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
237
window.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue