penguins  1.0.0
canvas.cc
Go to the documentation of this file.
1 #include "gui/canvas.hh"
2 #include "board.h"
3 #include "game.h"
4 #include "gui/controllers.hh"
5 #include "gui/game.hh"
6 #include "gui/game_state.hh"
7 #include "gui/main.hh"
8 #include "gui/tileset.hh"
9 #include "utils.h"
10 #include <cassert>
11 #include <cstdint>
12 #include <memory>
13 #include <wx/bitmap.h>
14 #include <wx/colour.h>
15 #include <wx/dc.h>
16 #include <wx/dcclient.h>
17 #include <wx/dcmemory.h>
18 #include <wx/defs.h>
19 #include <wx/event.h>
20 #include <wx/gdicmn.h>
21 #include <wx/geometry.h>
22 #include <wx/pen.h>
23 #include <wx/region.h>
24 #include <wx/window.h>
25 
26 // clang-format off
28  EVT_PAINT(CanvasPanel::on_paint)
29  EVT_MOUSE_EVENTS(CanvasPanel::on_any_mouse_event)
31 // clang-format on
32 
34 : wxWindow(parent, id), panel(panel), game(panel->game.get()) {
35  this->SetInitialSize(this->get_canvas_size());
36 #ifdef __WXMSW__
37  // Necessary to avoid flicker on Windows, see <https://wiki.wxwidgets.org/Flicker-Free_Drawing>.
38  this->SetDoubleBuffered(true);
39 #endif
40 }
41 
44 }
45 
47  return { point.x / TILE_SIZE, point.y / TILE_SIZE };
48 }
49 
51  return wxRect(coords.x * TILE_SIZE, coords.y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
52 }
53 
55  wxRect rect = this->get_tile_rect(coords);
56  return rect.GetPosition() + rect.GetSize() / 2;
57 }
58 
60  Coords null_coords = { -1, -1 };
61  if (!this->mouse_within_window) return null_coords;
62  wxPoint curr_tile_pos = this->mouse_is_down ? this->mouse_drag_pos : this->mouse_pos;
63  Coords curr_coords = this->tile_coords_at_point(curr_tile_pos);
64  if (!is_tile_in_bounds(game, curr_coords)) return null_coords;
65  int player_idx = game->current_player_index;
66  if (!game_check_player_index(game, player_idx)) return null_coords;
67  short player_id = game_get_player(game, player_idx)->id;
68  short tile = get_tile(game, curr_coords);
69  return get_tile_player_id(tile) == player_id ? curr_coords : null_coords;
70 }
71 
72 void CanvasPanel::on_paint(wxPaintEvent& WXUNUSED(event)) {
73  wxPaintDC window_dc(this);
74 
75  wxSize size = this->get_canvas_size();
76  if (!(size.x > 0 && size.y > 0)) {
77  this->board_bitmap.UnRef();
78  this->tiles_bitmap.UnRef();
79  return;
80  }
81 
82  wxRect update_region = GetUpdateRegion().GetBox();
83 
84  GameController* controller = this->panel->controller;
85  if (controller) controller->update_tile_attributes();
86 
87  for (int y = 0; y < game->board_height; y++) {
88  for (int x = 0; x < game->board_width; x++) {
89  Coords coords = { x, y };
90 
91  if (get_tile_attr(game, coords, TILE_DIRTY)) {
92  set_tile_attr(game, coords, TILE_DIRTY, false);
93  set_tile_attr(game, coords, TILE_NEEDS_REDRAW, true);
94  // Request repainting of the neighboring tiles too.
95  for (int dir = 0; dir < NEIGHBOR_MAX; dir++) {
96  Coords neighbor = NEIGHBOR_TO_COORDS[dir];
97  neighbor.x += coords.x, neighbor.y += coords.y;
98  if (!is_tile_in_bounds(game, neighbor)) continue;
99  set_tile_attr(game, neighbor, TILE_NEEDS_REDRAW, true);
100  }
101  }
102 
103  bool was_blocked = get_tile_attr(game, coords, TILE_WAS_BLOCKED);
104  bool is_blocked = get_tile_attr(game, coords, TILE_BLOCKED);
105  if (is_blocked != was_blocked) {
107  }
108  set_tile_attr(game, coords, TILE_WAS_BLOCKED, is_blocked);
109  }
110  }
111 
112  if (!this->tiles_bitmap.IsOk() || this->tiles_bitmap.GetSize() != size) {
113  this->tiles_bitmap.Create(size, 24);
114  }
115  if (!this->board_bitmap.IsOk() || this->board_bitmap.GetSize() != size) {
116  this->board_bitmap.Create(size, 24);
117  }
118  this->tiles_dc.SelectObject(this->tiles_bitmap);
119  this->paint_tiles(this->tiles_dc, update_region);
120  this->board_dc.SelectObject(this->board_bitmap);
121  this->paint_board(this->board_dc, update_region, this->tiles_dc);
122 
123  wxPoint update_pos = update_region.GetPosition();
124  window_dc.Blit(update_pos, update_region.GetSize(), &this->board_dc, update_pos);
127 
128  if (controller) controller->paint_overlay(window_dc);
129 }
130 
131 void CanvasPanel::draw_bitmap(wxDC& dc, const wxBitmap& bitmap, const wxPoint& pos) {
132 #ifdef __WXMSW__
133  // This works faster on Windows:
134  wxMemoryDC& bmp_dc = this->draw_bitmap_dc;
135  bmp_dc.SelectObjectAsSource(bitmap);
136  dc.Blit(pos, bmp_dc.GetSize(), &bmp_dc, wxPoint(0, 0), wxCOPY);
137 #else
138  dc.DrawBitmap(bitmap, pos);
139 #endif
140 }
141 
142 void CanvasPanel::paint_tiles(wxDC& dc, const wxRect& update_region) {
143  auto& tileset = wxGetApp().tileset;
144 
145  for (int y = 0; y < game->board_height; y++) {
146  for (int x = 0; x < game->board_width; x++) {
147  Coords coords = { x, y };
148  if (!get_tile_attr(game, coords, TILE_NEEDS_REDRAW)) continue;
149  wxRect tile_rect = this->get_tile_rect(coords);
150  if (!update_region.Intersects(tile_rect)) continue;
151  set_tile_attr(game, coords, TILE_NEEDS_REDRAW, false);
152  // The next layer of the board has to be repainted as well.
154 
155  short tile = get_tile(game, coords);
156  wxPoint tile_pos = tile_rect.GetPosition();
157 
158  uint32_t coords_hash = fnv32_hash(FNV32_INITIAL_STATE, &coords, sizeof(coords));
159 
160  if (is_water_tile(tile)) {
161  this->draw_bitmap(
162  dc, tileset.water_tiles[coords_hash % WXSIZEOF(tileset.water_tiles)], tile_pos
163  );
164  continue;
165  }
166 
167  this->draw_bitmap(
168  dc, tileset.ice_tiles[coords_hash % WXSIZEOF(tileset.ice_tiles)], tile_pos
169  );
170 
171  auto check_water = [&](int dx, int dy) -> bool {
172  Coords neighbor = { coords.x + dx, coords.y + dy };
173  return is_tile_in_bounds(game, neighbor) && is_water_tile(get_tile(game, neighbor));
174  };
175 
176  auto draw_edge = [&](int dx, int dy, TileEdge type) {
177  if (check_water(dx, dy)) {
178  this->draw_bitmap(dc, tileset.tile_edges[type], tile_pos);
179  }
180  };
181  draw_edge(0, -1, EDGE_TOP);
182  draw_edge(1, 0, EDGE_RIGHT);
183  draw_edge(0, 1, EDGE_BOTTOM);
184  draw_edge(-1, 0, EDGE_LEFT);
185 
186  auto draw_concave_corner = [&](int dx, int dy, TileCorner type) -> void {
187  if (check_water(dx, dy) && !check_water(dx, 0) && !check_water(0, dy)) {
188  this->draw_bitmap(dc, tileset.tile_concave_corners[type], tile_pos);
189  }
190  };
191  draw_concave_corner(1, -1, CORNER_TOP_RIGHT);
192  draw_concave_corner(1, 1, CORNER_BOTTOM_RIGHT);
193  draw_concave_corner(-1, 1, CORNER_BOTTOM_LEFT);
194  draw_concave_corner(-1, -1, CORNER_TOP_LEFT);
195 
196  auto draw_convex_corner = [&](int dx, int dy, TileCorner type) -> void {
197  if (check_water(dx, 0) && check_water(0, dy)) {
198  this->draw_bitmap(dc, tileset.tile_convex_corners[type], tile_pos);
199  }
200  };
201  draw_convex_corner(1, -1, CORNER_TOP_RIGHT);
202  draw_convex_corner(1, 1, CORNER_BOTTOM_RIGHT);
203  draw_convex_corner(-1, 1, CORNER_BOTTOM_LEFT);
204  draw_convex_corner(-1, -1, CORNER_TOP_LEFT);
205 
206  if (is_fish_tile(tile)) {
207  short fish = get_tile_fish(tile);
208  this->draw_bitmap(
209  dc, tileset.fish_sprites[(fish - 1) % WXSIZEOF(tileset.fish_sprites)], tile_pos
210  );
211  }
212  }
213  }
214 }
215 
216 void CanvasPanel::paint_board(wxDC& dc, const wxRect& update_region, wxDC& tiles_dc) {
217  auto& tileset = wxGetApp().tileset;
218 
219  Coords mouse_coords = this->tile_coords_at_point(this->mouse_pos);
220 
221  bool is_penguin_selected = false;
222  Coords selected_penguin = { -1, -1 };
223  if (game->phase == GAME_PHASE_MOVEMENT) {
224  selected_penguin = this->get_selected_penguin_coords();
225  is_penguin_selected = is_tile_in_bounds(game, selected_penguin);
226  }
227 
228  for (int y = 0; y < game->board_height; y++) {
229  for (int x = 0; x < game->board_width; x++) {
230  Coords coords = { x, y };
231  if (!get_tile_attr(game, coords, TILE_OVERLAY_NEEDS_REDRAW)) continue;
232  wxRect tile_rect = this->get_tile_rect(coords);
233  if (!update_region.Intersects(tile_rect)) continue;
235 
236  short tile = get_tile(game, coords);
237  wxPoint tile_pos = tile_rect.GetPosition();
238  dc.Blit(tile_pos, tile_rect.GetSize(), &tiles_dc, tile_pos);
239 
240  if (get_tile_attr(game, coords, TILE_BLOCKED)) {
241  this->draw_bitmap(dc, tileset.blocked_tile, tile_pos);
242  }
243 
244  if (is_penguin_tile(tile)) {
245  int player = game_find_player_by_id(game, get_tile_player_id(tile));
246  assert(player >= 0);
247  bool flipped = false;
248  if (is_penguin_selected && coords_same(coords, selected_penguin)) {
249  flipped = mouse_coords.x < selected_penguin.x;
250  }
251  wxBitmap* penguin_sprites =
252  flipped ? tileset.penguin_sprites_flipped : tileset.penguin_sprites;
253  this->draw_bitmap(
254  dc, penguin_sprites[player % WXSIZEOF(tileset.penguin_sprites)], tile_pos
255  );
256  }
257 
258  this->draw_bitmap(dc, tileset.grid_tile, tile_pos);
259  }
260  }
261 }
262 
263 void CanvasPanel::paint_selected_tile_outline(wxDC& dc, Coords coords, bool blocked) {
265  dc.SetPen(wxPen(blocked ? *wxRED : *wxGREEN, 5));
266  dc.DrawRectangle(this->get_tile_rect(coords));
267 }
268 
270  this->paint_move_arrow(dc, start, end, start, true);
271 }
272 
273 void CanvasPanel::paint_move_arrow(wxDC& dc, Coords start, Coords end, Coords fail, bool valid) {
274  wxPoint arrow_start = this->get_tile_centre(start);
275  wxPoint arrow_fail = this->get_tile_centre(fail);
276  wxPoint arrow_end = this->get_tile_centre(end);
277 
278  wxSize head_size(8, 8);
279  wxPen bg_pen(*wxBLACK, 6);
280  wxPen green_pen((*wxGREEN).ChangeLightness(75), 4);
281  wxPen red_pen((*wxRED).ChangeLightness(75), 4);
282 
283  if (!valid && !coords_same(fail, start)) {
284  dc.SetPen(bg_pen);
285  dc.DrawLine(arrow_start, arrow_fail);
286  dc.SetPen(green_pen);
287  dc.DrawLine(arrow_start, arrow_fail);
288  dc.SetPen(bg_pen);
289  this->paint_arrow_head(dc, arrow_start, arrow_fail, head_size, ARROW_HEAD_CROSS);
290  dc.DrawLine(arrow_fail, arrow_end);
291  this->paint_arrow_head(dc, arrow_fail, arrow_end, head_size);
292  dc.SetPen(red_pen);
293  this->paint_arrow_head(dc, arrow_start, arrow_fail, head_size, ARROW_HEAD_CROSS);
294  dc.DrawLine(arrow_fail, arrow_end);
295  this->paint_arrow_head(dc, arrow_fail, arrow_end, head_size);
296  } else {
297  dc.SetPen(bg_pen);
298  dc.DrawLine(arrow_start, arrow_end);
299  this->paint_arrow_head(dc, arrow_start, arrow_end, head_size);
300  dc.SetPen(valid ? green_pen : red_pen);
301  dc.DrawLine(arrow_start, arrow_end);
302  this->paint_arrow_head(dc, arrow_start, arrow_end, head_size);
303  }
304 }
305 
307  wxDC& dc, wxPoint start, wxPoint end, wxSize head_size, ArrowHeadType head_type
308 ) {
309  if (start == end) return;
310  wxPoint2DDouble norm(end - start);
311  norm.Normalize();
312  wxPoint2DDouble perp(-norm.m_y, norm.m_x);
313  wxPoint2DDouble head1 = -norm * head_size.x + perp * head_size.y;
314  wxPoint2DDouble head2 = -norm * head_size.x - perp * head_size.y;
315  wxPoint head1i(head1.m_x, head1.m_y), head2i(head2.m_x, head2.m_y);
316  if (head_type == ARROW_HEAD_NORMAL) {
317  dc.DrawLine(end, end + head1i);
318  dc.DrawLine(end, end + head2i);
319  } else if (head_type == ARROW_HEAD_CROSS) {
320  dc.DrawLine(end - head1i, end + head1i);
321  dc.DrawLine(end - head2i, end + head2i);
322  }
323 }
324 
326  this->prev_mouse_pos = this->mouse_pos;
327  this->mouse_pos = event.GetPosition();
328 
329  if (!this->mouse_is_down) {
330  this->mouse_drag_pos = this->mouse_pos;
331  }
332  if (event.ButtonDown()) {
333  this->mouse_is_down_real = this->mouse_is_down = true;
334  this->SetFocus();
335  } else if (event.ButtonUp()) {
336  this->mouse_is_down_real = this->mouse_is_down = false;
337  }
338 
339  if (event.Entering()) {
340  this->mouse_within_window = true;
341  } else if (event.Leaving()) {
342  this->mouse_within_window = false;
343  }
344 
345  GameController* controller = this->panel->controller;
346  if (!controller) {
347  event.Skip();
348  return;
349  }
350 
351  // NOTE: a `switch` is unusable here because the event types are defined as
352  // `extern` variables. `switch` in C++ can only work with statically-known
353  // constants.
354  auto event_type = event.GetEventType();
355  if (event_type == wxEVT_LEFT_DOWN) {
356  controller->on_mouse_down(event);
357  } else if (event_type == wxEVT_MOTION) {
358  controller->on_mouse_move(event);
359  } else if (event_type == wxEVT_LEFT_UP) {
360  controller->on_mouse_up(event);
361  } else if (event_type == wxEVT_ENTER_WINDOW) {
362  controller->on_mouse_enter_leave(event);
363  } else if (event_type == wxEVT_LEAVE_WINDOW) {
364  controller->on_mouse_enter_leave(event);
365  } else {
366  event.Skip();
367  }
368 }
bool is_tile_in_bounds(const Game *game, Coords coords)
Checks if the given coords are within the bounds of the board.
Definition: board.h:70
short get_tile(const Game *game, Coords coords)
Returns the value of the tile at coords. Fails if coords are outside the bounds.
Definition: board.h:108
bool get_tile_attr(const Game *game, Coords coords, short attr)
Checks whether the attribute attr of the tile at coords is set.
Definition: board.h:78
void set_tile_attr(Game *game, Coords coords, short attr, bool value)
Sets (or resets) the attribute attr of the tile at coords.
Definition: board.h:86
Functions for working with the game board (and the specifics of its encoding)
#define is_fish_tile(tile)
Definition: board.h:25
#define is_penguin_tile(tile)
Definition: board.h:26
#define is_water_tile(tile)
Definition: board.h:24
@ TILE_DIRTY
Set when a tile is changed with set_tile, can be unset by the UI. All tiles initially have this attri...
Definition: board.h:52
#define get_tile_player_id(tile)
Definition: board.h:28
#define get_tile_fish(tile)
Definition: board.h:27
wxBrush * wxTRANSPARENT_BRUSH
wxBEGIN_EVENT_TABLE(CanvasPanel, wxWindow) wxEND_EVENT_TABLE()
Responsible for drawing the board and painting the UI overlays.
Definition: canvas.hh:17
wxRect get_tile_rect(Coords coords) const
Definition: canvas.cc:50
wxPoint mouse_pos
Definition: canvas.hh:37
GamePanel * panel
Definition: canvas.hh:75
void paint_selected_tile_outline(wxDC &dc, Coords coords, bool blocked=false)
Definition: canvas.cc:263
wxMemoryDC board_dc
Definition: canvas.hh:67
Game * game
Definition: canvas.hh:76
void on_paint(wxPaintEvent &event)
Definition: canvas.cc:72
void paint_tiles(wxDC &dc, const wxRect &update_region)
Definition: canvas.cc:142
bool mouse_is_down
Definition: canvas.hh:35
void paint_arrow_head(wxDC &dc, wxPoint start, wxPoint end, wxSize head_size, ArrowHeadType head_type=ARROW_HEAD_NORMAL)
Definition: canvas.cc:306
void paint_move_arrow(wxDC &dc, Coords start, Coords end)
Definition: canvas.cc:269
void on_any_mouse_event(wxMouseEvent &event)
Definition: canvas.cc:325
static const wxCoord TILE_SIZE
Definition: canvas.hh:19
Coords tile_coords_at_point(wxPoint point) const
Definition: canvas.cc:46
wxBitmap board_bitmap
Definition: canvas.hh:66
@ ARROW_HEAD_NORMAL
Definition: canvas.hh:46
@ ARROW_HEAD_CROSS
Definition: canvas.hh:47
CanvasPanel(wxWindow *parent, wxWindowID id, GamePanel *panel)
Definition: canvas.cc:33
bool mouse_is_down_real
Definition: canvas.hh:36
wxPoint get_tile_centre(Coords coords) const
Definition: canvas.cc:54
Coords get_selected_penguin_coords() const
Definition: canvas.cc:59
wxBitmap tiles_bitmap
Definition: canvas.hh:68
void draw_bitmap(wxDC &dc, const wxBitmap &bitmap, const wxPoint &pos)
Definition: canvas.cc:131
void paint_board(wxDC &dc, const wxRect &update_region, wxDC &tiles_dc)
Definition: canvas.cc:216
bool mouse_within_window
Definition: canvas.hh:34
wxSize get_canvas_size() const
Definition: canvas.cc:42
wxMemoryDC tiles_dc
Definition: canvas.hh:69
wxPoint prev_mouse_pos
Definition: canvas.hh:38
wxPoint mouse_drag_pos
Definition: canvas.hh:39
virtual void on_mouse_move(wxMouseEvent &event)
Definition: controllers.cc:45
virtual void on_mouse_up(wxMouseEvent &event)
Definition: controllers.cc:46
virtual void on_mouse_down(wxMouseEvent &event)
Definition: controllers.cc:44
virtual void on_mouse_enter_leave(wxMouseEvent &event)
Definition: controllers.cc:52
virtual void paint_overlay(wxDC &dc)
Definition: controllers.cc:43
virtual void update_tile_attributes()
Definition: controllers.cc:162
GameController * controller
Definition: game.hh:74
virtual bool IsOk() const
virtual bool Create(int width, int height, int depth=wxBITMAP_SCREEN_DEPTH)
void SetPen(const wxPen &pen)
bool Blit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxDC *source, wxCoord xsrc, wxCoord ysrc, wxRasterOperationMode logicalFunc=wxCOPY, bool useMask=false, wxCoord xsrcMask=wxDefaultCoord, wxCoord ysrcMask=wxDefaultCoord)
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
void SetBrush(const wxBrush &brush)
void DrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
void GetSize(wxCoord *width, wxCoord *height) const
void DrawBitmap(const wxBitmap &bitmap, wxCoord x, wxCoord y, bool useMask=false)
void SelectObjectAsSource(const wxBitmap &bitmap)
void SelectObject(wxBitmap &bitmap)
bool ButtonDown(wxMouseButton but=wxMOUSE_BTN_ANY) const
bool Leaving() const
bool ButtonUp(wxMouseButton but=wxMOUSE_BTN_ANY) const
bool Entering() const
void UnRef()
wxPoint GetPosition() const
wxSize GetSize() const
bool Intersects(const wxRect &rect) const
void GetBox(wxCoord &x, wxCoord &y, wxCoord &width, wxCoord &height) const
void SetInitialSize(const wxSize &size=wxDefaultSize)
const wxRegion & GetUpdateRegion() const
void SetDoubleBuffered(bool on)
virtual void SetFocus()
wxColour * wxBLACK
wxColour * wxRED
wxColour * wxGREEN
int game_find_player_by_id(const Game *self, short id)
Returns an index of the player or -1 if no such player was found.
Definition: game.h:407
Player * game_get_player(const Game *self, int idx)
Returns a pointer to the player at the given index. Fails if the index isn't within the bounds of the...
Definition: game.h:394
bool game_check_player_index(const Game *self, int idx)
Checks if idx is within the bounds of Game::players.
Definition: game.h:387
The core of the unified game logic library, contains the Game struct.
@ GAME_PHASE_MOVEMENT
Set by movement_begin.
Definition: game.h:60
@ TILE_WAS_BLOCKED
Definition: game_state.hh:20
@ TILE_NEEDS_REDRAW
Definition: game_state.hh:22
@ TILE_BLOCKED
Definition: game_state.hh:19
@ TILE_OVERLAY_NEEDS_REDRAW
Definition: game_state.hh:23
wxAppDerivedClass & wxGetApp()
wxEventType wxEVT_MOTION
wxEventType wxEVT_LEFT_DOWN
#define wxEND_EVENT_TABLE()
wxEventType wxEVT_LEFT_UP
wxEventType wxEVT_ENTER_WINDOW
wxEventType wxEVT_LEAVE_WINDOW
wxBitmap wxNullBitmap
wxCOPY
A pair of 2D coordinates, used for addressing the Game::board_grid.
Definition: utils.h:15
int x
Definition: utils.h:16
int y
Definition: utils.h:17
GamePhase phase
The current state of the state machine, initially set to GAME_PHASE_NONE. Use game_set_phase for sett...
Definition: game.h:242
int board_width
Use setup_board for setting this.
Definition: game.h:264
int board_height
Use setup_board for setting this.
Definition: game.h:266
int current_player_index
A negative value means that there is no current player selected. Use game_set_current_player for sett...
Definition: game.h:256
short id
The unique ID, usually (but not necessarily) is just index + 1.
Definition: game.h:70
TileEdge
Definition: tileset.hh:8
@ EDGE_RIGHT
Definition: tileset.hh:10
@ EDGE_BOTTOM
Definition: tileset.hh:11
@ EDGE_TOP
Definition: tileset.hh:9
@ EDGE_LEFT
Definition: tileset.hh:12
TileCorner
Definition: tileset.hh:16
@ CORNER_TOP_RIGHT
Definition: tileset.hh:17
@ CORNER_BOTTOM_LEFT
Definition: tileset.hh:19
@ CORNER_TOP_LEFT
Definition: tileset.hh:20
@ CORNER_BOTTOM_RIGHT
Definition: tileset.hh:18
bool coords_same(Coords a, Coords b)
Checks if two Coords pairs are equal.
Definition: utils.h:46
const Coords NEIGHBOR_TO_COORDS[NEIGHBOR_MAX]
A table that maps Neighbor variants to relative Coords.
Definition: utils.c:27
uint32_t fnv32_hash(uint32_t state, const void *buf, size_t len)
Computes the 32-bit FNV-1a hash of a given byte sequence.
Definition: utils.h:151
#define FNV32_INITIAL_STATE
A constant for fnv32_hash.
Definition: utils.h:138
@ NEIGHBOR_MAX
Definition: utils.h:37
int wxWindowID