import processing.core.*; 
import processing.xml.*; 

import java.applet.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 
import java.util.regex.*; 

public class primavera3 extends PApplet {

Flor F[];
int numF;
VectorField V;
Personaje P;
Polen[] Pol;
Burbuja B;
PImage fondo;
PFont fuente;
int cuenta;

public void setup() {
  size(450,500,P3D);
  background(255); 
  frameRate(30);
  fondo = loadImage("arbol.jpg");
  numF = 20;
  F = new Flor[numF];  
  Pol = new Polen[numF+1];
  for (int n = 0; n < numF; n++) {
    F[n] = new Flor();
    Pol[n] = new Polen(n);    
  }
  Pol[numF] = new Polen(numF);
  V = new VectorField(10, 15);
  P = new Personaje();
  B = new Burbuja();
  fuente = loadFont("DejaVuSansMono-24.vlw");
  textFont(fuente);
  textMode(SCREEN);
  cuenta = 0;
}

public void idle() {
  if (keyPressed) {
    if (!P.salto) {
      if (keyCode == UP) {
        P.sobre = false;
        P.salto = true;
        P.vy -= 10;
        if (keyCode == LEFT)
          P.vx -= .5f;
        if (keyCode == RIGHT)
          P.vx += .5f;        
      }
      if (P.y > height-2*P.r-1 && keyCode == LEFT)
        P.vx -= 3;
      if (P.y > height-2*P.r-1 && keyCode == RIGHT)
        P.vx += 3;
    }
    if (P.salto) {
      if (keyCode == LEFT)
        P.vx -= .2f;
      if (keyCode == RIGHT)
        P.vx += .2f;
    }
  }
  V.idle();  
  P.idle();
  B.idle();
  for (int n = 0; n < numF; n++) {
    F[n].idle();
    Pol[n].idle();
  }
  Pol[numF].idle_burbuja();
}

public void draw() {
  ambientLight(128, 128, 128);
  directionalLight(128, 128, 128, 0, 0, 1);
  lightFalloff(1, 0, 0);
  lights();  
  if (frameCount %50 == 0) println(frameRate);
  idle();
  background(fondo);
//  V.draw();
  B.draw();
  P.draw();    
  for (int n = 0; n < numF; n++) {
    F[n].draw();
    Pol[n].draw();
  }
  Pol[numF].draw();
  fill(50);
  int n5 = floor(cuenta/10000);
  int n4 = floor((cuenta-n5*10000)/1000);
  int n3 = floor((cuenta-n5*10000-n4*1000)/100);
  int n2 = floor((cuenta-n5*10000-n4*1000-n3*100)/10);  
  int n1 = floor((cuenta-n5*10000-n4*1000-n3*100-n2*10));   
//  text(n5, width-22, height-112);
  text(n4, width-22, height-97);  
  text(n3, width-22, height-77);
  text(n2, width-22, height-57);
  text(n1, width-22, height-37);  
  fill(255,100,100);
  text("p", width-22, height-17);   
}

public void keyReleased() {
  if (keyCode == UP) {
    if (!P.salto) P.salto = true;    
  }
}
class Burbuja {
  
  float x, y;
  boolean comida;
  float r;
  int fc0;
  PImage burbuja;
  
  Burbuja() {
    fc0 = 300;
    x = random(100,width-100);
    y = height-50;//random(200,height-100);
    r = 10;
    burbuja = loadImage("burbuja.png");
  }
  
  public void idle() {
    if (comida) {
      x = random(100,width-100);
      y = random(200,height-100);      
      fc0 = frameCount;
      comida = false;
    }
  }
  
  public void draw() {
    if (frameCount > fc0 && !comida) {
      image(burbuja, x - burbuja.width*.5f, y - burbuja.height*.5f);
    }
  }
  
}


class Flor {
  
  float x, y;
  float vx, vy;
  float r;
  int fc0;
  boolean activo;
  int h1, h2;
 
  Flor() {
    x = random(80, width-80);
    y = random(20,80);
    r = 20;
    vx = 0;
    vy = 1.5f;
    fc0 = floor(random(1000));
    activo = false;
    h1 = floor(random(100,150));
    h2 = floor(random(100,150));    
  } 
  
  public void nueva() {
    x = random(80, width-80);
    y = random(20,80);
    vx = 0;
    vy = 1.5f;    
//    fc0 += frameCount;
    activo = false;
  }
  
  public void idle() {
    if (frameCount > fc0) {
      activo = true;
      V.altera(x, y);    
      float ang = V.viento(x, y);
      vx += .015f*V.l*cos(ang);
      vy += .015f*V.l*sin(ang);    
      vx = constrain(vx, -1.5f, 1.5f);
      vy = constrain(vy, -1.5f, 1.5f);
      x += vx;
      y += vy;
      if (y > height+r || y < -r) nueva();
      if (x > width+r || x < -r) nueva();    
    }
  }
  
  public void draw() {
    noStroke();
//    stroke(50);
//    if (activo)

    fill(255, 255-h1, 255-h2, 100);    
    pushMatrix();
    translate(x, y, 0);
    rotateX(PI/2);
    float l = r*.5f;
    for (int n = 0; n < 5; n++) {
      pushMatrix();
      rotateZ(PI/2.5f*n+frameCount*0.03f);
      beginShape();
      vertex(0, 0, -l);
      bezierVertex(l*.5f, 0, 0, l, l*.5f, 0, l, l, 0);
      bezierVertex(l, 1.5f*l, 0, l*.5f, 1.5f*l, l, 0, 2*l, l);
      bezierVertex(-l*.5f, 1.5f*l, l, -l, 1.5f*l, 0, -l, l, 0);  
      bezierVertex(-l, l*.5f, 0, -l*.5f, 0, 0, 0, 0, -l);
      endShape();
      popMatrix();
    }
    popMatrix();
//    ellipse(x, y, r, r);
  }
  
}
class Personaje {
  
  float x, y;
  float vx, vy;
  int nIn;
  float r;
  boolean salto;
  boolean sobre;
  PImage hormiga0, hormiga1;
  
  Personaje() {
    r = 10;
    x = width*.5f;
    y = height-r;
    vx = 0; vy = 0;
    salto = false;
    sobre = true;
    nIn = -1;
    hormiga0 = loadImage("hormiga0.png");
    hormiga1 = loadImage("hormiga1.png");    
  } 
  
  public void idle() {    
    x += vx;
    y += vy;   
    if (salto) {
      nIn = -1;
      vx *= .97f;
      vy += .3f;
      float ang = V.viento(x, y);
      vx += 0.01f*V.l*cos(ang);
      vy += 0.01f*V.l*sin(ang);  
      vx = constrain(vx, -2, 2);          
      vy = constrain(vy, -5, 5);    
      boolean s = true;
      for (int n = 0; n < numF; n++) {
        if (abs(x-F[n].x) < 2*r && abs(y-F[n].y) < r) {
          nIn = n;          
          salto = false;
          sobre = true;
          s = false;
          Pol[nIn].poliniza(F[nIn].x, F[nIn].y);        
        }
      }        
      if (s) {sobre = false; salto = true;}
    }    
    if (sobre) {
      vx = 0;
      vy = 0;
      if (nIn != -1) {
        x = F[nIn].x;
        y = F[nIn].y-F[nIn].r*.5f-r*.5f;
        if (abs(x-F[nIn].x) > 1.5f*r && abs(y-F[nIn].y) > .75f*r) {           
          sobre = false;
          salto = true;
        }        
      }
    }
    else salto = true;
    if (dist(x, y, B.x, B.y) < 2*B.r) {
      B.comida = true;
      Pol[numF].poliniza(B.x,B.y);          
      cuenta += 1000;
    }    
    if (x + r > width-1 || x < -r) {sobre = false; salto = true;}
    x = constrain(x, 0, width-r);
    if (y + r > height-1) {
      cuenta = 0;
      y = height-hormiga1.height*.5f;
      sobre = true;
      salto = false;
    }
  }
  
  public void draw() {
    fill(150);
    noStroke();
    pushMatrix();
    translate(x, y, 0);
    if (salto)
      image(hormiga0, -hormiga0.width*.5f, -hormiga0.height*.5f);
    else
      image(hormiga1, -hormiga1.width*.5f, -hormiga1.height*.5f);      
//    scale(1.3,1);
//    sphere(r*.7);     
    popMatrix();
  }
  
}
class Polen {
  
  int numP;
  float[] x, y;
  float x0, y0;
  float[] vx, vy;
  float[] d;  
  int[] fc0;
  boolean[] comida;
  int vida;
  int id;
  
  Polen(int id_) {
    id = id_;
    numP = 50;
    vida = 50;
    x0 = width*.5f;
    y0 = height*.5f;
    x = new float[numP];
    y = new float[numP];
    vx = new float[numP];
    vy = new float[numP];
    fc0 = new int[numP]; 
    d = new float[numP];   
    comida = new boolean[numP];
    for (int n = 0; n < numP; n++) {
      x[n] = x0+5*random(-1,1);
      y[n] = y0+5*random(-1,1);
      vx[n] = random(-1,1);
      vy[n] = -1+random(-1,1);
      fc0[n] = -1000;
      d[n] = 5;
      comida[n] = false;
    }
  } 
  
  public void poliniza(float x_, float y_) {
    x0 = x_; 
    y0 = y_;
    for (int n = 0; n < numP; n++) {
      x[n] = x0+5*random(-1,1);
      y[n] = y0+5*random(-1,1);
      vx[n] = V.l*random(-1,1);
      vy[n] = -1+V.l*random(-1,1);
      fc0[n] = frameCount+floor(random(0,100));
      if (id == numF) fc0[n] = frameCount + floor(random(0,20));
      comida[n] = false;      
    }    
  }
  
  public void idle() {
    for (int n = 0; n < numP; n++) {
      if (frameCount-fc0[n] > 0 && frameCount-fc0[n] < vida) {
        float ang = V.viento(x[n],y[n]);
        float vvx = V.l*cos(ang);
        float vvy = V.l*sin(ang);        
        x[n] += vx[n]+vvx;
        y[n] += vy[n]+vvy;
        vy[n] += 0.01f;
        if (dist(x[n],y[n],P.x,P.y) < 2*P.r) {
          comida[n] = true;
          d[n] = 10;          
          cuenta++;            
        }
        else d[n] = 5;
      }
      else {
        x[n] = F[id].x;
        y[n] = F[id].y;
      }
    }
  }

  public void idle_burbuja() {
    for (int n = 0; n < numP; n++) {
      if (frameCount-fc0[n] > 0 && frameCount-fc0[n] < vida) {
        comida[n] = true;
        d[n] = 10;
        float ang = V.viento(x[n],y[n]);
        float vvx = V.l*cos(ang);
        float vvy = V.l*sin(ang);        
        x[n] += vx[n]+vvx;
        y[n] += vy[n]+vvy;
        vy[n] += 0.01f;
      }
    }
  }
  
  public void draw() {
    stroke(120,255,255);
    noFill();
    for (int n = 0; n < numP; n++) {
      if (!comida[n]) fill(120,255,255);      
      if (frameCount-fc0[n] > 0 && frameCount-fc0[n] < vida) {          
        ellipse(x[n], y[n], d[n], d[n]);
      }
    }
  }
}

class VectorField {
  
  int nX, nY;
  int num;
  float ang[][];
  float x[][], y[][];
  float w, h;
  float l;
  
  VectorField(int nX_, int nY_) {
    nX = nX_;
    nY = nY_;
    num = nX*nY;
    w = (float)width/nX;
    h = (float)height/nY;
    l = 3;
    x = new float[nX][nY];
    y = new float[nX][nY];
    ang = new float[nX][nY];    
    for (int i = 0; i < nX; i++) {
      for (int j = 0; j < nY; j++) {
        x[i][j] = (i+.5f)*w;
        y[i][j] = (j+.5f)*w;        
        ang[i][j] = 0.f;
      }
    }
  } 
  
  public void idle() {
    float f2 = (frameCount %600 < 300)?-PI/2:0;
    for (int i = 0; i < nX; i++) {
      for (int j = 0; j < nY; j++) {   
        float angi_1 = (i == 0)?f2+0:ang[i-1][j];
        float angim1 = (i == nX-1)?f2-PI:ang[i+1][j];        
        float angj_1 = (j == 0)?f2+PI/2.f:ang[i][j-1];        
        float angjm1 = (j == nY-1)?f2-PI/2.f:ang[i][j+1];                
        ang[i][j] = .25f*(angi_1 + angim1 + angj_1 + angjm1);
      }
    }
  }
  
  public float viento(float x_, float y_) {
    int i = constrain(floor(x_/w), 0, nX-1);
    int j = constrain(floor(y_/h), 0, nY-1);
    return ang[i][j];
  }
  
  public void altera(float x_, float y_) {
    float angV = atan2(y_, x_)+PI/2.f;    
    for (int i = 0; i < nX; i++) {
      for (int j = 0; j < nY; j++) {  
        float d = dist(x[i][j], y[i][j], x_, y_);
        if (d < 50) {
          float f = l*(1-d/50.f);
          ang[i][j] += f*(angV-ang[i][j]);          
        }
      }
    }
  }
  
  public void draw() {
    stroke(50);
    for (int i = 0; i < nX; i++) {
      for (int j = 0; j < nY; j++) {    
        float x2 = x[i][j] + l*cos(ang[i][j]);
        float y2 = y[i][j] + l*sin(ang[i][j]);    
        line(x[i][j], y[i][j], x2, y2);
      }
    }
  }
  
}

  static public void main(String args[]) {
    PApplet.main(new String[] { "--bgcolor=#c4c4c4", "primavera3" });
  }
}
