From d7eb8ae28d420af8571e40e452524de251f7e212 Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Thu, 10 Jan 2019 16:14:07 -0500 Subject: [PATCH] update hexgrid and functions to store hexes in hashtable --- TODO.md | 2 ++ data/level.2.dae | 4 +-- src/gooey.cpp | 1 + src/hexgame.cpp | 7 ++-- src/hexgrid.cpp | 82 +++++++++++++++++++------------------------- src/hexgrid.h | 40 +++++++++++++-------- src/hexlib.h | 4 +++ src/scene_loader.cpp | 41 ++++++++++------------ 8 files changed, 92 insertions(+), 89 deletions(-) diff --git a/TODO.md b/TODO.md index afd6937..4f4429b 100644 --- a/TODO.md +++ b/TODO.md @@ -42,7 +42,9 @@ - move from COLLADA output to glTF (GL Transmission Format) https://www.khronos.org/gltf/ - add config.js/yaml for application config (remove some defines everywhere) - maybe try deferred rendering at some point to use a ton of lights +- use assimp material info in shaders for fancier lighting - add cpu performance counters in render loop + - hgUpdateUV buffer can probably be improved by adding selected hexes to a small cache structure - check for memory leaks w/ valgrind ## DONE: diff --git a/data/level.2.dae b/data/level.2.dae index 2cd4c3f..554dd55 100644 --- a/data/level.2.dae +++ b/data/level.2.dae @@ -12,7 +12,7 @@ - /home/doug/dev/blender.projects/palette.png + palette.png @@ -109,4 +109,4 @@ - \ No newline at end of file + diff --git a/src/gooey.cpp b/src/gooey.cpp index e65097f..355356a 100644 --- a/src/gooey.cpp +++ b/src/gooey.cpp @@ -151,6 +151,7 @@ renderHexgridWindow(hexgrid& grid, ImGuiWindowFlags window_flags) ImGui::Separator(); ImGui::Text("is_selecting"); ImGui::SameLine(); ImGui::TextUnformatted(grid.is_selecting ? "true" : "false"); + ImGui::Text("Hex Count: %lu", grid.hex_map.size()); ImGui::Text("current_hex: "); if (grid.current_hex) { diff --git a/src/hexgame.cpp b/src/hexgame.cpp index 0784cd0..5115a44 100644 --- a/src/hexgame.cpp +++ b/src/hexgame.cpp @@ -86,8 +86,10 @@ init() { // init global game state g_game_state = UTIL_ALLOC(1, game_state); - g_game_state->grid.hex_array = new vector; g_game_state->entities = UTIL_ALLOC(MAX_ENTITIES, Entity); + // TODO: I think this is necessary because we're using calloc to initialize gamestate + // which contains the hashtable. + g_game_state->grid.hex_map = std::unordered_map(); // init global render state g_render_state = UTIL_ALLOC(1, render_state); @@ -330,9 +332,6 @@ cleanUp(SDL_Handles &handles) game_state* gs = g_game_state; - if (g_game_state->grid.hex_array) - delete g_game_state->grid.hex_array; - for (uint i = 0; i < gs->entity_count; i++) { meFreeMeshGroup(gs->entities[i].mesh_group); rgFree(gs->entities[i].ren_group); diff --git a/src/hexgrid.cpp b/src/hexgrid.cpp index 34a27f6..12a60d6 100644 --- a/src/hexgrid.cpp +++ b/src/hexgrid.cpp @@ -5,7 +5,7 @@ // forward declarations -bool createHexagonGrid(hexgrid hg); +bool createHexagonGrid(hexgrid& hg); // interface @@ -29,10 +29,10 @@ hgGetSingleHex(hexgrid& hg, real32 x, real32 y) Point p(x, y); Hex h = hex_round(pixel_to_hex(hg.hexlib_layout, p)); - for (hex_info &hxi : *hg.hex_array) { - if (hex_equal(h, hxi.hex)) - return &hxi; - } + auto it = hg.hex_map.find(h); + + if (it != hg.hex_map.end()) + return &it->second; return nullptr; } @@ -40,11 +40,10 @@ hgGetSingleHex(hexgrid& hg, real32 x, real32 y) void hgResetHexes(hexgrid& hg) { - hg.start_hex = hg.current_hex = 0; + hg.start_hex = hg.current_hex = nullptr; - for (hex_info &hxi : *hg.hex_array) { - hxi.selected = false; - } + for (auto& it : hg.hex_map) + it.second.selected = false; } void @@ -56,12 +55,11 @@ hgUpdateHexFill(hexgrid& hg, int32 x, int32 y) hg.current_hex = hxi; int l = hex_distance(hg.start_hex->hex, hg.current_hex->hex); - for (hex_info &h : *hg.hex_array) - { - if (hex_distance(hg.start_hex->hex, h.hex) <= l) - h.selected = true; + for (auto& it: hg.hex_map) { + if (hex_distance(hg.start_hex->hex, it.second.hex) <= l) + it.second.selected = true; else - h.selected = false; + it.second.selected = false; } } } @@ -72,24 +70,18 @@ hgUpdateHexLineDraw(hexgrid& hg, int32 x, int32 y) hex_info *hxi = hgGetSingleHex(hg, x, y); if (hxi && (hxi != hg.current_hex) && hg.start_hex) { + // TODO: can avoid this loop by caching selected hexes + for (auto& it : hg.hex_map) + it.second.selected = false; + hg.current_hex = hxi; vector hexLine = hex_linedraw(hg.start_hex->hex, hxi->hex); - for (hex_info &h1 : *hg.hex_array) - { - for (uint i = 0; i < hexLine.size(); i++) - { - Hex h2 = hexLine[i]; - if (hex_equal(h1.hex, h2)) - { - h1.selected = true; - break; - } - else if (i == hexLine.size() - 1) - { - h1.selected = false; - } - } + for (Hex h : hexLine) { + auto it = hg.hex_map.find(h); + + if (it != hg.hex_map.end()) + it->second.selected = true; } } } @@ -123,8 +115,9 @@ hgUpdateHexConeFill(hexgrid& hg, int32 x, int32 y, float cone_angle, std::vector Point vert4 = Point(topX, topY); std::vector vertices = {p1, vert2, p2, vert4}; - for (hex_info &h : *hg.hex_array) - { + for (auto& it : hg.hex_map) { + hex_info& h = it.second; + test_p.x = h.XPos; test_p.y = h.YPos; @@ -146,12 +139,13 @@ hgUpdateUVBuffer(hexgrid& hg, float* uv_buffer, uint buf_len) { // NOTE: 6 triangles * 3 vertices * 3 floats (not 2 to stay aligned with vbuffer) uint buf_len_per_hex = 54; - assert(buf_len == hg.hex_array->size() * buf_len_per_hex); - for (uint i = 0; i < hg.hex_array->size(); i++) { - hex_info hxi = (*hg.hex_array)[i]; + assert(buf_len == hg.hex_map.size() * buf_len_per_hex); + + for (auto& it : hg.hex_map) { + hex_info hxi = it.second; v2f uv_coords = (hxi.selected) ? hg.selected_fill_color_uv : hg.fill_color_uv; - uint buf_idx = i * buf_len_per_hex; + uint buf_idx = hxi.hexID * buf_len_per_hex; for (uint j = 0; j < buf_len_per_hex; j +=3) { uv_buffer[buf_idx + j + 0] = uv_coords.x; @@ -164,25 +158,19 @@ hgUpdateUVBuffer(hexgrid& hg, float* uv_buffer, uint buf_len) // internal bool -createHexagonGrid(hexgrid hg) +createHexagonGrid(hexgrid& hg) { - if (hg.hex_array == nullptr) { - LOG(ERROR) << "hg.hex_array is not initialized\n"; - return false; - } - int hr = hg.hex_radius; int nhr = hg.hex_radius * -1; - for (int q = nhr; q <= hr; q++) - { + for (int q = nhr; q <= hr; q++) { int r1 = std::max(nhr, -q - hr); int r2 = std::min(hr, -q + hr); - for (int r = r1; r <= r2; r++) - { + for (int r = r1; r <= r2; r++) { hex_info hxi; - hxi.hexID = (int32) hg.hex_array->size(); + hxi.hexID = (int32) hg.hex_map.size(); + hxi.selected = false; hxi.hex.q = q; hxi.hex.r = r; hxi.hex.s = -q-r; Point p = hex_to_pixel(hg.hexlib_layout, hxi.hex); hxi.XPos = p.x; @@ -194,7 +182,7 @@ createHexagonGrid(hexgrid hg) if ((q > -2 && q < 2) && (r > -2 && r < 2)) { // skip } else { - hg.hex_array->push_back(hxi); + hg.hex_map.insert({hxi.hex, hxi}); } ///////////// } diff --git a/src/hexgrid.h b/src/hexgrid.h index 59ed4be..9a08a89 100644 --- a/src/hexgrid.h +++ b/src/hexgrid.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include "hexlib.h" #include "render_group.h" @@ -29,33 +30,44 @@ enum grid_type struct hex_info { - int32 hexID = 0; + uint hexID; Hex hex = {}; - real64 XPos = 0; - real64 YPos = 0; - bool selected = false; + real64 XPos; + real64 YPos; + bool selected; std::vector vertices; }; +struct hex_hashfunc +{ + // NOTE: hash_combine from boost + size_t operator()(const Hex& h) const { + std::hash int_hash; + size_t hq = int_hash(h.q); + size_t hr = int_hash(h.r); + return hq ^ (hr + 0x9e3779b9 + (hq << 6) + (hq >> 2)); + } +}; + struct hexgrid { - grid_type gridT = HEXAGON; + grid_type gridT; Layout hexlib_layout; Orientation hexlib_orientation; - v3f position = v3f(0, 0, 0); - uint hex_size = 10; - uint hex_radius = 0; + v3f position; + uint hex_size; + uint hex_radius; v2f fill_color_uv; v2f selected_fill_color_uv; v2f line_color_uv; - std::vector* hex_array = nullptr; - hex_info* start_hex = nullptr; - hex_info* current_hex = nullptr; - vector selected_hexes; - HexDrawMode draw_mode = CONE_FILL; - bool is_selecting = false; + std::unordered_map hex_map; + + hex_info* start_hex; + hex_info* current_hex; + HexDrawMode draw_mode; + bool is_selecting; }; bool hgCreateHexes(hexgrid& hg); diff --git a/src/hexlib.h b/src/hexlib.h index 0c977aa..75c7807 100644 --- a/src/hexlib.h +++ b/src/hexlib.h @@ -32,6 +32,10 @@ struct Hex int s; Hex(int q_, int r_, int s_): q(q_), r(r_), s(s_) {} Hex(): q(0), r(0), s(0) {} + + bool operator==(const Hex& h) const { + return (h.q == q && h.r == r && h.s == s); + } }; struct Orientation diff --git a/src/scene_loader.cpp b/src/scene_loader.cpp index 15462c4..4e9f39f 100644 --- a/src/scene_loader.cpp +++ b/src/scene_loader.cpp @@ -151,11 +151,11 @@ bool slCreateHexRenderGroups(hexgrid& hg, render_state* rs) { // NOTE: 6 triangles * 3 vertices per triangle * 3 floats per vertex - uint buf_len = hg.hex_array->size() * 6 * 3 * 3; + uint buf_len = hg.hex_map.size() * 6 * 3 * 3; rs->filled_hex_render_group = rgInitSingle(rs->default_shader, buf_len, true); // NOTE: 6 lines * 2 vertices per line * 3 floats per vertex - buf_len = hg.hex_array->size() * 6 * 2 * 3; + buf_len = hg.hex_map.size() * 6 * 2 * 3; rs->hex_line_render_group = rgInitSingle(rs->default_shader, buf_len, true, 0, GL_LINES); render_group* rg_filled = rs->filled_hex_render_group; @@ -282,6 +282,8 @@ parseVec4(const rapidjson::Value& node) return v4; } +// TODO: these should probably move to hexgrid.cpp, and pass in each raw buffer +// to avoid render_group dependancy void populateFilledHexGLBuffers(hexgrid& hg, render_group* rg_filled) { @@ -290,7 +292,7 @@ populateFilledHexGLBuffers(hexgrid& hg, render_group* rg_filled) gl_buffer& normal_buf = ro->normal_buffer; gl_buffer& uv_buf = ro->uv_buffer; - assert((hg.hex_array->size() * 6 * 3 * 3) == vbuf.buffer_len); + assert((hg.hex_map.size() * 6 * 3 * 3) == vbuf.buffer_len); // fill uv_buffer with palette texture coords hgUpdateUVBuffer(hg, uv_buf.buffer, uv_buf.buffer_len); @@ -304,10 +306,10 @@ populateFilledHexGLBuffers(hexgrid& hg, render_group* rg_filled) GLfloat* buf = vbuf.buffer; - for (uint i = 0; i < hg.hex_array->size(); i++) { + for (auto& it : hg.hex_map) { - hex_info hex = (*hg.hex_array)[i]; - uint idx = i * 54; // NOTE: 6 triangles * 3 vertices * 3 floats + hex_info hex = it.second; + uint idx = hex.hexID * 54; // NOTE: 6 triangles * 3 vertices * 3 floats // triangles for (uint j = 0; j < 6; j++) { @@ -322,15 +324,12 @@ populateFilledHexGLBuffers(hexgrid& hg, render_group* rg_filled) buf[idx + 4] = (GLfloat) hex.vertices[j].y; buf[idx + 5] = (GLfloat) 0.f; - if (j == 5) // re-use the first point for the last triangle - { + if (j == 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 - { + } else { // vertex 2 buf[idx + 6] = (GLfloat) hex.vertices[j + 1].x; buf[idx + 7] = (GLfloat) hex.vertices[j + 1].y; @@ -350,7 +349,7 @@ populateLineGLBuffers(hexgrid& hg, render_group* rg_lines) gl_buffer& normal_buf = ro->normal_buffer; gl_buffer& uv_buf = ro->uv_buffer; - assert((hg.hex_array->size() * 6 * 2 * 3) == vbuf.buffer_len); + assert((hg.hex_map.size() * 6 * 2 * 3) == vbuf.buffer_len); // cheat at vertex normals since all hexes lay flat on z-axis for (uint i = 0; i < normal_buf.buffer_len; i += 3) { @@ -367,19 +366,17 @@ populateLineGLBuffers(hexgrid& hg, render_group* rg_lines) } Point p1, p2; + // NOTE: these buffers won't be correctly indexed with hashtable, but that doesn't really + // matter for the lines, since they don't change color int idx = 0; - for (int i = 0; i < (int) hg.hex_array->size(); i++) - { - hex_info hxi = (*hg.hex_array)[i]; - for (int j = 0; j < 6; j ++) - { - if (j == 5) // wrap - { + for (auto it : hg.hex_map) { + hex_info hxi = it.second; + + for (int j = 0; j < 6; j ++) { + if (j == 5) { // wrap p1 = hxi.vertices[j]; p2 = hxi.vertices[0]; - } - else - { + } else { p1 = hxi.vertices[j]; p2 = hxi.vertices[j + 1]; }