Make hue knob more sensitive
[SugarCubes.git] / _Internals.pde
CommitLineData
49815cc0 1/**
1ecdb44a
MS
2 * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
3 *
4 * //\\ //\\ //\\ //\\
5 * ///\\\ ///\\\ ///\\\ ///\\\
6 * \\\/// \\\/// \\\/// \\\///
7 * \\// \\// \\// \\//
8 *
9 * EXPERTS ONLY!! EXPERTS ONLY!!
10 *
49815cc0
MS
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
16import glucose.*;
17import glucose.control.*;
3f8be614 18import glucose.effect.*;
f3f5a876 19import glucose.model.*;
49815cc0 20import glucose.pattern.*;
f3f5a876 21import glucose.transform.*;
49815cc0 22import glucose.transition.*;
49815cc0 23import heronarts.lx.*;
3f8be614 24import heronarts.lx.control.*;
49815cc0 25import heronarts.lx.effect.*;
49815cc0 26import heronarts.lx.modulator.*;
f3f5a876 27import heronarts.lx.pattern.*;
49815cc0
MS
28import heronarts.lx.transition.*;
29import ddf.minim.*;
30import ddf.minim.analysis.*;
31import processing.opengl.*;
5d70e4d7 32import rwmidi.*;
24fc0330 33import java.lang.reflect.*;
49815cc0
MS
34
35final int VIEWPORT_WIDTH = 900;
36final int VIEWPORT_HEIGHT = 700;
0e3c5542 37
92c06c97 38// The trailer is measured from the outside of the black metal (but not including the higher welded part on the front)
87998ff3
MS
39final float TRAILER_WIDTH = 240;
40final float TRAILER_DEPTH = 97;
41final float TRAILER_HEIGHT = 33;
42
41f26e8f 43final int MaxCubeHeight = 5;
41c436e4 44final int NumBackTowers = 11;
7e3329d2 45
51d0d59a 46int targetFramerate = 60;
49815cc0 47int startMillis, lastMillis;
a898d79b
MS
48
49// Core engine variables
49815cc0
MS
50GLucose glucose;
51HeronLX lx;
52LXPattern[] patterns;
24fc0330 53Effects effects;
a898d79b 54MappingTool mappingTool;
79ae8245 55PandaDriver[] pandaBoards;
e0794d3a 56PresetManager presetManager;
1f974cbc 57MidiEngine midiEngine;
a898d79b
MS
58
59// Display configuration mode
bf551144 60boolean mappingMode = false;
cc9fcf4b 61boolean debugMode = false;
554e38ff 62DebugUI debugUI;
34327c96
MS
63boolean uiOn = true;
64LXPattern restoreToPattern = null;
4c640acc 65PImage logo;
a41f334c 66float[] hsb = new float[3];
d626bc9b 67
a898d79b 68// Handles to UI objects
d626bc9b
MS
69UIContext[] overlays;
70UIPatternDeck uiPatternA;
a898d79b 71UICrossfader uiCrossfader;
a8d55ade 72UIMidi uiMidi;
d626bc9b
MS
73UIMapping uiMapping;
74UIDebugText uiDebugText;
cc9fcf4b 75
0a9f99cc 76// Camera variables
bda5421d 77float eyeR, eyeA, eyeX, eyeY, eyeZ, midX, midY, midZ;
0a9f99cc 78
34327c96
MS
79/**
80 * Engine construction and initialization.
81 */
d1dcc4b5
MS
82
83LXTransition _transition(GLucose glucose) {
84 return new DissolveTransition(glucose.lx).setDuration(1000);
85}
86
87LXPattern[] _leftPatterns(GLucose glucose) {
d626bc9b
MS
88 LXPattern[] patterns = patterns(glucose);
89 for (LXPattern p : patterns) {
d1dcc4b5 90 p.setTransition(_transition(glucose));
d626bc9b
MS
91 }
92 return patterns;
93}
94
d1dcc4b5
MS
95LXPattern[] _rightPatterns(GLucose glucose) {
96 LXPattern[] patterns = _leftPatterns(glucose);
97 LXPattern[] rightPatterns = new LXPattern[patterns.length+1];
98 int i = 0;
99 rightPatterns[i++] = new BlankPattern(glucose).setTransition(_transition(glucose));
100 for (LXPattern p : patterns) {
101 rightPatterns[i++] = p;
102 }
103 return rightPatterns;
104}
24fc0330
MS
105
106LXEffect[] _effectsArray(Effects effects) {
107 List<LXEffect> effectList = new ArrayList<LXEffect>();
108 for (Field f : effects.getClass().getDeclaredFields()) {
109 try {
110 Object val = f.get(effects);
111 if (val instanceof LXEffect) {
112 effectList.add((LXEffect)val);
113 }
114 } catch (IllegalAccessException iax) {}
115 }
116 return effectList.toArray(new LXEffect[]{});
117}
d1dcc4b5 118
34327c96
MS
119void logTime(String evt) {
120 int now = millis();
121 println(evt + ": " + (now - lastMillis) + "ms");
122 lastMillis = now;
123}
124
49815cc0
MS
125void setup() {
126 startMillis = lastMillis = millis();
127
128 // Initialize the Processing graphics environment
129 size(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, OPENGL);
0e3c5542 130 frameRate(targetFramerate);
3f8be614 131 noSmooth();
49815cc0
MS
132 // hint(ENABLE_OPENGL_4X_SMOOTH); // no discernable improvement?
133 logTime("Created viewport");
134
135 // Create the GLucose engine to run the cubes
186bc4d3 136 glucose = new GLucose(this, buildModel());
49815cc0 137 lx = glucose.lx;
cc9fcf4b 138 lx.enableKeyboardTempo();
49815cc0
MS
139 logTime("Built GLucose engine");
140
141 // Set the patterns
42a424d7 142 LXEngine engine = lx.engine;
d1dcc4b5
MS
143 engine.setPatterns(patterns = _leftPatterns(glucose));
144 engine.addDeck(_rightPatterns(glucose));
49815cc0 145 logTime("Built patterns");
a898d79b
MS
146 glucose.setTransitions(transitions(glucose));
147 logTime("Built transitions");
24fc0330 148 glucose.lx.addEffects(_effectsArray(effects = new Effects()));
49815cc0 149 logTime("Built effects");
4214e9a2 150
e0794d3a
MS
151 // Preset manager
152 presetManager = new PresetManager();
153 logTime("Loaded presets");
4214e9a2 154
1f974cbc
MS
155 // MIDI devices
156 midiEngine = new MidiEngine();
1f974cbc
MS
157 logTime("Setup MIDI devices");
158
e73ef85d 159 // Build output driver
186bc4d3 160 PandaMapping[] pandaMappings = buildPandaList();
45f43cc2
MS
161 pandaBoards = new PandaDriver[pandaMappings.length];
162 int pbi = 0;
163 for (PandaMapping pm : pandaMappings) {
44b8de9c 164 pandaBoards[pbi++] = new PandaDriver(pm.ip, glucose.model, pm);
45f43cc2
MS
165 }
166 mappingTool = new MappingTool(glucose, pandaMappings);
167 logTime("Built PandaDriver");
a8d55ade 168
49815cc0 169 // Build overlay UI
45f43cc2 170 debugUI = new DebugUI(pandaMappings);
d626bc9b 171 overlays = new UIContext[] {
42a424d7 172 uiPatternA = new UIPatternDeck(lx.engine.getDeck(GLucose.LEFT_DECK), "PATTERN A", 4, 4, 140, 324),
a8d55ade
MS
173 new UIBlendMode(4, 332, 140, 86),
174 new UIEffects(4, 422, 140, 144),
175 new UITempo(4, 570, 140, 50),
176 new UISpeed(4, 624, 140, 50),
177
42a424d7 178 new UIPatternDeck(lx.engine.getDeck(GLucose.RIGHT_DECK), "PATTERN B", width-144, 4, 140, 324),
d6ac1ee8 179 uiMidi = new UIMidi(midiEngine, width-144, 332, 140, 158),
4df91daf 180 new UIOutput(width-144, 494, 140, 106),
d626bc9b 181
a8d55ade 182 uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86),
d626bc9b 183
a8d55ade
MS
184 uiDebugText = new UIDebugText(148, height-138, width-304, 44),
185 uiMapping = new UIMapping(mappingTool, 4, 4, 140, 324),
d626bc9b
MS
186 };
187 uiMapping.setVisible(false);
49815cc0 188 logTime("Built overlay UI");
4c640acc
MS
189
190 // Load logo image
191 logo = loadImage("data/logo.png");
192
0a9f99cc 193 // Setup camera
d626bc9b 194 midX = TRAILER_WIDTH/2.;
0a9f99cc 195 midY = glucose.model.yMax/2;
e0cea600
MS
196 midZ = TRAILER_DEPTH/2.;
197 eyeR = -290;
0a9f99cc 198 eyeA = .15;
d626bc9b 199 eyeY = midY + 70;
0a9f99cc
MS
200 eyeX = midX + eyeR*sin(eyeA);
201 eyeZ = midZ + eyeR*cos(eyeA);
d6ac1ee8
MS
202
203 // Add mouse scrolling event support
bda5421d
MS
204 addMouseWheelListener(new java.awt.event.MouseWheelListener() {
205 public void mouseWheelMoved(java.awt.event.MouseWheelEvent mwe) {
206 mouseWheel(mwe.getWheelRotation());
207 }});
208
49815cc0 209 println("Total setup: " + (millis() - startMillis) + "ms");
e73ef85d 210 println("Hit the 'p' key to toggle Panda Board output");
49815cc0
MS
211}
212
34327c96
MS
213/**
214 * Core render loop and drawing functionality.
215 */
49815cc0 216void draw() {
0a9f99cc
MS
217 // Draws the simulation and the 2D UI overlay
218 background(40);
a898d79b 219
19d16a16
MS
220 color[] simulationColors;
221 color[] sendColors;
222 simulationColors = sendColors = glucose.getColors();
a898d79b 223 String displayMode = uiCrossfader.getDisplayMode();
d626bc9b 224 if (displayMode == "A") {
6b3d53ca 225 simulationColors = lx.engine.getDeck(GLucose.LEFT_DECK).getColors();
d626bc9b 226 } else if (displayMode == "B") {
6b3d53ca 227 simulationColors = lx.engine.getDeck(GLucose.RIGHT_DECK).getColors();
d626bc9b 228 }
554e38ff 229 if (debugMode) {
19d16a16
MS
230 debugUI.maskColors(simulationColors);
231 debugUI.maskColors(sendColors);
554e38ff 232 }
51d0d59a 233
0a9f99cc
MS
234 camera(
235 eyeX, eyeY, eyeZ,
236 midX, midY, midZ,
237 0, -1, 0
238 );
51d0d59a 239
a8d55ade 240 translate(0, 40, 0);
d626bc9b 241
51d0d59a
MS
242 noStroke();
243 fill(#141414);
87998ff3 244 drawBox(0, -TRAILER_HEIGHT, 0, 0, 0, 0, TRAILER_WIDTH, TRAILER_HEIGHT, TRAILER_DEPTH, TRAILER_HEIGHT/2.);
51d0d59a
MS
245 fill(#070707);
246 stroke(#222222);
0a9f99cc 247 beginShape();
51d0d59a 248 vertex(0, 0, 0);
87998ff3
MS
249 vertex(TRAILER_WIDTH, 0, 0);
250 vertex(TRAILER_WIDTH, 0, TRAILER_DEPTH);
251 vertex(0, 0, TRAILER_DEPTH);
51d0d59a 252 endShape();
4c640acc
MS
253
254 // Draw the logo on the front of platform
255 pushMatrix();
256 translate(0, 0, -1);
257 float s = .07;
258 scale(s, -s, s);
259 image(logo, TRAILER_WIDTH/2/s-logo.width/2, TRAILER_HEIGHT/2/s-logo.height/2-2/s);
260 popMatrix();
0a9f99cc 261
51d0d59a 262 noStroke();
e89eda9f
MS
263 if (glucose.model.bassBox.exists) {
264 drawBassBox(glucose.model.bassBox, false);
265 }
266 for (Speaker speaker : glucose.model.speakers) {
267 drawSpeaker(speaker);
268 }
51d0d59a
MS
269 for (Cube c : glucose.model.cubes) {
270 drawCube(c);
271 }
272
0a9f99cc
MS
273 noFill();
274 strokeWeight(2);
275 beginShape(POINTS);
e89eda9f 276 for (Point p : glucose.model.points) {
19d16a16 277 stroke(simulationColors[p.index]);
190d91c2 278 vertex(p.x, p.y, p.z);
0a9f99cc
MS
279 }
280 endShape();
281
d626bc9b 282 // 2D Overlay UI
0a9f99cc 283 drawUI();
d626bc9b 284
6702151a
MS
285 // Gamma correction here. Apply a cubic to the brightness
286 // for better representation of dynamic range
7f782b99 287 for (int i = 0; i < sendColors.length; ++i) {
a41f334c
MS
288 lx.RGBtoHSB(sendColors[i], hsb);
289 float b = hsb[2];
290 sendColors[i] = lx.hsb(360.*hsb[0], 100.*hsb[1], 100.*(b*b*b));
6702151a 291 }
e7f14d4d 292
e73ef85d 293 // TODO(mcslee): move into GLucose engine
79ae8245 294 for (PandaDriver p : pandaBoards) {
7f782b99 295 p.send(sendColors);
e73ef85d 296 }
49815cc0
MS
297}
298
e89eda9f
MS
299void drawBassBox(BassBox b, boolean hasSub) {
300
92c06c97 301 float in = .15;
e89eda9f
MS
302
303 if (hasSub) {
304 noStroke();
305 fill(#191919);
306 pushMatrix();
307 translate(b.x + BassBox.EDGE_WIDTH/2., b.y + BassBox.EDGE_HEIGHT/2, b.z + BassBox.EDGE_DEPTH/2.);
308 box(BassBox.EDGE_WIDTH-20*in, BassBox.EDGE_HEIGHT-20*in, BassBox.EDGE_DEPTH-20*in);
309 popMatrix();
310 }
e76480d4
MS
311
312 noStroke();
313 fill(#393939);
92c06c97
MS
314 drawBox(b.x+in, b.y+in, b.z+in, 0, 0, 0, BassBox.EDGE_WIDTH-in*2, BassBox.EDGE_HEIGHT-in*2, BassBox.EDGE_DEPTH-in*2, Cube.CHANNEL_WIDTH-in);
315
39011e7e
MS
316 pushMatrix();
317 translate(b.x+(Cube.CHANNEL_WIDTH-in)/2., b.y + BassBox.EDGE_HEIGHT-in, b.z + BassBox.EDGE_DEPTH/2.);
318 float lastOffset = 0;
319 for (float offset : BoothFloor.STRIP_OFFSETS) {
320 translate(offset - lastOffset, 0, 0);
321 box(Cube.CHANNEL_WIDTH-in, 0, BassBox.EDGE_DEPTH - 2*in);
322 lastOffset = offset;
323 }
324 popMatrix();
325
92c06c97
MS
326 pushMatrix();
327 translate(b.x + (Cube.CHANNEL_WIDTH-in)/2., b.y + BassBox.EDGE_HEIGHT/2., b.z + in);
328 for (int j = 0; j < 2; ++j) {
329 pushMatrix();
330 for (int i = 0; i < BassBox.NUM_FRONT_STRUTS; ++i) {
331 translate(BassBox.FRONT_STRUT_SPACING, 0, 0);
332 box(Cube.CHANNEL_WIDTH-in, BassBox.EDGE_HEIGHT - in*2, 0);
333 }
334 popMatrix();
335 translate(0, 0, BassBox.EDGE_DEPTH - 2*in);
336 }
337 popMatrix();
338
339 pushMatrix();
340 translate(b.x + in, b.y + BassBox.EDGE_HEIGHT/2., b.z + BassBox.SIDE_STRUT_SPACING + (Cube.CHANNEL_WIDTH-in)/2.);
341 box(0, BassBox.EDGE_HEIGHT - in*2, Cube.CHANNEL_WIDTH-in);
342 translate(BassBox.EDGE_WIDTH-2*in, 0, 0);
343 box(0, BassBox.EDGE_HEIGHT - in*2, Cube.CHANNEL_WIDTH-in);
ab77005f 344 popMatrix();
e76480d4 345
92c06c97
MS
346}
347
51d0d59a 348void drawCube(Cube c) {
254d34c0 349 float in = .15;
e76480d4
MS
350 noStroke();
351 fill(#393939);
254d34c0 352 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);
51d0d59a
MS
353}
354
e76480d4
MS
355void drawSpeaker(Speaker s) {
356 float in = .15;
357
358 noStroke();
359 fill(#191919);
360 pushMatrix();
361 translate(s.x, s.y, s.z);
362 rotate(s.ry / 180. * PI, 0, -1, 0);
363 translate(Speaker.EDGE_WIDTH/2., Speaker.EDGE_HEIGHT/2., Speaker.EDGE_DEPTH/2.);
364 box(Speaker.EDGE_WIDTH-20*in, Speaker.EDGE_HEIGHT-20*in, Speaker.EDGE_DEPTH-20*in);
254fbb68
MS
365 translate(0, Speaker.EDGE_HEIGHT/2. + Speaker.EDGE_HEIGHT*.8/2, 0);
366
367 fill(#222222);
368 box(Speaker.EDGE_WIDTH*.6, Speaker.EDGE_HEIGHT*.8, Speaker.EDGE_DEPTH*.75);
e76480d4
MS
369 popMatrix();
370
e76480d4
MS
371 noStroke();
372 fill(#393939);
373 drawBox(s.x+in, s.y+in, s.z+in, 0, s.ry, 0, Speaker.EDGE_WIDTH-in*2, Speaker.EDGE_HEIGHT-in*2, Speaker.EDGE_DEPTH-in*2, Cube.CHANNEL_WIDTH-in);
ab77005f 374}
e76480d4 375
51d0d59a
MS
376void drawBox(float x, float y, float z, float rx, float ry, float rz, float xd, float yd, float zd, float sw) {
377 pushMatrix();
378 translate(x, y, z);
e0cea600 379 rotate(rx / 180. * PI, -1, 0, 0);
51d0d59a 380 rotate(ry / 180. * PI, 0, -1, 0);
e0cea600 381 rotate(rz / 180. * PI, 0, 0, -1);
51d0d59a
MS
382 for (int i = 0; i < 4; ++i) {
383 float wid = (i % 2 == 0) ? xd : zd;
384
385 beginShape();
386 vertex(0, 0);
387 vertex(wid, 0);
388 vertex(wid, yd);
389 vertex(wid - sw, yd);
390 vertex(wid - sw, sw);
391 vertex(0, sw);
392 endShape();
393 beginShape();
394 vertex(0, sw);
395 vertex(0, yd);
396 vertex(wid - sw, yd);
397 vertex(wid - sw, yd - sw);
398 vertex(sw, yd - sw);
399 vertex(sw, sw);
400 endShape();
401
402 translate(wid, 0, 0);
403 rotate(HALF_PI, 0, -1, 0);
404 }
405 popMatrix();
406}
407
49815cc0 408void drawUI() {
d626bc9b
MS
409 camera();
410 javax.media.opengl.GL gl = ((PGraphicsOpenGL)g).beginGL();
411 gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
412 ((PGraphicsOpenGL)g).endGL();
413 strokeWeight(1);
414
49815cc0 415 if (uiOn) {
d626bc9b
MS
416 for (UIContext context : overlays) {
417 context.draw();
418 }
419 }
420
421 // Always draw FPS meter
422 fill(#555555);
423 textSize(9);
424 textAlign(LEFT, BASELINE);
425 text("FPS: " + ((int) (frameRate*10)) / 10. + " / " + targetFramerate + " (-/+)", 4, height-4);
426
427 if (debugMode) {
428 debugUI.draw();
49815cc0 429 }
49815cc0
MS
430}
431
4c640acc 432
34327c96
MS
433/**
434 * Top-level keyboard event handling
435 */
49815cc0 436void keyPressed() {
bf551144 437 if (mappingMode) {
d626bc9b 438 mappingTool.keyPressed(uiMapping);
bf551144 439 }
3f8be614 440 switch (key) {
2b068dd5
MS
441 case '1':
442 case '2':
443 case '3':
444 case '4':
445 case '5':
446 case '6':
447 case '7':
448 case '8':
449 if (!midiEngine.isQwertyEnabled()) {
450 presetManager.select(midiEngine.getFocusedDeck(), key - '1');
451 }
452 break;
453
454 case '!':
455 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 0);
456 break;
457 case '@':
458 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 1);
459 break;
460 case '#':
461 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 2);
462 break;
463 case '$':
464 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 3);
465 break;
466 case '%':
467 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 4);
468 break;
469 case '^':
470 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 5);
471 break;
472 case '&':
473 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 6);
474 break;
475 case '*':
476 if (!midiEngine.isQwertyEnabled()) presetManager.store(midiEngine.getFocusedDeck(), 7);
477 break;
478
0e3c5542
MS
479 case '-':
480 case '_':
481 frameRate(--targetFramerate);
482 break;
483 case '=':
484 case '+':
485 frameRate(++targetFramerate);
75e1ddde
MS
486 break;
487 case 'b':
24fc0330 488 effects.boom.trigger();
75e1ddde 489 break;
cc9fcf4b 490 case 'd':
d6ac1ee8 491 if (!midiEngine.isQwertyEnabled()) {
a8d55ade
MS
492 debugMode = !debugMode;
493 println("Debug output: " + (debugMode ? "ON" : "OFF"));
494 }
554e38ff 495 break;
bf551144 496 case 'm':
d6ac1ee8 497 if (!midiEngine.isQwertyEnabled()) {
a8d55ade
MS
498 mappingMode = !mappingMode;
499 uiPatternA.setVisible(!mappingMode);
500 uiMapping.setVisible(mappingMode);
501 if (mappingMode) {
502 restoreToPattern = lx.getPattern();
503 lx.setPatterns(new LXPattern[] { mappingTool });
504 } else {
505 lx.setPatterns(patterns);
506 LXTransition pop = restoreToPattern.getTransition();
507 restoreToPattern.setTransition(null);
508 lx.goPattern(restoreToPattern);
509 restoreToPattern.setTransition(pop);
510 }
bf551144
MS
511 }
512 break;
19d16a16
MS
513 case 't':
514 if (!midiEngine.isQwertyEnabled()) {
515 lx.engine.setThreaded(!lx.engine.isThreaded());
516 }
517 break;
e73ef85d 518 case 'p':
79ae8245
MS
519 for (PandaDriver p : pandaBoards) {
520 p.toggle();
521 }
cc9fcf4b 522 break;
3f8be614 523 case 'u':
d6ac1ee8 524 if (!midiEngine.isQwertyEnabled()) {
4df91daf
MS
525 uiOn = !uiOn;
526 }
3f8be614 527 break;
49815cc0
MS
528 }
529}
530
34327c96
MS
531/**
532 * Top-level mouse event handling
533 */
0a9f99cc 534int mx, my;
0a9f99cc 535void mousePressed() {
d626bc9b
MS
536 boolean debugged = false;
537 if (debugMode) {
538 debugged = debugUI.mousePressed();
539 }
540 if (!debugged) {
541 for (UIContext context : overlays) {
542 context.mousePressed(mouseX, mouseY);
543 }
0a9f99cc 544 }
d626bc9b
MS
545 mx = mouseX;
546 my = mouseY;
0a9f99cc
MS
547}
548
549void mouseDragged() {
d626bc9b
MS
550 boolean dragged = false;
551 for (UIContext context : overlays) {
552 dragged |= context.mouseDragged(mouseX, mouseY);
553 }
554 if (!dragged) {
0a9f99cc
MS
555 int dx = mouseX - mx;
556 int dy = mouseY - my;
557 mx = mouseX;
558 my = mouseY;
559 eyeA += dx*.003;
560 eyeX = midX + eyeR*sin(eyeA);
561 eyeZ = midZ + eyeR*cos(eyeA);
562 eyeY += dy;
563 }
564}
565
566void mouseReleased() {
d626bc9b
MS
567 for (UIContext context : overlays) {
568 context.mouseReleased(mouseX, mouseY);
569 }
0a9f99cc 570}
73687629 571
a0140e21 572void mouseWheel(int delta) {
d626bc9b
MS
573 boolean wheeled = false;
574 for (UIContext context : overlays) {
575 wheeled |= context.mouseWheel(mouseX, mouseY, delta);
576 }
577
578 if (!wheeled) {
0ba6ac44
MS
579 eyeR = constrain(eyeR - delta, -500, -80);
580 eyeX = midX + eyeR*sin(eyeA);
581 eyeZ = midZ + eyeR*cos(eyeA);
582 }
bda5421d 583}