From 62d78c4765a8bb7545e18a587b8bd5102870d118 Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Fri, 13 Nov 2020 10:53:19 -0500 Subject: [PATCH] re-add draw calls for new renderer structure --- examples/assimp_loading/main.cpp | 25 ++++---- include/lights.h | 11 ++++ include/render_object.h | 11 +++- include/renderer.h | 13 ++--- src/entity.cpp | 7 ++- src/mesh.cpp | 4 +- src/render_object.cpp | 99 ++++++++++++++++++++++++++++++-- src/renderer.cpp | 41 ++++++++----- 8 files changed, 167 insertions(+), 44 deletions(-) create mode 100644 include/lights.h diff --git a/examples/assimp_loading/main.cpp b/examples/assimp_loading/main.cpp index 04db193..b071b43 100644 --- a/examples/assimp_loading/main.cpp +++ b/examples/assimp_loading/main.cpp @@ -59,16 +59,10 @@ main() render_state* rs = renInit("assimp loading"); meInitAssimp(); - // TODO: entInit() doesn't allocate memory because we want to do the - // allocation in one big block, but this is really clunky to use - render_group* group_1 = renAllocateGroup(1, *rs->default_shader); - entity spaceship = group_1->entities[0]; - - // TODO: this should be handled in entInit - entSetWorldPosition(spaceship, glm::vec3(0, 0, 0)); - entScale(spaceship, glm::vec3(20, 20, 20)); - // TODO: implement setting rotation from entity - //spaceship.rotation = glm::vec4(0, 0, 0, 0); + // TODO: this needs to be more convenient + rs->render_groups = renAllocateGroup(1, *rs->default_shader); + rs->render_group_count = 1; + entity& spaceship = rs->render_groups->entities[0]; // setup camera cameraInitPerspective( @@ -92,10 +86,17 @@ main() // NOTE: testing assimp animation info logDebugAnimationInfo("../data/spaceship.glb"); - if (entInit(spaceship, "../data/spaceship.glb")) + if (entInit(spaceship, "../data/spaceship.glb")) { + // TODO: this should be handled in entInit + entSetWorldPosition(spaceship, glm::vec3(0, 0, 0)); + entScale(spaceship, glm::vec3(20, 20, 20)); + // TODO: implement setting rotation from entity + //spaceship.rotation = glm::vec4(0, 0, 0, 0); + doRenderLoop(rs, doFrameCallback); - else + } else { LOG(Error) << "Error initializing entity, exiting\n"; + } renShutdown(rs); meShutdownAssimp(); diff --git a/include/lights.h b/include/lights.h new file mode 100644 index 0000000..d317449 --- /dev/null +++ b/include/lights.h @@ -0,0 +1,11 @@ + +#pragma once + +struct point_light +{ + uint light_ID; + glm::vec3 position; + glm::vec3 color; + float intensity; +}; + diff --git a/include/render_object.h b/include/render_object.h index c4449fb..5077268 100644 --- a/include/render_object.h +++ b/include/render_object.h @@ -4,7 +4,10 @@ #include #include +#include "camera.h" +#include "lights.h" #include "mesh.h" +#include "shader_program.h" struct render_object @@ -16,6 +19,7 @@ struct render_object GLuint normal_buffer_id; GLuint uv_buffer_id; GLuint index_buffer_id; + GLuint index_buffer_count; }; bool roInit(meMeshInfo* mi_in, render_object& ro_out); @@ -23,5 +27,8 @@ bool roInit(meMeshInfo* mi_in, render_object& ro_out); // TODO: make use of glIsBuffer/glDeleteBuffers void roFree(render_object& ro); -// TODO: implement me! -void roDraw(render_object& ro); +void roDraw(render_object& ro, + camera& cam, + shader_program& shader, + point_light* lights, + uint num_lights); diff --git a/include/renderer.h b/include/renderer.h index 330947b..a8b611c 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -11,6 +11,7 @@ #include "camera.h" #include "entity.h" +#include "lights.h" #include "util.h" #include "shader_program.h" @@ -22,14 +23,6 @@ struct SDL_Handles SDL_DisplayMode currentDisplayMode; }; -struct point_light -{ - uint light_ID; - glm::vec3 position; - glm::vec3 color; - float intensity; -}; - // NOTE: array of entities rendered with the same shader program struct render_group { @@ -47,7 +40,9 @@ struct render_state camera cam; util_RGBA clear_col; - render_group** render_groups; + // TODO: this really needs to be a resizable array, or linked list, or + // ...gasp, std::vector + render_group* render_groups; uint render_group_count; shader_program* default_shader; diff --git a/src/entity.cpp b/src/entity.cpp index 6804d7d..be03480 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -65,6 +65,11 @@ void entScale(entity& e, glm::vec3 v) { e.world_transform = glm::scale(e.world_transform, v); + + for (uint i = 0; i < e.mesh_group.num_meshes; i++) { + render_object& ro = e.render_objs[i]; + ro.node_xform = glm::scale(ro.node_xform, v); + } } @@ -75,7 +80,7 @@ loadMeshIntoGL(entity& e) { for (uint i = 0; i < e.mesh_group.num_meshes; i++) { assert(e.render_objs != nullptr); - render_object ro = e.render_objs[i]; + render_object& ro = e.render_objs[i]; meMeshInfo* mi = e.mesh_group.meshes[i]; assert(mi != nullptr); diff --git a/src/mesh.cpp b/src/mesh.cpp index 9ba3ae7..6fd68c2 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -51,8 +51,8 @@ meLoadFromFile(meMeshGroup& mesh_group, const char* filepath) aiMesh* mesh = scene->mMeshes[i]; meMeshInfo* mi = copyMeshInfo(scene, mesh); - if (!mesh->HasTextureCoords(0) - || !loadDiffuseTexture(scene, mesh, mi)) + if (!mesh->HasTextureCoords(0) || + !loadDiffuseTexture(scene, mesh, mi)) { LOG(Error) << "Error loading texture, cleaning up import\n"; freeMesh(mi); diff --git a/src/render_object.cpp b/src/render_object.cpp index 2fc50e3..dcaef6f 100644 --- a/src/render_object.cpp +++ b/src/render_object.cpp @@ -1,4 +1,6 @@ +#include + #include "dumbLog.h" #include "render_object.h" @@ -7,6 +9,7 @@ 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); // interface @@ -25,8 +28,11 @@ roInit(meMeshInfo* mi_in, render_object& ro_out) ro_out.uv_buffer_id) && initGLIndexBuffer(mi_in->indices, mi_in->num_indices, - ro_out.index_buffer_id)) + 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; } @@ -41,6 +47,76 @@ roFree(render_object& ro) LOG(Debug) << "TODO: release GL buffers from render_object\n"; } +//----------- WIP -------------- + +// 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(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, &cam.projection[0][0]); + + glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(cam.model))); + glUniformMatrix3fv(shader.normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); +} + +inline void +enableGLFloatBuffer(uint buffer_id, uint location) +{ + glEnableVertexAttribArray(location); + glBindBuffer(GL_ARRAY_BUFFER, buffer_id); + glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); +} + +#include // TODO: remove this and make something in util.h + +inline void +updateLights(shader_program& shader, point_light* lights, uint num_lights) +{ + // 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(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(shader.program_id, ss.str().c_str()); + glUniform3fv(light_pos_loc, 1, &lights[i].position[0]); + } +} + +//----------- WIP -------------- + +void +roDraw(render_object& ro, + camera& cam, + shader_program& shader, + point_light* lights, + uint num_lights) +{ + glUseProgram(shader.program_id); + updateMatrices(shader, cam, ro.node_xform); + enableGLFloatBuffer(ro.vertex_buffer_id, 0); + enableGLFloatBuffer(ro.normal_buffer_id, 1); + updateLights(shader, lights, num_lights); + // 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); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ro.index_buffer_id); + glDrawElements(GL_TRIANGLES, ro.index_buffer_count, GL_UNSIGNED_INT, 0); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glUseProgram(0); +} // internal @@ -54,8 +130,7 @@ initGLFloatBuffer(glm::vec3* buffer, uint count, GLuint& buffer_id) buffer, GL_STATIC_DRAW); - // TODO: check for errors after buffering - return true; + return (glGetError() == GL_NO_ERROR); } bool @@ -68,6 +143,20 @@ initGLIndexBuffer(uint* buffer, uint num_indices, GLuint& buffer_id) buffer, GL_STATIC_DRAW); - // TODO: check for errors after buffering - return true; + return (glGetError() == GL_NO_ERROR); +} + +bool +initGLTexture(const util_image image, GLuint& tex_id) +{ + 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); } diff --git a/src/renderer.cpp b/src/renderer.cpp index 9821185..2c04e78 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -12,6 +12,7 @@ #include #include "dumbLog.h" +#include "render_object.h" #include "renderer.h" #include "default_shaders.cpp" @@ -66,6 +67,18 @@ renInit(const char* title, glm::vec2 viewport_dims) void renShutdown(render_state* rs) { + // TODO: need a nicer way to loop over entities and render_objects + for (uint i = 0; i < rs->render_group_count; i++) { + render_group& rg = rs->render_groups[i]; + + for (uint j = 0; j < rg.entity_count; j++) { + entity& e = rg.entities[j]; + + for (uint k = 0; k < e.ro_count; k++) + roFree(e.render_objs[k]); + } + } + utilSafeFree(rs->lights); SDL_GL_DeleteContext(rs->handles.glContext); SDL_DestroyWindow(rs->handles.window); @@ -78,6 +91,7 @@ renAllocateGroup(uint entity_count, shader_program shader) assert(entity_count > 0); render_group* rg = UTIL_ALLOC(1, render_group); rg->entities = UTIL_ALLOC(entity_count, entity); + rg->entity_count = entity_count; rg->shader = shader; return rg; } @@ -88,20 +102,21 @@ renRenderFrame(render_state* rs) glClearColor(rs->clear_col.R, rs->clear_col.G, rs->clear_col.B, rs->clear_col.A); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - // TODO: loop over new render_groups on render_state - // make call to roDraw for each render_object in each entity -#if 0 - // entities - for (uint i = 0; i < entity_count; i++) { - rgDraw(entities[i].ren_group, - entities[i].world_transform, - rs->cam.view, - rs->cam.projection, - rs->lights, - rs->num_lights - ); + for (uint i = 0; i < rs->render_group_count; i++) { + render_group& rg = rs->render_groups[i]; + + for (uint j = 0; j < rg.entity_count; j++) { + entity& e = rg.entities[j]; + + for (uint k = 0; k < e.ro_count; k++) { + roDraw(e.render_objs[k], + rs->cam, + rg.shader, + rs->lights, + rs->num_lights); + } + } } -#endif }