diff --git a/orgfile.org b/orgfile.org index 35db945..a0b7b49 100644 --- a/orgfile.org +++ b/orgfile.org @@ -36,6 +36,7 @@ while using as few libraries as possible. - State "DONE" from "TODO" [2015-08-02 Sun 19:09] ** TODO Fix readme markdown ** TODO Framebuffer and resolution independent rendering +** TODO Remove Kazmath dependency ** DONE Entity - State "DONE" from "TODO" [2015-09-15 Tue 12:17] ** TODO Positive and negative values for input_maps and returning corresponding values when they are true diff --git a/src/framebuffer.c b/src/framebuffer.c new file mode 100644 index 0000000..1babd74 --- /dev/null +++ b/src/framebuffer.c @@ -0,0 +1,163 @@ +#include "framebuffer.h" +#include "array.h" +#include "num_types.h" +#include "renderer.h" +#include "log.h" +#include "texture.h" + +#include "GL/glew.h" +#include "GLFW/glfw3.h" +#include + +struct FBO +{ + uint handle; + uint renderbuffer; + int texture; + int width; + int height; +}; + +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); +} + +int framebuffer_create(int width, int height, int has_depth, int has_color) +{ + int index = -1; + GLuint fbo; + GLuint renderbuffer; + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glGenRenderbuffers(1, &renderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); + glRenderbufferStorage(GL_RENDERBUFFER, + GL_DEPTH24_STENCIL8, + width, + height); + renderer_check_glerror("framebuffer:create"); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_DEPTH_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + renderbuffer); + renderer_check_glerror("framebuffer:create"); + if(has_color) + { + glDrawBuffer(GL_COLOR_ATTACHMENT0); + } + + if(has_depth) + { + glDrawBuffer(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->renderbuffer = renderbuffer; + framebuffer->texture = -1; + framebuffer->width = width; + framebuffer->height = height; + log_message("Framebuffer created successfully"); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + return index; +} + +void framebuffer_bind(int index) +{ + assert(index < array_len(fbo_list) && index > -1); + glBindFramebuffer(GL_FRAMEBUFFER, fbo_list[index].handle); +} + +void framebuffer_remove(int index) +{ + assert(index < array_len(fbo_list) && index > -1); + struct FBO* fbo = &fbo_list[index]; + if(fbo->texture != -1) texture_remove(fbo->texture); + glDeleteRenderbuffers(1, &fbo->renderbuffer); + glDeleteFramebuffers(1, &fbo->handle); +} + +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, int attachment) +{ + assert(index < array_len(fbo_list) && index > -1); + GLint current_fbo = 0; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo); + renderer_check_glerror("framebuffer:set_texture:glGet"); + framebuffer_bind(index); + glFramebufferTexture2D(GL_FRAMEBUFFER, + attachment, + GL_TEXTURE_2D, + texture_get_texture_handle(texture), + 0); + if(!renderer_check_glerror("framebuffer:set_texture:glFramebuffertexture")) + { + int current_fbo_tex = fbo_list[index].texture; + if(current_fbo_tex > -1) + texture_remove(current_fbo_tex); + + fbo_list[index].texture = texture; + texture_inc_refcount(texture); + } + glBindFramebuffer(GL_FRAMEBUFFER, current_fbo); +} + +int framebuffer_get_texture(int index) +{ + assert(index < array_len(fbo_list) && index > -1); + return fbo_list[index].texture; +} diff --git a/src/framebuffer.h b/src/framebuffer.h new file mode 100644 index 0000000..9347571 --- /dev/null +++ b/src/framebuffer.h @@ -0,0 +1,15 @@ +#ifndef framebuffer_H +#define framebuffer_H + +void framebuffer_init(void); +void framebuffer_cleanup(void); +int framebuffer_create(int width, int height, int has_depth, int has_color); +void framebuffer_bind(int index); +void framebuffer_remove(int index); +void framebuffer_unbind(void); +int framebuffer_get_width(int index); +int framebuffer_get_height(int index); +void framebuffer_set_texture(int index, int texture, int attachment); +int framebuffer_get_texture(int index); + +#endif diff --git a/src/game.c b/src/game.c index e4b5a89..1bc0e91 100644 --- a/src/game.c +++ b/src/game.c @@ -20,6 +20,7 @@ #include "utils.h" #include "texture.h" #include "material.h" +#include "framebuffer.h" void run(void); void update(float dt); @@ -32,6 +33,7 @@ int player_pitch_node = -1; void game_init(void) { + /* TODO: Implement dealing with init failures */ GLFWwindow* window = window_get_active(); /* Init systems */ input_init(window); @@ -39,6 +41,7 @@ void game_init(void) io_file_init("/mnt/Dev/Projects/Symmetry/assets/");/* TODO: Implement proper way of getting binary directory */ shader_init(); texture_init(); + framebuffer_init(); transform_init(); camera_init(); geom_init(); @@ -273,6 +276,7 @@ void game_cleanup(void) input_cleanup(); renderer_cleanup(); io_file_cleanup(); + framebuffer_cleanup(); texture_cleanup(); shader_cleanup(); } diff --git a/src/renderer.c b/src/renderer.c index 461bac9..292325d 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -5,6 +5,8 @@ #include "camera.h" #include "model.h" +static int default_fbo = -1; + void on_framebuffer_size_change(GLFWwindow* window, int width, int height); void renderer_init(GLFWwindow* window) @@ -38,11 +40,12 @@ void renderer_set_clearcolor(float red, float green, float blue, float alpha) glClearColor(red, green, blue, alpha); } -void renderer_check_glerror(const char* context) +int renderer_check_glerror(const char* context) { - GLenum error = glGetError(); + int error = 1; + GLenum error_code = glGetError(); const char* errorString = "No Error"; - switch(error) + switch(error_code) { case GL_INVALID_OPERATION: errorString = "Invalid Operation"; @@ -70,8 +73,10 @@ void renderer_check_glerror(const char* context) break; } - if(error != GL_NO_ERROR) - { + if(error_code != GL_NO_ERROR) log_error(context, errorString); - } + else + error = 0; + + return error; } diff --git a/src/renderer.h b/src/renderer.h index 97c4000..53870d9 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -7,6 +7,6 @@ void renderer_init(GLFWwindow* window); void renderer_draw(void); void renderer_cleanup(void); void renderer_set_clearcolor(float r, float g, float b, float a); -void renderer_check_glerror(const char* context); +int renderer_check_glerror(const char* context); #endif diff --git a/src/texture.c b/src/texture.c index c53d2cc..c5f5e6d 100644 --- a/src/texture.c +++ b/src/texture.c @@ -44,6 +44,7 @@ static int* empty_indices; int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt, int* internal_fmt); void debug_write_tga(struct Tga_Header* header, GLubyte* image_data); void copy_tga_pixel(GLubyte* source, GLubyte* dest, size_t bytes_per_pixel); +int create_gl_texture(uint* out_handle, int width, int height, int format, int int_fmt, int type, void* data); void texture_init(void) { @@ -62,7 +63,6 @@ int texture_create_from_file(const char* filename, int texture_unit) return index; } /* If texture not already loaded then try to load it */ - uint handle = 0; char* full_path = str_new("textures/"); full_path = str_concat(full_path, filename); FILE* file = io_file_open(full_path, "rb"); @@ -71,42 +71,25 @@ int texture_create_from_file(const char* filename, int texture_unit) if(file) { /* Load texture here */ - int width, height, internal_fmt, fmt; + int width, height, int_fmt, fmt; GLubyte* img_data = NULL; - width = height = internal_fmt = fmt = -1; - img_load_success = load_img(file, &img_data, &width, &height, &fmt, &internal_fmt); + width = height = int_fmt = fmt = -1; + img_load_success = load_img(file, &img_data, &width, &height, &fmt, &int_fmt); if(img_load_success) { - struct Texture* new_texture = NULL; - if(array_len(empty_indices) > 0) + index = texture_create(filename, texture_unit, width, height, fmt, int_fmt, GL_UNSIGNED_BYTE, img_data); + if(index > -1) { - index = *array_get_last(empty_indices, int); - array_pop(empty_indices); - new_texture = &texture_list[index]; + texture_param_set(index, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + texture_param_set(index, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + texture_param_set(index,GL_TEXTURE_WRAP_S,GL_REPEAT); + texture_param_set(index,GL_TEXTURE_WRAP_T,GL_REPEAT); } else { - new_texture = array_grow(texture_list, struct Texture); - index = array_len(texture_list) - 1; - new_texture->name = NULL; + log_error("texture:create_from_file", "Error creating texture"); } - assert(new_texture); - glGenTextures(1, &handle); - if(new_texture->name) - free(new_texture->name); - new_texture->name = str_new(filename); - new_texture->ref_count = 1; - new_texture->handle = handle; - new_texture->texture_unit = texture_unit; - glBindTexture(GL_TEXTURE_2D, handle); - texture_param_set(index, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - texture_param_set(index, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - texture_param_set(index,GL_TEXTURE_WRAP_S,GL_REPEAT); - texture_param_set(index,GL_TEXTURE_WRAP_T,GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, internal_fmt, width, height, 0, fmt, GL_UNSIGNED_BYTE, img_data); - renderer_check_glerror("texture:create"); - glBindTexture(GL_TEXTURE_2D, 0); free(img_data); } fclose(file); @@ -358,3 +341,75 @@ int texture_get_textureunit(int index) assert(index > -1 && index < array_len(texture_list)); return texture_list[index].texture_unit; } + +int texture_get_texture_handle(int index) +{ + assert(index > -1 && index < array_len(texture_list)); + return texture_list[index].handle; +} + +void texture_inc_refcount(int index) +{ + assert(index > -1 && index < array_len(texture_list)); + texture_list[index].ref_count++; +} + +void texture_dec_refcount(int index) +{ + assert(index > -1 && index < array_len(texture_list)); + texture_list[index].ref_count--; +} + +int texture_create(const char* name, + int texture_unit, + int width, + int height, + int format, + int int_fmt, + int type, + void* data) +{ + assert(name && texture_unit > -1 && texture_unit <= TU_SHADOWMAP4); + int index = -1; + uint handle = 0; + int success = create_gl_texture(&handle, width, height, format, int_fmt, type, data); + if(success) + { + struct Texture* new_tex = NULL; + if(array_len(empty_indices) > 0) + { + index = *array_get_last(empty_indices, int); + array_pop(empty_indices); + new_tex = &texture_list[index]; + } + else + { + new_tex = array_grow(texture_list, struct Texture); + index = array_len(texture_list) - 1; + } + new_tex->name = str_new(name); + new_tex->handle = handle; + new_tex->ref_count = 1; + new_tex->texture_unit = texture_unit; + } + return index; +} + +int create_gl_texture(uint* out_handle, int width, int height, int format, int int_fmt, int type, void* data) +{ + int success = 1; + glGenTextures(1, out_handle); + if(renderer_check_glerror("texture:create_gl_texture:glGentexture")) + { + success = 0; + } + else + { + glBindTexture(GL_TEXTURE_2D, *out_handle); + glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, width, height, 0, format, type, data); + if(renderer_check_glerror("texture:create_gl_texture:glTexImage2d")) + success = 0; + glBindTexture(GL_TEXTURE_2D, 0); + } + return success; +} diff --git a/src/texture.h b/src/texture.h index edb1758..2f237d3 100644 --- a/src/texture.h +++ b/src/texture.h @@ -19,5 +19,16 @@ void texture_bind(int index); void texture_unbind(int index); void texture_param_set(int index, int parameter, int value); int texture_get_textureunit(int index); +int texture_get_texture_handle(int index); +void texture_inc_refcount(int index); +void texture_dec_refcount(int index); +int texture_create(const char* name, + int texture_unit, + int width, + int height, + int format, + int int_fmt, + int type, + void* data); #endif