From 60d94b06f22cbe45740ff5d895e5616ba350d42c Mon Sep 17 00:00:00 2001 From: Dimitri Lozeve Date: Wed, 24 Feb 2021 21:48:54 +0100 Subject: [PATCH] Add a framebuffer to hold a texture --- shaders/invert_screen.frag | 15 +++++ src/main.c | 125 +++++++++++++++++++++++++++++-------- src/renderer.c | 19 ++++-- src/shaders.c | 4 ++ 4 files changed, 130 insertions(+), 33 deletions(-) create mode 100644 shaders/invert_screen.frag diff --git a/shaders/invert_screen.frag b/shaders/invert_screen.frag new file mode 100644 index 0000000..0949aae --- /dev/null +++ b/shaders/invert_screen.frag @@ -0,0 +1,15 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +uniform float u_time; +uniform uint u_frame; +uniform vec2 u_resolution; +uniform vec2 u_mouse; +uniform sampler2D u_texture; + +void main() { + //FragColor = texture(u_texture, TexCoords); + FragColor = vec4(1.0 - texelFetch(u_texture, ivec2(gl_FragCoord), 0)); +} diff --git a/src/main.c b/src/main.c index c48c4c8..be54738 100644 --- a/src/main.c +++ b/src/main.c @@ -11,10 +11,16 @@ int main(int argc, char *argv[]) { if (argc < 2) { - log_error("Usage: %s ", argv[0]); + log_error("Usage: %s []", argv[0]); return EXIT_FAILURE; } - const char *fragment_shader_file = argv[1]; + const char *screen_shader_file = argv[1]; + log_debug("Screen shader file: %s", screen_shader_file); + const char *buffer_shader_file = NULL; + if (argc >= 3) { + buffer_shader_file = argv[2]; + log_debug("Buffer shader file: %s", buffer_shader_file); + } GLFWwindow *window = initialize_window(WINDOW_WIDTH, WINDOW_HEIGHT); if (window == NULL) { @@ -24,45 +30,110 @@ int main(int argc, char *argv[]) { unsigned int VAO = initialize_vertices(); - unsigned int shader_program = glCreateProgram(); - if (!shader_program) { - log_error("Could not create shader program"); + unsigned int screen_shader = glCreateProgram(); + if (!screen_shader) { + log_error("Could not create screen shader program"); glfwDestroyWindow(window); glfwTerminate(); return EXIT_FAILURE; } - compile_shaders(&shader_program, fragment_shader_file); + compile_shaders(&screen_shader, screen_shader_file); + + unsigned int buffer_shader = 0; + unsigned int framebuffer = 0; + if (buffer_shader_file) { + buffer_shader = glCreateProgram(); + if (!buffer_shader) { + log_error("Could not create buffer shader program"); + glfwDestroyWindow(window); + glfwTerminate(); + return EXIT_FAILURE; + } + compile_shaders(&buffer_shader, buffer_shader_file); + + /* Framebuffer */ + framebuffer = 0; + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + /* color attachment texture */ + unsigned int texture_color_buffer = 0; + glGenTextures(1, &texture_color_buffer); + glBindTexture(GL_TEXTURE_2D, texture_color_buffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WINDOW_WIDTH, WINDOW_HEIGHT, 0, + GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + texture_color_buffer, 0); + /* check that the framebuffer is complete */ + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + log_error("Framebuffer is not complete"); + } else { + log_debug("Framebuffer initialized and complete"); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } /* Drawing loop */ size_t frame = 0; while (!glfwWindowShouldClose(window)) { - process_input(window, &shader_program, fragment_shader_file); + process_input(window, &screen_shader, screen_shader_file, &buffer_shader, + buffer_shader_file); - /* Background */ - glClearColor(0, 0, 0, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - glUseProgram(shader_program); - - /* Setup uniforms */ + /* data required for uniforms */ float time = glfwGetTime(); - int frag_time_location = glGetUniformLocation(shader_program, "u_time"); - glUniform1f(frag_time_location, time); - - int frag_frame_location = glGetUniformLocation(shader_program, "u_frame"); - glUniform1ui(frag_frame_location, frame); - int viewport[4] = {0}; glGetIntegerv(GL_VIEWPORT, viewport); - int frag_resolution_location = - glGetUniformLocation(shader_program, "u_resolution"); - glUniform2f(frag_resolution_location, viewport[2], viewport[3]); - double mouse_x = 0, mouse_y = 0; glfwGetCursorPos(window, &mouse_x, &mouse_y); - int frag_mouse_resolution_location = - glGetUniformLocation(shader_program, "u_mouse"); - glUniform2f(frag_mouse_resolution_location, mouse_x, mouse_y); + + if (frame % 100 == 0) { + log_debug("frame = %zu, time = %f, viewport = (%d, %d)", frame, time, + viewport[2], viewport[3]); + } + + if (buffer_shader_file) { + /* bind the framebuffer and draw to it */ + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + + /* Background */ + glClearColor(0, 0, 0, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(buffer_shader); + + /* Setup uniforms */ + glUniform1ui(glGetUniformLocation(buffer_shader, "u_frame"), frame); + glUniform1f(glGetUniformLocation(buffer_shader, "u_time"), time); + glUniform2f(glGetUniformLocation(buffer_shader, "u_resolution"), + viewport[2], viewport[3]); + glUniform2f(glGetUniformLocation(buffer_shader, "u_mouse"), mouse_x, + mouse_y); + glUniform1d(glGetUniformLocation(buffer_shader, "u_texture"), 0); + + /* Draw the vertices */ + // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); /* For wireframe mode */ + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + + /* bind back to default framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(screen_shader); + + /* Setup uniforms */ + glUniform1ui(glGetUniformLocation(screen_shader, "u_frame"), frame); + glUniform1f(glGetUniformLocation(screen_shader, "u_time"), time); + glUniform2f(glGetUniformLocation(screen_shader, "u_resolution"), + viewport[2], viewport[3]); + glUniform2f(glGetUniformLocation(screen_shader, "u_mouse"), mouse_x, + mouse_y); + glUniform1d(glGetUniformLocation(screen_shader, "u_texture"), 0); /* Draw the vertices */ // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); /* For wireframe mode */ diff --git a/src/renderer.c b/src/renderer.c index e0bb1dc..5380a5f 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -62,13 +62,14 @@ GLFWwindow *initialize_window(int width, int height) { unsigned int initialize_vertices() { /* Define vertices */ float vertices[] = { - -1.0, -1.0, 0.0, // bottom left - -1.0, 1.0, 0.0, // top left - 1.0, -1.0, 0.0, // top right - 1.0, 1.0, 0.0 // bottom right + // positions // texture coords + 1.0, 1.0, 0.0, 1.0, 1.0, // top right + 1.0, -1.0, 0.0, 1.0, 0.0, // bottom right + -1.0, -1.0, 0.0, 0.0, 0.0, // bottom left + -1.0, 1.0, 0.0, 0.0, 1.0, // top left }; unsigned int indices[] = { - 0, 1, 2, // first triangle + 0, 1, 3, // first triangle 1, 2, 3 // second triangle }; @@ -86,8 +87,14 @@ unsigned int initialize_vertices() { glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + /* position attribute */ + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); glEnableVertexAttribArray(0); + /* texture coord attribute */ + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), + (void *)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + log_debug("Vertex data initialized successfully"); return VAO; diff --git a/src/shaders.c b/src/shaders.c index c90fdb8..8ff296e 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -63,13 +63,17 @@ char *read_file(const char *const filename) { */ int compile_shaders(unsigned int *shader_program, const char *const fragment_shader_file) { + log_debug("Compiling %s", fragment_shader_file); /* Compile vertex shader */ const char *const vertex_shader_source = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" + "layout (location = 1) in vec2 aTexCoord;\n" + "out vec2 TexCoord;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos, 1.0);\n" + " TexCoord = aTexCoord;\n" "}\n"; unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER);