Mapping existing layout
[SugarCubes.git] / Grizzly.pde
CommitLineData
34490867
MS
1/**
2 * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
3 *
4 * //\\ //\\ //\\ //\\
5 * ///\\\ ///\\\ ///\\\ ///\\\
6 * \\\/// \\\/// \\\/// \\\///
7 * \\// \\// \\// \\//H
8 *
9 * EXPERTS ONLY!! EXPERTS ONLY!!
10 *
b9b7b3d4
MS
11 * If you are an artist, you may ignore this file! It contains
12 * the code to drive grizzly board outputs.
34490867 13 */
7d60f6f6 14import java.net.*;
34490867
MS
15GrizzlyOutput[] buildGrizzlies() throws SocketException, UnknownHostException {
16 return new GrizzlyOutput[] {
07af801c
MS
17 new GrizzlyOutput(lx, "192.168.88.100", 0, 0, 0, 39, 38, 40, 0, 37, 35, 0, 21, 20, 22, 0, 33, 32 ),
18 new GrizzlyOutput(lx, "192.168.88.104", 0, 13, 12, 0, 1, 2, 6, 5, 7, 0, 0, 4, 3, 9, 10, 11 ),
19 new GrizzlyOutput(lx, "192.168.88.105", 42, 41, 0, 43, 45, 44, 0, 0, 0, 0, 0, 0, 0, 24, 23, 25 ),
20 new GrizzlyOutput(lx, "192.168.88.107", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
34490867
MS
21 };
22}
23
b9b7b3d4
MS
24/**
25 * Grizzly Output, sends packets to one grizzly board with a fixed IP and a number
26 * of channels.
27 */
34490867
MS
28class GrizzlyOutput extends LXDatagramOutput {
29
e037f60f
MS
30 public final String ipAddress;
31
34490867
MS
32 private int frameNumber = 0;
33
b9b7b3d4 34 public GrizzlyOutput(LX lx, String ipAddress, int ... cubeIndices) throws UnknownHostException, SocketException {
34490867 35 super(lx);
e037f60f
MS
36 this.ipAddress = ipAddress;
37 int channelNum = 0;
34490867
MS
38 for (int rawCubeIndex : cubeIndices) {
39 if (rawCubeIndex > 0) {
40 Cube cube = model.getCubeByRawIndex(rawCubeIndex);
41 addDatagram(new GrizzlyDatagram(this, channelNum, cube).setAddress(ipAddress));
42 }
43 ++channelNum;
44 }
e037f60f 45 this.enabled.setValue(false);
34490867
MS
46 }
47
48 protected void beforeSend(int[] colors) {
49 ++frameNumber;
50 }
51
52 public int getFrameNumber() {
53 return this.frameNumber;
54 }
55}
56
b9b7b3d4
MS
57/**
58 * Datagram to a Grizzlyboard. A simple fixed OSC packet.
59 */
34490867
MS
60static class GrizzlyDatagram extends LXDatagram {
61
62 private static byte[] oscString(String s) {
63 int len = s.length();
64 int padding = (4 - ((len + 1) % 4)) % 4;
65 byte[] bytes = new byte[len + 1 + padding];
66 System.arraycopy(s.getBytes(), 0, bytes, 0, len);
67 for (int i = len; i < bytes.length; ++i) {
68 bytes[i] = 0;
69 }
70 return bytes;
71 }
72
73 private static int oscIntCopy(int i, byte[] buffer, int pos) {
74 buffer[pos] = (byte) ((i >> 24) & 0xff);
75 buffer[pos + 1] = (byte) ((i >> 16) & 0xff);
76 buffer[pos + 2] = (byte) ((i >> 8) & 0xff);
77 buffer[pos + 3] = (byte) (i & 0xff);
78 return 4;
79 }
80
81 private final static int[] STRIP_ORDERING = new int[] { 9, 8, 11, 5, 4, 7, 6, 10, 14, 2, 1, 0, 3, 13, 12, 15 };
82
83 private static int[] cubePointIndices(Cube cube) {
84 int[] pointIndices = new int[Cube.POINTS_PER_CUBE - 2];
85 int pi = 0;
86 for (int stripIndex : STRIP_ORDERING) {
87 Strip strip = cube.strips.get(stripIndex);
88 int stripLen = ((stripIndex == 9) || (stripIndex == 15)) ? 15 : 16;
89 for (int i = stripLen-1; i >= 0; --i) {
90 pointIndices[pi++] = strip.points.get(i).index;
91 }
92 }
93 return pointIndices;
94 }
95
96 private final static byte[] OSC_ADDRESS = oscString("/shady/pointbuffer");
97 private final static byte[] OSC_TYPETAG = oscString(",iiiiibi");
98
99 private final static int HEADER_LENGTH = OSC_ADDRESS.length + OSC_TYPETAG.length + 24;
100 private final static int FOOTER_LENGTH = 4;
101
102 private final static int OSC_PORT = 779;
103
104 private GrizzlyOutput output;
105
106 private int[] pointIndices;
107
108 private final int frameNumberPos;
109
110 private final int dataPos;
111
112 public GrizzlyDatagram(GrizzlyOutput output, int channelNum, Cube cube) {
113 this(output, channelNum, cubePointIndices(cube));
114 }
115
116 public GrizzlyDatagram(GrizzlyOutput output, int channelNum, int[] pointIndices) {
117 super(HEADER_LENGTH + 4*pointIndices.length + FOOTER_LENGTH);
118 setPort(OSC_PORT);
119
120 this.output = output;
121 this.pointIndices = pointIndices;
122 int dataLength = 4*pointIndices.length;
123
124 int pos = 0;
125
126 // OSC address
127 System.arraycopy(OSC_ADDRESS, 0, this.buffer, pos, OSC_ADDRESS.length);
128 pos += OSC_ADDRESS.length;
129
130 // OSC typetag
131 System.arraycopy(OSC_TYPETAG, 0, this.buffer, pos, OSC_TYPETAG.length);
132 pos += OSC_TYPETAG.length;
133 this.frameNumberPos = pos;
134 pos += oscIntCopy(0, this.buffer, pos); // placeholder for frame number
135 pos += oscIntCopy(0xDEADBEEF, this.buffer, pos);
136 pos += oscIntCopy(channelNum, this.buffer, pos);
137 pos += oscIntCopy(0xFEEDBEEF, this.buffer, pos);
138 pos += oscIntCopy(dataLength, this.buffer, pos);
139 pos += oscIntCopy(dataLength, this.buffer, pos);
140 this.dataPos = pos;
141
142 // end header
143 oscIntCopy(0xBEFFFFEB, this.buffer, this.buffer.length - 4);
144 }
145
146 void onSend(int[] colors) {
147 oscIntCopy(this.output.getFrameNumber(), this.buffer, frameNumberPos);
148 int dataIndex = this.dataPos;
149 for (int index : this.pointIndices) {
150 color c = (index >= 0) ? colors[index] : 0;
151 this.buffer[dataIndex] = (byte) 0; // unused, alpha
152 this.buffer[dataIndex + 1] = (byte) ((c >> 16) & 0xff); // r
153 this.buffer[dataIndex + 2] = (byte) ((c >> 8) & 0xff); // g
154 this.buffer[dataIndex + 3] = (byte) (c & 0xff); // b
155 dataIndex += 4;
156 }
157 }
158}