I tried to hack some old code in to get it into colours, but it looks crap. The zooming works nicely though, but it hits some pixels at some point for some reason.


// core mandelbrot set generating algorithm
// based on pseudo code found at
// http://en.wikipedia.org/wiki/Mandelbrot_set
// the offscreen image buffer method 
// (using PGraphics combined with PImage)
// was from here: 
// http://wiki.processing.org/w/Draw_to_off-screen_buffer
float xMin, xMax, yMin, yMax, xStart, xEnd, yStart, yEnd;
float xDrag1, xDrag2, yDrag1, yDrag2;
float iteration, max_iteration;
float cellCount, gridWidth, gridHeight, cellSize;
boolean dragging;
PGraphics gfx;
PImage img;

void setup() {
  size(500, 500, P2D);
  gfx = createGraphics(width, height, P2D);
  rectMode(CORNER);
  dragging = false;
  reset();
}

void reset() {
  // the plot range which can be updated by a mouseClick
  xMin = -2.5;
  xMax = 1;
  yMin = -1;
  yMax = 1;

  xStart = xMin;
  xEnd = xMax;
  yStart = yMin;
  yEnd = yMax;
  max_iteration = 100; 
  gridWidth = width;
  gridHeight = height;
  cellCount =  width;
  cellSize = gridWidth / cellCount;
  render();
}



void draw() {
  background(0);
  image(img, 0, 0);

  if (dragging) {
    fill(255, 255, 255, 20);
    rect(xDrag1, yDrag1, mouseX - xDrag1, mouseY - yDrag1);
  }
}
void  mousePressed() {
  dragging = !dragging;
  // we just stopped dragging - update the size
  if (!dragging) {
    xDrag2 = mouseX;
    yDrag2 = mouseY;
    // now update xStart, xEnd, yStart, yEnd
    xStart = xStart +  (xDrag1 / (float) width) * (xEnd - xStart);
    xEnd = xStart +  (xDrag2 / (float) width) * (xEnd - xStart);
    yStart = yStart +  (yDrag1 / (float) width) * (yEnd - yStart);
    yEnd = yStart +  (yDrag2 / (float) width) * (yEnd - yStart);
    //max_iteration *= 1.05;
    // update the image
    render();
  }
  // we just started dragging
  if (dragging) {
    xDrag1 = mouseX;
    yDrag1 = mouseY;
  }
}

void keyPressed() {
  reset();
}

void render() {
  gfx.beginDraw();
  gfx.strokeWeight(0);
  for (int x=0;x<cellCount;x++) {
    for (int y=0;y<cellCount;y++) {
      color c = getColor(x, y);
      gfx.fill(red(c) % 254, green(c) % 254, blue(c) % 254);
      //gfx.fill(getColor(x, y));
      gfx.rect(x*cellSize, y*cellSize, cellSize, cellSize);
    }
  }
  gfx.endDraw();
  img = gfx.get(0, 0, width, height);
}


// this is the clever bit
color getColor(int xPos, int yPos) {
  // used for the calculation in 'getColor'.
  float x0, y0;
  float x, y;
  float xTemp;
  color col;
  x = 0;
  y = 0;
  x0 = map(xPos, 0, cellCount, xStart, xEnd);
  y0 = map(yPos, 0, cellCount, yStart, yEnd);
  iteration = 0;
  //max_iteration = 1000;
  while (x*x + y*y <= (2*2) &&
    iteration < max_iteration) {
    xTemp = x*x - y*y + x0;
    y = 2*x*y + y0;
    x = xTemp;
    iteration ++;
  }  
  if (iteration == max_iteration) {
    col = color(0);
  }
  else {
    col = getColourHeat(iteration / max_iteration * 255f);
    //col = color( iteration / max_iteration * 255  %254) ;
  }
  return col;
}


private color getColourHeat(float v) {
  color rgb;
  rgb = 0;
  //i = (int) (value * 255f);
  int i = (int) v;
  if (i < 64) {
    // set it to the blue
    rgb = i;
  }
  if (i > 64 && i < 128) {
    // shift value onti the red
    rgb = i;
    rgb <<= 16;
    rgb |= 0x0000ff;
  }
  if (i > 128 && i < 192) {
    // fadendown the blue
    rgb = 0xff0000;      
    i = 255 - i;
    rgb |= i;
  }
  if (i > 192) {
    // red on max
    // fade in the green
    rgb = i;
    rgb <<= 8;
    rgb |= 0xff0000;
  }
  return rgb;
}

http://freespace.virgin.net/hugo.elias/graphics/x_water.htm

int[] source;
int[] dest;
int[] tempInts;
int pixCount;

void setup() {
  size(500, 500, P2D);
  // number of pixels on the screen
  pixCount = height * width;
  // two buffers the size of the screen
  source = new int[pixCount];
  dest = new int[pixCount];
}

void draw() {
  // update the ripple magnitude array
  updateMags();
  // now draw an image which is distorted based
  // on the values in the mags array
  for (int i=0;i<pixCount;i++){
    stroke(source[i]);
    point(i%width, i/width);
  }
}

void updateMags() {
  for (int i=width;i<pixCount - width;i++) {
    // calc new value based on old values, divide by 2
    // and subtract current value
    dest[i] = ((source[i-1] +
      source[i+1] + 
      source[i-width] + 
      source[i+width]) >> 1) - dest[i];
    // apply damping by dividing by (2^5)
    dest[i] -= (dest[i] >> 6);
  }
  // swap the buffers
  tempInts = dest;
  dest = source;
  source = tempInts;
}

void mouseDragged(){
  // 'excite' the source array!
  source[mouseX * mouseY] = 255;
}