]> git.mxchange.org Git - flightgear.git/blob - src/Main/FGManipulator.cxx
osgviewer mouse warp fixes
[flightgear.git] / src / Main / FGManipulator.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4 #include <osg/Math>
5 #include <osgViewer/Viewer>
6 #include <plib/pu.h>
7 #include "FGManipulator.hxx"
8
9 // The manipulator is responsible for updating a Viewer's camera. It's
10 // event handling method is also a convenient place to run the the FG
11 // idle and draw handlers.
12
13 FGManipulator::FGManipulator() :
14     idleHandler(0), drawHandler(0), windowResizeHandler(0), keyHandler(0),
15     mouseClickHandler(0), mouseMotionHandler(0), currentModifiers(0),
16     osgModifiers(0), resizable(true), mouseWarped(false)
17 {
18     using namespace osgGA;
19     
20     keyMaskMap[GUIEventAdapter::KEY_Shift_L]
21         = GUIEventAdapter::MODKEY_LEFT_SHIFT;
22     keyMaskMap[GUIEventAdapter::KEY_Shift_R]
23         = GUIEventAdapter::MODKEY_RIGHT_SHIFT;
24     keyMaskMap[GUIEventAdapter::KEY_Control_L]
25         = GUIEventAdapter::MODKEY_LEFT_CTRL;
26     keyMaskMap[GUIEventAdapter::KEY_Control_R]
27         = GUIEventAdapter::MODKEY_RIGHT_CTRL;
28     keyMaskMap[GUIEventAdapter::KEY_Alt_L] = GUIEventAdapter::MODKEY_LEFT_ALT;
29     keyMaskMap[GUIEventAdapter::KEY_Alt_R] = GUIEventAdapter::MODKEY_RIGHT_ALT;
30     // We have to implement numlock too.
31     numlockKeyMap[GUIEventAdapter::KEY_KP_Insert]  = '0';
32     numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
33     numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
34     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
35     numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
36     numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
37     numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
38     numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
39     numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
40     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
41 }
42
43 void FGManipulator::setByMatrix(const osg::Matrixd& matrix)
44 {
45     // Yuck
46     position = matrix.getTrans();
47     attitude = matrix.getRotate();
48 }
49
50 osg::Matrixd FGManipulator::getMatrix() const
51 {
52     return osg::Matrixd::rotate(attitude) * osg::Matrixd::translate(position);
53 }
54
55 osg::Matrixd FGManipulator::getInverseMatrix() const
56 {
57     return (osg::Matrixd::translate(-position)
58             * osg::Matrixd::rotate(attitude.inverse())) ;
59 }
60
61 // Not used, but part of the interface.
62 void FGManipulator::setNode(osg::Node* node)
63 {
64     _node = node;
65 }
66     
67 const osg::Node* FGManipulator::getNode() const
68 {
69     return _node.get();
70 }
71
72 osg::Node* FGManipulator::getNode()
73 {
74     return _node.get();
75 }
76
77 // All the usual translation from window system to FG / plib
78 static int osgToFGModifiers(int modifiers)
79 {
80     int result = 0;
81     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT |
82                      osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT))
83         result |= KEYMOD_SHIFT;
84     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL |
85                      osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
86         result |= KEYMOD_CTRL;
87     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_ALT |
88                      osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT))
89         result |= KEYMOD_ALT;
90     return result;
91 }
92
93 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
94                          osgGA::GUIActionAdapter& us)
95 {
96     currentModifiers = osgToFGModifiers(ea.getModKeyMask());
97     (void)handle(ea, us);
98 }
99
100 static bool
101 eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
102                 int& x, int& y)
103 {
104   x = -1;
105   y = -1;
106
107   const osgViewer::Viewer* viewer;
108   viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
109   if (!viewer)
110       return false;
111
112   float lx, ly;
113   const osg::Camera* camera;
114   camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
115
116   if (!fgOSIsMainCamera(camera))
117       return false;
118
119   x = int(lx);
120   y = int(camera->getViewport()->height() - ly);
121
122   return true;
123 }
124
125 bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
126                            osgGA::GUIActionAdapter& us)
127 {
128     int x, y;
129     switch (ea.getEventType()) {
130     case osgGA::GUIEventAdapter::FRAME:
131         if (idleHandler)
132             (*idleHandler)();
133         if (drawHandler)
134             (*drawHandler)();
135         mouseWarped = false;
136         return true;
137     case osgGA::GUIEventAdapter::KEYDOWN:
138     case osgGA::GUIEventAdapter::KEYUP:
139     {
140         int key, modmask;
141         handleKey(ea, key, modmask);
142         eventToViewport(ea, us, x, y);
143         if (keyHandler)
144             (*keyHandler)(key, modmask, x, y);
145         return true;
146     }
147     case osgGA::GUIEventAdapter::PUSH:
148     case osgGA::GUIEventAdapter::RELEASE:
149     {
150         bool mainWindow = eventToViewport(ea, us, x, y);
151         int button = 0;
152         switch (ea.getButton()) {
153         case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
154             button = 0;
155             break;
156         case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
157             button = 1;
158             break;
159         case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
160             button = 2;
161             break;
162         }
163         if (mouseClickHandler)
164             (*mouseClickHandler)(button,
165                                  (ea.getEventType()
166                                   == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
167         return true;
168     }
169     case osgGA::GUIEventAdapter::MOVE:
170     case osgGA::GUIEventAdapter::DRAG:
171         // If we warped the mouse, then disregard all pointer motion
172         // events for this frame. We really want to flush the event
173         // queue of mouse events, but don't have the ability to do
174         // that with osgViewer.
175         if (mouseWarped)
176             return true;
177         eventToViewport(ea, us, x, y);
178         if (mouseMotionHandler)
179             (*mouseMotionHandler)(x, y);
180         return true;
181     case osgGA::GUIEventAdapter::RESIZE:
182         if (resizable && windowResizeHandler)
183             (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
184         return true;
185      case osgGA::GUIEventAdapter::CLOSE_WINDOW:
186     case osgGA::GUIEventAdapter::QUIT_APPLICATION:
187         fgOSExit(0);
188         return true;
189     default:
190         return false;
191     }
192 }
193
194 void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
195                               int& modifiers)
196 {
197     key = ea.getKey();
198     // XXX Probably other translations are needed too.
199     switch (key) {
200     case osgGA::GUIEventAdapter::KEY_Escape: key = 0x1b; break;
201     case osgGA::GUIEventAdapter::KEY_Return: key = '\n'; break;
202     case osgGA::GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
203     case osgGA::GUIEventAdapter::KEY_Delete:   key = 0x7f; break;
204     case osgGA::GUIEventAdapter::KEY_Tab:      key = '\t'; break;
205     case osgGA::GUIEventAdapter::KEY_Left:     key = PU_KEY_LEFT;      break;
206     case osgGA::GUIEventAdapter::KEY_Up:       key = PU_KEY_UP;        break;
207     case osgGA::GUIEventAdapter::KEY_Right:    key = PU_KEY_RIGHT;     break;
208     case osgGA::GUIEventAdapter::KEY_Down:     key = PU_KEY_DOWN;      break;
209     case osgGA::GUIEventAdapter::KEY_Page_Up:   key = PU_KEY_PAGE_UP;   break;
210     case osgGA::GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
211     case osgGA::GUIEventAdapter::KEY_Home:     key = PU_KEY_HOME;      break;
212     case osgGA::GUIEventAdapter::KEY_End:      key = PU_KEY_END;       break;
213     case osgGA::GUIEventAdapter::KEY_Insert:   key = PU_KEY_INSERT;    break;
214     case osgGA::GUIEventAdapter::KEY_F1:       key = PU_KEY_F1;        break;
215     case osgGA::GUIEventAdapter::KEY_F2:       key = PU_KEY_F2;        break;
216     case osgGA::GUIEventAdapter::KEY_F3:       key = PU_KEY_F3;        break;
217     case osgGA::GUIEventAdapter::KEY_F4:       key = PU_KEY_F4;        break;
218     case osgGA::GUIEventAdapter::KEY_F5:       key = PU_KEY_F5;        break;
219     case osgGA::GUIEventAdapter::KEY_F6:       key = PU_KEY_F6;        break;
220     case osgGA::GUIEventAdapter::KEY_F7:       key = PU_KEY_F7;        break;
221     case osgGA::GUIEventAdapter::KEY_F8:       key = PU_KEY_F8;        break;
222     case osgGA::GUIEventAdapter::KEY_F9:       key = PU_KEY_F9;        break;
223     case osgGA::GUIEventAdapter::KEY_F10:      key = PU_KEY_F10;       break;
224     case osgGA::GUIEventAdapter::KEY_F11:      key = PU_KEY_F11;       break;
225     case osgGA::GUIEventAdapter::KEY_F12:      key = PU_KEY_F12;       break;
226     case osgGA::GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
227     case osgGA::GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
228     case osgGA::GUIEventAdapter::KEY_KP_Add:   key = '+'; break;
229     case osgGA::GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
230     case osgGA::GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
231     case osgGA::GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
232     }
233     osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
234     std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
235
236     if (numPadIter != numlockKeyMap.end()) {
237         if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
238             key = numPadIter->second;
239         }
240     } else {
241         // Track the modifiers because OSG is currently (2.0) broken
242         KeyMaskMap::iterator iter = keyMaskMap.find(key);
243         if (iter != keyMaskMap.end()) {
244             int mask = iter->second;
245             if (eventType == osgGA::GUIEventAdapter::KEYUP)
246                 osgModifiers &= ~mask;
247             else
248                 osgModifiers |= mask;
249         }
250     }
251     modifiers = osgToFGModifiers(osgModifiers);
252     currentModifiers = modifiers;
253     if (eventType == osgGA::GUIEventAdapter::KEYUP)
254         modifiers |= KEYMOD_RELEASED;
255 }
256