import SGBackground.*;
import Tuple.*;
import SGCamera.*;
import SGGUI.*;
import SGPhysics.*;
 
Gradient back;
SGCamera cam;
 
 
 
float time = 0;
 
PFont font;
 
SGGUI controller;
VerticalLayout settings;
 
SGSlider gravitySlide,vortexSlider,leaves,updraftSlider,restoreSlider,windSlider;
SGCheckBox vortexMotion, groundSpawn,clean;
 
PhysicsEngine PE;
int pts = 30;
 
PImage leafTex,rakeyGuy,tree;
 
Funnel fun;
Fan updraft;
LinearForce gravity,wind;
 
float billAspect = 1;
 
boolean paused = false;
 
int showGUI = 1;
 
 
 
void setup(){
 
size(550,550,P3D);
 
frameRate(30);
 
font = loadFont("writing.vlw");
textFont(font);
 
controller = new SGGUI(this,font);
settings = new VerticalLayout(controller,10,10,150);
leaves = new SGSlider("Leaves",2000,100,0,4000);
gravitySlide = new SGSlider("Gravity",.1,.01,0,.4);
updraftSlider = new SGSlider("Up draft",.11,.01,0,.2);
restoreSlider = new SGSlider("Restore",1,.2,0,3);
vortexSlider = new SGSlider("Vortex",2.5,.25,0,5);
windSlider = new SGSlider("Wind",.01,.01,0,.5);
 
vortexMotion = new SGCheckBox("Ground Motion",1);
groundSpawn = new SGCheckBox("Ground Spawn",1);
clean = new SGCheckBox("Ground Distribute",1);
 
 
settings.add(leaves);
settings.add(gravitySlide);
settings.add(windSlider);
settings.add(updraftSlider);
settings.add(restoreSlider);
settings.add(vortexSlider);
settings.add(vortexMotion);
settings.add(groundSpawn);
settings.add(clean);
controller.add(settings);
 
 
leafTex = loadImage("Leaf.png");
rakeyGuy = loadImage("rakeyGuy.png");
 
billAspect = leafTex.width/(float)leafTex.height;
 
cam = new SGCamera(this,20,-100,250,0,0,0);
cam.setMouseMode(LEFT,SGCamera.ORBIT);
cam.setMouseMode(RIGHT,SGCamera.DOLLY);
 
 
textureMode(NORMALIZED);
 
back = new Gradient(this,8);
back.addLight(new Tuple3f(width/2,400,300),color(240),1.f,1.5);
back.addLight(new Tuple3f(0,0,400),color(0,0,90),1.f,1);
 
PE = new PhysicsEngine(this);
 
gravity = new LinearForce(new Tuple3f(0,.1,0));
PE.addForce(gravity);
wind = new LinearForce(new Tuple3f(.01,0,.01));
PE.addForce(wind);
 
PE.addForce(new AAPlane(AAPlane.Y_AXIS,0,100,100,.5));
 
updraft = new Fan(new Tuple3f(0,0,0), new Tuple3f(0,-1,0),40,40,.11f);
PE.addForce(updraft);
 
fun = new Funnel(new Tuple3f(0,0,0),new Tuple3f(0,-1,0),.1,50);
PE.addForce(fun);
 
 
PE.addBody(new Tree(new Tuple3f(-50,-20,-50),rakeyGuy,20));
 
}
 
void draw(){
 
 
updraft.power = updraftSlider.getVal();
gravity.dir.y = gravitySlide.getVal();
if (vortexSlider.getVal() == 0){
fun.active = 0;
}
else{
fun.active = 1;
fun.maxVel = vortexSlider.getVal();
fun.restoreStrength = restoreSlider.getVal();
}
wind.dir.x = windSlider.getVal();
wind.dir.z = windSlider.getVal();
pts = (int)leaves.getVal();
float spRate = 0;
float spHeight = 10;
if (clean.val == 1) spRate = .7f;
if (groundSpawn.val == 0) spHeight = 100;
if (PE.bodies.size() < pts){
Leaf de;
float perc = random(0,.1);
for (int i = 0; i < (pts-PE.bodies.size())*perc; i++){
if (fun.active == 1 && random(0,1) > spRate){
de = new Leaf(new Tuple3f(fun.loc.x +random(-10,10) ,random(-spHeight,0),fun.loc.z +random(-10,10)));
}
else{
de = new Leaf(new Tuple3f(random(-100,100),random(-spHeight,0) ,random(-100,100)));
}
 
PE.addBody(de);
}
 
}
 
 
time++;
 
if (vortexMotion.val == 1){
fun.loc.x += .5*sin(.05*time);
fun.loc.z += .5*cos(.05*time);
}
 
back.draw();
 
cam.feed();
 
 
noStroke();
 
lights();
fill(0,60,0);
pushMatrix();
scale(1,.15,1);
translate(0,100,0);
box(200);
popMatrix();
 
noLights();
 
lights();
 
fill(128);
SGBody temp;
for (int i = 0; i < PE.bodies.size(); i++){
temp = (SGBody)PE.bodies.elementAt(i);
temp.calcDist(cam.pos);
 
 
}
Collections.sort(PE.bodies);
 
for (int i = 0; i < PE.bodies.size(); i++){
temp = (SGBody)PE.bodies.elementAt(i);
temp.render();
 
if (temp.pos.y > 100 || temp.pos.y < -250){
PE.bodies.removeElementAt(i);
i--;
}
}
 
 
stroke(0);
Constraint c;
for (int i=0; i < PE.constraints.size(); i++){
c = (Constraint)PE.constraints.elementAt(i);
c.render(this);
}
 
 
 
 
}
 
void keyPressed(){
if (key == ' ' ){
if (paused) paused = false;
else paused = true;
PE.setRunning(!paused);
}
else if (key == 'r' ){
 
PE.bodies = new Vector();
PE.addBody(new Tree(new Tuple3f(-50,-20,-50),rakeyGuy,20));
}
 
else if (key == 'g' ){
 
showGUI = 1- showGUI;
settings.setVisible(showGUI);
}
 
 
}
 
 
class Leaf extends DynamicBody implements Comparable{
 
Tuple3f rot,rz;
float sz;
float rate = .1f;
 
 
public Leaf(Tuple3f pos){
super(pos);
sz = random(2,3);
rot = new Tuple3f(random(-3,3),random(-3,3),random(-3,3));
rz = new Tuple3f(random(-rate,rate),random(-rate,rate),random(-rate,rate));
}
 
void render(){
pushMatrix();
 
 
if (pos.y < -1 || pos.y > 1){
rot.plusEquals(rz);
}
 
translate(pos.x,pos.y,pos.z);
 
beginShape();
rotateX(rot.x);
rotateY(rot.y);
rotateZ(rot.z);
texture(leafTex);
vertex(-sz*billAspect,0,-sz,0,0);
vertex(sz*billAspect,0,-sz,1,0);
vertex(sz*billAspect,0,sz,1,1);
vertex(-sz*billAspect,0,sz,0,1);
endShape();
 
 
popMatrix();
 
}
 
int compareTo(Object o){
if (((SGBody)o).camDist < camDist) return -1;
else return 1;
}
 
}