]> git.mxchange.org Git - flightgear.git/blob - src/Model/panelnode.cxx
Remove unnecessary includes/using
[flightgear.git] / src / Model / panelnode.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4
5 #include "panelnode.hxx"
6
7 #include <vector>
8 #include <algorithm>
9
10 #include <osg/Geode>
11 #include <osg/Switch>
12 #include <osg/BlendFunc>
13
14 #include <simgear/compiler.h>
15 #include <simgear/structure/exception.hxx>
16 #include <simgear/debug/logstream.hxx>
17
18 #include <simgear/scene/util/OsgMath.hxx>
19 #include <simgear/scene/util/SGPickCallback.hxx>
20 #include <simgear/scene/util/SGSceneUserData.hxx>
21 #include <simgear/scene/util/SGNodeMasks.hxx>
22
23 #include <plib/pu.h>
24
25 #include <Main/fg_os.hxx>
26 #include <Cockpit/panel.hxx>
27 #include <Cockpit/panel_io.hxx>
28 #include "Viewer/viewer.hxx"
29 #include "Viewer/viewmgr.hxx"
30
31 using std::vector;
32
33 class PanelTransformListener : public SGPropertyChangeListener
34 {
35 public:
36     PanelTransformListener(FGPanelNode* pn) : _panelNode(pn) {}
37     
38     virtual void valueChanged (SGPropertyNode * node)
39     {
40         _panelNode->dirtyBound();
41     }
42 private:
43     FGPanelNode* _panelNode;
44 };
45
46 static FGPanelNode* global_panel = NULL;
47
48 /**
49  * Built-in command: pass a mouse click to the panel.
50  *
51  * button: the mouse button number, zero-based.
52  * is-down: true if the button is down, false if it is up.
53  * x-pos: the x position of the mouse click.
54  * y-pos: the y position of the mouse click.
55  */
56 static bool
57 do_panel_mouse_click (const SGPropertyNode * arg)
58 {
59   if (global_panel)
60     return global_panel->getPanel()
61     ->doMouseAction(arg->getIntValue("button"),
62                     arg->getBoolValue("is-down") ? PU_DOWN : PU_UP,
63                     arg->getIntValue("x-pos"),
64                     arg->getIntValue("y-pos"));
65   else
66     return false;
67   
68   return false;
69 }
70
71 class FGPanelPickCallback : public SGPickCallback {
72 public:
73   FGPanelPickCallback(FGPanelNode* p) :
74     panel(p)
75   {}
76   
77   virtual bool buttonPressed( int b,
78                               const osgGA::GUIEventAdapter&,
79                               const Info& info )
80   {    
81     button = b;
82   // convert to panel coordinates
83     osg::Matrixd m = osg::Matrixd::inverse(panel->transformMatrix());
84     picked = toOsg(info.local) * m;
85     SG_LOG( SG_INSTR, SG_DEBUG, "panel pick: " << toSG(picked) );
86   
87   // send to the panel
88     return panel->getPanel()->doLocalMouseAction(button, MOUSE_BUTTON_DOWN, 
89                                           picked.x(), picked.y());
90   }
91   
92   virtual void update(double dt, int keyModState)
93   {
94     panel->getPanel()->updateMouseDelay(dt);
95   }
96   
97   virtual void buttonReleased( int,
98                                const osgGA::GUIEventAdapter&,
99                                const Info* )
100   {
101     panel->getPanel()->doLocalMouseAction(button, MOUSE_BUTTON_UP, 
102                                           picked.x(), picked.y());
103   }
104   
105 private:
106   FGPanelNode* panel;
107   int button;
108   osg::Vec3 picked;
109 };
110
111 class FGPanelSwitchCallback : public osg::NodeCallback {
112 public:
113   FGPanelSwitchCallback(FGPanelNode* pn) : 
114     panel(pn),
115     visProp(fgGetNode("/sim/panel/visibility"))
116   {
117   }
118   
119   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
120   {
121     assert(dynamic_cast<osg::Switch*>(node));
122     osg::Switch* sw = static_cast<osg::Switch*>(node);
123     
124     if (!visProp->getBoolValue()) {
125       sw->setValue(0, false);
126       return;
127     }
128   
129     
130     panel->lazyLoad(); // isVisible check needs the panel loaded for auto-hide flag
131     bool enabled = panel->isVisible2d();
132     sw->setValue(0, enabled);
133     if (!enabled)
134       return;
135     
136     traverse(node, nv);
137   }
138   
139 private:
140   FGPanelNode* panel;
141   SGPropertyNode* visProp;
142 };
143
144
145 FGPanelNode::FGPanelNode(SGPropertyNode* props) :
146   _resizeToViewport(false)
147 {  
148   commonInit();
149   _panelPath = props->getStringValue("path");
150
151   // And the corner points
152   SGPropertyNode* pt = props->getChild("bottom-left");
153   _bottomLeft[0] = pt->getFloatValue("x-m");
154   _bottomLeft[1] = pt->getFloatValue("y-m");
155   _bottomLeft[2] = pt->getFloatValue("z-m");
156   
157   pt = props->getChild("top-left");
158   _topLeft[0] = pt->getFloatValue("x-m");
159   _topLeft[1] = pt->getFloatValue("y-m");
160   _topLeft[2] = pt->getFloatValue("z-m");
161   
162   pt = props->getChild("bottom-right");
163   _bottomRight[0] = pt->getFloatValue("x-m");
164   _bottomRight[1] = pt->getFloatValue("y-m");
165   _bottomRight[2] = pt->getFloatValue("z-m");
166   
167   _depthTest = props->getBoolValue("depth-test");
168 }
169
170 FGPanelNode::FGPanelNode() :
171   _resizeToViewport(true),
172   _depthTest(false)
173 {
174     // for a 2D panel, various options adjust the transformation
175     // matrix. We need to pass this data on to OSG or its bounding box
176     // will be stale, and picking will break.
177     // http://code.google.com/p/flightgear-bugs/issues/detail?id=864
178     PanelTransformListener* ptl = new PanelTransformListener(this);
179     fgGetNode("/sim/panel/x-offset", true)->addChangeListener(ptl);
180     fgGetNode("/sim/panel/y-offset", true)->addChangeListener(ptl);
181     fgGetNode("/sim/startup/xsize", true)->addChangeListener(ptl);
182     fgGetNode("/sim/startup/ysize", true)->addChangeListener(ptl);
183     
184     commonInit();
185 }
186
187 void FGPanelNode::setPanelPath(const std::string& panel)
188 {
189   if (panel == _panelPath) {
190     return;
191   }
192   
193   _panelPath = panel;
194   if (_panel) {
195     _panel.clear();
196   }
197 }
198
199 void FGPanelNode::lazyLoad()
200 {
201   if (!_panelPath.empty() && !_panel) {
202     _panel = fgReadPanel(_panelPath);
203     if (!_panel) {
204       SG_LOG(SG_COCKPIT, SG_WARN, "failed to read panel from:" << _panelPath);
205       _panelPath = std::string(); // don't keep trying to read
206       return;
207     }
208     
209     _panel->setDepthTest(_depthTest);
210     initWithPanel();
211   }
212 }
213
214 void FGPanelNode::commonInit()
215 {
216   setUseDisplayList(false);
217   setDataVariance(Object::DYNAMIC);
218   getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
219   getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
220 }
221
222 void FGPanelNode::initWithPanel()
223 {
224   int i;
225
226   // Read out the pixel-space info
227   float panelWidth = _panel->getWidth();
228   float panelHeight = _panel->getHeight();
229
230   _panel->getLogicalExtent(_xmin, _ymin, _xmax, _ymax);
231     
232   // Now generate our transformation matrix.  For shorthand, use
233   // "a", "b", and "c" as our corners and "m" as the matrix. The
234   // vector u goes from a to b, v from a to c, and w is a
235   // perpendicular cross product.
236   osg::Vec3 a = _bottomLeft;
237   osg::Vec3 b = _bottomRight;
238   osg::Vec3 c = _topLeft;
239   osg::Vec3 u = b - a;
240   osg::Vec3 v = c - a;
241   osg::Vec3 w = u^v;
242
243     osg::Matrix& m = _xform;
244     if ((u.length2() == 0.0) || (b.length2() == 0.0)) {
245         m.makeIdentity();
246     } else {
247         // Now generate a trivial basis transformation matrix.  If we want
248         // to map the three unit vectors to three arbitrary vectors U, V,
249         // and W, then those just become the columns of the 3x3 matrix.
250         m(0,0) = u[0]; m(1,0) = v[0]; m(2,0) = w[0]; m(3,0) = a[0];//    |Ux Vx Wx|
251         m(0,1) = u[1]; m(1,1) = v[1]; m(2,1) = w[1]; m(3,1) = a[1];//m = |Uy Vy Wy|
252         m(0,2) = u[2]; m(1,2) = v[2]; m(2,2) = w[2]; m(3,2) = a[2];//    |Uz Vz Wz|
253         m(0,3) = 0;    m(1,3) = 0;    m(2,3) = 0;    m(3,3) = 1;
254     }
255
256   // The above matrix maps the unit (!) square to the panel
257   // rectangle.  Postmultiply scaling factors that match the
258   // pixel-space size of the panel.
259   for(i=0; i<4; ++i) {
260       m(0,i) *= 1.0/panelWidth;
261       m(1,i) *= 1.0/panelHeight;
262   }
263
264   dirtyBound();
265 }
266
267 FGPanelNode::~FGPanelNode()
268 {
269 }
270
271 osg::Matrix FGPanelNode::transformMatrix() const
272 {
273   if (!_panel) {
274     return osg::Matrix();
275   }
276
277   if (!_resizeToViewport) {
278     return _xform;
279   }
280   
281   double s = _panel->getAspectScale();
282   osg::Matrix m = osg::Matrix::scale(s, s, 1.0);
283   m *= osg::Matrix::translate(_panel->getXOffset(), _panel->getYOffset(), 0.0);
284
285   return m;
286 }
287
288 void
289 FGPanelNode::drawImplementation(osg::State& state) const
290 {  
291   if (!_panel) {
292     return;
293   }
294   
295   osg::ref_ptr<osg::RefMatrix> mv = new osg::RefMatrix;
296   mv->set(transformMatrix() * state.getModelViewMatrix());
297   state.applyModelViewMatrix(mv.get());
298   
299   _panel->draw(state);
300 }
301
302 osg::BoundingBox
303 FGPanelNode::computeBound() const
304 {
305
306   osg::Vec3 coords[3];
307   osg::Matrix m(transformMatrix());
308   coords[0] = m.preMult(osg::Vec3(_xmin,_ymin,0));
309   coords[1] = m.preMult(osg::Vec3(_xmax,_ymin,0));
310   coords[2] = m.preMult(osg::Vec3(_xmin,_ymax,0));
311
312   osg::BoundingBox bb;
313   bb.expandBy(coords[0]);
314   bb.expandBy(coords[1]);
315   bb.expandBy(coords[2]);
316   return bb;
317 }
318
319 void FGPanelNode::accept(osg::PrimitiveFunctor& functor) const
320 {
321   osg::Vec3 coords[4];
322   osg::Matrix m(transformMatrix());
323   
324   coords[0] = m.preMult(osg::Vec3(_xmin,_ymin,0));
325   coords[1] = m.preMult(osg::Vec3(_xmax,_ymin,0));
326   coords[2] = m.preMult(osg::Vec3(_xmax, _ymax, 0));
327   coords[3] = m.preMult(osg::Vec3(_xmin,_ymax,0));
328
329   functor.setVertexArray(4, coords);
330   functor.drawArrays( GL_QUADS, 0, 4);
331 }
332
333 bool FGPanelNode::isVisible2d() const
334 {
335   if (!_panel) {
336     return false;
337   }
338   
339   if (!_hideNonDefaultViews) {
340     _hideNonDefaultViews = fgGetNode("/sim/panel/hide-nonzero-view", true);
341   }
342   
343   if (_hideNonDefaultViews->getBoolValue()) {
344     if (globals->get_viewmgr()->get_current() != 0) {
345       return false;
346     }
347   }
348   
349   if (!_autoHide2d) {
350     _autoHide2d = fgGetNode("/sim/panel/hide-nonzero-heading-offset", true);
351   }
352   
353   if (_panel->getAutohide() && _autoHide2d->getBoolValue()) {
354     if (!globals->get_current_view()) {
355       return false;
356     }
357     
358     return globals->get_current_view()->getHeadingOffset_deg() == 0;
359   }
360   
361   return true;
362 }
363
364 static osg::Node* createGeode(FGPanelNode* panel)
365 {
366     osg::Geode* geode = new osg::Geode;
367     geode->addDrawable(panel);
368     
369     geode->setNodeMask(SG_NODEMASK_PICK_BIT | SG_NODEMASK_2DPANEL_BIT);
370     
371     SGSceneUserData* userData;
372     userData = SGSceneUserData::getOrCreateSceneUserData(geode);
373     userData->setPickCallback(new FGPanelPickCallback(panel));
374     return geode;
375 }
376
377 class PanelPathListener : public SGPropertyChangeListener
378 {
379 public:
380   PanelPathListener(FGPanelNode* pn) : _panelNode(pn) {}
381   
382   virtual void valueChanged (SGPropertyNode * node)
383   {
384     _panelNode->setPanelPath(node->getStringValue());
385   }
386 private:
387   FGPanelNode* _panelNode;
388 };
389
390
391 osg::Node* FGPanelNode::create2DPanelNode()
392 {
393   SGCommandMgr::instance()->addCommand("panel-mouse-click", do_panel_mouse_click);
394   
395   SGPropertyNode* pathNode = fgGetNode("/sim/panel/path");
396   
397   FGPanelNode* drawable = new FGPanelNode();
398 // need a global to keep the panel_mouse_click command working, sadly
399   global_panel = drawable;
400   
401   PanelPathListener* ppo = new PanelPathListener(drawable);
402   pathNode->addChangeListener(ppo);
403   drawable->setPanelPath(pathNode->getStringValue());
404     
405   osg::Switch* ps = new osg::Switch;
406   osg::StateSet* stateSet = ps->getOrCreateStateSet();
407   stateSet->setRenderBinDetails(1000, "RenderBin");
408   ps->addChild(createGeode(drawable));
409   
410   // speed optimization?
411   stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
412   stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
413   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
414   stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
415   stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
416   
417   ps->setUpdateCallback(new FGPanelSwitchCallback(drawable));
418   return ps;
419 }
420
421 osg::Node* FGPanelNode::load(SGPropertyNode *n)
422 {
423   FGPanelNode* drawable = new FGPanelNode(n);
424   drawable->lazyLoad(); // force load now for 2.5D panels
425   return createGeode(drawable);
426 }