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