/*

Visuals for the song "The Years" (v2)
Colors: darky
The Years has two loops: 4-chord loop and 5-chord loop.
With every loop a leaf/plant-stem appears
With every new layer of sound, new elements appear on the leafs.

resolutions:
720x576    (DVD progressive)
1024x768   (XGA)
1280x1024  (SXGA)
1600x1200  (UXGA)
1920x1080  (HDTV 1080i/50)
1280x720   (HDTV 720p)

*/

float looplen1=10500, looplen2=12700; // in ms

float screenAspectRatio=4.0/3.0;
float screenDiag=PI/2.0 + atan2(screenAspectRatio,1.0);
float screenSize=600;

void setup() {
  size(600,450,P3D);
  colorSetup();
  initPlants();
}

void draw() {
  background(murkybrown);
  updatePlants(30);
}

void keyPressed() {
  initPlants();
}




/////////////////////////////////////////////////////////////////////////
////////////////////////////// Plant Class //////////////////////////////

// vars:
Plant[] plant;
int nrOfPlant=0, nrOfMaxPlant=100;

// routines:
void initPlants() { 
  plant=new Plant[nrOfMaxPlant];
  for (int i=0;i<nrOfMaxPlant;i++) { plant[i]=new Plant(); } 
}
void updatePlants(int _nr) { 
  for (int i=0;i<_nr;i++) { 
    translate(0,0,-10);
    plant[i].update(i,_nr); 
  } 
}

// class:
class Plant {
  float x1=0,y1=0,x2=0,y2=0;  // start/end position 0..1
  float mainDirection=0; // main direction;

  int nrOfFragments=30;
  float[] frag1_x, frag1_y, frag2_x, frag2_y;
  float deviate2MaxLen;
  float deviate3MaxLen, phase3, circLen3;
  float offdeg1, offdeg2, COS1, SIN1, COS2, SIN2;
  float moveSpeed1, phase1;
  
  Plant() {
    initStartAndEnd();
    initFragments();
  }
  
  void initStartAndEnd() {
    // plant start position
    if (random(1)<0.5) { // plant start on bottom edge
      x1=pow(random(1),0.4); y1=1.1/screenAspectRatio;
    } else { // plant start on right edge
      x1=1.1; y1=pow(random(1),0.4)/screenAspectRatio;
    }
    // plant direction and length
    float offCenter=pow(random(1),2);  // 0: on diagonal; 1: off diagonal
    mainDirection=screenDiag + radians(10)*offCenter*(random(1)<0.5?-1:1);//random(PI/2.0,PI);
    float len=(random(0.7,0.7+(1-offCenter)*0.4))/1.0;
    // -> plant end position
    x2=x1+len*cos(mainDirection);
    y2=y1-len*sin(mainDirection);
  }
  
  void initFragments() {
    frag1_x=new float[nrOfFragments];
    frag1_y=new float[nrOfFragments];
    frag2_x=new float[nrOfFragments];
    frag2_y=new float[nrOfFragments];
    deviate2MaxLen=random(0.01,0.04)*(random(1)<0.5?-1:1);
    deviate3MaxLen=0.3*(random(1)<0.5?-1:1); phase3=random(TWO_PI); circLen3=random(0.5,1.5);
    offdeg1=-PI/2.0-mainDirection; COS1=cos(offdeg1); SIN1=sin(offdeg1);
    offdeg2=PI/2.0-mainDirection; COS2=cos(offdeg2); SIN2=sin(offdeg2);
    moveSpeed1=random(0.4,0.6); phase1=random(TWO_PI);
  }   
     
  void newPositions(float _frq) {  
    for (int i=0;i<nrOfFragments;i++) {
      float perc=i/((float)nrOfFragments-1); // percentage 0..1 from start to endpoint
      // calculate main points: straight line going from start to end
      float main_x=x1+(x2-x1)*perc; 
      float main_y=y1+(y2-y1)*perc;
      // deviation lengths:
      float deviate1Len=0.015*sin(perc*PI);  // main deviation length: shape is sinus
      float deviate2Len=deviate2MaxLen*perc*sin(2*perc*PI+_frq*moveSpeed1+phase1); // grand curved deviation length
      float deviate3Len=deviate3MaxLen*perc*cos(circLen3*perc*PI+phase3);
      // bottom line:
      frag1_x[i]=main_x + deviate1Len*COS1 + deviate2Len*COS1 + deviate3Len*COS1;
      frag1_y[i]=main_y + deviate1Len*SIN1 + deviate2Len*SIN1 + deviate3Len*SIN1;
      // top line:
      frag2_x[i]=main_x + deviate1Len*COS2 + deviate2Len*SIN2 + deviate3Len*COS1;
      frag2_y[i]=main_y + deviate1Len*SIN2 + deviate2Len*COS2 + deviate3Len*SIN1;
    }
  }
  
  void update(int _nr,int _outOfNr) {
    newPositions(TWO_PI*millis()/1000.0);
//    stroke(0,66,0,128);
    noStroke();
    fill(0,66*(1-_nr/(float)_outOfNr),0);
   
    for (int i=0;i<nrOfFragments-1;i++) {
      beginShape(QUAD_STRIP);
      screenVertex(frag1_x[i],frag1_y[i]);
      screenVertex(frag1_x[i+1],frag1_y[i+1]);
      screenVertex(frag2_x[i+1],frag2_y[i+1]);
      screenVertex(frag2_x[i],frag2_y[i]);
      endShape();
    }
  }
  
}
////////////////////////////// Plant Class //////////////////////////////
/////////////////////////////////////////////////////////////////////////





/////////////////////////////////////////////////////////////////////////
////////////////////////////// COLOR SETUP //////////////////////////////
int murkybrown;
void colorSetup() {
  murkybrown=color(42,28,4);
}
////////////////////////////// COLOR SETUP //////////////////////////////
/////////////////////////////////////////////////////////////////////////


void screenLine(float _x1, float _y1, float _x2, float _y2) {
  line(_x1*screenSize,_y1*screenSize,_x2*screenSize,_y2*screenSize);
}
void screenVertex(float _x1, float _y1) {
  vertex(_x1*screenSize,_y1*screenSize);
}
