42 FdF - isometric wireframe renderer in C
  • C 96.1%
  • Makefile 3.9%
Find a file
2026-05-16 21:11:09 +02:00
0_Libft_Gnl init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
1_Srcs init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
demo_maps init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
minilibx-linux@b8de9b4118 init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
.gitignore init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
.gitmodules init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
fil_de_fer.h init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
Makefile init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
program.c init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00
README.md init: fdf wireframe renderer with minilibx submodule 2026-05-16 21:11:09 +02:00

This project has been created as part of the 42 curriculum by clao.

Description

This project is about building the fdf program, creating a simple wireframe model representation of a 3D landscape by linking coordinates (x, y, z) through line segments.

Fil de Fer

The fdf program opens a file of type .fdf with map coordinates written in a specific format, after parsing the coordinates, the program opens a window visualising the map in isometric projection.

User can also use a set of keyboard controls to slightly manipulate the map.

The MiniLibX library is used, a simple programming API designed for those beginning in X-Window programming in C.

Rendering

The coordinates of a landscape are stored in a .fdf file, provided as a command line parameter to the fdf program. Here is an example:

$>cat demo_maps/basictest.fdf
0 0 1 2 3 4 5 6 7 8 9
0 0 0 1 2 3 4 5 6 7 8
0 0 0 0 1 2 3 4 5 6 7
0 0 0 0 0 1 2 3 4 5 6
0 0 0 0 0 0 1 2 3 4 5
0 0 0 0 0 0 0 1 2 3 4
0 0 0 0 0 0 0 0 1 2 3
0 0 0 0 0 0 0 0 0 1 2
0 0 0 0 0 0 0 0 0 0 1

Each number represents a coordinate of the map:

  • The horizontal position corresponds to its abscissa (x).
  • The vertical position corresponds to its ordinate (y).
  • The value corresponds to its altitude (z).

A number can also be followed by a hexadecimal value that represents the color of the corresponding coordinate. For example, 20,0xFF0000 represents a red point of altitude 20.

In order for the map values to be processed by the fdf program, each coordinate's data should be separated by space (' '), and in each data, its altitude value and color value should be separated by a single comma (',').

Instructions

Making the fdf program:

This project uses MiniLibX as a git submodule. Clone the repo with:

git clone --recurse-submodules https://git.ivanlcl.com/ivan/fil-de-fer.git

Or if already cloned:

git submodule update --init

MiniLibX also requires: libXext, libX11, zlib.

Then build:

make

Using the fdf program:

./fdf <the_map_file.fdf>

Keyboard controls:

  • W, S, A, D : to shift the map's view point.
  • T : to change the view to (top view) parallel projection.
  • I : to change the view to isometric projection.
  • J, K : to zoom in/out the view of the map.
  • H, L : to rotate the view point around the map's z axis.
  • Q, E : to change the z values of the map.

Only one single key works at the same time.

Approach

Isometric projection

In a map represented in isometric projection, each of the three axes x, y, z are separated by 120°, where z axis goes straight up, x axis goes to the right and downward by 30°, y goes to the left and downward by 30°.

  • For each step of x, the projected point moves to the right by cos(30°) and downward by sin(30°).
  • For each step of y, the projected point moves to the left by cos(30°) and downward by sin(30°).
  • For each step of z, the projected point moves upward by 1 if positive, downward by 1 if negative.

If a coordinate is (x, 0, 0):

  • The projected point appears at (x * cos(30°), x * sin(30°))

If a coordinate is (0, y, 0):

  • The projected point appears at (y * -cos(30°), y * sin(30°))

If a coordinate is (x, y, z):

  • The projected point's x value equals to (x - y) * cos(30°)
  • The projected point's y value equals to (x + y) * sin(30°) - z

By subtracting z from y, each projected point can move up or down on the z axis according to the coordinate's z value.

At the end, projection is about computing the 3D coordinates into 2D, it simulates a 3D view on a 2D screen.

Scaling the map

To ensure that every map looks "natural" and fits pleasantly within the window upon launch, the program calculates dynamic scaling factors.

  • To prevent high altitudes from over-stretching, altitude values are scaled based on the dimensions of the map and the range between the highest and lowest z points. A reverse proportion is implemented using a gentle logarithmic decay curve.
  • Before drawing, the program simulates the projected coordinates of the map's four extreme corners. These corners are used to determine a proper zoom factor that keeps the map within the window boundaries (minus a defined padding).
  • The program then calculates the necessary x and y offsets to center the map on the window.

Coloring the line segments

If the color values of two coordinates a and b are different, each pixel plotted between the two points has its own color value to represent a gradient.

  • Each pixel's color value is calculated according to its position between a and b: closer to b the pixel, more of b's color fades in, while a's color fades out.
  • A color is visualized through the intensity of three lights: red, green, and blue. Multiplying each light's value to a percentage determines how much the color fades in or out.

If there is no color value provided by the map file, the fdf program renders the map with the default colors defined in the fil_de_fer.h header file.

  • Coordinates with altitude values close to zero are rendered close to the MID color (cyan by default).
  • Coordinates with altitude values above zero and close to the maximum altitude value of the map are rendered close to the TOP color (white by default).
  • Coordinates with altitude values below zero and close to the minimum altitude value of the map are rendered close to the LOW color (blue by default).

Optimization

A few optimizations are implemented to smoothen the performance, especially when using interactive controls.

  • The program uses two separate MiniLibX images to prevent screen flickering when the map is updated during an interaction. The next frame is fully drawn on the off-screen image buffer before being put to the window. Images are swapped for each update.
  • Instead of calculating the isometric and rotation trigonometry for every single coordinate during the drawing loop, these values are precalculated once before each rendering and reused.
  • Before drawing a line segment, the program checks if both the points a and b are outside the window boundaries. If so, the line is ignored. Likewise, only pixels that pass the bounds-check are written to the image memory address.

Resources

AI (Gemini) was used during development as a learning assistant for:

  • Clarifying MiniLibX mechanics, concept of image buffers.
  • Project structuring, by breaking down the project into manageable "baby steps".
  • Understanding the underlying math of isometric projection.
  • Discussing map scaling strategies.
  • Explaining the concept behind RGB color and gradient.
  • Suggestions for performance optimization.

No final code was copy-pasted as-is from AI or the references: all implementations were written, adapted, and tested by me.

References