// "AVIARY" - Daniel Sanchez
// University of Oregon
// ARTD 252: Prof. J. Park
// April 27th, 2009
// Project no. 1
//
// In this project I explored combining code previously finished by another author
//with my own.  Thanks to Kyle McDonald and his project called ‘MultiShadow Error,’ which is made 
//available at http://openprocessing.com/visuals/?visualID=1188, I was able to take inspiration from
//his work and compose a new artistic and engaging piece.
//
// When I first saw his project, I was reminded of a childhood experience of watching 
//flocks of birds fly in between the tall buildings of downtown LA.  So I toke his code and used 
//it as the matrix for my images of birds. I also incorporated a background image as well 
//as a sound clip, respectively called “Birds” by M83, to give the piece some context.
//
// After the first round of working on this project I felt like the piece was still very 
//static and needed a dynamic element and some color.  So I inserted a piece of 
//code that allows the user to click on the screen, which engages some colored shapes into 
//the piece as well.
//
//Notes: Since most of my code has been embedded into the original code, you can find 
//Kyle’s original code on the separate tab in this file.
// You can also find instructions and code for uploading music files in examples section 
//of the application folder.
//Lastly, there are multiple variables in the code below.  "i" represnts the variable for
//the birds, whereas "n" represents the variable for the balls.

//..............I HOPE YOU ENJOY THIS PIECE......................//



//music section begin//
import ddf.minim.*;

AudioPlayer player;
Minim minim;
//music section end//


//original code begin//
float maxrots = .5; //changes the speed at which the birds travel
int totLines = 50; 
Line[] lines = new Line[totLines]; 
//original code end//

PImage b;//loads image of birds
PImage d;//loads background image

//below sets the ball array when the user clicks on the screen
int bCount = 100;//sets no. of balls that will appear on the screen at once

float [] yspd = new float[bCount];
float [] xspd = new float[bCount];
float [] xpos = new float[bCount];
float [] ypos = new float[bCount];
float [] bSize = new float[bCount];
float [] color1 = new float[bCount];
float gravity = 1;


//.......................//
void setup() { 
  size(400,600,P3D); //Set size to size of background image
  colorMode(RGB,100); //make sure you have the correct color mode
  
  //orignal code begin//
  for(int i = 0; i < totLines; i++) 
    lines[i] = randomLine(); 
  camera(1, 0, (height<width?height:width), 0, 0, 0, 0, 1, 0);{ 
  //original code end// 
  
     d = loadImage("skyline.jpg");//locates image file in project foloder
     b = loadImage("bird.png");//locates image file in project foloder
}
//Below sets properties for the balls
  noStroke(); for(int n=0; n<bCount; n++){
    xpos[n] = random(0,width);
    ypos[n] = random(0,height);
    yspd[n] = random(-10,10);
    xspd[n] = random(-10,10);
    bSize[n] = random(5,50);
  }


//muisc section begin//
minim = new Minim(this);
  
  // load a file, give the AudioPlayer buffers that are 1024 samples long
  // player = minim.loadFile("groove.mp3");
  
  // load a file, give the AudioPlayer buffers that are 2048 samples long
  player = minim.loadFile("birds.mp3", 2048);//locates music file in project folder
  // play the file
  player.play();
//music section end//  
}
//............end voidsetup...............//
 
 
//original code begin// 
Line randomLine() { 
  return new Line(randomPoint(),randomPoint()); 
} 
 
float e = 50;//changes the number of birds show in window 
Point randomPoint() { 
  return new Point(random(-e,e),random(-e,e),random(-e,e)); 
}  
float ti = 0; 
//original code end//


//...........................//
void draw() { 
  noCursor(); //removes the cursor from visibility
  background(d);//d=background image 

if (mousePressed == true){  
//code below for balls
  for(int n=0; n<bCount; n++){
    ypos[n] -= (yspd[n]+random(-1,5));
    xpos[n] -= (xspd[n]+random(-1,1));
    ypos[n] *= gravity;
    
    if(ypos[n] < 0){
      ypos[n] = height + 5;
      xpos[n] = random(0,width);
      color1[n] = random(0,255);
    }
//where the balls get drawn
    fill(random(0,255),random(0,255),random(0,255));
    noStroke();
    smooth();
    ellipse(xpos[n],ypos[n],bSize[n],bSize[n]);
  }
  
//original code begin (below code renders birds in matrix)//
  ti+=0.01; 
  rotateX(-ti); 
  rotateY(-ti/2); 
  rotateZ(-ti/3); 
  
  Point c = new Point(sin(ti)*width,cos(ti)*height,0); 
  for(int i = 0; i < totLines; i++) 
    nearestPoint(lines[i],c).render();
}//end of if statement

else {//begining of else statement. note: the code is repeated for the birds

  ti+=0.01; 
  rotateX(-ti); 
  rotateY(-ti/2); 
  rotateZ(-ti/3); 
 
  Point c = new Point(sin(ti)*width,cos(ti)*height,0); 
  for(int i = 0; i < totLines; i++) 
    nearestPoint(lines[i],c).render();
  }//end of else statement
} 
//...........end void draw...................//

//original code begin 
float interp(float low, float high, float t) { 
  return ((high - low) * t) + low; 
} 
 
Point nearestPoint(Line line, Point C) { 
  Point A = line.a; 
  Point B = line.b; 
  float t1 = A.x*A.x; 
  float t2 = A.y*A.y; 
  float t3 = A.z*A.z; 
  float t4 = B.x*A.x; 
  float t7 = B.y*A.y; 
  float t10 = B.z*A.z; 
  float t13 = -t1-t2-t3+t4-B.x*C.x+A.x*C.x+t7-B.y*C.y+A.y*C.y+t10-B.z*C.z+A.z*C.z; 
  float t14 = B.x*B.x; 
  float t15 = B.y*B.y; 
  float t16 = B.z*B.z; 
  float t23 = -t13/(t14+t1+t15+t2+t16+t3-2.0*t4-2.0*t7-2.0*t10); 
  return line.pointAt(t23); 
} 

//POINT
class Point { 
  float x, y, z; 
  float mouseX, mouseY, rotz; 
  float rotsx, rotsy, rotsz; 
  Point(float x, float y, float z) { 
    this.x = x; 
    this.y = y; 
    this.z = z; 
    mouseX = 0; 
    mouseY = 0; 
    rotz = 0; 
    rotsx = random(-maxrots,maxrots); 
    rotsy = random(-maxrots,maxrots); 
    rotsz = random(-maxrots,maxrots); 
  } 
  void render() { 
    mouseX += rotsx; 
    mouseY += rotsy; 
    rotz += rotsz; 
    pushMatrix(); 
    translate(x,y,z); 
    rotateX(mouseX); 
    rotateY(mouseY); 
    fill(0, 255); 
    image(b,0,0); //*Important: change from rect to image 
  
    popMatrix(); 
  } 
} 


//LINE 
class Line { 
  Point a, b; 
  Line(Point a, Point b) { 
    this.a = a; 
    this.b = b; 
  } 
  Point pointAt(float t) { 
    float x =  interp(a.x, b.x, t); 
    float y =  interp(a.y, b.y, t); 
    float z =  interp(a.z, b.z, t); 
    return new Point(x, y, z); 
  } 
  void render() { 
    line(a.x,a.y,a.z,b.x,b.y,b.z); 
  } 

}
//original code end//

//music section begin//
void stop()
{
  // always close Minim audio classes when you are done with them
  player.close();
  minim.stop();
  
  super.stop();
}
//end muisc section//