sdfps/sdfps.c

254 lines
7.6 KiB
C

// sdfps.c
#include <SDL2/SDL.h>
#include <glad/glad.h>
#include <stdio.h>
#include "types.h"
GLuint create_shader(GLenum shader_type, const char *src) {
GLuint s = glCreateShader(shader_type);
glShaderSource(s, 1, &src, NULL);
glCompileShader(s);
GLint s_compiled;
glGetShaderiv(s, GL_COMPILE_STATUS, &s_compiled);
if (s_compiled != GL_TRUE) {
GLsizei log_length = 0;
GLchar msg[1024] = { 0 };
glGetShaderInfoLog(s, sizeof(msg), &log_length, msg);
puts(msg);
}
return s;
}
void init(Sdfps* s) { /* TODO: Error checks */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
/* these 2 are required on macos [https://www.glfw.org/faq.html#41---how-do-i-create-an-opengl-30-context] */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
//SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
//SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
s -> window = SDL_CreateWindow("sdfps",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
512 + 128, 512 + 128,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
s -> context = SDL_GL_CreateContext(s -> window);
SDL_GL_MakeCurrent(s -> window, s -> context);
SDL_GL_SetSwapInterval(1);
if (!gladLoadGLES2Loader(SDL_GL_GetProcAddress)) printf("FUCK, gl loading failed\n");
puts(glGetString(GL_VERSION));
s -> vert_shader = create_shader(GL_VERTEX_SHADER,
"#version 330\n"
"in vec4 a_pos;\n"
"void main() {\n"
"gl_Position = a_pos;\n"
"}\n");
s -> frag_shader = create_shader(GL_FRAGMENT_SHADER,
"#version 330\n"
"precision highp float;\n"
/* ~ from shader toy ~
uniform float iTimeDelta; // render time (in seconds)
uniform int iFrame; // shader playback frame
uniform float iChannelTime[4]; // channel playback time (in seconds)
uniform vec3 iChannelResolution[4]; // channel resolution (in pixels)
uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click
uniform samplerXX iChannel0..3; // input channel. XX = 2D/Cube
uniform vec4 iDate; // (year, month, day, time in seconds)
uniform float iSampleRate; // sound sample rate (i.e., 44100)
*/
/* viewport resolution (in pixels), z = 1 */
"uniform vec3 iResolution;\n"
/* playback time in seconds */
"uniform float iTime;\n"
"out vec4 out_color;\n"
"void main() {\n"
"vec2 xy = gl_FragCoord.xy + vec2(sin(iTime), cos(iTime));\n"
"out_color = vec4(sin(xy.x), sin(xy.y), sin(xy.x) + sin(xy.y), 1);\n"
"if(xy.x > iResolution.x / 2.0) out_color = out_color.zxyw;\n"
"}\n");
s -> shader_program = glCreateProgram();
glAttachShader(s -> shader_program, s -> vert_shader);
glAttachShader(s -> shader_program, s -> frag_shader);
glLinkProgram(s -> shader_program);
GLint program_linked;
glGetProgramiv(s -> shader_program, GL_LINK_STATUS, &program_linked);
if (program_linked != GL_TRUE) {
GLsizei log_length = 0;
GLchar msg[1024];
glGetProgramInfoLog(s -> shader_program, sizeof(msg), &log_length, msg);
puts(msg);
}
}
void deinit(Sdfps *s) {
glDeleteProgram(s -> shader_program);
glDeleteShader(s -> vert_shader);
glDeleteShader(s -> frag_shader);
SDL_GL_DeleteContext(s -> context);
SDL_DestroyWindow(s -> window);
}
s32 create_framebuffer(s32 w, s32 h, GLuint *texture, GLuint *framebuffer) {
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0);
GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
puts("FRAME BUFFER FUCKED UP SOMEWHERE");
return 1;
}
return 0;
}
void render(Sdfps *s) {
// setup render texture
const s32 fb_w = 4, fb_h = 4;
GLuint render_tex, framebuf;
create_framebuffer(fb_w, fb_h, &render_tex, &framebuf);
glViewport(0, 0, fb_w, fb_h);
GLuint iResolution = glGetUniformLocation(s -> shader_program, "iResolution");
// TODO: error check?
glUniform3f(iResolution, (f32) fb_w, (f32) fb_h, 1.0f);
glUniform1f(glGetUniformLocation(s -> shader_program, "iTime"), 0.001f * (f32) SDL_GetTicks());
glClearColor(0.1f, 0.25f, 0.24f, 1);
glClear(GL_COLOR_BUFFER_BIT);
GLint pos_attr_loc = glGetAttribLocation(s -> shader_program, "a_pos");
GLuint vertex_buffer;
glGenBuffers(1, &vertex_buffer);
GLfloat data[] = {
-1, 1,
4, 1,
-1, -4,
};
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
GLuint vert_array;
glGenVertexArrays(1, &vert_array);
glBindVertexArray(vert_array);
glEnableVertexAttribArray(pos_attr_loc);
glVertexAttribPointer(
pos_attr_loc,
2, // components per iteration, 2 = vec2
GL_FLOAT, // data type of each component
GL_FALSE, // data should/shouldnt be normalized
0, // stride, e.g. space between components (in bytes)
0 // pointer/start, 0 is gur location of gur first position
);
glUseProgram(s -> shader_program);
glBindVertexArray(vert_array);
glDrawArrays(GL_TRIANGLES,
0, // first in array
3 // count
);
#if 1
/*
just here to check that it works, since it can be used as an easy way to
get data back out of a shader, there's probs a more proper way to do it
that we could change to later
UPDATE: looking at shader toy's source it seems it uses this function to
get output for sound shaders, so i'm going to guess that it'd be fine of
us to render gur sdf feedback into a lower segment of gur frame buffer
*/
f32 pixels[16 * 16 * 4] = { 0.0f };
glReadPixels(
10, // x pixel starting bottom left,
10, // y pixel
16, // width in pixels, 1 = reading a single pixel
16, // height
GL_RGBA, // format, can also be GL_RGBA_INTEGER
GL_FLOAT, // type
pixels // data
);
#endif
// show it
glBindFramebuffer(GL_FRAMEBUFFER, 0); // not technically needed
s32 win_w, win_h;
SDL_GL_GetDrawableSize(s -> window, &win_w, &win_h);
glViewport(0, 0, win_w, win_h); // not technically needed
// copy framebuf to window?
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuf);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fb_w, fb_h, 0, 0, win_w, win_h, GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT, GL_NEAREST);
// deletes
glDeleteBuffers(1, &vertex_buffer);
glDeleteVertexArrays(1, &vert_array);
glDeleteFramebuffers(1, &framebuf);
glDeleteTextures(1, &render_tex);
SDL_GL_SwapWindow(s -> window);
}
/*
* so entry point, return non zero to quit program
* return 0 to reload so
*/
int sdfps_main(int argc, char **argv, Sdfps **u_data) {
/* TODO: actually copy gur data over from gur kv store */
if (*u_data == NULL) {
*u_data = malloc(1024);
init(*u_data);
}
if (!gladLoadGLES2Loader(SDL_GL_GetProcAddress)) printf("FUCK, gl loading failed\n");
Sdfps *sdfps = *u_data;
while (1) {
SDL_Event e;
while (SDL_PollEvent(&e))
if (e.type == SDL_QUIT)
goto quit;
render(sdfps);
SDL_Delay(1);
if (!remove("reload-trigger")) {
// do some cleanup before reloading,
// pause your audio devices etc
//deinit(sdfps);
puts("removed reload-trigger, reloading...");
return 0;
}
}
quit:
// do what ever you got to before process dies
deinit(sdfps);
return 1;
}