New Grizzly code using LXOutput framework
[SugarCubes.git] / _Internals.pde
index 9d6b11889bd413b34ef8f8c9097ef720edbfea68..0100c051c82d0b4bc8b6125829c5bff708e664b3 100644 (file)
@@ -4,7 +4,7 @@
  *         //\\   //\\                 //\\   //\\  
  *        ///\\\ ///\\\               ///\\\ ///\\\
  *        \\\/// \\\///               \\\/// \\\///
  *         //\\   //\\                 //\\   //\\  
  *        ///\\\ ///\\\               ///\\\ ///\\\
  *        \\\/// \\\///               \\\/// \\\///
- *         \\//   \\//                 \\//   \\//
+ *         \\//   \\//                 \\//   \\//H
  *
  *        EXPERTS ONLY!!              EXPERTS ONLY!!
  *
  *
  *        EXPERTS ONLY!!              EXPERTS ONLY!!
  *
  */
 
 import glucose.*;
  */
 
 import glucose.*;
-import glucose.control.*;
-import glucose.effect.*;
 import glucose.model.*;
 import glucose.model.*;
-import glucose.pattern.*;
-import glucose.transform.*;
-import glucose.transition.*;
 import heronarts.lx.*;
 import heronarts.lx.*;
-import heronarts.lx.control.*;
 import heronarts.lx.effect.*;
 import heronarts.lx.modulator.*;
 import heronarts.lx.effect.*;
 import heronarts.lx.modulator.*;
+import heronarts.lx.parameter.*;
 import heronarts.lx.pattern.*;
 import heronarts.lx.pattern.*;
+import heronarts.lx.transform.*;
 import heronarts.lx.transition.*;
 import heronarts.lx.transition.*;
+import heronarts.lx.ui.*;
+import heronarts.lx.ui.component.*;
+import heronarts.lx.ui.control.*;
 import ddf.minim.*;
 import ddf.minim.analysis.*;
 import processing.opengl.*;
 import rwmidi.*;
 import ddf.minim.*;
 import ddf.minim.analysis.*;
 import processing.opengl.*;
 import rwmidi.*;
+import java.lang.reflect.*;
 
 final int VIEWPORT_WIDTH = 900;
 final int VIEWPORT_HEIGHT = 700;
 
 final int VIEWPORT_WIDTH = 900;
 final int VIEWPORT_HEIGHT = 700;
@@ -39,40 +39,38 @@ final float TRAILER_WIDTH = 240;
 final float TRAILER_DEPTH = 97;
 final float TRAILER_HEIGHT = 33;
 
 final float TRAILER_DEPTH = 97;
 final float TRAILER_HEIGHT = 33;
 
-final int MaxCubeHeight = 5;
-final int NumBackTowers = 11;
-
 int targetFramerate = 60;
 int startMillis, lastMillis;
 
 // Core engine variables
 GLucose glucose;
 int targetFramerate = 60;
 int startMillis, lastMillis;
 
 // Core engine variables
 GLucose glucose;
-HeronLX lx;
+LX lx;
+Model model;
 LXPattern[] patterns;
 LXPattern[] patterns;
+Effects effects;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
 MappingTool mappingTool;
 PandaDriver[] pandaBoards;
-MidiEngine midiEngine;
 PresetManager presetManager;
 PresetManager presetManager;
+MidiEngine midiEngine;
 
 // Display configuration mode
 boolean mappingMode = false;
 boolean debugMode = false;
 DebugUI debugUI;
 boolean uiOn = true;
 
 // Display configuration mode
 boolean mappingMode = false;
 boolean debugMode = false;
 DebugUI debugUI;
 boolean uiOn = true;
+boolean simulationOn = true;
+boolean diagnosticsOn = false;
 LXPattern restoreToPattern = null;
 PImage logo;
 float[] hsb = new float[3];
 
 // Handles to UI objects
 LXPattern restoreToPattern = null;
 PImage logo;
 float[] hsb = new float[3];
 
 // Handles to UI objects
-UIContext[] overlays;
 UIPatternDeck uiPatternA;
 UICrossfader uiCrossfader;
 UIMidi uiMidi;
 UIMapping uiMapping;
 UIDebugText uiDebugText;
 UIPatternDeck uiPatternA;
 UICrossfader uiCrossfader;
 UIMidi uiMidi;
 UIMapping uiMapping;
 UIDebugText uiDebugText;
-
-// Camera variables
-float eyeR, eyeA, eyeX, eyeY, eyeZ, midX, midY, midZ;
+UISpeed uiSpeed;
 
 /**
  * Engine construction and initialization.
 
 /**
  * Engine construction and initialization.
@@ -100,7 +98,19 @@ LXPattern[] _rightPatterns(GLucose glucose) {
   }
   return rightPatterns;
 }
   }
   return rightPatterns;
 }
-  
+
+LXEffect[] _effectsArray(Effects effects) {
+  List<LXEffect> effectList = new ArrayList<LXEffect>();
+  for (Field f : effects.getClass().getDeclaredFields()) {
+    try {
+      Object val = f.get(effects);
+      if (val instanceof LXEffect) {
+        effectList.add((LXEffect)val);
+      }
+    } catch (IllegalAccessException iax) {}
+  }
+  return effectList.toArray(new LXEffect[]{});
+} 
 
 void logTime(String evt) {
   int now = millis();
 
 void logTime(String evt) {
   int now = millis();
@@ -119,30 +129,39 @@ void setup() {
   logTime("Created viewport");
 
   // Create the GLucose engine to run the cubes
   logTime("Created viewport");
 
   // Create the GLucose engine to run the cubes
-  glucose = new GLucose(this, buildModel());
+  glucose = new GLucose(this, model = buildModel());
   lx = glucose.lx;
   lx.enableKeyboardTempo();
   logTime("Built GLucose engine");
   lx = glucose.lx;
   lx.enableKeyboardTempo();
   logTime("Built GLucose engine");
-  
+    
   // Set the patterns
   // Set the patterns
-  Engine engine = lx.engine;
+  LXEngine engine = lx.engine;
   engine.setPatterns(patterns = _leftPatterns(glucose));
   engine.addDeck(_rightPatterns(glucose));
   logTime("Built patterns");
   glucose.setTransitions(transitions(glucose));
   logTime("Built transitions");
   engine.setPatterns(patterns = _leftPatterns(glucose));
   engine.addDeck(_rightPatterns(glucose));
   logTime("Built patterns");
   glucose.setTransitions(transitions(glucose));
   logTime("Built transitions");
-  glucose.lx.addEffects(effects(glucose));
+  glucose.lx.addEffects(_effectsArray(effects = new Effects()));
   logTime("Built effects");
 
   logTime("Built effects");
 
-  // MIDI devices
-  midiEngine = new MidiEngine();
-  logTime("Setup MIDI devices");
-  
   // Preset manager
   presetManager = new PresetManager();
   logTime("Loaded presets");
 
   // Preset manager
   presetManager = new PresetManager();
   logTime("Loaded presets");
 
+  // MIDI devices
+  midiEngine = new MidiEngine();
+  logTime("Setup MIDI devices");
+
   // Build output driver
   // Build output driver
+  try {
+    GrizzlyOutput[] grizzlies = buildGrizzlies();
+    for (LXOutput output : grizzlies) {
+      lx.addOutput(output);
+    }
+  } catch (Exception x) {
+    x.printStackTrace();
+  }
+  
   PandaMapping[] pandaMappings = buildPandaList();
   pandaBoards = new PandaDriver[pandaMappings.length];
   int pbi = 0;
   PandaMapping[] pandaMappings = buildPandaList();
   pandaBoards = new PandaDriver[pandaMappings.length];
   int pbi = 0;
@@ -154,44 +173,32 @@ void setup() {
 
   // Build overlay UI
   debugUI = new DebugUI(pandaMappings);
 
   // Build overlay UI
   debugUI = new DebugUI(pandaMappings);
-  overlays = new UIContext[] {
-    uiPatternA = new UIPatternDeck(lx.engine.getDeck(0), "PATTERN A", 4, 4, 140, 324),
+  UIContext[] contexts = new UIContext[] {
+    uiPatternA = new UIPatternDeck(lx.ui, lx.engine.getDeck(GLucose.LEFT_DECK), "PATTERN A", 4, 4, 140, 324),
     new UIBlendMode(4, 332, 140, 86),
     new UIEffects(4, 422, 140, 144),
     new UITempo(4, 570, 140, 50),
     new UIBlendMode(4, 332, 140, 86),
     new UIEffects(4, 422, 140, 144),
     new UITempo(4, 570, 140, 50),
-    new UISpeed(4, 624, 140, 50),
+    uiSpeed = new UISpeed(4, 624, 140, 50),
         
         
-    new UIPatternDeck(lx.engine.getDeck(1), "PATTERN B", width-144, 4, 140, 324),
+    new UIPatternDeck(lx.ui, lx.engine.getDeck(GLucose.RIGHT_DECK), "PATTERN B", width-144, 4, 140, 324),
     uiMidi = new UIMidi(midiEngine, width-144, 332, 140, 158),
     new UIOutput(width-144, 494, 140, 106),
     
     uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86),
     
     uiDebugText = new UIDebugText(148, height-138, width-304, 44),
     uiMidi = new UIMidi(midiEngine, width-144, 332, 140, 158),
     new UIOutput(width-144, 494, 140, 106),
     
     uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86),
     
     uiDebugText = new UIDebugText(148, height-138, width-304, 44),
-    uiMapping = new UIMapping(mappingTool, 4, 4, 140, 324),
+    uiMapping = new UIMapping(mappingTool, 4, 4, 140, 324)
   };
   uiMapping.setVisible(false);
   };
   uiMapping.setVisible(false);
+  lx.ui.addLayer(new UICameraLayer(lx.ui).setCenter(TRAILER_WIDTH/2., glucose.model.yMax/2, TRAILER_DEPTH/2.).setRadius(290).addComponent(new UICubesLayer()));
+  for (UIContext context : contexts) {
+    lx.ui.addLayer(context);
+  }
   logTime("Built overlay UI");
 
   // Load logo image
   logo = loadImage("data/logo.png");
   logTime("Built overlay UI");
 
   // Load logo image
   logo = loadImage("data/logo.png");
-  
-  // Setup camera
-  midX = TRAILER_WIDTH/2.;
-  midY = glucose.model.yMax/2;
-  midZ = TRAILER_DEPTH/2.;
-  eyeR = -290;
-  eyeA = .15;
-  eyeY = midY + 70;
-  eyeX = midX + eyeR*sin(eyeA);
-  eyeZ = midZ + eyeR*cos(eyeA);
-  
-  // Add mouse scrolling event support
-  addMouseWheelListener(new java.awt.event.MouseWheelListener() { 
-    public void mouseWheelMoved(java.awt.event.MouseWheelEvent mwe) { 
-      mouseWheel(mwe.getWheelRotation());
-  }}); 
-  
+      
   println("Total setup: " + (millis() - startMillis) + "ms");
   println("Hit the 'p' key to toggle Panda Board output");
 }
   println("Total setup: " + (millis() - startMillis) + "ms");
   println("Hit the 'p' key to toggle Panda Board output");
 }
@@ -200,29 +207,132 @@ void setup() {
  * Core render loop and drawing functionality.
  */
 void draw() {
  * Core render loop and drawing functionality.
  */
 void draw() {
-  // Draws the simulation and the 2D UI overlay
+  long drawStart = System.nanoTime();
+  
+  // Set background
   background(40);
   background(40);
+  
+  // Send colors
+  color[] sendColors = glucose.getColors();
+  if (debugMode) {
+    debugUI.maskColors(sendColors);
+  }
+  
+  long gammaStart = System.nanoTime();
+  // Gamma correction here. Apply a cubic to the brightness
+  // for better representation of dynamic range
+  for (int i = 0; i < sendColors.length; ++i) {
+    lx.RGBtoHSB(sendColors[i], hsb);
+    float b = hsb[2];
+    sendColors[i] = lx.hsb(360.*hsb[0], 100.*hsb[1], 100.*(b*b*b));
+  }
+  long gammaNanos = System.nanoTime() - gammaStart;
 
 
-  color[] simulationColors;
-  color[] sendColors;
-  simulationColors = sendColors = glucose.getColors();
-  String displayMode = uiCrossfader.getDisplayMode();
-  if (displayMode == "A") {
-    simulationColors = lx.engine.getDeck(0).getColors();
-  } else if (displayMode == "B") {
-    simulationColors = lx.engine.getDeck(1).getColors();
+  long sendStart = System.nanoTime();
+  for (PandaDriver p : pandaBoards) {
+    p.send(sendColors);
   }
   }
+  long sendNanos = System.nanoTime() - sendStart;
+
+  drawFPS();
   if (debugMode) {
   if (debugMode) {
-    debugUI.maskColors(simulationColors);
-    debugUI.maskColors(sendColors);
+    debugUI.draw();
   }
 
   }
 
-  camera(
-    eyeX, eyeY, eyeZ,
-    midX, midY, midZ,
-    0, -1, 0
-  );
+  // TODO(mcslee): fix
+  long drawNanos = System.nanoTime() - drawStart;
+  
+  long simulationNanos = 0, uiNanos = 0;
+  if (diagnosticsOn) {
+    drawDiagnostics(drawNanos, simulationNanos, uiNanos, gammaNanos, sendNanos);
+  }  
+}
+
+class UICubesLayer extends UICameraComponent {
+  void onDraw(UI ui) {
+    color[] simulationColors = glucose.getColors();
+    String displayMode = uiCrossfader.getDisplayMode();
+    if (displayMode == "A") {
+      simulationColors = lx.engine.getDeck(GLucose.LEFT_DECK).getColors();
+    } else if (displayMode == "B") {
+      simulationColors = lx.engine.getDeck(GLucose.RIGHT_DECK).getColors();
+    }
+    if (debugMode) {
+      debugUI.maskColors(simulationColors);
+    }
+
+    long simulationStart = System.nanoTime();
+    if (simulationOn) {
+      drawSimulation(simulationColors);
+    }
+    long simulationNanos = System.nanoTime() - simulationStart;
+    
+    camera();
+    javax.media.opengl.GL gl = ((PGraphicsOpenGL)g).beginGL();
+    gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
+    ((PGraphicsOpenGL)g).endGL();
+    strokeWeight(1);
+  }      
+}
+
+void drawDiagnostics(long drawNanos, long simulationNanos, long uiNanos, long gammaNanos, long sendNanos) {
+  float ws = 4 / 1000000.;
+  int thirtyfps = 1000000000 / 30;
+  int sixtyfps = 1000000000 / 60;
+  int x = width - 138;
+  int y = height - 14;
+  int h = 10;
+  noFill();
+  stroke(#999999);
+  rect(x, y, thirtyfps * ws, h);
+  noStroke();
+  int xp = x;
+  float hv = 0;
+  for (long val : new long[] {lx.timer.drawNanos, simulationNanos, uiNanos, gammaNanos, sendNanos }) {
+    fill(lx.hsb(hv % 360, 100, 80));
+    rect(xp, y, val * ws, h-1);
+    hv += 140;
+    xp += val * ws;
+  }
+  noFill();
+  stroke(#333333);
+  line(x+sixtyfps*ws, y+1, x+sixtyfps*ws, y+h-1);
+  
+  y = y - 14;
+  xp = x;
+  float tw = thirtyfps * ws;
+  noFill();
+  stroke(#999999);
+  rect(x, y, tw, h);
+  h = 5;
+  noStroke();
+  for (long val : new long[] {
+    lx.engine.timer.deckNanos,
+    lx.engine.timer.copyNanos,
+    lx.engine.timer.fxNanos}) {
+    float amt = val / (float) lx.timer.drawNanos;
+    fill(lx.hsb(hv % 360, 100, 80));
+    rect(xp, y, amt * tw, h-1);
+    hv += 140;
+    xp += amt * tw;
+  }
+  
+  xp = x;
+  y += h;
+  hv = 120;
+  for (long val : new long[] {
+    lx.engine.getDeck(0).timer.runNanos,
+    lx.engine.getDeck(1).timer.runNanos,
+    lx.engine.getDeck(1).getFaderTransition().timer.blendNanos}) {
+    float amt = val / (float) lx.timer.drawNanos;
+    fill(lx.hsb(hv % 360, 100, 80));
+    rect(xp, y, amt * tw, h-1);
+    hv += 140;
+    xp += amt * tw;
+  }
+}
 
 
+void drawSimulation(color[] simulationColors) {
   translate(0, 40, 0);
 
   noStroke();
   translate(0, 40, 0);
 
   noStroke();
@@ -259,27 +369,11 @@ void draw() {
   noFill();
   strokeWeight(2);
   beginShape(POINTS);
   noFill();
   strokeWeight(2);
   beginShape(POINTS);
-  for (Point p : glucose.model.points) {
+  for (LXPoint p : glucose.model.points) {
     stroke(simulationColors[p.index]);
     vertex(p.x, p.y, p.z);
   }
   endShape();
     stroke(simulationColors[p.index]);
     vertex(p.x, p.y, p.z);
   }
   endShape();
-  
-  // 2D Overlay UI
-  drawUI();
-    
-  // Gamma correction here. Apply a cubic to the brightness
-  // for better representation of dynamic range
-  for (int i = 0; i < sendColors.length; ++i) {
-    lx.RGBtoHSB(sendColors[i], hsb);
-    float b = hsb[2];
-    sendColors[i] = lx.hsb(360.*hsb[0], 100.*hsb[1], 100.*(b*b*b));
-  }
-  
-  // TODO(mcslee): move into GLucose engine
-  for (PandaDriver p : pandaBoards) {
-    p.send(sendColors);
-  }
 }
 
 void drawBassBox(BassBox b, boolean hasSub) {
 }
 
 void drawBassBox(BassBox b, boolean hasSub) {
@@ -391,28 +485,12 @@ void drawBox(float x, float y, float z, float rx, float ry, float rz, float xd,
   popMatrix();
 }
 
   popMatrix();
 }
 
-void drawUI() {
-  camera();
-  javax.media.opengl.GL gl = ((PGraphicsOpenGL)g).beginGL();
-  gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
-  ((PGraphicsOpenGL)g).endGL();
-  strokeWeight(1);
-
-  if (uiOn) {
-    for (UIContext context : overlays) {
-      context.draw();
-    }
-  }
-  
+void drawFPS() {  
   // Always draw FPS meter
   fill(#555555);
   textSize(9);
   textAlign(LEFT, BASELINE);
   text("FPS: " + ((int) (frameRate*10)) / 10. + " / " + targetFramerate + " (-/+)", 4, height-4);
   // Always draw FPS meter
   fill(#555555);
   textSize(9);
   textAlign(LEFT, BASELINE);
   text("FPS: " + ((int) (frameRate*10)) / 10. + " / " + targetFramerate + " (-/+)", 4, height-4);
-
-  if (debugMode) {
-    debugUI.draw();
-  }
 }
 
 
 }
 
 
@@ -424,6 +502,44 @@ void keyPressed() {
     mappingTool.keyPressed(uiMapping);
   }
   switch (key) {
     mappingTool.keyPressed(uiMapping);
   }
   switch (key) {
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+      if (!midiEngine.isQwertyEnabled()) {
+        presetManager.select(midiEngine.getFocusedDeck(), key - '1');
+      }
+      break;
+    
+    case '!':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 0);
+      break;
+    case '@':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 1);
+      break;
+    case '#':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 2);
+      break;
+    case '$':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 3);
+      break;
+    case '%':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 4);
+      break;
+    case '^':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 5);
+      break;
+    case '&':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 6);
+      break;
+    case '*':
+      if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 7);
+      break;
+      
     case '-':
     case '_':
       frameRate(--targetFramerate);
     case '-':
     case '_':
       frameRate(--targetFramerate);
@@ -433,7 +549,7 @@ void keyPressed() {
       frameRate(++targetFramerate);
       break; 
     case 'b':
       frameRate(++targetFramerate);
       break; 
     case 'b':
-      EFF_boom.trigger();
+      effects.boom.trigger();
       break;    
     case 'd':
       if (!midiEngine.isQwertyEnabled()) {
       break;    
     case 'd':
       if (!midiEngine.isQwertyEnabled()) {
@@ -468,6 +584,16 @@ void keyPressed() {
         p.toggle();
       }
       break;
         p.toggle();
       }
       break;
+    case 'q':
+      if (!midiEngine.isQwertyEnabled()) {
+        diagnosticsOn = !diagnosticsOn;
+      }
+      break;
+    case 's':
+      if (!midiEngine.isQwertyEnabled()) {
+        simulationOn = !simulationOn;
+      }
+      break;
     case 'u':
       if (!midiEngine.isQwertyEnabled()) {
         uiOn = !uiOn;
     case 'u':
       if (!midiEngine.isQwertyEnabled()) {
         uiOn = !uiOn;
@@ -479,53 +605,9 @@ void keyPressed() {
 /**
  * Top-level mouse event handling
  */
 /**
  * Top-level mouse event handling
  */
-int mx, my;
 void mousePressed() {
 void mousePressed() {
-  boolean debugged = false;
   if (debugMode) {
   if (debugMode) {
-    debugged = debugUI.mousePressed();
-  }
-  if (!debugged) {
-    for (UIContext context : overlays) {
-      context.mousePressed(mouseX, mouseY);
-    }
-  }
-  mx = mouseX;
-  my = mouseY;
-}
-
-void mouseDragged() {
-  boolean dragged = false;
-  for (UIContext context : overlays) {
-    dragged |= context.mouseDragged(mouseX, mouseY);
-  }
-  if (!dragged) {
-    int dx = mouseX - mx;
-    int dy = mouseY - my;
-    mx = mouseX;
-    my = mouseY;
-    eyeA += dx*.003;
-    eyeX = midX + eyeR*sin(eyeA);
-    eyeZ = midZ + eyeR*cos(eyeA);
-    eyeY += dy;
+    debugUI.mousePressed();
   }
 }
 
   }
 }
 
-void mouseReleased() {
-  for (UIContext context : overlays) {
-    context.mouseReleased(mouseX, mouseY);
-  }
-}
-
-void mouseWheel(int delta) {
-  boolean wheeled = false;
-  for (UIContext context : overlays) {
-    wheeled |= context.mouseWheel(mouseX, mouseY, delta);
-  }
-  
-  if (!wheeled) {
-    eyeR = constrain(eyeR - delta, -500, -80);
-    eyeX = midX + eyeR*sin(eyeA);
-    eyeZ = midZ + eyeR*cos(eyeA);
-  }
-}