diff --git a/src/hexgame.cpp b/src/hexgame.cpp index 2b5f3e1..b46d81a 100644 --- a/src/hexgame.cpp +++ b/src/hexgame.cpp @@ -7,10 +7,7 @@ #include #endif -#include #include -#include -#include "aixlog.hpp" #include "hexgame.h" #include "hexlib.h" @@ -460,7 +457,6 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, int main(int argc, char* argv[]) #endif { - // init fancy new logger AixLog::Log::init(AixLog::Severity::trace, AixLog::Type::normal); LOG(INFO) << "Application started\n"; diff --git a/src/hexgame.h b/src/hexgame.h index 2d3100a..6d478a2 100644 --- a/src/hexgame.h +++ b/src/hexgame.h @@ -6,6 +6,8 @@ #include #include +#include "aixlog.hpp" + #include "hexlib.h" typedef float real32; diff --git a/src/renderer.h b/src/renderer.h index 808ca97..ae6def8 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -22,9 +22,70 @@ void renderFrame(const std::vector *hexes); void freeBuffers(); +const char * VERTEX_SHADER_CODE = + "#version 330 core\n" + "in vec3 vertexPosition_modelspace;\n" + "in vec3 vertexColor;\n" + "out vec3 fragmentColor;\n" + "uniform mat4 MVP;\n" + "void main()\n" + "{\n" + " gl_Position = MVP * vec4(vertexPosition_modelspace, 1);\n" + " fragmentColor = vertexColor;\n" + "}"; + +const char * FRAGMENT_SHADER_CODE = + "#version 330 core\n" + "in vec3 fragmentColor;\n" + "out vec3 color;\n" + "void main()\n" + "{\n" + " color = fragmentColor;\n" + "}"; + +const char * LINE_FRAGMENT_SHADER_CODE = + "#version 330 core\n" + "out vec3 color;\n" + "void main()\n" + "{\n" + " color = vec3(0,0,0);\n" + "}"; + + +typedef struct gl_matrix_info +{ + glm::mat4 projection; + glm::mat4 view; + glm::mat4 model; + glm::mat4 MVP; +} gl_matrix_info; + +typedef struct gl_buffer +{ + GLuint buffer_id; + size_t buffer_len; // NOTE: number of elements in buffer + GLfloat* buffer; +} gl_buffer; + +typedef 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; + GLuint program_id; + GLuint matrix_id; // NOTE: reference to a vertex shader's MVP matrix uniform + GLuint vertex_array_id; +} gl_render_group; + + +gl_matrix_info g_scene_matrices; +gl_render_group g_filled_hex_render_group; +gl_render_group g_hex_line_render_group; + // forward declarations bool initShaders(GLuint &programID1, GLuint &programID2); +bool initShaderProgram(gl_render_group &rg, const char * vertex_code, const char * frag_code, const char * mat_id); // enable debug output https://www.khronos.org/opengl/wiki/OpenGL_Error void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); @@ -32,23 +93,6 @@ void createScene(std::vector* hexes); void parseHexToGLBuffer(GLfloat buf[], int idx, const hex_info &hex); bool fillColorBuffer(GLfloat* buf, int len, std::vector *hexes); -// TODO: organize these into a struct/structs since we're using at least 2 now -glm::mat4 g_projection_matrix; -glm::mat4 g_view_matrix; -glm::mat4 g_model_matrix; -glm::mat4 g_MVP; -GLuint g_vertexbuffer; -GLuint g_vertex_buffer_triangle_count; -GLuint g_color_buffer; -size_t g_buf_size; -GLfloat *g_color_buf_data; -GLuint g_hex_programID; -GLuint g_matrixID; - -GLuint g_hex_line_vertexbuffer; -size_t g_line_buf_size; -GLuint g_line_programID; -GLuint g_line_matrixID; bool initRenderer(SDL_Handles &handles, v2i vpDims) @@ -104,80 +148,38 @@ initRenderer(SDL_Handles &handles, v2i vpDims) // hide VRAM debug messages glDebugMessageControl(GL_DONT_CARE, 33361, GL_DONT_CARE, 0, 0, GL_FALSE); - initShaders(g_hex_programID, g_line_programID); - g_matrixID = glGetUniformLocation(g_hex_programID, "g_MVP"); // shader variables for mvp xform - g_line_matrixID = glGetUniformLocation(g_line_programID, "g_MVP"); - + initShaderProgram(g_filled_hex_render_group, VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE, "MVP"); + initShaderProgram(g_hex_line_render_group, VERTEX_SHADER_CODE, LINE_FRAGMENT_SHADER_CODE, "MVP"); + return true; } -// TODO: figure out how to keep track of shader state, and pass in struct here -// TODO: make reusable by creating 1 program at a time +// NOTE: mat_id should match the matrix variable name in the shader source bool -initShaders(GLuint &programID1, GLuint &programID2) +initShaderProgram(gl_render_group &rg, const char * vertex_code, const char * frag_code, const char * mat_id) { - GLuint VertexArrayID; - glGenVertexArrays(1, &VertexArrayID); - glBindVertexArray(VertexArrayID); - - const char * VertexShaderCode = - "#version 330 core\n" - "in vec3 vertexPosition_modelspace;\n" - "in vec3 vertexColor;\n" - "out vec3 fragmentColor;\n" - "uniform mat4 g_MVP;\n" - "void main()\n" - "{\n" - " gl_Position = g_MVP * vec4(vertexPosition_modelspace, 1);\n" - " fragmentColor = vertexColor;\n" - "}"; - - const char * FragmentShaderCode = - "#version 330 core\n" - "in vec3 fragmentColor;\n" - "out vec3 color;\n" - "void main()\n" - "{\n" - " color = fragmentColor;\n" - "}"; -#if 1 - const char * LineFragmentShaderCode = - "#version 330 core\n" - "out vec3 color;\n" - "void main()\n" - "{\n" - " color = vec3(0,0,0);\n" - "}"; -#endif - GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); - GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - GLuint LineFragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(VertexShaderID, 1, &VertexShaderCode, NULL); - glShaderSource(FragmentShaderID, 1, &FragmentShaderCode, NULL); - glShaderSource(LineFragmentShaderID, 1, &LineFragmentShaderCode, NULL); - glCompileShader(VertexShaderID); - glCompileShader(FragmentShaderID); - glCompileShader(LineFragmentShaderID); - - programID1 = glCreateProgram(); - glAttachShader(programID1, VertexShaderID); - glAttachShader(programID1, FragmentShaderID); - glLinkProgram(programID1); - - programID2 = glCreateProgram(); - glAttachShader(programID2, VertexShaderID); - glAttachShader(programID2, LineFragmentShaderID); - glLinkProgram(programID2); - - glDetachShader(programID1, VertexShaderID); - glDetachShader(programID1, FragmentShaderID); - glDetachShader(programID2, LineFragmentShaderID); - glDetachShader(programID2, FragmentShaderID); - glDeleteShader(VertexShaderID); - glDeleteShader(FragmentShaderID); - glDeleteShader(LineFragmentShaderID); - - // TODO: what kind of errors can happen here? + 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.matrix_id = glGetUniformLocation(rg.program_id, mat_id); + + glDetachShader(rg.program_id, vertex_shader_id); + glDetachShader(rg.program_id, fragment_shader_id); + glDeleteShader(vertex_shader_id); + glDeleteShader(fragment_shader_id); + return true; } @@ -188,16 +190,16 @@ createScene(std::vector* hexes) // Model, View, Projection Matrices // left, right, bottom, top, zNear, zFar - g_projection_matrix = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f); + g_scene_matrices.projection = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f); - g_view_matrix = glm::lookAt( + g_scene_matrices.view = glm::lookAt( glm::vec3(0.0f, 0.0f, 2.0f), // camera position glm::vec3(0.0f, 0.0f, 0.0f), // look at position glm::vec3(0,1,0) // "up" vector ); - g_model_matrix = glm::mat4(1.0f); - g_MVP = g_projection_matrix * g_view_matrix * g_model_matrix; + g_scene_matrices.model = glm::mat4(1.0f); + g_scene_matrices.MVP = g_scene_matrices.projection * g_scene_matrices.view * g_scene_matrices.model; //////////////////// @@ -205,56 +207,59 @@ createScene(std::vector* hexes) // TODO: index duplicate vertices // http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/ - - // 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54 + int hex_count = (int) hexes->size(); + + gl_buffer *vertex_buffer = &g_filled_hex_render_group.vertex_buffer; + vertex_buffer->buffer_len = hex_count * 6 * 3 * 3; + vertex_buffer->buffer = (GLfloat*) std::calloc(vertex_buffer->buffer_len, sizeof(GLfloat)); + + // 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54 int buf_index = 54; - size_t hex_count = hexes->size(); - g_buf_size = 6 * 9 * hex_count; - GLfloat vbuf_data[g_buf_size] = { 0 }; - - for (int i = 0; i < (int) hex_count; i++) + for (int i = 0; i < hex_count; i++) { - parseHexToGLBuffer(vbuf_data, buf_index * i, (*hexes)[i]); + parseHexToGLBuffer(vertex_buffer->buffer, buf_index * i, (*hexes)[i]); } - - g_vertex_buffer_triangle_count = g_buf_size / 3; - glGenBuffers(1, &g_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, g_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_buf_size, vbuf_data, GL_STATIC_DRAW); - + + glGenBuffers(1, &g_filled_hex_render_group.vertex_buffer.buffer_id); + glBindBuffer(GL_ARRAY_BUFFER, g_filled_hex_render_group.vertex_buffer.buffer_id); + glBufferData(GL_ARRAY_BUFFER, vertex_buffer->buffer_len * sizeof(GLfloat), vertex_buffer->buffer, GL_DYNAMIC_DRAW); // color data for hex vertices - g_color_buf_data = (GLfloat*) std::calloc( g_buf_size, sizeof(GLfloat)); + gl_buffer *color_buffer = &g_filled_hex_render_group.color_buffer; + color_buffer->buffer_len = vertex_buffer->buffer_len; + color_buffer->buffer = (GLfloat*) std::calloc(color_buffer->buffer_len, sizeof(GLfloat)); - if (!fillColorBuffer(g_color_buf_data, (int) g_buf_size, hexes)) + if (!fillColorBuffer(color_buffer->buffer, color_buffer->buffer_len, hexes)) { - // TODO: log fatal error + //freeBuffers(); + //return false; + // TODO: check for retval in main() and run cleanUp() return; } - glGenBuffers(1, &g_color_buffer); - glBindBuffer(GL_ARRAY_BUFFER, g_color_buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_buf_size, g_color_buf_data, GL_DYNAMIC_DRAW); + glGenBuffers(1, &color_buffer->buffer_id); + glBindBuffer(GL_ARRAY_BUFFER, color_buffer->buffer_id); + glBufferData(GL_ARRAY_BUFFER, color_buffer->buffer_len * sizeof(GLfloat), color_buffer->buffer, GL_DYNAMIC_DRAW); - // Hex Line Vertex Data + // hex line vertex data - // TODO: surely there's a way to use indexed drawing for line vertices eg) LINE_LOOP - // and still use one buffer for multiple shapes/paths glDrawArraysIntanced?, glDrawElements? + // todo: surely there's a way to use indexed drawing for line vertices eg) line_loop + // and still use one buffer for multiple shapes/paths gldrawarraysintanced?, gldrawelements? // https://gamedev.stackexchange.com/questions/104310/opengl-4-5-primitive-restart-vs-base-index int line_vertices_per_hex = 6 * 2; // 12 vertices since we're using line segments atm - g_line_buf_size = hex_count * line_vertices_per_hex * 3; // 3 floats per vertex - GLfloat line_buf_data[g_line_buf_size] = { 0 }; + gl_buffer *line_vertex_buffer = &g_hex_line_render_group.vertex_buffer; + line_vertex_buffer->buffer_len = hexes->size() * line_vertices_per_hex * 3; // 3 floats per vertex + line_vertex_buffer->buffer = (GLfloat*) std::calloc(line_vertex_buffer->buffer_len, sizeof(GLfloat)); + Point p1, p2; int line_buf_idx = 0; - for (int i = 0; i < (int) hex_count; i++) + for (int i = 0; i < (int) hexes->size(); i++) { hex_info hxi = (*hexes)[i]; for (int j = 0; j < 6; j ++) { - Point p1, p2; - if (j == 5) // wrap { p1 = hxi.vertices[j]; @@ -266,20 +271,20 @@ createScene(std::vector* hexes) p2 = hxi.vertices[j + 1]; } - line_buf_data[line_buf_idx + 0] = p1.x; - line_buf_data[line_buf_idx + 1] = p1.y; - line_buf_data[line_buf_idx + 2] = 0.f; - line_buf_data[line_buf_idx + 3] = p2.x; - line_buf_data[line_buf_idx + 4] = p2.y; - line_buf_data[line_buf_idx + 5] = 0.f; + line_vertex_buffer->buffer[line_buf_idx + 0] = p1.x; + line_vertex_buffer->buffer[line_buf_idx + 1] = p1.y; + line_vertex_buffer->buffer[line_buf_idx + 2] = 0.f; + line_vertex_buffer->buffer[line_buf_idx + 3] = p2.x; + line_vertex_buffer->buffer[line_buf_idx + 4] = p2.y; + line_vertex_buffer->buffer[line_buf_idx + 5] = 0.f; line_buf_idx += 6; } } - glGenBuffers(1, &g_hex_line_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, g_hex_line_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * g_line_buf_size, line_buf_data, GL_STATIC_DRAW); + glGenBuffers(1, &line_vertex_buffer->buffer_id); + glBindBuffer(GL_ARRAY_BUFFER, line_vertex_buffer->buffer_id); + glBufferData(GL_ARRAY_BUFFER, line_vertex_buffer->buffer_len * sizeof(GLfloat), line_vertex_buffer->buffer, GL_STATIC_DRAW); } void @@ -381,7 +386,6 @@ openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { LOG((type == GL_DEBUG_TYPE_ERROR) ? ERROR : DEBUG) - << "openGLDebugCallback: " << (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "") << ", type: " << type << ", severity: " << severity @@ -395,51 +399,69 @@ renderFrame(std::vector *hexes) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - // filled hexes - - glUseProgram(g_hex_programID); + // TODO: learn how to use VAOs instead of these calls to glVertexAttribPointer + // https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Array_Object + gl_render_group* rg = &g_filled_hex_render_group; + glUseProgram(rg->program_id); // Send our transformation to the currently bound shader, in the "g_MVP" uniform - glUniformMatrix4fv(g_matrixID, 1, GL_FALSE, &g_MVP[0][0]); - + glUniformMatrix4fv(rg->matrix_id, 1, GL_FALSE, &g_scene_matrices.MVP[0][0]); + // 1st attribute buffer : vertices glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, g_vertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, rg->vertex_buffer.buffer_id); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); - + // 2nd attribute buffer : colors glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, g_color_buffer); + glBindBuffer(GL_ARRAY_BUFFER, rg->color_buffer.buffer_id); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); // get new colors every frame - fillColorBuffer(g_color_buf_data, (int) g_buf_size, hexes); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * g_buf_size, g_color_buf_data); - glDrawArrays(GL_TRIANGLES, 0, g_vertex_buffer_triangle_count); + fillColorBuffer(rg->color_buffer.buffer, rg->color_buffer.buffer_len, hexes); + glBufferSubData(GL_ARRAY_BUFFER, 0, rg->color_buffer.buffer_len * sizeof(GLfloat), rg->color_buffer.buffer); + + // draw + glDrawArrays(GL_TRIANGLES, 0, rg->vertex_buffer.buffer_len / 3); + + // cleanup glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); - - + + // hex lines - - glUseProgram(g_line_programID); + + rg = &g_hex_line_render_group; + glUseProgram(rg->program_id); // Send our transformation to the currently bound shader, in the "g_MVP" uniform - glUniformMatrix4fv(g_matrixID, 1, GL_FALSE, &g_MVP[0][0]); + glUniformMatrix4fv(rg->matrix_id, 1, GL_FALSE, &g_scene_matrices.MVP[0][0]); // 1st attribute buffer : vertices GLuint attrib_index = 0; // TODO: line buffer doesn't render if this is anything other than 0 glEnableVertexAttribArray(attrib_index); - glBindBuffer(GL_ARRAY_BUFFER, g_hex_line_vertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, rg->vertex_buffer.buffer_id); glVertexAttribPointer(attrib_index, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); - glDrawArrays(GL_LINES, 0, g_line_buf_size / 3); + glDrawArrays(GL_LINES, 0, rg->vertex_buffer.buffer_len / 3); } void freeBuffers() { - if (g_color_buf_data) + std::vector groups = {g_filled_hex_render_group, g_hex_line_render_group}; + + for (gl_render_group group : groups) { - free(g_color_buf_data); - g_color_buf_data = 0; + if (group.vertex_buffer.buffer) + { + std::free(group.vertex_buffer.buffer); + group.vertex_buffer.buffer = 0; + } + + if (group.color_buffer.buffer) + { + std::free(group.color_buffer.buffer); + group.color_buffer.buffer = 0; + } } + } #endif // RENDERER_H