working framebuffers, textures and feedback
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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}},
|
||||||
|
|||||||
+96
-84
@@ -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
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user