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

import processing.opengl.*; 

import java.applet.*; 
import java.awt.Dimension; 
import java.awt.Frame; 
import java.awt.event.MouseEvent; 
import java.awt.event.KeyEvent; 
import java.awt.event.FocusEvent; 
import java.awt.Image; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 
import java.util.regex.*; 

public class etoiles_qui_tournent_et_changent_de_nuance extends PApplet {

/*

 ROTATING PULSING STARS - Roald Baudoux 2011
 EACH STAR PULSES AT A DIFFERENT RATE AND ROTATES IN 3 D AROUND ITS CENTER
 THE GLOBAL 3D SPACE ROTATES AROUND ITSELF TOO
 HSB COLORS WITH VARYING HUE
 
*/



// VARIABLES
int numCubes = 200;
int maxDistance = 400;
PVector[] places = new PVector[numCubes]; // stores positions of cubes
PVector[] angles = new PVector[numCubes]; // stores orientations of cubes
PVector[] rotFreq = new PVector[numCubes]; // stores rotation frequencies of cubes in 3 D
float[] pulsFreq = new float[numCubes]; // stores pulsation frequencies for hue+saturation variation
float phaseX ; // phase for rotation around own center 
float phaseY ;
float phaseZ ;
int rate = 120; // set frameRate here
float currentPulse; //pulsation for HSB color variation
float currentHue;
float currentSat;
float myHue1 = 40; // star's start hue
float myHue2 = 180; // star's final hue
float mySat1 = 255; // star's start saturation
float mySat2 = 0; // star's intermediate saturation
float mySat3 = 255; // star's final saturation
float xRotateFrequency =  .503f ; //frequency for rotation around x axis
float yRotateFrequency =  .307f ; //frequency for rotation around y axis
float zRotateFrequency = .409f ; //frequency for rotation around z axis

public void setup() {
  size (500, 500, OPENGL);
  colorMode(HSB);
  frameRate(rate);
  //lights();
  noStroke();
  //stroke(44, 255, 255, 255);
  //strokeWeight(0);
  for (int i = 0; i < numCubes; i++) {
    places[i] = new PVector (random(0, maxDistance), random(0, maxDistance), random(-100, maxDistance)) ;
    angles[i] = new PVector (random(0, TWO_PI), random(0, TWO_PI), random(0, TWO_PI)) ;
    pulsFreq[i] = pow(10.f, random(-1.0f, 0.5f)) ;
    rotFreq[i] = new PVector (pow(10.f, random(-1.f, 0.001f)), pow(10.f, random(-1, 0.001f)), pow(10.f, random(-1, 0.001f))) ;
  }
}

public void draw() {
  background (0, 0, 0, 0);
  smooth();
  translate(width/2, height/2, 0);
  rotateX(xRotateFrequency * PApplet.parseFloat(frameCount) / PApplet.parseFloat(rate));
  rotateY(yRotateFrequency * PApplet.parseFloat(frameCount) / PApplet.parseFloat(rate));
  rotateZ(zRotateFrequency * PApplet.parseFloat(frameCount) / PApplet.parseFloat(rate));
  for (int i = 0; i < numCubes; i++) {
    pushMatrix() ;
    smooth();
    // POSITION AROUND CENTER
    rotateX(angles[i].x);
    rotateY(angles[i].y);
    rotateZ(angles[i].z);
    translate(places[i].x, places[i].y, places[i].z);
    // ORIENTATION
    phaseX = (((rotFreq[i].x * PApplet.parseFloat(frameCount) / PApplet.parseFloat(rate)) * TWO_PI) % TWO_PI);
    phaseY = (((rotFreq[i].y * PApplet.parseFloat(frameCount) / PApplet.parseFloat(rate)) * TWO_PI) % TWO_PI);
    phaseZ = (((rotFreq[i].z * PApplet.parseFloat(frameCount) / PApplet.parseFloat(rate)) * TWO_PI) % TWO_PI);
    rotateX(phaseX);
    rotateY(phaseY);
    rotateZ(phaseZ);
    // COLOR
    currentPulse = unipolarTriangle((pulsFreq[i] * PApplet.parseFloat(frameCount) / PApplet.parseFloat(rate)) % 1.f) ;
    // SETS HUE
    if (currentPulse < 0.5f ) {
      currentHue = myHue1 ;
    } else {
      currentHue = myHue2 ;     
    }
    // SETS SATURATION
    if (currentPulse < 0.5f ) {
      currentSat = PApplet.parseInt(((1.f - (2.f * currentPulse)) * mySat1) + ((2.f * currentPulse) * mySat2)) ;
    } else {
      currentSat = PApplet.parseInt(((1.f - (2.f * (currentPulse - 0.5f))) * mySat2) + ((2.f * (currentPulse - 0.5f)) * mySat3)) ;      
    }
    fill(currentHue, currentSat, 255, 255);
    scale(30);
    // DRAWS STAR
    beginShape() ;
    vertex(sin(0), cos(0), 0);
    vertex((sin(TWO_PI/10))/2.6f, (cos(TWO_PI/10))/2.6f, 0);
    vertex(sin(2 * TWO_PI/10), cos(2 * TWO_PI/10), 0);
    vertex((sin(3 * TWO_PI/10))/2.6f, (cos(3 * TWO_PI/10))/2.6f, 0);
    vertex(sin(4 * TWO_PI/10), cos(4 * TWO_PI/10), 0);
    vertex((sin(5 * TWO_PI/10))/2.6f, (cos(5 * TWO_PI/10))/2.6f, 0);
    vertex(sin(6 * TWO_PI/10), cos(6 * TWO_PI/10), 0);
    vertex((sin(7 * TWO_PI/10))/2.6f, (cos(7 * TWO_PI/10))/2.6f, 0);
    vertex(sin(8 * TWO_PI/10), cos(8 * TWO_PI/10), 0);
    vertex((sin(9 * TWO_PI/10))/2.6f, (cos(9 * TWO_PI/10))/2.6f, 0);
    endShape(CLOSE);
    popMatrix() ;
  }

}

public float unipolarTriangle(float phase) 
{
 float amp;
 amp = min(phase, 1.f) ;
 if (amp > 0.5f ) {
   amp = 0.5f - (amp - 0.5f);
 }
 amp *= 2.f;
 return amp;
}

  static public void main(String args[]) {
    PApplet.main(new String[] { "--present", "--bgcolor=#666666", "--stop-color=#cccccc", "etoiles_qui_tournent_et_changent_de_nuance" });
  }
}
