55#include <allegro5/allegro.h>
56#include <allegro5/allegro_image.h>
57#include <allegro5/allegro_primitives.h>
58#include <allegro5/allegro_font.h>
59#include <allegro5/allegro_ttf.h>
92#define PLAYER_MOVE_SPEED 4.0f
93#define JUMP_VELOCITY 9.0f
94#define JUMP_GRAVITY 20.0f
95#define CAM_SMOOTHING 8.0f
96#define PLAYER_MAX_HEIGH_DIFF 1
100#define TERRAIN_LAVE 1
101#define TERRAIN_SABLE 2
102#define TERRAIN_CHEMIN 3
103#define TERRAIN_TEMPLE3 4
104#define TERRAIN_TEMPLE4 5
105#define TERRAIN_PAILLE 6
106#define TERRAIN_ROCAILLE 7
110 "Water",
"Lava",
"Sand",
"Road",
"Temple Light",
"Temple Dark",
"Straw",
"Rock"};
114 "DATAS/tiles/eau_centre.bmp",
115 "DATAS/tiles/lave.bmp",
116 "DATAS/tiles/sable_centre.bmp",
117 "DATAS/tiles/chemin_centre.bmp",
118 "DATAS/tiles/temple3.bmp",
119 "DATAS/tiles/temple4.bmp",
120 "DATAS/tiles/paille.bmp",
121 "DATAS/tiles/rocaille.bmp"};
124#define NUM_PROJECTIONS ISO_NUM_PROJECTIONS
127#define NUM_MASKS ISO_NUM_MASKS
229#define MAP_FILE "iso_gui_map.isom"
237 if (fx < 0.0f) fx = 0.0f;
238 if (fy < 0.0f) fy = 0.0f;
239 if (fx > (
float)
MAP_W - 1e-4f) fx = (float)
MAP_W - 1e-4f;
240 if (fy > (
float)
MAP_H - 1e-4f) fy = (float)
MAP_H - 1e-4f;
252 if (fx < 0.0f) fx = 0.0f;
253 if (fy < 0.0f) fy = 0.0f;
254 if (fx > (
float)
MAP_W - 1e-4f) fx = (float)
MAP_W - 1e-4f;
255 if (fy > (
float)
MAP_H - 1e-4f) fy = (float)
MAP_H - 1e-4f;
257 int ix = (int)floorf(fx);
258 int iy = (int)floorf(fy);
267 float frac_x = fx - (float)ix;
268 float frac_y = fy - (float)iy;
271 int ix1 = (ix + 1 <
MAP_W) ? ix + 1 : ix;
272 int iy1 = (iy + 1 <
MAP_H) ? iy + 1 : iy;
278 float max_h = h00 + (float)max_climb;
279 if (h10 > max_h) h10 = max_h;
280 if (h01 > max_h) h01 = max_h;
281 if (h11 > max_h) h11 = max_h;
283 float top = h00 + (h10 - h00) * frac_x;
284 float bot = h01 + (h11 - h01) * frac_x;
285 return top + (bot - top) * frac_y;
293 al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
294 float cy = sy - 8.0f * zoom;
301 float shadow_cx, shadow_cy;
303 al_draw_filled_ellipse(sx, shadow_cy, 4.0f * zoom, 2.0f * zoom,
304 al_map_rgba(0, 0, 0, 60));
307 al_draw_filled_circle(sx, cy, 5.0f * zoom,
308 al_map_rgba(50, 200, 50, (
unsigned char)(220.0f * alpha)));
309 al_draw_circle(sx, cy, 5.0f * zoom,
310 al_map_rgba(255, 255, 255, (
unsigned char)(200.0f * alpha)), 1.5f);
316 al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
317 float cy = sy - 8.0f * zoom;
320 al_draw_filled_circle(sx, cy, 5.0f * zoom,
321 al_map_rgba(80, 120, 255, (
unsigned char)(220.0f * alpha)));
322 al_draw_circle(sx, cy, 5.0f * zoom,
323 al_map_rgba(200, 200, 255, (
unsigned char)(200.0f * alpha)), 1.5f);
325 al_draw_filled_ellipse(sx, cy + 8.0f * zoom, 4.0f * zoom, 2.0f * zoom,
326 al_map_rgba(0, 0, 0, 60));
332 al_draw_circle(tcx, tcy, 5.0f * zoom, al_map_rgba(255, 80, 80, 180), 1.5f);
333 al_draw_filled_ellipse(tcx, tcy + 8.0f * zoom, 4.0f * zoom, 2.0f * zoom,
334 al_map_rgba(255, 0, 0, 30));
340 srand((
unsigned)time(NULL));
342 for (
int y = 0; y <
MAP_H; y++)
343 for (
int x = 0; x <
MAP_W; x++) {
348 for (
int patch = 0; patch < 15; patch++) {
350 int cx = rand() %
MAP_W;
351 int cy = rand() %
MAP_H;
352 int radius = 2 + rand() % 4;
353 for (
int dy = -radius; dy <= radius; dy++)
354 for (
int dx = -radius; dx <= radius; dx++) {
355 int x = cx + dx, y = cy + dy;
356 if (x < 0 || x >=
MAP_W || y < 0 || y >=
MAP_H)
continue;
357 float dist = sqrtf((
float)(dx * dx + dy * dy));
358 if (dist <= radius && (rand() % 100) < (
int)(100.0f * (1.0f - dist / (
float)(radius + 1))))
363 for (
int hill = 0; hill < 8; hill++) {
365 int cx = rand() %
MAP_W;
366 int cy = rand() %
MAP_H;
367 int radius = 2 + rand() % 3;
368 for (
int dy = -radius; dy <= radius; dy++)
369 for (
int dx = -radius; dx <= radius; dx++) {
370 int x = cx + dx, y = cy + dy;
371 if (x < 0 || x >=
MAP_W || y < 0 || y >=
MAP_H)
continue;
372 float dist = sqrtf((
float)(dx * dx + dy * dy));
373 if (dist > radius)
continue;
374 int h = (int)((
float)peak_h * (1.0f - dist / (
float)(radius + 1)) + 0.5f);
394 for (
int y = 0; y <
MAP_H; y++)
395 for (
int x = 0; x <
MAP_W; x++) {
397 if (h > drop_max_h) drop_max_h = h;
445 for (
int y = 0; y <
MAP_H; y++)
446 for (
int x = 0; x <
MAP_W; x++) {
448 if (h > ghost_max_h) ghost_max_h = h;
482int main(
int argc,
char* argv[]) {
489 n_abort(
"Could not init Allegro.\n");
496 ALLEGRO_PATH* here = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
499 al_change_directory(al_path_cstr(here, ALLEGRO_NATIVE_PATH_SEP));
500 al_destroy_path(here);
512 if (!al_init_image_addon()) {
515 if (!al_init_primitives_addon()) {
518 if (!al_init_font_addon()) {
522 al_install_keyboard();
525 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE);
528 n_abort(
"Unable to create display\n");
530 al_set_window_title(
display,
"Nilorea Isometric Engine + GUI Demo");
532 ALLEGRO_FONT*
font = al_create_builtin_font();
534 n_abort(
"Unable to create builtin font\n");
540 n_abort(
"Failed to create ISO_MAP!\n");
549 n_abort(
"Failed to create camera!\n");
578 10, 185, 150, 20, 0.0, (
double)
MAX_HEIGHT, 0.0,
625 10, 23, 180, 66, NULL, NULL);
634 10, 111, 180, 66, NULL, NULL);
649 10, 243, 180, 20, 0.01, 2.0, 0.2,
655 10, 287, 180, 20, 0.01, 5.0, 0.5,
662 int saved_bmp_flags = al_get_new_bitmap_flags();
663 al_set_new_bitmap_flags(saved_bmp_flags & ~(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR));
682 al_set_new_bitmap_flags(saved_bmp_flags);
688 for (
int y = 0; y <
MAP_H && y < loaded->
height; y++)
689 for (
int x = 0; x <
MAP_W && x < loaded->
width; x++) {
702 float sx_center, sy_center;
715 ALLEGRO_TIMER* timer = al_create_timer(1.0 /
FPS);
716 ALLEGRO_EVENT_QUEUE* queue = al_create_event_queue();
717 al_register_event_source(queue, al_get_display_event_source(
display));
718 al_register_event_source(queue, al_get_timer_event_source(timer));
719 al_register_event_source(queue, al_get_keyboard_event_source());
720 al_register_event_source(queue, al_get_mouse_event_source());
722 al_start_timer(timer);
724 bool key_up =
false, key_down =
false, key_left =
false, key_right =
false;
725 bool key_space =
false;
726 float scroll_speed = 4.0f;
727 float dt = 1.0f / (float)
FPS;
739 al_wait_for_event(queue, &ev);
748 case ALLEGRO_EVENT_TIMER: {
756 float target_fx, target_fy;
767 float path_dist = sqrtf(path_dx * path_dx + path_dy * path_dy);
769 if (path_dist <= step) {
780 player_fx += (path_dx / path_dist) * step;
781 player_fy += (path_dy / path_dist) * step;
789 float move_dx = 0.0f, move_dy = 0.0f;
790 if (key_up) move_dy -= 1.0f;
791 if (key_down) move_dy += 1.0f;
792 if (key_left) move_dx -= 1.0f;
793 if (key_right) move_dx += 1.0f;
795 if (move_dx != 0.0f && move_dy != 0.0f) {
796 move_dx *= 0.70710678f;
797 move_dy *= 0.70710678f;
827 if (move_dx != 0.0f || move_dy != 0.0f) {
829 float new_fx =
player_fx + move_dx * speed;
830 float new_fy =
player_fy + move_dy * speed;
832 if (new_fx < 0.1f) new_fx = 0.1f;
833 if (new_fx > (
float)
MAP_W - 0.1f) new_fx = (float)
MAP_W - 0.1f;
834 if (new_fy < 0.1f) new_fy = 0.1f;
835 if (new_fy > (
float)
MAP_H - 0.1f) new_fy = (float)
MAP_H - 0.1f;
837 int new_tile_x = (int)floorf(new_fx);
838 int new_tile_y = (int)floorf(new_fy);
840 bool can_move =
true;
842 if (new_tile_x >= 0 && new_tile_x <
MAP_W &&
843 new_tile_y >= 0 && new_tile_y <
MAP_H) {
850 if ((
float)target_h >
player_z + 0.5f)
865 float slide_fx =
player_fx + move_dx * speed;
866 if (slide_fx < 0.1f) slide_fx = 0.1f;
867 if (slide_fx > (
float)
MAP_W - 0.1f) slide_fx = (float)
MAP_W - 0.1f;
868 int slide_tx = (int)floorf(slide_fx);
871 if (slide_tx >= 0 && slide_tx <
MAP_W) {
877 if ((
float)th >
player_z + 0.5f) can_x =
false;
888 float slide_fy =
player_fy + move_dy * speed;
889 if (slide_fy < 0.1f) slide_fy = 0.1f;
890 if (slide_fy > (
float)
MAP_H - 0.1f) slide_fy = (float)
MAP_H - 0.1f;
891 int slide_ty = (int)floorf(slide_fy);
894 if (slide_ty >= 0 && slide_ty <
MAP_H) {
900 if ((
float)th >
player_z + 0.5f) can_y =
false;
940 float sdx = 0.0f, sdy = 0.0f;
941 if (key_left) sdx += scroll_speed /
camera->zoom;
942 if (key_right) sdx -= scroll_speed /
camera->zoom;
943 if (key_up) sdy += scroll_speed /
camera->zoom;
944 if (key_down) sdy -= scroll_speed /
camera->zoom;
945 if (sdx != 0.0f || sdy != 0.0f)
951 double now = al_get_time();
1014 for (
int y = 0; y <
MAP_H; y++)
1015 for (
int x = 0; x <
MAP_W; x++) {
1017 if (h > drop_max_h) drop_max_h = h;
1019 player_z = (float)(drop_max_h + 1);
1042 int ghost_max_h = 0;
1043 for (
int y = 0; y <
MAP_H; y++)
1044 for (
int x = 0; x <
MAP_W; x++) {
1046 if (h > ghost_max_h) ghost_max_h = h;
1063 if (gui_algo >= 0 && gui_algo != (
int)
ghost_dr->algo)
1069 if (gui_blend >= 0 && gui_blend != (
int)
ghost_dr->blend_mode)
1087 if (fabs(gui_bt -
ghost_dr->blend_time) > 0.001)
1091 snprintf(btbuf,
sizeof(btbuf),
"Blend time: %.2fs",
ghost_dr->blend_time);
1098 if (fabs(gui_th -
ghost_dr->pos_threshold) > 0.001)
1102 snprintf(thbuf,
sizeof(thbuf),
"Threshold: %.2f",
ghost_dr->pos_threshold);
1113 snprintf(hbuf,
sizeof(hbuf),
"Height: %d",
paint_height);
1160 case ALLEGRO_EVENT_KEY_DOWN:
1161 switch (ev.keyboard.keycode) {
1163 case ALLEGRO_KEY_LEFT:
1167 case ALLEGRO_KEY_RIGHT:
1171 case ALLEGRO_KEY_UP:
1175 case ALLEGRO_KEY_DOWN:
1179 case ALLEGRO_KEY_SPACE:
1182 case ALLEGRO_KEY_ESCAPE:
1185 case ALLEGRO_KEY_PGDN:
1189 case ALLEGRO_KEY_PGUP:
1193 case ALLEGRO_KEY_EQUALS:
1194 case ALLEGRO_KEY_PAD_PLUS:
1197 case ALLEGRO_KEY_MINUS:
1198 case ALLEGRO_KEY_PAD_MINUS:
1203 int a = (int)((
ghost_dr->algo + 1) % 3);
1210 int b = (int)((
ghost_dr->blend_mode + 1) % 3);
1215 case ALLEGRO_KEY_COMMA:
1220 case ALLEGRO_KEY_FULLSTOP:
1230 case ALLEGRO_EVENT_KEY_UP:
1231 switch (ev.keyboard.keycode) {
1232 case ALLEGRO_KEY_LEFT:
1236 case ALLEGRO_KEY_RIGHT:
1240 case ALLEGRO_KEY_UP:
1244 case ALLEGRO_KEY_DOWN:
1248 case ALLEGRO_KEY_SPACE:
1254 case ALLEGRO_EVENT_MOUSE_AXES:
1259 (
float)ev.mouse.x, (
float)ev.mouse.y);
1263 case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
1267 (
float)ev.mouse.y, &wx, &wy);
1269 float click_fx = 0.0f, click_fy = 0.0f;
1271 &map_x, &map_y, &click_fx, &click_fy);
1272 if (map_x >= 0 && map_x < MAP_W && map_y >= 0 && map_y <
MAP_H) {
1281 int dest_x = map_x, dest_y = map_y;
1285 for (
int ring = 1; ring <= MAX(
MAP_W,
MAP_H) && !found; ring++) {
1286 for (
int ry = -ring; ry <= ring && !found; ry++)
1287 for (
int rx = -ring; rx <= ring && !found; rx++) {
1288 if (abs(rx) != ring && abs(ry) != ring)
continue;
1289 int nx = map_x + rx, ny = map_y + ry;
1290 if (nx >= 0 && nx < MAP_W && ny >= 0 && ny <
MAP_H &&
1311 if (final_tx == map_x && final_ty == map_y) {
1343 case ALLEGRO_EVENT_DISPLAY_CLOSE:
1347 case ALLEGRO_EVENT_DISPLAY_RESIZE:
1348 al_acknowledge_resize(
display);
1358 al_set_target_backbuffer(
display);
1359 al_clear_to_color(al_map_rgb(20, 25, 30));
1370 int iso_num_objects = 0;
1379 iso_objects[iso_num_objects].
user_data = NULL;
1388 iso_objects[iso_num_objects].
fx = (float)dr_pos.
x;
1389 iso_objects[iso_num_objects].
fy = (float)dr_pos.
y;
1390 iso_objects[iso_num_objects].
fz = dr_h;
1394 iso_objects[iso_num_objects].
user_data = NULL;
1409 iso_num_objects > 0 ? iso_objects : NULL,
1418 snprintf(sbuf,
sizeof(sbuf),
"Pos:(%.1f,%.1f) Z:%.1f GndH:%.1f %s | Zoom:%.1fx",
1422 snprintf(sbuf,
sizeof(sbuf),
"Paint height:%d | Zoom:%.1fx | Slope max:%d",
1425 snprintf(sbuf,
sizeof(sbuf),
"Brush:[%s] | Zoom:%.1fx | Slope max:%d",
1430 snprintf(sbuf,
sizeof(sbuf),
"Proj: %s (%.1f deg)",
1435 snprintf(sbuf,
sizeof(sbuf),
"Hover: (%d,%d) H:%d T:%s",
1468 al_destroy_font(
font);
1469 al_destroy_timer(timer);
1470 al_destroy_event_queue(queue);
1473 return EXIT_SUCCESS;
ALLEGRO_DISPLAY * display
void on_grid_toggle(int widget_id, void *user_data)
void on_player_toggle(int widget_id, void *user_data)
void on_smooth_toggle(int widget_id, void *user_data)
void on_ghost_toggle(int widget_id, void *user_data)
void on_proj_select(int widget_id, void *user_data)
void on_height_toggle(int widget_id, void *user_data)
static float interpolate_height_at_clamped(float fx, float fy, int max_climb)
static int gui_btn_smooth
static void draw_ghost_object(float sx, float sy, float zoom, float alpha, void *user_data)
static float ghost_path_angle
static int player_path_idx
static ASTAR_PATH * player_path
static void on_reset_click(int id, void *data)
static int gui_sld_dr_blend_time
static int gui_sld_dr_threshold
static double ghost_last_send
static int gui_sld_height
static float ghost_path_radius
static void draw_player_object(float sx, float sy, float zoom, float alpha, void *user_data)
static N_ISO_CAMERA * camera
static void randomize_map(void)
static int gui_sld_dr_interval
static float player_path_progress
static int gui_btn_proj[4]
static int gui_win_ghost_dr
static float player_click_fy
static ALLEGRO_BITMAP * transition_tiles[8][(16+16)]
static int smooth_slope_max
static int gui_lbl_dr_threshold
static float player_screen_y
static float ghost_path_speed
static float player_screen_x
static float ghost_path_cy
static int gui_btn_player
static ALLEGRO_BITMAP * tile_bitmaps[8]
static bool redraw_needed
static const char * terrain_files[8]
static float ghost_screen_x
static int gui_lbl_dr_algo
static float ghost_true_y
static int gui_rad_dr_blend
static int gui_btn_height
static float ghost_path_cx
static float player_click_fx
#define PLAYER_MOVE_SPEED
#define PLAYER_MAX_HEIGH_DIFF
static int gui_lbl_dr_interval
static DR_ENTITY * ghost_dr
static float ghost_screen_y
static double ghost_send_interval
static float ghost_true_x
static const char * terrain_names[8]
static int gui_lbl_dr_blend_time
static int gui_lbl_dr_blend
static ALLEGRO_BITMAP * transition_masks[(16+16)]
static int gui_lbl_height
static int gui_rad_dr_algo
static float interpolate_height_at(float fx, float fy)
static int gui_lbl_status
static N_GUI_CTX * gui_ctx
static bool player_on_ground
#define SCREEN_H
screen height
FONT * font
the default 8x8 font, valid after allegro_init()
#define SCREEN_W
screen width
ASTAR_PATH * n_astar_find_path(const ASTAR_GRID *grid, int sx, int sy, int sz, int gx, int gy, int gz, int diagonal, ASTAR_HEURISTIC heuristic)
Find a path using A* search.
uint8_t n_astar_grid_get_walkable(const ASTAR_GRID *grid, int x, int y, int z)
Get a cell's walkability.
#define ASTAR_ALLOW_DIAGONAL
Movement mode: 8-dir (2D) or 26-dir (3D).
void n_astar_grid_free(ASTAR_GRID *grid)
Free a grid and all its internal data.
void n_astar_path_free(ASTAR_PATH *path)
Free a path returned by n_astar_find_path.
@ ASTAR_HEURISTIC_CHEBYSHEV
max of axis deltas (optimal for 8-dir)
Grid structure holding walkability, costs, and dimensions.
The computed path result.
void n_abort(char const *format,...)
abort program with a text
void dr_entity_destroy(DR_ENTITY **entity_ptr)
Destroy a dead reckoning entity and set the pointer to NULL.
static DR_VEC3 dr_vec3(double x, double y, double z)
Create a DR_VEC3 from components.
void dr_entity_set_threshold(DR_ENTITY *entity, double threshold)
Set the position error threshold for triggering network updates.
void dr_entity_compute(DR_ENTITY *entity, double time, DR_VEC3 *out_pos)
Compute the dead reckoned display position at a given time.
DR_ENTITY * dr_entity_create(DR_ALGO algo, DR_BLEND blend_mode, double pos_threshold, double blend_time)
Create a new dead reckoning entity.
void dr_entity_set_blend_time(DR_ENTITY *entity, double blend_time)
Set the convergence blend duration.
DR_BLEND
Dead reckoning convergence/blending mode.
void dr_entity_set_blend_mode(DR_ENTITY *entity, DR_BLEND blend_mode)
Set the convergence blending mode.
bool dr_entity_check_threshold(const DR_ENTITY *entity, const DR_VEC3 *true_pos, const DR_VEC3 *true_vel, const DR_VEC3 *true_acc, double time)
Check whether the owner's true state has diverged from the dead reckoned prediction beyond the config...
DR_ALGO
Dead reckoning extrapolation algorithm.
void dr_entity_set_algo(DR_ENTITY *entity, DR_ALGO algo)
Set the extrapolation algorithm.
void dr_entity_receive_state(DR_ENTITY *entity, const DR_VEC3 *pos, const DR_VEC3 *vel, const DR_VEC3 *acc, double time)
Receive a new authoritative state update from the network.
void dr_entity_set_position(DR_ENTITY *entity, const DR_VEC3 *pos, const DR_VEC3 *vel, const DR_VEC3 *acc, double time)
Force-set entity position without triggering convergence blending.
@ DR_BLEND_PVB
Projective Velocity Blending (recommended).
@ DR_ALGO_VEL_ACC
Velocity + acceleration: P(t) = P0 + V0*t + 0.5*A0*t^2.
Dead reckoned entity with extrapolation and convergence state.
3D vector used for position, velocity, and acceleration
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
set the display (viewport) size so global scrollbars can be computed.
int n_gui_button_is_toggled(N_GUI_CTX *ctx, int widget_id)
Check if a toggle button is currently in the "on" state.
#define N_GUI_ALIGN_LEFT
left aligned text
int n_gui_add_slider(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, double min_val, double max_val, double initial, int mode, void(*on_change)(int, double, void *), void *user_data)
Add a slider widget.
int n_gui_wants_mouse(N_GUI_CTX *ctx)
Check if the mouse is currently over any open GUI window.
int n_gui_radiolist_add_item(N_GUI_CTX *ctx, int widget_id, const char *text)
add an item to a radiolist widget
void n_gui_label_set_text(N_GUI_CTX *ctx, int widget_id, const char *text)
set label text content
int n_gui_add_listbox(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int selection_mode, void(*on_select)(int, int, int, void *), void *user_data)
Add a listbox widget.
#define N_GUI_SLIDER_VALUE
slider uses raw start/end values
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
int n_gui_add_label(N_GUI_CTX *ctx, int window_id, const char *text, float x, float y, float w, float h, int align)
Add a static text label.
int n_gui_add_radiolist(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, void(*on_select)(int, int, void *), void *user_data)
Add a radio list widget (single selection with radio bullets).
void n_gui_close_window(N_GUI_CTX *ctx, int window_id)
Close (hide) a window.
void n_gui_listbox_set_selected(N_GUI_CTX *ctx, int widget_id, int index, int selected)
set the selection state of a listbox item
double n_gui_slider_get_value(N_GUI_CTX *ctx, int widget_id)
get the current value of a slider widget
int n_gui_listbox_add_item(N_GUI_CTX *ctx, int widget_id, const char *text)
add an item to a listbox widget
int n_gui_radiolist_get_selected(N_GUI_CTX *ctx, int widget_id)
get the selected item index in a radiolist widget
#define N_GUI_SELECT_SINGLE
single item selection
void n_gui_button_set_toggled(N_GUI_CTX *ctx, int widget_id, int toggled)
Set the toggle state of a button.
int n_gui_add_toggle_button(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int shape, int initial_state, void(*on_click)(int, void *), void *user_data)
Add a toggle button widget (stays clicked/unclicked on single click).
int n_gui_listbox_get_selected(N_GUI_CTX *ctx, int widget_id)
get the index of the first selected item in a listbox
void n_gui_draw(N_GUI_CTX *ctx)
draw all visible GUI windows and widgets
void n_gui_button_set_keycode(N_GUI_CTX *ctx, int widget_id, int keycode, int modifiers)
Bind a keyboard key with optional modifier requirements to a button.
int n_gui_add_window(N_GUI_CTX *ctx, const char *title, float x, float y, float w, float h)
Add a new pseudo-window to the context.
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
void n_gui_open_window(N_GUI_CTX *ctx, int window_id)
Open (show) a window.
void n_gui_slider_set_value(N_GUI_CTX *ctx, int widget_id, double value)
set the value of a slider widget
#define N_GUI_SHAPE_ROUNDED
rounded rectangle shape
void n_gui_radiolist_set_selected(N_GUI_CTX *ctx, int widget_id, int index)
set the selected item in a radiolist widget
void n_gui_set_widget_visible(N_GUI_CTX *ctx, int widget_id, int visible)
Show or hide a widget.
int n_gui_add_button(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int shape, void(*on_click)(int, void *), void *user_data)
Add a button widget to a window.
The top-level GUI context that holds all windows.
float fz
height in map units (elevation)
float fy
fractional map Y position
int height
map height in tiles (Y axis)
float occluded_alpha
overlay alpha when behind tiles [0..1], 0=hidden, 0.35=ghost, 1=always visible
float fx
fractional map X position
void * user_data
user data passed to draw callback
N_ISO_OBJECT_DRAW_FN draw
draw callback
int is_occluded
OUTPUT: set to 1 if behind tiles during last iso_map_draw() call.
int width
map width in tiles (X axis)
void iso_map_set_height(ISO_MAP *map, int mx, int my, int h)
Set the height at a cell (clamped to [0, max_height]).
ISO_MAP * iso_map_new(int width, int height, int num_terrains, int max_height)
Create a new height-aware isometric map.
void n_iso_camera_zoom(N_ISO_CAMERA *cam, float dz, float mouse_x, float mouse_y)
Zoom the camera toward a screen-space point.
void n_iso_camera_center_on(N_ISO_CAMERA *cam, float world_x, float world_y, int screen_w, int screen_h)
Center the camera so that a world point is at screen center.
int iso_map_save(const ISO_MAP *map, const char *filename)
Save ISO_MAP to a binary file.
void iso_map_lerp_projection(ISO_MAP *map, float dt)
Smoothly interpolate the projection angle toward the target.
void iso_mask_tile_to_diamond(ALLEGRO_BITMAP *bmp, int tile_w, int tile_h)
Mask a tile bitmap to the isometric diamond shape.
ISO_MAP * iso_map_load(const char *filename)
Load ISO_MAP from a binary file.
void n_iso_camera_free(N_ISO_CAMERA **cam)
Free a camera and set the pointer to NULL.
const char * iso_projection_name(int preset)
Get the display name for a projection preset.
void n_iso_camera_follow(N_ISO_CAMERA *cam, float target_x, float target_y, int screen_w, int screen_h, float smoothing, float dt)
Smoothly follow a world-space target.
int iso_map_get_terrain(const ISO_MAP *map, int mx, int my)
Get the terrain type at a cell.
void iso_map_draw(const ISO_MAP *map, ALLEGRO_BITMAP **tile_bitmaps, ALLEGRO_BITMAP ***transition_tiles, int num_masks, ALLEGRO_BITMAP **overlay_bitmaps, int num_overlay_tiles, float cam_px, float cam_py, float zoom, int screen_w, int screen_h, int player_mode, N_ISO_OBJECT *objects, int num_objects)
Draw the full ISO_MAP with segment-sorted rendering.
void iso_map_to_screen(const ISO_MAP *map, int mx, int my, int h, float *screen_x, float *screen_y)
Convert map tile coordinates to screen pixel coordinates.
void iso_map_set_projection(ISO_MAP *map, int preset, float tile_width)
Set projection parameters from a preset and tile width.
void n_iso_camera_screen_to_world(const N_ISO_CAMERA *cam, float sx, float sy, float *wx, float *wy)
Convert screen pixel coordinates to world coordinates.
void iso_map_to_screen_f(const ISO_MAP *map, float fmx, float fmy, float h, float *screen_x, float *screen_y)
Convert map coordinates to screen coordinates (float version).
void iso_map_free(ISO_MAP **map_ptr)
Free an ISO_MAP and set the pointer to NULL.
void iso_generate_transition_tiles(ALLEGRO_BITMAP ***tiles, ALLEGRO_BITMAP **masks, ALLEGRO_BITMAP **tile_bitmaps, int num_terrains, int tile_w, int tile_h)
Pre-composite transition tiles (terrain texture * alpha mask).
void iso_map_set_projection_target(ISO_MAP *map, int preset)
Set the target projection for smooth interpolation.
void iso_map_set_terrain(ISO_MAP *map, int mx, int my, int terrain)
Set the terrain type at a cell.
void iso_generate_transition_masks(ALLEGRO_BITMAP **masks, int tile_w, int tile_h)
Generate the 32 procedural transition alpha masks (16 edge + 16 corner).
int iso_map_get_height(const ISO_MAP *map, int mx, int my)
Get the height at a cell.
float iso_map_interpolate_height(const ISO_MAP *map, float fx, float fy)
Bilinear height interpolation at fractional map coordinates.
#define ISO_PROJ_CLASSIC
Projection ID: classic 2:1 isometric (~26.565 degree angle).
void n_iso_camera_world_to_screen(const N_ISO_CAMERA *cam, float wx, float wy, float *sx, float *sy)
Convert world coordinates to screen pixel coordinates.
void iso_screen_to_map_height_f(const ISO_MAP *map, float screen_x, float screen_y, int tile_w, int tile_h, int *mx, int *my, float *out_fx, float *out_fy)
Height-aware screen-to-map conversion returning fractional tile coordinates.
void iso_screen_to_map_height(const ISO_MAP *map, float screen_x, float screen_y, int tile_w, int tile_h, int *mx, int *my)
Height-aware screen-to-map conversion with diamond hit testing.
void n_iso_camera_scroll(N_ISO_CAMERA *cam, float dx, float dy)
Scroll the camera by (dx, dy) world units.
N_ISO_CAMERA * n_iso_camera_new(float zoom_min, float zoom_max)
Create a new 2D isometric camera.
Height-aware isometric map with terrain and height layers, per-cell height values,...
2D isometric camera for viewport management.
Drawable object for depth-sorted isometric rendering.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
#define LOG_INFO
informational
A* Pathfinding API for 2D and 3D grids.
Common headers and low-level functions & define.
Dead Reckoning API for latency hiding in networked games.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.
Isometric/axonometric tile engine with height maps, terrain transitions, and A* pathfinding integrati...
List structures and definitions.
N_STR and string function declaration.