Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_iso_engine.c File Reference

Isometric/axonometric tile engine with height maps, terrain transitions, and A* pathfinding integration. More...

#include <math.h>
#include <stdio.h>
#include "nilorea/n_astar.h"
#include "nilorea/n_iso_engine.h"
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
+ Include dependency graph for n_iso_engine.c:

Go to the source code of this file.

Functions

static int _cmp_draw_entry (const void *a, const void *b)
 
static ALLEGRO_COLOR _compute_tile_tint (int seg_top, int max_height, float intensity, float ambient_r, float ambient_g, float ambient_b, float dyn_r, float dyn_g, float dyn_b)
 
static void _draw_height_borders (const ISO_MAP *map, int mx, int my, int seg_idx, int seg_bottom, int seg_top, int has_underside_face, const float vx[4], const float vy[4], float lift)
 Draw black border outlines on the diamond edges of an elevated tile.
 
static void _draw_segment_sides (const ISO_MAP *map, float east_x, float east_y, float south_x, float south_y, float west_x, float west_y, int mx, int my, int seg_bottom, int seg_top, float lift, float height_brightness, int wall_terrain_override)
 Draw cliff side faces for a single segment {seg_bottom..seg_top}.
 
static void _draw_segment_underside (ALLEGRO_BITMAP *bmp, float base_dx, float base_dy, float phw, float phh, float tile_draw_w, float tile_draw_h, int tile_w, int tile_h)
 Draw the underside face of a floating segment at 65% brightness.
 
static void _draw_tile_warped (ALLEGRO_BITMAP *bmp, const float vx[4], const float vy[4], int tile_w, int tile_h, ALLEGRO_COLOR tint)
 Draw a tile bitmap warped to 4 pre-computed screen vertices.
 
static ALLEGRO_COLOR _height_tint (int seg_top, int max_height, float intensity)
 Compute a brightness tint color for a segment at a given height.
 
static void _iso_corner_to_screen (float hw, float hh, float tl, int cx, int cy, float fh, float cam_px, float cam_py, float zoom, float *sx, float *sy)
 Project a tile corner to screen coordinates (canonical formula).
 
static int _iso_object_check_occlusion (const ISO_MAP *map, float obj_fx, float obj_fy, float obj_fz, float obj_sx, float obj_sy, float sprite_h, float sprite_half_w, float cam_px, float cam_py, float zoom, float *out_clip_y)
 Check if an object is occluded by tiles drawn in front of it.
 
static float _iso_preset_angle (int preset)
 Get the angle in degrees for a projection preset.
 
static float _smooth_neighbor_h (const ISO_MAP *map, float h_self, int nx, int ny)
 Helper: clamp neighbor height for smooth slope rendering.
 
static int _tile_covers_height (const ISO_MAP *map, int mx, int my, int z)
 Check if a tile has geometry covering height level z.
 
int camera_to_map (MAP **map, int tx, int ty, int x, int y)
 Center Map on given map coordinate, with x & y offset.
 
int camera_to_scr (MAP **map, int x, int y)
 Center Map on given screen coordinate.
 
int create_empty_map (MAP **map, const char *name, int XSIZE, int YSIZE, int TILEW, int TILEH, int nbmaxobjects, int nbmaxgroup, int nbmaxanims, int nbtiles, int nbanims)
 Create an empty map.
 
int draw_map (MAP *map, ALLEGRO_BITMAP *bmp, int destx, int desty, int mode)
 Draw a MAP *map on the ALLEGRO_BITMAP *bmp.
 
int free_map (MAP **map)
 Free the map.
 
int get_value (MAP *map, int type, int x, int y)
 Get a the tilenumber of a cell item.
 
void iso_corner_to_screen (const ISO_MAP *map, int cx, int cy, float fh, float cam_px, float cam_py, float zoom, float *sx, float *sy)
 Project a tile corner to screen coordinates (canonical formula).
 
float iso_diamond_dist (int px, int py, int tile_w, int tile_h)
 Distance from pixel to the diamond edge.
 
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).
 
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).
 
int iso_is_in_diamond (int px, int py, int tile_w, int tile_h)
 Test if pixel (px,py) is inside the isometric diamond.
 
int iso_map_build_draw_order (const ISO_MAP *map, ISO_DRAW_ENTRY *out, int max_entries)
 Build the draw order for segment-sorted rendering.
 
void iso_map_calc_transitions (const ISO_MAP *map, int mx, int my, int *edge_bits, int *corner_bits)
 Compute terrain transition bitmasks for a cell (Article 934).
 
void iso_map_calc_transitions_full (const ISO_MAP *map, int mx, int my, int *edge_bits, int *corner_bits)
 Compute per-terrain transition bitmasks with height filtering.
 
void iso_map_corner_heights (const ISO_MAP *map, int mx, int my, float *h_n, float *h_e, float *h_s, float *h_w)
 Compute average corner heights for smooth tile rendering (Article 2026).
 
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_free (ISO_MAP **map_ptr)
 Free an ISO_MAP and set the pointer to NULL.
 
int iso_map_get_ability (const ISO_MAP *map, int mx, int my)
 Get the ability at a cell.
 
int iso_map_get_height (const ISO_MAP *map, int mx, int my)
 Get the height at a cell.
 
const ISO_TILE_SEGMENTSiso_map_get_segments (const ISO_MAP *map, int mx, int my)
 get per-tile segments.
 
int iso_map_get_terrain (const ISO_MAP *map, int mx, int my)
 Get the terrain type at a cell.
 
ISO_VISIBLE_EDGES iso_map_get_visible_edges (const ISO_MAP *map, int mx, int my)
 Compute which diamond edges of tile (mx,my) need a height border.
 
ISO_VISIBLE_EDGES iso_map_get_visible_edges_segment (const ISO_MAP *map, int mx, int my, int seg_idx)
 Per-segment edge visibility with adjacency + occlusion.
 
float iso_map_interpolate_height (const ISO_MAP *map, float fx, float fy)
 Bilinear height interpolation at fractional map coordinates.
 
void iso_map_lerp_projection (ISO_MAP *map, float dt)
 Smoothly interpolate the projection angle toward the target.
 
ISO_MAPiso_map_load (const char *filename)
 Load ISO_MAP from a binary file.
 
ISO_MAPiso_map_new (int width, int height, int num_terrains, int max_height)
 Create a new height-aware isometric map.
 
void iso_map_randomize (ISO_MAP *map)
 Randomize terrain and height for testing/demo purposes.
 
int iso_map_save (const ISO_MAP *map, const char *filename)
 Save ISO_MAP to a binary file.
 
void iso_map_set_ability (ISO_MAP *map, int mx, int my, int ab)
 Set the ability at a cell.
 
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])
 
void iso_map_set_projection (ISO_MAP *map, int preset, float tile_width)
 Set projection parameters from a preset and tile width.
 
void iso_map_set_projection_custom (ISO_MAP *map, float half_w, float half_h, float tile_lift)
 Set custom projection parameters directly.
 
void iso_map_set_projection_target (ISO_MAP *map, int preset)
 Set the target projection for smooth interpolation.
 
int iso_map_set_segments (ISO_MAP *map, int mx, int my, const ISO_TILE_SEGMENT *segs, int count)
 set per-tile segments on an ISO_MAP.
 
void iso_map_set_terrain (ISO_MAP *map, int mx, int my, int terrain)
 Set the terrain type at a cell.
 
int iso_map_should_transition (const ISO_MAP *map, int mx1, int my1, int mx2, int my2)
 Check if terrain blending should occur between two adjacent cells.
 
int iso_map_should_transition_smooth (const ISO_MAP *map, int mx1, int my1, int mx2, int my2)
 Check if terrain transition should render between two cells (height-aware).
 
void iso_map_smooth_corner_heights (const ISO_MAP *map, int mx, int my, float *h_n, float *h_e, float *h_s, float *h_w)
 Compute smooth corner heights with slope clamping.
 
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_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_mask_tile_to_diamond (ALLEGRO_BITMAP *bmp, int tile_w, int tile_h)
 Mask a tile bitmap to the isometric diamond shape.
 
const char * iso_projection_name (int preset)
 Get the display name for a projection preset.
 
void iso_screen_to_map (const ISO_MAP *map, float screen_x, float screen_y, int *mx, int *my)
 Convert screen pixel coordinates to map 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 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.
 
int load_map (MAP **map, char *filename)
 Load the map from filename.
 
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.
 
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.
 
void n_iso_camera_free (N_ISO_CAMERA **cam)
 Free a camera and set the pointer to NULL.
 
N_ISO_CAMERAn_iso_camera_new (float zoom_min, float zoom_max)
 Create a new 2D isometric camera.
 
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 n_iso_camera_scroll (N_ISO_CAMERA *cam, float dx, float dy)
 Scroll the camera by (dx, dy) world units.
 
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 n_iso_camera_zoom (N_ISO_CAMERA *cam, float dz, float mouse_x, float mouse_y)
 Zoom the camera toward a screen-space point.
 
int save_map (MAP *map, char *filename)
 Save the map to filename.
 
int ScreenToMap (int mx, int my, int *Tilex, int *Tiley, ALLEGRO_BITMAP *mousemap)
 Convert screen coordinate to map coordinate.
 
int set_value (MAP *map, int type, int x, int y, int value)
 Set the value of a cell in a map.
 

Detailed Description

Isometric/axonometric tile engine with height maps, terrain transitions, and A* pathfinding integration.

Author
Castagnier Mickael
Version
2.0
Date
01/03/2026

Definition in file n_iso_engine.c.

Function Documentation

◆ _cmp_draw_entry()

static int _cmp_draw_entry ( const void *  a,
const void *  b 
)
static

Definition at line 1506 of file n_iso_engine.c.

References ISO_DRAW_ENTRY::bottom, ISO_DRAW_ENTRY::mx, and ISO_DRAW_ENTRY::my.

Referenced by iso_map_build_draw_order().

+ Here is the caller graph for this function:

◆ _compute_tile_tint()

static ALLEGRO_COLOR _compute_tile_tint ( int  seg_top,
int  max_height,
float  intensity,
float  ambient_r,
float  ambient_g,
float  ambient_b,
float  dyn_r,
float  dyn_g,
float  dyn_b 
)
inlinestatic

Definition at line 2033 of file n_iso_engine.c.

Referenced by iso_map_draw().

+ Here is the caller graph for this function:

◆ _draw_height_borders()

static void _draw_height_borders ( const ISO_MAP map,
int  mx,
int  my,
int  seg_idx,
int  seg_bottom,
int  seg_top,
int  has_underside_face,
const float  vx[4],
const float  vy[4],
float  lift 
)
static

Draw black border outlines on the diamond edges of an elevated tile.

Rules:

  • Only draws edges where height difference > 1 or neighbor missing.
  • NEVER draws the top vertex (N) where NW and NE edges meet — it is always hidden behind the tile surface itself.
  • At corners E, S, W where two drawn edges meet, they join naturally.
  • Occlusion is handled by painter's algorithm: tiles drawn later (closer to camera) paint over borders of earlier tiles.

Diamond vertices: N=vx[0] (top), E=vx[1] (right), S=vx[2] (bottom), W=vx[3] (left)

Definition at line 2348 of file n_iso_engine.c.

References ISO_VISIBLE_EDGES::draw_ne, ISO_VISIBLE_EDGES::draw_nw, ISO_VISIBLE_EDGES::draw_se, ISO_VISIBLE_EDGES::draw_sw, ISO_VISIBLE_EDGES::draw_underside, iso_map_get_visible_edges_segment(), ISO_VISIBLE_EDGES::neighbor_top_ne, ISO_VISIBLE_EDGES::neighbor_top_nw, ISO_VISIBLE_EDGES::neighbor_top_se, and ISO_VISIBLE_EDGES::neighbor_top_sw.

Referenced by iso_map_draw().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _draw_segment_sides()

static void _draw_segment_sides ( const ISO_MAP map,
float  east_x,
float  east_y,
float  south_x,
float  south_y,
float  west_x,
float  west_y,
int  mx,
int  my,
int  seg_bottom,
int  seg_top,
float  lift,
float  height_brightness,
int  wall_terrain_override 
)
static

Draw cliff side faces for a single segment {seg_bottom..seg_top}.

For ground segments (seg_bottom==0) uses neighbor-aware wall height. For floating segments (seg_bottom>0) draws full segment height.

Definition at line 2123 of file n_iso_engine.c.

References iso_map_get_height(), and iso_map_get_terrain().

Referenced by iso_map_draw().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _draw_segment_underside()

static void _draw_segment_underside ( ALLEGRO_BITMAP *  bmp,
float  base_dx,
float  base_dy,
float  phw,
float  phh,
float  tile_draw_w,
float  tile_draw_h,
int  tile_w,
int  tile_h 
)
static

Draw the underside face of a floating segment at 65% brightness.

The underside is a diamond drawn at the segment's bottom height.

Definition at line 2224 of file n_iso_engine.c.

Referenced by iso_map_draw().

+ Here is the caller graph for this function:

◆ _draw_tile_warped()

static void _draw_tile_warped ( ALLEGRO_BITMAP *  bmp,
const float  vx[4],
const float  vy[4],
int  tile_w,
int  tile_h,
ALLEGRO_COLOR  tint 
)
static

Draw a tile bitmap warped to 4 pre-computed screen vertices.

Uses two textured triangles mapped to the warped diamond shape. Vertices must come from _iso_corner_to_screen for bit-identical shared edges between adjacent tiles.

Definition at line 2067 of file n_iso_engine.c.

Referenced by iso_map_draw().

+ Here is the caller graph for this function:

◆ _height_tint()

static ALLEGRO_COLOR _height_tint ( int  seg_top,
int  max_height,
float  intensity 
)
inlinestatic

Compute a brightness tint color for a segment at a given height.

Higher segments are brighter (closer to white), lower segments are darker.

Parameters
seg_toptop height of the segment
max_heightmaximum height in the map (0 = no scaling)
intensitytint intensity (0.0 = no tint/white, 1.0 = full range)
Returns
ALLEGRO_COLOR to use as multiply tint

Definition at line 2019 of file n_iso_engine.c.

◆ _iso_corner_to_screen()

static void _iso_corner_to_screen ( float  hw,
float  hh,
float  tl,
int  cx,
int  cy,
float  fh,
float  cam_px,
float  cam_py,
float  zoom,
float *  sx,
float *  sy 
)
inlinestatic

Project a tile corner to screen coordinates (canonical formula).

Every screen vertex in the renderer must come from this function so that two tiles sharing a corner get bit-identical screen positions regardless of which tile's draw call is computing the vertex.

The camera offset (cam_px, cam_py) must be integer-snapped pixel offsets computed as floor(cam_x * zoom), floor(cam_y * zoom). This ensures the fractional pixel position of each vertex comes only from (wx * zoom), which is constant per vertex, eliminating sub-pixel aliasing shimmer during camera movement.

Parameters
hwmap->proj.half_w (unzoomed)
hhmap->proj.half_h (unzoomed)
tlmap->proj.tile_lift (unzoomed)
cxcorner X in tile grid (e.g. mx+1 for the East corner)
cycorner Y in tile grid
fhheight (float, supports smooth-height interpolation)
cam_pxinteger-snapped camera pixel X: floor(cam_x * zoom)
cam_pyinteger-snapped camera pixel Y: floor(cam_y * zoom)
zoomzoom factor
sxoutput screen X
syoutput screen Y

Definition at line 2004 of file n_iso_engine.c.

Referenced by _iso_object_check_occlusion(), and iso_map_draw().

+ Here is the caller graph for this function:

◆ _iso_object_check_occlusion()

static int _iso_object_check_occlusion ( const ISO_MAP map,
float  obj_fx,
float  obj_fy,
float  obj_fz,
float  obj_sx,
float  obj_sy,
float  sprite_h,
float  sprite_half_w,
float  cam_px,
float  cam_py,
float  zoom,
float *  out_clip_y 
)
static

Check if an object is occluded by tiles drawn in front of it.

Tests tiles at higher depth (mx+my) in a forward cone to see if any elevated tile's screen area overlaps the object's screen position.

Parameters
mapthe map
obj_fxobject fractional map X
obj_fyobject fractional map Y
obj_fzobject height
obj_sxobject screen X (camera-transformed)
obj_syobject screen Y (camera-transformed)
sprite_hsprite height used for occlusion bounding
cam_pxcamera X offset in pixels
cam_pycamera Y offset in pixels
zoomcurrent zoom
Returns
1 if occluded, 0 if visible

Definition at line 2259 of file n_iso_engine.c.

References _iso_corner_to_screen(), ISO_PROJECTION::half_h, ISO_PROJECTION::half_w, ISO_MAP::height, iso_map_get_height(), iso_map_to_screen(), ISO_MAP::max_height, ISO_MAP::proj, ISO_PROJECTION::tile_lift, and ISO_MAP::width.

Referenced by iso_map_draw().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _iso_preset_angle()

static float _iso_preset_angle ( int  preset)
static

Get the angle in degrees for a projection preset.

Parameters
presetone of ISO_PROJ_CLASSIC, ISO_PROJ_ISOMETRIC, ISO_PROJ_STAGGERED, ISO_PROJ_MILITARY
Returns
angle in degrees

Definition at line 696 of file n_iso_engine.c.

References ISO_PROJ_CLASSIC, ISO_PROJ_ISOMETRIC, ISO_PROJ_MILITARY, and ISO_PROJ_STAGGERED.

Referenced by iso_map_set_projection(), and iso_map_set_projection_target().

+ Here is the caller graph for this function:

◆ _smooth_neighbor_h()

static float _smooth_neighbor_h ( const ISO_MAP map,
float  h_self,
int  nx,
int  ny 
)
inlinestatic

Helper: clamp neighbor height for smooth slope rendering.

If the height difference exceeds smooth_slope_max, return self height (creating a cliff instead of a slope).

Definition at line 1426 of file n_iso_engine.c.

References iso_map_get_height(), and ISO_MAP::smooth_slope_max.

Referenced by iso_map_smooth_corner_heights().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _tile_covers_height()

static int _tile_covers_height ( const ISO_MAP map,
int  mx,
int  my,
int  z 
)
static

Check if a tile has geometry covering height level z.

Returns 1 if any segment of (mx,my) has bottom <= z AND top > z, meaning the tile's wall/surface extends strictly above z. Used for occlusion: a tile drawn later in painter order covers edges of earlier tiles when its wall passes above the edge height.

Requires the occluding tile to be at least 2 height units taller (top > z + 1) so that single-step stairs (+1 per tile) do not suppress the NW/NE borders — the step only partially covers the edge, and painter order handles the overlap visually.

Definition at line 1824 of file n_iso_engine.c.

References ISO_TILE_SEGMENT::bottom, ISO_TILE_SEGMENTS::count, ISO_MAP::height, iso_map_get_height(), iso_map_get_segments(), ISO_TILE_SEGMENTS::segs, ISO_TILE_SEGMENT::top, and ISO_MAP::width.

Referenced by iso_map_get_visible_edges_segment().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: