Send normalized values back to APC40
[SugarCubes.git] / _DebugUI.pde
CommitLineData
d626bc9b
MS
1/**
2 * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
3 *
4 * //\\ //\\ //\\ //\\
5 * ///\\\ ///\\\ ///\\\ ///\\\
6 * \\\/// \\\/// \\\/// \\\///
7 * \\// \\// \\// \\//
8 *
9 * EXPERTS ONLY!! EXPERTS ONLY!!
10 *
11 * Overlay UI that indicates pattern control, etc. This will be moved
12 * into the Processing library once it is stabilized and need not be
13 * regularly modified.
14 */
15
16class DebugUI {
17
18 final ChannelMapping[] channelList;
19 final int debugX = 5;
20 final int debugY = 5;
21 final int debugXSpacing = 28;
22 final int debugYSpacing = 21;
23 final int[][] debugState;
24 final int[] indexState;
25
26 final int CUBE_STATE_UNUSED = 0;
27 final int CUBE_STATE_USED = 1;
28 final int CUBE_STATE_DUPLICATED = 2;
29
30 final int DEBUG_STATE_ANIM = 0;
31 final int DEBUG_STATE_WHITE = 1;
32 final int DEBUG_STATE_OFF = 2;
33 final int DEBUG_STATE_UNUSED = 3;
34
35 DebugUI(PandaMapping[] pandaMappings) {
36 int totalChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD;
37 debugState = new int[totalChannels+1][ChannelMapping.CUBES_PER_CHANNEL+1];
38 indexState = new int[glucose.model.cubes.size()+1];
39
40 channelList = new ChannelMapping[totalChannels];
41 int channelIndex = 0;
42 for (PandaMapping pm : pandaMappings) {
43 for (ChannelMapping channel : pm.channelList) {
44 channelList[channelIndex++] = channel;
45 }
46 }
47 for (int i = 0; i < debugState.length; ++i) {
48 for (int j = 0; j < debugState[i].length; ++j) {
49 debugState[i][j] = DEBUG_STATE_ANIM;
50 }
51 }
52
53 for (int rawIndex = 0; rawIndex < glucose.model.cubes.size()+1; ++rawIndex) {
54 indexState[rawIndex] = CUBE_STATE_UNUSED;
55 }
56 for (ChannelMapping channel : channelList) {
57 for (int rawCubeIndex : channel.objectIndices) {
58 if (rawCubeIndex > 0)
59 ++indexState[rawCubeIndex];
60 }
61 }
62 }
63
64 void draw() {
65 noStroke();
66 int xBase = debugX;
67 int yPos = debugY;
68
69 textSize(10);
70
71 fill(#000000);
72 rect(0, 0, debugX + 5*debugXSpacing, height);
73
74 int channelNum = 0;
75 for (ChannelMapping channel : channelList) {
76 int xPos = xBase;
77 drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]);
78 xPos += debugXSpacing;
79
80 switch (channel.mode) {
81 case ChannelMapping.MODE_CUBES:
82 int stateIndex = 0;
83 boolean first = true;
84 for (int rawCubeIndex : channel.objectIndices) {
85 if (rawCubeIndex < 0) {
86 break;
87 }
88 if (first) {
89 first = false;
90 } else {
91 stroke(#999999);
92 line(xPos - 12, yPos + 8, xPos, yPos + 8);
93 }
94 drawNumBox(xPos, yPos, rawCubeIndex, debugState[channelNum][stateIndex+1], indexState[rawCubeIndex]);
95 ++stateIndex;
96 xPos += debugXSpacing;
97 }
98 break;
99 case ChannelMapping.MODE_BASS:
100 drawNumBox(xPos, yPos, "B", debugState[channelNum][1]);
101 break;
102 case ChannelMapping.MODE_SPEAKER:
103 drawNumBox(xPos, yPos, "S" + channel.objectIndices[0], debugState[channelNum][1]);
104 break;
105 case ChannelMapping.MODE_STRUTS_AND_FLOOR:
106 drawNumBox(xPos, yPos, "F", debugState[channelNum][1]);
107 break;
108 case ChannelMapping.MODE_NULL:
109 break;
110 default:
111 throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
112 }
113
114 yPos += debugYSpacing;
115 ++channelNum;
116 }
117 drawNumBox(xBase, yPos, "A", debugState[channelNum][0]);
118 yPos += debugYSpacing * 2;
119
120 noFill();
121 fill(#CCCCCC);
122 text("Unused Cubes", xBase, yPos + 12);
123 yPos += debugYSpacing;
124
125 int xIndex = 0;
126 for (int rawIndex = 1; rawIndex <= glucose.model.cubes.size(); ++rawIndex) {
127 if (indexState[rawIndex] == CUBE_STATE_UNUSED) {
128 drawNumBox(xBase + (xIndex * debugXSpacing), yPos, rawIndex, DEBUG_STATE_UNUSED);
129 ++xIndex;
130 if (xIndex > 4) {
131 xIndex = 0;
132 yPos += debugYSpacing + 2;
133 }
134 }
135 }
136 }
137
138
139 void drawNumBox(int xPos, int yPos, int label, int state) {
140 drawNumBox(xPos, yPos, "" + label, state);
141 }
142
143 void drawNumBox(int xPos, int yPos, String label, int state) {
144 drawNumBox(xPos, yPos, "" + label, state, CUBE_STATE_USED);
145 }
146
147 void drawNumBox(int xPos, int yPos, int label, int state, int cubeState) {
148 drawNumBox(xPos, yPos, "" + label, state, cubeState);
149 }
150
151 void drawNumBox(int xPos, int yPos, String label, int state, int cubeState) {
152 noFill();
153 color textColor = #cccccc;
154 switch (state) {
155 case DEBUG_STATE_ANIM:
156 noStroke();
157 fill(#880000);
158 rect(xPos, yPos, 16, 8);
159 fill(#000088);
160 rect(xPos, yPos+8, 16, 8);
161 noFill();
162 stroke(textColor);
163 break;
164 case DEBUG_STATE_WHITE:
165 stroke(textColor);
166 fill(#e9e9e9);
167 textColor = #333333;
168 break;
169 case DEBUG_STATE_OFF:
170 stroke(textColor);
171 break;
172 case DEBUG_STATE_UNUSED:
173 stroke(textColor);
174 fill(#880000);
175 break;
176 }
177
178 if (cubeState >= CUBE_STATE_DUPLICATED) {
179 stroke(textColor = #FF0000);
180 }
181
182 rect(xPos, yPos, 16, 16);
183 noStroke();
184 fill(textColor);
185 text(label, xPos + 2, yPos + 12);
186 }
187
188 void maskColors(color[] colors) {
189 color white = #FFFFFF;
190 color off = #000000;
191 int channelIndex = 0;
192 int state;
193 for (ChannelMapping channel : channelList) {
194 switch (channel.mode) {
195 case ChannelMapping.MODE_CUBES:
196 int cubeIndex = 1;
197 for (int rawCubeIndex : channel.objectIndices) {
198 if (rawCubeIndex >= 0) {
199 state = debugState[channelIndex][cubeIndex];
200 if (state != DEBUG_STATE_ANIM) {
201 color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
202 Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex);
2bb56822 203 for (LXPoint p : cube.points) {
d626bc9b
MS
204 colors[p.index] = debugColor;
205 }
206 }
207 }
208 ++cubeIndex;
209 }
210 break;
211
212 case ChannelMapping.MODE_BASS:
213 state = debugState[channelIndex][1];
214 if (state != DEBUG_STATE_ANIM) {
215 color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
216 for (Strip s : glucose.model.bassBox.boxStrips) {
2bb56822 217 for (LXPoint p : s.points) {
d626bc9b
MS
218 colors[p.index] = debugColor;
219 }
220 }
221 }
222 break;
223
224 case ChannelMapping.MODE_STRUTS_AND_FLOOR:
225 state = debugState[channelIndex][1];
226 if (state != DEBUG_STATE_ANIM) {
227 color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
2bb56822 228 for (LXPoint p : glucose.model.boothFloor.points) {
d626bc9b
MS
229 colors[p.index] = debugColor;
230 }
231 for (Strip s : glucose.model.bassBox.struts) {
2bb56822 232 for (LXPoint p : s.points) {
d626bc9b
MS
233 colors[p.index] = debugColor;
234 }
235 }
236 }
237 break;
238
239 case ChannelMapping.MODE_SPEAKER:
240 state = debugState[channelIndex][1];
241 if (state != DEBUG_STATE_ANIM) {
242 color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
2bb56822 243 for (LXPoint p : glucose.model.speakers.get(channel.objectIndices[0]).points) {
d626bc9b
MS
244 colors[p.index] = debugColor;
245 }
246 }
247 break;
248
249 case ChannelMapping.MODE_NULL:
250 break;
251
252 default:
253 throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
254 }
255 ++channelIndex;
256 }
257 }
258
259 boolean mousePressed() {
260 int dx = (mouseX - debugX) / debugXSpacing;
261 int dy = (mouseY - debugY) / debugYSpacing;
262 if ((dy < 0) || (dy >= debugState.length)) {
263 return false;
264 }
265 if ((dx < 0) || (dx >= debugState[dy].length)) {
266 return false;
267 }
268 int newState = debugState[dy][dx] = (debugState[dy][dx] + 1) % 3;
269 if (dy == debugState.length-1) {
270 for (int[] states : debugState) {
271 for (int i = 0; i < states.length; ++i) {
272 states[i] = newState;
273 }
274 }
275 } else if (dx == 0) {
276 for (int i = 0; i < debugState[dy].length; ++i) {
277 debugState[dy][i] = newState;
278 }
279 }
280 return true;
281 }
282}
283