From 49c562f6eddfc75b08d00e8294e2a6dd64314bfe Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Thu, 18 Oct 2018 07:07:40 -0400 Subject: [PATCH] completed entity changes to renderer/render_group can now use rgInitSingle() to initializa a render_group with only one group of buffers (render_object) --- src/render_group.cpp | 88 +++---- src/render_group.h | 8 + src/renderer.cpp | 594 +++++++++++++++++++++++-------------------- src/util.cpp | 3 + 4 files changed, 368 insertions(+), 325 deletions(-) diff --git a/src/render_group.cpp b/src/render_group.cpp index b7fa836..a97f4a1 100644 --- a/src/render_group.cpp +++ b/src/render_group.cpp @@ -20,7 +20,6 @@ render_object * allocateRenderObject(uint buffer_len, uint index_len = 0); void freeRenderObject(render_object* ro); bool convertMeshInfo(meMeshInfo* mesh, render_object* ro, bool use_normals); -void sendBufferToGL(gl_buffer* buffer, GLenum usage, GLenum target); void sendIndexBufferToGL(gl_index_buffer* index_buffer, GLenum usage, GLenum target); void drawRenderObject(render_group* rg, render_object* ro, glm::mat4 model_matrix, glm::mat4 view_matrix, glm::mat4 projection_matrix, @@ -29,6 +28,29 @@ void drawRenderObject(render_group* rg, render_object* ro, // interface +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] = allocateRenderObject(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) { @@ -59,7 +81,6 @@ rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char // TODO: quick hack to allow 'dynamic' stack allocation for msvc // also remove INFO_LOG_MAX_LENGTH define -#if 1 GLint isLinked = 0; glGetProgramiv(sp.program_id, GL_LINK_STATUS, &isLinked); if (isLinked == GL_FALSE) { @@ -76,42 +97,19 @@ rgInitShaderProgram(rg_shader_program& sp, const char * vertex_code, const char return false; } -#endif return true; } -// TODO: should pass in a buffer of colors here instead of hexes, move to renderer.cpp -// we don't need to know about hexes here -#if 0 -void -rgFillColorBuffer(GLfloat buf[], int len, std::vector* 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]; - utilConvertColor(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]; - } - } -} -#endif - +// TODO: move Entity initialization to Entity.h/.cpp to fix circular dependancy +// then just call into convertMeshInfo directly bool rgInitEntity(Entity* e) { render_group* rg = UTIL_ALLOC(1, render_group); e->ren_group = rg; rg->draw_indexed = true; + rg->draw_mode = GL_TRIANGLES; rg->use_normals = e->mesh_group.use_normals; uint num_meshes = rg->num_objects = e->mesh_group.num_meshes; @@ -139,13 +137,21 @@ rgInitEntity(Entity* e) return true; } +void +rgBufferData(gl_buffer* buffer, GLenum usage, GLenum target) +{ + glGenBuffers(1, &buffer->buffer_id); + glBindBuffer(target, buffer->buffer_id); + glBufferData(target, buffer->buffer_len * sizeof(GLfloat), buffer->buffer, usage); +} + void rgDraw(render_group* rg, glm::mat4 model_matrix, glm::mat4 view_matrix, glm::mat4 projection_matrix, glm::vec3 light_position, GLuint light_id, bool update_vertex_data) { for (uint i = 0; i < rg->num_objects; i++) { drawRenderObject(rg, rg->render_objects[i], model_matrix, view_matrix, projection_matrix, - light_position, light_id, false); + light_position, light_id, update_vertex_data); } } @@ -160,6 +166,7 @@ rgFree(render_group* rg) for (uint i = 0; i < rg->num_objects; i++) freeRenderObject(rg->render_objects[i]); + utilSafeFree(rg->render_objects); utilSafeFree(rg); } @@ -208,14 +215,6 @@ freeRenderObject(render_object* ro) utilSafeFree(ro); } -void -sendBufferToGL(gl_buffer* buffer, GLenum usage, GLenum target) -{ - glGenBuffers(1, &buffer->buffer_id); - glBindBuffer(target, buffer->buffer_id); - glBufferData(target, buffer->buffer_len * sizeof(GLfloat), buffer->buffer, usage); -} - void sendIndexBufferToGL(gl_index_buffer* index_buffer, GLenum usage, GLenum target) { @@ -271,10 +270,10 @@ convertMeshInfo(meMeshInfo* mesh, render_object* ro, bool use_normals) for (uint i = 0; i < mesh->num_indices; i++) index_buf[i] = mesh->indices[i]; - sendBufferToGL(&ro->vertex_buffer, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); - sendBufferToGL(&ro->color_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + rgBufferData(&ro->vertex_buffer, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); + rgBufferData(&ro->color_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER); if (use_normals) - sendBufferToGL(&ro->normal_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + rgBufferData(&ro->normal_buffer, GL_STATIC_DRAW, GL_ARRAY_BUFFER); sendIndexBufferToGL(&ro->index_buffer, GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); return true; @@ -314,7 +313,6 @@ drawRenderObject(render_group* rg, render_object* ro, } // 3rd attribute buffer: normals -#if 1 if (rg->use_normals) { glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, ro->normal_buffer.buffer_id); @@ -325,17 +323,13 @@ drawRenderObject(render_group* rg, render_object* ro, 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]); } -#endif // draw if (rg->draw_indexed) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ro->index_buffer.buffer_id); - // TODO: find out why rg->draw_mode isn't being preserved as GL_TRIANGLES - //glDrawElements(rg->draw_mode, ro->index_buffer.buffer_len, GL_UNSIGNED_INT, 0); - glDrawElements(GL_TRIANGLES, ro->index_buffer.buffer_len, GL_UNSIGNED_INT, 0); + glDrawElements(rg->draw_mode, ro->index_buffer.buffer_len, GL_UNSIGNED_INT, 0); } else { - //glDrawArrays(rg->draw_mode, 0, ro->vertex_buffer.buffer_len / 3); - glDrawArrays(GL_TRIANGLES, 0, ro->vertex_buffer.buffer_len / 3); + glDrawArrays(rg->draw_mode, 0, ro->vertex_buffer.buffer_len / 3); } // cleanup diff --git a/src/render_group.h b/src/render_group.h index 8c67568..0342b28 100644 --- a/src/render_group.h +++ b/src/render_group.h @@ -53,10 +53,18 @@ struct render_group GLenum draw_mode = GL_TRIANGLES; }; +// 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 rgInitEntity(Entity* e); +void +rgBufferData(gl_buffer* buffer, GLenum usage, GLenum target); + // TODO: fix this function to use just buffers instead of hexes //void rgFillColorBuffer(GLfloat buf[], int len, std::vector* hexes); diff --git a/src/renderer.cpp b/src/renderer.cpp index 6ec9d3e..e7b7e09 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -83,11 +83,23 @@ struct camera }; +// forward declarations +void initMatrices(projection_type p); +void openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message, const void* userParam); +bool initHexGridBuffers(std::vector* hexes); +void fillTriangleBufferFromHex(GLfloat buf[], int idx, const hex_info &hex); +void fillColorBuffer(GLfloat buf[], int len, std::vector* hexes); +void fillHexLineBuffer(GLfloat buf[], int len, std::vector* hexes); + + // globals static gl_matrix_info g_scene_matrices; static render_group* g_filled_hex_render_group; static render_group* g_hex_line_render_group; static render_group* g_debug_render_group; +static rg_shader_program g_default_shader; +static rg_shader_program g_line_shader; // NOTE: entity render_group pointers are kept in the entity struct static camera g_camera; @@ -95,125 +107,7 @@ static camera g_camera; static renPointLight g_test_light; -bool -addTexture(SDL_Handles &handles, const char * path) -{ - // testing - LOG(INFO) << "Loading image: " << path << "\n"; - SDL_Surface* image = IMG_Load(path); - - if (!image) - { - LOG(ERROR) << "IMG_Load: " << IMG_GetError() << "\n"; - return false; - } - - GLuint tex_id; - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, 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); - - // store opengl id in SDL_Surface.userdat - image->userdata = (void*)(intptr_t) tex_id; - handles.texSurfaces.push_back(image); - - return true; -} - -v2f -getUnprojectedCoords(int32 x, int32 y, int32 vp_width, int32 vp_height) -{ - // NOTE: using depth buffer may not be as accurate as doing ray-cast - GLfloat depth; - glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); - glm::vec4 viewport = glm::vec4(0, 0, vp_width, vp_height); - glm::vec3 wincoord = glm::vec3(x, y, depth); - glm::vec3 vU = glm::unProject(wincoord, g_scene_matrices.view, g_scene_matrices.projection, viewport); - v2f v(vU.x, vU.y); - - return v; -} - -v3f -getCameraPosition() -{ - return v3f(g_camera.position.x, g_camera.position.y, g_camera.position.z); -} - -void -initMatrices(projection_type p) -{ - // TODO: many constants used here should be passed as args - - if (p == PERSPECTIVE) - { - g_scene_matrices.projection = glm::infinitePerspective( - glm::radians(60.f), // FoV - 16.f / 9.f, // ascpect ratio - 0.1f // near clip plane - ); - - g_camera.position = glm::vec3(640,0,100); - g_camera.target = glm::vec3(640,500,0); - //g_camera.target = glm::vec3(0,0,0); - // inital rotation should match target direction - glm::vec3 &p = g_camera.position; - glm::vec3 &t = g_camera.target; - g_camera.hAngle = 0; - g_camera.vAngle = glm::atan((t.z - p.z) / (t.y - p.y)); - - ////// - // TODO: add call to rotate camera here to remove duplicate code - camera &c = g_camera; - float &h = c.hAngle; - float &v = c.vAngle; - c.forward = glm::vec3( - glm::cos(v) * glm::sin(h), - glm::cos(v) * glm::cos(h), - glm::sin(v) - ); - - glm::normalize(c.forward); - ////// - - g_camera.up = glm::vec3(0,1,0); - g_camera.left = glm::normalize(glm::cross(g_camera.up, g_camera.forward)); - g_camera.up = glm::normalize(glm::cross(g_camera.forward, g_camera.left)); - - g_scene_matrices.view = glm::lookAt( - g_camera.position, // camera position - g_camera.position + g_camera.forward, - g_camera.up // "up" vector - ); - } - else // ORTHO - { - // left, right, bottom, top, zNear, zFar - g_scene_matrices.projection = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f); - g_scene_matrices.view = glm::lookAt( - glm::vec3(0.0f, 0.0f, 1.0f), // camera position - glm::vec3(0.0f, 0.0f, 0.0f), // look at position - glm::vec3(0,1,0) // "up" vector - ); - } - - g_scene_matrices.model = glm::mat4(1.0f); - g_scene_matrices.MVP = g_scene_matrices.projection * g_scene_matrices.view * g_scene_matrices.model; -} - -void -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) - << (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "") - << ", type: " << type - << ", severity: " << severity - << ", message: " << message << "\n"; -} +// interface bool initRenderer(SDL_Handles &handles, v2i vpDims) @@ -258,15 +152,10 @@ initRenderer(SDL_Handles &handles, v2i vpDims) glEnable(GL_DEPTH_TEST); glEnable(GL_LINE_SMOOTH); - - // TODO: blending, these options break the http://www.opengl-tutorial.org tutorials atm - // Setup render state: alpha-blending enabled, polygon fill -#if 1 glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_ONE, GL_SRC_ALPHA); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -#endif // TODO: glDebugMessageCallback is only availabe from >v4.3 // check and warn if context doesn't support this function here @@ -275,16 +164,10 @@ initRenderer(SDL_Handles &handles, v2i vpDims) // hide VRAM debug messages glDebugMessageControl(GL_DONT_CARE, 33361, GL_DONT_CARE, 0, 0, GL_FALSE); - g_filled_hex_render_group = UTIL_ALLOC(1, render_group); - g_hex_line_render_group = UTIL_ALLOC(1, render_group); - g_debug_render_group = UTIL_ALLOC(1, render_group); -#if 0 const char* vs_code = utilDumpTextFile(DEFAULT_VERTEX_SHADER_FILE); const char* fs_code = utilDumpTextFile(DEFAULT_FRAGMENT_SHADER_FILE); - bool shader_error = (!rgInitShaderProgram(&g_filled_hex_render_group, vs_code, fs_code) - || !rgInitShaderProgram(&g_hex_line_render_group, vs_code, LINE_FRAGMENT_SHADER_CODE) - || !rgInitShaderProgram(&g_debug_render_group, vs_code, DEBUG_FRAGMENT_SHADER_CODE)); + bool shader_error = !rgInitShaderProgram(g_default_shader, vs_code, fs_code); utilSafeFree(vs_code); utilSafeFree(fs_code); @@ -292,167 +175,102 @@ initRenderer(SDL_Handles &handles, v2i vpDims) if (shader_error) { LOG(ERROR) << "Error initializing shader program\n"; return false; - } else { - return true; } -#else - return true; -#endif -} -void -fillTriangleBufferFromHex(GLfloat buf[], int idx, const hex_info &hex) -{ - // triangles - for (int i = 0; i < 6; i++) - { - // vertex 0 - buf[idx + 0] = (GLfloat) hex.XPos; - buf[idx + 1] = (GLfloat) hex.YPos; - buf[idx + 2] = (GLfloat) 0.f; - - // vertex 1 - buf[idx + 3] = (GLfloat) hex.vertices[i].x; - buf[idx + 4] = (GLfloat) hex.vertices[i].y; - buf[idx + 5] = (GLfloat) 0.f; - - if (i == 5) // re-use the first point for the last triangle - { - // vertex 2 - buf[idx + 6] = (GLfloat) hex.vertices[0].x; - buf[idx + 7] = (GLfloat) hex.vertices[0].y; - buf[idx + 8] = (GLfloat) 0.f; - } - else - { - // vertex 2 - buf[idx + 6] = (GLfloat) hex.vertices[i + 1].x; - buf[idx + 7] = (GLfloat) hex.vertices[i + 1].y; - buf[idx + 8] = (GLfloat) 0.f; - } - - // we've added 9 GLfloats per loop - idx += 9; - } -} - -void -fillHexLineBuffer(GLfloat buf[], int len, std::vector* hexes) -{ - Point p1, p2; - int idx = 0; - for (int i = 0; i < (int) hexes->size(); i++) - { - hex_info hxi = (*hexes)[i]; - for (int j = 0; j < 6; j ++) - { - if (j == 5) // wrap - { - p1 = hxi.vertices[j]; - p2 = hxi.vertices[0]; - } - else - { - p1 = hxi.vertices[j]; - p2 = hxi.vertices[j + 1]; - } - - buf[idx + 0] = p1.x; - buf[idx + 1] = p1.y; - buf[idx + 2] = 0.f; - buf[idx + 3] = p2.x; - buf[idx + 4] = p2.y; - buf[idx + 5] = 0.f; - idx += 6; - } - } + return true; } bool -initHexGridBuffers(std::vector* hexes) +addTexture(SDL_Handles &handles, const char * path) { -#if 0 - // TODO: index duplicate vertices - // 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54 - uint vbuf_len = hexes->size() * 6 * 3 * 3; - uint line_vertices_per_hex = 6 * 2; // 12 vertices since we're using line segments atm - uint line_buf_len = hexes->size() * line_vertices_per_hex * 3; // 3 floats per vertex - - gl_buffer& vbuf = * rgInitGLBuffer(&g_filled_hex_render_group.vertex_buffer, vbuf_len); - gl_buffer& cbuf = * rgInitGLBuffer(&g_filled_hex_render_group.color_buffer, vbuf_len); - gl_buffer& normal_buf = * rgInitGLBuffer(&g_filled_hex_render_group.normal_buffer, vbuf_len); - gl_buffer& line_buf = * rgInitGLBuffer(&g_hex_line_render_group.vertex_buffer, line_buf_len); + // testing + LOG(INFO) << "Loading image: " << path << "\n"; + SDL_Surface* image = IMG_Load(path); - if (!vbuf.buffer || !cbuf.buffer || !line_buf.buffer || !normal_buf.buffer) + if (!image) + { + LOG(ERROR) << "IMG_Load: " << IMG_GetError() << "\n"; return false; + } - for (uint i = 0; i < hexes->size(); i++) - fillTriangleBufferFromHex(vbuf.buffer, 54 * i, (*hexes)[i]); - - rgSendBufferToGL(&vbuf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); + GLuint tex_id; + glGenTextures(1, &tex_id); + glBindTexture(GL_TEXTURE_2D, tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, 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); - // color data for hex vertices + // store opengl id in SDL_Surface.userdat + image->userdata = (void*)(intptr_t) tex_id; + handles.texSurfaces.push_back(image); - rgFillColorBuffer(cbuf.buffer, vbuf_len, hexes); - rgSendBufferToGL(&cbuf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); + return true; +} - // cheat at vertex normals since all hexes lay flat on z-axis - - for (uint i = 0; i < vbuf_len; i += 3) { - normal_buf.buffer[i] = 0; - normal_buf.buffer[i + 1] = 0; - normal_buf.buffer[i + 2] = 1; - } - rgSendBufferToGL(&normal_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); - g_filled_hex_render_group->use_normals = true; +v2f +getUnprojectedCoords(int32 x, int32 y, int32 vp_width, int32 vp_height) +{ + // NOTE: using depth buffer may not be as accurate as doing ray-cast + GLfloat depth; + glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + glm::vec4 viewport = glm::vec4(0, 0, vp_width, vp_height); + glm::vec3 wincoord = glm::vec3(x, y, depth); + glm::vec3 vU = glm::unProject(wincoord, g_scene_matrices.view, g_scene_matrices.projection, viewport); + v2f v(vU.x, vU.y); - // hex line vertex data + return v; +} - fillHexLineBuffer(line_buf.buffer, line_buf_len, hexes); - g_hex_line_render_group->vertex_buffer.buffer_len = line_buf_len; - rgSendBufferToGL(&line_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); - // TODO: add a color buffer to hex_line and debug render groups to re-use - // fragment shaders and simplify draw rgDraw() -#endif - return true; +v3f +getCameraPosition() +{ + return v3f(g_camera.position.x, g_camera.position.y, g_camera.position.z); } bool createScene(std::vector* hexes, Entity* entities, uint32 entity_count) { + // entities + + for (uint i = 0; i < entity_count; i++) { + rgInitEntity(&entities[i]); + entities[i].ren_group->shader = g_default_shader; + } + initMatrices(PROJ_TYPE); if (!initHexGridBuffers(hexes)) return false; // debug draw vertices -#if 0 - rgInitGLBuffer(&g_debug_render_group->vertex_buffer, 4 * 3); // 4 vertices * 3 floats per vertex - if (!g_debug_render_group->vertex_buffer.buffer) - return false; + uint debug_buf_len = 12; // 4 vertices, 3 floats per vertex + g_debug_render_group = rgInitSingle(g_default_shader, debug_buf_len, true, 0, GL_LINE_LOOP); - rgSendBufferToGL(&g_debug_render_group->vertex_buffer, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); -#endif - // entities + if (g_debug_render_group == nullptr) + return false; - const char* vs_code = utilDumpTextFile(DEFAULT_VERTEX_SHADER_FILE); - const char* fs_code = utilDumpTextFile(DEFAULT_FRAGMENT_SHADER_FILE); - rg_shader_program sp; + gl_buffer& debug_vertex_buf = g_debug_render_group->render_objects[0]->vertex_buffer; + gl_buffer& debug_color_buf = g_debug_render_group->render_objects[0]->color_buffer; + gl_buffer& debug_normal_buf = g_debug_render_group->render_objects[0]->normal_buffer; - bool shader_errors = !rgInitShaderProgram(sp, vs_code, fs_code); - utilSafeFree(vs_code); - utilSafeFree(fs_code); + for (uint i = 0; i < debug_buf_len; i += 3) { + debug_color_buf.buffer[i] = 1.f; + debug_color_buf.buffer[i + 1] = 0.f; + debug_color_buf.buffer[i + 2] = 0.f; - if (shader_errors) - return false; - - for (uint i = 0; i < entity_count; i++) { - rgInitEntity(&entities[i]); - entities[i].ren_group->shader = sp; + debug_normal_buf.buffer[i] = 0.f; + debug_normal_buf.buffer[i + 1] = 0.f; + debug_normal_buf.buffer[i + 2] = 1.f; } + rgBufferData(&debug_vertex_buf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); + rgBufferData(&debug_color_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + rgBufferData(&debug_normal_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + // lights + // TODO: load light properties from scene/level files //g_test_light.light_ID = glGetUniformLocation(g_entity_render_group.program_id, "light_position"); @@ -558,49 +376,41 @@ renderFrame(std::vector *hexes, Entity* entities, uint32 entity_count) glClearColor(g_clear_col.R, g_clear_col.G, g_clear_col.B, g_clear_col.A); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - //glm::mat4 m_model = g_scene_matrices.model; + glm::mat4 m_model = g_scene_matrices.model; glm::mat4 m_view = g_scene_matrices.view; glm::mat4 m_projection = g_scene_matrices.projection; // filled hexes -#if 0 // get new colors every frame - gl_render_group* rg = g_filled_hex_render_group; - rgFillColorBuffer(rg->color_buffer.buffer, rg->color_buffer.buffer_len, hexes); - rgDraw(rg, GL_TRIANGLES, m_model, m_view, m_projection, + render_group* rg = g_filled_hex_render_group; + gl_buffer& color_buf = rg->render_objects[0]->color_buffer; + fillColorBuffer(color_buf.buffer, color_buf.buffer_len, hexes); + rgDraw(rg, m_model, m_view, m_projection, g_test_light.position, g_test_light.light_ID); // hex lines - - rgDraw(g_hex_line_render_group, GL_LINES, m_model, m_view, m_projection, - g_test_light.position, g_test_light.light_ID); -#endif + rgDraw(g_hex_line_render_group, m_model, m_view, m_projection, + g_test_light.position, g_test_light.light_ID); // entities for (uint i = 0; i < entity_count; i++) { - rgDraw( - entities[i].ren_group, entities[i].world_transform , m_view, m_projection, - g_test_light.position, g_test_light.light_ID - ); + rgDraw(entities[i].ren_group, entities[i].world_transform , m_view, m_projection, + g_test_light.position, g_test_light.light_ID); } } void renderDebug(std::vector &vertices) { -#if 0 - // TODO: indexed line drawing - // copy vertices to render group - GLfloat* buf = g_debug_render_group->vertex_buffer.buffer; + GLfloat* buf = g_debug_render_group->render_objects[0]->vertex_buffer.buffer; buf[0] = vertices[0].x; buf[1] = vertices[0].y; buf[2] = 0; buf[3] = vertices[1].x; buf[4] = vertices[1].y; buf[2] = 0; buf[6] = vertices[2].x; buf[7] = vertices[2].y; buf[8] = 0; buf[9] = vertices[3].x; buf[10] = vertices[3].y; buf[11] = 0; - rgDraw(g_debug_render_group, GL_LINE_LOOP, g_scene_matrices.model, g_scene_matrices.view, + rgDraw(g_debug_render_group, g_scene_matrices.model, g_scene_matrices.view, g_scene_matrices.projection, g_test_light.position, g_test_light.light_ID, true); -#endif } void @@ -616,3 +426,231 @@ freeBuffers() rgFree(group); } + +// internal + +void +initMatrices(projection_type p) +{ + // TODO: many constants used here should be passed as args + + if (p == PERSPECTIVE) + { + g_scene_matrices.projection = glm::infinitePerspective( + glm::radians(60.f), // FoV + 16.f / 9.f, // ascpect ratio + 0.1f // near clip plane + ); + + g_camera.position = glm::vec3(640,0,100); + g_camera.target = glm::vec3(640,500,0); + //g_camera.target = glm::vec3(0,0,0); + // inital rotation should match target direction + glm::vec3 &p = g_camera.position; + glm::vec3 &t = g_camera.target; + g_camera.hAngle = 0; + g_camera.vAngle = glm::atan((t.z - p.z) / (t.y - p.y)); + + ////// + // TODO: add call to rotate camera here to remove duplicate code + camera &c = g_camera; + float &h = c.hAngle; + float &v = c.vAngle; + c.forward = glm::vec3( + glm::cos(v) * glm::sin(h), + glm::cos(v) * glm::cos(h), + glm::sin(v) + ); + + glm::normalize(c.forward); + ////// + + g_camera.up = glm::vec3(0,1,0); + g_camera.left = glm::normalize(glm::cross(g_camera.up, g_camera.forward)); + g_camera.up = glm::normalize(glm::cross(g_camera.forward, g_camera.left)); + + g_scene_matrices.view = glm::lookAt( + g_camera.position, // camera position + g_camera.position + g_camera.forward, + g_camera.up // "up" vector + ); + } + else // ORTHO + { + // left, right, bottom, top, zNear, zFar + g_scene_matrices.projection = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f); + g_scene_matrices.view = glm::lookAt( + glm::vec3(0.0f, 0.0f, 1.0f), // camera position + glm::vec3(0.0f, 0.0f, 0.0f), // look at position + glm::vec3(0,1,0) // "up" vector + ); + } + + g_scene_matrices.model = glm::mat4(1.0f); + g_scene_matrices.MVP = g_scene_matrices.projection * g_scene_matrices.view * g_scene_matrices.model; +} + +void +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) + << (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "") + << ", type: " << type + << ", severity: " << severity + << ", message: " << message << "\n"; +} + +bool +initHexGridBuffers(std::vector* hexes) +{ + // TODO: index duplicate vertices + // 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54 + uint line_vertices_per_hex = 6 * 2; // 12 vertices since we're using line segments atm + uint line_buf_len = hexes->size() * line_vertices_per_hex * 3; // 3 floats per vertex + uint vbuf_len = hexes->size() * 6 * 3 * 3; + + g_filled_hex_render_group = rgInitSingle(g_default_shader, vbuf_len, true); + + if (g_filled_hex_render_group == nullptr) + return false; + + gl_buffer& vbuf = g_filled_hex_render_group->render_objects[0]->vertex_buffer; + gl_buffer& cbuf = g_filled_hex_render_group->render_objects[0]->color_buffer; + gl_buffer& normal_buf = g_filled_hex_render_group->render_objects[0]->normal_buffer; + + for (uint i = 0; i < hexes->size(); i++) + fillTriangleBufferFromHex(vbuf.buffer, i * 54, (*hexes)[i]); + + rgBufferData(&vbuf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); + fillColorBuffer(cbuf.buffer, vbuf_len, hexes); + rgBufferData(&cbuf, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER); + + // cheat at vertex normals since all hexes lay flat on z-axis + + for (uint i = 0; i < vbuf_len; i += 3) { + normal_buf.buffer[i] = 0.f; + normal_buf.buffer[i + 1] = 0.f; + normal_buf.buffer[i + 2] = 1.f; + } + rgBufferData(&normal_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + + // hex lines + + g_hex_line_render_group = rgInitSingle(g_default_shader, line_buf_len, true, 0, GL_LINES); + + if (g_hex_line_render_group == nullptr) + return false; + + gl_buffer& line_buf = g_hex_line_render_group->render_objects[0]->vertex_buffer; + gl_buffer& line_color_buf = g_hex_line_render_group->render_objects[0]->color_buffer; + gl_buffer& line_normal_buf = g_hex_line_render_group->render_objects[0]->normal_buffer; + fillHexLineBuffer(line_buf.buffer, line_buf_len, hexes); + rgBufferData(&line_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + + for (uint i = 0; i < line_buf_len; i++) + line_color_buf.buffer[i] = 0.f; + + rgBufferData(&line_color_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + + for (uint i = 0; i < line_buf_len; i += 3) { + line_normal_buf.buffer[i] = 0.f; + line_normal_buf.buffer[i + 1] = 0.f; + line_normal_buf.buffer[i + 2] = 1.f; + } + + rgBufferData(&line_normal_buf, GL_STATIC_DRAW, GL_ARRAY_BUFFER); + + return true; +} + +void +fillTriangleBufferFromHex(GLfloat buf[], int idx, const hex_info &hex) +{ + // triangles + for (int i = 0; i < 6; i++) + { + // vertex 0 + buf[idx + 0] = (GLfloat) hex.XPos; + buf[idx + 1] = (GLfloat) hex.YPos; + buf[idx + 2] = (GLfloat) 0.f; + + // vertex 1 + buf[idx + 3] = (GLfloat) hex.vertices[i].x; + buf[idx + 4] = (GLfloat) hex.vertices[i].y; + buf[idx + 5] = (GLfloat) 0.f; + + if (i == 5) // re-use the first point for the last triangle + { + // vertex 2 + buf[idx + 6] = (GLfloat) hex.vertices[0].x; + buf[idx + 7] = (GLfloat) hex.vertices[0].y; + buf[idx + 8] = (GLfloat) 0.f; + } + else + { + // vertex 2 + buf[idx + 6] = (GLfloat) hex.vertices[i + 1].x; + buf[idx + 7] = (GLfloat) hex.vertices[i + 1].y; + buf[idx + 8] = (GLfloat) 0.f; + } + + // we've added 9 GLfloats per loop + idx += 9; + } +} + +void +fillColorBuffer(GLfloat buf[], int len, std::vector* 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]; + // TODO: check performance of this since we call multiple times per frame + // maybe can cache glfloat triplets somewhere + utilConvertColor(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]; + } + } +} + +void +fillHexLineBuffer(GLfloat buf[], int len, std::vector* hexes) +{ + Point p1, p2; + int idx = 0; + for (int i = 0; i < (int) hexes->size(); i++) + { + hex_info hxi = (*hexes)[i]; + for (int j = 0; j < 6; j ++) + { + if (j == 5) // wrap + { + p1 = hxi.vertices[j]; + p2 = hxi.vertices[0]; + } + else + { + p1 = hxi.vertices[j]; + p2 = hxi.vertices[j + 1]; + } + + buf[idx + 0] = p1.x; + buf[idx + 1] = p1.y; + buf[idx + 2] = 0.f; + buf[idx + 3] = p2.x; + buf[idx + 4] = p2.y; + buf[idx + 5] = 0.f; + idx += 6; + } + } +} diff --git a/src/util.cpp b/src/util.cpp index 27c8fb0..b86d4ce 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,4 +1,5 @@ +#include #include #include @@ -41,6 +42,8 @@ utilLogAlloc(uint item_count, uint type_size, const char* file_name, const int l << file_name << ":" << line; } + assert(mem != nullptr); // might as well stop execution here + return mem; }