X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2Fpanelnode.cxx;h=84448b866b3314a292d142a4a17c80f5c71de851;hb=c6f88e5b9be767d93fd34f3b01c0e949fbd0044b;hp=e49f3197bcb92914759d817bdb8ef05b41dd749c;hpb=b53cd9c59fcca7d98c24436a1ebfeed981b9634f;p=flightgear.git diff --git a/src/Model/panelnode.cxx b/src/Model/panelnode.cxx index e49f3197b..84448b866 100644 --- a/src/Model/panelnode.cxx +++ b/src/Model/panelnode.cxx @@ -1,14 +1,60 @@ -#include -#include
+#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + +#include + #include #include #include "panelnode.hxx" +using std::vector; + + +// 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 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; +} + +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; + // Make an FGPanel object. But *don't* call init() or bind() on // it -- those methods touch static state. - _panel = fgReadPanel(props->getStringValue("path")); + const char *path = props->getStringValue("path"); + _panel = fgReadPanel(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(); @@ -30,46 +76,42 @@ FGPanelNode::FGPanelNode(SGPropertyNode* props) _bottomRight[1] = pt->getFloatValue("y-m"); _bottomRight[2] = pt->getFloatValue("z-m"); - // Now generate out transformation matrix. For shorthand, use + // Now generate our transformation matrix. For shorthand, use // "a", "b", and "c" as our corners and "m" as the matrix. The // vector u goes from a to b, v from a to c, and w is a // perpendicular cross product. - float *a = _bottomLeft, *b = _bottomRight, *c = _topLeft, *m = _xform; - float u[3], v[3], w[3]; - int i; - for(i=0; i<3; i++) u[i] = b[i] - a[i]; // U = B - A - for(i=0; i<3; i++) v[i] = c[i] - a[i]; // V = C - A - - w[0] = u[1]*v[2] - v[1]*u[2]; // W = U x V - w[1] = u[2]*v[0] - v[2]*u[0]; - w[2] = u[0]*v[1] - v[0]*u[1]; + osg::Vec3 a = _bottomLeft; + osg::Vec3 b = _bottomRight; + osg::Vec3 c = _topLeft; + osg::Vec3 u = b - a; + osg::Vec3 v = c - a; + osg::Vec3 w = u^v; + osg::Matrix& m = _xform; // Now generate a trivial basis transformation matrix. If we want // to map the three unit vectors to three arbitrary vectors U, V, // and W, then those just become the columns of the 3x3 matrix. - m[0] = u[0]; m[4] = v[0]; m[8] = w[0]; m[12] = a[0]; // |Ux Vx Wx| - m[1] = u[1]; m[5] = v[1]; m[9] = w[1]; m[13] = a[1]; // m = |Uy Vy Wy| - m[2] = u[2]; m[6] = v[2]; m[10] = w[2]; m[14] = a[2]; // |Uz Vz Wz| - m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; + m(0,0) = u[0]; m(1,0) = v[0]; m(2,0) = w[0]; m(3,0) = a[0];// |Ux Vx Wx| + m(0,1) = u[1]; m(1,1) = v[1]; m(2,1) = w[1]; m(3,1) = a[1];//m = |Uy Vy Wy| + m(0,2) = u[2]; m(1,2) = v[2]; m(2,2) = w[2]; m(3,2) = a[2];// |Uz Vz Wz| + m(0,3) = 0; m(1,3) = 0; m(2,3) = 0; m(3,3) = 1; // The above matrix maps the unit (!) square to the panel // rectangle. Postmultiply scaling factors that match the // pixel-space size of the panel. - for(i=0; i<4; i++) { - m[0+i] *= 1.0/_xmax; - m[4+i] *= 1.0/_ymax; + for(i=0; i<4; ++i) { + m(0,i) *= 1.0/_xmax; + m(1,i) *= 1.0/_ymax; } - // Now plib initialization. The bounding sphere is defined nicely - // by our corner points: - float cx = (b[0]+c[0])/2; - float cy = (b[1]+c[1])/2; - float cz = (b[2]+c[2])/2; - float r = sqrt((cx-a[0])*(cx-a[0]) + - (cy-a[1])*(cy-a[1]) + - (cz-a[2])*(cz-a[2])); - bsphere.setCenter(cx, cy, cz); - bsphere.setRadius(r); + dirtyBound(); + + // All done. Add us to the list + all_3d_panels.push_back(this); + + setUseDisplayList(false); + getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); } FGPanelNode::~FGPanelNode() @@ -77,24 +119,72 @@ FGPanelNode::~FGPanelNode() delete _panel; } -void FGPanelNode::draw() +void +FGPanelNode::drawImplementation(osg::State& state) const { - // What's the difference? - draw_geometry(); + osg::ref_ptr mv = new osg::RefMatrix; + mv->set(_xform*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); } -void FGPanelNode::draw_geometry() +osg::BoundingBox +FGPanelNode::computeBound() const { - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glMultMatrixf(_xform); - _panel->draw(); - glPopMatrix(); + osg::BoundingBox bb; + bb.expandBy(_bottomLeft); + bb.expandBy(_bottomRight); + bb.expandBy(_topLeft); + return bb; } -void FGPanelNode::die() +bool FGPanelNode::doMouseAction(int button, int updown, int x, int y) { - SG_LOG(SG_ALL,SG_ALERT,"Unimplemented function called on FGPanelNode"); - *(int*)0=0; + // 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); }