A small OpenGL 3+ renderer and game engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

149 lines
4.2 KiB

#include <glm/gtc/matrix_transform.hpp>
#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);
inline void
updateMatrices(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)
{
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)
{
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);
}
void
roDraw(render_object& ro,
camera& cam,
shader_program& shader,
light_group* lights)
{
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);
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 * 3 * sizeof(GLfloat), // NOTE: 3 floats per vertex prop
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);
}
// 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);
}