A 3d fps game made in OpenGL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Symmetry/src/framebuffer.c

300 lines
8.3 KiB

#include "framebuffer.h"
#include "array.h"
#include "renderer.h"
#include "log.h"
#include "texture.h"
#include "gl_load.h"
#include <assert.h>
struct FBO
{
uint handle;
uint depth_renderbuffer;
uint color_renderbuffer;
int texture_attachments[FA_NUM_ATTACHMENTS];
int width;
int height;
int resizeable;
};
struct FBO* fbo_list;
int* empty_indices;
void framebuffer_init(void)
{
fbo_list = array_new(struct FBO);
empty_indices = array_new(int);
}
void framebuffer_cleanup(void)
{
for(int i = 0; i < array_len(fbo_list); i++)
framebuffer_remove(i);
array_free(fbo_list);
array_free(empty_indices);
fbo_list = NULL;
empty_indices = NULL;
}
int framebuffer_create(int width, int height, int has_depth, int has_color, int resizeable)
{
int index = -1;
GLuint fbo = 0;
GLuint depth_renderbuffer = 0;
GLuint color_renderbuffer = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
if(has_depth)
{
glGenRenderbuffers(1, &depth_renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER,
GL_DEPTH_COMPONENT,
width,
height);
renderer_check_glerror("framebuffer:create:depth_renderbuffer");
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
depth_renderbuffer);
renderer_check_glerror("framebuffer:create:depth_renderbuffer");
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
if(has_color)
{
glGenRenderbuffers(1, &color_renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER,
GL_RGBA8,
width,
height);
renderer_check_glerror("framebuffer:create:color_renderbuffer");
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
color_renderbuffer);
renderer_check_glerror("framebuffer:create:color_renderbuffer");
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
glDrawBuffer(has_color ? GL_COLOR_ATTACHMENT0 : GL_NONE);
renderer_check_glerror("framebuffer:create");
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
{
log_error("framebuffer:create", "Framebuffer not created!");
renderer_check_glerror("framebuffer:create");
}
else
{
struct FBO* framebuffer = NULL;
if(array_len(empty_indices) == 0)
{
framebuffer = array_grow(fbo_list, struct FBO);
index = array_len(fbo_list) - 1;
}
else
{
index = *array_get_last(empty_indices, int);
array_pop(empty_indices);
}
framebuffer->handle = fbo;
framebuffer->depth_renderbuffer = depth_renderbuffer;
framebuffer->color_renderbuffer = color_renderbuffer;
framebuffer->width = width;
framebuffer->height = height;
framebuffer->resizeable = resizeable;
for(int i = 0; i < FA_NUM_ATTACHMENTS; i++) framebuffer->texture_attachments[i] = -1;
log_message("Framebuffer created successfully");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return index;
}
void framebuffer_bind(int index)
{
assert(index < array_len(fbo_list) && index > -1);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_list[index].handle);
/* if(fbo_list[index].color_renderbuffer != 0) */
/* glDrawBuffer(GL_COLOR_ATTACHMENT0); */
/* else */
/* glDrawBuffer(GL_NONE); */
}
void framebuffer_remove(int index)
{
assert(index < array_len(fbo_list) && index > -1);
struct FBO* fbo = &fbo_list[index];
for(int i = 0; i < FA_NUM_ATTACHMENTS; i++)
{
if(fbo->texture_attachments[i] != -1)
{
texture_remove(fbo->texture_attachments[i]);
fbo->texture_attachments[i] = -1;
}
}
if(fbo->depth_renderbuffer != 0) glDeleteRenderbuffers(1, &fbo->depth_renderbuffer);
if(fbo->color_renderbuffer != 0) glDeleteRenderbuffers(1, &fbo->color_renderbuffer);
glDeleteFramebuffers(1, &fbo->handle);
fbo->color_renderbuffer = 0;
fbo->depth_renderbuffer = 0;
fbo->handle = 0;
fbo->width = -1;
fbo->height = -1;
}
void framebuffer_unbind(void)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
int framebuffer_get_width(int index)
{
assert(index < array_len(fbo_list) && index > -1);
return fbo_list[index].width;
}
int framebuffer_get_height(int index)
{
assert(index < array_len(fbo_list) && index > -1);
return fbo_list[index].height;
}
void framebuffer_set_texture(int index, int texture, enum Framebuffer_Attachment attachment)
{
assert(index < array_len(fbo_list) && index > -1);
GLenum gl_attachment = -1;
switch(attachment)
{
case FA_COLOR_ATTACHMENT0: gl_attachment = GL_COLOR_ATTACHMENT0; break;
case FA_DEPTH_ATTACHMENT: gl_attachment = GL_DEPTH_ATTACHMENT; break;
default: log_error("framebuffer:set_texture", "Invalid attachment type"); return;
};
struct FBO* fbo = &fbo_list[index];
int current_texture = fbo->texture_attachments[attachment];
if(current_texture != -1)
{
texture_remove(current_texture);
fbo->texture_attachments[attachment] = -1;
}
if(texture == -1) return;
GLint current_fbo = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
renderer_check_glerror("framebuffer:set_texture:glGet");
framebuffer_bind(index);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
gl_attachment,
GL_TEXTURE_2D,
texture_get_texture_handle(texture),
0);
renderer_check_glerror("framebuffer:set_texture:glFramebuffertexture2d");
fbo->texture_attachments[attachment] = texture;
if(attachment == FA_COLOR_ATTACHMENT0) glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
}
int framebuffer_get_texture(int index, enum Framebuffer_Attachment attachment)
{
assert(index < array_len(fbo_list) &&
index > -1 &&
attachment < FA_NUM_ATTACHMENTS &&
(int)attachment > -1);
return fbo_list[index].texture_attachments[attachment];
}
uint framebuffer_get_gl_handle(int index)
{
assert(index < array_len(fbo_list) && index > -1);
return fbo_list[index].handle;
}
void framebuffer_resize(int index, int width, int height)
{
assert(index > -1 && index < array_len(fbo_list));
width -= (width % 2);
height -= (height % 2);
GLint current_fbo = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_fbo);
renderer_check_glerror("framebuffer:resize:glGet");
struct FBO* fbo = &fbo_list[index];
if(!fbo->resizeable) return;
framebuffer_bind(index);
if(fbo->depth_renderbuffer != 0)
{
glBindRenderbuffer(GL_RENDERBUFFER, fbo->depth_renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER,
GL_DEPTH_COMPONENT,
width,
height);
renderer_check_glerror("framebuffer:resize:depth_renderbuffer");
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
fbo->depth_renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
if(fbo->color_renderbuffer != 0)
{
glBindRenderbuffer(GL_RENDERBUFFER, fbo->color_renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER,
GL_RGBA8,
width,
height);
renderer_check_glerror("framebuffer:resize:color_renderbuffer");
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
fbo->color_renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
for(int i = 0; i < FA_NUM_ATTACHMENTS; i++)
{
if(fbo->texture_attachments[i] != -1)
{
int texture = fbo->texture_attachments[i];
GLenum gl_attachment = -1;
switch(i)
{
case FA_COLOR_ATTACHMENT0: gl_attachment = GL_COLOR_ATTACHMENT0; break;
case FA_DEPTH_ATTACHMENT: gl_attachment = GL_DEPTH_ATTACHMENT; break;
default: log_error("framebuffer:resize", "Invalid attachment type"); continue;
};
texture_resize(texture, width, height, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
gl_attachment,
GL_TEXTURE_2D,
texture_get_texture_handle(texture),
0);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
fbo->width = width;
fbo->height = height;
log_message("Resized framebuffer to %dx%d", width, height);
}
void framebuffer_resize_all(int width, int height)
{
for(int i = 0; i < array_len(fbo_list); i++)
{
if(fbo_list[i].resizeable) framebuffer_resize(i, width, height);
}
}
void framebuffer_resizeable_set(int index, int resizeable)
{
assert(index > -1 && index < array_len(fbo_list));
fbo_list[index].resizeable = resizeable ? 1 : 0;
}