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

int stepSize=8;
int numParts=20;
float rx,ry;

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,10);
    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
*/

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

  // 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=128/((e-s)/stepSize);
  int a=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); vertex(tc*r2,ts*r2);
  
  // 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;
    fill(cr,cg,cb,a);
    // use correct vertex order
    if (rowflag) {
      vertex(tc*r2,ts*r2); vertex(tc*r1,ts*r1);
    } else {
      vertex(tc*r1,ts*r1); vertex(tc*r2,ts*r2);
    }
    // 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*r2,ts*r2); vertex(tc*r1,ts*r1);
  } else {
    vertex(tc*r1,ts*r1); vertex(tc*r2,ts*r2);
  }
  endShape();
}

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

  void update() {
    drawSegment((int)start,(int)end,r1,r2,col);
    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,220)+start;
    r1=(int)random(200);
    r2=(int)random(20,100)+r1;
    col=(int)random(0xffffff);
    speed=random(-10,10);
  }
}

}