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