import processing.core.*; 
import processing.data.*; 
import processing.event.*; 
import processing.opengl.*; 

import ddf.minim.*; 

import java.util.HashMap; 
import java.util.ArrayList; 
import java.io.File; 
import java.io.BufferedReader; 
import java.io.PrintWriter; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.IOException; 

public class smoke extends PApplet {



AudioPlayer player;
Minim minim;

PShape s;
PFont f;

float i = 0.0f;

ParticleSystem ps0;
ParticleSystem ps1;
ParticleSystem ps2;
ParticleSystem ps3;

ParticleSystem ps4;
ParticleSystem ps5;
ParticleSystem ps6;
ParticleSystem ps7;

ParticleSystem ps8;
ParticleSystem ps9;
ParticleSystem ps10;
ParticleSystem ps11;

public void setup() {
//  size(640,360, P3D);
  size(1280, 720, P3D);
  ps0 = new ParticleSystem(0,new PVector(width / 2, height / 2));
  ps1 = new ParticleSystem(0,new PVector(width, height / 2));
  ps2 = new ParticleSystem(0,new PVector(width, 0));
  ps3 = new ParticleSystem(0,new PVector(width / 2, 0));

  ps4 = new ParticleSystem(0,new PVector(width / 2, height / 2, width / 2));
  ps5 = new ParticleSystem(0,new PVector(width, height / 2, width / 2));
  ps6 = new ParticleSystem(0,new PVector(width, 0, width / 2));
  ps7 = new ParticleSystem(0,new PVector(width / 2, 0, width / 2));

  ps8 = new ParticleSystem(0,new PVector(width / 2, height / 2, -width / 2));
  ps9 = new ParticleSystem(0,new PVector(width, height / 2, -width / 2));
  ps10 = new ParticleSystem(0,new PVector(width, 0, -width / 2));
  ps11 = new ParticleSystem(0,new PVector(width / 2, 0, -width / 2));
  setupMusic();
  s = loadShape("face.obj");
  f = createFont("Arial",72,true); 
}


public void setupMusic() {
  minim = new Minim(this);
  player = minim.loadFile("music.mp3", 2048);
  player.play();
}

public void draw() {
  setupWorldViews();
  setupParticleSystems();
}

public void setupWorldViews() {
  background(0);
  camera(
    sin(millis() * 0.0005f) * (width / 2.0f), height * 0.25f , cos(millis() * 0.0005f) * (width / 2),
    width, sin(millis() * 0.001f) * height, 0.0f,
    0, 1, 0
  );
  perspective();
  ambientLight(255, 255, 255);
  directionalLight(255, 0, 0, 1, 0, 0);
  directionalLight(255, 0, 0, -1, 0, 0);
  directionalLight(0, 255, 0, 0, 1, 0);
  directionalLight(0, 255, 0, 0, -1, 0);
  directionalLight(0, 0, 255, 0, 0, 1);
  directionalLight(0, 0, 255, 0, 0, -1);
  pushMatrix();
  translate(width * 0.75f, height * 0.25f, 0);
  rotate(i, 1, -1, 1);
  scale((sin(millis() * 0.0005f) * sin(millis() * 0.0005f) * 10) + 1);
  shape(s);
  popMatrix();
  i += 0.05f;
  
  pushMatrix();
  textFont(f);
  fill(255);
  translate(width, -height, 0);
  rotate(HALF_PI, 0, -1, 0);
  text("Demoscene: 3D Fire Disco", 0, 0);
  text("Made by unixman", 0, 72);
  text("For Graffathon 2015", 0, 72 * 2);
  popMatrix();
}

public void setupParticleSystems() {
  runParticleSystem(ps0);
  runParticleSystem(ps1);
  runParticleSystem(ps2);
  runParticleSystem(ps3);
  runParticleSystem(ps4);
  runParticleSystem(ps5);
  runParticleSystem(ps6);
  runParticleSystem(ps7);
  runParticleSystem(ps8);
  runParticleSystem(ps9);
  runParticleSystem(ps10);
  runParticleSystem(ps11);
}


public void runParticleSystem(ParticleSystem ps) {
  float dx = sin(millis() * 0.001f) * 0.01f;
  float dy = cos(millis() * 0.001f) * 0.01f;
  PVector wind = new PVector(dx,dy);
  ps.applyForce(wind);
  ps.run();
  for (int i = 0; i < 2; i++) {
    ps.addParticle();
  }
} 

class ParticleSystem {

  ArrayList<Particle> particles;
  PVector origin;
  PImage img;
  
  ParticleSystem(int num, PVector v) {
    particles = new ArrayList<Particle>();
    origin = v.get();
    for (int i = 0; i < num; i++) {
      particles.add(new Particle(origin, img));
    }
  }

  public void run() {
    for (int i = particles.size()-1; i >= 0; i--) {
      Particle p = particles.get(i);
      p.run();
      if (p.isDead()) {
        particles.remove(i);
      }
    }
  }

  public void applyForce(PVector dir) {
    // Enhanced loop!!!
    for (Particle p: particles) {
      p.applyForce(dir);
    }
  
  }  

  public void addParticle() {
    particles.add(new Particle(origin,img));
  }

}

class Particle {
  PVector loc;
  PVector vel;
  PVector acc;
  float lifespan;
  PImage img;

  Particle(PVector l,PImage img_) {
    acc = new PVector(0,0);
    float vx = randomGaussian() * 0.3f;
    float vy = randomGaussian() * 0.3f - 1.0f;
    vel = new PVector(vx,vy);
    loc = l.get();
    lifespan = 500.0f;
  }

  public void run() {
    update();
    render();
  }

  public void applyForce(PVector f) {
    acc.add(f);
  }  

  // Method to update location
  public void update() {
    vel.add(acc);
    loc.add(vel);
    lifespan -= 2.5f;
    acc.mult(0);
  }

  public void render() {
    fill(240, 117, 17, lifespan);
    noStroke();
    pushMatrix();
    translate(loc.x, loc.y, loc.z);
    box(10);
    popMatrix();
  }

  public boolean isDead() {
    if (lifespan <= 0.0f) {
      return true;
    } else {
      return false;
    }
  }
}

public void stop()
{
  player.close();
  minim.stop();
  super.stop();
}
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "--full-screen", "--bgcolor=#666666", "--hide-stop", "smoke" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
