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];
}