From db54b4b635029308d3bc4454058761c4b45fed81 Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Wed, 16 Dec 2020 11:40:05 -0500 Subject: [PATCH] prepare codepath for default meshes/shaders --- include/entity.h | 15 +-- include/render_object.h | 49 +++---- include/shader_program.h | 10 +- include/types.h | 16 +++ src/entity.cpp | 66 +++------- src/render_object.cpp | 274 +++++++++++++++++++++++++++++---------- src/renderer.cpp | 8 ++ src/util.cpp | 5 +- 8 files changed, 279 insertions(+), 164 deletions(-) create mode 100644 include/types.h diff --git a/include/entity.h b/include/entity.h index c7e4f19..121521f 100644 --- a/include/entity.h +++ b/include/entity.h @@ -5,31 +5,25 @@ #include "mesh.h" #include "render_object.h" +#include "types.h" -enum mesh_group_type -{ - DEFAULT_MESHES = 0, - SIMPLE_MESH = 1 -}; - // TODO: having a separate code path for each shader is annoying and error // prone. could try using opaque pointers at high level (renderer, entity), // and then cast to the appropriate render_object/mesh/shader type in the lower // level functions based on the mesh_type property struct entity { - mesh_group_type mesh_type; + mesh_t mesh_type; simple_mesh mesh; - simple_render_object simple_ro; + simple_render_object* simple_ro; GLenum draw_mode; // TODO: should be a pointer into a global array of mesh_info(s) or // mesh_groups stored on the render_state object mesh_group meshes; - render_object* render_objs; - uint ro_count; + render_objects* render_objs; }; bool entInitModel(entity& e, const char* model_path); @@ -45,3 +39,4 @@ void entTranslate(entity& e, glm::vec3 v); void entScale(entity& e, glm::vec3 v); void entRotate(entity& e, float angle, glm::vec3 axis); + diff --git a/include/render_object.h b/include/render_object.h index 8a5bd3e..8c0d7f5 100644 --- a/include/render_object.h +++ b/include/render_object.h @@ -10,40 +10,41 @@ #include "shader_program.h" -struct render_object -{ - glm::mat4 node_xform; +struct render_objects; +struct simple_render_object; - GLuint tex_id; - GLuint vertex_buffer_id; - GLuint normal_buffer_id; - GLuint uv_buffer_id; - GLuint index_buffer_id; - uint index_buffer_count; -}; +render_objects* +roInitModel(mesh_group meshes); -struct simple_render_object -{ - glm::mat4 model_transform; - GLuint vertex_buffer_id; - GLuint vertex_color_buffer_id; - uint vertex_count; -}; +void +roFree(render_objects* r_objs); -bool roInit(mesh_info* mi_in, render_object& ro_out); +simple_render_object* +roInitSimpleMesh(simple_mesh& mesh_in); -bool roInitSimpleMesh(simple_mesh& mesh_in, simple_render_object& ro_out); +void +roFreeSimple(simple_render_object* ro); -void roFree(render_object& ro); +void +roTranslate(render_objects* r_objs, glm::mat4 xform); -void roFreeSimple(simple_render_object& ro); +void +roScale(render_object* ro, glm::mat4 xform); -void roDraw(render_object& ro, +void +roRotate(render_object* ro, glm::mat4 xform); + +// TODO: we probably want to re-introduce a world_transform matrix here again +// so we can do: projection * view * world_transform * model_transform +// that way model animations and world orientation/position can be separated +void +roDraw(render_objects* r_ojbs, camera& cam, - default_shader_program& shader, + shader_wrapper sw, light_group* lights); -void roDrawSimple(simple_render_object& ro, +void +roDrawSimple(simple_render_object* ro, camera& cam, simple_shader_program& shader, GLenum draw_mode); diff --git a/include/shader_program.h b/include/shader_program.h index 5b95638..6a342fe 100644 --- a/include/shader_program.h +++ b/include/shader_program.h @@ -3,6 +3,8 @@ #include +#include "types.h" + struct default_shader_program { @@ -25,15 +27,9 @@ struct simple_shader_program GLuint vertex_array_id; }; -enum shader_type -{ - SIMPLE_SHADER = 0, - DEFAULT_SHADER = 1 -}; - struct shader_wrapper { - shader_type type; + shader_t shader_type; default_shader_program* default_shader; simple_shader_program* simple_shader; }; diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..59fcbe7 --- /dev/null +++ b/include/types.h @@ -0,0 +1,16 @@ + +#pragma once + + +enum shader_t +{ + SIMPLE_SHADER, + DEFAULT_SHADER +}; + +enum mesh_t +{ + SIMPLE_MESH, + DEFAULT_MESHES +}; + diff --git a/src/entity.cpp b/src/entity.cpp index b4dcf44..5ad39db 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -25,9 +25,9 @@ entInitModel(entity& e, const char* model_path) if (meLoadFromFile(e.meshes, model_path)) { - e.ro_count = e.meshes.num_meshes; - e.render_objs = UTIL_ALLOC(e.ro_count, render_object); - if (loadMeshesIntoGL(e)) + e.render_objs = roInitModel(e.meshes); + + if (e.render_objs != nullptr) return true; } @@ -63,20 +63,8 @@ entInitSimpleMesh(entity& e, simple_mesh& mesh, GLenum draw_mode) void entFree(entity& e) { - if (e.mesh_type == DEFAULT_MESHES) - meFreeMeshGroup(e.meshes); - - if (e.mesh_type == SIMPLE_MESH) { - meFreeSimpleMesh(e.mesh); - roFreeSimple(e.simple_ro); - } - - for (uint i = 0; i < e.ro_count; i++) - roFree(e.render_objs[i]); - - utilSafeFree(e.render_objs); + roFree(e.render_objs); e.render_objs = nullptr; - e.ro_count = 0; } void @@ -115,8 +103,8 @@ void entScale(entity& e, glm::vec3 v) { #if 0 - e.world_transform = glm::scale(e.world_transform, v); -#endif + //e.world_transform = glm::scale(e.world_transform, v); + if (e.mesh_type == SIMPLE_MESH) { // } @@ -127,18 +115,18 @@ entScale(entity& e, glm::vec3 v) ro.node_xform = glm::scale(ro.node_xform, v); } } - +#endif } void entRotate(entity& e, float angle, glm::vec3 axis) { #if 0 - e.world_transform = glm::rotate(e.world_transform, angle, axis); -#endif + //e.world_transform = glm::rotate(e.world_transform, angle, axis); + if (e.mesh_type == SIMPLE_MESH) { - e.simple_ro.model_transform = - glm::rotate(e.simple_ro.model_transform, angle, axis); + glm::mat4& xform = roGetTransform(e.simple_ro); + xform = glm::rotate(xform, angle, axis); } if (e.mesh_type == DEFAULT_MESHES) { @@ -147,6 +135,7 @@ entRotate(entity& e, float angle, glm::vec3 axis) ro.node_xform = glm::rotate(ro.node_xform, angle, axis); } } +#endif } @@ -159,34 +148,17 @@ initDefaults(entity& e) entSetWorldPosition(e, glm::vec3(0, 0, 0)); } -bool -loadMeshesIntoGL(entity& e) -{ - for (uint i = 0; i < e.meshes.num_meshes; i++) { - assert(e.render_objs != nullptr); - render_object& ro = e.render_objs[i]; - mesh_info* mi = e.meshes.meshes[i]; - assert(mi != nullptr); - - if (!roInit(mi, ro)) { - LOG(Error) << "Error initializing render objects\n"; - entFree(e); - return false; - } - } - - return true; -} - bool loadSimpleMeshIntoGL(entity& e) { assert(e.mesh.num_vertices > 0); + e.simple_ro = roInitSimpleMesh(e.mesh); - if (roInitSimpleMesh(e.mesh, e.simple_ro)) - return true; + if (e.simple_ro == nullptr) { + LOG(Error) << "Error initializing render object\n"; + entFree(e); + return false; + } - LOG(Error) << "Error initializing render object\n"; - entFree(e); - return false; + return true; } diff --git a/src/render_object.cpp b/src/render_object.cpp index 91e0cc6..d06e590 100644 --- a/src/render_object.cpp +++ b/src/render_object.cpp @@ -7,128 +7,230 @@ // forward declarations +struct default_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; + uint index_buffer_count; +}; + +struct simple_render_object +{ + glm::mat4 model_transform; + GLuint vertex_buffer_id; + GLuint vertex_color_buffer_id; + uint vertex_count; +}; + +struct render_objects +{ + void* objects; + uint count; + mesh_t mesh_type; +}; + +void drawSimple(render_objects* r_objs, + camera& cam, + shader_wrapper sw, + light_group* lights); +void drawDefault(render_objects* r_objs, + camera& cam, + shader_wrapper sw, + light_group* lights); bool initGLFloatBuffer(glm::vec3* buffer, uint count, GLuint& buffer_id); bool initGLIndexBuffer(uint* buffer, uint num_indices, GLuint& buffer_id); bool initGLTexture(const util_image image, GLuint& tex_id); -inline void -updateMatrices(default_shader_program& shader, camera& cam, +bool loadMeshIntoGL(default_render_object* ro_out, mesh_info* mi_in); +inline void updateMatrices(default_shader_program* shader, + camera& cam, glm::mat4 node_xform); inline void enableGLFloatBuffer(uint buffer_id, uint location); // interface -bool -roInit(mesh_info* mi_in, render_object& ro_out) +render_objects* +roInitModel(mesh_group mg) { - if (initGLFloatBuffer(mi_in->vertices, - mi_in->num_vertices, - ro_out.vertex_buffer_id) && - initGLFloatBuffer(mi_in->normals, - mi_in->num_vertices, - ro_out.normal_buffer_id) && - initGLFloatBuffer(mi_in->texture_coords, - mi_in->num_vertices, - ro_out.uv_buffer_id) && - initGLIndexBuffer(mi_in->indices, - mi_in->num_indices, - ro_out.index_buffer_id) && - initGLTexture(mi_in->diffuse_texture, ro_out.tex_id)) - { - ro_out.node_xform = mi_in->model_transform; - ro_out.index_buffer_count = mi_in->num_indices; - return true; + uint count = mg.num_meshes; + assert(count > 0); + + render_objects* r_objs = UTIL_ALLOC(1, render_objects); + r_objs->objects = UTIL_ALLOC(count, default_render_object); + r_objs->count = count; + r_objs->mesh_type = DEFAULT_MESHES; + + default_render_object* objects = (default_render_object*) r_objs->objects; + + for (uint i = 0; i < count; i++) { + if (!loadMeshIntoGL(&objects[i], mg.meshes[i])) { + roFree(r_objs); + return nullptr; + } } - LOG(Error) << "Failed to initialize render_object\n"; - roFree(ro_out); - return false; + return r_objs; } -bool -roInitSimpleMesh(simple_mesh& mesh_in, simple_render_object& ro_out) +void +roFree(render_objects* r_objs) +{ + if (r_objs->mesh_type == SIMPLE_MESH) { + // + } else if (r_objs->mesh_type == DEFAULT_MESHES) { + default_render_object* objects = + (default_render_object*) r_objs->objects; + + for (uint i = 0; i < r_objs->count; i++) { + glDeleteBuffers(1, &objects[i].vertex_buffer_id); + glDeleteBuffers(1, &objects[i].normal_buffer_id); + glDeleteBuffers(1, &objects[i].uv_buffer_id); + glDeleteBuffers(1, &objects[i].index_buffer_id); + glDeleteTextures(1, &objects[i].tex_id); + } + + utilSafeFree(r_objs->objects); + utilSafeFree(r_objs); + } +} + +simple_render_object* +roInitSimpleMesh(simple_mesh& mesh_in) { + // TODO: switch on mesh type here + simple_render_object* ro_out = UTIL_ALLOC(1, simple_render_object); + if (initGLFloatBuffer(mesh_in.vertices, mesh_in.num_vertices, - ro_out.vertex_buffer_id) && + ro_out->vertex_buffer_id) && initGLFloatBuffer(mesh_in.vert_colors, mesh_in.num_vertices, - ro_out.vertex_color_buffer_id)) + ro_out->vertex_color_buffer_id)) { - ro_out.model_transform = mesh_in.model_transform; - ro_out.vertex_count = mesh_in.num_vertices; - return true; + ro_out->model_transform = mesh_in.model_transform; + ro_out->vertex_count = mesh_in.num_vertices; + return ro_out; } LOG(Error) << "Failed to initialize render_object\n"; roFreeSimple(ro_out); - return false; + return nullptr; } void -roFree(render_object& ro) +roFreeSimple(simple_render_object* ro) { - glDeleteBuffers(1, &ro.vertex_buffer_id); - glDeleteBuffers(1, &ro.normal_buffer_id); - glDeleteBuffers(1, &ro.uv_buffer_id); - glDeleteBuffers(1, &ro.index_buffer_id); - glDeleteTextures(1, &ro.tex_id); + glDeleteBuffers(1, &ro->vertex_buffer_id); + glDeleteBuffers(1, &ro->vertex_color_buffer_id); + utilSafeFree(ro); } void -roFreeSimple(simple_render_object& ro) +roTranslate(render_objects* r_objs, glm::mat4 xform) { - glDeleteBuffers(1, &ro.vertex_buffer_id); - glDeleteBuffers(1, &ro.vertex_color_buffer_id); + if (r_objs->mesh_type == SIMPLE_MESH) { + // + } + + else if (r_objs->mesh_type == DEFAULT_MESHES) { + // + } } void -roDraw(render_object& ro, - camera& cam, - default_shader_program& shader, - light_group* lights) +roScale(render_object* ro, glm::mat4 xform) { - glUseProgram(shader.program_id); - updateMatrices(shader, cam, ro.node_xform); - enableGLFloatBuffer(ro.vertex_buffer_id, 0); - enableGLFloatBuffer(ro.normal_buffer_id, 1); - // TODO: could pass in a stride parameter here to enableGLFloatBuffer() - // could then use a 2d buffer for uv coords - enableGLFloatBuffer(ro.uv_buffer_id, 2); - glBindTexture(GL_TEXTURE_2D, ro.tex_id); - glUniform1i(shader.sampler_id, 0); - if (lights->needs_update) - lightsUpdate(lights, &shader); +} - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ro.index_buffer_id); - glDrawElements(GL_TRIANGLES, ro.index_buffer_count, GL_UNSIGNED_INT, 0); +void +roRotate(render_object* ro, glm::mat4 xform) +{ - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(2); - glUseProgram(0); } void -roDrawSimple(simple_render_object& ro, +roDraw(render_objects* r_objs, + camera& cam, + shader_wrapper sw, + light_group* lights) +{ + if (r_objs->mesh_type == SIMPLE_MESH) { + drawSimple(r_objs, cam, sw, lights); + } else if (r_objs->mesh_type == DEFAULT_MESHES) { + drawDefault(r_objs, cam, sw, lights); + } +} + +void +roDrawSimple(simple_render_object* ro, camera& cam, simple_shader_program& shader, GLenum draw_mode) { glUseProgram(shader.program_id); - cam.MVP = cam.projection * cam.view * ro.model_transform; + cam.MVP = cam.projection * cam.view * ro->model_transform; glUniformMatrix4fv(shader.MVP_id, 1, GL_FALSE, &cam.MVP[0][0]); - enableGLFloatBuffer(ro.vertex_buffer_id, 0); - enableGLFloatBuffer(ro.vertex_color_buffer_id, 1); - glDrawArrays(draw_mode, 0, ro.vertex_count); + enableGLFloatBuffer(ro->vertex_buffer_id, 0); + enableGLFloatBuffer(ro->vertex_color_buffer_id, 1); + glDrawArrays(draw_mode, 0, ro->vertex_count); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glUseProgram(0); } + // internal +void +drawSimple(render_objects* r_objs, + camera& cam, + shader_wrapper sw, + light_group* lights) +{ + +} + +void +drawDefault(render_objects* r_objs, + camera& cam, + shader_wrapper sw, + light_group* lights) +{ + default_shader_program* shader = sw.default_shader; + default_render_object* objects = (default_render_object*) r_objs->objects; + glUseProgram(shader->program_id); + updateMatrices(shader, cam, objects->node_xform); + if (lights->needs_update) lightsUpdate(lights, shader); + + for (uint i = 0; i < r_objs->count; i++) { + enableGLFloatBuffer(objects[i].vertex_buffer_id, 0); + enableGLFloatBuffer(objects[i].normal_buffer_id, 1); + // TODO: could pass in a stride parameter here to enableGLFloatBuffer() + // could then use a 2d buffer for uv coords + enableGLFloatBuffer(objects[i].uv_buffer_id, 2); + glBindTexture(GL_TEXTURE_2D, objects[i].tex_id); + glUniform1i(shader->sampler_id, 0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, objects[i].index_buffer_id); + glDrawElements(GL_TRIANGLES, + objects[i].index_buffer_count, + GL_UNSIGNED_INT, + 0); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + } + + glUseProgram(0); +} + bool initGLFloatBuffer(glm::vec3* buffer, uint count, GLuint& buffer_id) { @@ -170,21 +272,49 @@ initGLTexture(const util_image image, GLuint& tex_id) return (glGetError() == GL_NO_ERROR); } +bool +loadMeshIntoGL(default_render_object* ro_out, mesh_info* mi_in) +{ + assert(mi_in != nullptr && ro_out != nullptr); + + if (initGLFloatBuffer(mi_in->vertices, + mi_in->num_vertices, + ro_out->vertex_buffer_id) && + initGLFloatBuffer(mi_in->normals, + mi_in->num_vertices, + ro_out->normal_buffer_id) && + initGLFloatBuffer(mi_in->texture_coords, + mi_in->num_vertices, + ro_out->uv_buffer_id) && + initGLIndexBuffer(mi_in->indices, + mi_in->num_indices, + ro_out->index_buffer_id) && + initGLTexture(mi_in->diffuse_texture, ro_out->tex_id)) + { + ro_out->node_xform = mi_in->model_transform; + ro_out->index_buffer_count = mi_in->num_indices; + return true; + } + + LOG(Error) << "Failed to initialize render_object\n"; + return false; +} + // TODO: really only need to update the view and projection matrices once per // frame, maybe add another interface function in render_object to call from // renRenderFrame inline void -updateMatrices(default_shader_program& shader, +updateMatrices(default_shader_program* shader, camera& cam, glm::mat4 node_xform) { - glUniformMatrix4fv(shader.model_matrix_id, 1, GL_FALSE, &node_xform[0][0]); - glUniformMatrix4fv(shader.view_matrix_id, 1, GL_FALSE, &cam.view[0][0]); - glUniformMatrix4fv(shader.projection_matrix_id, 1, GL_FALSE, + glUniformMatrix4fv(shader->model_matrix_id, 1, GL_FALSE, &node_xform[0][0]); + glUniformMatrix4fv(shader->view_matrix_id, 1, GL_FALSE, &cam.view[0][0]); + glUniformMatrix4fv(shader->projection_matrix_id, 1, GL_FALSE, &cam.projection[0][0]); glm::mat3 normal_matrix = glm::transpose( glm::inverse(glm::mat3(cam.model))); - glUniformMatrix3fv(shader.normal_matrix_id, 1, GL_FALSE, + glUniformMatrix3fv(shader->normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); } diff --git a/src/renderer.cpp b/src/renderer.cpp index 88aa7d5..d74c538 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -167,6 +167,14 @@ renRenderFrame(render_state* rs) } } #endif + if (rg.shader.shader_type == DEFAULT_SHADER) { + for (uint j = 0; j < rg.entity_count; j++) { + roDraw(rg.entities[j].render_objs, + rs->cam, + rg.shader, + rs->lights); + } + } } } diff --git a/src/util.cpp b/src/util.cpp index d40e79a..71afb38 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -80,10 +80,7 @@ utilLogAlloc(uint item_count, uint type_size, const char* file_name, const int l void utilSafeFree(const void* mem) { - if (mem != nullptr) { - std::free((void *) mem); - mem = nullptr; - } + if (mem != nullptr) std::free((void *) mem); } //-----------------