import processing.core.*;
import processing.data.*;
import processing.event.*;
import processing.opengl.*;

import java.util.HashMap;
import java.util.ArrayList;
import java.io.File;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

public class layer_size_velocity_opacity extends PApplet {

int num = 24; 
float s = 3;
float reflex = 0.3f; 
float aperture = 64; 

int bg = color(255, 0, 0); 
int fg1 = color(255, 0, 0);
int fg2 = color(255, 0, 0);

 public void setup() {

  /* size commented out by preprocessor */;
  noStroke();
  frameRate(25);

  aa = new float[8];
  bb = new float[aa.length];
  reset();
}

 public void mouseClicked() {
  reset();
}


float t = 0; 

float[] aa; // great naming conventions, I know...
float[] bb;
float transition = 0;

 public void reset() {
  for (int i = 0; i<bb.length; i++) {
    float v = random(1, 8);
    bb[i] = aa[i];
    aa[i] = random(2)<1?v:-v;
  }
  transition = 1;
}
 public void draw() {
  t+=0.0008f;
  background(0);

  transition*=(1-reflex);


  for (float v = 0; v<num; v++) {
    for (float u = 0; u<num; u++) {
      float h = 42
        *sin((aa[0]*u-aa[1]*v)/num+4.2f*aa[4]*t+aa[6])
        *cos((aa[2]*v+aa[3]*u )/num+aa[5]*t+aa[7]);

      float h2 = 42
        *sin((bb[0]*u-bb[1]*v)/num+4.2f*bb[4]*t+bb[6])
        *cos((bb[2]*v+bb[3]*u )/num+bb[5]*t+bb[7]);
      h = lerp(h, h2, transition);

      float u1 = u/num*2-1;
      float v1 = v/num*2-1;

      float u2 = cos(t)*u1 + sin(t)*v1;
      float v2 = sin(t)*u1 - cos(t)*v1; 
      // transformation after transformation, I'm not entirely sure what's going on here anymore. #dontTouchItItWorks

      float u3 = u2/2+0.5f;
      float v3 = v2/2+0.5f;

      float x = u3*min(width, height);
      float y = v3*min(width, height);

      float a = x-y;
      float b = x+y;

      pushMatrix();
      translate(0, 0);
      translate(width/2, 0);
      float dist = 1.5f-b/2/height-h/500;
      scale(atan(1/dist)*3.4f);  // a little math, but mostly magic
      translate(-width/2, -height/3.5f);

      float blur = (1-dist)*aperture;
      fill(lerpColor(fg1, fg2, constrain(map(blur, -aperture/3, aperture/2, 0, 1), 0, 1)), // blend the colors
        min(s*255/max(sq(blur/2)*2, 1), 255)); // add transparency

      translate(0, -h); // creates the waves
      ellipse(a/4+width/2, b/42+height/2, max(abs(blur), s), max(abs(blur), s));
      popMatrix();
    }
  }
}


  public void settings() { size(1200, 640); }

  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "layer_size_velocity_opacity" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}