diff --git a/Makefile.am b/Makefile.am index 452b943..091bc3f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,4 +2,4 @@ AUTOMAKE_OPTIONS = foreign subdir-objects -Wall bin_PROGRAMS = forge forge_SOURCES = src/main.c src/args.c src/forge.c src/file.c forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -include_HEADERS = src/main.h src/args.h src/config.h src/types.h src/forge.h src/file.h include/linmath.h include/glad/gl.h \ No newline at end of file +include_HEADERS = src/main.h src/args.h src/config.h src/types.h src/forge.h src/file.h src/constants.h include/linmath.h include/glad/gl.h \ No newline at end of file diff --git a/README.md b/README.md index 93779c7..e9a4e60 100644 --- a/README.md +++ b/README.md @@ -86,10 +86,11 @@ make -f Makefile.dev release-arch - [x] Create GLSL Window - [x] Load static fragment shader into GLSL - [x] Add default uniforms - - [ ] Read fragment shader from file + - [x] Read fragment shader from file - [ ] Handle compilation errors - - [ ] Minimal working fragment sample - - [ ] Hot-reload fragment shader + - [x] Minimal working fragment sample + - [x] Hot-reload fragment shader + - [ ] Specify fragment shader path - [x] Force fullscreen - [x] Select screen as argument / config - [ ] Midi diff --git a/shaders/frag.glsl b/shaders/frag.glsl new file mode 100644 index 0000000..84167be --- /dev/null +++ b/shaders/frag.glsl @@ -0,0 +1,15 @@ +#version 330 + +uniform float iTime; +uniform vec2 iResolution; +in vec2 vUV; +out vec4 fragColor; + +void main() { + vec2 uv0 = vUV.st; + float ratio = iResolution.x / iResolution.y; + vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); + vec3 color = vec3(vUV, sin(iTime * 0.5) * 0.5 + 0.5); + color *= 1 - step(cos(iTime) * 0.1 + 0.5,length(uv1)); + fragColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/src/args.c b/src/args.c index cc11b9c..e7cbd77 100644 --- a/src/args.c +++ b/src/args.c @@ -1,10 +1,11 @@ -#include "args.h" -#include "config.h" #include #include #include #include +#include "args.h" +#include "config.h" + void print_help(int status_code) { puts(PACKAGE " " VERSION "\n\n" diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 0000000..c71bd0c --- /dev/null +++ b/src/constants.h @@ -0,0 +1,16 @@ +#include "types.h" + +static const char *vertex_shader_text = + "#version 330\n" + "uniform mat4 mvp;\n" + "in vec2 vPos;\n" + "out vec2 vUV;\n" + "void main()\n" + "{\n" + " gl_Position = mvp * vec4(vPos, 0.0, 1.0);\n" + " vUV = vPos;\n" + "}\n"; + +static const Vertex vertices[6] = {{{0.0f, 0.0f}}, {{0.0f, 1.0f}}, + {{1.0f, 1.0f}}, {{0.0f, 0.0f}}, + {{1.0f, 1.0f}}, {{1.0f, 0.0f}}}; \ No newline at end of file diff --git a/src/file.c b/src/file.c index 8e9ab26..96ed195 100644 --- a/src/file.c +++ b/src/file.c @@ -23,7 +23,9 @@ bool should_update_file(File *file) { void update_file(File *file) { // free remaining data - free(file->content); + if (file->content != 0) { + free(file->content); + } // init empty file file->content = 0; file->error = false; @@ -56,7 +58,9 @@ void update_file(File *file) { } File read_file(char *path) { - File file = {path, 0, 0, 0}; + File file = {path, 0, false, 0}; update_file(&file); return file; -} \ No newline at end of file +} + +void free_file(File *file) { free(file->content); } \ No newline at end of file diff --git a/src/file.h b/src/file.h index e9f9239..c2dcea7 100644 --- a/src/file.h +++ b/src/file.h @@ -9,4 +9,6 @@ bool should_update_file(File *file); void update_file(File *file); +void free_file(File *file); + #endif \ No newline at end of file diff --git a/src/forge.c b/src/forge.c index af3bdc2..811d0bf 100644 --- a/src/forge.c +++ b/src/forge.c @@ -1,47 +1,18 @@ -#include "config.h" -#include "types.h" #include #include #include -#include +#include "config.h" +#include "constants.h" +#include "file.h" +#include "types.h" +#include #define GLAD_GL_IMPLEMENTATION #include #define GLFW_INCLUDE_NONE #include -static const Vertex vertices[6] = {{{0.0f, 0.0f}}, {{0.0f, 1.0f}}, - {{1.0f, 1.0f}}, {{0.0f, 0.0f}}, - {{1.0f, 1.0f}}, {{1.0f, 0.0f}}}; - -static const char *vertex_shader_text = - "#version 330\n" - "uniform mat4 mvp;\n" - "in vec2 vPos;\n" - "out vec2 vUV;\n" - "void main()\n" - "{\n" - " gl_Position = mvp * vec4(vPos, 0.0, 1.0);\n" - " vUV = vPos;\n" - "}\n"; - -static const char *fragment_shader_text = - "#version 330\n" - "uniform float iTime;\n" - "uniform vec2 iResolution;\n" - "in vec2 vUV;\n" - "out vec4 fragColor;\n" - "void main()\n" - "{\n" - " vec2 uv0 = vUV.st;\n" - " float ratio = iResolution.x / iResolution.y;\n" - " vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);\n" - " vec3 color = vec3(vUV, sin(iTime * 0.5) * 0.5 + 0.5);\n" - " color *= 1 - step(cos(iTime) * 0.5 + 0.5,length(uv1));\n" - " fragColor = vec4(color, 1.0);\n" - "}\n"; - void error_callback(int error, const char *description) { fprintf(stderr, "Error %d: %s\n", error, description); glfwTerminate(); @@ -56,6 +27,8 @@ static void key_callback(GLFWwindow *window, int key, int scancode, int action, } } +// TODO extract to window file +// TODO split into smaller functions void *init_window(GLFWwindow **window, Parameters params) { // set errors handler glfwSetErrorCallback(error_callback); @@ -112,8 +85,11 @@ void *init_window(GLFWwindow **window, Parameters params) { return window; } -ShaderProgram init_program() { +// TODO extract to "shaders" file +// TODO split into smaller functions +ShaderProgram init_program(File fragment_shader) { ShaderProgram program = {}; + GLint status_params; glGenBuffers(1, &program.vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, program.vertex_buffer); @@ -123,10 +99,27 @@ ShaderProgram init_program() { glShaderSource(program.vertex_shader, 1, &vertex_shader_text, NULL); glCompileShader(program.vertex_shader); + glGetShaderiv(program.vertex_shader, GL_COMPILE_STATUS, &status_params); + if (status_params == GL_FALSE) { + program.error = true; + // TODO use glGetShaderInfoLog( GLuint shader, GLsizei + // maxLength, GLsizei *length, GLchar *infoLog); + } + program.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(program.fragment_shader, 1, &fragment_shader_text, NULL); + glShaderSource(program.fragment_shader, 1, + (const GLchar *const *)&fragment_shader.content, NULL); glCompileShader(program.fragment_shader); + glGetShaderiv(program.fragment_shader, GL_COMPILE_STATUS, &status_params); + if (status_params == GL_FALSE) { + program.error = true; + } + + if (program.error) { + return program; + } + program.program = glCreateProgram(); glAttachShader(program.program, program.vertex_shader); glAttachShader(program.program, program.fragment_shader); @@ -146,6 +139,21 @@ ShaderProgram init_program() { return program; } +// TODO extract to "shaders" file +void update_program(ShaderProgram program, File fragment_shader) { + GLint status_params; + glShaderSource(program.fragment_shader, 1, + (const GLchar *const *)&fragment_shader.content, NULL); + glCompileShader(program.fragment_shader); + + glGetShaderiv(program.fragment_shader, GL_COMPILE_STATUS, &status_params); + if (status_params == GL_FALSE) { + fprintf(stderr, "Failed to compile shaders\n"); // TODO add info + return; + } + glLinkProgram(program.program); +} + void loop(GLFWwindow *window, ShaderProgram program) { int width, height; glfwGetFramebufferSize(window, &width, &height); @@ -173,13 +181,32 @@ void loop(GLFWwindow *window, ShaderProgram program) { void forge_run(Parameters params) { GLFWwindow *window; + File fragment_shader = read_file("shaders/tmp.glsl"); + + if (fragment_shader.error) { + fprintf(stderr, "Cannot read file\n"); + exit(EXIT_FAILURE); + } + init_window(&window, params); - ShaderProgram program = init_program(); + ShaderProgram program = init_program(fragment_shader); + + if (program.error) { + fprintf(stderr, "Failed to compile shaders\n"); + glfwTerminate(); + exit(EXIT_FAILURE); + } while (!glfwWindowShouldClose(window)) { + if (should_update_file(&fragment_shader)) { + update_file(&fragment_shader); + update_program(program, fragment_shader); + } loop(window, program); } glfwTerminate(); + + free_file(&fragment_shader); } \ No newline at end of file diff --git a/src/main.c b/src/main.c index d881353..992bf9b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,11 @@ -#include "args.h" -#include "config.h" -#include "forge.h" #include #include #include +#include "args.h" +#include "config.h" +#include "forge.h" + int main(int argc, char **argv) { Parameters params; params = parse_args(argc, argv); diff --git a/src/types.h b/src/types.h index 90e4cbc..f5a1a61 100644 --- a/src/types.h +++ b/src/types.h @@ -1,8 +1,9 @@ -#include -#include #include #include +#include +#include + #ifndef TYPES_H #define TYPES_H @@ -35,6 +36,8 @@ typedef struct ShaderProgram { GLuint ires_location; GLuint vertex_array; + + bool error; } ShaderProgram; #endif \ No newline at end of file