1 #include "LDInputHandler.h"
2 #include "LDrawModelViewer.h"
3 #include <TCFoundation/TCAlertManager.h>
4 #include <TCFoundation/TCAlert.h>
5 #include <TCFoundation/TCMacros.h>
6
7 #ifdef WIN32
8 #if defined(_MSC_VER) && _MSC_VER >= 1400 && defined(_DEBUG)
9 #define new DEBUG_CLIENTBLOCK
10 #endif // _DEBUG
11 #endif // WIN32
12
13 #ifdef COCOA
14 #include <Foundation/Foundation.h>
15 #define STOP_TIME ((NSDate *&)m_stopTime)
16 #endif // COCOA
17
18 TCFloat LDInputHandler::sm_keyRotationSpeed = 0.5f;
19
LDInputHandler(LDrawModelViewer * m_modelViewer)20 LDInputHandler::LDInputHandler(LDrawModelViewer *m_modelViewer):
21 m_modelViewer(m_modelViewer),
22 m_viewMode(VMExamine),
23 m_mouseMode(MMNone),
24 m_appleRightClick(false),
25 m_numButtons(sizeof(m_buttonsDown) / sizeof(m_buttonsDown[0]))
26 #ifdef WIN32
27 , m_haveStopTicks(false)
28 #endif // WIN32
29 #ifdef COCOA
30 , m_stopTime(NULL)
31 #endif // COCOA
32 {
33 memset(&m_buttonsDown, 0, sizeof(m_buttonsDown));
34 TCAlertManager::registerHandler(LDrawModelViewer::frameDoneAlertClass(),
35 this, (TCAlertCallback)&LDInputHandler::frameDone);
36 }
37
~LDInputHandler(void)38 LDInputHandler::~LDInputHandler(void)
39 {
40 }
41
dealloc(void)42 void LDInputHandler::dealloc(void)
43 {
44 #ifdef COCOA
45 [STOP_TIME release];
46 #endif // COCOA
47 TCAlertManager::unregisterHandler(this);
48 TCObject::dealloc();
49 }
50
cancelMouseDrag(void)51 void LDInputHandler::cancelMouseDrag(void)
52 {
53 m_mouseMode = MMNone;
54 for (int i = 0; i < m_numButtons; i++)
55 {
56 m_buttonsDown[i] = false;
57 }
58 }
59
setViewMode(LDInputHandler::ViewMode value)60 void LDInputHandler::setViewMode(LDInputHandler::ViewMode value)
61 {
62 stopRotation();
63 m_viewMode = value;
64 if (m_modelViewer)
65 {
66 m_modelViewer->setViewMode((LDrawModelViewer::ViewMode)value);
67 if (value == VMExamine)
68 {
69 m_modelViewer->setConstrainZoom(true);
70 }
71 else
72 {
73 m_modelViewer->setConstrainZoom(false);
74 }
75 m_modelViewer->requestRedraw();
76 }
77 }
78
stopRotation(void)79 void LDInputHandler::stopRotation(void)
80 {
81 recordRotationStop();
82 m_rotationSpeed = 0.0f;
83 m_modelViewer->setXRotate(0.0f);
84 m_modelViewer->setYRotate(0.0f);
85 m_modelViewer->setRotationSpeed(m_rotationSpeed);
86 }
87
updateSpinRateXY(int xPos,int yPos)88 void LDInputHandler::updateSpinRateXY(int xPos, int yPos)
89 {
90 int deltaX = xPos - m_lastX;
91 int deltaY = yPos - m_lastY;
92 TCFloat magnitude = (TCFloat)sqrt((TCFloat)(deltaX * deltaX +
93 deltaY * deltaY));
94
95 m_rotationSpeed = magnitude / 10.0f;
96 if (fEq(m_rotationSpeed, 0.0f))
97 {
98 stopRotation();
99 }
100 else
101 {
102 m_modelViewer->setXRotate((TCFloat)deltaY);
103 m_modelViewer->setYRotate((TCFloat)deltaX);
104 }
105 m_modelViewer->setRotationSpeed(m_rotationSpeed);
106 m_modelViewer->requestRedraw();
107 }
108
updateHeadXY(TCULong modifierKeys,int xPos,int yPos)109 void LDInputHandler::updateHeadXY(TCULong modifierKeys, int xPos, int yPos)
110 {
111 TCFloat magnitude = (TCFloat)(xPos - m_clickX);
112 TCFloat denom = 5000.0f;
113 TCFloat fov = m_modelViewer->getFov();
114
115 denom /= (TCFloat)tan(deg2rad(fov));
116 if (modifierKeys & MKShift)
117 {
118 debugPrintf("Faster.\n");
119 denom /= 2.0f;
120 }
121 m_modelViewer->setCameraXRotate(magnitude / denom);
122 magnitude = (TCFloat)(yPos - m_clickY);
123 m_modelViewer->setCameraYRotate(magnitude / -denom);
124 m_modelViewer->requestRedraw();
125 }
126
updatePanXY(int xPos,int yPos)127 void LDInputHandler::updatePanXY(int xPos, int yPos)
128 {
129 if (m_viewMode == VMExamine)
130 {
131 int deltaX = xPos - m_lastX;
132 int deltaY = yPos - m_lastY;
133
134 m_modelViewer->panXY(deltaX, deltaY);
135 m_modelViewer->requestRedraw();
136 }
137 }
138
updateZoomY(int yPos)139 void LDInputHandler::updateZoomY(int yPos)
140 {
141 TCFloat magnitude = (TCFloat)(yPos - m_clickY);
142
143 m_modelViewer->setZoomSpeed(magnitude / 2.0f);
144 m_modelViewer->requestRedraw();
145 }
146
leftDown(TCULong modifierKeys,int xPos,int yPos)147 bool LDInputHandler::leftDown(TCULong modifierKeys, int xPos, int yPos)
148 {
149 if (modifierKeys & MKShift)
150 {
151 if (!m_modelViewer->getUseLighting() ||
152 m_modelViewer->getContrastingLightDirModel() == NULL)
153 {
154 // Allowing this will likely just lead to confusion.
155 return false;
156 }
157 m_mouseMode = MMLight;
158 m_modelViewer->setShowLightDir(true);
159 m_modelViewer->requestRedraw();
160 }
161 else if (modifierKeys & MKControl)
162 {
163 m_mouseMode = MMPan;
164 }
165 else
166 {
167 m_mouseMode = MMNormal;
168 updateSpinRateXY(xPos, yPos);
169 }
170 clearRotationStop();
171 return true;
172 }
173
mouseDown(TCULong modifierKeys,MouseButton button,int x,int y)174 bool LDInputHandler::mouseDown(
175 TCULong modifierKeys,
176 MouseButton button,
177 int x,
178 int y)
179 {
180 if (button < MBFirst || button > MBLast)
181 {
182 return false;
183 }
184 if (modifierKeys & MKAppleControl && button == MBLeft)
185 {
186 m_appleRightClick = true;
187 button = MBRight;
188 }
189 // Don't process chorded mouse clicks.
190 for (int i = 0; i < m_numButtons; i++)
191 {
192 if (i != button && m_buttonsDown[i])
193 {
194 return false;
195 }
196 }
197 m_buttonsDown[button] = true;
198 m_lastX = m_lastFrameX = m_clickX = x;
199 m_lastY = m_lastFrameY = m_clickY = y;
200 switch (button)
201 {
202 case MBLeft:
203 if (!leftDown(modifierKeys, x, y))
204 {
205 return false;
206 }
207 break;
208 case MBRight:
209 m_modelViewer->setClipZoom((modifierKeys & MKControl) != 0);
210 m_mouseMode = MMZoom;
211 break;
212 case MBMiddle:
213 m_mouseMode = MMPan;
214 break;
215 default:
216 return false;
217 }
218 TCAlertManager::sendAlert(captureAlertClass(), this);
219 return true;
220 }
221
mouseCaptureChanged(void)222 bool LDInputHandler::mouseCaptureChanged(void)
223 {
224 if (m_buttonsDown[MBLeft])
225 {
226 if (m_viewMode == VMFlyThrough || m_viewMode == VMWalk)
227 {
228 m_modelViewer->setCameraXRotate(0.0f);
229 m_modelViewer->setCameraYRotate(0.0f);
230 }
231 else
232 {
233 m_modelViewer->setXRotate(0.0f);
234 m_modelViewer->setYRotate(0.0f);
235 m_modelViewer->setRotationSpeed(0.0f);
236 }
237 m_modelViewer->setShowLightDir(false);
238 }
239 if (m_buttonsDown[MBRight])
240 {
241 m_modelViewer->setZoomSpeed(0.0f);
242 }
243 m_mouseMode = MMNone;
244 for (int i = 0; i < m_numButtons; i++)
245 {
246 m_buttonsDown[i] = false;
247 }
248 return true;
249 }
250
mouseUp(TCULong modifierKeys,MouseButton button,int x,int y)251 bool LDInputHandler::mouseUp(
252 TCULong modifierKeys,
253 MouseButton button,
254 int x,
255 int y)
256 {
257 if (button < MBFirst || button > MBLast)
258 {
259 return false;
260 }
261 if (button == MBLeft && m_appleRightClick)
262 {
263 m_appleRightClick = false;
264 button = MBRight;
265 }
266 if (!m_buttonsDown[button])
267 {
268 return false;
269 }
270 if (x != m_lastX || y != m_lastY)
271 {
272 mouseMove(modifierKeys, x, y);
273 }
274 switch (button)
275 {
276 case MBLeft:
277 if (m_viewMode == VMFlyThrough || m_viewMode == VMWalk)
278 {
279 m_modelViewer->setCameraXRotate(0.0f);
280 m_modelViewer->setCameraYRotate(0.0f);
281 }
282 else if (checkSpin())
283 {
284 m_rotationSpeed =
285 (TCFloat)sqrt((TCFloat)(m_lastXRotate * m_lastXRotate +
286 m_lastYRotate * m_lastYRotate)) / 10.0f;
287 m_modelViewer->setXRotate(m_lastXRotate);
288 m_modelViewer->setYRotate(m_lastYRotate);
289 m_modelViewer->setRotationSpeed(m_rotationSpeed);
290 }
291 m_modelViewer->setShowLightDir(false);
292 if (m_modelViewer->getExamineMode() == LDrawModelViewer::EMLatLong)
293 {
294 // In latitude/longitude mode, we don't want it to spin along both
295 // axes at once, because once the latitude gets to 90 or -90, it
296 // just stops.
297 if (fabs(m_modelViewer->getXRotate()) >
298 fabs(m_modelViewer->getYRotate()))
299 {
300 m_modelViewer->setYRotate(0.0f);
301 }
302 else if (fabs(m_modelViewer->getYRotate()) >
303 fabs(m_modelViewer->getXRotate()))
304 {
305 m_modelViewer->setXRotate(0.0f);
306 }
307 else if (fabs(m_modelViewer->getYRotate()) ==
308 fabs(m_modelViewer->getXRotate()) &&
309 m_modelViewer->getXRotate() != 0.0f)
310 {
311 m_modelViewer->setXRotate(0.0f);
312 }
313 }
314 break;
315 case MBRight:
316 m_modelViewer->setZoomSpeed(0.0f);
317 default:
318 break;
319 }
320 TCAlertManager::sendAlert(releaseAlertClass(), this);
321 m_modelViewer->requestRedraw();
322 m_buttonsDown[button] = false;
323 m_mouseMode = MMNone;
324 return true;
325 }
326
updateLightXY(int xPos,int yPos)327 void LDInputHandler::updateLightXY(int xPos, int yPos)
328 {
329 m_modelViewer->mouseMoveLight(xPos - m_lastX, yPos - m_lastY);
330 m_modelViewer->requestRedraw();
331 }
332
updateXY(TCULong modifierKeys,int xPos,int yPos)333 void LDInputHandler::updateXY(TCULong modifierKeys, int xPos, int yPos)
334 {
335 if (m_viewMode == VMExamine)
336 {
337 //m_lastMoveTime = getTimeRef();
338 updateSpinRateXY(xPos, yPos);
339 }
340 else
341 {
342 updateHeadXY(modifierKeys, xPos, yPos);
343 }
344 }
345
mouseMove(TCULong modifierKeys,int x,int y)346 bool LDInputHandler::mouseMove(TCULong modifierKeys, int x, int y)
347 {
348 bool retValue = true;
349
350 switch (m_mouseMode)
351 {
352 case MMNormal:
353 updateXY(modifierKeys, x, y);
354 break;
355 case MMZoom:
356 updateZoomY(y);
357 break;
358 case MMPan:
359 updatePanXY(x, y);
360 break;
361 case MMLight:
362 updateLightXY(x, y);
363 break;
364 default:
365 retValue = false;
366 break;
367 }
368 m_lastX = x;
369 m_lastY = y;
370 return retValue;
371 }
372
mouseWheel(TCULong modifierKeys,TCFloat amount)373 bool LDInputHandler::mouseWheel(TCULong modifierKeys, TCFloat amount)
374 {
375 // Don't process while while any mouse buttons are pressed.
376 for (int i = 0; i < m_numButtons; i++)
377 {
378 if (m_buttonsDown[i])
379 {
380 return false;
381 }
382 }
383 m_modelViewer->setClipZoom((modifierKeys & MKControl) != 0);
384 m_modelViewer->zoom((TCFloat)amount * -0.5f);
385 m_modelViewer->requestRedraw();
386 return true;
387 }
388
setMouseUpPending(bool value)389 void LDInputHandler::setMouseUpPending(bool value)
390 {
391 m_mouseUpPending = value;
392 m_mouseUpHandled = true;
393 }
394
frameDone(TCAlert * alert)395 void LDInputHandler::frameDone(TCAlert *alert)
396 {
397 if (m_mouseMode == MMNormal && m_viewMode == VMExamine &&
398 alert->getSender() == m_modelViewer)
399 {
400 // We're spinning, and a frame just completed drawing, so
401 // check to see if we should stop the spinning.
402 m_mouseUpHandled = false;
403 TCAlertManager::sendAlert(peekMouseUpAlertClass(), this);
404 if (!m_mouseUpHandled ||
405 (m_mouseUpHandled && m_mouseUpPending))
406 {
407 updateSpinRateXY(m_lastX, m_lastY);
408 }
409 m_lastFrameX = m_lastX;
410 m_lastFrameY = m_lastY;
411 }
412 }
413
updateCameraMotion(TCVector & cameraMotion,TCFloat motionAmount,TCFloat strafeAmount)414 void LDInputHandler::updateCameraMotion(
415 TCVector &cameraMotion,
416 TCFloat motionAmount,
417 TCFloat strafeAmount)
418 {
419 for (int i = 0; i < 2; i++)
420 {
421 if (cameraMotion[i] > 0.0f)
422 {
423 cameraMotion[i] = strafeAmount;
424 }
425 else if (cameraMotion[i] < 0.0f)
426 {
427 cameraMotion[i] = -strafeAmount;
428 }
429 }
430 if (cameraMotion[2] > 0.0f)
431 {
432 cameraMotion[2] = motionAmount;
433 }
434 else if (cameraMotion[2] < 0.0f)
435 {
436 cameraMotion[2] = -motionAmount;
437 }
438 }
439
updateCameraRotation(TCFloat rotationAmount,TCFloat rollAmount)440 void LDInputHandler::updateCameraRotation(
441 TCFloat rotationAmount,
442 TCFloat rollAmount)
443 {
444 TCFloat value = m_modelViewer->getCameraXRotate();
445
446 if (value > 0)
447 {
448 m_modelViewer->setCameraXRotate(rotationAmount);
449 }
450 else if (value < 0)
451 {
452 m_modelViewer->setCameraXRotate(-rotationAmount);
453 }
454 value = m_modelViewer->getCameraYRotate();
455 if (value > 0)
456 {
457 m_modelViewer->setCameraYRotate(rotationAmount);
458 }
459 else if (value < 0)
460 {
461 m_modelViewer->setCameraYRotate(-rotationAmount);
462 }
463 value = m_modelViewer->getCameraZRotate();
464 if (value > 0)
465 {
466 m_modelViewer->setCameraZRotate(rollAmount);
467 }
468 else if (value < 0)
469 {
470 m_modelViewer->setCameraZRotate(-rollAmount);
471 }
472 }
473
keyDown(TCULong modifierKeys,KeyCode keyCode)474 bool LDInputHandler::keyDown(TCULong modifierKeys, KeyCode keyCode)
475 {
476 if (m_viewMode == VMExamine)
477 {
478 TCFloat rotationSpeed = sm_keyRotationSpeed;
479
480 if (modifierKeys & MKShift)
481 {
482 rotationSpeed *= 2.0f;
483 }
484 switch (keyCode)
485 {
486 case KCUp:
487 m_modelViewer->setXRotate(-1.0f);
488 m_rotationSpeed = rotationSpeed;
489 break;
490 case KCDown:
491 m_modelViewer->setXRotate(1.0f);
492 m_rotationSpeed = rotationSpeed;
493 break;
494 case KCLeft:
495 m_modelViewer->setYRotate(-1.0f);
496 m_rotationSpeed = rotationSpeed;
497 break;
498 case KCRight:
499 m_modelViewer->setYRotate(1.0f);
500 m_rotationSpeed = rotationSpeed;
501 break;
502 case KCShift:
503 if (fEq(m_modelViewer->getRotationSpeed(), 0.0f))
504 {
505 return true;
506 }
507 m_rotationSpeed = rotationSpeed;
508 break;
509 case KCSpace:
510 stopRotation();
511 break;
512 default:
513 return false;
514 }
515 m_modelViewer->setRotationSpeed(m_rotationSpeed);
516 m_modelViewer->requestRedraw();
517 return true;
518 }
519 else if (m_viewMode == VMFlyThrough || m_viewMode == VMWalk)
520 {
521 TCVector cameraMotion = m_modelViewer->getCameraMotion();
522 TCFloat fov = m_modelViewer->getFov();
523 TCFloat motionAmount = m_modelViewer->getDefaultDistance() / 400.0f;
524 TCFloat rotationAmount = 0.01f * (TCFloat)tan(deg2rad(fov));
525 TCFloat rollAmount = 0.01f;
526 TCFloat strafeAmount = 1.0f * (TCFloat)sqrt(fov / 45.0f);
527
528 if (modifierKeys & MKShift)
529 {
530 motionAmount *= 2.0f;
531 strafeAmount *= 2.0f;
532 rotationAmount *= 2.0f;
533 rollAmount *= 2.0f;
534 }
535 switch (keyCode)
536 {
537 case KCW:
538 cameraMotion[2] = -motionAmount;
539 break;
540 case KCS:
541 cameraMotion[2] = motionAmount;
542 break;
543 case KCA:
544 cameraMotion[0] = -strafeAmount;
545 break;
546 case KCD:
547 cameraMotion[0] = strafeAmount;
548 break;
549 case KCR:
550 cameraMotion[1] = strafeAmount;
551 break;
552 case KCF:
553 cameraMotion[1] = -strafeAmount;
554 break;
555 case KCE:
556 m_modelViewer->setCameraZRotate(rollAmount);
557 break;
558 case KCQ:
559 m_modelViewer->setCameraZRotate(-rollAmount);
560 break;
561 case KCUp:
562 m_modelViewer->setCameraYRotate(rotationAmount);
563 break;
564 case KCDown:
565 m_modelViewer->setCameraYRotate(-rotationAmount);
566 break;
567 case KCLeft:
568 m_modelViewer->setCameraXRotate(-rotationAmount);
569 break;
570 case KCRight:
571 m_modelViewer->setCameraXRotate(rotationAmount);
572 break;
573 case KCShift:
574 updateCameraMotion(cameraMotion, motionAmount, strafeAmount);
575 updateCameraRotation(rotationAmount, rollAmount);
576 break;
577 default:
578 return false;
579 break;
580 }
581 m_modelViewer->setCameraMotion(cameraMotion);
582 m_modelViewer->requestRedraw();
583 //forceRedraw(2);
584 return true;
585 }
586 return false;
587 }
588
keyUp(TCULong,KeyCode keyCode)589 bool LDInputHandler::keyUp(TCULong /*modifierKeys*/, KeyCode keyCode)
590 {
591 if (m_viewMode == VMExamine)
592 {
593 switch (keyCode)
594 {
595 case KCUp:
596 case KCDown:
597 m_modelViewer->setXRotate(0.0f);
598 break;
599 case KCLeft:
600 case KCRight:
601 m_modelViewer->setYRotate(0.0f);
602 break;
603 case KCShift:
604 m_rotationSpeed = sm_keyRotationSpeed;
605 break;
606 default:
607 return false;
608 }
609 if (m_modelViewer->getXRotate() == 0.0f &&
610 m_modelViewer->getYRotate() == 0.0f)
611 {
612 m_rotationSpeed = 0.0f;
613 }
614 m_modelViewer->setRotationSpeed(m_rotationSpeed);
615 m_modelViewer->requestRedraw();
616 return true;
617 }
618 else if (m_viewMode == VMFlyThrough || m_viewMode == VMWalk)
619 {
620 TCVector cameraMotion = m_modelViewer->getCameraMotion();
621
622 switch (keyCode)
623 {
624 case KCW:
625 cameraMotion[2] = 0.0f;
626 break;
627 case KCS:
628 cameraMotion[2] = 0.0f;
629 break;
630 case KCA:
631 cameraMotion[0] = 0.0f;
632 break;
633 case KCD:
634 cameraMotion[0] = 0.0f;
635 break;
636 case KCR:
637 cameraMotion[1] = 0.0f;
638 break;
639 case KCF:
640 cameraMotion[1] = 0.0f;
641 break;
642 case KCE:
643 m_modelViewer->setCameraZRotate(0.0f);
644 break;
645 case KCQ:
646 m_modelViewer->setCameraZRotate(0.0f);
647 break;
648 case KCUp:
649 m_modelViewer->setCameraYRotate(0.0f);
650 break;
651 case KCDown:
652 m_modelViewer->setCameraYRotate(0.0f);
653 break;
654 case KCLeft:
655 m_modelViewer->setCameraXRotate(0.0f);
656 break;
657 case KCRight:
658 m_modelViewer->setCameraXRotate(0.0f);
659 break;
660 case KCShift:
661 {
662 TCFloat fov = m_modelViewer->getFov();
663 TCFloat motionAmount = m_modelViewer->getDefaultDistance() /
664 400.0f;
665 TCFloat rotationAmount = 0.01f * (TCFloat)tan(deg2rad(fov));
666 TCFloat strafeAmount = 1.0f * (TCFloat)sqrt(fov / 45.0f);
667
668 updateCameraMotion(cameraMotion, motionAmount, strafeAmount);
669 updateCameraRotation(rotationAmount, 0.01f);
670 }
671 break;
672 default:
673 return 1;
674 break;
675 }
676 m_modelViewer->setCameraMotion(cameraMotion);
677 m_modelViewer->requestRedraw();
678 //forceRedraw(2);
679 return 0;
680 }
681 return false;
682 }
683
getAlertSender(void)684 TCObject *LDInputHandler::getAlertSender(void)
685 {
686 return m_modelViewer;
687 }
688
recordRotationStop(void)689 void LDInputHandler::recordRotationStop(void)
690 {
691 if (!fEq(m_modelViewer->getXRotate(), 0.0f) ||
692 !fEq(m_modelViewer->getYRotate(), 0.0f))
693 {
694 m_lastXRotate = m_modelViewer->getXRotate();
695 m_lastYRotate = m_modelViewer->getYRotate();
696 #ifdef WIN32
697 m_stopTicks = GetTickCount();
698 m_haveStopTicks = true;
699 #endif // WIN32
700 #ifdef COCOA
701 [STOP_TIME release];
702 STOP_TIME = [[NSDate alloc] init];
703 #endif // COCOA
704 }
705 }
706
clearRotationStop(void)707 void LDInputHandler::clearRotationStop(void)
708 {
709 #ifdef WIN32
710 m_haveStopTicks = false;
711 #endif // WIN32
712 #ifdef COCOA
713 [STOP_TIME release];
714 STOP_TIME = nil;
715 #endif // COCOA
716 }
717
checkSpin(void)718 bool LDInputHandler::checkSpin(void)
719 {
720 bool retValue = false;
721 #ifdef WIN32
722 if (m_haveStopTicks)
723 {
724 retValue = GetTickCount() - m_stopTicks < 50;
725 m_haveStopTicks = false;
726 }
727 #endif // WIN32
728 #ifdef COCOA
729 retValue = STOP_TIME != nil && [STOP_TIME timeIntervalSinceNow] > -0.1f;
730 [STOP_TIME release];
731 STOP_TIME = nil;
732 #endif // COCOA
733 return retValue;
734 }
735