8 changed files with 403 additions and 276 deletions
@ -0,0 +1,280 @@
|
||||
|
||||
#include <cassert> |
||||
#include <cstdlib> // calloc |
||||
|
||||
// TODO: decide on extension library
|
||||
//#include <GL/glew.h>
|
||||
#include <GL/gl3w.h> |
||||
#include <glm/glm.hpp> |
||||
#include <glm/geometric.hpp> |
||||
#include <glm/gtc/matrix_transform.hpp> |
||||
|
||||
#include "aixlog.hpp" |
||||
|
||||
#include "render_group.h" |
||||
|
||||
|
||||
gl_render_group* |
||||
rgCreateGroup() |
||||
{ |
||||
gl_render_group* rg = (gl_render_group *) std::calloc(1, sizeof(gl_render_group)); |
||||
return rg; |
||||
} |
||||
|
||||
bool |
||||
rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char * frag_code, |
||||
const char* model_name, const char* view_name, const char* projection_name) |
||||
{ |
||||
glGenVertexArrays(1, &rg->vertex_array_id); |
||||
glBindVertexArray(rg->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); |
||||
|
||||
rg->program_id = glCreateProgram(); |
||||
glAttachShader(rg->program_id, vertex_shader_id); |
||||
glAttachShader(rg->program_id, fragment_shader_id); |
||||
glLinkProgram(rg->program_id); |
||||
|
||||
rg->model_matrix_id = glGetUniformLocation(rg->program_id, model_name); |
||||
rg->view_matrix_id = glGetUniformLocation(rg->program_id, view_name); |
||||
rg->projection_matrix_id = glGetUniformLocation(rg->program_id, projection_name); |
||||
|
||||
glDetachShader(rg->program_id, vertex_shader_id); |
||||
glDetachShader(rg->program_id, fragment_shader_id); |
||||
glDeleteShader(vertex_shader_id); |
||||
glDeleteShader(fragment_shader_id); |
||||
|
||||
// check for errors
|
||||
GLint isLinked = 0; |
||||
glGetProgramiv(rg->program_id, GL_LINK_STATUS, &isLinked); |
||||
if (isLinked == GL_FALSE) { |
||||
GLint maxLength = 0; |
||||
glGetProgramiv(rg->program_id, GL_INFO_LOG_LENGTH, &maxLength); |
||||
|
||||
// The maxLength includes the NULL character
|
||||
GLchar infoLog[maxLength]; |
||||
glGetProgramInfoLog(rg->program_id, maxLength, &maxLength, &infoLog[0]); |
||||
LOG(ERROR) << infoLog << "\n"; |
||||
|
||||
// The program is useless now. So delete it.
|
||||
glDeleteProgram(rg->program_id); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// NOTE: this will only work after a call to glBindBuffer
|
||||
bool |
||||
checkGLBufferSize(GLenum buf_type, int expected_size, int line_num) |
||||
{ |
||||
GLint gl_size; |
||||
glGetBufferParameteriv(buf_type, GL_BUFFER_SIZE ,&gl_size); |
||||
|
||||
if (expected_size != gl_size) |
||||
{ |
||||
LOG(ERROR) << "line: " << line_num << "gl buffer size mismatch\n"; |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool |
||||
rgInitGLBufferObject(gl_buffer* buf_obj, int len, GLenum usage, GLfloat data[]) |
||||
{ |
||||
buf_obj->buffer_len = (size_t) len; |
||||
buf_obj->buffer = (GLfloat*) std::calloc(len, sizeof(GLfloat)); |
||||
|
||||
if (data) |
||||
{ |
||||
for (int i = 0; i < len; i++) |
||||
buf_obj->buffer[i] = data[i]; |
||||
} |
||||
|
||||
glGenBuffers(1, &buf_obj->buffer_id); |
||||
glBindBuffer(GL_ARRAY_BUFFER, buf_obj->buffer_id); |
||||
glBufferData(GL_ARRAY_BUFFER, len * sizeof(GLfloat), buf_obj->buffer, usage); |
||||
|
||||
if (!checkGLBufferSize(GL_ARRAY_BUFFER, len * sizeof(GLfloat), __LINE__)) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// NOTE: helper for fillColorBuffer() to convert uint32 color to GLfloat triplet
|
||||
void |
||||
convertColor(GLfloat buf[3], uint32 color) |
||||
{ |
||||
// NOTE: not using the alpha values for now
|
||||
buf[0] = (GLfloat) ((color >> 24) & 0xFF) / (GLfloat) 255;
|
||||
buf[1] = (GLfloat) ((color >> 16) & 0xFF) / (GLfloat) 255;
|
||||
buf[2] = (GLfloat) ((color >> 8) & 0xFF) / (GLfloat) 255;
|
||||
} |
||||
|
||||
void |
||||
rgFillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes) |
||||
{ |
||||
int buf_idx; |
||||
int buf_len_per_hex = 54; // NOTE: 3 * 3 * 6
|
||||
GLfloat color_buf[3]; |
||||
for (int i = 0; i < (int) hexes->size(); i++) |
||||
{ |
||||
buf_idx = i * buf_len_per_hex; |
||||
hex_info hxi = (*hexes)[i]; |
||||
convertColor(color_buf, hxi.current_color); |
||||
|
||||
for (int j = 0; j < buf_len_per_hex; j+=3) |
||||
{ |
||||
buf[buf_idx + j] = color_buf[0]; |
||||
buf[buf_idx + j + 1] = color_buf[1]; |
||||
buf[buf_idx + j + 2] = color_buf[2]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool |
||||
rgInitEntity(gl_render_group* rg, Entity* e) |
||||
{ |
||||
bool retVal = true; |
||||
|
||||
// TODO: entity scaling
|
||||
e->model_transform = glm::scale(glm::mat4(1), glm::vec3(100, 100, 100)); |
||||
|
||||
uint entity_buf_len = e->num_vertices * 3; |
||||
GLfloat* entity_buf = (GLfloat*) std::calloc(entity_buf_len, sizeof(GLfloat)); |
||||
GLfloat* entity_color_buf = (GLfloat*) std::calloc(entity_buf_len, sizeof(GLfloat)); |
||||
|
||||
// dump vertices into temporary buffer
|
||||
uint vertex_index = 0; |
||||
uint vertex_prop_index = 0; |
||||
GLfloat entity_test_color[3]; |
||||
convertColor(entity_test_color, 0xF46000FF); |
||||
|
||||
for (uint j = 0; j < entity_buf_len; j++) { |
||||
const glm::vec3& vertex = e->vertices[vertex_index]; |
||||
|
||||
switch (vertex_prop_index) { |
||||
case 0: entity_buf[j] = vertex.x; break; |
||||
case 1: entity_buf[j] = vertex.y; break; |
||||
case 2: entity_buf[j] = vertex.z; break; |
||||
} |
||||
|
||||
entity_color_buf[j] = entity_test_color[vertex_prop_index]; |
||||
vertex_prop_index++; |
||||
|
||||
if (vertex_prop_index == 3) { |
||||
vertex_prop_index = 0; |
||||
vertex_index++; |
||||
} |
||||
} |
||||
|
||||
#if 1 |
||||
if (!rgInitGLBufferObject(&rg->vertex_buffer, entity_buf_len, |
||||
GL_DYNAMIC_DRAW, entity_buf)) |
||||
retVal = false; |
||||
|
||||
if (!rgInitGLBufferObject(&rg->color_buffer, entity_buf_len, |
||||
GL_STATIC_DRAW, entity_color_buf)) |
||||
retVal = false; |
||||
#endif |
||||
|
||||
// TODO: testing indexed draw
|
||||
|
||||
gl_buffer index_buffer; |
||||
index_buffer.num_indices = e->num_indices; |
||||
// TODO: there's no associated call to free this alloc until we remake
|
||||
index_buffer.indices = (uint *) std::calloc(e->num_indices, sizeof(uint)); |
||||
|
||||
for (uint i = 0; i < e->num_indices; i++) |
||||
index_buffer.indices[i] = e->indices[i]; |
||||
|
||||
rg->index_buffer = index_buffer; |
||||
|
||||
//////////
|
||||
|
||||
std::free(entity_buf); |
||||
std::free(entity_color_buf); |
||||
entity_buf = entity_color_buf = nullptr; |
||||
|
||||
return retVal; |
||||
} |
||||
|
||||
void |
||||
rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, |
||||
glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data) |
||||
{ |
||||
glUseProgram(rg->program_id); |
||||
glUniformMatrix4fv(rg->model_matrix_id, 1, GL_FALSE, &model_matrix[0][0]); |
||||
glUniformMatrix4fv(rg->view_matrix_id, 1, GL_FALSE, &view_matrix[0][0]); |
||||
glUniformMatrix4fv(rg->projection_matrix_id, 1, GL_FALSE, &projection_matrix[0][0]); |
||||
|
||||
// 1st attribute buffer : vertices
|
||||
glEnableVertexAttribArray(0); |
||||
glBindBuffer(GL_ARRAY_BUFFER, rg->vertex_buffer.buffer_id); |
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
||||
|
||||
if (update_vertex_data) |
||||
{ |
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, rg->vertex_buffer.buffer_len * sizeof(GLfloat), |
||||
rg->vertex_buffer.buffer); |
||||
} |
||||
|
||||
// 2nd attribute buffer : colors
|
||||
if (rg->color_buffer.buffer) |
||||
{ |
||||
glEnableVertexAttribArray(1); |
||||
glBindBuffer(GL_ARRAY_BUFFER, rg->color_buffer.buffer_id); |
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); |
||||
|
||||
// TODO: maybe add an option to not send color data every frame?
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, rg->color_buffer.buffer_len * sizeof(GLfloat), |
||||
rg->color_buffer.buffer); |
||||
} |
||||
// draw
|
||||
glDrawArrays(draw_mode, 0, rg->vertex_buffer.buffer_len / 3); |
||||
|
||||
// cleanup
|
||||
glDisableVertexAttribArray(0); |
||||
if (rg->color_buffer.buffer) |
||||
glDisableVertexAttribArray(1); |
||||
} |
||||
|
||||
void |
||||
rgDrawIndexed(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, |
||||
glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data) |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
void |
||||
rgFree(gl_render_group* rg) |
||||
{ |
||||
assert(rg != nullptr); |
||||
gl_buffer bufs[] = {rg->vertex_buffer, rg->color_buffer, rg->index_buffer}; |
||||
for (uint i = 0; i < 3; i++) { |
||||
gl_buffer& buf = bufs[i]; |
||||
if (buf.buffer != nullptr) { |
||||
std::free(buf.buffer); |
||||
buf.buffer = nullptr; |
||||
} |
||||
if (buf.indices != nullptr) { |
||||
std::free(buf.indices); |
||||
buf.indices = nullptr; |
||||
} |
||||
} |
||||
|
||||
if (rg->entities != nullptr) { |
||||
// TODO: handle entity memory
|
||||
} |
||||
|
||||
std::free(rg); |
||||
rg = nullptr; |
||||
} |
||||
|
||||
@ -0,0 +1,52 @@
|
||||
|
||||
// TODO: put type info into seperate header from hexgame.h
|
||||
//#include "types.h"
|
||||
#include "hexgame.h" |
||||
|
||||
struct gl_buffer |
||||
{ |
||||
GLuint buffer_id = 0; |
||||
size_t buffer_len = 0; // NOTE: number of elements in buffer
|
||||
GLfloat* buffer = nullptr; |
||||
uint num_indices = 0; |
||||
uint* indices = nullptr; |
||||
} ; |
||||
|
||||
struct gl_render_group |
||||
{ |
||||
// NOTE: For now the renderFrame function will assume these are the same size
|
||||
gl_buffer vertex_buffer; |
||||
gl_buffer color_buffer; |
||||
gl_buffer index_buffer; |
||||
GLuint program_id = 0; |
||||
GLuint model_matrix_id = 0; |
||||
GLuint view_matrix_id = 0; |
||||
GLuint projection_matrix_id = 0; |
||||
GLuint vertex_array_id = 0; |
||||
Entity* entities = nullptr; |
||||
}; |
||||
|
||||
typedef struct gl_buffer gl_buffer; |
||||
typedef struct gl_render_group gl_render_group; |
||||
|
||||
gl_render_group* rgCreateGroup(); |
||||
|
||||
// NOTE: model_name, view_name, and projection_name should match the matrix variable
|
||||
// names in the shader source
|
||||
bool rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char * frag_code, |
||||
const char* model_name, const char* view_name, const char* projection_name); |
||||
|
||||
bool rgInitGLBufferObject(gl_buffer* buf_obj, int len, GLenum usage, GLfloat data[]); |
||||
|
||||
bool rgInitEntity(gl_render_group* rg, Entity* e); |
||||
|
||||
void rgFillColorBuffer(GLfloat buf[], int len, std::vector<hex_info>* hexes); |
||||
|
||||
void rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, |
||||
glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data = false); |
||||
|
||||
void rgDrawIndexed(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, |
||||
glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data = false); |
||||
|
||||
void rgFree(gl_render_group* rg); |
||||
|
||||
Loading…
Reference in new issue