> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.wTxwt553bcw/rev.248
 * 
 * authors: 
 *   Rui Gil

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



//'z' zoom in
//'x' zoom out
//'j' toggle julia/mandelbrot
//' ' reset

private boolean julia = true;
private int detail = 3; // try 2, 1 or 0, more detail, less framerate
float zoom = 1, moveX = -0.5f, moveY = 0;
PImage offscreen;

void setup() {
  size(512,512,P2D);
  colorMode(HSB);
  loadPixels();
}

void draw() {
  float rfactor = 1/(0.3f * width * zoom ); // precalc real factor
  float ifactor = 1/(0.3f * height * zoom); // precalc imaginary factor
  int yoffset = 0;
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      float real, imaginary, nextReal, nextImaginary, currentReal, currentImaginary;
      // screen represents a specific area in the complex plane, going from -0.3 to 0.3 in the real axis
      // formula: Zn+1 = Z^2 + C 
      // Z and C are complex numbers
      // if "julia set" then mouse coordinates specify C
      // else Mandelbrot set.
      nextReal = julia ? (x - 256) * rfactor  + moveX : 0;
      nextImaginary = julia ? (y - 256) * ifactor + moveY : 0;
      real = julia ? (mouseX - 256) * rfactor + moveX: (x - 256) * rfactor  + moveX;
      imaginary = julia ? (mouseY - 256) * rfactor + moveX : (y - 256) * ifactor + moveY;

      int maxiterations = 256>>detail; // more detail means more iterations, less framerate
      int iterations = 0;
      for (iterations = 0; iterations < maxiterations; iterations++) {
        currentReal = nextReal;
        currentImaginary = nextImaginary;
        nextReal = currentReal * currentReal - currentImaginary * currentImaginary + real;
        nextImaginary = 2 * currentReal * currentImaginary + imaginary;
        // multiplying complex numbers make them "spin" on the complex plane
        // if they escape a circle with diameter 4 the iterations stop
        if((nextReal * nextReal + nextImaginary * nextImaginary) > 4) break;  
      }
      // the number of iterations that takes to escape the circle represents the color
      // black, means they didn't escape the circle.
      pixels[x+yoffset] = color((iterations<<detail)&0xff,255,(iterations == maxiterations ? 0: 255));
      ; 
    }
    yoffset += width;
  }
  updatePixels();
}

void keyPressed() {
    if (key == 'j') {
        julia = !julia;
    }
    // zoom in
    if (key == 'z') {
        float zoomfactor = 0.3f/zoom;
        moveX += ((float)(mouseX-256)/width) * zoomfactor;
        moveY += ((float)(mouseY-256)/height) * zoomfactor;
        zoom *= 1.04;
    }
    // zoom out
    if (key == 'x') {
        float zoomfactor = 0.3f/zoom;
        moveX += ((256-mouseX)/(float)width) * zoomfactor;
        moveY += ((256-mouseY)/(float)height) * zoomfactor;
        zoom /= 1.04;
        zoom = zoom < 1 ? 1 : zoom;
    }
    // space to reset
    if (key == ' ') {
        zoom = 1;
        moveX = -0.5f;
        moveY = 0;
    }
}