SCPattern moved out of GLucose
[SugarCubes.git] / JR.pde
diff --git a/JR.pde b/JR.pde
index cd494fa02b84a000f452c462ecf209595a720f8c..4abcc62c1226d1b25dd1a8fbb0b162bae8364966 100644 (file)
--- a/JR.pde
+++ b/JR.pde
@@ -1,13 +1,15 @@
-color BLACK = color(0, 0, 0);
+color BLACK = #000000;
 
 class Gimbal extends SCPattern {
 
+  private final PerfTimer perf = new PerfTimer();
+  
   private final boolean DEBUG_MANUAL_ABG = false;
   private final int MAXIMUM_BEATS_PER_REVOLUTION = 100;
   
   private boolean first_run = true;
-  private final Projection projection;
-  private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 20./MAXIMUM_BEATS_PER_REVOLUTION);
+  private final LXProjection projection;
+  private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 25./MAXIMUM_BEATS_PER_REVOLUTION);
   private final BasicParameter hueDeltaParam = new BasicParameter("HUED", 60./360);
   private final BasicParameter fadeFromCoreParam = new BasicParameter("FADE", 1);
   private final BasicParameter girthParam = new BasicParameter("GRTH", .18);
@@ -19,9 +21,9 @@ class Gimbal extends SCPattern {
   private final BasicParameter bP = new BasicParameter("b", 0);
   private final BasicParameter gP = new BasicParameter("g", 0);
 
-  Gimbal(GLucose glucose) {
-    super(glucose);
-    projection = new Projection(model);
+  Gimbal(LX lx) {
+    super(lx);
+    projection = new LXProjection(model);
     addParameter(beatsPerRevolutionParam);
     addParameter(hueDeltaParam);
     addParameter(fadeFromCoreParam);
@@ -75,41 +77,53 @@ class Gimbal extends SCPattern {
     Ring ring2 = new Ring((hue + hue_delta * 1) % 360, radius2, girth);
     Ring ring3 = new Ring((hue + hue_delta * 2) % 360, radius3, girth);
 
-    projection.reset(model)
+    projection.reset()
       // Translate so the center of the car is the origin
-      .translateCenter(model, 0, 0, 0);
+      .center();
 
-    for (Coord c : projection) {
+    for (LXVector c : projection) {
       //if (first_run) println(c.x + "," + c.y + "," + c.z);
 
-      rotate3d(c, a, 0, 0);
-      rotate3d(c, PI/4, PI/4, PI/4);
+      rotate3dA(c, a);
+      rotate3dPiOver4(c);
       color color1 = ring1.colorFor(c);
 
-      rotate3d(c, 0, b, 0);
+      rotate3dB(c, b);
       color color2 = ring2.colorFor(c);
 
-      rotate3d(c, 0, 0, g);
+      rotate3dG(c, g);
       color color3 = ring3.colorFor(c);
             
       colors[c.index] = specialBlend(color1, color2, color3);      
     }
 
-    first_run = false;
+    first_run = false;    
   }
 
   class Ring {
 
     float hue;
     float radius, girth;
+    float _multiplier;
 
     public Ring(float hue, float radius, float girth) {
       this.hue = hue;
       this.radius = radius;
       this.girth = girth;
+      this._multiplier = 100. / girth * fadeFromCoreParam.getValuef();
     }
 
-    public color colorFor(Coord c) {
+    public color colorFor(LXVector c) {
+      float xy_distance_to_circle = sqrt(c.x * c.x + c.y * c.y) - radius;
+      float z_distance_to_circle = c.z * ringExtendParam.getValuef();
+      
+      float distance_to_circle
+          = sqrt(xy_distance_to_circle * xy_distance_to_circle
+               + z_distance_to_circle * z_distance_to_circle); 
+
+      return lx.hsb(this.hue, 100, 100. - distance_to_circle * _multiplier);
+
+      /* PRE-OPTIMIZED IMPLEMENTATION
       float theta = atan2(c.y, c.x);
       float nearest_circle_x = cos(theta) * radius;
       float nearest_circle_y = sin(theta) * radius;
@@ -121,21 +135,68 @@ class Gimbal extends SCPattern {
                + pow(nearest_circle_z - c.z * ringExtendParam.getValuef(), 2));
 
       float xy_distance = sqrt(c.x*c.x + c.y*c.y);
-      return color(this.hue, 100, (1 - distance_to_circle / girth * fadeFromCoreParam.getValuef()) * 100);
+      return lx.hsb(this.hue, 100, (1 - distance_to_circle / girth * fadeFromCoreParam.getValuef()) * 100);
+      */
     }
-
+    
   }
 
 }
 
 
+class PerfTimer {
+  
+  private final Map<String, Integer> m = new TreeMap<String, Integer>();
+  private String current_phase = null;
+  private int current_phase_start_time = 0;
+  private int total_time = 0;
+  
+  public void start(String phase_name) {
+    if (current_phase != null) {
+      stop();
+    }
+    current_phase = phase_name;
+    current_phase_start_time = millis();
+  }
+  
+  public void stop() {
+    int current_time = millis();
+    
+    assert(current_phase != null);
+    assert(current_phase_start_time != 0);
+    int time_ellapsed = current_time - current_phase_start_time;
+    m.put(current_phase,
+        (m.containsKey(current_phase) ? m.get(current_phase) : 0)
+        + time_ellapsed);
+
+    current_phase = null;
+    current_phase_start_time = 0;
+    total_time += time_ellapsed;
+  }
+  
+  public void report() {
+    if (random(0, 60 * 4) < 1) {
+      println("~~~~~~~~~~~~~~~~~~");
+      for (String phase_name : m.keySet()) {
+        print(phase_name);
+        for (int i = phase_name.length(); i < 30; ++i) {
+          print(" ");
+        }
+        println("" + (float) m.get(phase_name) / total_time);
+      }
+    }
+  }
+  
+}
+
+
 
 
 
 
 class Zebra extends SCPattern {
 
-  private final Projection projection;
+  private final LXProjection projection;
   SinLFO angleM = new SinLFO(0, PI * 2, 30000);
 
 /*
@@ -144,14 +205,14 @@ class Zebra extends SCPattern {
   _P size;
   */
 
-  Zebra(GLucose glucose) {
-    super(glucose);
-    projection = new Projection(model);
+  Zebra(LX lx) {
+    super(lx);
+    projection = new LXProjection(model);
 
     addModulator(angleM).trigger();
   }
 
-  color colorFor(Coord c) {
+  color colorFor(LXVector c) {
     float hue = lx.getBaseHuef();
 
 
@@ -166,18 +227,18 @@ class Zebra extends SCPattern {
     int stripe_count = 12;
     float stripe_width = model.xMax / (float)stripe_count;
     if (Math.floor((c.x) / stripe_width) % 2 == 0) {
-      return color(hue, 100, 100);
+      return lx.hsb(hue, 100, 100);
     } else {
-      return color((hue + 90) % 360, 100, 100);
+      return lx.hsb((hue + 90) % 360, 100, 100);
     }
 
 
     /* OCTANTS
 
     if ((isPositiveBit(c.x) + isPositiveBit(c.y) + isPositiveBit(c.z)) % 2 == 0) {
-      return color(lx.getBaseHuef(), 100, 100);
+      return lx.hsb(lx.getBaseHuef(), 100, 100);
     } else {
-      return color(0, 0, 0);
+      return lx.hsb(0, 0, 0);
     }
     */
   }
@@ -191,11 +252,11 @@ class Zebra extends SCPattern {
     float b = (millis() / 1200.f) % (2 * PI);
     float g = (millis() / 1600.f) % (2 * PI);
 
-    projection.reset(model)
+    projection.reset()
       // Translate so the center of the car is the origin
-      .translateCenter(model, 0, 0, 0);
+      .center();
 
-    for (Coord c : projection) {
+    for (LXVector c : projection) {
 //      rotate3d(c, a, b, g);
       colors[c.index] = colorFor(c);
     }
@@ -215,7 +276,45 @@ class Zebra extends SCPattern {
 
 }
 
-void rotate3d(Coord c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
+float HALF_OF_ONE_OVER_SQRT2_MINUS_1 = (1./sqrt(2) - 1) / 2;
+float HALF_OF_ONE_OVER_SQRT2_PLUS_1  = (1./sqrt(2) + 1) / 2;
+float SQRT2 = sqrt(2);
+
+/** Equivalent to rotate3d(c, a, 0, 0); */
+void rotate3dA(LXVector c, float a) {
+  float ox = c.x, oy = c.y;
+  float cosa = cos(a);
+  float sina = sin(a);
+  c.x = ox * cosa - oy * sina;
+  c.y = ox * sina + oy * cosa;
+}
+/** Equivalent to rotate3d(c, 0, b, 0); */
+void rotate3dB(LXVector c, float b) {
+  float ox = c.x, oz = c.z;
+  float cosb = cos(b);
+  float sinb = sin(b);
+  c.x = ox * cosb + oz * sinb;
+  c.z = oz * cosb - ox * sinb;
+}
+/** Equivalent to rotate3d(c, 0, 0, g); */
+void rotate3dG(LXVector c, float g) {
+  float oy = c.y, oz = c.z;
+  float cosg = cos(g);
+  float sing = sin(g);
+  c.y = oy * cosg - oz * sing;
+  c.z = oz * cosg + oy * sing;
+}
+/** Equivalent to rotate3d(c, PI/4, PI/4, PI/4); */
+void rotate3dPiOver4(LXVector c) {
+  float ox = c.x, oy = c.y, oz = c.z;
+  c.x = ox / 2 + oy * HALF_OF_ONE_OVER_SQRT2_MINUS_1 + oz * HALF_OF_ONE_OVER_SQRT2_PLUS_1;
+  c.y = ox / 2 + oy * HALF_OF_ONE_OVER_SQRT2_PLUS_1 + oz * HALF_OF_ONE_OVER_SQRT2_MINUS_1;
+  c.z = - ox / SQRT2 + oy / 2 + oz / 2;
+}
+
+void rotate3d(LXVector c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
+  float ox = c.x, oy = c.y, oz = c.z;
+
   float cosa = cos(a);
   float cosb = cos(b);
   float cosg = cos(g);
@@ -232,11 +331,10 @@ void rotate3d(Coord c, float a /* roll */, float b /* pitch */, float g /* yaw *
   float c1 = -sinb;
   float c2 = cosb*sing;
   float c3 = cosb*cosg;
-
-  float[] cArray = { c.x, c.y, c.z };
-  c.x = dotProduct(new float[] {a1, a2, a3}, cArray);
-  c.y = dotProduct(new float[] {b1, b2, b3}, cArray);
-  c.z = dotProduct(new float[] {c1, c2, c3}, cArray);
+  
+  c.x = ox * a1 + oy * a2 + oz * a3;
+  c.y = ox * b1 + oy * b2 + oz * b3;
+  c.z = ox * c1 + oy * c2 + oz * c3;  
 }
 
 float dotProduct(float[] a, float[] b) {
@@ -267,11 +365,12 @@ color specialBlend(color c1, color c2, color c3) {
   float b1 = brightness(c1); 
   float b2 = brightness(c2);
   float b3 = brightness(c3);
-  float relative_b1 = b1 / (b1 + b2 + b3);
-  float relative_b2 = b2 / (b1 + b2 + b3);
-  float relative_b3 = b3 / (b1 + b2 + b3);
+  float b_denominator = b1 + b2 + b3;
+  float relative_b1 = b1 / b_denominator;
+  float relative_b2 = b2 / b_denominator;
+  float relative_b3 = b3 / b_denominator;
   
-  return color(
+  return lx.hsb(
     (h1 * relative_b1 + h2 * relative_b1 + h3 * relative_b3) % 360,
      s1 * relative_b1 + s2 * relative_b2 + s3 * relative_b3,
      max(max(b1, b2), b3)