Skip to content

Data Structures

The engine is small enough that the main data model can be described directly. What matters most is not just which structs exist, but which ones own long-lived state, which ones are temporary, and which modules are allowed to mutate them.

Runtime ownership

Global owner, local temporaries, and per-module mutation rules

The engine relies on a small set of core structs. `t_app` owns the runtime, temporary structs stay local to parsing or rendering, and each subsystem only mutates the part of the state it is responsible for.

01
`t_app` is the global runtime owner

Allocated on the stack in `main`, initialized by `init_app`, released by `free_app`.

t_config config owns
t_map map owns
t_player player
t_input input
void * mlx_ptr / win_ptr MLX
t_img frame MLX
t_img tex_no / tex_so / tex_we / tex_ea MLX
int win_w / win_h · floor_color / ceiling_color
double dir_x/y · plane_x/y
double delta_time · last_frame_time
t_bonus_ctx bonus bonus
mutation policy

render writes frame buffers, input writes player/camera, parsing writes config/map, bonus writes `app->bonus.*` only

lifetime

`init_app` → parsing → MLX init → loop → `free_app`

02
temporary structs never become global state

These structs exist only for a local stage, then disappear.

t_ray stack · one column · discarded after draw
double ray_dir_x / ray_dir_y
int map_x / map_y
double delta_x / delta_y
double side_x / side_y
int step_x / step_y
int side
double perp_dist
int draw_start / draw_end

lifetime = one rendered column

t_parse_headers stack · parse_file only
char ** lines
int line_count
int * map_start
const char * map_path
t_bfs_context heap temp · validation only
char ** lines / visited
int * qx / qy
t_size qcap / head / tail
int px / py / leak / alloc_fail
03
persistent runtime structs

These types stay alive across many frames and define the runtime surface of the engine.

t_map owned by t_app
char ** grid
int height
t_player spawn + movement state
double x / y
char orientation
t_input per-frame intent state
int forward / backward / left / right
int turn_left / turn_right
int mouse_dx / mouse_last_x / mouse_ready
t_img MLX image wrapper
void * img_ptr
char * addr
int bpp / line_len
int width / height / endian
t_bonus_ctx embedded in t_app
t_bonus_assets assets
t_bonus_retro retro
t_bonus_doors doors
t_bonus_levels levels
t_bonus_pickups / t_bonus_sprites pickups / sprites
t_bonus_stats / t_bonus_hud stats / hud

bonus subsystems mutate only their own sub-structs

04
module-level write rules

Clear write boundaries keep the codebase defendable and reduce accidental coupling.

render

writes `frame.addr`, reads most of the rest

input

writes `input`, `player.x/y`, and `dir/plane`

parsing

writes config strings and `map.grid`

bonus

writes only `app->bonus.*` and reads shared world state

The most important types in the current codebase are:

  • t_app
  • t_ray
  • t_map
  • t_player
  • t_input
  • t_img
  • bonus runtime structs grouped under t_bonus_ctx

Together they define ownership, per-frame state, and render-local working data.

t_app is the runtime owner.

It is:

  • created on the stack in main
  • initialized by init_app
  • filled progressively during startup
  • released by free_app

That is why parsing, rendering, bonus systems, and cleanup all converge on the same root object.

Not every struct should live for the whole runtime.

Examples of temporary data:

  • t_ray for one rendered column
  • parse context structs used only during parsing
  • BFS validation context used only during map closure checks

Examples of persistent runtime data:

  • map storage
  • player state
  • input state
  • MLX images
  • bonus subsystem state

This distinction keeps ownership clear.

The codebase stays understandable because write access is effectively scoped by subsystem:

  • parsing writes config and final map storage
  • validation writes the discovered player spawn before vector initialization
  • input updates movement and camera state
  • render writes frame buffers
  • bonus modules mutate only bonus-owned runtime state

That keeps side effects localized and easier to explain.

This structure model matters during evaluation because it answers three questions cleanly:

  1. who owns the data
  2. how long does it live
  3. who is allowed to mutate it

That is usually more useful than listing every field mechanically.

  • include/structs.h
  • include/structs_bonus.h
  • srcs/core/init_app.c
  • srcs/render/raycast.c
  • srcs/validation/validate_closed_setup.c