]> git.mxchange.org Git - flightgear.git/blob - src/Main/FGManipulator.cxx
- let the OSG on-screen-statistics function no longer be hard-coded
[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 <Main/fg_props.hxx>
8 #include "FGManipulator.hxx"
9
10 #if !defined(X_DISPLAY_MISSING)
11 #define X_DOUBLE_SCROLL_BUG 1
12 #endif
13
14 const int displayStatsKey = 1;
15 const int printStatsKey = 2;
16
17
18 // The manipulator is responsible for updating a Viewer's camera. It's
19 // event handling method is also a convenient place to run the the FG
20 // idle and draw handlers.
21
22 FGManipulator::FGManipulator() :
23     idleHandler(0), drawHandler(0), windowResizeHandler(0), keyHandler(0),
24     mouseClickHandler(0), mouseMotionHandler(0),
25     statsHandler(new osgViewer::StatsHandler), statsEvent(new osgGA::GUIEventAdapter),
26     currentModifiers(0), osgModifiers(0), resizable(true), mouseWarped(false),
27     scrollButtonPressed(false), useEventModifiers(false)
28 {
29     using namespace osgGA;
30     statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey);
31     statsHandler->setKeyEventPrintsOutStats(printStatsKey);
32     statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
33
34     keyMaskMap[GUIEventAdapter::KEY_Shift_L]
35         = GUIEventAdapter::MODKEY_LEFT_SHIFT;
36     keyMaskMap[GUIEventAdapter::KEY_Shift_R]
37         = GUIEventAdapter::MODKEY_RIGHT_SHIFT;
38     keyMaskMap[GUIEventAdapter::KEY_Control_L]
39         = GUIEventAdapter::MODKEY_LEFT_CTRL;
40     keyMaskMap[GUIEventAdapter::KEY_Control_R]
41         = GUIEventAdapter::MODKEY_RIGHT_CTRL;
42     keyMaskMap[GUIEventAdapter::KEY_Alt_L] = GUIEventAdapter::MODKEY_LEFT_ALT;
43     keyMaskMap[GUIEventAdapter::KEY_Alt_R] = GUIEventAdapter::MODKEY_RIGHT_ALT;
44     keyMaskMap[GUIEventAdapter::KEY_Meta_L] = GUIEventAdapter::MODKEY_LEFT_META;
45     keyMaskMap[GUIEventAdapter::KEY_Meta_R] = GUIEventAdapter::MODKEY_RIGHT_META;
46     keyMaskMap[GUIEventAdapter::KEY_Super_L] = GUIEventAdapter::MODKEY_LEFT_META;
47     keyMaskMap[GUIEventAdapter::KEY_Super_R] = GUIEventAdapter::MODKEY_RIGHT_META;
48     // We have to implement numlock too.
49     numlockKeyMap[GUIEventAdapter::KEY_KP_Insert]  = '0';
50     numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
51     numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
52     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
53     numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
54     numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
55     numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
56     numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
57     numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
58     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
59
60     for (int i = 0; i < 128; i++)
61         release_keys[i] = i;
62 }
63
64 void FGManipulator::setByMatrix(const osg::Matrixd& matrix)
65 {
66     // Yuck
67     position = matrix.getTrans();
68     attitude = matrix.getRotate();
69 }
70
71 osg::Matrixd FGManipulator::getMatrix() const
72 {
73     return osg::Matrixd::rotate(attitude) * osg::Matrixd::translate(position);
74 }
75
76 osg::Matrixd FGManipulator::getInverseMatrix() const
77 {
78     return (osg::Matrixd::translate(-position)
79             * osg::Matrixd::rotate(attitude.inverse())) ;
80 }
81
82 // Not used, but part of the interface.
83 void FGManipulator::setNode(osg::Node* node)
84 {
85     _node = node;
86 }
87     
88 const osg::Node* FGManipulator::getNode() const
89 {
90     return _node.get();
91 }
92
93 osg::Node* FGManipulator::getNode()
94 {
95     return _node.get();
96 }
97
98 // All the usual translation from window system to FG / plib
99 static int osgToFGModifiers(int modifiers)
100 {
101     int result = 0;
102     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT |
103                      osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT))
104         result |= KEYMOD_SHIFT;
105     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL |
106                      osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
107         result |= KEYMOD_CTRL;
108     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_ALT |
109                      osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT))
110         result |= KEYMOD_ALT;
111     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_META |
112                      osgGA::GUIEventAdapter::MODKEY_RIGHT_META))
113         result |= KEYMOD_META;
114     return result;
115 }
116
117 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
118                          osgGA::GUIActionAdapter& us)
119 {
120     currentModifiers = osgToFGModifiers(ea.getModKeyMask());
121     (void)handle(ea, us);
122 }
123
124 static bool
125 eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
126                 int& x, int& y)
127 {
128   x = -1;
129   y = -1;
130
131   const osgViewer::Viewer* viewer;
132   viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
133   if (!viewer)
134       return false;
135
136   float lx, ly;
137   const osg::Camera* camera;
138   camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
139
140   if (!(camera && fgOSIsMainCamera(camera)))
141       return false;
142
143   x = int(lx);
144   y = int(camera->getViewport()->height() - ly);
145
146   return true;
147 }
148
149 bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
150                            osgGA::GUIActionAdapter& us)
151 {
152     int x = 0;
153     int y = 0;
154     handleStats(us);
155
156     switch (ea.getEventType()) {
157     case osgGA::GUIEventAdapter::FRAME:
158         if (idleHandler)
159             (*idleHandler)();
160         if (drawHandler)
161             (*drawHandler)();
162         mouseWarped = false;
163         return true;
164     case osgGA::GUIEventAdapter::KEYDOWN:
165     case osgGA::GUIEventAdapter::KEYUP:
166     {
167         int key, modmask;
168         handleKey(ea, key, modmask);
169         eventToViewport(ea, us, x, y);
170         if (keyHandler)
171             (*keyHandler)(key, modmask, x, y);
172         return true;
173     }
174     case osgGA::GUIEventAdapter::PUSH:
175     case osgGA::GUIEventAdapter::RELEASE:
176     {
177         bool mainWindow = eventToViewport(ea, us, x, y);
178         int button = 0;
179         switch (ea.getButton()) {
180         case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
181             button = 0;
182             break;
183         case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
184             button = 1;
185             break;
186         case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
187             button = 2;
188             break;
189         }
190         if (mouseClickHandler)
191             (*mouseClickHandler)(button,
192                                  (ea.getEventType()
193                                   == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
194         return true;
195     }
196     case osgGA::GUIEventAdapter::SCROLL:
197     {
198         bool mainWindow = eventToViewport(ea, us, x, y);
199 #ifdef X_DOUBLE_SCROLL_BUG
200         scrollButtonPressed = !scrollButtonPressed;
201         if (!scrollButtonPressed) // Drop the button release event
202             return true;
203 #endif
204         int button;
205         if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
206             button = 3;
207         else
208             button = 4;
209         if (mouseClickHandler) {
210             (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
211             (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
212         }
213         return true;
214     }
215     case osgGA::GUIEventAdapter::MOVE:
216     case osgGA::GUIEventAdapter::DRAG:
217         // If we warped the mouse, then disregard all pointer motion
218         // events for this frame. We really want to flush the event
219         // queue of mouse events, but don't have the ability to do
220         // that with osgViewer.
221         if (mouseWarped)
222             return true;
223         if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
224             (*mouseMotionHandler)(x, y);
225         return true;
226     case osgGA::GUIEventAdapter::RESIZE:
227         if (resizable && windowResizeHandler)
228             (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
229         return true;
230      case osgGA::GUIEventAdapter::CLOSE_WINDOW:
231     case osgGA::GUIEventAdapter::QUIT_APPLICATION:
232         fgOSExit(0);
233         return true;
234     default:
235         return false;
236     }
237 }
238
239 void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
240                               int& modifiers)
241 {
242     key = ea.getKey();
243     // XXX Probably other translations are needed too.
244     switch (key) {
245     case osgGA::GUIEventAdapter::KEY_Escape: key = 0x1b; break;
246     case osgGA::GUIEventAdapter::KEY_Return: key = '\n'; break;
247     case osgGA::GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
248     case osgGA::GUIEventAdapter::KEY_Delete:   key = 0x7f; break;
249     case osgGA::GUIEventAdapter::KEY_Tab:      key = '\t'; break;
250     case osgGA::GUIEventAdapter::KEY_Left:     key = PU_KEY_LEFT;      break;
251     case osgGA::GUIEventAdapter::KEY_Up:       key = PU_KEY_UP;        break;
252     case osgGA::GUIEventAdapter::KEY_Right:    key = PU_KEY_RIGHT;     break;
253     case osgGA::GUIEventAdapter::KEY_Down:     key = PU_KEY_DOWN;      break;
254     case osgGA::GUIEventAdapter::KEY_Page_Up:   key = PU_KEY_PAGE_UP;   break;
255     case osgGA::GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
256     case osgGA::GUIEventAdapter::KEY_Home:     key = PU_KEY_HOME;      break;
257     case osgGA::GUIEventAdapter::KEY_End:      key = PU_KEY_END;       break;
258     case osgGA::GUIEventAdapter::KEY_Insert:   key = PU_KEY_INSERT;    break;
259     case osgGA::GUIEventAdapter::KEY_F1:       key = PU_KEY_F1;        break;
260     case osgGA::GUIEventAdapter::KEY_F2:       key = PU_KEY_F2;        break;
261     case osgGA::GUIEventAdapter::KEY_F3:       key = PU_KEY_F3;        break;
262     case osgGA::GUIEventAdapter::KEY_F4:       key = PU_KEY_F4;        break;
263     case osgGA::GUIEventAdapter::KEY_F5:       key = PU_KEY_F5;        break;
264     case osgGA::GUIEventAdapter::KEY_F6:       key = PU_KEY_F6;        break;
265     case osgGA::GUIEventAdapter::KEY_F7:       key = PU_KEY_F7;        break;
266     case osgGA::GUIEventAdapter::KEY_F8:       key = PU_KEY_F8;        break;
267     case osgGA::GUIEventAdapter::KEY_F9:       key = PU_KEY_F9;        break;
268     case osgGA::GUIEventAdapter::KEY_F10:      key = PU_KEY_F10;       break;
269     case osgGA::GUIEventAdapter::KEY_F11:      key = PU_KEY_F11;       break;
270     case osgGA::GUIEventAdapter::KEY_F12:      key = PU_KEY_F12;       break;
271     case osgGA::GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
272     case osgGA::GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
273     case osgGA::GUIEventAdapter::KEY_KP_Add:   key = '+'; break;
274     case osgGA::GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
275     case osgGA::GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
276     case osgGA::GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
277     }
278     osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
279     std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
280
281     if (numPadIter != numlockKeyMap.end()) {
282         if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
283             key = numPadIter->second;
284         }
285     } else if (useEventModifiers) {
286         
287     }else {
288         // Track the modifiers because OSG is currently (2.0) broken
289         KeyMaskMap::iterator iter = keyMaskMap.find(key);
290         if (iter != keyMaskMap.end()) {
291             int mask = iter->second;
292             if (eventType == osgGA::GUIEventAdapter::KEYUP)
293                 osgModifiers &= ~mask;
294             else
295                 osgModifiers |= mask;
296         }
297     }
298     modifiers = osgToFGModifiers(osgModifiers);
299     currentModifiers = modifiers;
300     if (eventType == osgGA::GUIEventAdapter::KEYUP)
301         modifiers |= KEYMOD_RELEASED;
302
303     // Release the letter key, for which the keypress was reported
304     if (key >= 0 && key < 128) {
305         if (modifiers & KEYMOD_RELEASED) {
306             key = release_keys[key];
307         } else {
308             release_keys[key] = key;
309             if (key >= 1 && key <= 26) {
310                 release_keys[key + '@'] = key;
311                 release_keys[key + '`'] = key;
312             } else if (key >= 'A' && key <= 'Z') {
313                 release_keys[key - '@'] = key;
314                 release_keys[tolower(key)] = key;
315             } else if (key >= 'a' && key <= 'z') {
316                 release_keys[key - '`'] = key;
317                 release_keys[toupper(key)] = key;
318             }
319         }
320     }
321 }
322
323 void FGManipulator::handleStats(osgGA::GUIActionAdapter& us)
324 {
325     static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true);
326     static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true);
327
328     if (display->getBoolValue()) {
329         statsEvent->setKey(displayStatsKey);
330         statsHandler->handle(*statsEvent, us);
331         display->setBoolValue(false);
332     }
333
334     if (print->getBoolValue()) {
335         statsEvent->setKey(printStatsKey);
336         statsHandler->handle(*statsEvent, us);
337         print->setBoolValue(false);
338     }
339 }
340