commit a0a6428dcaf83c72b280bbb28b2e550482480d60
Author: M. Yamanaka <myamanaka@live.com>
Date: Wed, 17 Feb 2021 00:44:06 -0500
upload of fractal wallpaper generator
Diffstat:
A | LICENSE | | | 20 | ++++++++++++++++++++ |
A | Makefile | | | 19 | +++++++++++++++++++ |
A | README | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | config.c | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | config.h | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | fracwall.c | | | 36 | ++++++++++++++++++++++++++++++++++++ |
A | juliamath.c | | | 101 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | juliamath.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);