int SEG = 1;

int WIDTH=300;
int HEIGHT=300;
int WH = WIDTH*HEIGHT;

int WIDTHSEG = WIDTH/SEG;
int HEIGHTSEG = HEIGHT/SEG;
int WHSEG = WIDTHSEG*HEIGHTSEG;

BImage scene;
BImage im1, im2, im3;

float bump[] = new float[WHSEG];
float vel[] = new float[WHSEG];
float t[] = new float[WHSEG];

int blend(int org, int col, int alpha) { 
  int r1=(org&0x0000ff); 
  int g1=(org&0x00ff00); 
  int b1=(org&0xff0000); 
  int r2=(col&0x0000ff); 
  int g2=(col&0x00ff00); 
  int b2=(col&0xff0000); 
   
  int r3=(((alpha*(r1-r2)) >>8 )+r2)&0x000000ff; 
  int g3=(((alpha*(g1-g2)) >>8 )+g2)&0x0000ff00; 
  int b3=(((alpha*(b1-b2)) >>8 )+b2)&0x00ff0000; 
 
  return (r3)|(g3)|(b3); 
  } 

void drawline(int x0, int y0, int x1, int y1, int pix, float buffer[]) {
  int dy = y1 - y0;
  int dx = x1 - x0;
  int stepx, stepy;

  if (dy < 0) { dy = -dy;  stepy = -WIDTHSEG; } else { stepy = WIDTHSEG; }
  if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }
  dy <<= 1;
  dx <<= 1;
	
  y0 *= WIDTHSEG;
  y1 *= WIDTHSEG;
	
  if (dx > dy) {
    int fraction = dy - (dx >> 1);
    while (x0 != x1) {
      if (fraction >= 0) {
        y0 += stepy;
        fraction -= dx;
        }
      x0 += stepx;
      fraction += dy;
      buffer[x0+y0] += pix;
      }
    }
  else {
    int fraction = dx - (dy >> 1);
    while (y0 != y1) {
      if (fraction >= 0) {
        x0 += stepx;
        fraction -= dy;
        }
      y0 += stepy;
      fraction += dx;
      buffer[x0+y0] += pix;
      }
    }
  }

float constrain(float val, float minv, float maxv) {  
  return (val > maxv) ? maxv : ((val < minv) ? minv : val);  
} 

void setup() {
  size(300,300);
  scene = loadImage("tp1.jpg");
  
  im1 = loadImage("tp1.jpg");
  im2 = loadImage("tp2.jpg");
  im3 = loadImage("tp3.jpg");
  
  for(int i = 0; i < WH; i++) {
    pixels[i] = scene.pixels[i];
    if(i < WHSEG) {
      bump[i] = 0;
      vel[i] = 0;
      }
    }
  }

int sloop = 0;



void loop() {
  for(int i = 0; i < (int)random(4); i++) {
    block((int)random(WIDTH/SEG)-5, (int)random(HEIGHT/SEG)-5, random(10));
    }
  int x, y, u, bu;
  int newpix;
  float mX, mY, du;
  newpix = 0;
  u = 0;
  bu= 0;
  mX = 0;
  mY = 0;
  
  for(int i = WIDTHSEG+1; i < WHSEG-WIDTHSEG-1; i++) {
    
    bump[i] = (vel[i+1]
              + vel[i-1]
              + vel[i+WIDTHSEG]
              + vel[i-WIDTHSEG]
              + vel[i-WIDTHSEG-1]/2
              + vel[i-WIDTHSEG+1]/2
              + vel[i+WIDTHSEG-1]/2
              + vel[i+WIDTHSEG+1]/2)/4 - bump[i];
    
    bump[i] *= 0.95;
    }
  
  for(int i = 0; i < WHSEG; i++) {
    t[i] = vel[i];
    vel[i] = bump[i];
    bump[i] = t[i];
    }
  
  for(int i = 0; i < WH; i++) {
    x = i%WIDTH;
    y = (int)i/HEIGHT;
    newpix = 0;
    if(x > SEG && x < WIDTH-SEG && y > SEG && y < HEIGHT-SEG) {
      bu = (int)(x/SEG+((y/SEG)*WIDTHSEG));
      mX = (float)((bump[bu] - bump[bu-1]) + (bump[bu+1] - bump[bu]))*32;
      mY = (float)((bump[bu] - bump[bu-WIDTHSEG]) + (bump[bu+WIDTHSEG] - bump[bu]))/32;
      mX = constrain(mX,-2,2);
      mY = constrain(mY,-2,2);
      u = (int)(x+mX+(y+mY)*WIDTH);
      if(u < WH && u > 0) {
        newpix=scene.pixels[u];
        }
      }
    pixels[i] = newpix;
    }

  for(int i = 0; i < WH-1; i++) {
    if(sloop < 255) {
      scene.pixels[i] = blend(im1.pixels[i], im2.pixels[i], 255-sloop);
      }
    else if(sloop < 510) {
      scene.pixels[i] = blend(im2.pixels[i], im3.pixels[i], 255-sloop%255);
      }
    else if(sloop < 765) {
      scene.pixels[i] = blend(im3.pixels[i], im1.pixels[i], 255-sloop%255);
      }
    else sloop = 0;
    }
  sloop+=1;
  }
  
int tmouseX, tmouseY;
void mouseMoved() {
  tmouseX = mouseX/SEG-5;
  tmouseY = mouseY/SEG-5;
  block(tmouseX, tmouseY, 0.5);
  }

void block(int x, int y, float str) {
  int dist = 0;
  int zu;
  for(int i=0; i < 10; i++) {
    for(int u=0; u < 10; u++) {
      dist = (i-5)*(i-5)+(u-5)*(u-5);
      if(dist < 25 && dist > 0) {
        zu = x+i+(y+u)*WIDTHSEG;
        if(zu > 0 && zu < WHSEG)
          bump[zu] = str*(1-dist/25);
        }
      }
    }
  }
 
void mousePressed() {
  block(mouseX/SEG-5, mouseY/SEG-5, 10);
  }
