+osg::Matrix FGPanelNode::transformMatrix() const
+{
+ if (!_panel) {
+ return osg::Matrix();
+ }
+
+ if (!_resizeToViewport) {
+ return _xform;
+ }
+
+ double s = _panel->getAspectScale();
+ osg::Matrix m = osg::Matrix::scale(s, s, 1.0);
+ m *= osg::Matrix::translate(_panel->getXOffset(), _panel->getYOffset(), 0.0);
+
+ return m;
+}
+
+void
+FGPanelNode::drawImplementation(osg::State& state) const
+{
+ if (!_panel) {
+ return;
+ }
+
+ osg::ref_ptr<osg::RefMatrix> mv = new osg::RefMatrix;
+ mv->set(transformMatrix() * state.getModelViewMatrix());
+ state.applyModelViewMatrix(mv.get());
+
+ _panel->draw(state);
+}
+
+osg::BoundingBox
+#if OSG_VERSION_LESS_THAN(3,3,2)
+FGPanelNode::computeBound()
+#else
+FGPanelNode::computeBoundingBox()
+#endif
+const
+{
+
+ osg::Vec3 coords[3];
+ osg::Matrix m(transformMatrix());
+ coords[0] = m.preMult(osg::Vec3(_xmin,_ymin,0));
+ coords[1] = m.preMult(osg::Vec3(_xmax,_ymin,0));
+ coords[2] = m.preMult(osg::Vec3(_xmin,_ymax,0));
+
+ osg::BoundingBox bb;
+ bb.expandBy(coords[0]);
+ bb.expandBy(coords[1]);
+ bb.expandBy(coords[2]);
+ return bb;
+}
+
+void FGPanelNode::accept(osg::PrimitiveFunctor& functor) const
+{
+ osg::Vec3 coords[4];
+ osg::Matrix m(transformMatrix());
+
+ coords[0] = m.preMult(osg::Vec3(_xmin,_ymin,0));
+ coords[1] = m.preMult(osg::Vec3(_xmax,_ymin,0));
+ coords[2] = m.preMult(osg::Vec3(_xmax, _ymax, 0));
+ coords[3] = m.preMult(osg::Vec3(_xmin,_ymax,0));
+
+ functor.setVertexArray(4, coords);
+ functor.drawArrays( GL_QUADS, 0, 4);
+}
+
+bool FGPanelNode::isVisible2d() const
+{
+ if (!_panel) {
+ return false;
+ }
+
+ if (!_hideNonDefaultViews) {
+ _hideNonDefaultViews = fgGetNode("/sim/panel/hide-nonzero-view", true);
+ }
+
+ if (_hideNonDefaultViews->getBoolValue()) {
+ if (globals->get_viewmgr()->get_current() != 0) {
+ return false;
+ }
+ }
+
+ if (!_autoHide2d) {
+ _autoHide2d = fgGetNode("/sim/panel/hide-nonzero-heading-offset", true);
+ }
+
+ if (_panel->getAutohide() && _autoHide2d->getBoolValue()) {
+ if (!globals->get_current_view()) {
+ return false;
+ }
+
+ return globals->get_current_view()->getHeadingOffset_deg() == 0;
+ }
+
+ return true;
+}
+
+static osg::Node* createGeode(FGPanelNode* panel)
+{
+ osg::Geode* geode = new osg::Geode;
+ geode->addDrawable(panel);
+
+ geode->setNodeMask(SG_NODEMASK_PICK_BIT | SG_NODEMASK_2DPANEL_BIT);
+
+ SGSceneUserData* userData;
+ userData = SGSceneUserData::getOrCreateSceneUserData(geode);
+ userData->setPickCallback(new FGPanelPickCallback(panel));
+ return geode;
+}
+
+osg::Node* FGPanelNode::create2DPanelNode()
+{
+ FGPanelNode* drawable = new FGPanelNode;
+
+ osg::Switch* ps = new osg::Switch;
+ osg::StateSet* stateSet = ps->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1000, "RenderBin");
+ ps->addChild(createGeode(drawable));
+
+ // speed optimization?
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+
+ ps->setUpdateCallback(new FGPanelSwitchCallback(drawable));
+ return ps;
+}
+
+osg::Node* FGPanelNode::load(SGPropertyNode *n)
+{
+ FGPanelNode* drawable = new FGPanelNode(n);
+ drawable->lazyLoad(); // force load now for 2.5D panels
+ return createGeode(drawable);
+}
+
+/**
+ * Built-in command: pass a mouse click to the panel.
+ *
+ * button: the mouse button number, zero-based.
+ * is-down: true if the button is down, false if it is up.
+ * x-pos: the x position of the mouse click.
+ * y-pos: the y position of the mouse click.
+ */
+bool
+FGPanelNode::panelMouseClickCommand(const SGPropertyNode * arg)
+{
+ return _panel->doMouseAction(arg->getIntValue("button"),
+ arg->getBoolValue("is-down") ? PU_DOWN : PU_UP,
+ arg->getIntValue("x-pos"),
+ arg->getIntValue("y-pos"));
+}