adding Dan's anims Pong, Noise to master
[SugarCubes.git] / _Overlay.pde
1 import java.lang.reflect.*;
2
3 /**
4 * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
5 *
6 * //\\ //\\ //\\ //\\
7 * ///\\\ ///\\\ ///\\\ ///\\\
8 * \\\/// \\\/// \\\/// \\\///
9 * \\// \\// \\// \\//
10 *
11 * EXPERTS ONLY!! EXPERTS ONLY!!
12 *
13 * Overlay UI that indicates pattern control, etc. This will be moved
14 * into the Processing library once it is stabilized and need not be
15 * regularly modified.
16 */
17 abstract class OverlayUI {
18 protected final PFont titleFont = createFont("Myriad Pro", 10);
19 protected final color titleColor = #AAAAAA;
20 protected final PFont itemFont = createFont("Lucida Grande", 11);
21 protected final PFont knobFont = titleFont;
22 protected final int w = 140;
23 protected final int leftPos;
24 protected final int leftTextPos;
25 protected final int lineHeight = 20;
26 protected final int sectionSpacing = 12;
27 protected final int controlSpacing = 18;
28 protected final int tempoHeight = 20;
29 protected final int knobSize = 28;
30 protected final float knobIndent = .4;
31 protected final int knobSpacing = 6;
32 protected final int knobLabelHeight = 14;
33 protected final color lightBlue = #666699;
34 protected final color lightGreen = #669966;
35
36 private PImage logo;
37
38 protected final int STATE_DEFAULT = 0;
39 protected final int STATE_ACTIVE = 1;
40 protected final int STATE_PENDING = 2;
41
42 protected OverlayUI() {
43 leftPos = width - w;
44 leftTextPos = leftPos + 4;
45 logo = loadImage("logo-sm.png");
46 }
47
48 protected void drawLogoAndBackground() {
49 image(logo, 4, 4);
50 stroke(color(0, 0, 100));
51 // fill(color(0, 0, 50, 50)); // alpha is bad for perf
52 fill(color(0, 0, 30));
53 rect(leftPos-1, -1, w+2, height+2);
54 }
55
56 protected void drawToggleTip(String s) {
57 fill(#999999);
58 textFont(itemFont);
59 textAlign(LEFT);
60 text(s, leftTextPos, height-6);
61 }
62
63 protected void drawHelpTip() {
64 textFont(itemFont);
65 textAlign(RIGHT);
66 text("Tap 'u' to restore UI", width-4, height-6);
67 }
68
69 public void drawFPS() {
70 textFont(titleFont);
71 textAlign(LEFT);
72 fill(#666666);
73 text("FPS: " + (((int)(frameRate * 10)) / 10.), 4, height-6);
74 text("Target (-/+):", 50, height-6);
75 fill(#000000);
76 rect(104, height-16, 20, 12);
77 fill(#666666);
78 text("" + targetFramerate, 108, height-6);
79 }
80
81 protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod) {
82 return drawObjectList(yPos, title, items, classNameArray(items, null), stateMethod);
83 }
84
85 protected int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod) {
86 noStroke();
87 fill(titleColor);
88 textFont(titleFont);
89 textAlign(LEFT);
90 text(title, leftTextPos, yPos += lineHeight);
91 if (items != null) {
92 textFont(itemFont);
93 color textColor;
94 boolean even = true;
95 for (int i = 0; i < items.length; ++i) {
96 Object o = items[i];
97 int state = STATE_DEFAULT;
98 try {
99 state = ((Integer) stateMethod.invoke(this, o)).intValue();
100 } catch (Exception x) {
101 throw new RuntimeException(x);
102 }
103 switch (state) {
104 case STATE_ACTIVE:
105 fill(lightGreen);
106 textColor = #eeeeee;
107 break;
108 case STATE_PENDING:
109 fill(lightBlue);
110 textColor = color(0, 0, 75 + 15*sin(millis()/200.));;
111 break;
112 default:
113 textColor = 0;
114 fill(even ? #666666 : #777777);
115 break;
116 }
117 rect(leftPos, yPos+6, width, lineHeight);
118 fill(textColor);
119 text(names[i], leftTextPos, yPos += lineHeight);
120 even = !even;
121 }
122 }
123 return yPos;
124 }
125
126 protected String[] classNameArray(Object[] objects, String suffix) {
127 if (objects == null) {
128 return null;
129 }
130 String[] names = new String[objects.length];
131 for (int i = 0; i < objects.length; ++i) {
132 names[i] = className(objects[i], suffix);
133 }
134 return names;
135 }
136
137 protected String className(Object p, String suffix) {
138 String s = p.getClass().getName();
139 int li;
140 if ((li = s.lastIndexOf(".")) > 0) {
141 s = s.substring(li + 1);
142 }
143 if (s.indexOf("SugarCubes$") == 0) {
144 s = s.substring("SugarCubes$".length());
145 }
146 if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) {
147 s = s.substring(0, li);
148 }
149 return s;
150 }
151
152 protected int objectClickIndex(int firstItemY) {
153 return (mouseY - firstItemY) / lineHeight;
154 }
155
156 abstract public void draw();
157 abstract public void mousePressed();
158 abstract public void mouseDragged();
159 abstract public void mouseReleased();
160 }
161
162 /**
163 * UI for control of patterns, transitions, effects.
164 */
165 class ControlUI extends OverlayUI {
166 private final String[] patternNames;
167 private final String[] transitionNames;
168 private final String[] effectNames;
169
170 private int firstPatternY;
171 private int firstPatternKnobY;
172 private int firstTransitionY;
173 private int firstTransitionKnobY;
174 private int firstEffectY;
175 private int firstEffectKnobY;
176
177 private int tempoY;
178
179 private Method patternStateMethod;
180 private Method transitionStateMethod;
181 private Method effectStateMethod;
182
183 ControlUI() {
184 patternNames = classNameArray(patterns, "Pattern");
185 transitionNames = classNameArray(transitions, "Transition");
186 effectNames = classNameArray(effects, "Effect");
187
188 try {
189 patternStateMethod = getClass().getMethod("getState", LXPattern.class);
190 effectStateMethod = getClass().getMethod("getState", LXEffect.class);
191 transitionStateMethod = getClass().getMethod("getState", LXTransition.class);
192 } catch (Exception x) {
193 throw new RuntimeException(x);
194 }
195 }
196
197 public void draw() {
198 drawLogoAndBackground();
199 int yPos = 0;
200 firstPatternY = yPos + lineHeight + 6;
201 yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod);
202 yPos += controlSpacing;
203 firstPatternKnobY = yPos;
204 int xPos = leftTextPos;
205 for (int i = 0; i < glucose.NUM_PATTERN_KNOBS/2; ++i) {
206 drawKnob(xPos, yPos, knobSize, glucose.patternKnobs.get(i));
207 drawKnob(xPos, yPos + knobSize + knobSpacing + knobLabelHeight, knobSize, glucose.patternKnobs.get(glucose.NUM_PATTERN_KNOBS/2 + i));
208 xPos += knobSize + knobSpacing;
209 }
210 yPos += 2*(knobSize + knobLabelHeight) + knobSpacing;
211
212 yPos += sectionSpacing;
213 firstTransitionY = yPos + lineHeight + 6;
214 yPos = drawObjectList(yPos, "TRANSITION", transitions, transitionNames, transitionStateMethod);
215 yPos += controlSpacing;
216 firstTransitionKnobY = yPos;
217 xPos = leftTextPos;
218 for (VirtualTransitionKnob knob : glucose.transitionKnobs) {
219 drawKnob(xPos, yPos, knobSize, knob);
220 xPos += knobSize + knobSpacing;
221 }
222 yPos += knobSize + knobLabelHeight;
223
224 yPos += sectionSpacing;
225 firstEffectY = yPos + lineHeight + 6;
226 yPos = drawObjectList(yPos, "FX", effects, effectNames, effectStateMethod);
227 yPos += controlSpacing;
228 firstEffectKnobY = yPos;
229 xPos = leftTextPos;
230 for (VirtualEffectKnob knob : glucose.effectKnobs) {
231 drawKnob(xPos, yPos, knobSize, knob);
232 xPos += knobSize + knobSpacing;
233 }
234 yPos += knobSize + knobLabelHeight;
235
236 yPos += sectionSpacing;
237 yPos = drawObjectList(yPos, "TEMPO", null, null, null);
238 yPos += 6;
239 tempoY = yPos;
240 stroke(#111111);
241 fill(tempoDown ? lightGreen : color(0, 0, 35 - 8*lx.tempo.rampf()));
242 rect(leftPos + 4, yPos, w - 8, tempoHeight);
243 fill(0);
244 textAlign(CENTER);
245 text("" + ((int)(lx.tempo.bpmf() * 100) / 100.), leftPos + w/2., yPos + tempoHeight - 6);
246 yPos += tempoHeight;
247
248 drawToggleTip("Tap 'u' to hide");
249 }
250
251 public LXParameter getOrNull(List<LXParameter> items, int index) {
252 if (index < items.size()) {
253 return items.get(index);
254 }
255 return null;
256 }
257
258 public int getState(LXPattern p) {
259 if (p == lx.getPattern()) {
260 return STATE_ACTIVE;
261 } else if (p == lx.getNextPattern()) {
262 return STATE_PENDING;
263 }
264 return STATE_DEFAULT;
265 }
266
267 public int getState(LXEffect e) {
268 if (e.isEnabled()) {
269 return STATE_PENDING;
270 } else if (e == glucose.getSelectedEffect()) {
271 return STATE_ACTIVE;
272 }
273 return STATE_DEFAULT;
274 }
275
276 public int getState(LXTransition t) {
277 if (t == lx.getTransition()) {
278 return STATE_PENDING;
279 } else if (t == glucose.getSelectedTransition()) {
280 return STATE_ACTIVE;
281 }
282 return STATE_DEFAULT;
283 }
284
285 private void drawKnob(int xPos, int yPos, int knobSize, LXParameter knob) {
286 final float knobValue = knob.getValuef();
287 String knobLabel = knob.getLabel();
288 if (knobLabel == null) {
289 knobLabel = "-";
290 } else if (knobLabel.length() > 4) {
291 knobLabel = knobLabel.substring(0, 4);
292 }
293
294 ellipseMode(CENTER);
295 noStroke();
296 fill(#222222);
297 // For some reason this arc call really crushes drawing performance. Presumably
298 // because openGL is drawing it and when we overlap the second set of arcs it
299 // does a bunch of depth buffer intersection tests? Ellipse with a trapezoid cut out is faster
300 // arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent));
301 ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize);
302
303 float endArc = HALF_PI + knobIndent + (TWO_PI-2*knobIndent)*knobValue;
304 fill(lightGreen);
305 arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, endArc);
306
307 // Mask notch out of knob
308 fill(color(0, 0, 30));
309 beginShape();
310 vertex(xPos + knobSize/2, yPos + knobSize/2.);
311 vertex(xPos + knobSize/2 - 6, yPos + knobSize);
312 vertex(xPos + knobSize/2 + 6, yPos + knobSize);
313 endShape();
314
315 // Center circle of knob
316 fill(#333333);
317 ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize/2, knobSize/2);
318
319 fill(0);
320 rect(xPos, yPos + knobSize + 2, knobSize, knobLabelHeight - 2);
321 fill(#999999);
322 textAlign(CENTER);
323 textFont(knobFont);
324 text(knobLabel, xPos + knobSize/2, yPos + knobSize + knobLabelHeight - 2);
325 }
326
327 private int patternKnobIndex = -1;
328 private int transitionKnobIndex = -1;
329 private int effectKnobIndex = -1;
330
331 private int lastY;
332 private int releaseEffect = -1;
333 private boolean tempoDown = false;
334
335 public void mousePressed() {
336 lastY = mouseY;
337 patternKnobIndex = transitionKnobIndex = effectKnobIndex = -1;
338 releaseEffect = -1;
339 if (mouseY > tempoY) {
340 if (mouseY - tempoY < tempoHeight) {
341 lx.tempo.tap();
342 tempoDown = true;
343 }
344 } else if ((mouseY >= firstEffectKnobY) && (mouseY < firstEffectKnobY + knobSize + knobLabelHeight)) {
345 effectKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
346 } else if (mouseY > firstEffectY) {
347 int effectIndex = objectClickIndex(firstEffectY);
348 if (effectIndex < effects.length) {
349 if (effects[effectIndex] == glucose.getSelectedEffect()) {
350 effects[effectIndex].enable();
351 releaseEffect = effectIndex;
352 }
353 glucose.setSelectedEffect(effectIndex);
354 }
355 } else if ((mouseY >= firstTransitionKnobY) && (mouseY < firstTransitionKnobY + knobSize + knobLabelHeight)) {
356 transitionKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
357 } else if (mouseY > firstTransitionY) {
358 int transitionIndex = objectClickIndex(firstTransitionY);
359 if (transitionIndex < transitions.length) {
360 glucose.setSelectedTransition(transitionIndex);
361 }
362 } else if ((mouseY >= firstPatternKnobY) && (mouseY < firstPatternKnobY + 2*(knobSize+knobLabelHeight) + knobSpacing)) {
363 patternKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
364 if (mouseY >= firstPatternKnobY + knobSize + knobLabelHeight + knobSpacing) {
365 patternKnobIndex += glucose.NUM_PATTERN_KNOBS / 2;
366 }
367 } else if (mouseY > firstPatternY) {
368 int patternIndex = objectClickIndex(firstPatternY);
369 if (patternIndex < patterns.length) {
370 lx.goIndex(patternIndex);
371 }
372 }
373 }
374
375 public void mouseDragged() {
376 int dy = lastY - mouseY;
377 lastY = mouseY;
378 if (patternKnobIndex >= 0 && patternKnobIndex < glucose.NUM_PATTERN_KNOBS) {
379 LXParameter p = glucose.patternKnobs.get(patternKnobIndex);
380 p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
381 } else if (effectKnobIndex >= 0 && effectKnobIndex < glucose.NUM_EFFECT_KNOBS) {
382 LXParameter p = glucose.effectKnobs.get(effectKnobIndex);
383 p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
384 } else if (transitionKnobIndex >= 0 && transitionKnobIndex < glucose.NUM_TRANSITION_KNOBS) {
385 LXParameter p = glucose.transitionKnobs.get(transitionKnobIndex);
386 p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
387 }
388 }
389
390 public void mouseReleased() {
391 tempoDown = false;
392 if (releaseEffect >= 0) {
393 effects[releaseEffect].trigger();
394 releaseEffect = -1;
395 }
396 }
397
398 }
399
400 /**
401 * UI for control of mapping.
402 */
403 class MappingUI extends OverlayUI {
404
405 private MappingTool mappingTool;
406
407 private final String MAPPING_MODE_ALL = "All On";
408 private final String MAPPING_MODE_CHANNEL = "Channel";
409 private final String MAPPING_MODE_SINGLE_CUBE = "Single Cube";
410
411 private final String[] mappingModes = {
412 MAPPING_MODE_ALL,
413 MAPPING_MODE_CHANNEL,
414 MAPPING_MODE_SINGLE_CUBE
415 };
416 private final Method mappingModeStateMethod;
417
418 private final String CUBE_MODE_ALL = "All Strips";
419 private final String CUBE_MODE_SINGLE_STRIP = "Single Strip";
420 private final String CUBE_MODE_STRIP_PATTERN = "Strip Pattern";
421 private final String[] cubeModes = {
422 CUBE_MODE_ALL,
423 CUBE_MODE_SINGLE_STRIP,
424 CUBE_MODE_STRIP_PATTERN
425 };
426 private final Method cubeModeStateMethod;
427
428 private final String CHANNEL_MODE_RED = "Red";
429 private final String CHANNEL_MODE_GREEN = "Green";
430 private final String CHANNEL_MODE_BLUE = "Blue";
431 private final String[] channelModes = {
432 CHANNEL_MODE_RED,
433 CHANNEL_MODE_GREEN,
434 CHANNEL_MODE_BLUE,
435 };
436 private final Method channelModeStateMethod;
437
438 private int firstMappingY;
439 private int firstCubeY;
440 private int firstChannelY;
441 private int channelFieldY;
442 private int cubeFieldY;
443 private int stripFieldY;
444
445 private boolean dragCube;
446 private boolean dragStrip;
447 private boolean dragChannel;
448
449 MappingUI(MappingTool mappingTool) {
450 this.mappingTool = mappingTool;
451 try {
452 mappingModeStateMethod = getClass().getMethod("getMappingState", Object.class);
453 channelModeStateMethod = getClass().getMethod("getChannelState", Object.class);
454 cubeModeStateMethod = getClass().getMethod("getCubeState", Object.class);
455 } catch (Exception x) {
456 throw new RuntimeException(x);
457 }
458 }
459
460 public int getMappingState(Object mappingMode) {
461 boolean active = false;
462 if (mappingMode == MAPPING_MODE_ALL) {
463 active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_ALL;
464 } else if (mappingMode == MAPPING_MODE_CHANNEL) {
465 active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_CHANNEL;
466 } else if (mappingMode == MAPPING_MODE_SINGLE_CUBE) {
467 active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_SINGLE_CUBE;
468 }
469 return active ? STATE_ACTIVE : STATE_DEFAULT;
470 }
471
472 public int getChannelState(Object channelMode) {
473 boolean active = false;
474 if (channelMode == CHANNEL_MODE_RED) {
475 active = mappingTool.channelModeRed;
476 } else if (channelMode == CHANNEL_MODE_GREEN) {
477 active = mappingTool.channelModeGreen;
478 } else if (channelMode == CHANNEL_MODE_BLUE) {
479 active = mappingTool.channelModeBlue;
480 }
481 return active ? STATE_ACTIVE : STATE_DEFAULT;
482 }
483
484 public int getCubeState(Object cubeMode) {
485 boolean active = false;
486 if (cubeMode == CUBE_MODE_ALL) {
487 active = mappingTool.cubeMode == mappingTool.CUBE_MODE_ALL;
488 } else if (cubeMode == CUBE_MODE_SINGLE_STRIP) {
489 active = mappingTool.cubeMode == mappingTool.CUBE_MODE_SINGLE_STRIP;
490 } else if (cubeMode == CUBE_MODE_STRIP_PATTERN) {
491 active = mappingTool.cubeMode == mappingTool.CUBE_MODE_STRIP_PATTERN;
492 }
493 return active ? STATE_ACTIVE : STATE_DEFAULT;
494 }
495
496 public void draw() {
497 drawLogoAndBackground();
498 int yPos = 0;
499 firstMappingY = yPos + lineHeight + 6;
500 yPos = drawObjectList(yPos, "MAPPING MODE", mappingModes, mappingModes, mappingModeStateMethod);
501 yPos += sectionSpacing;
502
503 firstCubeY = yPos + lineHeight + 6;
504 yPos = drawObjectList(yPos, "CUBE MODE", cubeModes, cubeModes, cubeModeStateMethod);
505 yPos += sectionSpacing;
506
507 firstChannelY = yPos + lineHeight + 6;
508 yPos = drawObjectList(yPos, "CHANNELS", channelModes, channelModes, channelModeStateMethod);
509 yPos += sectionSpacing;
510
511 channelFieldY = yPos + lineHeight + 6;
512 yPos = drawValueField(yPos, "CHANNEL ID", mappingTool.channelIndex + 1);
513 yPos += sectionSpacing;
514
515 cubeFieldY = yPos + lineHeight + 6;
516 yPos = drawValueField(yPos, "CUBE ID", glucose.model.getRawIndexForCube(mappingTool.cubeIndex));
517 yPos += sectionSpacing;
518
519 stripFieldY = yPos + lineHeight + 6;
520 yPos = drawValueField(yPos, "STRIP ID", mappingTool.stripIndex + 1);
521
522 drawToggleTip("Tap 'm' to return");
523 }
524
525 private int drawValueField(int yPos, String label, int value) {
526 yPos += lineHeight;
527 textAlign(LEFT);
528 textFont(titleFont);
529 fill(titleColor);
530 text(label, leftTextPos, yPos);
531 fill(0);
532 yPos += 6;
533 rect(leftTextPos, yPos, w-8, lineHeight);
534 yPos += lineHeight;
535
536 fill(#999999);
537 textAlign(CENTER);
538 textFont(itemFont);
539 text("" + value, leftTextPos + (w-8)/2, yPos - 5);
540
541 return yPos;
542 }
543
544 private int lastY;
545
546 public void mousePressed() {
547 dragCube = dragStrip = dragChannel = false;
548 lastY = mouseY;
549 if (mouseY >= stripFieldY) {
550 if (mouseY < stripFieldY + lineHeight) {
551 dragStrip = true;
552 }
553 } else if (mouseY >= cubeFieldY) {
554 if (mouseY < cubeFieldY + lineHeight) {
555 dragCube = true;
556 }
557 } else if (mouseY >= channelFieldY) {
558 if (mouseY < channelFieldY + lineHeight) {
559 dragChannel = true;
560 }
561 } else if (mouseY >= firstChannelY) {
562 int index = objectClickIndex(firstChannelY);
563 switch (index) {
564 case 0: mappingTool.channelModeRed = !mappingTool.channelModeRed; break;
565 case 1: mappingTool.channelModeGreen = !mappingTool.channelModeGreen; break;
566 case 2: mappingTool.channelModeBlue = !mappingTool.channelModeBlue; break;
567 }
568 } else if (mouseY >= firstCubeY) {
569 int index = objectClickIndex(firstCubeY);
570 switch (index) {
571 case 0: mappingTool.cubeMode = mappingTool.CUBE_MODE_ALL; break;
572 case 1: mappingTool.cubeMode = mappingTool.CUBE_MODE_SINGLE_STRIP; break;
573 case 2: mappingTool.cubeMode = mappingTool.CUBE_MODE_STRIP_PATTERN; break;
574 }
575 } else if (mouseY >= firstMappingY) {
576 int index = objectClickIndex(firstMappingY);
577 switch (index) {
578 case 0: mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL; break;
579 case 1: mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL; break;
580 case 2: mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE; break;
581 }
582 }
583 }
584
585 public void mouseReleased() {
586 }
587
588 public void mouseDragged() {
589 final int DRAG_THRESHOLD = 5;
590 int dy = lastY - mouseY;
591 if (abs(dy) >= DRAG_THRESHOLD) {
592 lastY = mouseY;
593 if (dragCube) {
594 if (dy < 0) {
595 mappingTool.decCube();
596 } else {
597 mappingTool.incCube();
598 }
599 } else if (dragStrip) {
600 if (dy < 0) {
601 mappingTool.decStrip();
602 } else {
603 mappingTool.incStrip();
604 }
605 } else if (dragChannel) {
606 if (dy < 0) {
607 mappingTool.decChannel();
608 } else {
609 mappingTool.incChannel();
610 }
611 }
612 }
613
614 }
615 }
616
617 class DebugUI {
618
619 final int[][] channelList;
620 final int debugX = 10;
621 final int debugY = 42;
622 final int debugXSpacing = 28;
623 final int debugYSpacing = 22;
624 final int[][] debugState = new int[17][6];
625
626 final int DEBUG_STATE_ANIM = 0;
627 final int DEBUG_STATE_WHITE = 1;
628 final int DEBUG_STATE_OFF = 2;
629
630 DebugUI(int[][] frontChannels, int[][] rearChannels) {
631 channelList = new int[frontChannels.length + rearChannels.length][];
632 int channelIndex = 0;
633 for (int[] channel : frontChannels) {
634 channelList[channelIndex++] = channel;
635 }
636 for (int[] channel : rearChannels) {
637 channelList[channelIndex++] = channel;
638 }
639 for (int i = 0; i < debugState.length; ++i) {
640 for (int j = 0; j < debugState[i].length; ++j) {
641 debugState[i][j] = DEBUG_STATE_ANIM;
642 }
643 }
644 }
645
646 void draw() {
647 noStroke();
648 int xBase = debugX;
649 int yPos = debugY;
650
651 fill(color(0, 0, 0, 80));
652 rect(4, 32, 172, 388);
653
654 int channelNum = 0;
655 for (int[] channel : channelList) {
656 int xPos = xBase;
657 drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]);
658
659 boolean first = true;
660 int cubeNum = 0;
661 for (int cube : channel) {
662 if (cube == 0) {
663 break;
664 }
665 xPos += debugXSpacing;
666 if (first) {
667 first = false;
668 } else {
669 stroke(#999999);
670 line(xPos - 12, yPos + 8, xPos, yPos + 8);
671 }
672 drawNumBox(xPos, yPos, cube, debugState[channelNum][cubeNum+1]);
673 ++cubeNum;
674 }
675
676 yPos += debugYSpacing;
677 ++channelNum;
678 }
679 drawNumBox(xBase, yPos, "A", debugState[channelNum][0]);
680 }
681
682 void drawNumBox(int xPos, int yPos, int label, int state) {
683 drawNumBox(xPos, yPos, "" + label, state);
684 }
685
686 void drawNumBox(int xPos, int yPos, String label, int state) {
687 noFill();
688 color textColor = #cccccc;
689 switch (state) {
690 case DEBUG_STATE_ANIM:
691 noStroke();
692 fill(#880000);
693 rect(xPos, yPos, 16, 8);
694 fill(#000088);
695 rect(xPos, yPos+8, 16, 8);
696 noFill();
697 stroke(textColor);
698 rect(xPos, yPos, 16, 16);
699 break;
700 case DEBUG_STATE_WHITE:
701 stroke(textColor);
702 fill(#e9e9e9);
703 rect(xPos, yPos, 16, 16);
704 textColor = #333333;
705 break;
706 case DEBUG_STATE_OFF:
707 stroke(textColor);
708 rect(xPos, yPos, 16, 16);
709 break;
710 }
711
712 noStroke();
713 fill(textColor);
714 text(label, xPos + 2, yPos + 12);
715
716 }
717
718 void maskColors(color[] colors) {
719 color white = #FFFFFF;
720 color off = #000000;
721 int channelIndex = 0;
722 for (int[] channel : channelList) {
723 int cubeIndex = 1;
724 for (int rawCubeIndex : channel) {
725 if (rawCubeIndex > 0) {
726 int state = debugState[channelIndex][cubeIndex];
727 if (state != DEBUG_STATE_ANIM) {
728 color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
729 Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex);
730 for (Point p : cube.points) {
731 colors[p.index] = debugColor;
732 }
733 }
734 }
735 ++cubeIndex;
736 }
737 ++channelIndex;
738 }
739 }
740
741 void mousePressed() {
742 int dx = (mouseX - debugX) / debugXSpacing;
743 int dy = (mouseY - debugY) / debugYSpacing;
744 if ((dy >= 0) && (dy < debugState.length)) {
745 if ((dx >= 0) && (dx < debugState[dy].length)) {
746 int newState = debugState[dy][dx] = (debugState[dy][dx] + 1) % 3;
747 if (dy == 16) {
748 for (int[] states : debugState) {
749 for (int i = 0; i < states.length; ++i) {
750 states[i] = newState;
751 }
752 }
753 } else if (dx == 0) {
754 for (int i = 0; i < debugState[dy].length; ++i) {
755 debugState[dy][i] = newState;
756 }
757 }
758 }
759 }
760 }
761 }