fracwall

This fractal wallpaper generator creates a bitmap file depicting either the Mandelbrot or the Julia set
Log | Files | Refs | README | LICENSE

commit a0a6428dcaf83c72b280bbb28b2e550482480d60
Author: M. Yamanaka <myamanaka@live.com>
Date:   Wed, 17 Feb 2021 00:44:06 -0500

upload of fractal wallpaper generator

Diffstat:
ALICENSE | 20++++++++++++++++++++
AMakefile | 19+++++++++++++++++++
AREADME | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.c | 43+++++++++++++++++++++++++++++++++++++++++++
Aconfig.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afracwall.c | 36++++++++++++++++++++++++++++++++++++
Ajuliamath.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ajuliamath.h | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 432 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2021 M. Yamanaka <myamanaka@live.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Makefile b/Makefile @@ -0,0 +1,19 @@ +# Fractal Wallpaper Makefile +# "Makefile" +# M. Yamanaka +# email: myamanaka@live.com +# website: csmyamanaka.com +# license: MIT (See included "LICENSE" file for details) + +FILES=fracwall.c juliamath.c config.c +FIOPPDIR=$(HOME)/.local/repos/fileiopp +FILEIOPP=$(FIOPPDIR)/fileiopp.o +OUT=FracWall + +all: $(OUT) + +$(OUT): $(FILES) $(FILEIOPP) + gcc $^ -I$(FIOPPDIR) -o $@ + +clean: + rm -f *.o $(OUT) *.bmp diff --git a/README b/README @@ -0,0 +1,59 @@ +Fractal Wallpaper Generator +"fracwall" +M. Yamanaka +email: myamanaka@live.com +website: csmyamanaka.com +license: MIT (See included "LICENSE" file for details) + +Description: +============ +Have you just installed Arch Linux and your favourite window manager? Have you installed all the programs +you need to make your workflow precisely how you like it? Don't like downloading random wallpapers from the +internet but still want something epic to compliment your desktop setup? Why not make your own? +The fractal wallpaper generator allows you to create a bitmap image of a complex fractal (Mandelbrot or Julia) +so that you can add a homemade, and may I say, sophisticated looking wallpaper to decorate your awesome setup. + +Acknowledgment: +=============== +I found the following two videos by the youtube channel "The Mathemagicians' Guild" extremely helpful +in understanding the mathematical background of the Mandelbrot and Julia sets. + [1] "The Mandelbrot Set Explained" <https://www.youtube.com/watch?v=7MotVcGvFMg> + [2] "Julia Sets, and how they relate to The Mandelbrot Set" <https://www.youtube.com/watch?v=dctJ7ISkU-4> + +Additionally, I have employed a design concept from Suckless Software <https://suckless.org> +where the configuration file is a component of the source code. +Please note, that unlike your typical Suckless software, I use a source and header for the configuration (i.e. there is a config.c and a config.h). +The file to edit it "config.c". +Please DO NOT edit "config.h"! + +Dependencies: +============= +File IO ++ "fileiopp" from my repositories <git.csmyamanaka.com/fileiopp> + +Installation: +============= +Edit the Makefile included in fracwall so that the "FIOPPDIR" variable points to the fileiopp directory. + +After that, compile the program with + + make + +Uninstall: +========= +Get rid of binaries, *.o, and *.bmp files with + + make clean + +Usage: +====== +Edit the configuration file, "config.c", to your liking by modifying variables corresponding to screen size, +complex number plane render window, Julia set fractal parameters, etc. + +Run the compiled program with + + ./Fracwall + +This creates a bitmap file ("wallpaper.bmp" by default) which can then be set as a desktop wallpaper +using hsetroot for example. + + diff --git a/config.c b/config.c @@ -0,0 +1,43 @@ +/* + Configuration File Source + "config.c" + M. Yamanaka + email: myamanaka@live.com + website: csmyamanaka.com + license: MIT (See included "LICENSE" file for details) +*/ + +#include "config.h" + +/* + This is the config file to edit. + + While I am definitely borrowing from Suckless's design principles, + I am still dividing the source from the header. + + If I may say so myself, I believe that the variable names are sufficiently + descriptive but if not, the description of the variables are available in + the header file, "config.h" +*/ + +const char* img_name = "wallpaper.bmp"; +int img_width = 1366; +int img_height = 768; + +/* + min/max on X and Y axes +*/ +float vx_min = -1.5;//-2; +float vx_max = 1.5;//2; +float vy_min = -1.5;//-2; +float vy_max = 1.5;//2; + +int iter_max = 30; + +/* + 0 for mandelbrot, else julia +*/ +int fractal_flag = 0; + +float julia_C[2] = {-0.5, -1}; + diff --git a/config.h b/config.h @@ -0,0 +1,61 @@ +/* + Configuration File Header + "config.h" + M. Yamanaka + email: myamanaka@live.com + website: csmyamanaka.com + license: MIT (See included "LICENSE" file for details) +*/ + +#pragma once + +/* + I have borrowed a design concept from Suckless Software and made the + configuration file a component of the source code to be compiled with + the rest of the software. + + NOTE!! + Please do not edit the values here. This is a header file and should + not have any assignments. PLEASE!!!! edit the source file "config.c". + I know you normally edit the header files for Suckless programs + but in this case, please edit the source file. +*/ + +/* + Your output image details. + It might be nice to have an image that is exactly your screen size. + By default, this set to my screen size. +*/ + + +const char* img_name; +int img_width; +int img_height; + +/* + The fractal window on the complex plane. The image details above are converted in the program to match + these values. By default, I adjusted the vertical max and min values to that the image doesn't get + stretched horizontally but this can be changed to whatever the user wants. +*/ +float vx_min; +float vx_max; +float vy_min; +float vy_max; + +/* + maximum number of iterations f(z) or "fz" in "juliamath.h" before the recursion terminates. +*/ +int iter_max; + +/* + Fractal flag + If this value is 0, the program generates the Mandelbrot set. Otherwise, it produces a Julia set. +*/ +int fractal_flag; + +/* + Pre-selected constant value for the Julia set {re, im}. + By default, I have C = -0.1 - i. I tried several values experimentally and found I like this one. +*/ +float julia_C[2]; + diff --git a/fracwall.c b/fracwall.c @@ -0,0 +1,36 @@ +/* + Fractal Wallpaper Generator + "fracwall.c" + M. Yamanaka + email: myamanaka@live.com + website: csmyamanaka.com + license: MIT (See included "LICENSE" file for details) +*/ + +#include "juliamath.h" +#include "bmpfileiopp.h" + +int main(){ + + /* + create pre-fractal array of iteration values + */ + int* array = imgIters(1200, 800); + + /* + create bitmap file + */ + BMPIS b = {800, 1200, 3, "wallpaper.bmp"}; + char* pv = (char*)malloc(sizeof(char)*1200*800*3); + + /* + simple and tentative colouring scheme: will come up with a better one soon! + */ + for(int i = 0; i < 1200*800; i++){ + pv[i*3] = (char)(int)(1.0*255*array[i]/iter_max); + pv[i*3 + 1] = (char)(int)(1.0*255*array[i]/iter_max); + pv[i*3 + 2] = (char)(int)(1.0*255*array[i]/iter_max); + } + writeBMP(b, pv); + return 0; +} diff --git a/juliamath.c b/juliamath.c @@ -0,0 +1,101 @@ +/* + Back-end Math for the Julia/Mandelbrot Set implementation file + "juliamath.c" + M. Yamanaka + email: myamanaka@live.com + website: csmyamanaka.com + license: MIT (See included "LICENSE" file for details) +*/ + +#include "juliamath.h" + +int cmplxAdd(float* rz, float* op1, float* op2){ + /* + op1 ... first operand + op2 ... second operand + rz ... result + */ + rz[0] = op1[0] + op2[0]; + rz[1] = op1[1] + op2[1]; + return 0; +} + +int cmplxMult(float* rz, float* op1, float* op2){ + /* + op1 ... first operand + op2 ... second operand + rz ... result + */ + rz[0] = op1[0]*op2[0] - op1[1]*op2[1]; + rz[1] = op1[0]*op2[1] + op1[1]*op2[0]; + return 0; +} + +float cmplxLenSq(float* ipt){ + /* + ipt ... input complex number + */ + return ipt[0]*ipt[0] + ipt[1]*ipt[1]; +} + +float convNtoR(int ipt, int sz, float cmin, float cmax){ + /* + ipt ... number pending conversion + sz ... image length in a given dimension before conversion + cmin ... mininum value of a given axis on the complex plane + cmax ... maximun " " " etc ... + */ + + /* + ipt ranges from [0 to sz) and needs to be mapped to [0, 1) + */ + + return ((1.0*ipt)/sz)*(cmax - cmin) + cmin; +} + +int fz(float* z, float* C, int* n){ + /* + z ... z in f(z) = z^2 + C + C ... C in f(z) = z^2 + C + n ... current iteration + */ + if(cmplxLenSq(z) < 4 && *n < iter_max){ + float reg[2]; //temporary register + cmplxMult(reg, z, z); + cmplxAdd(z, reg, C); + (*n)++; + fz(z, C, n); + } + return 0; +} + +int* imgIters(int w, int h){ + /* + w ... width or number of columns + h ... height or number of rows + */ + + //Initialize array that contains the escape for each pixel initialized to 0 + int* data = (int*)malloc(sizeof(int)*w*h); + for(int i = 0; i < w*h; i++) data[i] = 0; + + //for each pixel, calculate the Re-Im plane conversion then calculate escape count + for(int i = 0; i < h; i++){ + for(int j = 0; j < w; j++){ + + /* + C + 0 points to 0 + 0i, C + 2 points to the pixel converted to complex coordinates and C + 4 points to the + pre-selected constant for the Julia set. + */ + float C[6] = {0, 0, convNtoR(j, w, vx_min, vx_max), convNtoR(i, h, vy_min, vy_max), julia_C[0], julia_C[1]}; + + /* + fractal_flag: 0 creates the mandelbrot set, otherwise julia + I use a nifty little maneuver with boolean arithmetics to avoid using if-else statements + */ + fz(C + 2*(fractal_flag != 0), C + 2 + 2*(fractal_flag != 0), data + i*w + j); + } + } + + return data; +} diff --git a/juliamath.h b/juliamath.h @@ -0,0 +1,93 @@ +/* + Back-end Math for the Julia/Mandelbrot Set header file + "juliamath.h" + M. Yamanaka + email: myamanaka@live.com + website: csmyamanaka.com + license: MIT (See included "LICENSE" file for details) +*/ + +#pragma once + +/* + I'm using a config file as a part of the source code suckless style + Please note that the file to edit is "config.c" not "config.h" +*/ +#include "config.h" +#include <stdlib.h> + +/* + Complex addition/multiplication + Both the Mandelbrot and Julia sets are sets of complex numbers thereby necessitating some complex arithmetics. + The arguments from left to right are: + float* ... result + float* ... first operand + float* ... second operand + There is a return value of an integer which doesn't do anything for now but + eventually, I may implement error codes +*/ +int cmplxAdd(float*, float*, float*); +int cmplxMult(float*, float*, float*); + +/* + Complex length squared + The distance from a given complex number to origin of the complex plane (0 + 0i) is the length or the magnitude + of a complex number. This function calculates this value squared as it is easier to calculate and is equally useful + in the Julia/Mandelbrot set algorithm. + The sole argument to this function is: + float* ... input complex number + The return value is the result of the calculation +*/ +float cmplxLenSq(float*); + +/* + Domain conversion + Axis-agnostically converts a number in the pixel domain to the complex domain, namely an integer in [0, # of pixels) is + converted to a float in [min, max). + The arguments from left to right are: + int ... input number in the pixel domain in either axis + int ... the length of the axis in the pixel domain + float ... minimum value of a given axis in the complex plane + float ... maximum value of a given axis in the complex plane + The resulting number in the complex plane (irrespective of the axis) is returned. +*/ +float convNtoR(int, int, float, float); + +/* + Function of z + ... or f(z) = z^2 + C as described by the first reference video (labelled [1] in the "README" file under the "Acknowledgment" section). + Although this isn't a mathematically pure implementation (i.e. doesn't return a complex number), it instead updates the z parameter + since its address is available to the function. Likewise, variable storing the number of iterations until termination is + also incremented through reference. In a purely mathematical sense, the termination condition is described in the first reference + video as the instance where the magnitude of f(z) is greater than 2 but in a practical sense, the video also shows a case where + it takes many iterations (over 1000 iterations for C = -0.55 + 0.48i in the video) to reach this point in the Mandelbrot set. + For this reason, the number of iterations is restricted, favouring computational feasibility over accuracy. For my implementation, + this limit is controlled by the variable "iter_max" in the included configuration file "config.c". + The second reference video (labelled [2] in the "README" file under "Acknowledgment") shows how this equation can be used to + generate both the Julia set as well as the Mandelbrot set by adjusting the parameters appropriately (see "imgIters" below for details). + The arguments from left to right are: + float* ... first complex number i.e. z + float* ... second complex number i.e. C + int* ... address keeping track of current iteration count + The return value is unused but may be used in the future to indicate errors. +*/ +int fz(float*, float*, int*); + +/* + Iteration values over the image + For every pixel in the resulting image, this function uses the above function "fz" or f(z) = z^2 + C to calculate the number of iterations + to reach the aforementioned termination conditions. According to the second reference video (See [2] in README), the Mandelbrot and Julia + sets begin their respective iteration processes by determining which of the variables in the equation f(z) = z^2 + C corresponds to the pixel + values and which is constant. The reference video provides a helpful chart showing that for the Mandelbrot set, C corresponds to the pixel + values and the initial z value is 0 whereas, for the Julia set, the z corresponds to the pixel values and C is a pre-selected constant which + determines the appearance of the resulting fractal. In my implementation, the user can choose this value in the configuration file "config.c" + by modifying the value of the variable "julia_C". Based on this reference video, my understanding is that any value reasonably close to and within + the borders of the mandelbrot set should produce reasonably nice looking Julia fractals. I have done some experimenting with different C values + and found that C = -0.1 - i (i.e. julia_C[2] = {-0.1, -1}) looks ok at 30 iterations (i.e. iter_max = 30 in "config.c"). + The variable "fractal_flag" in "config.c" determines which type of fractal is generated (0 ... mandelbrot, else julia). + The arguments from left to right are: + int ... width + int ... height + The resulting array is returned. +*/ +int* imgIters(int, int);

Generated using stagit (https://codemadness.org/stagit.html)