+++ /dev/null
-/**
- * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
- *
- * //\\ //\\ //\\ //\\
- * ///\\\ ///\\\ ///\\\ ///\\\
- * \\\/// \\\/// \\\/// \\\///
- * \\// \\// \\// \\//H
- *
- * EXPERTS ONLY!! EXPERTS ONLY!!
- *
- * If you are an artist, you may ignore this file! It contains
- * the code to drive grizzly board outputs.
- */
-import java.net.*;
-GrizzlyOutput[] buildGrizzlies() throws SocketException, UnknownHostException {
- return new GrizzlyOutput[] {
- new GrizzlyOutput(lx, "192.168.88.100", 0, 0, 0, 39, 38, 40, 0, 37, 35, 0, 21, 20, 22, 0, 33, 32 ),
- new GrizzlyOutput(lx, "192.168.88.104", 0, 13, 12, 0, 1, 2, 6, 5, 7, 0, 0, 4, 3, 9, 10, 11 ),
- new GrizzlyOutput(lx, "192.168.88.105", 42, 41, 0, 43, 45, 44, 0, 0, 0, 0, 0, 0, 0, 24, 23, 25 ),
- new GrizzlyOutput(lx, "192.168.88.107", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
- };
-}
-
-/**
- * Grizzly Output, sends packets to one grizzly board with a fixed IP and a number
- * of channels.
- */
-class GrizzlyOutput extends LXDatagramOutput {
-
- public final String ipAddress;
-
- private int frameNumber = 0;
-
- public GrizzlyOutput(LX lx, String ipAddress, int ... cubeIndices) throws UnknownHostException, SocketException {
- super(lx);
- this.ipAddress = ipAddress;
- int channelNum = 0;
- for (int rawCubeIndex : cubeIndices) {
- if (rawCubeIndex > 0) {
- Cube cube = model.getCubeByRawIndex(rawCubeIndex);
- addDatagram(new GrizzlyDatagram(this, channelNum, cube).setAddress(ipAddress));
- }
- ++channelNum;
- }
- this.enabled.setValue(false);
- }
-
- protected void beforeSend(int[] colors) {
- ++frameNumber;
- }
-
- public int getFrameNumber() {
- return this.frameNumber;
- }
-}
-
-/**
- * Datagram to a Grizzlyboard. A simple fixed OSC packet.
- */
-static class GrizzlyDatagram extends LXDatagram {
-
- private static byte[] oscString(String s) {
- int len = s.length();
- int padding = (4 - ((len + 1) % 4)) % 4;
- byte[] bytes = new byte[len + 1 + padding];
- System.arraycopy(s.getBytes(), 0, bytes, 0, len);
- for (int i = len; i < bytes.length; ++i) {
- bytes[i] = 0;
- }
- return bytes;
- }
-
- private static int oscIntCopy(int i, byte[] buffer, int pos) {
- buffer[pos] = (byte) ((i >> 24) & 0xff);
- buffer[pos + 1] = (byte) ((i >> 16) & 0xff);
- buffer[pos + 2] = (byte) ((i >> 8) & 0xff);
- buffer[pos + 3] = (byte) (i & 0xff);
- return 4;
- }
-
- private final static int[] STRIP_ORDERING = new int[] { 9, 8, 11, 5, 4, 7, 6, 10, 14, 2, 1, 0, 3, 13, 12, 15 };
-
- private static int[] cubePointIndices(Cube cube) {
- int[] pointIndices = new int[Cube.POINTS_PER_CUBE - 2];
- int pi = 0;
- for (int stripIndex : STRIP_ORDERING) {
- Strip strip = cube.strips.get(stripIndex);
- int stripLen = ((stripIndex == 9) || (stripIndex == 15)) ? 15 : 16;
- for (int i = stripLen-1; i >= 0; --i) {
- pointIndices[pi++] = strip.points.get(i).index;
- }
- }
- return pointIndices;
- }
-
- private final static byte[] OSC_ADDRESS = oscString("/shady/pointbuffer");
- private final static byte[] OSC_TYPETAG = oscString(",iiiiibi");
-
- private final static int HEADER_LENGTH = OSC_ADDRESS.length + OSC_TYPETAG.length + 24;
- private final static int FOOTER_LENGTH = 4;
-
- private final static int OSC_PORT = 779;
-
- private GrizzlyOutput output;
-
- private int[] pointIndices;
-
- private final int frameNumberPos;
-
- private final int dataPos;
-
- public GrizzlyDatagram(GrizzlyOutput output, int channelNum, Cube cube) {
- this(output, channelNum, cubePointIndices(cube));
- }
-
- public GrizzlyDatagram(GrizzlyOutput output, int channelNum, int[] pointIndices) {
- super(HEADER_LENGTH + 4*pointIndices.length + FOOTER_LENGTH);
- setPort(OSC_PORT);
-
- this.output = output;
- this.pointIndices = pointIndices;
- int dataLength = 4*pointIndices.length;
-
- int pos = 0;
-
- // OSC address
- System.arraycopy(OSC_ADDRESS, 0, this.buffer, pos, OSC_ADDRESS.length);
- pos += OSC_ADDRESS.length;
-
- // OSC typetag
- System.arraycopy(OSC_TYPETAG, 0, this.buffer, pos, OSC_TYPETAG.length);
- pos += OSC_TYPETAG.length;
- this.frameNumberPos = pos;
- pos += oscIntCopy(0, this.buffer, pos); // placeholder for frame number
- pos += oscIntCopy(0xDEADBEEF, this.buffer, pos);
- pos += oscIntCopy(channelNum, this.buffer, pos);
- pos += oscIntCopy(0xFEEDBEEF, this.buffer, pos);
- pos += oscIntCopy(dataLength, this.buffer, pos);
- pos += oscIntCopy(dataLength, this.buffer, pos);
- this.dataPos = pos;
-
- // end header
- oscIntCopy(0xBEFFFFEB, this.buffer, this.buffer.length - 4);
- }
-
- void onSend(int[] colors) {
- oscIntCopy(this.output.getFrameNumber(), this.buffer, frameNumberPos);
- int dataIndex = this.dataPos;
- for (int index : this.pointIndices) {
- color c = (index >= 0) ? colors[index] : 0;
- this.buffer[dataIndex] = (byte) 0; // unused, alpha
- this.buffer[dataIndex + 1] = (byte) ((c >> 16) & 0xff); // r
- this.buffer[dataIndex + 2] = (byte) ((c >> 8) & 0xff); // g
- this.buffer[dataIndex + 3] = (byte) (c & 0xff); // b
- dataIndex += 4;
- }
- }
-}
import processing.opengl.*;
import rwmidi.*;
import java.lang.reflect.*;
+import java.net.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
LXEffect[] effectsArr;
DiscreteParameter selectedEffect;
MappingTool mappingTool;
-GrizzlyOutput[] grizzlies;
+IPOutput[] outputs = {};
PresetManager presetManager;
MidiEngine midiEngine;
boolean mappingMode = false;
boolean debugMode = false;
boolean simulationOn = true;
+boolean structureOn = false;
boolean diagnosticsOn = false;
LXPattern restoreToPattern = null;
PImage logo;
logTime("Setup MIDI devices");
// Build output driver
- grizzlies = new GrizzlyOutput[]{};
try {
- grizzlies = buildGrizzlies();
- for (LXOutput output : grizzlies) {
+ outputs = buildOutputs();
+ for (LXOutput output : outputs) {
lx.addOutput(output);
}
} catch (Exception x) {
x.printStackTrace();
}
- logTime("Built Grizzly Outputs");
+ logTime("Built Grizzly + Panda Outputs");
// Mapping tool
mappingTool = new MappingTool(lx);
// Right controls
new UIPatternDeck(lx.ui, lx.engine.getDeck(RIGHT_DECK), "PATTERN B", width-144, 4, 140, 324),
uiMidi = new UIMidi(midiEngine, width-144, 332, 140, 158),
- new UIOutput(grizzlies, width-144, 494, 140, 106),
+ new UIOutput(outputs, width-144, 494, 140, 106),
// Crossfader
uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86),
println("Total setup: " + (millis() - startMillis) + "ms");
println("Hit the 'o' key to toggle live output");
- lx.engine.framesPerSecond.setValue(120);
+ lx.engine.framesPerSecond.setValue(60);
lx.engine.setThreaded(true);
}
break;
case 'o':
case 'p':
- for (LXOutput output : grizzlies) {
+ for (LXOutput output : outputs) {
output.enabled.toggle();
}
break;
simulationOn = !simulationOn;
}
break;
+ case 'S':
+ if (!midiEngine.isQwertyEnabled()) {
+ structureOn = !structureOn;
+ }
+ break;
}
}
* The first value is the offset moving NE (towards back-right).
* The second value is the offset moving NW (negative comes forward-right).
*/
-static final float[][] TOWER_CONFIG = new float[][] {
- new float[] { 0, 0, RISER, 4 },
- new float[] { 25, -10, RISER, 4 },
- new float[] { 50, -22.5, FLOOR, 5 },
- new float[] { 17.25, -35.5, FLOOR, 6 },
- new float[] { 43.25, -51.5, RISER, 6 },
- new float[] { 69.25, -56, FLOOR, 6 },
- new float[] { 12.75, -62.5, RISER, 4 },
- new float[] { 38.75, -78.5, FLOOR, 5 },
- new float[] { 65.75, -83, RISER, 5 },
-
+static final TowerConfig[] TOWER_CONFIG = {
+ new TowerConfig("A", 0, 0, RISER, 4),
+ new TowerConfig("B", 25, -10, RISER, 4),
+ new TowerConfig("C", 50, -22.5, FLOOR, 5),
+ new TowerConfig("D", 17.25, -35.5, FLOOR, 6),
+ new TowerConfig("E", 43.25, -51.5, RISER, 6),
+ new TowerConfig("F", 69.25, -56, FLOOR, 6),
+ new TowerConfig("G", 12.75, -62.5, RISER, 4),
+ new TowerConfig("H", 38.75, -78.5, FLOOR, 5),
+ new TowerConfig("I", 65.75, -83, RISER, 5),
+ new TowerConfig("J", 11.75, -89, RISER, 3),
+ new TowerConfig("K", -50, -28, FLOOR, 3),
+ new TowerConfig("L", -14, -28, FLOOR, 4),
+ new TowerConfig("M", -16, -81, FLOOR, 3),
+ new TowerConfig("N", -56, 8, FLOOR, 2),
+ new TowerConfig("O", -9, 27, RISER, 2),
+ new TowerConfig("P", -28, 0, RISER, 3),
+ new TowerConfig("Q", -14, 54, FLOOR, 2),
+ new TowerConfig("R", -30, -54, RISER, 2),
};
+/**
+ * Mappings for the output drivers. Can mix grizzly boards with
+ * panda boards in here no problem.
+ */
+IPOutput[] buildOutputs() throws SocketException, UnknownHostException {
+ return new IPOutput[] {
+// new GrizzlyOutput(lx, "192.168.88.100", 0, 0, 0, 39, 38, 40, 0, 37, 35, 0, 21, 20, 22, 0, 33, 32 ),
+// new GrizzlyOutput(lx, "192.168.88.104", 0, 13, 12, 0, 1, 2, 6, 5, 7, 0, 0, 4, 3, 9, 10, 11 ),
+// new GrizzlyOutput(lx, "192.168.88.105", 42, 41, 0, 43, 45, 44, 0, 0, 0, 0, 0, 0, 0, 24, 23, 25 ),
+// new GrizzlyOutput(lx, "192.168.88.107", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
+
+ new PandaOutput(lx, "10.200.1.29", new String[][] {
+ new String[] { "00", "00", "00", "00" }, // 1
+ new String[] { "00", "00", "00", "00" }, // 2
+ new String[] { "E1", "E2", "E3", "E4" }, // 3
+ new String[] { "E5", "E6", "D5", "D6" }, // 4
+ new String[] { "H2", "H3", "H4", "H5" }, // 5
+ new String[] { "G1", "G2", "G3", "G4" }, // 6
+ new String[] { "00", "00", "00", "00" }, // 7
+ new String[] { "D1", "D2", "D3", "D4" }, // 8
+ }),
+
+ new PandaOutput(lx, "10.200.1.30", new String[][] {
+ new String[] { "00", "00", "00", "00" }, // 1
+ new String[] { "J1", "J2", "J3", "00" }, // 2
+ new String[] { "B1", "B2", "B3", "B4" }, // 3
+ new String[] { "K1", "K2", "K3", "00" }, // 4
+ new String[] { "F1", "F2", "F3", "F4" }, // 5
+ new String[] { "L1", "L2", "L3", "L4" }, // 6
+ new String[] { "C1", "C2", "C3", "C4" }, // 7
+ new String[] { "I1", "I2", "I3", "I4" }, // 8
+ }),
+
+ new PandaOutput(lx, "10.200.1.31", new String[][] {
+ new String[] { "00", "00", "00", "00" }, // 1
+ new String[] { "00", "00", "00", "00" }, // 2
+ new String[] { "A1", "A2", "A3", "A4" }, // 3
+ new String[] { "M1", "M2", "M3", "00" }, // 4
+ new String[] { "N1", "N2", "O1", "O2" }, // 5
+ new String[] { "C5", "F5", "F6", "I5" }, // 6
+ new String[] { "P1", "P2", "P3", "00" }, // 7
+ new String[] { "Q1", "Q2", "R1", "R2" }, // 8
+ }),
+
+ };
+}
+
+static class TowerConfig {
+ public final String id;
+ public final float x;
+ public final float z;
+ public final float base;
+ public final int numCubes;
+
+ public TowerConfig(String id, float z, float x, float base, int numCubes) {
+ this.id = id;
+ this.x = x;
+ this.z = z;
+ this.base = base;
+ this.numCubes = numCubes;
+ }
+}
+
public Model buildModel() {
List<Tower> towers = new ArrayList<Tower>();
float rt2 = sqrt(2);
float x, y, z, xd, zd, num;
- for (float[] tc : TOWER_CONFIG) {
- x = -tc[1];
- z = tc[0];
- y = tc[2];
- num = tc[3];
+ for (TowerConfig tc : TOWER_CONFIG) {
+ x = -tc.x;
+ z = tc.z;
+ y = tc.base;
+ num = tc.numCubes;
if (z < x) {
zd = -(x-z)/rt2;
xd = z*rt2 - zd;
}
List<Cube> tower = new ArrayList<Cube>();
for (int n = 0; n < num; ++n) {
- Cube cube = new Cube(xd + 24, y, zd + 84, 0, -45, 0);
+ Cube cube = new Cube(tc.id + (n+1), xd + 24, y, zd + 84, 0, -45, 0);
tower.add(cube);
cubes[cubeIndex++] = cube;
y += SPACING;
}
- towers.add(new Tower(tower));
+ towers.add(new Tower(tc.id, tower));
}
return new Model(towers, cubes);
public final List<Cube> cubes;
public final List<Face> faces;
public final List<Strip> strips;
+
+ public final Map<String, Cube> cubeTable;
private final Cube[] _cubes;
List<Cube> cubeList = new ArrayList<Cube>();
List<Face> faceList = new ArrayList<Face>();
List<Strip> stripList = new ArrayList<Strip>();
+ Map<String, Cube> _cubeTable = new HashMap<String, Cube>();
for (Cube cube : _cubes) {
if (cube != null) {
+ _cubeTable.put(cube.id, cube);
cubeList.add(cube);
for (Face face : cube.faces) {
faceList.add(face);
this.cubes = Collections.unmodifiableList(cubeList);
this.faces = Collections.unmodifiableList(faceList);
this.strips = Collections.unmodifiableList(stripList);
+ this.cubeTable = Collections.unmodifiableMap(_cubeTable);
}
private static class Fixture extends LXAbstractFixture {
public Cube getCubeByRawIndex(int index) {
return _cubes[index];
}
+
+ public Cube getCubeById(String id) {
+ return this.cubeTable.get(id);
+ }
}
/**
* Model of a set of cubes stacked in a tower
*/
public static class Tower extends LXModel {
+
+ /**
+ * Tower id
+ */
+ public final String id;
+
/**
* Immutable list of cubes
*/
*
* @param cubes Array of cubes
*/
- public Tower(List<Cube> cubes) {
+ public Tower(String id, List<Cube> cubes) {
super(cubes.toArray(new Cube[] {}));
+ this.id = id;
+
List<Cube> cubeList = new ArrayList<Cube>();
List<Face> faceList = new ArrayList<Face>();
List<Strip> stripList = new ArrayList<Strip>();
new Strip.Metrics(EDGE_HEIGHT, POINTS_PER_STRIP)
);
+ public final String id;
+
/**
* Immutable list of all cube faces
*/
*/
public final float rz;
- public Cube(double x, double y, double z, double rx, double ry, double rz) {
- this((float) x, (float) y, (float) z, (float) rx, (float) ry, (float) rz);
- }
-
- public Cube(float x, float y, float z, float rx, float ry, float rz) {
+ public Cube(String id, float x, float y, float z, float rx, float ry, float rz) {
super(new Fixture(x, y, z, rx, ry, rz));
Fixture fixture = (Fixture) this.fixtures.get(0);
+ this.id = id;
+
while (rx < 0) rx += 360;
while (ry < 0) ry += 360;
while (rz < 0) rz += 360;
--- /dev/null
+/**
+ * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
+ *
+ * //\\ //\\ //\\ //\\
+ * ///\\\ ///\\\ ///\\\ ///\\\
+ * \\\/// \\\/// \\\/// \\\///
+ * \\// \\// \\// \\//H
+ *
+ * EXPERTS ONLY!! EXPERTS ONLY!!
+ *
+ * If you are an artist, you may ignore this file! It contains
+ * the code to drive grizzly board outputs.
+ */
+
+private final static int[] STRIP_ORDERING = new int[] { 9, 8, 11, 5, 4, 7, 6, 10, 14, 2, 1, 0, 3, 13, 12, 15 };
+
+static int[] cubePointIndices(Cube cube) {
+ int[] pointIndices = new int[Cube.POINTS_PER_CUBE - 2];
+ int pi = 0;
+ for (int stripIndex : STRIP_ORDERING) {
+ Strip strip = cube.strips.get(stripIndex);
+ int stripLen = ((stripIndex == 9) || (stripIndex == 15)) ? 15 : 16;
+ for (int i = stripLen-1; i >= 0; --i) {
+ pointIndices[pi++] = strip.points.get(i).index;
+ }
+ }
+ return pointIndices;
+}
+
+abstract class IPOutput extends LXDatagramOutput {
+ public final String ipAddress;
+
+ protected IPOutput(LX lx, String ipAddress) throws SocketException {
+ super(lx);
+ this.ipAddress = ipAddress;
+ }
+}
+
+static abstract class OSCDatagram extends LXDatagram {
+
+ protected OSCDatagram(int bufferSize) {
+ super(bufferSize);
+ }
+
+ protected final static int OSC_PORT = 779;
+
+ protected static byte[] oscString(String s) {
+ int len = s.length();
+ int padding = (4 - ((len + 1) % 4)) % 4;
+ byte[] bytes = new byte[len + 1 + padding];
+ System.arraycopy(s.getBytes(), 0, bytes, 0, len);
+ for (int i = len; i < bytes.length; ++i) {
+ bytes[i] = 0;
+ }
+ return bytes;
+ }
+
+ protected static int oscIntCopy(int i, byte[] buffer, int pos) {
+ buffer[pos] = (byte) ((i >> 24) & 0xff);
+ buffer[pos + 1] = (byte) ((i >> 16) & 0xff);
+ buffer[pos + 2] = (byte) ((i >> 8) & 0xff);
+ buffer[pos + 3] = (byte) (i & 0xff);
+ return 4;
+ }
+}
+
+/**
+ * Grizzly Output, sends packets to one grizzly board with a fixed IP and a number
+ * of channels.
+ */
+class GrizzlyOutput extends IPOutput {
+
+ private int frameNumber = 0;
+
+ public GrizzlyOutput(LX lx, String ipAddress, int ... cubeIndices) throws UnknownHostException, SocketException {
+ super(lx, ipAddress);
+ int channelNum = 0;
+ for (int rawCubeIndex : cubeIndices) {
+ if (rawCubeIndex > 0) {
+ Cube cube = model.getCubeByRawIndex(rawCubeIndex);
+ addDatagram(new GrizzlyDatagram(this, channelNum, cube).setAddress(ipAddress));
+ }
+ ++channelNum;
+ }
+ this.enabled.setValue(false);
+ }
+
+ protected void beforeSend(int[] colors) {
+ ++frameNumber;
+ }
+
+ public int getFrameNumber() {
+ return this.frameNumber;
+ }
+}
+
+/**
+ * Datagram to a Grizzlyboard. A simple fixed OSC packet.
+ */
+static class GrizzlyDatagram extends OSCDatagram {
+
+ private final static byte[] OSC_ADDRESS = oscString("/shady/pointbuffer");
+ private final static byte[] OSC_TYPETAG = oscString(",iiiiibi");
+
+ private final static int HEADER_LENGTH = OSC_ADDRESS.length + OSC_TYPETAG.length + 24;
+ private final static int FOOTER_LENGTH = 4;
+
+ private GrizzlyOutput output;
+
+ private int[] pointIndices;
+
+ private final int frameNumberPos;
+
+ public GrizzlyDatagram(GrizzlyOutput output, int channelNum, Cube cube) {
+ this(output, channelNum, cubePointIndices(cube));
+ }
+
+ public GrizzlyDatagram(GrizzlyOutput output, int channelNum, int[] pointIndices) {
+ super(HEADER_LENGTH + 4*pointIndices.length + FOOTER_LENGTH);
+ setPort(OSC_PORT);
+
+ this.output = output;
+ this.pointIndices = pointIndices;
+ int dataLength = 4*pointIndices.length;
+
+ int pos = 0;
+
+ // OSC address
+ System.arraycopy(OSC_ADDRESS, 0, this.buffer, pos, OSC_ADDRESS.length);
+ pos += OSC_ADDRESS.length;
+
+ // OSC typetag
+ System.arraycopy(OSC_TYPETAG, 0, this.buffer, pos, OSC_TYPETAG.length);
+ pos += OSC_TYPETAG.length;
+ this.frameNumberPos = pos;
+ pos += oscIntCopy(0, this.buffer, pos); // placeholder for frame number
+ pos += oscIntCopy(0xDEADBEEF, this.buffer, pos);
+ pos += oscIntCopy(channelNum, this.buffer, pos);
+ pos += oscIntCopy(0xFEEDBEEF, this.buffer, pos);
+ pos += oscIntCopy(dataLength, this.buffer, pos);
+ pos += oscIntCopy(dataLength, this.buffer, pos);
+
+ // end header
+ oscIntCopy(0xBEFFFFEB, this.buffer, this.buffer.length - 4);
+ }
+
+ void onSend(int[] colors) {
+ oscIntCopy(this.output.getFrameNumber(), this.buffer, frameNumberPos);
+ int dataIndex = HEADER_LENGTH;
+ for (int index : this.pointIndices) {
+ color c = (index >= 0) ? colors[index] : 0;
+ this.buffer[dataIndex] = (byte) 0; // unused, alpha
+ this.buffer[dataIndex + 1] = (byte) ((c >> 16) & 0xff); // r
+ this.buffer[dataIndex + 2] = (byte) ((c >> 8) & 0xff); // g
+ this.buffer[dataIndex + 3] = (byte) (c & 0xff); // b
+ dataIndex += 4;
+ }
+ }
+}
+
+/**
+ * Grizzly Output, sends packets to one grizzly board with a fixed IP and a number
+ * of channels.
+ */
+class PandaOutput extends IPOutput {
+
+ public PandaOutput(LX lx, String ipAddress, String[][] channelMappings) throws UnknownHostException, SocketException {
+ super(lx, ipAddress);
+ int packetNum = 0;
+ int[] packetPointIndices = new int[PandaDatagram.PIXELS_PER_PACKET];
+ int[] noCubePoints = new int[Cube.POINTS_PER_CUBE - 2]; // 15-strips
+ for (int i = 0; i < noCubePoints.length; ++i) {
+ noCubePoints[i] = -1;
+ }
+ int[] cubePointIndices;
+ int pi = 0;
+ for (String[] channel : channelMappings) {
+ for (int i = 0; i < PandaDatagram.CUBES_PER_CHANNEL; ++i) {
+ Cube cube = model.getCubeById((i < channel.length) ? channel[i] : null);
+ cubePointIndices = (cube == null) ? noCubePoints : cubePointIndices(cube);
+ for (int index : cubePointIndices) {
+ packetPointIndices[pi++] = index;
+ if (pi >= PandaDatagram.PIXELS_PER_PACKET) {
+ addDatagram(new PandaDatagram(packetNum, packetPointIndices).setAddress(ipAddress));
+ pi = 0;
+ packetPointIndices = new int[PandaDatagram.PIXELS_PER_PACKET];
+ ++packetNum;
+ }
+ }
+ }
+ // 2 dummy pixels per cube at the end of each channel, due to 15-strips
+ for (int i = 0; i < PandaDatagram.CUBES_PER_CHANNEL * 2; ++i) {
+ packetPointIndices[pi++] = -1;
+ if (pi >= PandaDatagram.PIXELS_PER_PACKET) {
+ addDatagram(new PandaDatagram(packetNum, packetPointIndices).setAddress(ipAddress));
+ pi = 0;
+ packetPointIndices = new int[PandaDatagram.PIXELS_PER_PACKET];
+ ++packetNum;
+ }
+ }
+ }
+ if (pi > 0) {
+ addDatagram(new PandaDatagram(packetNum, packetPointIndices).setAddress(ipAddress));
+ }
+ this.enabled.setValue(false);
+ }
+}
+
+/**
+ * Datagram to a Panda board. A simple fixed OSC packet.
+ */
+static class PandaDatagram extends OSCDatagram {
+
+ private final static byte[] OSC_ADDRESS = oscString("/shady/pointbuffer");
+ private final static byte[] OSC_TYPETAG = oscString(",iib");
+
+ private final static int HEADER_LENGTH = OSC_ADDRESS.length + OSC_TYPETAG.length + 12;
+
+ private final static int PORT = 9001;
+
+ public final static int CUBES_PER_CHANNEL = 4;
+
+ public final static int PIXELS_PER_CHANNEL = Cube.POINTS_PER_CUBE * CUBES_PER_CHANNEL;
+
+ public final static int PIXELS_PER_PACKET = 352;
+
+ public final static int BYTES_PER_PIXEL = 4;
+
+ public final static int PACKET_SIZE = BYTES_PER_PIXEL*PIXELS_PER_PACKET;
+
+ private int[] pointIndices;
+
+ public PandaDatagram(int packetNum, int[] pointIndices) {
+ super(HEADER_LENGTH + PACKET_SIZE);
+ setPort(PORT);
+
+ this.pointIndices = pointIndices;
+
+ int pos = 0;
+
+ // OSC address
+ System.arraycopy(OSC_ADDRESS, 0, this.buffer, pos, OSC_ADDRESS.length);
+ pos += OSC_ADDRESS.length;
+
+ // OSC typetag
+ System.arraycopy(OSC_TYPETAG, 0, this.buffer, pos, OSC_TYPETAG.length);
+ pos += OSC_TYPETAG.length;
+
+ // Packet number
+ pos += oscIntCopy(packetNum, this.buffer, pos);
+
+ // Length of blob
+ pos += oscIntCopy(PACKET_SIZE, this.buffer, pos);
+
+ // Length of blob in osc-blob
+ pos += oscIntCopy(PACKET_SIZE, this.buffer, pos);
+ }
+
+ void onSend(int[] colors) {
+ int dataIndex = HEADER_LENGTH;
+ for (int index : this.pointIndices) {
+ color c = (index >= 0) ? colors[index] : 0;
+ this.buffer[dataIndex] = (byte) 0; // unused, alpha
+ this.buffer[dataIndex + 1] = (byte) ((c >> 16) & 0xff); // r
+ this.buffer[dataIndex + 2] = (byte) ((c >> 8) & 0xff); // g
+ this.buffer[dataIndex + 3] = (byte) (c & 0xff); // b
+ dataIndex += 4;
+ }
+ }
+}
* If you're an artist, create a new tab in the Processing environment with
* your name. Implement your classes there, and add them to the list below.
*/
-
LXPattern[] patterns(LX lx) {
return new LXPattern[] {
private int cubeIndex = 0;
private int stripIndex = 0;
- private int channelIndex = 0;
public final int MAPPING_MODE_ALL = 0;
public final int MAPPING_MODE_CHANNEL = 1;
public boolean channelModeRed = true;
public boolean channelModeGreen = false;
public boolean channelModeBlue = false;
-
- private final int numChannels;
-
+
MappingTool(LX lx) {
super(lx);
- // TODO(mcslee): port channels to grizzly
- numChannels = 1;
- setChannel();
- }
-
- public int numChannels() {
- return numChannels;
- }
-
- private void setChannel() {
- // TODO(mcslee): port to grizzly
}
private int indexOfCubeInChannel(Cube c) {
}
}
- public void setChannel(int index) {
- if (numChannels > 0) {
- channelIndex = index % numChannels;
- }
- setChannel();
- }
-
- public void incChannel() {
- channelIndex = (channelIndex + 1) % numChannels;
- setChannel();
- }
-
- public void decChannel() {
- channelIndex = (channelIndex + numChannels - 1) % numChannels;
- setChannel();
- }
-
public void setStrip(int index) {
stripIndex = index % Cube.STRIPS_PER_CUBE;
}
public void keyPressed(UIMapping uiMapping) {
switch (keyCode) {
- case UP: if (mappingMode == MAPPING_MODE_CHANNEL) incChannel(); else incCube(); break;
- case DOWN: if (mappingMode == MAPPING_MODE_CHANNEL) decChannel(); else decCube(); break;
+ case UP: incCube(); break;
+ case DOWN: decCube(); break;
case LEFT: decStrip(); break;
case RIGHT: incStrip(); break;
}
case 'g': channelModeGreen = !channelModeGreen; break;
case 'b': channelModeBlue = !channelModeBlue; break;
}
- uiMapping.setChannelID(channelIndex+1);
uiMapping.setCubeID(cubeIndex+1);
uiMapping.setStripID(stripIndex+1);
uiMapping.redraw();
popMatrix();
noStroke();
- for (Cube c : model.cubes) {
- drawCube(c);
+ if (structureOn) {
+ for (Cube c : model.cubes) {
+ drawCube(c);
+ }
}
noFill();
float in = .15;
noStroke();
fill(#393939);
- // drawBox(c.x+in, c.y+in, c.z+in, c.rx, c.ry, c.rz, Cube.EDGE_WIDTH-in*2, Cube.EDGE_HEIGHT-in*2, Cube.EDGE_WIDTH-in*2, Cube.CHANNEL_WIDTH-in);
+ drawBox(c.x+in, c.y+in, c.z+in, c.rx, c.ry, c.rz, Cube.EDGE_WIDTH-in*2, Cube.EDGE_HEIGHT-in*2, Cube.EDGE_WIDTH-in*2, Cube.CHANNEL_WIDTH-in);
}
void drawBox(float x, float y, float z, float rx, float ry, float rz, float xd, float yd, float zd, float sw) {
}
class UIOutput extends UIWindow {
- public UIOutput(GrizzlyOutput[] grizzlies, float x, float y, float w, float h) {
+ public UIOutput(IPOutput[] outputs, float x, float y, float w, float h) {
super(lx.ui, "OUTPUT", x, y, w, h);
float yp = UIWindow.TITLE_LABEL_HEIGHT;
- final UIItemList outputs = new UIItemList(1, UIWindow.TITLE_LABEL_HEIGHT, w-2, 80);
+ final UIItemList itemList = new UIItemList(1, UIWindow.TITLE_LABEL_HEIGHT, w-2, 80);
List<UIItemList.Item> items = new ArrayList<UIItemList.Item>();
- for (GrizzlyOutput grizzly : grizzlies) {
- items.add(new GrizzlyScrollItem(grizzly));
- grizzly.enabled.addListener(new LXParameterListener() {
+ for (IPOutput output : outputs) {
+ items.add(new OutputItem(output));
+ output.enabled.addListener(new LXParameterListener() {
public void onParameterChanged(LXParameter parameter) {
- outputs.redraw();
+ itemList.redraw();
}
});
}
- outputs.setItems(items).addToContainer(this);
+ itemList.setItems(items).addToContainer(this);
}
- class GrizzlyScrollItem extends UIItemList.AbstractItem {
- final GrizzlyOutput output;
+ class OutputItem extends UIItemList.AbstractItem {
+ final IPOutput output;
- GrizzlyScrollItem(GrizzlyOutput output) {
+ OutputItem(IPOutput output) {
this.output = output;
}
private final MappingTool mappingTool;
- private final UIIntegerBox channelBox;
+ private final UILabel cubeLabel;
private final UIIntegerBox cubeBox;
private final UIIntegerBox stripBox;
else if (value == MAP_MODE_CHANNEL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL;
else if (value == MAP_MODE_CUBE) mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE;
}
- }.setOptions(new String[] { MAP_MODE_ALL, MAP_MODE_CHANNEL, MAP_MODE_CUBE }).addToContainer(this);
+ }.setOptions(new String[] { MAP_MODE_ALL, MAP_MODE_CUBE }).addToContainer(this);
yp += 24;
- new UILabel(4, yp+8, w-10, 20).setLabel("CHANNEL ID").addToContainer(this);
+ new UILabel(4, yp+8, w-10, 20).setLabel("CUBE ID").addToContainer(this);
yp += 24;
- (channelBox = new UIIntegerBox(4, yp, w-10, 20) {
- protected void onValueChange(int value) {
- mappingTool.setChannel(value-1);
- }
- }).setRange(1, mappingTool.numChannels()).addToContainer(this);
+ (cubeLabel = new UILabel(4, yp, w-10, 20))
+ .setAlignment(CENTER, CENTER)
+ .setLabel(model.cubes.get(0).id)
+ .setBackgroundColor(#222222)
+ .setBorderColor(#666666)
+ .addToContainer(this);
yp += 24;
- new UILabel(4, yp+8, w-10, 20).setLabel("CUBE ID").addToContainer(this);
+ new UILabel(4, yp+8, w-10, 20).setLabel("CUBE NUMBER").addToContainer(this);
yp += 24;
(cubeBox = new UIIntegerBox(4, yp, w-10, 20) {
protected void onValueChange(int value) {
}
- public void setChannelID(int value) {
- channelBox.setValue(value);
- }
-
public void setCubeID(int value) {
cubeBox.setValue(value);
+ cubeLabel.setLabel(model.getCubeByRawIndex(value).id);
}
public void setStripID(int value) {