/fractals

Multithreaded interactive Mandelbrot and Julia viewer built via a library on OpenGL

Primary LanguageC

fractals

This project creates colorful fractals designed to be interacted with through keyboard and mouse events. Like 3d_wireframe, it uses the minilibx library on top of OpenGL to plot images onto the screen.

Mandelbrot: screen shot 2017-08-12 at 4 08 18 pm

Julia: screen shot 2017-08-11 at 6 25 29 pm

Mandelbrot Cube: screen shot 2017-08-11 at 6 27 32 pm

Julia Cube: screen shot 2017-08-11 at 6 31 16 pm

Key Details

The project utilized child processes and multithreading to maintain the fluidity of the program's output. On line 112 in main, a child procress is created via a successful fork. This child process proceeds to run through the rest of the program while the parent process completes the execution of main. Depending on whether the user wants to open more than one fractal at a time, the forking of a new process sits inside a while loop so multiple processes can be created if needed.

screen shot 2017-08-09 at 5 14 21 pm

The next interesting detail is the environment initialization function. The returned environment struct pointer is the program's main data structure. On top of holding the dimensions and figures needed to calculate the graphical image, it also incoporates the data for connecting to the mlx graphics server in the minilibx directory. From lines 74 to 83 in init_env, the struct's varied pointers point to function calls within the source code directory and the minilibx library. For example, the pointers in lines 75 and 81 connect to the mlx functions that create both the window itself and the graphical image that spawns on top of it. Lines 78 to 80 initialize the other struct variables of the project as pointer members of the environment variable. These structs serve as component pieces to be modified from key and mouse events.

screen shot 2017-08-09 at 5 15 24 pm

The details to be examined next are in the the calling function handle_colors on line 78 above. This function matters as it's format served as a template for the other handlers in init_env and it's code demonstrates the coloring procedure as implied by the function's name.

screen shot 2017-08-09 at 5 16 08 pm

After memory is allocated and set for the color struct pointer, it is then passed through 10 coloring functions in rapid and sequential order. Each coloring functions holds an integer array of 24 hard-coded hex values that are based on aesthetic color palettes. Through a simple whileloop, this array of hex values is transfered into the rgb member at an indexed position (9 in the example below) of the color struct pointer. The modular design of the coloring function below is replicated for all 10 coloring functions with the exception of the hex value array.

screen shot 2017-08-09 at 5 16 23 pm

Two other important members of the environment struct pointer are the function pointers to reset_func and redraw_func. These two members contain the project's multithreading aspect and image calculations. The redraw_func function in particular is worth exploring in depth.

screen shot 2017-08-09 at 5 15 38 pm

An array of type pthread_t is created on line 32 of redraw_func. The container stores the multiple threads that calculate the coordinates to be drawn. It is filled through a run of the while loop on line 35 before being terminated with the subsequent while loop on line 38. The rest of the function outputs the determined values and adjusts them after output has been accomplished. On line 36, handle_threads passes back each newly created pthread_t which contains data like the coloring and placement of each coordinate. These coordinates are found by running through all of the x and y values of the entire window and computing the math behind the correct output of each coordinate. The placement of each coordinate follows a simple formula inspired from this wonderful resource below:

http://lodev.org/cgtutor/juliamandelbrot.html

An example of the math behind one of the fractal types (the Mandelbrot set; shortened to simply mand in the function below) can be found in the following snippet:

screen shot 2017-08-09 at 5 17 15 pm

The data type double is used instead of interger due to the more precise nature of the type. The calculations to find the real and imaginary numbers are formulated around the midpoints of the image, the size of the image, and the complex number's relationship to the window size. (Note: the complex numbers for the julia types are based on the horizontal and vertical values of the mouse's position rather than the environment's midpoints. The same formula used with the midpoints is instead used to find the x and y values for the julia types). Afterwards, a loop is run to calculate the new values of x and y. It is broken if the max number of iterations is exceeded or if the combined x and y values exceed a set limit. If the loop breaks from exceeding the set limit, valid coordinates have been found. The preceding function is returned the loop's index (mand's index for this fractal example) and then passes the same index, environment variable, and the valid coordinates to calculate_coordinate.

screen shot 2017-08-11 at 8 55 48 pm

Finally, with the coordinates and colors taken care of, calculate_coordinate combines the two primarily through modulus division on line 21. The calculation takes the index determined from the calculation above and adds it to a predetermined offset. This sum is then modulo by the sum total of colors which results in an index. This new index is stored in an integer array for later data processing and output.

The remainder of this program includes key and mouse hooks that are behind the interactive elements of the project. Please refer to the User Interface in the Features section for an understanding of what these events can do.

Features

The following images are screenshots from exploring the fractals at varied depth and a screenshot of the user interface.

Mandelbrot zoomed with increased iterations:

screen shot 2017-08-11 at 6 35 47 pm

screen shot 2017-08-11 at 8 41 41 pm

Julia zoomed with increased iterations:

screen shot 2017-08-11 at 8 14 04 pm

screen shot 2017-08-11 at 8 36 57 pm

Mandelbrot Cube zoomed with increased iterations:

screen shot 2017-08-11 at 8 17 06 pm

screen shot 2017-08-11 at 8 19 09 pm

Julia Cube zoomed with increased iterations:

screen shot 2017-08-11 at 8 22 02 pm

screen shot 2017-08-11 at 8 23 56 pm

User Interface:

screen shot 2017-08-11 at 9 47 19 pm

Implementation (Mac OSX Sierra)

To run this project, clone this repo into your terminal and generate the executable via the make command.

git clone https://github.com/keenanromain/fractals.git
cd fractals
rm -rf libft
git clone https://github.com/keenanromain/libft.git
cd libft
make
cd ..
make

A successful make command will create an executable called 'fractol'. To see the proper usage, run this executable from the fractals root directory like such:

./fractol

Following the usage specifications, choose one or a combination of your prefered fractal types to run.

Acknowledgement

This project was developed at École 42 USA in Fremont, California.