2022-03-21 17:58:17 +00:00
|
|
|
// sdfps.c
|
|
|
|
|
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
|
|
|
|
#include <glad/glad.h>
|
|
|
|
|
2022-03-21 21:56:24 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2022-03-21 17:58:17 +00:00
|
|
|
#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,
|
2022-04-05 14:49:46 +00:00
|
|
|
512 + 128, 512 + 128,
|
2022-03-21 17:58:17 +00:00
|
|
|
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"
|
2022-03-21 21:56:24 +00:00
|
|
|
|
2022-04-05 14:49:46 +00:00
|
|
|
/* ~ 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)
|
|
|
|
*/
|
|
|
|
|
2022-03-21 21:56:24 +00:00
|
|
|
/* viewport resolution (in pixels), z = 1 */
|
|
|
|
"uniform vec3 iResolution;\n"
|
2022-03-21 22:01:49 +00:00
|
|
|
/* playback time in seconds */
|
|
|
|
"uniform float iTime;\n"
|
2022-03-21 21:56:24 +00:00
|
|
|
|
2022-03-21 17:58:17 +00:00
|
|
|
"out vec4 out_color;\n"
|
|
|
|
"void main() {\n"
|
2022-03-21 22:01:49 +00:00
|
|
|
"vec2 xy = gl_FragCoord.xy + vec2(sin(iTime), cos(iTime));\n"
|
2022-03-21 21:56:24 +00:00
|
|
|
"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"
|
2022-03-21 17:58:17 +00:00
|
|
|
"}\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) {
|
2022-03-21 21:56:24 +00:00
|
|
|
glDeleteProgram(s -> shader_program);
|
|
|
|
glDeleteShader(s -> vert_shader);
|
|
|
|
glDeleteShader(s -> frag_shader);
|
2022-03-21 17:58:17 +00:00
|
|
|
SDL_GL_DeleteContext(s -> context);
|
|
|
|
SDL_DestroyWindow(s -> window);
|
|
|
|
}
|
|
|
|
|
2022-03-21 21:56:24 +00:00
|
|
|
s32 create_framebuffer(s32 w, s32 h, GLuint *texture, GLuint *framebuffer) {
|
|
|
|
glGenTextures(1, texture);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, *texture);
|
2022-03-21 17:58:17 +00:00
|
|
|
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);
|
2022-03-21 21:56:24 +00:00
|
|
|
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);
|
|
|
|
|
2022-03-21 17:58:17 +00:00
|
|
|
GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
2022-03-21 21:56:24 +00:00
|
|
|
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
|
2022-03-21 17:58:17 +00:00
|
|
|
puts("FRAME BUFFER FUCKED UP SOMEWHERE");
|
2022-03-21 21:56:24 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2022-03-21 17:58:17 +00:00
|
|
|
|
2022-03-21 21:56:24 +00:00
|
|
|
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);
|
2022-03-21 17:58:17 +00:00
|
|
|
|
2022-03-21 21:56:24 +00:00
|
|
|
GLuint iResolution = glGetUniformLocation(s -> shader_program, "iResolution");
|
|
|
|
// TODO: error check?
|
|
|
|
glUniform3f(iResolution, (f32) fb_w, (f32) fb_h, 1.0f);
|
2022-03-21 22:01:49 +00:00
|
|
|
glUniform1f(glGetUniformLocation(s -> shader_program, "iTime"), 0.001f * (f32) SDL_GetTicks());
|
2022-03-21 17:58:17 +00:00
|
|
|
|
|
|
|
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
|
2022-03-21 21:56:24 +00:00
|
|
|
/*
|
|
|
|
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
|
2022-04-05 14:49:46 +00:00
|
|
|
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
|
2022-03-21 21:56:24 +00:00
|
|
|
*/
|
2022-03-21 17:58:17 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|