Skip to content

librity/ft_fractol

Repository files navigation

42 São Paulo - fract-ol

Norminette v3 42 São Paulo License Code size in bytes Lines of code Top language Last commit

A fractal navigator in pure C.


📜 Table of Contents

🧐 About

This is an interactive program that lets you explore the three fractals: The Mandelbrot and Julia sets, and the Newton fractal of the polynomial z^3 - 1. All three produce beautiful geometric structures that repeat themselves over increasing levels of detail.

It also lets you switch between three different color modes (algorithms): Escape-Time, Linear Interpolation and Bernstein polynomials. The first one is the quickest while the last two are the prettiest.

This is my favorite project from the 42 curriculum: I not only learned a lot, I now have a folder full of sick desktop background I can show off. It taught me how to translate mathematical objects and operations into structures and functions. I also learned many different C optimizations, from compiler flags to changes in workflow and logic.

✅ Checklist

Mandatory

  • Compiles with -Wall -Wextra -Werror
  • .linux file (42 Workspaces)
  • Makefile rules: $(NAME) all clean fclean re
  • Follows norminette 3.3.51
  • Should not quit unexpectedly (segmentation fault, bus error, double free, etc.)
  • All allocated heap memory properly freed, no memory leaks.
    • Check memory leaks with valgrind
  • Program name fractol
  • Test in workspaces
  • Turn in Makefile, *.h, *.c , .linux , .gitignore
  • DON’T turn in libs as submodules.
  • Receives the fractal type as arguments
    • Bad arguments: exits properly with a help message
  • Allowed functions:
    • open, close, read, write, malloc, free, perror, strerror, exit
    • All math.h
    • All mlx.h
    • All libft.h
    • Your ft_printf (may be modified)
      • No printf from stdio.h
  • Must use MiniLibX
  • Make must compile without relinking
  • No global variables
  • Renders Mandelbrot
  • Renders Julia
    • Receives Julia factor as arguments
  • Handles zoom with mouse wheel
  • Renders fractals with colors gradients proportional to iterations
  • Smooth window management (minimizing, focus switch, etc.)
  • ESC closes the program cleanly
  • Clicking the window's x button closes the program cleanly
  • Must use MiniLibX’s images (no mlx_pixel_put)

Bonus

  • Render another fractal of your choice
  • Zoom follows mouse position
  • Arrow keys move the view
  • Changes color on keypress

Extra Features

  • Add LERP color mode
  • Add Bernstein polynomials color mode
  • Save to .bmp on keypress
  • Change max_iterations on keypress
  • Change infinity on keypress
  • Add tests with minunit.h
  • Render with threads (optimization).
  • Change julia parameters on keypress
  • Fullscreen mode on keypress
  • Switch fractal on keypress
  • Random colors on keypress
  • Add anti-aliasing

🏁 Getting Started

⚙️ Prerequisites

This will only compile on Linux and FreeBSD.

You will need a C compiler (gcc or clang) and minilibx, an X-Window API in C made by 42 Paris:

# Clone the repo
git clone https://github.com/42Paris/minilibx-linux.git
cd minilibx-linux

# Install dependencies and build
sudo apt install libxext-dev libxrandr-dev libx11-dev libbsd-dev libssl-dev
make

# Copy archive and headers to system path
sudo cp libmlx.a /usr/local/lib/
sudo cp mlx.h /usr/local/include/

# Add pages to man (optional)
sudo mkdir /usr/local/man/man1
sudo cp man/man1/* /usr/local/man/man1/
man mlx

🖥️ Installing

Clone the repo and build with make:

$ git clone --recurse-submodules https://github.com/librity/ft_fractol.git
$ cd ft_fractol
$ make
$ fractol mandelbrot

This should open a new window rendering the mandelbrot fractal. You can also render the julia set (that requires a complex factor), and the Newton fractal of the polynomial z^3 - 1:

$ fractol julia -0.391 -0.587
$ fractol newton

🕹️ Controls

  • Esc or q: Exit program
  • = and -: Zoom in and out
  • Mouse Wheel: Zoom in and out
  • Arrow Keys: Move fractal position
  • Mouse Left Click: Warp to clicked pixel
  • c: Switch color mode
  • l and .: Shift color bases up and down
  • i and k: Increase and decrease iterations
  • t and g: Increase and decrease infinity
  • s: Save viewport to bitmap

🎨 Gallery

and much, much more...

📝 Notes

We can understand the basic workflow of the program from its main.c: all its function behave on the program's highest levels of abstraction.

We have a control structure ctl of type t_fractol where we inject anything that might change during runtime: we have the window size, the mlx instance, window and buffer, rendering params like the maximum number of iterations, and function pointers that allow us to dynamically change which fractal and how color is rendered. We set all its default settings with initialize_params: this ensures that the program won't crash if you forgot to set a param.

The window buffer is mostly handled by minilibx: we just create it in initialize_mlx, then set the color of its pixels and draw it to the window whenever we render a fractal.

In handle_arguments we verify and parse the strings we received from the shell. If the arguments don't match any of the options we exit the program with a help message.

We then initialize_mlx, which safely creates an mlx instance, window and image (a.k.a. the frame buffer). We always check and exit the program if any of the pointers are NULL: Not doing this WILL CRASH YOUR COMPUTER AND IT'S REALLY NOT FUNNY (mine crashed three times during this project). We also set the event handlers with mlx_hooks: this will let us interact with the program with our mouse and keyboard (zoom in/out, move, etc.) We finally render the first frame of the fractal and draw it to the window.

When we run the function mlx_loop we initialize the internal workflow of mlx. It basically listens for events and runs the handlers functions we set. All our handlers do basically the same thing: they change a ctl parameter, then render another frame and draw it to the window.

The renderers is where the magic happens:

  1. Iterate through every pixel in the buffer
  2. Transform it to a complex number (pixel(x, y) = x + y*i)
  3. Run the fractal algorithm on that number
  4. Run the color algorithm on the number of iterations
  5. Draw that color to the buffer's pixel.

The Mandelbrot algorithm iterates the complex number c inside the function Fn(z) = z^2 + c, where F0(z) = 0.

The Julia algorithm is very similar to Mandelbrot's: we iterate the complex number c and factor f inside the function Fn(z) = z^2 + f, where F0(z) = c.

The Newton fractal iterates the Newton–Raphson method over an arbitrary differentiable function (z^3 - 1 in this case) for every pixel on the screen.

🛸 42 São Paulo

Part of the larger 42 Network, 42 São Paulo is a software engineering school that offers a healthy alternative to traditional education:

  • It doesn't have any teachers and classes.
  • Students learn by cooperating and correcting each other's work (peer-to-peer learning).
  • Its focus is as much on social skills as it is on technical skills.
  • It's completely free to anyone that passes its selection process - The Piscine

It's an amazing school, and I'm grateful for the opportunity.

📚 Resources

minilibx

minilibx functions

void	*mlx_init();
void	*mlx_new_window(void *mlx_ptr, int size_x, int size_y, char *title);
int	mlx_clear_window(void *mlx_ptr, void *win_ptr);
int	mlx_pixel_put(void *mlx_ptr, void *win_ptr, int x, int y, int color);
void	*mlx_new_image(void *mlx_ptr,int width,int height);
char	*mlx_get_data_addr(void *img_ptr, int *bits_per_pixel,
			   int *size_line, int *endian);
int	mlx_put_image_to_window(void *mlx_ptr, void *win_ptr, void *img_ptr,
				int x, int y);
int	mlx_get_color_value(void *mlx_ptr, int color);
int	mlx_mouse_hook (void *win_ptr, int (*funct_ptr)(), void *param);
int	mlx_key_hook (void *win_ptr, int (*funct_ptr)(), void *param);
int	mlx_expose_hook (void *win_ptr, int (*funct_ptr)(), void *param);
int	mlx_loop_hook (void *mlx_ptr, int (*funct_ptr)(), void *param);
int	mlx_loop (void *mlx_ptr);
int mlx_loop_end (void *mlx_ptr);
int	mlx_string_put(void *mlx_ptr, void *win_ptr, int x, int y, int color,
		       char *string);
void	mlx_set_font(void *mlx_ptr, void *win_ptr, char *name);
void	*mlx_xpm_to_image(void *mlx_ptr, char **xpm_data,
			  int *width, int *height);
void	*mlx_xpm_file_to_image(void *mlx_ptr, char *filename,
			       int *width, int *height);
int	mlx_destroy_window(void *mlx_ptr, void *win_ptr);
int	mlx_destroy_image(void *mlx_ptr, void *img_ptr);
int	mlx_destroy_display(void *mlx_ptr);
int	mlx_hook(void *win_ptr, int x_event, int x_mask,
                 int (*funct)(), void *param);
int	mlx_do_key_autorepeatoff(void *mlx_ptr);
int	mlx_do_key_autorepeaton(void *mlx_ptr);
int	mlx_do_sync(void *mlx_ptr);
int	mlx_mouse_get_pos(void *mlx_ptr, void *win_ptr, int *x, int *y);
int	mlx_mouse_move(void *mlx_ptr, void *win_ptr, int x, int y);
int	mlx_mouse_hide(void *mlx_ptr, void *win_ptr);
int	mlx_mouse_show(void *mlx_ptr, void *win_ptr);
int	mlx_get_screen_size(void *mlx_ptr, int *sizex, int *sizey);

Fractals

Mandelbrot set

Julia set

Tricorn

Burning Ship

Newton Fractal

OneLoneCoder

Window Viewport

Videos

Math

Luc de Jonckheere’s Thesis

Fractal Software

Map

valgrind

GCC -fsanitize=address -fsanitize=leak

// Won't detect this leak
int	main(void)
{
	void	*ptr;
	ptr = malloc(8);
	return (0);
}

Debug Flag -g

Optimization Flags

Minilibx close window on red cross click

X Server/X11/X Window System

Wayland

Zoom

**GNU Multiple Precision Arithmetic Library**

Nvidia Compute Unified Device Architecture

C Optimizations

Coloring Algorithms

Escape-Time Algorithm

Linear Interpolation (lerp)

Color Gradients

Bernstein polynomials Color

r(t) = 9 ∗ (1t) ∗ t^3255
g(t) = 15 ∗ (1t)^2t^2255
b(t) = 8.5 ∗ (1t)^3t255

Graphic Effects

Anti-Aliasing (NOT A FILTER)

Blur Filters

Anisotropic filters

Bitwise Operations

pthread.h

ft_ftoa, ft_dtoa, ft_ldtoa

sizeof(int): 4
sizeof(long): 8
sizeof(long long): 8
sizeof(float): 4
sizeof(double): 8
sizeof(long double): 16

ft_atof, ft_atold

Norminette-compliant C formatter

Automatically add functions to C header

C Multiline String Literal

C Documenting Functions

C Testing

C Function Pointers

Makefile wildcard foreach patsubst addprefix filter-out

Relinking

Git

Git submodule

Color Inspirations