/*********************************
FIREWORKS
by Keith Pasko
12.6.04

for a fun "bug", uncomment the
fill and rect functions in draw
*********************************/

Explosion[] myExplosion;
int presstime;
int numParticles=700;
int maxExplosions=7;
int [] counter=new int[maxExplosions+2];
float xpos;
float ypos;
int numpressed;
int presscount;
color colur;

boolean active;
PImage beginImage;

void setup()
{
  active=false;
  beginImage=loadImage("beginImage.gif");
  imageMode(CENTER);
  size(600,300);
  ellipseMode(CENTER_RADIUS);
  myExplosion=new Explosion[maxExplosions+2];
  framerate(60);
  smooth();
  noStroke();
  colur=color(255,255,255);
}

void draw(){
  //fill (10,10,20,160);
  //rect (0,0,width,height);
  if (active==true){
    background (10,10,20);

    if (numpressed<maxExplosions+1){
      for (int i=0; i<numpressed;i++){
        myExplosion[i].update();
        myExplosion[i].display();
      }
    }else{
      for (int i=0;i<maxExplosions-1;i++){
        myExplosion[i].update();
        myExplosion[i].display();
      }
    }
  }else{
  beginScreen();
  }
}

void beginScreen()
{
  image (beginImage,300,150);
}

void keyPressed()
{
  if (key==32  && active==false){
     active = true;
     }
     
  if (key=='1'){
    colur=color (213,0,0);
  }else if (key=='2'){
    colur=color(253,167,167);
  }else if (key=='3'){
    colur=color(250,176,17);
  }else if (key=='4'){
    colur=color(253,255,95);
  }else if (key=='5'){
    colur=color(76,245,68);
  }else if (key=='6'){
    colur=color(124,243,250);
  }else if (key=='7'){
    colur=color(11,38,204);
  }else if (key=='8'){
    colur=color(196,151,231);
  }else if (key=='9'){
    colur=color (255,255,255);
  }
}

void mousePressed()
{
  presscount++;
  if (presscount==2*maxExplosions+1){
    presscount=presscount-maxExplosions;
  }

  if (presscount>maxExplosions+1){
    counter[maxExplosions+1]=counter[presscount-maxExplosions-1];
    counter [presscount-maxExplosions-1]=millis();
  }else{
    counter[presscount-1]=millis();
  }
}

void mouseReleased()
{
  numpressed++;
  if (presscount>maxExplosions+1){
    presstime=millis()-counter[presscount-maxExplosions-1];
  }else{
    presstime=millis()-counter[presscount-1];
  }
  xpos=mouseX;
  ypos=mouseY;
  color c=colur;
  float mag=presstime/40;
  mag=constrain(mag,6,15);
  if (numpressed==2*maxExplosions+1){
    numpressed=numpressed-maxExplosions;
  }
  if (numpressed>=maxExplosions+1){
    myExplosion[maxExplosions+1]=myExplosion[numpressed-maxExplosions-1];
    myExplosion[numpressed-maxExplosions-1]=new Explosion (xpos, ypos, mag,c);
  }else{
    myExplosion[numpressed-1]=new Explosion(xpos,ypos,mag,c);
  }

}

///////////////////
//   EXPLOSIONS  //
///////////////////

class Explosion
{
  float x1;
  float y1;
  float magnitude;
  color c;

  Particle[] myParticle;

  Explosion(float xpos,float ypos, float mag, color col)
  {
    x1=xpos;
    y1=ypos;
    magnitude=mag;
    c=col;

    myParticle=new Particle[numParticles];
    for (int i=0;i<numParticles;i++){
      float ag;
      float lif=random(.4,2.1);
      float scl=random(.5,1.5);
      float thet=random(0,PI);
      float ph=random(TWO_PI);
      float inits=random(.12*sq(mag),.20*sq(mag));
      if (presscount>maxExplosions+1){
        ag=(millis()-counter[presscount-maxExplosions-1]);
      }else{
        ag=(millis()-counter[numpressed-1]);
      }
      myParticle[i]=new Particle(scl,thet,ph,inits,lif,ag);
    }
  }

  void update()
  {
    for (int i=0;i<numParticles;i++){
      if (myParticle[i].z<210){
        myParticle[i].update(x1,y1);
      }
    }
  }

  void display()
  {
    for (int i=0;i<numParticles;i++){
      if (myParticle[i].z<210){
        myParticle[i].display(x1,y1,c);
      }
    }
  }

}

///////////////////
//   PARTICLES   //
///////////////////

class Particle
{
  float x;
  float y;
  float z;
  float s;              //initial speed
  float siz_max;            //max particle size
  float theta;          //spherical coordinates - angle from z-axis
  float phi;            //spherical coordinates - rotation around y-axis
  float life;          //particle lifespan
  float age;          //how long the particle has lived
  float vel3d;        //instantaneous velocity in 3 dimensions
  float dragcoef;    //drag at any given time
  float windcoef;
  float gravcoef;
  float siz;          //size of particle (changable)
  float op;      //opacity

  float drag=1;        //drag force amount
  float gravity=5;      //gravity force amount
  float wind=0;        //wind force amount
  float winddir=0;      //wind direction
  float e=2.178;    // Euler's constant e
  float sramp=.4;   //age at which particles grow to regular size

  Particle (float scl,float thet,float ph, float inits, float lif, float ag)
  {
    siz_max=scl;
    theta=thet;
    phi=ph;
    s=inits;
    life=lif;
    age=ag;
  }

  void update(float x0,float y0)
  {
    if ((age/1000)>life){
      op=0;
    }

    if((age/1000)>life){
      op=((life-age/1000))*255;
    }else{
      op=255;
    }

    if (z>210){
      op=0;
    }

    if ((age/1000)<sramp){
      siz=((age/1000)/sramp)*siz_max;
    }else{
      siz=siz_max;
    }

    vel3d=sqrt((sq(s*sin(theta)*cos(phi))+sq(-s*cos(theta))+sq(s*sin(theta)*sin(phi))));

    if (drag>0){
      dragcoef=vel3d*(1-pow(e,(-drag*(age/1000))))/drag;
    }else{
      dragcoef=vel3d*(age/1000);
    }

    gravcoef=gravity*age/1000;

    x+=dragcoef*s*sin(theta)*cos(phi)/vel3d;//+windcoef*cos(winddir);
    y+=dragcoef*-s*cos(theta)/vel3d;//+gravcoef;
    z=dragcoef*s*sin(theta)*sin(phi)/vel3d;//+windcoef*sin(winddir);

  }

  void display(float x0,float y0, color c)
  {
    push();
    translate (x0+x,y0+y,z);
    fill(red(c)+random(-30,30),green(c)+random(-30,30),blue(c)+random(-30,30),op);
    ellipse(0,0,siz,siz);
    pop();
  }

}

Project 4: Context
Extend an idea you've explored previously in your life, but adapt it to the context of an interactive system which requires the viewer to engage with the material.