diff --git a/src/constants.h b/src/constants.h index b29f807..05efc93 100644 --- a/src/constants.h +++ b/src/constants.h @@ -3,7 +3,7 @@ #ifndef CONSTANTS_H #define CONSTANTS_H -static const char *vertex_shader_text = +static char *vertex_shader_text = "#version 330\n" "uniform mat4 mvp;\n" "in vec2 vPos;\n" diff --git a/src/file.c b/src/file.c index 96ed195..55e7868 100644 --- a/src/file.c +++ b/src/file.c @@ -6,19 +6,16 @@ #include "types.h" -void update_file_time(File *file) { +time_t get_file_time(File file) { struct stat attr; - if (stat(file->path, &attr) == 0) { - file->last_write = attr.st_mtime; + if (stat(file.path, &attr) == 0) { + return attr.st_mtim.tv_sec; } + return 0; } -bool should_update_file(File *file) { - struct stat attr; - if (stat(file->path, &attr) == 0) { - return file->last_write != attr.st_mtime; - } - return false; +bool should_update_file(File file) { + return file.last_write != get_file_time(file); } void update_file(File *file) { @@ -54,7 +51,7 @@ void update_file(File *file) { // append null byte file->content[length] = '\0'; // read last update time - update_file_time(file); + file->last_write = get_file_time(*file); } File read_file(char *path) { diff --git a/src/file.h b/src/file.h index c2dcea7..3f43eae 100644 --- a/src/file.h +++ b/src/file.h @@ -5,7 +5,7 @@ File read_file(char *path); -bool should_update_file(File *file); +bool should_update_file(File file); void update_file(File *file); diff --git a/src/forge.c b/src/forge.c index 45af7f5..9dd6d88 100644 --- a/src/forge.c +++ b/src/forge.c @@ -24,12 +24,12 @@ static void key_callback(Window *window, int key, } void loop(Window *window, ShaderProgram program, bool hot_reload, - File fragment_shader) { + File *fragment_shader) { Context context; - if (hot_reload && should_update_file(&fragment_shader)) { - update_file(&fragment_shader); - update_program(program, fragment_shader); + if (hot_reload && should_update_file(*fragment_shader)) { + update_file(fragment_shader); + update_program(program, *fragment_shader); } context = get_window_context(window); @@ -60,7 +60,7 @@ void forge_run(Parameters params) { } while (!window_should_close(window)) { - loop(window, program, params.hot_reload, fragment_shader); + loop(window, program, params.hot_reload, &fragment_shader); } close_window(window, true); diff --git a/src/shaders.c b/src/shaders.c index d6c5992..0d1cea1 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -6,50 +6,66 @@ #include "constants.h" #include "types.h" -// TODO split into smaller functions -ShaderProgram init_program(File fragment_shader) { - ShaderProgram program = {}; +bool compile_shader(GLuint shader_id, char *name, char *source_code) { GLint status_params; + char log[1024]; + // update shader source code + glShaderSource(shader_id, 1, (const GLchar **)&source_code, NULL); + + // compile shader + glCompileShader(shader_id); + + // get compilation status + glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params); + glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log); + + if (status_params == GL_FALSE) { + fprintf(stderr, "Failed to compile shader '%s'\n%s\n", name, log); + } else { + fprintf(stdout, "Compiled shader '%s'\n", name); + } + + return status_params == GL_TRUE; +} + +ShaderProgram init_program(File fragment_shader) { + ShaderProgram program = {0}; + + // create vertex buffer and setup vertices glGenBuffers(1, &program.vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, program.vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + // compile vertex shader program.vertex_shader = glCreateShader(GL_VERTEX_SHADER); - 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.error |= !compile_shader( + program.vertex_shader, "internal vertex shader", vertex_shader_text); + // compile fragment shader program.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - 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; - } + program.error |= !compile_shader( + program.fragment_shader, fragment_shader.path, fragment_shader.content); if (program.error) { return program; } + // create and link full shader program program.program = glCreateProgram(); glAttachShader(program.program, program.vertex_shader); glAttachShader(program.program, program.fragment_shader); glLinkProgram(program.program); + // create uniforms pointers program.mvp_location = glGetUniformLocation(program.program, "mvp"); program.itime_location = glGetUniformLocation(program.program, "iTime"); program.ires_location = glGetUniformLocation(program.program, "iResolution"); + + // create attribute pointer program.vpos_location = glGetAttribLocation(program.program, "vPos"); + // create vertex array and bind to vPos attribute glGenVertexArrays(1, &program.vertex_array); glBindVertexArray(program.vertex_array); glEnableVertexAttribArray(program.vpos_location); @@ -60,35 +76,39 @@ ShaderProgram init_program(File fragment_shader) { } 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); + bool result; - 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; + result = compile_shader(program.fragment_shader, fragment_shader.path, + fragment_shader.content); + + if (result) { + // re-link program + glLinkProgram(program.program); } - glLinkProgram(program.program); } void apply_program(ShaderProgram program, Context context) { mat4x4 m, p, mvp; + // update viewport glViewport(0, 0, context.width, context.height); + // clear buffer glClear(GL_COLOR_BUFFER_BIT); + // create model-view-projection matrix mat4x4_identity(m); mat4x4_ortho(p, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f); mat4x4_mul(mvp, p, m); vec2 resolution = {(float)context.width, (float)context.height}; + // update uniforms glUseProgram(program.program); glUniformMatrix4fv(program.mvp_location, 1, GL_FALSE, (const GLfloat *)&mvp); glUniform1f(program.itime_location, (const GLfloat)context.time); glUniform2fv(program.ires_location, 1, (const GLfloat *)&resolution); + + // start vertex handling glBindVertexArray(program.vertex_array); glDrawArrays(GL_TRIANGLES, 0, 6); } \ No newline at end of file diff --git a/src/types.h b/src/types.h index a0b1a41..9cce66d 100644 --- a/src/types.h +++ b/src/types.h @@ -27,21 +27,20 @@ typedef struct File { } File; typedef struct ShaderProgram { - GLuint program; + bool error; - GLuint vertex_buffer; + GLuint program; GLuint vertex_shader; GLuint fragment_shader; GLuint mvp_location; - GLuint vpos_location; GLuint itime_location; GLuint ires_location; + GLuint vertex_buffer; GLuint vertex_array; - - bool error; + GLuint vpos_location; } ShaderProgram; typedef GLFWwindow Window; diff --git a/src/window.c b/src/window.c index 4a9fc84..d3d3069 100644 --- a/src/window.c +++ b/src/window.c @@ -49,6 +49,9 @@ GLFWwindow *create_window(GLFWmonitor *monitor, void (*key_callback)(Window *, int, int, int, int)) { // Window related hints glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); + glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE); + glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_FALSE); + glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE); // create fullscreen window in selected monitor GLFWwindow *window =