Browse Source

Introduce framebuffer for flashbanging on hot reloading

rexim 3 years ago
parent
commit
45f8089da5
6 changed files with 134 additions and 11 deletions
  1. 14 0
      glextloader.c
  2. 91 10
      main.c
  3. 1 0
      render.conf
  4. 14 0
      shaders/debug.frag
  5. 12 0
      shaders/debug.vert
  6. 2 1
      shaders/main.frag

+ 14 - 0
glextloader.c

@@ -24,6 +24,13 @@ static PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = NULL;
 static PFNGLUNIFORM1FPROC glUniform1f = NULL;
 static PFNGLBUFFERSUBDATAPROC glBufferSubData = NULL;
 static PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced = NULL;
+static PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
+static PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
+static PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
+static PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = NULL;
+static PFNGLUNIFORM1IPROC glUniform1i = NULL;
+static PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL;
+static PFNGLUNIFORM4FPROC glUniform4f = NULL;
 
 static void load_gl_extensions(void)
 {
@@ -53,6 +60,13 @@ static void load_gl_extensions(void)
     glVertexAttribPointer     = (PFNGLVERTEXATTRIBPOINTERPROC) glfwGetProcAddress("glVertexAttribPointer");
     glUniform1f               = (PFNGLUNIFORM1FPROC) glfwGetProcAddress("glUniform1f");
     glBufferSubData           = (PFNGLBUFFERSUBDATAPROC) glfwGetProcAddress("glBufferSubData");
+    glGenFramebuffers         = (PFNGLGENFRAMEBUFFERSPROC) glfwGetProcAddress("glGenFramebuffers");
+    glBindFramebuffer         = (PFNGLBINDFRAMEBUFFERPROC) glfwGetProcAddress("glBindFramebuffer");
+    glFramebufferTexture2D    = (PFNGLFRAMEBUFFERTEXTURE2DPROC) glfwGetProcAddress("glFramebufferTexture2D");
+    glCheckFramebufferStatus  = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) glfwGetProcAddress("glCheckFramebufferStatus");
+    glUniform1i               = (PFNGLUNIFORM1IPROC) glfwGetProcAddress("glUniform1i");
+    glDrawBuffers             = (PFNGLDRAWBUFFERSPROC) glfwGetProcAddress("glDrawBuffers");
+    glUniform4f               = (PFNGLUNIFORM4FPROC) glfwGetProcAddress("glUniform4f");
 
     if (glfwExtensionSupported("GL_ARB_debug_output")) {
         fprintf(stderr, "INFO: ARB_debug_output is supported\n");

+ 91 - 10
main.c

@@ -331,6 +331,7 @@ bool r_reload_textures(Renderer *r)
 
     glDeleteTextures(1, &r->texture);
     glGenTextures(1, &r->texture);
+    glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, r->texture);
 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -370,18 +371,26 @@ bool r_reload_shaders(Renderer *r)
     return true;
 }
 
-void r_reload(Renderer *r)
+bool r_reload(Renderer *r)
 {
     r->reload_failed = true;
-    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
 
-    if (!r_reload_shaders(r)) return;
-    if (!r_reload_textures(r)) return;
+    if (!r_reload_shaders(r)) return false;
+    if (!r_reload_textures(r)) return false;
 
     r->reload_failed = false;
-    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+    return true;
 }
 
+#define COLOR_BLACK_V4F ((V4f){0.0f, 0.0f, 0.0f, 1.0f})
+#define COLOR_RED_V4F ((V4f){1.0f, 0.0f, 0.0f, 1.0f})
+#define COLOR_GREEN_V4F ((V4f){0.0f, 1.0f, 0.0f, 1.0f})
+
+float t = 0.0f;
+float dt = 0.0f;
+V4f color = {0};
+
 void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
 {
     (void) scancode;
@@ -391,7 +400,13 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
     if (action == GLFW_PRESS) {
         if (key == GLFW_KEY_F5) {
             reload_render_conf("render.conf");
-            r_reload(&global_renderer);
+            dt = -2.0f;
+            t = 1.0f;
+            if (r_reload(&global_renderer)) {
+                color = COLOR_GREEN_V4F;
+            } else {
+                color = COLOR_RED_V4F;
+            }
         } else if (key == GLFW_KEY_F6) {
 #define SCREENSHOT_PNG_PATH "screenshot.png"
             printf("Saving the screenshot at %s\n", SCREENSHOT_PNG_PATH);
@@ -424,6 +439,8 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
     }
 }
 
+GLuint framebuffer;
+
 void window_size_callback(GLFWwindow* window, int width, int height)
 {
     (void) window;
@@ -487,7 +504,7 @@ void r_clear(Renderer *r)
     r->vertex_buf_sz = 0;
 }
 
-#define COLOR_BLACK_V4F ((V4f){0.0f, 0.0f, 0.0f, 1.0f})
+
 
 int main(void)
 {
@@ -535,6 +552,55 @@ int main(void)
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
+    GLuint framebuffer_texture;
+    glGenTextures(1, &framebuffer_texture);
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, framebuffer_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_BORDER);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+
+    glTexImage2D(
+        GL_TEXTURE_2D,
+        0,
+        GL_RGBA,
+        DEFAULT_SCREEN_WIDTH,
+        DEFAULT_SCREEN_HEIGHT,
+        0,
+        GL_RGBA,
+        GL_UNSIGNED_BYTE,
+        NULL);
+
+    glGenFramebuffers(1, &framebuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer_texture, 0);
+
+    GLenum draw_buffers = GL_COLOR_ATTACHMENT0;
+    glDrawBuffers(1, &draw_buffers);
+
+    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (status != GL_FRAMEBUFFER_COMPLETE) {
+        fprintf(stderr, "ERROR: Could not complete the framebuffer\n");
+        exit(1);
+    }
+
+    GLuint framebuffer_program;
+    if (!load_shader_program("./shaders/debug.vert", "./shaders/debug.frag", &framebuffer_program)) {
+        exit(1);
+    }
+    glUseProgram(framebuffer_program);
+
+    GLuint framebuffer_tex_uniform = glGetUniformLocation(framebuffer_program, "tex");
+    GLuint framebuffer_color_uniform = glGetUniformLocation(framebuffer_program, "color");
+    GLuint framebuffer_t_uniform = glGetUniformLocation(framebuffer_program, "t");
+
+    glUniform1i(framebuffer_tex_uniform, 1);
+    glUniform4f(framebuffer_color_uniform, 1.0, 0.0, 0.0, 1.0);
+
+    printf("Successfully created the debug framebuffer\n");
+
     Renderer *r = &global_renderer;
 
     r_init(r);
@@ -547,6 +613,8 @@ int main(void)
     double prev_time = 0.0;
     double delta_time = 0.0f;
     while (!glfwWindowShouldClose(window)) {
+        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+
         glClear(GL_COLOR_BUFFER_BIT);
 
         int width, height;
@@ -556,7 +624,8 @@ int main(void)
         xpos = xpos - width * 0.5f;
         ypos = (height - ypos) - height * 0.5f;
 
-        if (!global_renderer.reload_failed) {
+        // if (!r->reload_failed) {
+            glUseProgram(r->program);
             r_clear(r);
             r_sync_uniforms(r, width, height, time, xpos, ypos);
             r_quad_cr(
@@ -566,9 +635,21 @@ int main(void)
                 COLOR_BLACK_V4F);
             r_sync_buffers(r);
 
-            glDrawArraysInstanced(GL_TRIANGLES, 0, (GLsizei) global_renderer.vertex_buf_sz, 1);
-        }
+            glDrawArraysInstanced(GL_TRIANGLES, 0, (GLsizei) r->vertex_buf_sz, 1);
+        // }
 
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+        glClear(GL_COLOR_BUFFER_BIT);
+        glUseProgram(framebuffer_program);
+        t += dt * delta_time;
+        if (t <= 0.0f) {
+            t = 0.0f;
+            dt = 0.0f;
+        }
+        glUniform1f(framebuffer_t_uniform, t);
+        glUniform4f(framebuffer_color_uniform, color.x, color.y, color.z, color.w);
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
         glfwSwapBuffers(window);
         glfwPollEvents();

+ 1 - 0
render.conf

@@ -1,3 +1,4 @@
 vert = shaders/main.vert
 frag = shaders/main.frag
 texture = assets/tsodinW-345.png
+#texture = assets/tsodinFlushed-112.png

+ 14 - 0
shaders/debug.frag

@@ -0,0 +1,14 @@
+#version 330
+
+precision mediump float;
+
+uniform sampler2D tex;
+uniform vec4 color;
+uniform float t;
+
+in vec2 uv;
+out vec4 out_color;
+
+void main(void) {
+    out_color = mix(texture(tex, vec2(uv.x, uv.y)), color, t);
+}

+ 12 - 0
shaders/debug.vert

@@ -0,0 +1,12 @@
+#version 330
+
+precision mediump float;
+
+out vec2 uv;
+
+void main(void)
+{
+    uv.x = (gl_VertexID & 1);
+    uv.y = ((gl_VertexID >> 1) & 1);
+    gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0);
+}

+ 2 - 1
shaders/main.frag

@@ -5,13 +5,14 @@ precision mediump float;
 uniform vec2 resolution;
 uniform float time;
 uniform vec2 mouse;
+uniform sampler2D tex;
 
 in vec2 uv;
 in vec4 color;
 out vec4 out_color;
 
 void main(void) {
-    out_color = vec4(
+    out_color = texture(tex, vec2(uv.x, 1.0 - uv.y)) * vec4(
         (sin(uv.x + time) + 1.0) / 2.0,
         (cos(uv.y + time) + 1.0) / 2.0,
         (cos(uv.x + uv.y + time) + 1.0) / 2.0,