working framebuffers, textures and feedback

This commit is contained in:
2025-09-15 00:10:00 +02:00
parent 85e061398e
commit ede531de57
6 changed files with 116 additions and 105 deletions
+3 -2
View File
@@ -100,11 +100,12 @@ make -f Makefile.dev release-arch
- [x] fps in window title - [x] fps in window title
- [x] Clean code - [x] Clean code
- [ ] Multi-stage shaders - [ ] 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 - [ ] 2 in 2 fx 1 mix 1 fx layout
- [ ] Include fragments with special directive - [ ] Include fragments with special directive
- [ ] 16 input + 16 fx definition and selection (with param) - [ ] 16 input + 16 fx definition and selection (with param)
- [ ] Feedback texture - [x] Feedback texture
- [ ] Free opengl memory
- [ ] Clean code - [ ] Clean code
- [ ] Midi - [ ] Midi
- [ ] Read Midi events - [ ] Read Midi events
+4 -4
View File
@@ -2,15 +2,15 @@
uniform float iTime; uniform float iTime;
uniform vec2 iResolution; uniform vec2 iResolution;
uniform sampler2D frame0;
in vec2 vUV; in vec2 vUV;
layout(location = 0) out vec4 fragColor; out vec3 fragColor;
uniform sampler2D frame0;
void main() { void main() {
vec2 uv0 = vUV.st; vec2 uv0 = vUV.st;
float ratio = iResolution.x / iResolution.y; float ratio = iResolution.x / iResolution.y;
vec2 uv1 = (uv0 - .5) * vec2(ratio, 1); vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
vec3 color = vec3(vUV, sin(iTime * 0.5) * 0.5 + 0.5); vec3 color = vec3(vUV, sin(iTime * 0.5) * 0.5 + 0.5);
color *= 1 - step(cos(iTime) * 0.1 + 0.5,length(uv1)); color *= 1 - step(cos(iTime) * 0.1 + 0.4, length(uv1));
fragColor = vec4(color, 1.0); fragColor = color + texture(frame0, vUV - 0.01).xyz * 0.5;
} }
+1 -5
View File
@@ -9,12 +9,8 @@
#define VERSION "(dev)" #define VERSION "(dev)"
#endif #endif
#ifndef FRAMEBUFFER_IDS
#define FRAMEBUFFER_IDS {0, 1, 2, 3, 4, 5, 6, 7}
#endif
#ifndef BUFFER_COUNT #ifndef BUFFER_COUNT
#define BUFFER_COUNT 8 #define BUFFER_COUNT 1
#endif #endif
#endif #endif
+4 -3
View File
@@ -5,7 +5,8 @@
static char *vertex_shader_text = static char *vertex_shader_text =
"#version 460\n" "#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" "in vec2 vPos;\n"
"out vec2 vUV;\n" "out vec2 vUV;\n"
"void main()\n" "void main()\n"
@@ -18,10 +19,10 @@ static char *output_fragment_shader_text =
"#version 460\n" "#version 460\n"
"in vec2 vUV;\n" "in vec2 vUV;\n"
"out vec4 fragColor;\n" "out vec4 fragColor;\n"
"uniform sampler2D frame0\n" "uniform sampler2D frame0;\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" fragColor = vec4(texture(frame0, vUV).xyz, 1.0);\n" " fragColor = texture(frame0, vUV);\n"
"}\n"; "}\n";
static const Vertex vertices[6] = {{{0.0f, 0.0f}}, {{0.0f, 1.0f}}, static const Vertex vertices[6] = {{{0.0f, 0.0f}}, {{0.0f, 1.0f}},
+95 -83
View File
@@ -34,65 +34,44 @@ bool compile_shader(GLuint shader_id, char *name, char *source_code) {
ShaderProgram init_program(File fragment_shader, Context context) { ShaderProgram init_program(File fragment_shader, Context context) {
int i, j; int i, j;
GLenum draw_buffers[BUFFER_COUNT];
char uniform_name[32]; 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++) { for (i = 0; i < BUFFER_COUNT; i++) {
draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i; glActiveTexture(GL_TEXTURE0 + 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]); glBindTexture(GL_TEXTURE_2D, program.textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0,
GL_RGB, GL_UNSIGNED_BYTE, 0); GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindRenderbuffer(GL_RENDERBUFFER, program.render_buffers[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, context.width, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
context.height); }
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, program.render_buffers[i]);
// create frame buffers
glGenFramebuffers(BUFFER_COUNT, program.frame_buffers);
for (i = 0; i < BUFFER_COUNT; i++) {
glBindFramebuffer(GL_FRAMEBUFFER, program.frame_buffers[i]); glBindFramebuffer(GL_FRAMEBUFFER, program.frame_buffers[i]);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
GL_RENDERBUFFER, program.render_buffers[i]); program.textures[i], 0);
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) { 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)); glCheckFramebufferStatus(GL_FRAMEBUFFER));
program.error = true; program.error = true;
return program; return program;
} }
} }
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// compile vertex shader // compile vertex shader
program.vertex_shader = glCreateShader(GL_VERTEX_SHADER); program.vertex_shader = glCreateShader(GL_VERTEX_SHADER);
program.error |= !compile_shader( program.error |= !compile_shader(
@@ -112,75 +91,108 @@ ShaderProgram init_program(File fragment_shader, Context context) {
return program; return program;
} }
// create and link full shader program // create vertex buffer and setup vertices
program.program = glCreateProgram(); glGenBuffers(1, &program.vertex_buffer);
glAttachShader(program.program, program.vertex_shader); glBindBuffer(GL_ARRAY_BUFFER, program.vertex_buffer);
glAttachShader(program.program, program.fragment_shader); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glAttachShader(program.program, program.output_fragment_shader);
glLinkProgram(program.program);
// create uniforms pointers // create vertex array
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
glGenVertexArrays(1, &program.vertex_array); glGenVertexArrays(1, &program.vertex_array);
glBindVertexArray(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; return program;
} }
void update_program(ShaderProgram program, File fragment_shader) { void update_program(ShaderProgram program, File fragment_shader) {
bool result; bool result;
int i;
result = compile_shader(program.fragment_shader, fragment_shader.path, result = compile_shader(program.fragment_shader, fragment_shader.path,
fragment_shader.content); fragment_shader.content);
if (result) { if (result) {
// re-link program // 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) { void apply_program(ShaderProgram program, Context context) {
mat4x4 m, p, mvp; int i, j;
// update viewport if (context.width != program.last_width ||
glViewport(0, 0, context.width, context.height); context.height != program.last_height) {
// clear buffer glViewport(0, 0, context.width, context.height);
glClear(GL_COLOR_BUFFER_BIT);
// create model-view-projection matrix for (i = 0; i < BUFFER_COUNT; i++) {
mat4x4_identity(m); glActiveTexture(GL_TEXTURE0 + i);
mat4x4_ortho(p, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context.width, context.height, 0,
mat4x4_mul(mvp, p, m); GL_RGB, GL_UNSIGNED_BYTE, 0);
}
}
vec2 resolution = {(float)context.width, (float)context.height}; vec2 resolution = {(float)context.width, (float)context.height};
// update uniforms for (i = 0; i < BUFFER_COUNT + 1; i++) {
glUseProgram(program.program); glUseProgram(program.programs[i]);
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);
// start vertex handling if (i == BUFFER_COUNT) {
glBindVertexArray(program.vertex_array); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
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
+8 -7
View File
@@ -30,23 +30,24 @@ typedef struct File {
typedef struct ShaderProgram { typedef struct ShaderProgram {
bool error; bool error;
GLuint program; int last_width;
int last_height;
GLuint programs[BUFFER_COUNT + 1];
GLuint vertex_shader; GLuint vertex_shader;
GLuint fragment_shader; GLuint fragment_shader;
GLuint output_fragment_shader; GLuint output_fragment_shader;
GLuint mvp_location; GLuint itime_locations[BUFFER_COUNT];
GLuint itime_location; GLuint ires_locations[BUFFER_COUNT];
GLuint ires_location; GLuint frames_locations[BUFFER_COUNT + 1][BUFFER_COUNT];
GLuint frames_location[BUFFER_COUNT]; GLuint vpos_locations[BUFFER_COUNT + 1];
GLuint vertex_buffer; GLuint vertex_buffer;
GLuint vertex_array; GLuint vertex_array;
GLuint vpos_location;
GLuint frame_buffers[BUFFER_COUNT]; GLuint frame_buffers[BUFFER_COUNT];
GLuint render_buffers[BUFFER_COUNT];
GLuint textures[BUFFER_COUNT]; GLuint textures[BUFFER_COUNT];
} ShaderProgram; } ShaderProgram;