xxxxxxxxxx
const MAX_ITERATIONS = 100;
const ITER_SHADE_SCALE = 360 / MAX_ITERATIONS;
const ESCAPE_RADIUS = 2;
const LIMIT = ESCAPE_RADIUS * ESCAPE_RADIUS;
const WIDTH = 900;
const HEIGHT = 750;
const PIXEL_SCALE = 1 / 300; // scales picture up
const X_MOD = 0.65; // pans picture left
const points1 = [[0, 300, 100, 0], [15, 200, 100, 50], [99, 100, 100, 100]];
const points2 = [[0, 200, 100, 0], [15, 120, 100, 40], [99, 50, 100, 70]];
const points3 = [[0, 0, 100, 0], [15, 50, 100, 50], [99, 100, 100, 100]];
const points4 = [[0, 30, 100, 0], [5, 200, 100, 25], [15, 0, 100, 50], [25, 200, 100, 75], [99, 360, 100, 100]];
function setup() {
createCanvas(WIDTH, HEIGHT);
background(100);
noStroke();
rectMode(CENTER);
colorMode(HSL);
noLoop();
// noprotect
}
function inMandelbrotSet(c) {
// tells if given complex number c stays within Mandelbrot set, and if it escapes, how many iterations it took
// iter 0 if in set, else 1-100 number of iterations to escape
let z = [0.0, 0.0]; // complex numbers as 1 by 2 arrays
let iter = 0; // additional variable to store number of iterations for choosing color
for (let i = 0; i < MAX_ITERATIONS; i++) {
z = [
sq(z[0]) - sq(z[1]) + c[0],
2 * z[0] * z[1] + c[1]
];
if (sq(z[0]) + sq(z[1]) > LIMIT) {
iter = i;
return iter;
}
}
return iter;
}
function complexize(x, y) {
// converts x y position on screen to a complex number
c = [
(x - WIDTH / 2) * PIXEL_SCALE - X_MOD,
-(y - HEIGHT / 2) * PIXEL_SCALE
];
return c;
}
function index(point) {return point[0];}
function hsl(point) {return [point[1], point[2], point[3]];}
function createPalette(size, points) {
// creates and returns a color palette, array of HSL colors indexed to match each possible number of iterations
let palette = [];
// Fill first color until first point.
for (let i = 0; i <= index(points[0]); i++) {
palette.push(hsl(points[0]));
}
for (let i = 0; i < points.length - 1; i++) {
let p = points[i];
let p1 = points[i + 1];
if (i === 0 || index(p) > index(points[i - 1])) {
palette.push((hsl(p)));
}
// Interpolate color values until next color point.
let d = index(p1) - index(p);
let hsl0 = hsl(p);
let h0 = hsl0[0];
let s0 = hsl0[1];
let l0 = hsl0[2];
let hsl1 = hsl(p1);
let h1 = hsl1[0];
let s1 = hsl1[1];
let l1 = hsl1[2];
let dh = (h1 - h0) / d;
let ds = (s1 - s0) / d;
let dl = (l1 - l0) / d;
for (let j = 1; j < d; j++) {
palette.push([h0 + j * dh, s0 + j * ds, l0 + j * dl]);
}
}
// Fill last color to end.
for (let i = index(points[points.length - 1]); i < size; i++) {
palette.push(hsl(points[points.length - 1]));
}
return palette;
}
function draw() {
let iter;
for (let x = 1; x <= WIDTH; x++) {
for (let y = 1; y <= HEIGHT; y++) {
iter = inMandelbrotSet(complexize(x, y));
fill (iter * ITER_SHADE_SCALE); // black and white, number of iterations purely affecting the lightness
rect (x, y, 1, 1);
}
}
}
function keyPressed() {
let iter;
let points = points1;
if (keyCode === LEFT_ARROW) {
points = points1; // lightning
}
if (keyCode === UP_ARROW) {
points = points2; // poison
}
if (keyCode === RIGHT_ARROW) {
points = points3; // fire
}
if (keyCode === DOWN_ARROW) {
points = points4; // rainbow
}
let palette = createPalette(MAX_ITERATIONS, points);
for (let x = 1; x <= WIDTH; x++) {
for (let y = 1; y <= HEIGHT; y++) {
iter = inMandelbrotSet(complexize(x, y));
fill (palette[iter]);
rect (x, y, 1, 1);
}
}
}