diff --git a/shaders/frag.glsl b/shaders/frag.glsl index 3a76911..2e0adeb 100644 --- a/shaders/frag.glsl +++ b/shaders/frag.glsl @@ -2,8 +2,10 @@ uniform float iTime; uniform vec2 iResolution; +uniform sampler2D frame0; in vec2 vUV; out vec4 fragColor; +layout(location = 0) out vec4 fragColor2; void main() { vec2 uv0 = vUV.st; @@ -12,4 +14,5 @@ void main() { 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); + fragColor2 = vec4(color, 1.0); } \ No newline at end of file diff --git a/src/config.h b/src/config.h index 3dc61d6..a553bb1 100644 --- a/src/config.h +++ b/src/config.h @@ -9,4 +9,12 @@ #define VERSION "(dev)" #endif +#ifndef FRAMEBUFFER_IDS +#define FRAMEBUFFER_IDS {0, 1, 2, 3, 4, 5, 6, 7} +#endif + +#ifndef BUFFER_COUNT +#define BUFFER_COUNT 8 +#endif + #endif \ No newline at end of file diff --git a/src/forge.c b/src/forge.c index 1d2caac..0636823 100644 --- a/src/forge.c +++ b/src/forge.c @@ -59,6 +59,7 @@ void forge_run(Parameters params) { ShaderProgram program; Window *window; Timer timer; + Context context; fragment_shader = read_file(params.frag_path); @@ -69,7 +70,9 @@ void forge_run(Parameters params) { window = init_window(PACKAGE " " VERSION, params.screen, error_callback, key_callback); - program = init_program(fragment_shader); + context = get_window_context(window); + + program = init_program(fragment_shader, context); if (program.error) { close_window(window, true); diff --git a/src/shaders.c b/src/shaders.c index bb340c6..0f9c035 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -2,6 +2,7 @@ #include #include +#include "config.h" #include "constants.h" #include "logs.h" #include "types.h" @@ -31,14 +32,67 @@ bool compile_shader(GLuint shader_id, char *name, char *source_code) { return status_params == GL_TRUE; } -ShaderProgram init_program(File fragment_shader) { - ShaderProgram program = {0}; +ShaderProgram init_program(File fragment_shader, Context context) { + int i, j; + GLenum draw_buffers[BUFFER_COUNT]; + char uniform_name[32]; + + for (i = 0; i < BUFFER_COUNT; i++) { + draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i; + } + + ShaderProgram program = {.error = false, .frame_buffers = FRAMEBUFFER_IDS}; // 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); + // create framebuffers and textures + glGenTextures(1, program.textures); + glGenFramebuffers(BUFFER_COUNT, program.frame_buffers); + glGenRenderbuffers(BUFFER_COUNT, program.render_buffers); + for (i = 0; i < BUFFER_COUNT; i++) { + glTextureParameteri(program.textures[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTextureParameteri(program.textures[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTextureParameteri(program.textures[i], GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTextureParameteri(program.textures[i], GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, program.textures[i]); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, program.render_buffers[i]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, context.width, + context.height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, program.render_buffers[i]); + + glBindFramebuffer(GL_FRAMEBUFFER, program.frame_buffers[i]); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, program.render_buffers[i]); + + for (j = 0; j < BUFFER_COUNT; j++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + j, + GL_TEXTURE_2D, program.textures[j], 0); + } + + glDrawBuffers(BUFFER_COUNT, draw_buffers); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + log_error("Framebuffer %d is KO: %x", i, + glCheckFramebufferStatus(GL_FRAMEBUFFER)); + program.error = true; + return program; + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + // compile vertex shader program.vertex_shader = glCreateShader(GL_VERTEX_SHADER); program.error |= !compile_shader( @@ -64,6 +118,12 @@ ShaderProgram init_program(File fragment_shader) { program.itime_location = glGetUniformLocation(program.program, "iTime"); program.ires_location = glGetUniformLocation(program.program, "iResolution"); + for (i = 0; i < BUFFER_COUNT; i++) { + sprintf(uniform_name, "frame%d", i); + program.frames_location[i] = + glGetUniformLocation(program.program, uniform_name); + } + // create attribute pointer program.vpos_location = glGetAttribLocation(program.program, "vPos"); diff --git a/src/shaders.h b/src/shaders.h index b89622e..3c75a09 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -3,7 +3,7 @@ #ifndef SHADERS_H #define SHADERS_H -ShaderProgram init_program(File fragment_shader); +ShaderProgram init_program(File fragment_shader, Context context); void update_program(ShaderProgram program, File fragment_shader); diff --git a/src/types.h b/src/types.h index 2a1f1dc..d0a3920 100644 --- a/src/types.h +++ b/src/types.h @@ -5,6 +5,8 @@ #include #include +#include "config.h" + #ifndef TYPES_H #define TYPES_H @@ -36,10 +38,15 @@ typedef struct ShaderProgram { GLuint mvp_location; GLuint itime_location; GLuint ires_location; + GLuint frames_location[BUFFER_COUNT]; GLuint vertex_buffer; GLuint vertex_array; GLuint vpos_location; + + GLuint frame_buffers[BUFFER_COUNT]; + GLuint render_buffers[BUFFER_COUNT]; + GLuint textures[BUFFER_COUNT]; } ShaderProgram; typedef GLFWwindow Window;