This is the working branch from my desktop, that drives the cubes well with no bugs...
[SugarCubes.git] / JR.pde
diff --git a/JR.pde b/JR.pde
new file mode 100755 (executable)
index 0000000..ec0923f
--- /dev/null
+++ b/JR.pde
@@ -0,0 +1,280 @@
+color BLACK = color(0, 0, 0);
+
+class Gimbal extends SCPattern {
+
+  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 BasicParameter hueDeltaParam = new BasicParameter("HUED", 60./360);
+  private final BasicParameter fadeFromCoreParam = new BasicParameter("FADE", 1);
+  private final BasicParameter girthParam = new BasicParameter("GRTH", .18);
+  private final BasicParameter ringExtendParam = new BasicParameter("XTND", 1);
+  private final BasicParameter relativeSpeedParam = new BasicParameter("RLSP", .83);
+  private final BasicParameter sizeParam = new BasicParameter("SIZE", .9);
+
+  private final BasicParameter aP = new BasicParameter("a", 0);
+  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);
+    addParameter(beatsPerRevolutionParam);
+    addParameter(hueDeltaParam);
+    addParameter(fadeFromCoreParam);
+    addParameter(girthParam);
+    addParameter(ringExtendParam);
+    addParameter(relativeSpeedParam);
+    addParameter(sizeParam);
+    
+    if (DEBUG_MANUAL_ABG) {
+      addParameter(aP);
+      addParameter(bP);
+      addParameter(gP);
+    }
+  }
+
+  float a = 0, b = 0, g = 0;
+
+  public void run(int deltaMs) {
+
+    if (DEBUG_MANUAL_ABG) {
+      a = aP.getValuef() * (2 * PI); 
+      b = bP.getValuef() * (2 * PI);
+      g = gP.getValuef() * (2 * PI);
+    } else {
+      float relativeSpeed = relativeSpeedParam.getValuef();
+      float time = millis() / 1000.f;
+      
+      int beatsPerRevolution = (int) (beatsPerRevolutionParam.getValuef() * MAXIMUM_BEATS_PER_REVOLUTION) + 1;
+      float radiansPerMs = 2 * PI             // radians / revolution
+                         / beatsPerRevolution // beats / revolution
+                         * lx.tempo.bpmf()    // BPM beats / min
+                         / 60                 // sec / min
+                         / 1000;              // ms / sec
+      
+      a += deltaMs * radiansPerMs * pow(relativeSpeed, 0);
+      b += deltaMs * radiansPerMs * pow(relativeSpeed, 1);
+      g += deltaMs * radiansPerMs * pow(relativeSpeed, 2);
+      a %= 2 * PI;
+      b %= 2 * PI;
+      g %= 2 * PI;
+    }
+
+    float hue = lx.getBaseHuef();
+    float hue_delta = hueDeltaParam.getValuef() * 360;
+    
+    float radius1 = model.xMax / 2 * sizeParam.getValuef();
+    float radius2 = ((model.xMax + model.yMax) / 2) / 2 * sizeParam.getValuef();
+    float radius3 = model.yMax / 2 * sizeParam.getValuef();
+    float girth = model.xMax * girthParam.getValuef();
+    Ring ring1 = new Ring((hue + hue_delta * 0) % 360, radius1, girth);
+    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)
+      // Translate so the center of the car is the origin
+      .translateCenter(model, 0, 0, 0);
+
+    for (Coord 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);
+      color color1 = ring1.colorFor(c);
+
+      rotate3d(c, 0, b, 0);
+      color color2 = ring2.colorFor(c);
+
+      rotate3d(c, 0, 0, g);
+      color color3 = ring3.colorFor(c);
+            
+      colors[c.index] = specialBlend(color1, color2, color3);      
+    }
+
+    first_run = false;
+  }
+
+  class Ring {
+
+    float hue;
+    float radius, girth;
+
+    public Ring(float hue, float radius, float girth) {
+      this.hue = hue;
+      this.radius = radius;
+      this.girth = girth;
+    }
+
+    public color colorFor(Coord c) {
+      float theta = atan2(c.y, c.x);
+      float nearest_circle_x = cos(theta) * radius;
+      float nearest_circle_y = sin(theta) * radius;
+      float nearest_circle_z = 0;
+
+      float distance_to_circle
+          = sqrt(pow(nearest_circle_x - c.x, 2)
+               + pow(nearest_circle_y - c.y, 2)
+               + 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);
+    }
+
+  }
+
+}
+
+
+
+
+
+
+class Zebra extends SCPattern {
+
+  private final Projection projection;
+  SinLFO angleM = new SinLFO(0, PI * 2, 30000);
+
+/*
+  SinLFO x, y, z, dx, dy, dz;
+  float cRad;
+  _P size;
+  */
+
+  Zebra(GLucose glucose) {
+    super(glucose);
+    projection = new Projection(model);
+
+    addModulator(angleM).trigger();
+  }
+
+  color colorFor(Coord c) {
+    float hue = lx.getBaseHuef();
+
+
+
+
+/* SLIDE ALONG
+    c.x = c.x + millis() / 100.f;
+    */
+
+
+
+    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);
+    } else {
+      return color((hue + 90) % 360, 100, 100);
+    }
+
+
+    /* OCTANTS
+
+    if ((isPositiveBit(c.x) + isPositiveBit(c.y) + isPositiveBit(c.z)) % 2 == 0) {
+      return color(lx.getBaseHuef(), 100, 100);
+    } else {
+      return color(0, 0, 0);
+    }
+    */
+  }
+
+  int isPositiveBit(float f) {
+    return f > 0 ? 1 : 0;
+  }
+
+  public void run(int deltaMs) {
+    float a = (millis() / 1000.f) % (2 * PI);
+    float b = (millis() / 1200.f) % (2 * PI);
+    float g = (millis() / 1600.f) % (2 * PI);
+
+    projection.reset(model)
+      // Translate so the center of the car is the origin
+      .translateCenter(model, 0, 0, 0);
+
+    for (Coord c : projection) {
+//      rotate3d(c, a, b, g);
+      colors[c.index] = colorFor(c);
+    }
+
+    first_run = false;
+  }
+
+
+  // Utility!
+  boolean first_run = true;
+  private void log(String s) {
+    if (first_run) {
+      println(s);
+    }
+  }
+
+
+}
+
+void rotate3d(Coord c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
+  float cosa = cos(a);
+  float cosb = cos(b);
+  float cosg = cos(g);
+  float sina = sin(a);
+  float sinb = sin(b);
+  float sing = sin(g);
+
+  float a1 = cosa*cosb;
+  float a2 = cosa*sinb*sing - sina*cosg;
+  float a3 = cosa*sinb*cosg + sina*sing;
+  float b1 = sina*cosb;
+  float b2 = sina*sinb*sing + cosa*cosg;
+  float b3 = sina*sinb*cosg - cosa*sing;
+  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);
+}
+
+float dotProduct(float[] a, float[] b) {
+  float ret = 0;
+  for (int i = 0 ; i < a.length; ++i) {
+    ret += a[i] * b[i];
+  }
+  return ret;
+}
+
+color specialBlend(color c1, color c2, color c3) {
+  float h1 = hue(c1);
+  float h2 = hue(c2); 
+  float h3 = hue(c3);
+  
+  // force h1 < h2 < h3
+  while (h2 < h1) {
+    h2 += 360;
+  }
+  while (h3 < h2) {
+    h3 += 360;
+  }
+
+  float s1 = saturation(c1); 
+  float s2 = saturation(c2); 
+  float s3 = saturation(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);
+  
+  return color(
+    (h1 * relative_b1 + h2 * relative_b1 + h3 * relative_b3) % 360,
+     s1 * relative_b1 + s2 * relative_b2 + s3 * relative_b3,
+     max(max(b1, b2), b3)
+  );
+}
+