10 changed files with 168 additions and 417 deletions
@ -1,99 +0,0 @@
|
||||
|
||||
#pragma once |
||||
|
||||
#include <GL/glew.h> |
||||
#include <glm/glm.hpp> |
||||
|
||||
#include "util.h" |
||||
#include "util_image.h" |
||||
|
||||
|
||||
// TODO: can these structs be used as opaque pointers?
|
||||
struct gl_buffer |
||||
{ |
||||
GLuint buffer_id; |
||||
uint count; // NOTE: number of elements in buffer
|
||||
uint max_count; // NOTE: maxium number of elements buffer can fit
|
||||
GLfloat* buffer; |
||||
}; |
||||
|
||||
struct gl_index_buffer |
||||
{ |
||||
GLuint buffer_id; |
||||
uint count; // NOTE: number of elements in buffer
|
||||
uint max_count; // NOTE: maxium number of elements buffer can fit
|
||||
uint* buffer; |
||||
}; |
||||
|
||||
struct render_object |
||||
{ |
||||
glm::mat4 node_xform; |
||||
|
||||
// TODO: can remove these once we're using the global color palatte for all textures
|
||||
bool use_texture; |
||||
GLuint tex_id; |
||||
|
||||
gl_buffer vertex_buffer; |
||||
gl_buffer normal_buffer; |
||||
gl_buffer uv_buffer; |
||||
gl_index_buffer index_buffer; |
||||
}; |
||||
|
||||
struct rg_shader_program |
||||
{ |
||||
GLuint program_id; |
||||
|
||||
GLuint model_matrix_id; |
||||
GLuint view_matrix_id; |
||||
GLuint projection_matrix_id; |
||||
GLuint normal_matrix_id; |
||||
|
||||
GLuint vertex_array_id; |
||||
GLuint sampler_id; |
||||
GLuint num_lights_id; |
||||
}; |
||||
|
||||
struct render_group |
||||
{ |
||||
uint num_objects; |
||||
render_object** render_objects; |
||||
rg_shader_program shader; |
||||
bool use_normals; |
||||
bool draw_indexed; |
||||
GLenum draw_mode = GL_TRIANGLES; |
||||
char name[64]; |
||||
}; |
||||
|
||||
// TODO: maybe pull out to seperate header
|
||||
struct rg_point_light |
||||
{ |
||||
uint light_ID; |
||||
glm::vec3 position; |
||||
glm::vec3 color; |
||||
float intensity; |
||||
}; |
||||
|
||||
render_object * rgAllocateRenderObject(uint buffer_len, uint index_len = 0); |
||||
|
||||
// NOTE: initializes a render_group with 1 render_object allocated
|
||||
render_group* rgInitSingle(rg_shader_program& sp, uint vertex_buffer_len, |
||||
bool use_normals = false, uint index_buffer_len = 0, |
||||
GLenum draw_mode = GL_TRIANGLES); |
||||
|
||||
bool rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char * frag_code); |
||||
|
||||
bool rgInitGLTexture(GLuint& tex_id, util_image image); |
||||
|
||||
void rgInitGLFloatBuffer(gl_buffer* buffer, GLenum usage, GLenum target); |
||||
|
||||
void rgInitGLIndexBuffer(gl_index_buffer* index_buffer, GLenum usage, GLenum target); |
||||
|
||||
void rgUpdateGLBuffer(gl_buffer& buffer); |
||||
|
||||
void rgDraw(render_group* rg, glm::mat4 model_matrix, |
||||
glm::mat4 view_matrix, glm::mat4 projection_matrix, |
||||
rg_point_light* lights, uint num_lights, |
||||
bool update_vertex_data = false); |
||||
|
||||
void rgFree(render_group* rg); |
||||
|
||||
@ -0,0 +1,28 @@
|
||||
|
||||
#pragma once |
||||
|
||||
#include <GL/glew.h> |
||||
#include <glm/glm.hpp> |
||||
|
||||
|
||||
struct 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; |
||||
}; |
||||
|
||||
struct point_light |
||||
{ |
||||
uint light_ID; |
||||
glm::vec3 position; |
||||
glm::vec3 color; |
||||
float intensity; |
||||
}; |
||||
|
||||
void roFree(render_object* ro); |
||||
|
||||
@ -0,0 +1,22 @@
|
||||
|
||||
#pragma once |
||||
|
||||
#include <GL/glew.h> |
||||
|
||||
|
||||
struct shader_program |
||||
{ |
||||
GLuint program_id; |
||||
|
||||
GLuint model_matrix_id; |
||||
GLuint view_matrix_id; |
||||
GLuint projection_matrix_id; |
||||
GLuint normal_matrix_id; |
||||
|
||||
GLuint vertex_array_id; |
||||
GLuint sampler_id; |
||||
GLuint num_lights_id; |
||||
}; |
||||
|
||||
shader_program* initShaderProgram(const char* vertex_code, const char* frag_code); |
||||
|
||||
@ -1,277 +0,0 @@
|
||||
|
||||
#include <sstream> // TODO: remove this and make something in util.h |
||||
#include <cassert> |
||||
|
||||
#include <glm/glm.hpp> |
||||
#include <glm/geometric.hpp> |
||||
#include <glm/gtc/matrix_transform.hpp> |
||||
|
||||
#include "dumbLog.h" |
||||
|
||||
#include "render_group.h" |
||||
#include "util.h" |
||||
|
||||
#define INFO_LOG_MAX_LENGTH 312 |
||||
|
||||
|
||||
// forward declarations
|
||||
|
||||
void freeRenderObject(render_object* ro); |
||||
void rgInitGLIndexBuffer(gl_index_buffer* index_buffer, GLenum usage, GLenum target); |
||||
|
||||
|
||||
// interface
|
||||
|
||||
render_object * |
||||
rgAllocateRenderObject(uint buffer_len, uint index_len) |
||||
{ |
||||
render_object* ro = UTIL_ALLOC(1, render_object); |
||||
|
||||
if (ro == nullptr) |
||||
return nullptr; |
||||
|
||||
ro->vertex_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat); |
||||
ro->vertex_buffer.count = ro->vertex_buffer.max_count = buffer_len; |
||||
ro->normal_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat); |
||||
ro->normal_buffer.count = ro->normal_buffer.max_count = buffer_len; |
||||
ro->uv_buffer.buffer = UTIL_ALLOC(buffer_len, GLfloat); |
||||
ro->uv_buffer.count = ro->uv_buffer.max_count = buffer_len; |
||||
|
||||
if (index_len > 0) { |
||||
ro->index_buffer.buffer = UTIL_ALLOC(index_len, uint); |
||||
ro->index_buffer.count = index_len; |
||||
} |
||||
|
||||
if (ro->vertex_buffer.buffer == nullptr || |
||||
ro->normal_buffer.buffer == nullptr || |
||||
((index_len > 0) && (ro->vertex_buffer.buffer == nullptr))) |
||||
{ |
||||
freeRenderObject(ro); |
||||
return nullptr; |
||||
} |
||||
|
||||
return ro; |
||||
} |
||||
|
||||
render_group* |
||||
rgInitSingle(rg_shader_program& sp, uint vertex_buffer_len, |
||||
bool use_normals, uint index_buffer_len, |
||||
GLenum draw_mode) |
||||
{ |
||||
render_group* rg = UTIL_ALLOC(1, render_group); |
||||
rg->shader = sp; |
||||
rg->use_normals = use_normals; |
||||
rg->draw_indexed = (index_buffer_len > 0); |
||||
rg->draw_mode = draw_mode; |
||||
|
||||
rg->render_objects = UTIL_ALLOC(1, render_object*); |
||||
rg->render_objects[0] = rgAllocateRenderObject(vertex_buffer_len, index_buffer_len); |
||||
rg->num_objects = 1; |
||||
|
||||
if (rg->render_objects[0] == nullptr) { |
||||
LOG(Error) << "Allocation Error\n"; |
||||
rgFree(rg); |
||||
} |
||||
|
||||
return rg; |
||||
} |
||||
|
||||
bool |
||||
rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char * frag_code) |
||||
{ |
||||
glGenVertexArrays(1, &sp.vertex_array_id); |
||||
glBindVertexArray(sp.vertex_array_id); |
||||
GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); |
||||
GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER); |
||||
|
||||
glShaderSource(vertex_shader_id, 1, &vertex_code, NULL); |
||||
glShaderSource(fragment_shader_id, 1, &frag_code, NULL); |
||||
glCompileShader(vertex_shader_id); |
||||
glCompileShader(fragment_shader_id); |
||||
|
||||
sp.program_id = glCreateProgram(); |
||||
glAttachShader(sp.program_id, vertex_shader_id); |
||||
glAttachShader(sp.program_id, fragment_shader_id); |
||||
glLinkProgram(sp.program_id); |
||||
|
||||
sp.model_matrix_id = glGetUniformLocation(sp.program_id, "model"); |
||||
sp.view_matrix_id = glGetUniformLocation(sp.program_id, "view"); |
||||
sp.projection_matrix_id = glGetUniformLocation(sp.program_id, "projection"); |
||||
sp.normal_matrix_id = glGetUniformLocation(sp.program_id, "normal_matrix"); |
||||
sp.num_lights_id = glGetUniformLocation(sp.program_id, "num_lights"); |
||||
sp.sampler_id = glGetUniformLocation(sp.program_id, "sampler"); |
||||
|
||||
glDetachShader(sp.program_id, vertex_shader_id); |
||||
glDetachShader(sp.program_id, fragment_shader_id); |
||||
glDeleteShader(vertex_shader_id); |
||||
glDeleteShader(fragment_shader_id); |
||||
|
||||
// TODO: quick hack to allow 'dynamic' stack allocation for msvc
|
||||
// also remove INFO_LOG_MAX_LENGTH define
|
||||
GLint isLinked = 0; |
||||
glGetProgramiv(sp.program_id, GL_LINK_STATUS, &isLinked); |
||||
if (isLinked == GL_FALSE) { |
||||
GLint maxLength = INFO_LOG_MAX_LENGTH; |
||||
glGetProgramiv(sp.program_id, GL_INFO_LOG_LENGTH, &maxLength); |
||||
#ifdef _WIN32 |
||||
GLchar infoLog[312] = { 0 }; |
||||
#else |
||||
GLchar infoLog[maxLength] = { 0 }; |
||||
#endif |
||||
glGetProgramInfoLog(sp.program_id, maxLength, &maxLength, &infoLog[0]); |
||||
LOG(Error) << infoLog << "\n"; |
||||
glDeleteProgram(sp.program_id); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
rgInitGLTexture(GLuint& tex_id, util_image image) |
||||
{ |
||||
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); |
||||
} |
||||
|
||||
void |
||||
rgInitGLFloatBuffer(gl_buffer* buffer, GLenum usage, GLenum target) |
||||
{ |
||||
glGenBuffers(1, &buffer->buffer_id); |
||||
glBindBuffer(target, buffer->buffer_id); |
||||
glBufferData(target, buffer->max_count * sizeof(GLfloat), buffer->buffer, usage); |
||||
} |
||||
|
||||
void |
||||
rgInitGLIndexBuffer(gl_index_buffer* index_buffer, GLenum usage, GLenum target) |
||||
{ |
||||
glGenBuffers(1, &index_buffer->buffer_id); |
||||
glBindBuffer(target, index_buffer->buffer_id); |
||||
glBufferData(target, index_buffer->count * sizeof(uint), index_buffer->buffer, usage); |
||||
} |
||||
|
||||
void |
||||
rgUpdateGLBuffer(gl_buffer& buffer) |
||||
{ |
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer.buffer_id); |
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, buffer.count * sizeof(GLfloat), buffer.buffer); |
||||
} |
||||
|
||||
void |
||||
rgDraw(render_group* rg, glm::mat4 model_matrix, |
||||
glm::mat4 view_matrix, glm::mat4 projection_matrix, |
||||
rg_point_light* lights, uint num_lights, bool update_vertex_data) |
||||
{ |
||||
for (uint i = 0; i < rg->num_objects; i++) { |
||||
render_object* ro = rg->render_objects[i]; |
||||
|
||||
glUseProgram(rg->shader.program_id); |
||||
glUniformMatrix4fv(rg->shader.model_matrix_id, 1, GL_FALSE, &model_matrix[0][0]); |
||||
glUniformMatrix4fv(rg->shader.view_matrix_id, 1, GL_FALSE, &view_matrix[0][0]); |
||||
glUniformMatrix4fv(rg->shader.projection_matrix_id, 1, GL_FALSE, &projection_matrix[0][0]); |
||||
|
||||
// 1st attribute buffer : vertices
|
||||
glEnableVertexAttribArray(0); |
||||
glBindBuffer(GL_ARRAY_BUFFER, ro->vertex_buffer.buffer_id); |
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
||||
|
||||
if (update_vertex_data) |
||||
{ |
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, ro->vertex_buffer.count * sizeof(GLfloat), |
||||
ro->vertex_buffer.buffer); |
||||
} |
||||
|
||||
// 2rd attribute buffer: normals
|
||||
if (rg->use_normals) { |
||||
glEnableVertexAttribArray(1); |
||||
glBindBuffer(GL_ARRAY_BUFFER, ro->normal_buffer.buffer_id); |
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
||||
|
||||
glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(model_matrix))); |
||||
glUniformMatrix3fv(rg->shader.normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); |
||||
|
||||
// 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(rg->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(rg->shader.program_id, ss.str().c_str()); |
||||
glUniform3fv(light_pos_loc, 1, &lights[i].position[0]); |
||||
} |
||||
} |
||||
|
||||
// 3rd attribute buffer: UV coordinates
|
||||
if (ro->use_texture) { |
||||
glEnableVertexAttribArray(2); |
||||
glBindBuffer(GL_ARRAY_BUFFER, ro->uv_buffer.buffer_id); |
||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
||||
glBindTexture(GL_TEXTURE_2D, ro->tex_id); |
||||
glUniform1i(rg->shader.sampler_id, 0); |
||||
} |
||||
|
||||
// draw
|
||||
if (rg->draw_indexed) { |
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ro->index_buffer.buffer_id); |
||||
glDrawElements(rg->draw_mode, ro->index_buffer.count, GL_UNSIGNED_INT, 0); |
||||
} else { |
||||
glDrawArrays(rg->draw_mode, 0, ro->vertex_buffer.count / 3); |
||||
} |
||||
|
||||
// cleanup
|
||||
glDisableVertexAttribArray(0); |
||||
if (rg->use_normals) |
||||
glDisableVertexAttribArray(1); |
||||
if (ro->use_texture) |
||||
glDisableVertexAttribArray(2); |
||||
|
||||
glUseProgram(0); |
||||
} |
||||
} |
||||
|
||||
void |
||||
rgFree(render_group* rg) |
||||
{ |
||||
if (rg == nullptr) { |
||||
LOG(Error) << "tried to free nullptr\n"; |
||||
return; |
||||
} |
||||
|
||||
for (uint i = 0; i < rg->num_objects; i++) |
||||
freeRenderObject(rg->render_objects[i]); |
||||
|
||||
utilSafeFree(rg->render_objects); |
||||
utilSafeFree(rg); |
||||
} |
||||
|
||||
|
||||
// internal
|
||||
|
||||
void |
||||
freeRenderObject(render_object* ro) |
||||
{ |
||||
if (ro == nullptr) { |
||||
LOG(Error) << "Tried to free nullptr\n"; |
||||
return; |
||||
} |
||||
|
||||
glDeleteTextures(1, &ro->tex_id); |
||||
utilSafeFree(ro->vertex_buffer.buffer); |
||||
utilSafeFree(ro->normal_buffer.buffer); |
||||
utilSafeFree(ro->uv_buffer.buffer); |
||||
utilSafeFree(ro->index_buffer.buffer); |
||||
utilSafeFree(ro); |
||||
} |
||||
@ -0,0 +1,10 @@
|
||||
|
||||
#include "dumbLog.h" |
||||
#include "render_object.h" |
||||
|
||||
|
||||
void |
||||
roFree(render_object* ro) |
||||
{ |
||||
LOG(Debug) << "TODO: release GL buffers from render_object\n"; |
||||
} |
||||
@ -0,0 +1,61 @@
|
||||
|
||||
#include "dumbLog.h" |
||||
#include "shader_program.h" |
||||
#include "util.h" |
||||
|
||||
|
||||
// TODO: remove and fix hack for dynamic stack allocation
|
||||
#define INFO_LOG_MAX_LENGTH 312 |
||||
|
||||
|
||||
shader_program* |
||||
initShaderProgram(const char* vertex_code, const char* frag_code) |
||||
{ |
||||
shader_program* sp = UTIL_ALLOC(1, shader_program); |
||||
glGenVertexArrays(1, &sp->vertex_array_id); |
||||
glBindVertexArray(sp->vertex_array_id); |
||||
GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); |
||||
GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER); |
||||
|
||||
glShaderSource(vertex_shader_id, 1, &vertex_code, NULL); |
||||
glShaderSource(fragment_shader_id, 1, &frag_code, NULL); |
||||
glCompileShader(vertex_shader_id); |
||||
glCompileShader(fragment_shader_id); |
||||
|
||||
sp->program_id = glCreateProgram(); |
||||
glAttachShader(sp->program_id, vertex_shader_id); |
||||
glAttachShader(sp->program_id, fragment_shader_id); |
||||
glLinkProgram(sp->program_id); |
||||
|
||||
sp->model_matrix_id = glGetUniformLocation(sp->program_id, "model"); |
||||
sp->view_matrix_id = glGetUniformLocation(sp->program_id, "view"); |
||||
sp->projection_matrix_id = glGetUniformLocation(sp->program_id, "projection"); |
||||
sp->normal_matrix_id = glGetUniformLocation(sp->program_id, "normal_matrix"); |
||||
sp->num_lights_id = glGetUniformLocation(sp->program_id, "num_lights"); |
||||
sp->sampler_id = glGetUniformLocation(sp->program_id, "sampler"); |
||||
|
||||
glDetachShader(sp->program_id, vertex_shader_id); |
||||
glDetachShader(sp->program_id, fragment_shader_id); |
||||
glDeleteShader(vertex_shader_id); |
||||
glDeleteShader(fragment_shader_id); |
||||
|
||||
GLint isLinked = 0; |
||||
glGetProgramiv(sp->program_id, GL_LINK_STATUS, &isLinked); |
||||
if (isLinked == GL_FALSE) { |
||||
GLint maxLength = INFO_LOG_MAX_LENGTH; |
||||
glGetProgramiv(sp->program_id, GL_INFO_LOG_LENGTH, &maxLength); |
||||
#ifdef _WIN32 |
||||
GLchar infoLog[312] = { 0 }; |
||||
#else |
||||
GLchar infoLog[maxLength] = { 0 }; |
||||
#endif |
||||
glGetProgramInfoLog(sp->program_id, maxLength, &maxLength, &infoLog[0]); |
||||
LOG(Error) << infoLog << "\n"; |
||||
glDeleteProgram(sp->program_id); |
||||
|
||||
return nullptr; |
||||
} |
||||
|
||||
return sp; |
||||
} |
||||
|
||||
Loading…
Reference in new issue