cub3D is a 3D graphics engine inspired by classic shooters like Wolfenstein 3D. This project introduces raycasting algorithms and real-time graphics programming, creating a dynamic 3D representation of a 2D maze from a first-person perspective using trigonometry, geometrics, and efficient rendering techniques.
![]() |
![]() |
![]() |
![]() |
Our implementation prioritizes a solid, highly configurable graphics engine with a clean architecture that separates simulation from rendering, enabling real-time experimentation with rendering techniques and in-game configuration. We've integrated performance optimizations to maintain high FPS rates, and built an advanced physics system. This foundation allows seamless addition of new features—sprites, dynamic lighting, AI—without compromising performance.
- ✅ Map validation ensuring proper maze structure and player positioning
- 📄 Support for
.cubfile format with texture and color configuration - 🧭 Player starting position and orientation detection (N/S/E/W)
- 🎨 Color parsing for floor and ceiling with RGB values
- 🎯 Real-time 3D rendering using raycasting
- 🎯 DDA algorithm for efficient ray-wall intersection calculations
- 🧱 Textured walls with support for different textures based on wall orientation (North, South, East, West)
- 🎨 Customizable floor and ceiling colors
- 🕹️ Player movement with WASD keys and sprint mode
- 🗺️ Minimap display for navigation assistance
- 🧱 Wall collision detection to prevent walking through walls and ensure realistic movement
- 🖱️ Mouse look clamped to prevent unnatural rotations and configurable sensitivity
- 🎥 Pitch control with up/down arrow keys and mouse vertical movement
- 🔄 Toggle raycasting, textures, fish-eye correction, distance mode and FOV
- 🗺️ Minimap with zoom and optional ray display for better spatial awareness
- 🖱️ Mouse control with sensitivity adjustment and toggle for personalized experience
- 🎚️ Adjust player volume, enhancing immersion
- 🖥️ Terminal info log for all configuration changes, providing feedback on enabled/disabled features and current settings.
- 🔄 Configurable rendering modes for performance
- 🖥️ FPS display and frame timing for performance monitoring
- ⚡ Performance optimizations in base behavior including operation reduction and local variable usage for stable, consistent frame rates
- 🏎️ Boost mode with low-level process and memory management enhancements (x2.5 FPS rate improvement)
- 🏛️ Architecture with simulation and rendering separation
- ⚙️ Configurable Advanced physics system for deterministic movement and interactions, independent of framerate
- 🎯 2D plane acceleration and deceleration with per-axis control
- 🪐 Multiple gravity modes (Ground, Moon, Jupiter, Spectre, Jetpack)
- 📍 Jump direction preservation and flight mode
- 🧍 Crouch and prone position support
- 🌫️ Configurable Atmospheric effects with fog and desaturation shaders featuring multiple modes
- 🧱 Bonus textures for walls
- 🎨 Custom Maps and Textures with personalized visual configurations and styling options
cub3D/
├── inc/ # Main headers
├── src/ # Source code
│ ├── ambiances/ # Fog, shaders, and atmosphere presets
│ ├── bridge/ # Data transfer between parsing and runtime
│ ├── events/ # Keyboard/mouse input handlers
│ ├── mains/ # Program entry point
│ ├── mem_utils/ # Memory-optimized helpers
│ ├── mlx_init_close/ # MLX init/teardown and setup
│ ├── moves/ # Player movement and physics updates
│ ├── parsing/ # .cub file parsing and validation
│ └── render/ # Raycasting and 2D/3D rendering
├── libs/ # Third-party libs
│ ├── libft/ # Utility library
│ └── minilibx-linux/ # MiniLibX (graphics library)
├── assets/ # Game assets
│ ├── maps/ # Sample maps
│ └── textures/ # Project textures
├── textures/ # Linked textures for parsing
├── docs/ # Documentation and media
└── Makefile # Build rules
You can view the complete project architecture and ask an AI about the code here: https://deepwiki.com/alcarril/cub3D/1-overview
- Linux with X11 (Xlib, Xext, Xfixes) and zlib.
ccandmake.- MiniLibX: a simple graphics library for window management and drawing, included as a submodule in this repository.
- Libft: self custom C library with utility functions, included in this repository.
sudo apt-get update
sudo apt-get install gcc make xorg libxext-dev libbsd-dev libxfixes-devgit clone https://github.com/alcarril/cub3D.git
cd cub3D
git submodule update --init --recursivegit clone --recurse-submodules https://github.com/alcarril/cub3D.git
cd cub3Dmake./cub3D assets/maps/good/self/performance.cubControls are handled through keyboard and mouse events captured by the X11 library via MiniLibX, allowing real-time configuration of the graphics engine, frame display, physics behavior, and overall gameplay experience.
| Category | Key | Action |
|---|---|---|
| Movement & Camera | W, A, S, D |
Move player |
| Movement & Camera | Arrow keys | Rotate camera / look up & down |
| Movement & Camera | Left Shift |
Sprint |
| Movement & Camera | Space |
Jump (physics enabled) |
| Movement & Camera | Left Ctrl |
Crouch (physics enabled) |
| Movement & Camera | Caps Lock |
Ground pound (physics enabled) |
| Movement & Camera | Q |
Flight mode (physics enabled) |
| Graphics | O |
Raycasting on/off |
| Graphics | T |
Textures on/off |
| Graphics | F |
Fish-eye correction on/off (textures off) |
| Graphics | E |
Euclidean / perpendicular distance (textures off) |
| Graphics | C |
Boost render mode |
| Display & Mouse | M |
Minimap on/off |
| Display & Mouse | R |
Rays on minimap on/off |
| Display & Mouse | + / - |
Minimap zoom in / out |
| Display & Mouse | J |
Mouse control on/off |
| Display & Mouse | Mouse wheel | Adjust mouse sensitivity |
| Display & Mouse | , / . |
Decrease / increase player volume |
| Environment | U |
Atmospheres on/off |
| Environment | 1 .. 4 |
Select atmosphere |
| Physics | P |
Physics system on/off |
| Physics | K |
DukeDoom mode |
| Physics | 6 .. 0 |
Gravity modes |
Note: All controls can be viewed in the terminal, where a log is recorded when they are enabled or disabled.
Map files must have a .cub extension and follow this structure:
NO textures/path/to/north_texture.xpm
SO textures/path/to/south_texture.xpm
WE textures/path/to/west_texture.xpm
EA textures/path/to/east_texture.xpm
F 220,100,0
C 225,30,0
111111111111
100000000001
100000S00001
111111111111
- Texture paths: NO (North), SO (South), WE (West), EA (East)
- Floor color: F R,G,B (RGB values 0-255)
- Ceiling color: C R,G,B (RGB values 0-255)
- Map grid:
1: Wall0: Empty spaceN/S/E/W: Player starting position and orientation
Raycasting is the core rendering technique used in this project, allowing us to create a 3D perspective from a 2D map by casting rays from the player's position and calculating their intersections with walls. This method is efficient for rendering simple 3D environments and is the basis for many classic games like Wolfenstein 3D and Doom. It uses mathematical concepts such as trigonometry and geometry to determine how rays interact with the environment, enabling the engine to render walls, floors, ceilings, and textures in real time.
The Digital Differential Analyzer (DDA) algorithm is a method for calculating the intersection of rays with a grid-based map, which is essential for raycasting.This allows the engine to efficiently determine where rays hit walls and how to render them on screen, making it a fundamental part of the raycasting process.
- Grid-based only: Works exclusively in discrete and Euclidean spaces; not suitable for continuous or complex geometries.
- Efficient complexity: Reduces complexity to O(1) per step, though total steps can be high for large maps or long walls—without precision loss.
- Multi-step process: Consists of several sequential steps to trace the ray through the grid.
When textures are disabled, the engine can switch between Euclidean distance (straight-line distance from player to wall) and perpendicular distance (distance along the ray's path). The latter is used for fish-eye correction, which eliminates distortion by ensuring that walls appear straight regardless of the viewing angle, providing a more realistic perspective.
Note: 📝 More on raycasting, DDA, and fish-eye correction: Our Notion article.v
To render the minimap, a 2D scaling relationship is established between the window's pixel matrix dimensions and the map's grid dimensions. This scaling is then applied to each point drawn on the minimap, leveraging 2D set rendering logic to efficiently map world coordinates to screen space.
- Grid-to-screen transformation: Converting map grid positions to minimap screen coordinates using the scaling factor
- Set-based filtering: Efficiently filtering map cells to determine visibility within the minimap bounds
- Coordinate clamping: Ensuring all rendered points remain within valid screen boundaries
- Cell type detection: Each scaled point is checked to determine if it belongs to a wall or floor cell
- Color assignment: Walls and floors are rendered with distinct colors for clarity
- Dynamic translation: Points are translated based on zoom level and player position to keep the player centered
- Ray visualization: Rays are drawn using the same scale and translation as the map, with a distinctive color for differentiation
- Adaptive rendering: The minimap adjusts dynamically to window size and map dimensions while maintaining spatial accuracy and visual clarity
Note: 📝 More on 2D rendering sets and minimap: Our Notion article.
Mouse control is implemented by capturing mouse movement and translating it into camera rotation. The system prioritizes low-latency, consistent input handling through polling rather than event-based callbacks.
Why polling instead of event queues? Event-based systems process input through MiniLibX's event queue, which introduces latency that can exceed frame time, causing inconsistent camera responsiveness. Polling the mouse position every frame ensures input is processed synchronously with the render loop, delivering predictable, low-latency control that matches modern shooter games.
Key features:
- Polling-based tracking: Mouse position is queried each frame rather than handled through event hooks, reducing input latency and jitter
- Frame-synchronized input: Direct synchronization with the render loop eliminates queue-based delays
- Pixel clamping: Mouse movement is clamped to a maximum pixel delta per frame, ensuring consistent rotation speed regardless of window dimensions
- Center reset: The mouse cursor is repositioned to the screen center after each frame, preventing the player's wrist from leaving the mousepad
- Configurable sensitivity: Mouse sensitivity is fully adjustable to suit individual player preferences
- Toggle control: Mouse look can be enabled or disabled with J, allowing players to switch between mouse and keyboard control as needed
Note: 📝 First MLX API usage and event handling example: Fractol repo.
When boost mode is enabled, low-level optimizations are applied to critical render loops and buffer filling operations, achieving performance improvements of up to 2.5x in frame rate.
When rendering an image, there are certain functions that are called once per pixel. For example, in a window of 1280 × 720 pixels, a function would be called around 900,000 times per frame. These highly-repeated loops are called hot loops.
Hot loops are loops that execute millions of times per second in performance-critical code across graphics engines, real-time simulations, physics, machine learning, and data processing systems. Because they run so frequently, every CPU cycle counts, small inefficiencies drastically reduce performance and optimizing hot loops is essential for achieving high FPS rates in realtime applications.
| Optimization | Description |
|---|---|
| Pointer indirections | Causes cache misses, breaks prefetching, increases RAM latency |
| Frequent cache misses | Reduce throughput, fill pipelines with NOPs, cause stalls |
if statements in hot loops |
Unpredictable branches can hurt branch prediction and pipeline efficiency; deterministic input may still be OK |
| Function pointers | Increase call overhead and cache misses; worse than deterministic ifs |
| Misaligned multiplications | Misaligned memory accesses → inefficient, more cache misses, reduces vectorization |
| Function calls | Stack/register overhead, breaks pipeline optimization, reduces vectorization |
| Calls saturating the I-cache | Many scattered instructions → lower throughput, I-cache pressure |
| Heavy divisions and multiplications | Slow operations → may stall hot loops |
| Optimization | Description |
|---|---|
| Memory alignment | Enables contiguous and predictable access, reduces cache misses, supports SIMD and vectorization |
| Contiguous memory / Struct of Arrays (SoA) | Facilitates prefetching, efficient cache line loading, enables SIMD and vectorization |
| Prefetching | Brings data into cache ahead of time, keeps pipeline full, supports vectorization and SIMD |
| SIMD | Processes multiple data elements per instruction, increases throughput, requires aligned and contiguous data |
| Vectorization | Converts scalar operations into block operations, depends on alignment, contiguity, and prefetching |
| Loop unrolling | Reduces loop control overhead, allows SIMD/vectorization to be more effective |
| Use of registers and local variables | Reduces memory accesses, keeps data close to the CPU, accelerates hot loops and vectorization |
| Microprocessor performance improvements | Takes advantage of modern CPU enhancements like larger caches, better branch prediction, higher clock speeds, and SIMD/vector units |
Note: 📝 More on CPU: Our Notion article.
Note: 📝 More on processor optimizations: Our Notion article.
Instead of writing memory byte-by-byte, this implementation fills memory using larger aligned blocks that match cache lines and pages, allowing modern CPUs to write much faster. By aligning the destination pointer, expanding the fill value into larger patterns, and writing progressively smaller blocks only when needed, this approach reduces write operations and improves CPU and cache efficiency.
| Optimization | Description |
|---|---|
| Memory alignment | Aligns the destination pointer to 64-byte cache line boundaries to avoid unaligned writes and cache penalties. |
| Pattern expansion | Expands the input int value into long and long long patterns to write multiple bytes per instruction. |
| Large block writes | Fills memory using the largest possible blocks first (4 KB pages, 64-bit, 32-bit, then bytes). |
| Loop unrolling | Unrolls inner loops to reduce branching overhead and improve instruction-level parallelism. |
| Cache & TLB efficiency | Page-sized writes improve cache utilization and reduce TLB misses. |
| Linear control flow | Uses a single iterative flow to minimize function calls and branch mispredictions. |
| Tail handling | Handles remaining bytes with progressively smaller writes to ensure correctness. |
Note: 📝 More on Memory Fill: Our Notion article.
The architecture of our game engine is designed to be modular, efficient, and scalable, with a clear separation between the simulation (game logic, physics, world state) and the renderer (visual representation). This separation allows for independent development and optimization of each component, enabling us to maintain a clean codebase and easily add new features without disrupting existing functionality.
| Principle | Description |
|---|---|
| Simulation vs Rendering | Simulation updates world state; renderer displays resolved state independently |
| Determinism | Fixed timestep ensures reproducible behavior across hardware |
| Parallelism | Logic, physics, and rendering run separately for better resource distribution |
| Modularity | renderer_t abstraction allows swapping MiniLibX, SDL2, OpenGL, or Vulkan without disruption |
flowchart LR
A[frame start] --> B[mouse input]
B --> C[player movement]
C --> D{raycasting on?}
D -- yes --> E[throw rays]
D -- no --> K[skip 3D]
E --> F{textures + ambiance?}
F -- yes --> G[render floor/ceiling amb]
F -- no --> H{boost + mouse seen?}
H -- yes --> I[render floor/ceiling speed]
H -- no --> J[render floor/ceiling]
G --> L[render walls]
I --> L
J --> L
L --> M{textures on?}
M -- yes --> N{ambiance on?}
N -- yes --> O[render walls ambiance]
N -- no --> P{boost on?}
P -- yes --> Q[render walls tex speed]
P -- no --> R[render walls tex]
M -- no --> S[render walls no textures]
O --> T
Q --> T
R --> T
S --> T
K --> T
T{minimap on?} -- yes --> U[render minimap]
T -- no --> V[swap buffer]
U --> V
Note: 📝 More on Architecture: Our Notion article.
The physics system manages movement and interactions through discrete real-time simulation, ensuring deterministic, framerate-independent behavior.
Core Features:
- 2D Acceleration/Deceleration – Responsive movement with configurable forces
- Per-Axis Control – Independent forces for strafing and external interactions
- Z-Axis Movement – Jump and gravity with multiple profiles
- Jump Preservation – Initial direction maintained with parabolic motion an air deceleration
- Flight Mode – Free 3D movement
- Crouch/Prone – Camera height adjustment and speed reduction for stealth mechanics
| Key | Gravity Mode | Description |
|---|---|---|
6 |
Ground | Standard Earth gravity |
7 |
Moon | Reduced gravity (1/6 of Earth) |
8 |
Jupiter | Increased gravity (2.5x Earth) |
9 |
Spectre | Zero gravity |
0 |
Jetpack | Upward thrust |
Note: 📝 More on physics and movement: Our Notion article.
The engine includes configurable atmospheric effects that can be toggled on/off with U and switched between different modes using keys 1 to 4. These effects enhance visual immersion by simulating various environmental conditions:
| Key | Atmosphere | Recommended Use | Fog (color/profile) | Max Distance |
|---|---|---|---|---|
1 |
ASTURIAS | Open fields | Light medium gray, moderate fog | 0.7x map |
2 |
CEMETERY | Enclosed/medieval spaces | Dark medium gray, dense fog | Medium distance |
3 |
OPEN | Outdoor with sunlight | Dark medium gray (walls) and light (floor/ceiling), light fog | 0.9x map |
4 |
MATRIX | Digital environments | Green, moderate fog | 0.7x map |
Warning: Atmospheric effects significantly reduce engine performance due to required mathematical calculations. Modern engines typically use lookup tables and/or parallelize these calculations across threads.
- 🖼️ Textured floor and ceiling rendering
- 🪟 Render mode for narrow corridors
- 🎭 Sprite system and animations
- 🤖 Basic enemy and NPC AI
- 📊 HUD with health, ammunition, and status information
- 💥 Damage system, weapons, and interactive objects
- 💨 Wind system, collision interactions, and external environmental factors affecting the player
| Futuristic | |
|---|---|
![]() |
![]() |
| Lego | |
![]() |
![]() |
| Matrix | |
![]() |
![]() |
| Moon | |
![]() |
![]() |
| Iglu | |
![]() |
![]() |
| Mazmorra | |
![]() |
![]() |
| Find Translator | |
![]() |
![]() |
| CPU | |
![]() |
![]() |
| Bonus Texture | |
![]() |
![]() |
| Wolf Bunker | |
![]() |
![]() |
- https://www.dmae.upct.es/~plgomez/archivos%20docencia/teoria16-17/tema4-euclideo-a.pdf
- https://www.3blue1brown.com/lessons/vectors
- https://www.universoformulas.com/matematicas/trigonometria/razones-trigonometricas/
- https://www.superprof.es/apuntes/escolar/matematicas/trigonometria/razones-trigonometricas-3.html
- https://www.geogebra.org/m/pyPGsGVc
- https://www.superprof.es/diccionario/matematicas/geometria/triangulos-semejantes.html
- https://lodev.org/cgtutor/raycasting.html
- https://alotroladodeltelefonoblog.wordpress.com/2022/08/27/la-matematica-tras-el-raycasting-parte-1/
- https://alotroladodeltelefonoblog.wordpress.com/2022/09/09/la-matematica-tras-el-raycasting-parte-2/
- https://splashkit.io/guides/physics/8-3d-projection-raycasting/
- https://www.youtube.com/watch?v=ebzlMOw79Yw
- https://www.youtube.com/watch?v=NbSee-XM7WA&t=1400s
- https://www.youtube.com/watch?v=gYRrGTC7GtA
- https://www.youtube.com/watch?v=g8p7nAbDz6Y
- https://www.youtube.com/watch?v=Yt0Ovv2-5cI&si=gIG8nU31eDPryYO7
- https://www.youtube.com/shorts/TEbIfbmJSwo
- 🧑💻 Alejandro Carrillo (alcarril) - https://github.com/alcarril
- 🧑💻 Carlos Arbon (carbon-m) - https://github.com/GranCAM
This project is licensed under the MIT License - see the LICENSE file for details.
MIT























