//created=16 Mar 08
//description=Depth of field using precalculated depth blurred imposters
//title=Dandelion
//titlebar=Depth of Field Using Precalculated Depth Blurred Imposters
//publish=true
//tags=dof
 
import SGBackground.*;
import Tuple.*;
import SGCamera.*;
import SGQuickVar.*;
 
 
Gradient back;
SGCamera cam;
 
int res = 15;
int pad = 5;
PImage bee;
PImage DOF [] = new PImage[res];
 
Vector locs = new Vector();
 
PFont font;
 
SGVariable focus,dof,hof,lions;
 
float time = 0;
int running = 1;
 
float maxSize = 200;
 
 
void setup(){
 
size(550,550,P3D);
frameRate(30);
 
 
font = loadFont("writing.vlw");
textFont(font);
focus = new SGVariable(this,font,"Focal Length",'a','z',140,3,0,1000);
dof = new SGVariable(this,font,"Depth of Field",'s','x',10,.1,1,50);
hof = new SGVariable(this,font,"Nozzle Spread",'d','c',20,.5,0,500);
lions = new SGVariable(this,font,"Lions",'f','v',35,1,1,100);
 
 
cam = new SGCamera(this,20,-10,150,0,0,0);
cam.setMouseMode(LEFT,SGCamera.ORBIT);
cam.setMouseMode(RIGHT,SGCamera.DOLLY);
 
 
bee = loadImage("flour.png"); //hee hee, I misspelled flower. Actually, I think these things are weeds.
for (int i = 0; i < res; i++){
 
//make it twice as big to support nice blur
DOF[i] = new PImage(bee.width+(pad*i),bee.height+(pad*i),ARGB);
DOF[i].loadPixels();
//clear the alpha channel
for (int j = 0; j < DOF[i].width*DOF[i].height; j++){
DOF[i].pixels[j] = color(0,0,0,0);
}
DOF[i].updatePixels();
 
DOF[i].copy(bee,0,0,bee.width,bee.height,i*pad/2,i*pad/2,DOF[i].width-i*pad,DOF[i].height-i*pad);
 
DOF[i].filter(BLUR,i);
}
textureMode(NORMALIZED);
//hint(ENABLE_DEPTH_SORT);
//hint(ENABLE_ACCURATE_TEXTURES);
 
for (int i = 0; i < lions.val; i++){
locs.add(new Dream(new Tuple3f(random(-hof.val,hof.val),random(-hof.val,hof.val),random(-maxSize,maxSize))));
 
}
back = new Gradient(this,10);
back.addLight(new Tuple3f(width-50,50,300),color(240),1.f,1.5);
back.addLight(new Tuple3f(0,0,400),color(0,0,90),1.f,1);
 
}
 
void draw(){
 
time += .1f;
back.draw();
 
cam.feed();
 
Dream d;
for (int i = 0; i < locs.size(); i++){
d = (Dream)locs.elementAt(i);
d.draw();
if (d.loc.z> maxSize){
locs.remove(d);
i--;
}
}
 
while (locs.size() < lions.val ){
d = new Dream(new Tuple3f(random(-hof.val,hof.val),random(-hof.val,hof.val),random(-100,-150)));
locs.insertElementAt(d,0);
}
 
Collections.sort(locs);
 
}
 
class Dream implements Comparable{
 
Tuple3f loc;
float dz;
float flen;
float rot;
float scalar;
Dream(Tuple3f loc){
this.loc = loc;
flen = loc.distance(cam.pos);
scalar = random(-.5,.5);
//dz = random(-1,1);
}
 
void draw(){
if (running == 1){
rot = sin(time*scalar);
loc.z+=2 + dz;
}
//need distance from camera
flen = loc.distance(cam.pos);
 
pushMatrix();
int which;
float ht,wd;
//stroke(0);
 
translate(loc.x,loc.y,loc.z);
rotateZ(rot);
beginShape(QUADS);
 
 
which = (int)abs((flen-focus.val)/dof.val);
 
float sc = 0;
if (which > res-1){
sc = (which - res - 1)/((float)pad);
which = res - 1;
}
texture(DOF[which]);
ht = DOF[which].height/20.f;
wd = DOF[which].width/20.f;
ht += sc;
wd += sc;
vertex(-wd,-ht,0,0);
vertex(wd,-ht,1,0);
vertex(wd,ht,1,1);
vertex(-wd,ht,0,1);
endShape();
popMatrix();
}
 
int compareTo(Object o){
if (((Dream)o).flen < flen) return -1;
else return 1;
}
 
}
 
void keyPressed(){
 
if (key == ' '){
running = 1- running;
}
 
}