diff --git a/include/animation.h b/include/animation.h index df725ee..10a42bc 100644 --- a/include/animation.h +++ b/include/animation.h @@ -4,7 +4,7 @@ #include #include "util.h" -#include "render_group.h" +#include "render_object.h" struct node_animation diff --git a/include/entity.h b/include/entity.h index a450d7a..262a576 100644 --- a/include/entity.h +++ b/include/entity.h @@ -2,10 +2,16 @@ #pragma once #include -#include #include "mesh.h" -#include "render_group.h" +#include "render_object.h" + + +struct render_objects +{ + render_object* objs; + uint count; +}; // NOTE: an entity is the basic unit of the high level renderer interface struct entity @@ -19,38 +25,16 @@ struct entity // mesh_groups stored on the render_state object meMeshGroup mesh_group; - // NOTE: an array of render objects with all the vertex, normal, and uv - // data loaded from assimp - render_object* ren_objects; - uint ren_object_count; - - //render_group* ren_group; + render_objects render_objs; }; -// NOTE: an entity group is an array of entities rendered with the same shader -// program -struct entity_group -{ - entity* entities; - uint entity_count; - - rg_shader_program shader_prg; -}; +bool entInit(entity& e, const char* model_path); -inline void -entTranslate(entity& e, glm::vec3 v) -{ - e.world_transform = glm::translate(e.world_transform, v); -} +void entFree(entity& e); -inline void -entScale(entity& e, glm::vec3 v) -{ - e.world_transform = glm::scale(e.world_transform, v); -} +void entSetWorldPosition(entity& e, float x, float y, float z); -bool entInit(entity& e, const char* model_path, rg_shader_program& shader); +void entTranslate(entity& e, glm::vec3 v); -void entFree(entity& e); +void entScale(entity& e, glm::vec3 v); -void entSetWorldPosition(entity& e, float x, float y, float z); diff --git a/include/render_group.h b/include/render_group.h deleted file mode 100644 index 0ec391c..0000000 --- a/include/render_group.h +++ /dev/null @@ -1,99 +0,0 @@ - -#pragma once - -#include -#include - -#include "util.h" -#include "util_image.h" - - -// TODO: can these structs be used as opaque pointers? -struct gl_buffer -{ - GLuint buffer_id; - uint count; // NOTE: number of elements in buffer - uint max_count; // NOTE: maxium number of elements buffer can fit - GLfloat* buffer; -}; - -struct gl_index_buffer -{ - GLuint buffer_id; - uint count; // NOTE: number of elements in buffer - uint max_count; // NOTE: maxium number of elements buffer can fit - uint* buffer; -}; - -struct render_object -{ - glm::mat4 node_xform; - - // TODO: can remove these once we're using the global color palatte for all textures - bool use_texture; - GLuint tex_id; - - gl_buffer vertex_buffer; - gl_buffer normal_buffer; - gl_buffer uv_buffer; - gl_index_buffer index_buffer; -}; - -struct rg_shader_program -{ - GLuint program_id; - - GLuint model_matrix_id; - GLuint view_matrix_id; - GLuint projection_matrix_id; - GLuint normal_matrix_id; - - GLuint vertex_array_id; - GLuint sampler_id; - GLuint num_lights_id; -}; - -struct render_group -{ - uint num_objects; - render_object** render_objects; - rg_shader_program shader; - bool use_normals; - bool draw_indexed; - GLenum draw_mode = GL_TRIANGLES; - char name[64]; -}; - -// TODO: maybe pull out to seperate header -struct rg_point_light -{ - uint light_ID; - glm::vec3 position; - glm::vec3 color; - float intensity; -}; - -render_object * rgAllocateRenderObject(uint buffer_len, uint index_len = 0); - -// NOTE: initializes a render_group with 1 render_object allocated -render_group* rgInitSingle(rg_shader_program& sp, uint vertex_buffer_len, - bool use_normals = false, uint index_buffer_len = 0, - GLenum draw_mode = GL_TRIANGLES); - -bool rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char * frag_code); - -bool rgInitGLTexture(GLuint& tex_id, util_image image); - -void rgInitGLFloatBuffer(gl_buffer* buffer, GLenum usage, GLenum target); - -void rgInitGLIndexBuffer(gl_index_buffer* index_buffer, GLenum usage, GLenum target); - -void rgUpdateGLBuffer(gl_buffer& buffer); - -void rgDraw(render_group* rg, glm::mat4 model_matrix, - glm::mat4 view_matrix, glm::mat4 projection_matrix, - rg_point_light* lights, uint num_lights, - bool update_vertex_data = false); - -void rgFree(render_group* rg); - diff --git a/include/render_object.h b/include/render_object.h new file mode 100644 index 0000000..3d4a0a9 --- /dev/null +++ b/include/render_object.h @@ -0,0 +1,28 @@ + +#pragma once + +#include +#include + + +struct render_object +{ + glm::mat4 node_xform; + + GLuint tex_id; + GLuint vertex_buffer_id; + GLuint normal_buffer_id; + GLuint uv_buffer_id; + GLuint index_buffer_id; +}; + +struct point_light +{ + uint light_ID; + glm::vec3 position; + glm::vec3 color; + float intensity; +}; + +void roFree(render_object* ro); + diff --git a/include/renderer.h b/include/renderer.h index f02d082..3d6afb7 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -11,8 +11,8 @@ #include "camera.h" #include "entity.h" -#include "render_group.h" #include "util.h" +#include "shader_program.h" struct SDL_Handles @@ -22,7 +22,16 @@ struct SDL_Handles SDL_DisplayMode currentDisplayMode; }; -struct rg_point_light; +struct point_light; + +// NOTE: array of entities rendered with the same shader program +struct render_group +{ + entity* entities; + uint entity_count; + + shader_program shader; +}; struct render_state { @@ -32,11 +41,10 @@ struct render_state camera cam; util_RGBA clear_col; - //rg_shader_program default_shader; - entity_group* entity_groups; - uint entity_group_count; + render_group* render_groups; + uint render_group_count; - rg_point_light* lights; + point_light* lights; uint num_lights; uint max_lights; }; @@ -47,5 +55,3 @@ void renShutdown(render_state* rs); void renRenderFrame(render_state* rs, Entity* entities, uint32 entity_count); -//void renRenderDebug(render_state* rs, std::vector &vertices); - diff --git a/include/shader_program.h b/include/shader_program.h new file mode 100644 index 0000000..0345d9b --- /dev/null +++ b/include/shader_program.h @@ -0,0 +1,22 @@ + +#pragma once + +#include + + +struct shader_program +{ + GLuint program_id; + + GLuint model_matrix_id; + GLuint view_matrix_id; + GLuint projection_matrix_id; + GLuint normal_matrix_id; + + GLuint vertex_array_id; + GLuint sampler_id; + GLuint num_lights_id; +}; + +shader_program* initShaderProgram(const char* vertex_code, const char* frag_code); + diff --git a/src/entity.cpp b/src/entity.cpp index 93c1ee3..6e4ec67 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -1,4 +1,6 @@ +#include + #include "dumbLog.h" #include "entity.h" @@ -8,7 +10,7 @@ bool initEntityROs(entity& e); bool convertMeshInfo(meMeshInfo* mesh, render_object* ro, bool use_normals, bool use_texture); bool -entInit(entity& e, const char* model_path, rg_shader_program& shader) +entInit(entity& e, const char* model_path) { e.world_transform = glm::mat4(1.0); entScale(e, glm::vec3(1.0)); @@ -34,7 +36,9 @@ void entFree(entity& e) { meFreeMeshGroup(e.mesh_group); - rgFree(e.ren_group); + + for (uint i = 0; i < e.render_objs.count; i++) + roFree(&e.render_objs.objs[i]); } void @@ -45,6 +49,18 @@ entSetWorldPosition(entity& e, float x, float y, float z) e.world_transform[3][2] = z; } +void +entTranslate(entity& e, glm::vec3 v) +{ + e.world_transform = glm::translate(e.world_transform, v); +} + +void +entScale(entity& e, glm::vec3 v) +{ + e.world_transform = glm::scale(e.world_transform, v); +} + void initEntityRG(entity& e, rg_shader_program& shader, bool use_normals) { diff --git a/src/render_group.cpp b/src/render_group.cpp deleted file mode 100644 index be92675..0000000 --- a/src/render_group.cpp +++ /dev/null @@ -1,277 +0,0 @@ - -#include // TODO: remove this and make something in util.h -#include - -#include -#include -#include - -#include "dumbLog.h" - -#include "render_group.h" -#include "util.h" - -#define INFO_LOG_MAX_LENGTH 312 - - -// forward declarations - -void freeRenderObject(render_object* ro); -void rgInitGLIndexBuffer(gl_index_buffer* index_buffer, GLenum usage, GLenum target); - - -// interface - -render_object * -rgAllocateRenderObject(uint buffer_len, uint index_len) -{ - render_object* ro = UTIL_ALLOC(1, render_object); - - if (ro == nullptr) - return nullptr; - - ro->vertex_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat); - ro->vertex_buffer.count = ro->vertex_buffer.max_count = buffer_len; - ro->normal_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat); - ro->normal_buffer.count = ro->normal_buffer.max_count = buffer_len; - ro->uv_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat); - ro->uv_buffer.count = ro->uv_buffer.max_count = buffer_len; - - if (index_len > 0) { - ro->index_buffer.buffer = UTIL_ALLOC(index_len, uint); - ro->index_buffer.count = index_len; - } - - if (ro->vertex_buffer.buffer == nullptr || - ro->normal_buffer.buffer == nullptr || - ((index_len > 0) && (ro->vertex_buffer.buffer == nullptr))) - { - freeRenderObject(ro); - return nullptr; - } - - return ro; -} - -render_group* -rgInitSingle(rg_shader_program& sp, uint vertex_buffer_len, - bool use_normals, uint index_buffer_len, - GLenum draw_mode) -{ - render_group* rg = UTIL_ALLOC(1, render_group); - rg->shader = sp; - rg->use_normals = use_normals; - rg->draw_indexed = (index_buffer_len > 0); - rg->draw_mode = draw_mode; - - rg->render_objects = UTIL_ALLOC(1, render_object*); - rg->render_objects[0] = rgAllocateRenderObject(vertex_buffer_len, index_buffer_len); - rg->num_objects = 1; - - if (rg->render_objects[0] == nullptr) { - LOG(Error) << "Allocation Error\n"; - rgFree(rg); - } - - return rg; -} - -bool -rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char * frag_code) -{ - glGenVertexArrays(1, &sp.vertex_array_id); - glBindVertexArray(sp.vertex_array_id); - GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); - GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(vertex_shader_id, 1, &vertex_code, NULL); - glShaderSource(fragment_shader_id, 1, &frag_code, NULL); - glCompileShader(vertex_shader_id); - glCompileShader(fragment_shader_id); - - sp.program_id = glCreateProgram(); - glAttachShader(sp.program_id, vertex_shader_id); - glAttachShader(sp.program_id, fragment_shader_id); - glLinkProgram(sp.program_id); - - sp.model_matrix_id = glGetUniformLocation(sp.program_id, "model"); - sp.view_matrix_id = glGetUniformLocation(sp.program_id, "view"); - sp.projection_matrix_id = glGetUniformLocation(sp.program_id, "projection"); - sp.normal_matrix_id = glGetUniformLocation(sp.program_id, "normal_matrix"); - sp.num_lights_id = glGetUniformLocation(sp.program_id, "num_lights"); - sp.sampler_id = glGetUniformLocation(sp.program_id, "sampler"); - - glDetachShader(sp.program_id, vertex_shader_id); - glDetachShader(sp.program_id, fragment_shader_id); - glDeleteShader(vertex_shader_id); - glDeleteShader(fragment_shader_id); - - // TODO: quick hack to allow 'dynamic' stack allocation for msvc - // also remove INFO_LOG_MAX_LENGTH define - GLint isLinked = 0; - glGetProgramiv(sp.program_id, GL_LINK_STATUS, &isLinked); - if (isLinked == GL_FALSE) { - GLint maxLength = INFO_LOG_MAX_LENGTH; - glGetProgramiv(sp.program_id, GL_INFO_LOG_LENGTH, &maxLength); -#ifdef _WIN32 - GLchar infoLog[312] = { 0 }; -#else - GLchar infoLog[maxLength] = { 0 }; -#endif - glGetProgramInfoLog(sp.program_id, maxLength, &maxLength, &infoLog[0]); - LOG(Error) << infoLog << "\n"; - glDeleteProgram(sp.program_id); - - return false; - } - - return true; -} - -bool -rgInitGLTexture(GLuint& tex_id, util_image image) -{ - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - GLenum pixel_format = (image.num_channels == 3) ? GL_RGB : GL_RGBA; - glTexImage2D(GL_TEXTURE_2D, 0, pixel_format, image.w, image.h, 0, - pixel_format, GL_UNSIGNED_BYTE, image.pixels); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - return (glGetError() == GL_NO_ERROR); -} - -void -rgInitGLFloatBuffer(gl_buffer* buffer, GLenum usage, GLenum target) -{ - glGenBuffers(1, &buffer->buffer_id); - glBindBuffer(target, buffer->buffer_id); - glBufferData(target, buffer->max_count * sizeof(GLfloat), buffer->buffer, usage); -} - -void -rgInitGLIndexBuffer(gl_index_buffer* index_buffer, GLenum usage, GLenum target) -{ - glGenBuffers(1, &index_buffer->buffer_id); - glBindBuffer(target, index_buffer->buffer_id); - glBufferData(target, index_buffer->count * sizeof(uint), index_buffer->buffer, usage); -} - -void -rgUpdateGLBuffer(gl_buffer& buffer) -{ - glBindBuffer(GL_ARRAY_BUFFER, buffer.buffer_id); - glBufferSubData(GL_ARRAY_BUFFER, 0, buffer.count * sizeof(GLfloat), buffer.buffer); -} - -void -rgDraw(render_group* rg, glm::mat4 model_matrix, - glm::mat4 view_matrix, glm::mat4 projection_matrix, - rg_point_light* lights, uint num_lights, bool update_vertex_data) -{ - for (uint i = 0; i < rg->num_objects; i++) { - render_object* ro = rg->render_objects[i]; - - glUseProgram(rg->shader.program_id); - glUniformMatrix4fv(rg->shader.model_matrix_id, 1, GL_FALSE, &model_matrix[0][0]); - glUniformMatrix4fv(rg->shader.view_matrix_id, 1, GL_FALSE, &view_matrix[0][0]); - glUniformMatrix4fv(rg->shader.projection_matrix_id, 1, GL_FALSE, &projection_matrix[0][0]); - - // 1st attribute buffer : vertices - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, ro->vertex_buffer.buffer_id); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); - - if (update_vertex_data) - { - glBufferSubData(GL_ARRAY_BUFFER, 0, ro->vertex_buffer.count * sizeof(GLfloat), - ro->vertex_buffer.buffer); - } - - // 2rd attribute buffer: normals - if (rg->use_normals) { - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, ro->normal_buffer.buffer_id); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); - - glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(model_matrix))); - glUniformMatrix3fv(rg->shader.normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); - - // TODO: use Uniform Buffer Objects to update light data - // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt - // https://www.khronos.org/opengl/wiki/Uniform_Buffer_Objects - - glUniform1ui(rg->shader.num_lights_id, num_lights); - - for (uint i = 0; i < num_lights; i++) { - // TODO: don't do this every frame * every render_group - std::stringstream ss; - ss << "lights[" << i << "].position"; - int light_pos_loc = glGetUniformLocation(rg->shader.program_id, ss.str().c_str()); - glUniform3fv(light_pos_loc, 1, &lights[i].position[0]); - } - } - - // 3rd attribute buffer: UV coordinates - if (ro->use_texture) { - glEnableVertexAttribArray(2); - glBindBuffer(GL_ARRAY_BUFFER, ro->uv_buffer.buffer_id); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); - glBindTexture(GL_TEXTURE_2D, ro->tex_id); - glUniform1i(rg->shader.sampler_id, 0); - } - - // draw - if (rg->draw_indexed) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ro->index_buffer.buffer_id); - glDrawElements(rg->draw_mode, ro->index_buffer.count, GL_UNSIGNED_INT, 0); - } else { - glDrawArrays(rg->draw_mode, 0, ro->vertex_buffer.count / 3); - } - - // cleanup - glDisableVertexAttribArray(0); - if (rg->use_normals) - glDisableVertexAttribArray(1); - if (ro->use_texture) - glDisableVertexAttribArray(2); - - glUseProgram(0); - } -} - -void -rgFree(render_group* rg) -{ - if (rg == nullptr) { - LOG(Error) << "tried to free nullptr\n"; - return; - } - - for (uint i = 0; i < rg->num_objects; i++) - freeRenderObject(rg->render_objects[i]); - - utilSafeFree(rg->render_objects); - utilSafeFree(rg); -} - - -// internal - -void -freeRenderObject(render_object* ro) -{ - if (ro == nullptr) { - LOG(Error) << "Tried to free nullptr\n"; - return; - } - - glDeleteTextures(1, &ro->tex_id); - utilSafeFree(ro->vertex_buffer.buffer); - utilSafeFree(ro->normal_buffer.buffer); - utilSafeFree(ro->uv_buffer.buffer); - utilSafeFree(ro->index_buffer.buffer); - utilSafeFree(ro); -} diff --git a/src/render_object.cpp b/src/render_object.cpp new file mode 100644 index 0000000..736f003 --- /dev/null +++ b/src/render_object.cpp @@ -0,0 +1,10 @@ + +#include "dumbLog.h" +#include "render_object.h" + + +void +roFree(render_object* ro) +{ + LOG(Debug) << "TODO: release GL buffers from render_object\n"; +} diff --git a/src/shader_program.cpp b/src/shader_program.cpp new file mode 100644 index 0000000..81c05f4 --- /dev/null +++ b/src/shader_program.cpp @@ -0,0 +1,61 @@ + +#include "dumbLog.h" +#include "shader_program.h" +#include "util.h" + + +// TODO: remove and fix hack for dynamic stack allocation +#define INFO_LOG_MAX_LENGTH 312 + + +shader_program* +initShaderProgram(const char* vertex_code, const char* frag_code) +{ + shader_program* sp = UTIL_ALLOC(1, shader_program); + glGenVertexArrays(1, &sp->vertex_array_id); + glBindVertexArray(sp->vertex_array_id); + GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); + GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vertex_shader_id, 1, &vertex_code, NULL); + glShaderSource(fragment_shader_id, 1, &frag_code, NULL); + glCompileShader(vertex_shader_id); + glCompileShader(fragment_shader_id); + + sp->program_id = glCreateProgram(); + glAttachShader(sp->program_id, vertex_shader_id); + glAttachShader(sp->program_id, fragment_shader_id); + glLinkProgram(sp->program_id); + + sp->model_matrix_id = glGetUniformLocation(sp->program_id, "model"); + sp->view_matrix_id = glGetUniformLocation(sp->program_id, "view"); + sp->projection_matrix_id = glGetUniformLocation(sp->program_id, "projection"); + sp->normal_matrix_id = glGetUniformLocation(sp->program_id, "normal_matrix"); + sp->num_lights_id = glGetUniformLocation(sp->program_id, "num_lights"); + sp->sampler_id = glGetUniformLocation(sp->program_id, "sampler"); + + glDetachShader(sp->program_id, vertex_shader_id); + glDetachShader(sp->program_id, fragment_shader_id); + glDeleteShader(vertex_shader_id); + glDeleteShader(fragment_shader_id); + + GLint isLinked = 0; + glGetProgramiv(sp->program_id, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) { + GLint maxLength = INFO_LOG_MAX_LENGTH; + glGetProgramiv(sp->program_id, GL_INFO_LOG_LENGTH, &maxLength); +#ifdef _WIN32 + GLchar infoLog[312] = { 0 }; +#else + GLchar infoLog[maxLength] = { 0 }; +#endif + glGetProgramInfoLog(sp->program_id, maxLength, &maxLength, &infoLog[0]); + LOG(Error) << infoLog << "\n"; + glDeleteProgram(sp->program_id); + + return nullptr; + } + + return sp; +} +