From ede531de57273b4ca5c8c157f6d82e7a34ed4bdf Mon Sep 17 00:00:00 2001 From: klemek Date: Mon, 15 Sep 2025 00:10:00 +0200 Subject: [PATCH] working framebuffers, textures and feedback --- README.md | 5 +- shaders/frag.glsl | 8 +-- src/config.h | 6 +- src/constants.h | 7 +- src/shaders.c | 180 ++++++++++++++++++++++++---------------------- src/types.h | 15 ++-- 6 files changed, 116 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 0ad84c2..cb02a8e 100644 --- a/README.md +++ b/README.md @@ -100,11 +100,12 @@ make -f Makefile.dev release-arch - [x] fps in window title - [x] Clean code - [ ] Multi-stage shaders - - [ ] Test 2 stages with render to texture + - [x] Test 2 stages with render to texture - [ ] 2 in 2 fx 1 mix 1 fx layout - [ ] Include fragments with special directive - [ ] 16 input + 16 fx definition and selection (with param) - - [ ] Feedback texture + - [x] Feedback texture + - [ ] Free opengl memory - [ ] Clean code - [ ] Midi - [ ] Read Midi events diff --git a/shaders/frag.glsl b/shaders/frag.glsl index 562f429..61a6ea8 100644 --- a/shaders/frag.glsl +++ b/shaders/frag.glsl @@ -2,15 +2,15 @@ uniform float iTime; uniform vec2 iResolution; -uniform sampler2D frame0; in vec2 vUV; -layout(location = 0) out vec4 fragColor; +out vec3 fragColor; +uniform sampler2D frame0; void main() { vec2 uv0 = vUV.st; float ratio = iResolution.x / iResolution.y; vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); 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); + color *= 1 - step(cos(iTime) * 0.1 + 0.4, length(uv1)); + fragColor = color + texture(frame0, vUV - 0.01).xyz * 0.5; } \ No newline at end of file diff --git a/src/config.h b/src/config.h index a553bb1..7c2c8cd 100644 --- a/src/config.h +++ b/src/config.h @@ -9,12 +9,8 @@ #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 +#define BUFFER_COUNT 1 #endif #endif \ No newline at end of file diff --git a/src/constants.h b/src/constants.h index 0e2d851..843d6ba 100644 --- a/src/constants.h +++ b/src/constants.h @@ -5,7 +5,8 @@ static char *vertex_shader_text = "#version 460\n" - "uniform mat4 mvp;\n" + "const mat4 mvp = " + "{{2.,0.,0.,0.},{0.,2.,0.,0.},{0.,0.,2.,0.},{-1.,-1.,1.,1.}};\n" "in vec2 vPos;\n" "out vec2 vUV;\n" "void main()\n" @@ -18,10 +19,10 @@ static char *output_fragment_shader_text = "#version 460\n" "in vec2 vUV;\n" "out vec4 fragColor;\n" - "uniform sampler2D frame0\n" + "uniform sampler2D frame0;\n" "void main()\n" "{\n" - " fragColor = vec4(texture(frame0, vUV).xyz, 1.0);\n" + " fragColor = texture(frame0, vUV);\n" "}\n"; static const Vertex vertices[6] = {{{0.0f, 0.0f}}, {{0.0f, 1.0f}}, diff --git a/src/shaders.c b/src/shaders.c index 8ec7adb..ddebe32 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -34,65 +34,44 @@ bool compile_shader(GLuint shader_id, char *name, char *source_code) { ShaderProgram init_program(File fragment_shader, Context context) { int i, j; - GLenum draw_buffers[BUFFER_COUNT]; char uniform_name[32]; + ShaderProgram program = {.error = false, + .last_width = context.width, + .last_height = context.height}; + + // create empty textures + glGenTextures(BUFFER_COUNT, program.textures); + 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); + glActiveTexture(GL_TEXTURE0 + i); 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]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + // create frame buffers + glGenFramebuffers(BUFFER_COUNT, program.frame_buffers); + + for (i = 0; i < BUFFER_COUNT; 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); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + program.textures[i], 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - log_error("Framebuffer %d is KO: %x", i, + log_error("Framebuffer %d is KO: %x", i + 1, 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( @@ -112,75 +91,108 @@ ShaderProgram init_program(File fragment_shader, Context context) { return program; } - // create and link full shader program - program.program = glCreateProgram(); - glAttachShader(program.program, program.vertex_shader); - glAttachShader(program.program, program.fragment_shader); - glAttachShader(program.program, program.output_fragment_shader); - glLinkProgram(program.program); + // 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 uniforms pointers - program.mvp_location = glGetUniformLocation(program.program, "mvp"); - 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"); - - // create vertex array and bind to vPos attribute + // create vertex array 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)); - log_success("Program initialized"); + // create and link full shader program + for (i = 0; i < BUFFER_COUNT + 1; i++) { + program.programs[i] = glCreateProgram(); + glAttachShader(program.programs[i], program.vertex_shader); + if (i == BUFFER_COUNT) { + glAttachShader(program.programs[i], program.output_fragment_shader); + } else { + // TODO add others + glAttachShader(program.programs[i], program.fragment_shader); + } + glLinkProgram(program.programs[i]); + + // create uniforms pointers + if (i != BUFFER_COUNT) { + program.itime_locations[i] = + glGetUniformLocation(program.programs[i], "iTime"); + program.ires_locations[i] = + glGetUniformLocation(program.programs[i], "iResolution"); + } + + for (j = 0; j < BUFFER_COUNT; j++) { + sprintf(uniform_name, "frame%d", j); + program.frames_locations[i][j] = + glGetUniformLocation(program.programs[i], uniform_name); + } + + // create attribute pointer + program.vpos_locations[i] = + glGetAttribLocation(program.programs[i], "vPos"); + + glEnableVertexAttribArray(program.vpos_locations[i]); + glVertexAttribPointer(program.vpos_locations[i], 2, GL_FLOAT, GL_FALSE, + sizeof(Vertex), (void *)offsetof(Vertex, pos)); + + log_success("Program %d initialized", i); + } return program; } void update_program(ShaderProgram program, File fragment_shader) { bool result; + int i; result = compile_shader(program.fragment_shader, fragment_shader.path, fragment_shader.content); if (result) { // re-link program - glLinkProgram(program.program); + for (i = 0; i < BUFFER_COUNT; i++) { + glLinkProgram(program.programs[i]); + } - log_success("Program updated"); + log_success("Programs updated"); } } void apply_program(ShaderProgram program, Context context) { - mat4x4 m, p, mvp; + int i, j; - // update viewport - glViewport(0, 0, context.width, context.height); - // clear buffer - glClear(GL_COLOR_BUFFER_BIT); + if (context.width != program.last_width || + context.height != program.last_height) { + glViewport(0, 0, context.width, context.height); - // 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); + for (i = 0; i < BUFFER_COUNT; i++) { + glActiveTexture(GL_TEXTURE0 + i); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0, + GL_RGB, GL_UNSIGNED_BYTE, 0); + } + } 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); + for (i = 0; i < BUFFER_COUNT + 1; i++) { + glUseProgram(program.programs[i]); - // start vertex handling - glBindVertexArray(program.vertex_array); - glDrawArrays(GL_TRIANGLES, 0, 6); -} \ No newline at end of file + if (i == BUFFER_COUNT) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glClear(GL_COLOR_BUFFER_BIT); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, program.frame_buffers[0]); + + glUniform1f(program.itime_locations[i], (const GLfloat)context.time); + glUniform2fv(program.ires_locations[i], 1, (const GLfloat *)&resolution); + } + + for (j = 0; j < BUFFER_COUNT; j++) { + glUniform1i(program.frames_locations[i][j], j); + } + + glDrawArrays(GL_TRIANGLES, 0, 6); + } +} + +// TODO clean buffers from opengl memories \ No newline at end of file diff --git a/src/types.h b/src/types.h index 2590836..6c25b50 100644 --- a/src/types.h +++ b/src/types.h @@ -30,23 +30,24 @@ typedef struct File { typedef struct ShaderProgram { bool error; - GLuint program; + int last_width; + int last_height; + + GLuint programs[BUFFER_COUNT + 1]; GLuint vertex_shader; GLuint fragment_shader; GLuint output_fragment_shader; - GLuint mvp_location; - GLuint itime_location; - GLuint ires_location; - GLuint frames_location[BUFFER_COUNT]; + GLuint itime_locations[BUFFER_COUNT]; + GLuint ires_locations[BUFFER_COUNT]; + GLuint frames_locations[BUFFER_COUNT + 1][BUFFER_COUNT]; + GLuint vpos_locations[BUFFER_COUNT + 1]; GLuint vertex_buffer; GLuint vertex_array; - GLuint vpos_location; GLuint frame_buffers[BUFFER_COUNT]; - GLuint render_buffers[BUFFER_COUNT]; GLuint textures[BUFFER_COUNT]; } ShaderProgram;