Skip to content

Architecture Overview

This codebase is easiest to read as a layered architecture. Each layer owns a clear responsibility, and control flow moves through them in a fixed order from startup to shutdown.

System structure

Six layers around one runtime owner and one frame loop

This architecture is easiest to understand as layered responsibilities: bootstrap, parsing, runtime state, input/update, rendering, then cleanup. The control flow crosses those layers in a strict startup-to-shutdown order.

01
architectural layers

Each layer has a clear job and a clear file namespace in the repository.

1 Bootstrap

entrypoint, CLI validation, startup sequencing, and loop setup

main.cinit_app.c
2 Parsing & Validation

config parsing, map loading, duplicate checks, and closure validation

parse_file.cparse_config.cparse_textures.cparse_colors.cparse_map.cvalidate_map*.c
3 Runtime State

`t_app`, player vectors, MLX handles, frame image, and bonus runtime ownership

structs.hinit_app.cinit_mlx.c
4 Input & Update

keyboard, mouse, movement, collision, rotation, and per-frame state updates

input_keys.cinput_mouse.cinput_update.cmove_player.cmove_collision.crotation.c
5 Raycasting & Render

background, DDA traversal, wall projection, texture draw, overlays, and final present

render_frame.craycast.craycast_draw.cdraw_vignette.c
6 Cleanup & Errors

centralized shutdown, guarded destruction, and explicit error reporting

shutdown.cerror.cmemory.c
02
control flow from startup to shutdown

The runtime sequence is linear until the loop starts, then repeats through `draw_frame(...)`.

1 main(argc, argv) CLI
2 init_app(&app) NULL init
3 bonus_levels_init(&app) bonus
4 parse_file(&app, path) parsing
5 init_player_vectors(&app) player
6 init_mlx(&app) MLX alloc
7 mlx_hook × 5 hooks
8 mlx_loop_hook(draw_frame) loop
9a timing + input + bonus update draw_frame
9b background + raycast + overlays draw_frame
9c vignette + HUD + mlx_put_image draw_frame
10 close_window -> free_app -> exit shutdown
03
cross-layer invariants

These rules are what make the architecture coherent instead of just “folder names”.

parsing finishes before MLX init

invalid maps never reach window or texture initialization

`t_app` is the runtime owner

persistent state and resource cleanup converge on one root object

mandatory and bonus share one runtime flow

bonus features integrate through modules and no-op safe fallbacks

`free_app(...)` covers all exits

startup failure, runtime close, and fatal exits rely on the same cleanup model

one final image blit per frame

render writes to buffers first, then presents once through MLX

The current codebase is organized around six practical layers:

  1. bootstrap
  2. parsing and validation
  3. runtime state
  4. input and update
  5. raycasting and rendering
  6. cleanup and errors

That split mirrors the execution order of the engine.

The bootstrap layer starts in main.c.

Its job is to:

  • validate CLI arguments
  • initialize the global app state
  • prepare bonus level context
  • resolve the active map path
  • launch parsing and graphics initialization
  • bind MLX hooks and enter the loop

The parsing layer transforms raw .cub text into validated runtime data.

It is responsible for:

  • reading the file
  • parsing required headers
  • detecting duplicates or malformed values
  • validating map symbols and enclosure
  • producing the final map storage

This stage completes before MLX initialization starts.

The ownership root is t_app.

It contains:

  • parsed config
  • validated map
  • player position and camera basis
  • MLX handles and images
  • mandatory textures
  • bonus runtime state

That is why both rendering and cleanup can stay centralized.

Once startup succeeds, the runtime loop repeatedly:

  1. updates timing and input
  2. updates bonus systems
  3. renders world content
  4. draws overlays
  5. presents one final image

So the architecture is shaped both by file boundaries and by frame lifecycle.

The last layer centralizes shutdown and error handling.

That includes:

  • explicit error reporting
  • ordered MLX teardown
  • map/config release
  • bonus shutdown delegation
  • normal close handling

That is what keeps partial init failures and runtime exits manageable.

  • srcs/core/main.c
  • srcs/parsing/
  • srcs/validation/
  • srcs/input/
  • srcs/render/
  • srcs/core/shutdown.c
  • srcs/tools/utils.c