#include #include "dumbLog.h" #include "render_object.h" // forward declarations 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 bool roInit(meMeshInfo* mi_in, render_object& ro_out) { 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"; roFree(ro_out); return false; } void 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 bool initGLFloatBuffer(glm::vec3* buffer, uint count, GLuint& buffer_id) { glGenBuffers(1, &buffer_id); glBindBuffer(GL_ARRAY_BUFFER, buffer_id); glBufferData(GL_ARRAY_BUFFER, count * sizeof(GLfloat), buffer, GL_STATIC_DRAW); 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) { 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); }