diff --git a/README b/README index 4232edf..14a58bb 100644 --- a/README +++ b/README @@ -9,13 +9,15 @@ Features: pixels TODO: - fix lighting normal bugs (branch "normal_bug") + store meshes separately from entities for reuse linear memory allocator for assets (branch "render_group_fix") + maybe update UTIL_ALLOC macro to use arena allocator? + fix lighting normal bugs (branch "normal_bug") finish node animations from assimp add input abstraction for SDL - store meshes separately from entities for reuse add a function to update camera transforms only once per frame, per shader update camera to use quaternions for rotation + re-combine simple/default meshes/render_objects Dependencies: glew diff --git a/examples/render_groups/main.cpp b/examples/render_groups/main.cpp index 25320c9..35cd358 100644 --- a/examples/render_groups/main.cpp +++ b/examples/render_groups/main.cpp @@ -53,6 +53,7 @@ createModelEntities(render_group* rg, glm::vec3 max_pos, glm::vec3 scaling) { +#if 0 assert(rg != nullptr); for (uint i = 0; i < item_count; i++) { @@ -72,11 +73,14 @@ createModelEntities(render_group* rg, } return true; +#endif + return false; } void doFrameCallbackPre(render_state* rs) { +#if 0 static input_state is = {}; inputProcessEvents(&is); @@ -89,9 +93,11 @@ doFrameCallbackPre(render_state* rs) static float angle = 1.2 / 60; // NOTE: 60 FPS static glm::vec3 axis(0, 0, 1); - for (uint i = 0; i < rs->render_group_count; i++) { - for (uint j = 0; j < rs->render_groups[i]->entity_count; j++) { - entity& e = rs->render_groups[i]->entities[j]; + for (uint i = 0; i < rs->render_groups->count; i++) { + render_group* rg = &rs->render_groups->groups[i]; + + for (uint j = 0; j < rg->count; j++) { + entity* e = &rg->entities[j]; entRotate(e, angle, axis); } } @@ -105,6 +111,7 @@ doFrameCallbackPre(render_state* rs) l2.position = glm::vec3( square.world_transform * glm::vec4(10000, 0, -1000, 1)); rs->lights->needs_update = true; +#endif } int @@ -177,10 +184,22 @@ main() renDoRenderLoop(rs, 60, doFrameCallbackPre); #endif +#if 0 model* ret = assetLoadFromFile(rs->assets, rs->arena, "../data/blender/spaceship.gltf"); assert(ret != nullptr); +#endif + + // NOTE: testing entity system with new asset structures + // FIXME: wtf is this? + shader_wrapper sw = { DEFAULT_SHADER, rs->default_shader, nullptr }; + render_group* rg = rgAlloc(rs->render_groups, 64, sw); + entity* e = + rgAppend(rg, rs->assets, rs->arena, "../data/blender/spaceship.gltf"); + assert(e != nullptr); + + renDoRenderLoop(rs, 60); renShutdown(rs); return 0; diff --git a/include/asset.h b/include/asset.h index 6880d2b..4fff7b2 100644 --- a/include/asset.h +++ b/include/asset.h @@ -20,11 +20,11 @@ struct mesh uint num_indices; glm::vec3* vertices; glm::vec3* normals; - uint* indices; // FIXME: will have to use vec2 here to be able to use memcpy // this will break render_object::initGLFLoatBuffer logic which expects // vec3 glm::vec2* texture_coords; + uint* indices; glm::mat4* xform; }; @@ -57,3 +57,6 @@ assetLoadFromFile(model_assets* assets, memory_arena* arena, const char* filename); +model* +assetGetCached(model_assets* assets, uint64_t path_hash); + diff --git a/include/camera.h b/include/camera.h index 8346416..4230fc4 100644 --- a/include/camera.h +++ b/include/camera.h @@ -44,7 +44,7 @@ cameraIntersectPlane(camera& cam, v3f& intersection); void -cameraInitPerspective(camera& cam, +cameraInitPerspective(camera* cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up, diff --git a/include/entity.h b/include/entity.h index fc16687..4c6cf9d 100644 --- a/include/entity.h +++ b/include/entity.h @@ -3,34 +3,23 @@ #include -#include "mesh.h" +#include "asset.h" #include "render_object.h" #include "types.h" -// 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 { glm::mat4 world_transform; - // TODO: hide simple_mesh/mesh_group pointer behind abstraction - simple_mesh* mesh; - - // 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; + //mesh_group meshes; + uint64_t model_id; // NOTE: filepath hash render_objects* render_objs; }; -bool entInitModel(entity& e, const char* model_path); - -bool entInitMesh(entity& e, simple_mesh* mesh, GLenum draw_mode); - -void entUpdateSimpleMesh(entity& e, simple_mesh* mesh, GLenum draw_mode); +bool entInitModel(entity* e, model* mdl); -void entFree(entity& e); +// FIXME: might as well stay consistent and make all these pointers +void entFree(entity* e); void entSetWorldPosition(entity& e, glm::vec3 v); @@ -38,5 +27,5 @@ void entTranslate(entity& e, glm::vec3 v); void entScale(entity& e, glm::vec3 v); -void entRotate(entity& e, float angle, glm::vec3 axis); +void entRotate(entity* e, float angle, glm::vec3 axis); diff --git a/include/render_object.h b/include/render_object.h index 5196e47..eefe9e8 100644 --- a/include/render_object.h +++ b/include/render_object.h @@ -4,19 +4,16 @@ #include #include +#include "asset.h" #include "camera.h" #include "lights.h" -#include "mesh.h" #include "shader_program.h" struct render_objects; render_objects* -roInitModel(mesh_group meshes); - -render_objects* -roInitSimpleMesh(simple_mesh& mesh_in, GLenum draw_mode); +roInitModel(model* mdl); void roFree(render_objects* r_objs); @@ -24,9 +21,7 @@ roFree(render_objects* r_objs); void roDraw(render_objects* r_ojbs, glm::mat4 world_transform, - camera& cam, + camera* cam, shader_wrapper sw, light_group* lights); -void -roUpdateSimpleMesh(render_objects* r_objs, simple_mesh* mesh, GLenum draw_mode); diff --git a/include/renderer.h b/include/renderer.h index 2e99707..559c15c 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -22,19 +22,27 @@ struct render_group { // TODO: also needs to be resizable entity* entities; - uint entity_count; - + uint count; + uint max_size; shader_wrapper shader; +}; - // TODO: does it makes sense to have the mesh_type stored on the - // render_group? can then easily pass to roDraw() along with the entity - // render_objects... - // only the mesh object and render object really need to know about the - // mesh_type... - // - //mesh_t mesh_type; +struct rg_info +{ + render_group* groups; + uint count; + uint max_size; }; +render_group* +rgAlloc(rg_info* rgi, uint num_entites, shader_wrapper shader); + +entity* +rgAppend(render_group* rg, + model_assets* assets, + memory_arena* arena, + const char* model_path); + struct SDL_Handles { SDL_Window *window; @@ -42,18 +50,16 @@ struct SDL_Handles SDL_DisplayMode currentDisplayMode; }; +#define DEFAULT_RG_COUNT 256 struct render_state { glm::vec2 viewport_dims; - camera cam; + camera* cam; util_RGBA clear_col; SDL_Handles* handles; bool running; - // TODO: this really needs to be a resizable array, or linked list, or - // ...gasp, std::vector - render_group** render_groups; - uint render_group_count; + rg_info* render_groups; // WIP model_assets* assets; @@ -79,9 +85,6 @@ renInit(const char* title = "Tangerine", void renShutdown(render_state* rs); -render_group* -renAllocateGroup(uint entity_count, shader_wrapper shader); - // NOTE: callback function signature to use with renDoRenderLoop() typedef void (*frame_callback_fn) (render_state*); diff --git a/include/util.h b/include/util.h index 14ad4ad..a2e4b50 100644 --- a/include/util.h +++ b/include/util.h @@ -89,7 +89,7 @@ bool utilMatchPrefix(const char* lhs, const char* rhs, int sz); #define FNV1_64_INIT ((uint64_t) 0xcbf29ce484222325ULL) #define FNV_64_PRIME ((uint64_t) 0x100000001b3ULL) uint64_t -utilFNV64a_str(char *str, uint64_t hval = FNV1_64_INIT); +utilFNV64a_str(const char *str, uint64_t hval = FNV1_64_INIT); //----------------- // Memory allocation diff --git a/src/asset.cpp b/src/asset.cpp index 2aa72b0..4538317 100644 --- a/src/asset.cpp +++ b/src/asset.cpp @@ -244,3 +244,15 @@ assetLoadFromFile(model_assets* assets, return mdl; } +// FIXME: reorganize asset.cpp, put interface at the top +model* +assetGetCached(model_assets* assets, uint64_t path_hash) +{ + for (uint i = 0; i < assets->count; i++) { + if (assets->models[i].filepath_hash == path_hash) + return &assets->models[i]; + } + + LOG(Debug) << "asset not cached: " << path_hash << "\n"; + return nullptr; +} diff --git a/src/camera.cpp b/src/camera.cpp index e89b563..13ab4a5 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -20,7 +20,7 @@ inline glm::vec3 convertv3f(v3f v); // interface void -cameraInitPerspective(camera& cam, +cameraInitPerspective(camera* cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up, @@ -28,26 +28,27 @@ cameraInitPerspective(camera& cam, { assert(aspect_ratio > 0); - cam.position = position; - cam.target = target; - cam.world_up = world_up; - cam.projection = glm::infinitePerspective(glm::radians(FOV), + cam->position = position; + cam->target = target; + cam->world_up = world_up; + cam->projection = glm::infinitePerspective(glm::radians(FOV), aspect_ratio, NEAR_CLIP_PLANE); - cam.forward = glm::normalize(target - position); - cam.left = glm::normalize(glm::cross(cam.world_up, cam.forward)); - cam.up = glm::normalize(glm::cross(cam.forward, cam.left)); + cam->forward = glm::normalize(target - position); + cam->left = glm::normalize(glm::cross(cam->world_up, cam->forward)); + cam->up = glm::normalize(glm::cross(cam->forward, cam->left)); - cam.hAngle = glm::atan(cam.forward.x, cam.forward.y); + cam->hAngle = glm::atan(cam->forward.x, cam->forward.y); // NOTE: get absolute value of relative axis for vAngle component - real32 len = glm::sqrt(glm::pow(cam.forward.y, 2) + - glm::pow(cam.forward.x, 2)); - cam.vAngle = glm::atan(cam.forward.z, len); - - cam.view = glm::lookAt(cam.position, cam.position + cam.forward, cam.up); - cam.model = glm::mat4(1.0f); - cam.MVP = cam.projection * cam.view * cam.model; + real32 len = glm::sqrt(glm::pow(cam->forward.y, 2) + + glm::pow(cam->forward.x, 2)); + cam->vAngle = glm::atan(cam->forward.z, len); + + cam->view = + glm::lookAt(cam->position, cam->position + cam->forward, cam->up); + cam->model = glm::mat4(1.0f); + cam->MVP = cam->projection * cam->view * cam->model; } void diff --git a/src/entity.cpp b/src/entity.cpp index 5253599..1aaa41b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -14,7 +14,7 @@ void initDefaults(entity& e); // interface - +#if 0 bool entInitModel(entity& e, const char* model_path) { @@ -31,35 +31,26 @@ entInitModel(entity& e, const char* model_path) entFree(e); return false; } +#endif bool -entInitMesh(entity& e, simple_mesh* mesh, GLenum draw_mode) +entInitModel(entity* e, model* mdl) { - initDefaults(e); - e.mesh = mesh; - e.render_objs = roInitSimpleMesh(*e.mesh, draw_mode); + e->render_objs = roInitModel(mdl); - if (e.render_objs == nullptr) + if (e->render_objs == nullptr) { + entFree(e); return false; + } return true; } void -entUpdateSimpleMesh(entity& e, simple_mesh* mesh, GLenum draw_mode) -{ - roUpdateSimpleMesh(e.render_objs, mesh, draw_mode); -} - -void -entFree(entity& e) +entFree(entity* e) { - roFree(e.render_objs); - e.render_objs = nullptr; - meFreeMeshGroup(e.meshes); - - if (e.mesh != nullptr) meFreeSimpleMesh(e.mesh); - e.mesh = nullptr; + roFree(e->render_objs); + e->render_objs = nullptr; } void @@ -83,9 +74,9 @@ entScale(entity& e, glm::vec3 v) } void -entRotate(entity& e, float angle, glm::vec3 axis) +entRotate(entity*& e, float angle, glm::vec3 axis) { - e.world_transform = glm::rotate(e.world_transform, angle, axis); + e->world_transform = glm::rotate(e->world_transform, angle, axis); } diff --git a/src/render_object.cpp b/src/render_object.cpp index b782ed9..53a12d2 100644 --- a/src/render_object.cpp +++ b/src/render_object.cpp @@ -5,8 +5,6 @@ #include "render_object.h" -// forward declarations - struct default_render_object { glm::mat4 node_xform; @@ -19,52 +17,30 @@ struct default_render_object uint index_buffer_count; }; -struct simple_render_object -{ - glm::mat4 model_transform; - GLuint vertex_buffer_id; - GLuint vertex_color_buffer_id; - uint vertex_count; - GLenum draw_mode; -}; - struct render_objects { - void* objects; + default_render_object* objects; uint count; mesh_t mesh_type; }; + +// forward declarations + void drawDefault(render_objects* r_objs, glm::mat4 world_transform, - camera& cam, - shader_wrapper sw, - light_group* lights); -void drawSimple(render_objects* r_objs, - glm::mat4 world_transform, - camera& cam, + camera* cam, shader_wrapper sw, light_group* lights); -inline void enableGLFloatBuffer(uint buffer_id, uint location); -bool initGLFloatBuffer(glm::vec3* buffer, - uint count, - GLuint& buffer_id, - GLenum usage = GL_STATIC_DRAW); -bool initGLIndexBuffer(uint* buffer, uint num_indices, GLuint& buffer_id); -bool initGLTexture(const util_image image, GLuint& tex_id); -bool loadMeshIntoGL(default_render_object* ro_out, mesh_info* mi_in); -inline void updateMatrices(default_shader_program* shader, - camera& cam, - glm::mat4 world_xform, - glm::mat4 node_xform); +bool loadMeshIntoGL(default_render_object* ro_out, mesh* me_in); // interface render_objects* -roInitModel(mesh_group mg) +roInitModel(model* mdl) { - uint count = mg.num_meshes; + uint count = mdl->num_meshes; assert(count > 0); render_objects* r_objs = UTIL_ALLOC(1, render_objects); @@ -75,7 +51,7 @@ roInitModel(mesh_group mg) default_render_object* objects = (default_render_object*) r_objs->objects; for (uint i = 0; i < count; i++) { - if (!loadMeshIntoGL(&objects[i], mg.meshes[i])) { + if (!loadMeshIntoGL(&objects[i], &mdl->meshes[i])) { roFree(r_objs); return nullptr; } @@ -84,44 +60,13 @@ roInitModel(mesh_group mg) return r_objs; } -render_objects* -roInitSimpleMesh(simple_mesh& mesh_in, GLenum draw_mode) -{ - render_objects* r_objs = UTIL_ALLOC(1, render_objects); - r_objs->count = 1; - r_objs->mesh_type = SIMPLE_MESH; - r_objs->objects = UTIL_ALLOC(1, simple_render_object); - - simple_render_object* objects = (simple_render_object*) r_objs->objects; - - if (initGLFloatBuffer(mesh_in.vertices, - mesh_in.num_vertices, - objects->vertex_buffer_id, - GL_DYNAMIC_DRAW) && - initGLFloatBuffer(mesh_in.vert_colors, - mesh_in.num_vertices, - objects->vertex_color_buffer_id, - GL_DYNAMIC_DRAW)) - { - objects->model_transform = mesh_in.model_transform; - objects->vertex_count = mesh_in.num_vertices; - objects->draw_mode = draw_mode; - return r_objs; - } - - LOG(Error) << "Failed to initialize render_object\n"; - roFree(r_objs); - return nullptr; -} - 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; + default_render_object* objects = r_objs->objects; for (uint i = 0; i < r_objs->count; i++) { glDeleteBuffers(1, &objects[i].vertex_buffer_id); @@ -140,98 +85,39 @@ roFree(render_objects* r_objs) void roDraw(render_objects* r_objs, glm::mat4 world_transform, - camera& cam, + camera* cam, shader_wrapper sw, light_group* lights) { - if (r_objs->mesh_type == SIMPLE_MESH) - drawSimple(r_objs, world_transform, cam, sw, lights); - else if (r_objs->mesh_type == DEFAULT_MESHES) - drawDefault(r_objs, world_transform, cam, sw, lights); + assert(r_objs->mesh_type == DEFAULT_MESHES); + drawDefault(r_objs, world_transform, cam, sw, lights); } -void -roUpdateSimpleMesh(render_objects* r_objs, simple_mesh* mesh, GLenum draw_mode) -{ - assert(r_objs != nullptr && r_objs->objects != nullptr); - assert(mesh != nullptr && mesh->vertices != nullptr); - simple_render_object* sro = (simple_render_object*) r_objs->objects; - assert(sro->vertex_count == mesh->num_vertices); - - sro->draw_mode = draw_mode; - glBindBuffer(GL_ARRAY_BUFFER, sro->vertex_buffer_id); - glBufferSubData( - GL_ARRAY_BUFFER, - 0, - 3 * sro->vertex_count * sizeof(GLfloat), - mesh->vertices); - glBindBuffer(GL_ARRAY_BUFFER, sro->vertex_color_buffer_id); - glBufferSubData( - GL_ARRAY_BUFFER, - 0, - 3 * sro->vertex_count * sizeof(GLfloat), - mesh->vert_colors); -} // internal -void -drawDefault(render_objects* r_objs, - glm::mat4 world_transform, - camera& cam, - shader_wrapper sw, - light_group* lights) +bool +initGLBuffer(void* buffer, + uint count, + GLuint* buffer_id, + uint el_count = 3, + uint el_size = sizeof(float), + GLenum target = GL_ARRAY_BUFFER, + GLenum usage = GL_STATIC_DRAW) { - default_shader_program* shader = sw.default_shader; - default_render_object* objects = (default_render_object*) r_objs->objects; - glUseProgram(shader->program_id); - updateMatrices(shader, cam, world_transform, 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); + if ((el_count == 3 && el_size == sizeof(float)) + || (el_count == 2 && el_size == sizeof(float)) + || (el_count == 1 && el_size == sizeof(unsigned short))) + { + glGenBuffers(1, buffer_id); + glBindBuffer(target, *buffer_id); + glBufferData(target, count * el_count * el_size, buffer, usage); - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(2); + return (glGetError() == GL_NO_ERROR); } - glUseProgram(0); -} - -void -drawSimple(render_objects* r_objs, - glm::mat4 world_transform, - camera& cam, - shader_wrapper sw, - light_group* lights) -{ - simple_render_object* ro = (simple_render_object*) r_objs->objects; - simple_shader_program* shader = - (simple_shader_program*) sw.simple_shader; - glUseProgram(shader->program_id); - cam.MVP = cam.projection * cam.view * ro->model_transform; - glUniformMatrix4fv( - shader->world_transform_id, 1, GL_FALSE, &world_transform[0][0]); - 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(ro->draw_mode, 0, ro->vertex_count); - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glUseProgram(0); + return false; } inline void @@ -242,35 +128,6 @@ enableGLFloatBuffer(uint buffer_id, uint location) glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); } -bool -initGLFloatBuffer(glm::vec3* buffer, - uint count, - GLuint& buffer_id, - GLenum usage) -{ - glGenBuffers(1, &buffer_id); - glBindBuffer(GL_ARRAY_BUFFER, buffer_id); - glBufferData(GL_ARRAY_BUFFER, - count * 3 * sizeof(GLfloat), // NOTE: 3 floats per vertex prop - buffer, - usage); - - return (glGetError() == GL_NO_ERROR); -} - -bool -initGLIndexBuffer(uint* buffer, uint num_indices, GLuint& buffer_id) -{ - glGenBuffers(1, &buffer_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - num_indices * sizeof(uint), - buffer, - GL_STATIC_DRAW); - - return (glGetError() == GL_NO_ERROR); -} - bool initGLTexture(const util_image image, GLuint& tex_id) { @@ -287,27 +144,26 @@ initGLTexture(const util_image image, GLuint& tex_id) } 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) && - // FIXME: this is broken now with tinygltf, need to use vec2 - 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)) +loadMeshIntoGL(default_render_object* ro_out, mesh* mesh_in) +{ + assert(mesh_in != nullptr && ro_out != nullptr); + + if (initGLBuffer(mesh_in->vertices, mesh_in->num_vertices, + &ro_out->vertex_buffer_id) + && initGLBuffer(mesh_in->normals, mesh_in->num_vertices, + &ro_out->normal_buffer_id) + && initGLBuffer(mesh_in->texture_coords, mesh_in->num_vertices, + &ro_out->uv_buffer_id, 2) + && initGLBuffer(mesh_in->indices, mesh_in->num_indices, + &ro_out->index_buffer_id, 1, sizeof(unsigned short), + GL_ELEMENT_ARRAY_BUFFER) + // FIXME: re-implement diffuse texture, but with index into an array + // on render_state + //&& initGLTexture(mesh_in->diffuse_texture, ro_out->tex_id)) + ) { - ro_out->node_xform = mi_in->model_transform; - ro_out->index_buffer_count = mi_in->num_indices; + ro_out->node_xform = *mesh_in->xform; + ro_out->index_buffer_count = mesh_in->num_indices; return true; } @@ -320,19 +176,55 @@ loadMeshIntoGL(default_render_object* ro_out, mesh_info* mi_in) // renRenderFrame inline void updateMatrices(default_shader_program* shader, - camera& cam, + camera* cam, glm::mat4 world_xform, glm::mat4 node_xform) { glUniformMatrix4fv( shader->world_transform_id, 1, GL_FALSE, &world_xform[0][0]); 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->view_matrix_id, 1, GL_FALSE, &cam->view[0][0]); glUniformMatrix4fv(shader->projection_matrix_id, 1, GL_FALSE, - &cam.projection[0][0]); + &cam->projection[0][0]); glm::mat3 normal_matrix = glm::transpose( - glm::inverse(glm::mat3(cam.model))); + glm::inverse(glm::mat3(cam->model))); glUniformMatrix3fv(shader->normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); } +void +drawDefault(render_objects* r_objs, + glm::mat4 world_transform, + camera* cam, + shader_wrapper sw, + light_group* lights) +{ + default_shader_program* shader = sw.default_shader; + default_render_object* objects = r_objs->objects; + glUseProgram(shader->program_id); + updateMatrices(shader, cam, world_transform, 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); +} + diff --git a/src/renderer.cpp b/src/renderer.cpp index 0039a35..725147c 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -37,6 +37,53 @@ void setDefaults(render_state* rs, glm::vec2 viewport_dims); // interface +render_group* +rgAlloc(rg_info* rgi, uint num_entites, shader_wrapper shader) +{ + assert(rgi != nullptr); + + if (rgi->count < rgi->max_size) { + render_group* rg = &rgi->groups[rgi->count]; + rgi->count++; + rg->entities = UTIL_ALLOC(num_entites, entity); + rg->max_size = num_entites; + rg->shader = shader; + return rg; + } + + LOG(Error) << "no free render_group\n"; + return nullptr; +} + +entity* +rgAppend(render_group* rg, + model_assets* assets, + memory_arena* arena, + const char* model_path) +{ + assert(rg != nullptr); + + if (rg->count < rg->max_size) { + entity* e = &rg->entities[rg->count]; + rg->count++; + // FIXME: maybe actually load the model here... + // get path hash + // check for hash in rs->assets->models[i]->filepath_hash + // load new model if not found + model* mdl = assetGetCached(assets, utilFNV64a_str(model_path)); + + if (mdl == nullptr) + mdl = assetLoadFromFile(assets, arena, model_path); + + // load model into gl, entInitModel(e, model) + if (entInitModel(e, mdl)) + return e; + } + + LOG(Error) << "no free entity in render_group\n"; + return nullptr; +} + render_state* renInit(const char* title, glm::vec2 viewport_dims, @@ -46,8 +93,14 @@ renInit(const char* title, { render_state* rs = UTIL_ALLOC(1, render_state); rs->handles = UTIL_ALLOC(1, SDL_Handles); + rs->cam = UTIL_ALLOC(1, camera); + // TODO: add parameter for custom render_group count + rs->render_groups = UTIL_ALLOC(1, rg_info); + rs->render_groups->groups = UTIL_ALLOC(DEFAULT_RG_COUNT, render_group); + rs->render_groups->max_size = DEFAULT_RG_COUNT; rs->arena = arenaInit(arena_size); rs->assets = assetInitBlock(rs->arena, asset_size); + rs->lights = lightsInit(); setDefaults(rs, viewport_dims); if (initSDL(rs->handles, SDL_init_flags) && @@ -66,11 +119,11 @@ renInit(const char* title, void renShutdown(render_state* rs) { - for (uint i = 0; i < rs->render_group_count; i++) { - for (uint j = 0; j < rs->render_groups[i]->entity_count; j++) - entFree(rs->render_groups[i]->entities[j]); + for (uint i = 0; i < rs->render_groups->count; i++) { + render_group* rg = &rs->render_groups->groups[i]; - utilSafeFree(rs->render_groups[i]->entities); + for (uint j = 0; j < rg->count; j++) + entFree(&rg->entities[j]); } shaderFree(rs->default_shader->program_id); @@ -84,24 +137,12 @@ renShutdown(render_state* rs) utilSafeFree(rs->render_groups); rs->render_groups = nullptr; arenaFree(rs->arena); - meShutdownAssimp(); SDL_GL_DeleteContext(rs->handles->glContext); SDL_DestroyWindow(rs->handles->window); SDL_Quit(); utilSafeFree(rs->handles); } -render_group* -renAllocateGroup(uint entity_count, shader_wrapper 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; -} - void renDoRenderLoop(render_state* rs, uint framerate, @@ -146,13 +187,13 @@ renRenderFrame(render_state* rs) rs->clear_col.A); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - for (uint i = 0; i < rs->render_group_count; i++) { - render_group* rg = rs->render_groups[i]; + for (uint i = 0; i < rs->render_groups->count; i++) { + render_group* rg = &rs->render_groups->groups[i]; - for (uint j = 0; j < rg->entity_count; j++) { - entity& e = rg->entities[j]; - roDraw(e.render_objs, - e.world_transform, + for (uint j = 0; j < rg->count; j++) { + entity* e = &rg->entities[j]; + roDraw(e->render_objs, + e->world_transform, rs->cam, rg->shader, rs->lights); @@ -312,7 +353,6 @@ setDefaults(render_state* rs, glm::vec2 viewport_dims) { rs->running = true; rs->viewport_dims = viewport_dims; - rs->lights = lightsInit(); rs->clear_col.R = CLEAR_COL_R; rs->clear_col.B = CLEAR_COL_B; rs->clear_col.G = CLEAR_COL_G; diff --git a/src/util.cpp b/src/util.cpp index 216951f..f51228a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -62,7 +62,7 @@ utilMatchPrefix(const char* lhs, const char* rhs, int sz) // Hashing uint64_t -utilFNV64a_str(char* str, uint64_t hval) +utilFNV64a_str(const char* str, uint64_t hval) { unsigned char* s = (unsigned char *)str; // unsigned string