Skip to main content

Overview

Cub3D is a 3D raycasting engine that renders a first-person perspective game world similar to Wolfenstein 3D. The engine uses the Digital Differential Analysis (DDA) algorithm to cast rays through a 2D grid-based map and render walls with textured surfaces.

Core Components

The system is organized into several functional components:

Map Parser

Validates and loads .cub map files containing textures, colors, and map layout

Raycasting Engine

Implements DDA algorithm to calculate wall intersections and distances

Rendering Pipeline

Converts raycasting data into textured vertical wall slices

Input System

Handles keyboard events for player movement and camera rotation

File Organization

The codebase follows a modular structure with clear separation of concerns:

Main Entry Point

main.c - Program initialization and main loop setup
main.c (lines 74-100)
int	main(int ac, char **av)
{
	t_map	mapa;

	if (ac != 2)
		return (msg(1, ARGERROR), 1);
	if (av[1][0] == '\0')
		return (msg(1, ARGERROR2), 1);
	init_values(&mapa);
	if (ismap(av[1], &mapa) == 1)
	{
		mapa.path = ft_strdup(av[1]);
		if (check3atributtes(&mapa) == 0)
			return (msg(2, "Saliendo...\n"), freeall(&mapa), 1);
	}
	else
		return (msg(1, ARGERROR3), 1);
	cubed_init(&mapa);
	mlx_hook (mapa.win_ptr, 2, KeyPressMask, handle_key, &mapa);
	mlx_hook (mapa.win_ptr, 3, KeyReleaseMask, key_release, &mapa);
	mlx_hook (mapa.win_ptr, DestroyNotify, StructureNotifyMask,
		closewindow, &mapa);
	mlx_loop_hook (mapa.mlx_ptr, cubed_render, &mapa);
	mlx_loop (mapa.mlx_ptr);
	freeall(&mapa);
	return (0);
}

Parsing System

Parses texture paths, floor/ceiling colors from the map file header
  • parsefloorceilingdirections() - Main parsing loop
  • checkatributes() - Validates individual attribute lines
Assigns parsed values to the map structure
  • asign_directions() - Validates and stores texture paths
  • asign_colors() - Validates and stores RGB color values
Map validation and grid parsing
  • ismap() - Validates .cub file extension
  • check3atributtes() - Orchestrates parsing pipeline
  • mapcpy() - Copies map grid from file
Map validation and flood fill
  • checkns() - Validates player starting position
  • flood_fill() - Ensures map is properly enclosed

Raycasting System

raycasting.c - Core DDA implementation
  • raycasting() - Main loop that casts rays for each screen column
  • init_dda() - Initializes ray parameters and step directions
  • perform_dda() - Executes DDA algorithm to find wall hits
  • calculate_wall_data() - Computes perpendicular distance and wall height
  • select_texture() - Determines which texture to use based on ray direction

Rendering System

drawing.c - Converts raycasting data to pixels
  • clear_image() - Clears the frame buffer
  • draw_3d_dda() - Draws ceiling, walls, and floor for a vertical slice
  • draw_wall() - Samples texture data and renders wall column
  • calculate_and_draw_pixel() - Maps texture coordinates to screen pixels
utils7.c - Low-level drawing utilities
  • put_pixel() - Writes a single pixel to the image buffer
  • parse_color() - Converts RGB string to integer color value

Input System

utils5.c, utils6.c, utils7.c - Event handling and movement
  • handle_key() / key_release() - Keyboard event handlers
  • cubed_render() - Main render loop called every frame
  • move_cubed() - Updates player position based on input
  • rotate_cubed() - Updates camera angle
  • is_wall() - Collision detection

MiniLibX Integration

The engine uses MiniLibX, a simple X-Window graphics library for rendering:
1

Initialization

mlx_init() creates the graphics context
2

Window Creation

mlx_new_window() creates a 1732×1000 pixel window
3

Texture Loading

mlx_xpm_file_to_image() loads XPM texture files for each wall direction
4

Image Buffer

mlx_new_image() creates a framebuffer for double-buffering
5

Event Hooks

mlx_hook() registers keyboard and window event callbacks
6

Render Loop

mlx_loop_hook() sets up the continuous rendering loop
7

Display

mlx_put_image_to_window() presents the rendered frame
main.c (lines 51-72)
void	cubed_init(t_map *mapa)
{
	mapa->xx = mapa->y * SIZE + (SIZE / 2);
	mapa->yy = mapa->x * SIZE + (SIZE / 2);
	mapa->speed = 1;
	mapa->key_a = 0;
	mapa->key_w = 0;
	mapa->key_d = 0;
	mapa->key_s = 0;
	mapa->key_left = 0;
	mapa->key_right = 0;
	set_player_dir_and_plane(mapa);
	mapa->floor_color = parse_color(mapa->floorcolor);
	mapa->ceiling_color = parse_color(mapa->ceilingcolor);
	mapa->mlx_ptr = mlx_init();
	load_all_textures(mapa);
	mapa->win_ptr = mlx_new_window(mapa->mlx_ptr, WIDTH, HEIGHT, mapa->name);
	mapa->img_ptr = mlx_new_image(mapa->mlx_ptr, WIDTH, HEIGHT);
	mapa->pixel_ptr = mlx_get_data_addr(mapa->img_ptr, &mapa->bpp,
			&mapa->line_length, &mapa->endian);
	mlx_put_image_to_window(mapa->mlx_ptr, mapa->win_ptr, mapa->img_ptr, 0, 0);
}

Rendering Pipeline

The rendering process follows this sequence each frame:
1

Clear Frame Buffer

clear_image() resets all pixels to black
2

Update Player State

  • Process keyboard input for movement and rotation
  • Update player position (xx, yy) with collision detection
  • Update camera direction vectors (dir_x, dir_y)
  • Update camera plane vectors (plane_x, plane_y)
3

Cast Rays

For each of the 1732 screen columns:
  • Calculate ray direction based on camera position
  • Initialize DDA parameters
  • Step through grid until wall is hit
  • Calculate perpendicular distance to wall
  • Determine wall height on screen
4

Texture Selection

Based on which side of the wall was hit (North/South/East/West), select appropriate texture
5

Draw Column

  • Draw ceiling pixels above wall (sky blue: 0x87CEEB)
  • Sample texture and draw textured wall pixels
  • Draw floor pixels below wall (dark gray: 0x444444)
6

Present Frame

mlx_put_image_to_window() displays the completed frame

Frame Timing

utils6.c (lines 74-91)
int	cubed_render(t_map *mapa)
{
	mapa->new_x = mapa->xx;
	mapa->new_y = mapa->yy;
	move_cubed(mapa, mapa->dir_x, mapa->dir_y);
	rotate_cubed (mapa);
	mapa->map_x = mapa->xx;
	mapa->map_y = mapa->yy;
	if (mapa->starting_angle > 2 * PI)
		mapa->starting_angle = 0;
	if (mapa->starting_angle < 0)
		mapa->starting_angle = 2 * PI;
	set_player_dir_and_plane(mapa);
	clear_image(mapa);
	raycasting (mapa, -1);
	mlx_put_image_to_window(mapa->mlx_ptr, mapa->win_ptr, mapa->img_ptr, 0, 0);
	return (0);
}
The render loop is called continuously by MiniLibX’s event system. There is no explicit frame rate limiting, so rendering speed depends on hardware capabilities.

Main Execution Flow

Configuration Constants

Key constants defined in cub3.h:
ConstantValueDescription
WIDTH1732Screen width in pixels
HEIGHT1000Screen height in pixels
SIZE30Grid cell size (affects movement scale)
POV1.17Field of view multiplier
PI3.14159265358979323846Pi constant for angle calculations
The SIZE constant affects both the map scale and collision detection. Changing it requires adjusting player movement speed and collision thresholds.

Error Handling

The system includes comprehensive error checking:
  • Argument validation: Checks for exactly 2 arguments and .cub extension
  • File validation: Verifies map file can be opened and is not empty
  • Texture validation: Ensures all texture files exist and can be loaded
  • Map validation: Verifies map is closed, contains exactly one player, and has valid characters
  • Memory allocation: Checks all allocations and frees resources on error
  • Color validation: Ensures RGB values are in 0-255 range
All errors print descriptive messages to stderr and exit with status 1.