diff --git a/Makefile.dev b/Makefile.dev index 214abbd..2d61725 100644 --- a/Makefile.dev +++ b/Makefile.dev @@ -9,7 +9,7 @@ clean: build: @mkdir -p build - gcc -v -Wall -Wextra src/*.c src/*.h -Iinclude -lglfw -lGL -lm -ldl -o build/$(TARGET) + gcc -Wall -Wextra src/*.h src/*.c -Iinclude -lglfw -lGL -lm -o build/$(TARGET) run: build ./build/forge --hot-reload --frag=./shaders/frag.glsl diff --git a/README.md b/README.md index 58f773c..b5fe668 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ $EDITOR configure.ac # make full build make -f Makefile.dev release # update PKGBUILD with new version and sha256 sum -sha256sum forge-x.y.z.tar.gz +sha256sum build/forge-x.y.z.tar.gzx $EDITOR PKGBUILD # push to repo git commit -am "forge vX.Y.Z" diff --git a/configure.ac b/configure.ac index 8f9f133..139f65d 100644 --- a/configure.ac +++ b/configure.ac @@ -4,6 +4,7 @@ AC_PROG_CC AC_CHECK_HEADERS([stdio.h]) AC_CHECK_HEADERS([stdlib.h]) AC_CHECK_HEADERS([stdbool.h]) +AC_CHECK_HEADERS([stddef.h]) AC_CHECK_HEADERS([string.h]) AC_CHECK_HEADERS([time.h]) AC_CHECK_HEADERS([sys/stat.h]) diff --git a/src/constants.h b/src/constants.h index c71bd0c..b29f807 100644 --- a/src/constants.h +++ b/src/constants.h @@ -1,5 +1,8 @@ #include "types.h" +#ifndef CONSTANTS_H +#define CONSTANTS_H + static const char *vertex_shader_text = "#version 330\n" "uniform mat4 mvp;\n" @@ -13,4 +16,6 @@ static const char *vertex_shader_text = 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 + {{1.0f, 1.0f}}, {{1.0f, 0.0f}}}; + +#endif \ No newline at end of file diff --git a/src/forge.c b/src/forge.c index 83d107f..ee14e21 100644 --- a/src/forge.c +++ b/src/forge.c @@ -2,16 +2,11 @@ #include #include -#include "config.h" -#include "constants.h" #include "file.h" +#include "glfw.h" +#include "shaders.h" #include "types.h" - -#include -#define GLAD_GL_IMPLEMENTATION -#include -#define GLFW_INCLUDE_NONE -#include +#include "window.h" void error_callback(int error, const char *description) { fprintf(stderr, "Error %d: %s\n", error, description); @@ -19,7 +14,7 @@ void error_callback(int error, const char *description) { exit(EXIT_FAILURE); } -static void key_callback(GLFWwindow *window, int key, +static void key_callback(Window *window, int key, __attribute__((unused)) int scancode, int action, int mods) { // close window on escape key @@ -28,134 +23,9 @@ static void key_callback(GLFWwindow *window, int key, } } -// TODO extract to window file -// TODO split into smaller functions -void *init_window(GLFWwindow **window, Parameters params) { - // set errors handler - glfwSetErrorCallback(error_callback); - - // print current GLFW version - fprintf(stdout, "[GLFW] %s\n", glfwGetVersionString()); - - // init GLFW - if (!glfwInit()) { - fprintf(stderr, "[GLFW] Initialization failed\n"); - exit(EXIT_FAILURE); - } - - // add context to window before creation - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_DECORATED, 0); - - // detect monitors - int count; - GLFWmonitor **monitors = glfwGetMonitors(&count); - - // check selected monitor availability - if (params.screen >= count) { - fprintf(stderr, "Screen %d is out of range [0-%d]\n", params.screen, - count - 1); - glfwTerminate(); - exit(EXIT_FAILURE); - } - - // create fullscreen window in selected monitor - (*window) = glfwCreateWindow(1, 1, PACKAGE " " VERSION, - monitors[params.screen], NULL); - - // handle window creation fail - if (!(*window)) { - fprintf(stderr, "[GLFW] Window or context creation failed\n"); - glfwTerminate(); - exit(EXIT_FAILURE); - } - - // use current window - glfwMakeContextCurrent((*window)); - // link GLAD and GLFW window - gladLoadGL(glfwGetProcAddress); - // set keyboard handler - glfwSetKeyCallback((*window), key_callback); - // hide cursor - glfwSetInputMode((*window), GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - // vsync - glfwSwapInterval(1); - - return window; -} - -// 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); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - 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.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; - } - - if (program.error) { - return program; - } - - program.program = glCreateProgram(); - glAttachShader(program.program, program.vertex_shader); - glAttachShader(program.program, program.fragment_shader); - glLinkProgram(program.program); - - program.mvp_location = glGetUniformLocation(program.program, "mvp"); - program.itime_location = glGetUniformLocation(program.program, "iTime"); - program.ires_location = glGetUniformLocation(program.program, "iResolution"); - program.vpos_location = glGetAttribLocation(program.program, "vPos"); - - glGenVertexArrays(1, &program.vertex_array); - glBindVertexArray(program.vertex_array); - glEnableVertexAttribArray(program.vpos_location); - glVertexAttribPointer(program.vpos_location, 2, GL_FLOAT, GL_FALSE, - sizeof(Vertex), (void *)offsetof(Vertex, pos)); - - 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) { +void loop(Window *window, ShaderProgram program) { + // TODO remove GLFW references + // TODO split into smaller functions int width, height; glfwGetFramebufferSize(window, &width, &height); vec2 resolution = {(float)width, (float)height}; @@ -180,7 +50,8 @@ void loop(GLFWwindow *window, ShaderProgram program) { } void forge_run(Parameters params) { - GLFWwindow *window; + // TODO remove GLFW references + Window *window; File fragment_shader = read_file(params.frag_path); @@ -189,7 +60,7 @@ void forge_run(Parameters params) { exit(EXIT_FAILURE); } - init_window(&window, params); + init_window(&window, params, error_callback, key_callback); ShaderProgram program = init_program(fragment_shader); diff --git a/src/glfw.h b/src/glfw.h new file mode 100644 index 0000000..28e7f7b --- /dev/null +++ b/src/glfw.h @@ -0,0 +1,10 @@ +#ifndef GLFW_H +#define GLFW_H + +#define GLAD_GL_IMPLEMENTATION +#include + +#define GLFW_INCLUDE_NONE +#include + +#endif \ No newline at end of file diff --git a/src/shaders.c b/src/shaders.c index e69de29..fb981c9 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -0,0 +1,74 @@ +#include + +#include + +#include "constants.h" +#include "glfw.h" +#include "types.h" + +// 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); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + 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.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; + } + + if (program.error) { + return program; + } + + program.program = glCreateProgram(); + glAttachShader(program.program, program.vertex_shader); + glAttachShader(program.program, program.fragment_shader); + glLinkProgram(program.program); + + program.mvp_location = glGetUniformLocation(program.program, "mvp"); + program.itime_location = glGetUniformLocation(program.program, "iTime"); + program.ires_location = glGetUniformLocation(program.program, "iResolution"); + program.vpos_location = glGetAttribLocation(program.program, "vPos"); + + glGenVertexArrays(1, &program.vertex_array); + glBindVertexArray(program.vertex_array); + glEnableVertexAttribArray(program.vpos_location); + glVertexAttribPointer(program.vpos_location, 2, GL_FLOAT, GL_FALSE, + sizeof(Vertex), (void *)offsetof(Vertex, pos)); + + return program; +} + +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); +} \ No newline at end of file diff --git a/src/shaders.h b/src/shaders.h index afbf5ea..c9cdfb2 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -1,4 +1,10 @@ +#include "types.h" + #ifndef SHADERS_H #define SHADERS_H +ShaderProgram init_program(File fragment_shader); + +void update_program(ShaderProgram program, File fragment_shader); + #endif \ No newline at end of file diff --git a/src/types.h b/src/types.h index 20bd51f..c160f4f 100644 --- a/src/types.h +++ b/src/types.h @@ -1,9 +1,10 @@ #include #include -#include #include +#include "glfw.h" + #ifndef TYPES_H #define TYPES_H @@ -42,4 +43,6 @@ typedef struct ShaderProgram { bool error; } ShaderProgram; +typedef GLFWwindow Window; + #endif \ No newline at end of file diff --git a/src/window.c b/src/window.c index e69de29..a064525 100644 --- a/src/window.c +++ b/src/window.c @@ -0,0 +1,68 @@ +#include +#include + +#include + +#include "config.h" +#include "glfw.h" +#include "types.h" + +// TODO split into smaller functions +// TODO custom struct to remove glfw in signature +void *init_window(Window **window, Parameters params, + void (*error_callback)(int, const char *), + void (*key_callback)(Window *, int, int, int, int)) { + // set errors handler + glfwSetErrorCallback(error_callback); + + // print current GLFW version + fprintf(stdout, "[GLFW] %s\n", glfwGetVersionString()); + + // init GLFW + if (!glfwInit()) { + fprintf(stderr, "[GLFW] Initialization failed\n"); + exit(EXIT_FAILURE); + } + + // add context to window before creation + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_DECORATED, 0); + + // detect monitors + int count; + GLFWmonitor **monitors = glfwGetMonitors(&count); + + // check selected monitor availability + if (params.screen >= count) { + fprintf(stderr, "Screen %d is out of range [0-%d]\n", params.screen, + count - 1); + glfwTerminate(); + exit(EXIT_FAILURE); + } + + // create fullscreen window in selected monitor + (*window) = glfwCreateWindow(1, 1, PACKAGE " " VERSION, + monitors[params.screen], NULL); + + // handle window creation fail + if (!(*window)) { + fprintf(stderr, "[GLFW] Window or context creation failed\n"); + glfwTerminate(); + exit(EXIT_FAILURE); + } + + // use current window + glfwMakeContextCurrent((*window)); + // link GLAD and GLFW window + gladLoadGL(glfwGetProcAddress); + // set keyboard handler + glfwSetKeyCallback((*window), key_callback); + // hide cursor + glfwSetInputMode((*window), GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + // vsync + glfwSwapInterval(1); + + return window; +} \ No newline at end of file diff --git a/src/window.h b/src/window.h index 46ddc2c..98ce7f8 100644 --- a/src/window.h +++ b/src/window.h @@ -1,4 +1,10 @@ +#include "types.h" + #ifndef WINDOW_H #define WINDOW_H +void *init_window(Window **window, Parameters params, + void (*error_callback)(int, const char *), + void (*key_callback)(Window *, int, int, int, int)); + #endif \ No newline at end of file