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.*; 

public class circleSegmentsAlt extends BApplet {
// title:  circle segments demo
// author: toxi@toxi.co.uk
// date:   11/08/03

int stepSize=10;
int numParts=25;
float rx=0;
float ry=0;
Part[]  parts;

void setup() {
  size(505,255);
  background(0xfff0e8d0);
  noStroke();
  parts=new Part[numParts];
  for(int i=0; i<numParts; i++) {
    parts[i]=new Part();
  }
}

void loop() {
  rx+=((width/2-mouseX)*0.01f-rx)*0.1f;
  ry+=((height/2-mouseY)*0.01f-ry)*0.1f;
  
  translate(width/2,height/2,-50);
  rotateY(rx);
  rotateX(ry);
  for(int i=0; i<numParts; i++) {
    translate(0,0,2);
    parts[i].update();
  }
}

// respawn all parts on mouse click
void mousePressed() {
  for(int i=0; i<numParts; i++) parts[i].init();
}

/**
* draws a circle segment between start <-> end angle (in degrees)
* inner and outer radius specify width
* colour param is base colour only to which an alpha gradient is applied
* out radius is tapered
* z coordinate increases every step
*/

void drawSegment(int s, int e, int r1, int r2, int c, float zInc) {

  // flag to indicate reversed vertex order
  // for every other row when creating QUAD_STRIP
  boolean rowflag=true;

  // precalc colour components
  int cr= c>>16 &0xff;
  int cg= c>>8  &0xff;
  int cb= c     &0xff;

  // alpha increase per step
  int astep=224/((e-s)/stepSize);
  int a=0;

  float rr2=(float)r2;
  float r2step=(r2-r1)/(float)((e-s)/stepSize);
  
  float z=0;
  
  beginShape(QUAD_STRIP);
  
  // add first vertices
  fill(cr,cg,cb,a);
  float ts=sin(radians(s));
  float tc=cos(radians(s));
  vertex(tc*r1,ts*r1,z); vertex(tc*rr2,ts*rr2,z);
  
  // add intermediate vertices, snap to {step} degrees
  while((s=((s+stepSize)/stepSize)*stepSize)<e) {
    ts=sin(radians(s));
    tc=cos(radians(s));
    // increase alpha value
    a+=astep;
    rr2=max(rr2-r2step,r1);
    z+=zInc;
    
    fill(cr,cg,cb,a);
    // use correct vertex order
    if (rowflag) {
      vertex(tc*rr2,ts*rr2,z); vertex(tc*r1,ts*r1,z);
    } else {
      vertex(tc*r1,ts*r1,z); vertex(tc*rr2,ts*rr2,z);
    }
    // reverse vertex order for next step
    rowflag=!rowflag;
  }
  
  // add last 2 vertices at end angle
  ts=sin(radians(e));
  tc=cos(radians(e));
  fill(cr,cg,cb,a);
  if (rowflag) {
    vertex(tc*rr2,ts*rr2,z); vertex(tc*r1,ts*r1,z);
  } else {
    vertex(tc*r1,ts*r1,z); vertex(tc*rr2,ts*rr2,z);
  }
  endShape();
}

class Part {
  // start/end angle of segment
  float start,end;
  // inner/outer radius
  int r1,r2;
  // transition factor
  float f;
  // colour
  int col;
  // move speed
  float speed;
  // z twist
  float zInc;
  
  public Part() {
    init();
  }

  void update() {
    f+=(1-f)*0.04f; // slowly fade in
    drawSegment((int)start,(int)end,(int)(r1*f),(int)(r2*f),col,zInc);
    start+=speed;
    end+=speed;
    if (start<0) { start+=360; end+=360; }
    else if (start>360) { start-=360; end-=360; }
  }
  
  void init() {
    start=random(360);
    end=random(30,300)+start;
    r1=(int)random(30,180);
    r2=(int)random(20,100)+r1;
    col=(int)random(0xffffff);
    speed=random(-15,15);
    zInc=random(10);
    // if speed is negative, expand segment in opposite Z direction
    if (speed<0) zInc=-zInc;
    f=0;
  }
}

}