_flipx(fgGetNode("/sim/panel/flip-x", true)),
_xsize_node(fgGetNode("/sim/startup/xsize", true)),
_ysize_node(fgGetNode("/sim/startup/ysize", true)),
- _enable_depth_test(false)
+ _enable_depth_test(false),
+ _drawPanelHotspots("/sim/panel-hotspots")
{
}
void
-FGPanel::update (double dt)
+FGPanel::update (double /* dt */)
{
- std::cout << "OSGFIXME" << std::endl;
+ updateMouseDelay();
}
-void
-FGPanel::update (osg::State& state, GLfloat winx, GLfloat winw, GLfloat winy, GLfloat winh)
-{
- using namespace osg;
- // Calculate accelerations
- // and jiggle the panel accordingly
- // The factors and bounds are just
- // initial guesses; using sqrt smooths
- // out the spikes.
- double x_offset = _x_offset->getIntValue();
- double y_offset = _y_offset->getIntValue();
-
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- Matrixf proj;
- if ( _flipx->getBoolValue() ) {
- proj = Matrixf::ortho2D(winx + winw, winx, winy + winh, winy); /* up side down */
- } else {
- proj = Matrixf::ortho2D(winx, winx + winw, winy, winy + winh); /* right side up */
- }
- glLoadMatrix(proj.ptr());
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
+double
+FGPanel::getAspectScale() const
+{
+ // set corner-coordinates correctly
- glTranslated(x_offset, y_offset, 0);
+ int xsize = _xsize_node->getIntValue();
+ int ysize = _ysize_node->getIntValue();
+ float aspect_adjust = get_aspect_adjust(xsize, ysize);
- draw(state);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-}
-
-/**
- * Update the panel.
- */
-void
-FGPanel::update (osg::State& state)
-{
- // Do nothing if the panel isn't visible.
- if ( !fgPanelVisible() ) {
- return;
- }
-
- updateMouseDelay();
-
- // Now, draw the panel
- float aspect_adjust = get_aspect_adjust(_xsize_node->getIntValue(),
- _ysize_node->getIntValue());
- if (aspect_adjust <1.0)
- update(state, WIN_X, int(WIN_W * aspect_adjust), WIN_Y, WIN_H);
- else
- update(state, WIN_X, WIN_W, WIN_Y, int(WIN_H / aspect_adjust));
+ if (aspect_adjust < 1.0)
+ return ysize / (double) WIN_H;
+ else
+ return xsize /(double) WIN_W;
}
/**
}
}
-
void
FGPanel::draw(osg::State& state)
{
+
// In 3D mode, it's possible that we are being drawn exactly on top
// of an existing polygon. Use an offset to prevent z-fighting. In
// 2D mode, this is a no-op.
panelStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
panelStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
panelStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
+
osg::Material* material = new osg::Material;
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(1, 1, 1, 1));
material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
panelStateSet->setAttribute(material);
+
panelStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
panelStateSet->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK));
panelStateSet->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL));
// Draw yellow "hotspots" if directed to. This is a panel authoring
// feature; not intended to be high performance or to look good.
- if ( fgGetBool("/sim/panel-hotspots") ) {
+ if ( _drawPanelHotspots ) {
static osg::ref_ptr<osg::StateSet> hotspotStateSet;
if (!hotspotStateSet.valid()) {
hotspotStateSet = new osg::StateSet;
#include <simgear/compiler.h>
#include <simgear/props/props.hxx>
+#include <simgear/props/PropertyObject.hxx>
+
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/structure/SGBinding.hxx>
#include <simgear/math/interpolater.hxx>
virtual void unbind ();
virtual void draw (osg::State& state);
virtual void update (double);
- void update (osg::State& state);
- virtual void update (osg::State& state, GLfloat winx, GLfloat winw, GLfloat winy, GLfloat winh);
+
+ //void update (osg::State& state);
+ //virtual void update (osg::State& state, GLfloat winx, GLfloat winw, GLfloat winy, GLfloat winh);
virtual void updateMouseDelay();
bool getAutohide(void) const { return _autohide; };
void setAutohide(bool enable) { _autohide = enable; };
+
+ double getAspectScale() const;
private:
void setupVirtualCockpit();
instrument_list_type _instruments;
bool _enable_depth_test;
bool _autohide;
+
+ SGPropObjBool _drawPanelHotspots;
};
}
if (mode.pass_through) {
+ // remove once PUI uses standard picking mechanism
if (0 <= x && 0 <= y && puMouse(b, updown, x, y))
return;
- else if (0 <= x && 0 <= y && (globals->get_current_panel() != 0) &&
- globals->get_current_panel()->getVisibility() &&
- globals->get_current_panel()->doMouseAction(b, updown, x, y))
- return;
- else if (0 <= x && 0 <= y && fgHandle3DPanelMouseEvent(b, updown, x, y))
- return;
else {
// pui didn't want the click event so compute a
// scenegraph intersection point corresponding to the mouse click
#endif
Camera* camera = info->camera.get();
Matrix viewMatrix;
- if ((info->flags & VIEW_ABSOLUTE) != 0)
+
+ if (info->flags & GUI) {
+ viewMatrix = osg::Matrix(); // identifty transform on the GUI camera
+ } else if ((info->flags & VIEW_ABSOLUTE) != 0)
viewMatrix = slave._viewOffset;
else
viewMatrix = masterView * slave._viewOffset;
camera->setViewMatrix(viewMatrix);
Matrix projectionMatrix;
- if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
+
+ if (info->flags & GUI) {
+ projectionMatrix = osg::Matrix::ortho2D(0, info->width, 0, info->height);
+ } else if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
if (info->flags & ENABLE_MASTER_ZOOM) {
if (info->relativeCameraParent < _cameras.size()) {
// template projection matrix and view matrix of the current camera
camera->setCullingMode(osg::CullSettings::NO_CULLING);
camera->setProjectionResizePolicy(Camera::FIXED);
camera->setReferenceFrame(Transform::ABSOLUTE_RF);
- const int cameraFlags = GUI;
+ const int cameraFlags = GUI | DO_INTERSECTION_TEST;
CameraInfo* result = addCamera(cameraFlags, camera, Matrixd::identity(),
Matrixd::identity(), false);
SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
}
}
+const CameraInfo* CameraGroup::getGUICamera() const
+{
+ ConstCameraIterator result
+ = std::find_if(camerasBegin(), camerasEnd(),
+ FlagTester<CameraInfo>(GUI));
+ if (result == camerasEnd()) {
+ return NULL;
+ }
+
+ return *result;
+}
+
Camera* getGUICamera(CameraGroup* cgroup)
{
- CameraGroup::CameraIterator end = cgroup->camerasEnd();
- CameraGroup::CameraIterator result
- = std::find_if(cgroup->camerasBegin(), end,
- FlagTester<CameraInfo>(CameraGroup::GUI));
- if (result != end)
- return (*result)->camera.get();
- else
- return 0;
+ const CameraInfo* info = cgroup->getGUICamera();
+ if (!info) {
+ return NULL;
+ }
+
+ return info->camera.get();
}
+static bool computeCameraIntersection(const CameraInfo* cinfo,
+ const osgGA::GUIEventAdapter* ea,
+ osgUtil::LineSegmentIntersector::Intersections& intersections)
+{
+ using osgUtil::Intersector;
+ using osgUtil::LineSegmentIntersector;
+ double x, y;
+ eventToWindowCoords(ea, x, y);
+
+ if (!(cinfo->flags & CameraGroup::DO_INTERSECTION_TEST))
+ return false;
+
+ const Camera* camera = cinfo->camera.get();
+ if (camera->getGraphicsContext() != ea->getGraphicsContext())
+ return false;
+
+ const Viewport* viewport = camera->getViewport();
+ double epsilon = 0.5;
+ if (!(x >= viewport->x() - epsilon
+ && x < viewport->x() + viewport->width() -1.0 + epsilon
+ && y >= viewport->y() - epsilon
+ && y < viewport->y() + viewport->height() -1.0 + epsilon))
+ return false;
+
+ Vec4d start(x, y, 0.0, 1.0);
+ Vec4d end(x, y, 1.0, 1.0);
+ Matrix windowMat = viewport->computeWindowMatrix();
+ Matrix startPtMat = Matrix::inverse(camera->getProjectionMatrix()
+ * windowMat);
+ Matrix endPtMat;
+ if (!cinfo->farCamera.valid() || cinfo->farCamera->getNodeMask() == 0)
+ endPtMat = startPtMat;
+ else
+ endPtMat = Matrix::inverse(cinfo->farCamera->getProjectionMatrix()
+ * windowMat);
+ start = start * startPtMat;
+ start /= start.w();
+ end = end * endPtMat;
+ end /= end.w();
+ ref_ptr<LineSegmentIntersector> picker
+ = new LineSegmentIntersector(Intersector::VIEW,
+ Vec3d(start.x(), start.y(), start.z()),
+ Vec3d(end.x(), end.y(), end.z()));
+ osgUtil::IntersectionVisitor iv(picker.get());
+ const_cast<Camera*>(camera)->accept(iv);
+ if (picker->containsIntersections()) {
+ intersections = picker->getIntersections();
+ return true;
+ }
+
+ return false;
+}
+
bool computeIntersections(const CameraGroup* cgroup,
const osgGA::GUIEventAdapter* ea,
osgUtil::LineSegmentIntersector::Intersections& intersections)
{
- using osgUtil::Intersector;
- using osgUtil::LineSegmentIntersector;
- double x, y;
- eventToWindowCoords(ea, x, y);
+ // test the GUI first
+ const CameraInfo* guiCamera = cgroup->getGUICamera();
+ if (guiCamera && computeCameraIntersection(guiCamera, ea, intersections))
+ return true;
+
// Find camera that contains event
for (CameraGroup::ConstCameraIterator iter = cgroup->camerasBegin(),
e = cgroup->camerasEnd();
iter != e;
++iter) {
const CameraInfo* cinfo = iter->get();
- if ((cinfo->flags & CameraGroup::DO_INTERSECTION_TEST) == 0)
- continue;
- const Camera* camera = cinfo->camera.get();
- if (camera->getGraphicsContext() != ea->getGraphicsContext())
+ if (cinfo == guiCamera)
continue;
- const Viewport* viewport = camera->getViewport();
- double epsilon = 0.5;
- if (!(x >= viewport->x() - epsilon
- && x < viewport->x() + viewport->width() -1.0 + epsilon
- && y >= viewport->y() - epsilon
- && y < viewport->y() + viewport->height() -1.0 + epsilon))
- continue;
- Vec4d start(x, y, 0.0, 1.0);
- Vec4d end(x, y, 1.0, 1.0);
- Matrix windowMat = viewport->computeWindowMatrix();
- Matrix startPtMat = Matrix::inverse(camera->getProjectionMatrix()
- * windowMat);
- Matrix endPtMat;
- if (!cinfo->farCamera.valid() || cinfo->farCamera->getNodeMask() == 0)
- endPtMat = startPtMat;
- else
- endPtMat = Matrix::inverse(cinfo->farCamera->getProjectionMatrix()
- * windowMat);
- start = start * startPtMat;
- start /= start.w();
- end = end * endPtMat;
- end /= end.w();
- ref_ptr<LineSegmentIntersector> picker
- = new LineSegmentIntersector(Intersector::VIEW,
- Vec3d(start.x(), start.y(), start.z()),
- Vec3d(end.x(), end.y(), end.z()));
- osgUtil::IntersectionVisitor iv(picker.get());
- const_cast<Camera*>(camera)->accept(iv);
- if (picker->containsIntersections()) {
- intersections = picker->getIntersections();
+
+ if (computeCameraIntersection(cinfo, ea, intersections))
return true;
- } else {
- break;
- }
}
+
intersections.clear();
return false;
}
* get aspect ratio of master camera's viewport
*/
double getMasterAspectRatio() const;
+
+ /**
+ * find the GUI camera if one is defined
+ */
+ const CameraInfo* getGUICamera() const;
protected:
CameraList _cameras;
osg::ref_ptr<osgViewer::Viewer> _viewer;
{
fgSetInt("/sim/time/warp-delta", d);
}
+
+void FGGlobals::set_current_panel( FGPanel *cp )
+{
+ current_panel = cp;
+// poke the renderer to rebuild the scene node as necessary
+ get_renderer()->panelChanged();
+}
// end of globals.cxx
inline void set_ATC_mgr( FGATCMgr *a ) {ATC_mgr = a; }
inline FGPanel *get_current_panel() const { return current_panel; }
- inline void set_current_panel( FGPanel *cp ) { current_panel = cp; }
+ void set_current_panel( FGPanel *cp );
inline FGControls *get_controls() const { return controls; }
inline void set_controls( FGControls *c ) { controls = c; }
}
};
-
-osg::Node* load_panel(SGPropertyNode *n)
-{
- osg::Geode* geode = new osg::Geode;
- geode->addDrawable(new FGPanelNode(n));
- return geode;
-}
-
-SGPath resolve_path(const std::string& s)
-{
- return globals->resolve_maybe_aircraft_path(s);
-}
-
}
// This is the top level master main function that is registered as
////////////////////////////////////////////////////////////////////
globals->set_matlib( new SGMaterialLib );
simgear::SGModelLib::init(globals->get_fg_root(), globals->get_props());
- simgear::SGModelLib::setPanelFunc(load_panel);
+ simgear::SGModelLib::setPanelFunc(FGPanelNode::load);
////////////////////////////////////////////////////////////////////
// Initialize the TG scenery subsystem.
#include <Time/light.hxx>
#include <Time/light.hxx>
#include <Cockpit/panel.hxx>
+
#include <Model/panelnode.hxx>
#include <Model/modelmgr.hxx>
#include <Model/acmodel.hxx>
private:
};
-class SGHUDAndPanelDrawable : public osg::Drawable {
+class SGHUDDrawable : public osg::Drawable {
public:
- SGHUDAndPanelDrawable()
+ SGHUDDrawable()
{
// Dynamic stuff, do not store geometry
setUseDisplayList(false);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushClientAttrib(~0u);
-
+
HUD *hud = static_cast<HUD*>(globals->get_subsystem("hud"));
hud->draw(state);
- // update the panel subsystem
- if ( globals->get_current_panel() != NULL )
- globals->get_current_panel()->update(state);
- // We don't need a state here - can be safely removed when we can pick
- // correctly
- fgUpdate3DPanels();
-
glPopClientAttrib();
glPopAttrib();
-
}
- virtual osg::Object* cloneType() const { return new SGHUDAndPanelDrawable; }
- virtual osg::Object* clone(const osg::CopyOp&) const { return new SGHUDAndPanelDrawable; }
+ virtual osg::Object* cloneType() const { return new SGHUDDrawable; }
+ virtual osg::Object* clone(const osg::CopyOp&) const { return new SGHUDDrawable; }
private:
};
static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
+static osg::ref_ptr<osg::Switch> panelSwitch;
+
+
+// update callback for the switch node controlling the 2D panel
+class FGPanelSwitchCallback : public osg::NodeCallback {
+public:
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+ {
+ assert(dynamic_cast<osg::Switch*>(node));
+ osg::Switch* sw = static_cast<osg::Switch*>(node);
+
+ bool enabled = fgPanelVisible();
+ sw->setValue(0, enabled);
+ if (!enabled)
+ return;
+ traverse(node, nv);
+ }
+};
+
#ifdef FG_JPEG_SERVER
static void updateRenderer()
{
// plug in the GUI
osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
if (guiCamera) {
+
osg::Geode* geode = new osg::Geode;
geode->addDrawable(new SGPuDrawable);
- geode->addDrawable(new SGHUDAndPanelDrawable);
+ geode->addDrawable(new SGHUDDrawable);
guiCamera->addChild(geode);
+
+ panelSwitch = new osg::Switch;
+ osg::StateSet* stateSet = panelSwitch->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1000, "RenderBin");
+
+ // 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);
+
+
+ panelSwitch->setUpdateCallback(new FGPanelSwitchCallback);
+ panelChanged();
+
+ guiCamera->addChild(panelSwitch.get());
}
+
osg::Switch* sw = new osg::Switch;
sw->setUpdateCallback(new FGScenerySwitchCallback);
sw->addChild(mRoot.get());
stateSet->setAttributeAndModes(new osg::Program, osg::StateAttribute::ON);
}
+void FGRenderer::panelChanged()
+{
+ if (!panelSwitch) {
+ return;
+ }
+
+ osg::Node* n = FGPanelNode::createNode(globals->get_current_panel());
+ if (panelSwitch->getNumChildren()) {
+ panelSwitch->setChild(0, n);
+ } else {
+ panelSwitch->addChild(n);
+ }
+}
+
// Update all Visuals (redraws anything graphics related)
void
FGRenderer::update( ) {
SGSky* getSky() const { return _sky; }
+ /**
+ * inform the renderer when the global (2D) panel is changed
+ */
+ void panelChanged();
protected:
osg::ref_ptr<osgViewer::Viewer> viewer;
osg::ref_ptr<flightgear::FGEventHandler> eventHandler;
# include <config.h>
#endif
-#include <simgear/compiler.h>
-#include <simgear/structure/exception.hxx>
+#include "panelnode.hxx"
#include <vector>
#include <algorithm>
-#include <Cockpit/panel.hxx>
-#include <Cockpit/panel_io.hxx>
-#include "panelnode.hxx"
+#include <osg/Geode>
-using std::vector;
+#include <simgear/compiler.h>
+#include <simgear/structure/exception.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/scene/util/OSGMath.hxx>
+#include <simgear/scene/util/SGPickCallback.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
+#include <simgear/scene/util/SGNodeMasks.hxx>
-// Static (!) handling for all 3D panels in the program.
-// OSGFIXME: Put the panel as different elements in the scenegraph.
-// Then just pick in that scenegraph.
-vector<FGPanelNode*> all_3d_panels;
-bool fgHandle3DPanelMouseEvent( int button, int updown, int x, int y )
-{
- for ( unsigned int i = 0; i < all_3d_panels.size(); i++ ) {
- if ( all_3d_panels[i]->doMouseAction(button, updown, x, y) ) {
- return true;
- }
- }
- return false;
-}
+#include <Main/fg_os.hxx>
+#include <Cockpit/panel.hxx>
+#include <Cockpit/panel_io.hxx>
-void fgUpdate3DPanels()
-{
- for ( unsigned int i = 0; i < all_3d_panels.size(); i++ ) {
- all_3d_panels[i]->getPanel()->updateMouseDelay();
- }
-}
-FGPanelNode::FGPanelNode(SGPropertyNode* props)
-{
- int i;
+using std::vector;
+class FGPanelPickCallback : public SGPickCallback {
+public:
+ FGPanelPickCallback(FGPanelNode* p) :
+ panel(p)
+ {}
+
+ virtual bool buttonPressed(int b, const Info& info)
+ {
+ button = b;
+ // convert to panel coordinates
+ osg::Matrixd m = osg::Matrixd::inverse(panel->transformMatrix());
+ picked = toOsg(info.local) * m;
+ SG_LOG( SG_INSTR, SG_DEBUG, "panel pick: " << toSG(picked) );
+
+ // send to the panel
+ return panel->getPanel()->doLocalMouseAction(button, MOUSE_BUTTON_DOWN,
+ picked.x(), picked.y());
+ }
+
+ virtual void update(double /* dt */)
+ {
+ panel->getPanel()->updateMouseDelay();
+ }
+
+ virtual void buttonReleased(void)
+ {
+ panel->getPanel()->doLocalMouseAction(button, MOUSE_BUTTON_UP,
+ picked.x(), picked.y());
+ }
+
+private:
+ FGPanelNode* panel;
+ int button;
+ osg::Vec3 picked;
+};
+
+FGPanelNode::FGPanelNode(SGPropertyNode* props) :
+ _resizeToViewport(false)
+{
// Make an FGPanel object. But *don't* call init() or bind() on
// it -- those methods touch static state.
const char *path = props->getStringValue("path");
if (!_panel)
throw sg_io_exception(string("Failed to load panel ") + path);
- // Never mind. We *have* to call init to make sure the static
- // state is initialized (it's not, if there aren't any 2D
- // panels). This is a memory leak and should be fixed!`
- // FIXME
- _panel->init();
-
- _panel->setDepthTest( props->getBoolValue("depth-test") );
-
- // Read out the pixel-space info
- _xmax = _panel->getWidth();
- _ymax = _panel->getHeight();
-
// And the corner points
SGPropertyNode* pt = props->getChild("bottom-left");
_bottomLeft[0] = pt->getFloatValue("x-m");
_bottomLeft[1] = pt->getFloatValue("y-m");
_bottomLeft[2] = pt->getFloatValue("z-m");
-
+
pt = props->getChild("top-left");
_topLeft[0] = pt->getFloatValue("x-m");
_topLeft[1] = pt->getFloatValue("y-m");
_topLeft[2] = pt->getFloatValue("z-m");
-
+
pt = props->getChild("bottom-right");
_bottomRight[0] = pt->getFloatValue("x-m");
_bottomRight[1] = pt->getFloatValue("y-m");
_bottomRight[2] = pt->getFloatValue("z-m");
+
+ _panel->setDepthTest( props->getBoolValue("depth-test") );
+
+ initWithPanel();
+}
+
+FGPanelNode::FGPanelNode(FGPanel* p) :
+ _panel(p),
+ _resizeToViewport(true)
+{
+ initWithPanel();
+}
+
+void FGPanelNode::initWithPanel()
+{
+ int i;
+
+ // Never mind. We *have* to call init to make sure the static
+ // state is initialized (it's not, if there aren't any 2D
+ // panels). This is a memory leak and should be fixed!`
+ // FIXME
+ _panel->init();
+
+ // Read out the pixel-space info
+ _xmax = _panel->getWidth();
+ _ymax = _panel->getHeight();
+
// Now generate our transformation matrix. For shorthand, use
// "a", "b", and "c" as our corners and "m" as the matrix. The
m(1,i) *= 1.0/_ymax;
}
- _lastViewport[0] = 0;
- _lastViewport[1] = 0;
- _lastViewport[2] = 0;
- _lastViewport[3] = 0;
-
dirtyBound();
-
- // All done. Add us to the list
- all_3d_panels.push_back(this);
-
setUseDisplayList(false);
+ setDataVariance(Object::DYNAMIC);
+
getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
}
FGPanelNode::~FGPanelNode()
{
- vector<FGPanelNode*>::iterator i =
- find(all_3d_panels.begin(), all_3d_panels.end(), this);
- if (i != all_3d_panels.end()) {
- all_3d_panels.erase(i);
- }
delete _panel;
}
+osg::Matrix FGPanelNode::transformMatrix() const
+{
+ 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
-{
+{
osg::ref_ptr<osg::RefMatrix> mv = new osg::RefMatrix;
- mv->set(_xform*state.getModelViewMatrix());
+ mv->set(transformMatrix() * state.getModelViewMatrix());
state.applyModelViewMatrix(mv.get());
- // Grab the matrix state, so that we can get back from screen
- // coordinates to panel coordinates when the user clicks the
- // mouse.
- // OSGFIXME: we don't need that when we can really pick
- _lastModelview = state.getModelViewMatrix();
- _lastProjection = state.getProjectionMatrix();
-
- const osg::Viewport* vp = state.getCurrentViewport();
- _lastViewport[0] = vp->x();
- _lastViewport[1] = vp->y();
- _lastViewport[2] = vp->width();
- _lastViewport[3] = vp->height();
-
_panel->draw(state);
}
osg::BoundingBox
FGPanelNode::computeBound() const
{
+ osg::Vec3 coords[4];
+ osg::Matrix m(transformMatrix());
+ coords[0] = m.preMult(osg::Vec3(0,0,0));
+ coords[1] = m.preMult(osg::Vec3(_xmax,0,0));
+ coords[2] = m.preMult(osg::Vec3(0,_ymax,0));
+
osg::BoundingBox bb;
- bb.expandBy(_bottomLeft);
- bb.expandBy(_bottomRight);
- bb.expandBy(_topLeft);
+ bb.expandBy(coords[0]);
+ bb.expandBy(coords[1]);
+ bb.expandBy(coords[2]);
return bb;
}
-bool FGPanelNode::doMouseAction(int button, int updown, int x, int y)
+void FGPanelNode::accept(osg::PrimitiveFunctor& functor) const
{
- if (_lastViewport[2] == 0 || _lastViewport[3] == 0) {
- // we haven't been drawn yet, presumably
- return false;
- }
+ osg::Vec3 coords[4];
+ osg::Matrix m(transformMatrix());
+
+ coords[0] = m.preMult(osg::Vec3(0,0,0));
+ coords[1] = m.preMult(osg::Vec3(_xmax,0,0));
+ coords[2] = m.preMult(osg::Vec3(_xmax, _ymax, 0));
+ coords[3] = m.preMult(osg::Vec3(0,_ymax,0));
+
+ functor.setVertexArray(4, coords);
+ functor.drawArrays( GL_QUADS, 0, 4);
+}
+
+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;
+}
- // Covert the screen coordinates to viewport coordinates in the
- // range [0:1], then transform to OpenGL "post projection" coords
- // in [-1:1]. Remember the difference in Y direction!
- float vx = (x + 0.5 - _lastViewport[0]) / _lastViewport[2];
- float vy = (y + 0.5 - _lastViewport[1]) / _lastViewport[3];
- vx = 2*vx - 1;
- vy = 1 - 2*vy;
-
- // Make two vectors in post-projection coordinates at the given
- // screen, one in the near field and one in the far field.
- osg::Vec3 a, b;
- a[0] = b[0] = vx;
- a[1] = b[1] = vy;
- a[2] = 0.75; // "Near" Z value
- b[2] = -0.75; // "Far" Z value
-
- // Run both vectors "backwards" through the OpenGL matrix
- // transformation. Remember to w-normalize the vectors!
- osg::Matrix m = _lastModelview*_lastProjection;
- m = osg::Matrix::inverse(m);
-
- a = m.preMult(a);
- b = m.preMult(b);
-
- // And find their intersection on the z=0 plane. The resulting X
- // and Y coordinates are the hit location in panel coordinates.
- float dxdz = (b[0] - a[0]) / (b[2] - a[2]);
- float dydz = (b[1] - a[1]) / (b[2] - a[2]);
- int panelX = (int)(a[0] - a[2]*dxdz + 0.5);
- int panelY = (int)(a[1] - a[2]*dydz + 0.5);
-
- return _panel->doLocalMouseAction(button, updown, panelX, panelY);
+osg::Node* FGPanelNode::createNode(FGPanel* p)
+{
+ FGPanelNode* drawable = new FGPanelNode(p);
+ return createGeode(drawable);
}
+osg::Node* FGPanelNode::load(SGPropertyNode *n)
+{
+ FGPanelNode* drawable = new FGPanelNode(n);
+ return createGeode(drawable);
+}
class FGPanel;
class SGPropertyNode;
-// PanelNode defines an SSG leaf object that draws a FGPanel object
-// into the scene graph. Note that this is an incomplete SSG object,
-// many methods, mostly involved with modelling and runtime
-// inspection, are unimplemented.
+// PanelNode defines an OSG drawable wrapping the 2D panel drawing code
-// Static mouse handler for all FGPanelNodes. Very clumsy; this
-// should really be done through our container (an aircraft model,
-// typically).
-bool fgHandle3DPanelMouseEvent(int button, int updown, int x, int y);
-void fgUpdate3DPanels();
-
-class FGPanelNode : public osg::Drawable // OSGFIXME
+class FGPanelNode : public osg::Drawable
{
public:
+ FGPanelNode(FGPanel* panel);
+
FGPanelNode(SGPropertyNode* props);
virtual ~FGPanelNode();
virtual osg::Object* cloneType() const { return 0; }
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return 0; }
- bool doMouseAction(int button, int updown, int x, int y);
-
FGPanel* getPanel() { return _panel; }
virtual void drawImplementation(osg::RenderInfo& renderInfo) const
{ drawImplementation(*renderInfo.getState()); }
+
void drawImplementation(osg::State& state) const;
virtual osg::BoundingBox computeBound() const;
+ /** Return true, FGPanelNode does support accept(PrimitiveFunctor&). */
+ virtual bool supports(const osg::PrimitiveFunctor&) const { return true; }
+
+ virtual void accept(osg::PrimitiveFunctor& functor) const;
+
+ static osg::Node* load(SGPropertyNode *n);
+ static osg::Node* createNode(FGPanel* panel);
+
+ osg::Matrix transformMatrix() const;
+
private:
+ void initWithPanel();
+
FGPanel* _panel;
+
+ bool _resizeToViewport;
// Panel corner coordinates
osg::Vec3 _bottomLeft, _topLeft, _bottomRight;
// The matrix that results, which transforms 2D x/y panel
// coordinates into 3D coordinates of the panel quadrilateral.
osg::Matrix _xform;
-
- // The matrix transformation state that was active the last time
- // we were rendered. Used by the mouse code to compute
- // intersections.
- mutable osg::Matrix _lastModelview;
- mutable osg::Matrix _lastProjection;
- mutable double _lastViewport[4];
};