// sdfps.c #include #include #include #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, 800, 600, 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" /* 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 */ 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; }