diff --git a/src/Input/input.cxx b/src/Input/input.cxx index 98fe85bcd..fdb13de5e 100644 --- a/src/Input/input.cxx +++ b/src/Input/input.cxx @@ -66,7 +66,7 @@ SG_USING_STD(ifstream); SG_USING_STD(string); SG_USING_STD(vector); -void mouseClickHandler(int button, int updown, int x, int y); +void mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter*); void mouseMotionHandler(int x, int y); void keyHandler(int key, int keymod, int mousex, int mousey); @@ -247,7 +247,7 @@ FGInput::doKey (int k, int modifiers, int x, int y) } void -FGInput::doMouseClick (int b, int updown, int x, int y) +FGInput::doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea) { int modifiers = fgGetKeyModifiers(); @@ -272,13 +272,15 @@ FGInput::doMouseClick (int b, int updown, int x, int y) } if (mode.pass_through) { - if (puMouse(b, updown, x, y)) + // The pu stuff seems to need that. May be it does opengl picking ... + fgMakeCurrent(); + if (0 <= x && 0 <= y && puMouse(b, updown, x, y)) return; - else if ((globals->get_current_panel() != 0) && + 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 (fgHandle3DPanelMouseEvent(b, updown, x, y)) + else if (0 <= x && 0 <= y && fgHandle3DPanelMouseEvent(b, updown, x, y)) return; else { // pui didn't want the click event so compute a @@ -291,7 +293,7 @@ FGInput::doMouseClick (int b, int updown, int x, int y) // The nearest one is the first one and the deepest // (the most specialized one in the scenegraph) is the first. std::vector pickList; - if (FGRenderer::pick(x, y, pickList)) { + if (FGRenderer::pick(x, y, pickList, ea)) { std::vector::const_iterator i; for (i = pickList.begin(); i != pickList.end(); ++i) { if (i->callback->buttonPressed(b, i->info)) { @@ -1097,10 +1099,10 @@ void keyHandler(int key, int keymod, int mousex, int mousey) default_input->doKey(key, keymod, mousex, mousey); } -void mouseClickHandler(int button, int updown, int x, int y) +void mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea) { if(default_input) - default_input->doMouseClick(button, updown, x, y); + default_input->doMouseClick(button, updown, x, y, mainWindow, ea); } void mouseMotionHandler(int x, int y) diff --git a/src/Input/input.hxx b/src/Input/input.hxx index 7a981b0fa..99116dbe6 100644 --- a/src/Input/input.hxx +++ b/src/Input/input.hxx @@ -134,7 +134,7 @@ public: * @param x The X position of the mouse event, in screen coordinates. * @param y The Y position of the mouse event, in screen coordinates. */ - virtual void doMouseClick (int button, int updown, int x, int y); + virtual void doMouseClick (int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter*); /** diff --git a/src/Main/FGManipulator.cxx b/src/Main/FGManipulator.cxx index a5078fb59..580b82d48 100644 --- a/src/Main/FGManipulator.cxx +++ b/src/Main/FGManipulator.cxx @@ -44,9 +44,8 @@ osg::Node* FGManipulator::getNode() return _node.get(); } -namespace { // All the usual translation from window system to FG / plib -int osgToFGModifiers(int modifiers) +static int osgToFGModifiers(int modifiers) { int result = 0; if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT | @@ -60,7 +59,6 @@ int osgToFGModifiers(int modifiers) result |= KEYMOD_ALT; return result; } -} // namespace void FGManipulator::init(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us) @@ -69,17 +67,29 @@ void FGManipulator::init(const osgGA::GUIEventAdapter& ea, (void)handle(ea, us); } -namespace { -void eventToViewport(const osgGA::GUIEventAdapter& ea, - osgGA::GUIActionAdapter& us, - int& x, int& y) +static bool +eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us, + int& x, int& y) { - x = (int)ea.getX(); - y = (int)ea.getY(); - if (ea.getMouseYOrientation() - == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) - y = (int)ea.getWindowHeight() - y; -} + x = -1; + y = -1; + + const osgViewer::Viewer* viewer; + viewer = dynamic_cast(&us); + if (!viewer) + return false; + + float lx, ly; + const osg::Camera* camera; + camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly); + + if (!fgOSIsMainCamera(camera)) + return false; + + x = int(lx); + y = int(camera->getViewport()->height() - ly); + + return true; } bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea, @@ -101,12 +111,12 @@ bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea, eventToViewport(ea, us, x, y); if (keyHandler) (*keyHandler)(key, modmask, x, y); + return true; } - return true; case osgGA::GUIEventAdapter::PUSH: case osgGA::GUIEventAdapter::RELEASE: { - eventToViewport(ea, us, x, y); + bool mainWindow = eventToViewport(ea, us, x, y); int button = 0; switch (ea.getButton()) { case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON: @@ -122,7 +132,7 @@ bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea, if (mouseClickHandler) (*mouseClickHandler)(button, (ea.getEventType() - == osgGA::GUIEventAdapter::RELEASE), x, y); + == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea); return true; } case osgGA::GUIEventAdapter::MOVE: @@ -131,10 +141,6 @@ bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea, if (mouseMotionHandler) (*mouseMotionHandler)(x, y); return true; - case osgGA::GUIEventAdapter::RESIZE: - if (windowResizeHandler) - (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight()); - return true; case osgGA::GUIEventAdapter::CLOSE_WINDOW: case osgGA::GUIEventAdapter::QUIT_APPLICATION: fgOSExit(0); @@ -143,7 +149,7 @@ bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea, return false; } } - + void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers) { diff --git a/src/Main/fg_os.cxx b/src/Main/fg_os.cxx index 26767fcc4..a9fcf86c9 100644 --- a/src/Main/fg_os.cxx +++ b/src/Main/fg_os.cxx @@ -90,7 +90,7 @@ static void GLUTmotion (int x, int y) static void GLUTmouse (int button, int updown, int x, int y) { GlutModifiers = glutGetModifiers(); - if(MouseClickHandler) (*MouseClickHandler)(button, updown, x, y); + if(MouseClickHandler) (*MouseClickHandler)(button, updown, x, y, true, 0); } static void GLUTspecialkeyup(int k, int x, int y) @@ -240,3 +240,13 @@ void fgOSOpenWindow(int w, int h, int bpp, bool alpha, void fgMakeCurrent() { } + +bool fgOSIsMainCamera(const osg::Camera*) +{ + return true; +} + +bool fgOSIsMainContext(const osg::GraphicsContext*) +{ + return true; +} diff --git a/src/Main/fg_os.hxx b/src/Main/fg_os.hxx index 931dcb10f..9bbbb4d95 100644 --- a/src/Main/fg_os.hxx +++ b/src/Main/fg_os.hxx @@ -60,12 +60,15 @@ void fgRequestRedraw(); // Callbacks and registration API // +namespace osg { class Camera; class GraphicsContext; } +namespace osgGA { class GUIEventAdapter; } + typedef void (*fgIdleHandler)(); typedef void (*fgDrawHandler)(); typedef void (*fgWindowResizeHandler)(int w, int h); typedef void (*fgKeyHandler)(int key, int keymod, int mousex, int mousey); -typedef void (*fgMouseClickHandler)(int button, int updown, int x, int y); +typedef void (*fgMouseClickHandler)(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter*); typedef void (*fgMouseMotionHandler)(int x, int y); void fgRegisterIdleHandler(fgIdleHandler func); @@ -77,4 +80,8 @@ void fgRegisterMouseClickHandler(fgMouseClickHandler func); void fgRegisterMouseMotionHandler(fgMouseMotionHandler func); void fgMakeCurrent(); + +bool fgOSIsMainCamera(const osg::Camera* camera); +bool fgOSIsMainContext(const osg::GraphicsContext* context); + #endif // _FG_OS_HXX diff --git a/src/Main/fg_os_osgviewer.cxx b/src/Main/fg_os_osgviewer.cxx index 120647237..7cde2a83d 100644 --- a/src/Main/fg_os_osgviewer.cxx +++ b/src/Main/fg_os_osgviewer.cxx @@ -13,6 +13,7 @@ #include #include "fg_os.hxx" +#include "fg_props.hxx" #include "util.hxx" #include "globals.hxx" #include "renderer.hxx" @@ -65,42 +66,133 @@ void fgRequestRedraw() // fg_os implementation // - static osg::ref_ptr viewer; +static osg::ref_ptr mainCamera; void fgOSOpenWindow(int w, int h, int bpp, bool alpha, bool stencil, bool fullscreen) { + osg::GraphicsContext::WindowingSystemInterface* wsi; + wsi = osg::GraphicsContext::getWindowingSystemInterface(); + viewer = new osgViewer::Viewer; // Avoid complications with fg's custom drawables. - viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded); - osg::ref_ptr traits - = new osg::GraphicsContext::Traits; + std::string mode; + mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded"); + if (mode == "AutomaticSelection") + viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection); + else if (mode == "CullDrawThreadPerContext") + viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext); + else if (mode == "DrawThreadPerContext") + viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext); + else if (mode == "CullThreadPerCameraDrawThreadPerContext") + viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext); + else + viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded); + osg::ref_ptr traits; + traits = new osg::GraphicsContext::Traits; int cbits = (bpp <= 16) ? 5 : 8; int zbits = (bpp <= 16) ? 16 : 24; - traits->width = w; - traits->height = h; traits->red = traits->green = traits->blue = cbits; traits->depth = zbits; if (alpha) traits->alpha = 8; if (stencil) traits->stencil = 8; - if (fullscreen) - traits->windowDecoration = false; - else - traits->windowDecoration = true; - traits->supportsResize = true; traits->doubleBuffer = true; - osg::GraphicsContext* gc - = osg::GraphicsContext::createGraphicsContext(traits.get()); - viewer->getCamera()->setGraphicsContext(gc); + traits->mipMapGeneration = true; + traits->windowName = "FlightGear"; + traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers); + traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples); + traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync); + + if (fullscreen) { + unsigned width = 0; + unsigned height = 0; + wsi->getScreenResolution(*traits, width, height); + traits->windowDecoration = false; + traits->width = width; + traits->height = height; + traits->supportsResize = false; + } else { + traits->windowDecoration = true; + traits->width = w; + traits->height = h; + traits->supportsResize = true; + } + + osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL; + + // Ok, first the children. + // that achieves some magic ordering og the slaves so that we end up + // in the main window more often. + // This can be sorted out better when we got rid of glut and sdl. + if (fgHasNode("/sim/rendering/camera")) { + SGPropertyNode* renderingNode = fgGetNode("/sim/rendering"); + for (int i = 0; i < renderingNode->nChildren(); ++i) { + SGPropertyNode* cameraNode = renderingNode->getChild(i); + if (strcmp(cameraNode->getName(), "camera") != 0) + continue; + + // get a new copy of the traits struct + osg::ref_ptr cameraTraits; + cameraTraits = new osg::GraphicsContext::Traits(*traits); + + double shearx = cameraNode->getDoubleValue("shear-x", 0); + double sheary = cameraNode->getDoubleValue("shear-y", 0); + cameraTraits->hostName = cameraNode->getStringValue("host-name", ""); + cameraTraits->displayNum = cameraNode->getIntValue("display", 0); + cameraTraits->screenNum = cameraNode->getIntValue("screen", 0); + if (cameraNode->getBoolValue("fullscreen", fullscreen)) { + unsigned width = 0; + unsigned height = 0; + wsi->getScreenResolution(*cameraTraits, width, height); + cameraTraits->windowDecoration = false; + cameraTraits->width = width; + cameraTraits->height = height; + cameraTraits->supportsResize = false; + } else { + cameraTraits->windowDecoration = true; + cameraTraits->width = cameraNode->getIntValue("width", w); + cameraTraits->height = cameraNode->getIntValue("height", h); + cameraTraits->supportsResize = true; + } + // FIXME, currently this is too much of a problem to route the resize + // events. When we do no longer need sdl and such this + // can be simplified + cameraTraits->supportsResize = false; + + // ok found a camera configuration, add a new slave ... + osg::ref_ptr camera = new osg::Camera; + + osg::GraphicsContext* gc; + gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get()); + gc->realize(); + camera->setGraphicsContext(gc); + // If a viewport isn't set on the camera, then it's hard to dig it + // out of the SceneView objects in the viewer, and the coordinates + // of mouse events are somewhat bizzare. + camera->setViewport(new osg::Viewport(0, 0, cameraTraits->width, cameraTraits->height)); + camera->setProjectionResizePolicy(rsp); + viewer->addSlave(camera.get(), osg::Matrix::translate(-shearx, -sheary, 0), osg::Matrix()); + } + } + + // now the main camera ... + osg::ref_ptr camera = new osg::Camera; + mainCamera = camera; + osg::GraphicsContext* gc; + gc = osg::GraphicsContext::createGraphicsContext(traits.get()); + gc->realize(); + gc->makeCurrent(); + camera->setGraphicsContext(gc); // If a viewport isn't set on the camera, then it's hard to dig it // out of the SceneView objects in the viewer, and the coordinates // of mouse events are somewhat bizzare. - viewer->getCamera()->setViewport(new osg::Viewport(0, 0, - traits->width, - traits->height)); + camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); + camera->setProjectionResizePolicy(rsp); + viewer->addSlave(camera.get()); + viewer->setCameraManipulator(globals->get_renderer()->getManipulator()); // Let FG handle the escape key with a confirmation viewer->setKeyEventSetsDone(0); @@ -134,7 +226,8 @@ int fgGetKeyModifiers() void fgWarpMouse(int x, int y) { - viewer->requestWarpPointer((float)x, (float)y); + // Hack, currently the pointer is just recentered. So, we know the relative coordinates ... + viewer->requestWarpPointer(0, 0); } // Noop @@ -142,24 +235,85 @@ void fgOSInit(int* argc, char** argv) { } +// Noop void fgOSFullScreen() { - // Noop, but is probably doable - } -// No support in OSG yet +// #define OSG_HAS_MOUSE_CURSOR_PATCH +#ifdef OSG_HAS_MOUSE_CURSOR_PATCH +static void setMouseCursor(osg::Camera* camera, int cursor) +{ + if (!camera) + return; + osg::GraphicsContext* gc = camera->getGraphicsContext(); + if (!gc) + return; + osgViewer::GraphicsWindow* gw; + gw = dynamic_cast(gc); + if (!gw) + return; + + osgViewer::GraphicsWindow::MouseCursor mouseCursor; + mouseCursor = osgViewer::GraphicsWindow::InheritCursor; + if (cursor == MOUSE_CURSOR_NONE) + mouseCursor = osgViewer::GraphicsWindow::NoCursor; + else if(cursor == MOUSE_CURSOR_POINTER) + mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor; + else if(cursor == MOUSE_CURSOR_WAIT) + mouseCursor = osgViewer::GraphicsWindow::WaitCursor; + else if(cursor == MOUSE_CURSOR_CROSSHAIR) + mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor; + else if(cursor == MOUSE_CURSOR_LEFTRIGHT) + mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor; + + gw->setCursor(mouseCursor); +} +#endif + +static int _cursor = -1; + void fgSetMouseCursor(int cursor) { + _cursor = cursor; +#ifdef OSG_HAS_MOUSE_CURSOR_PATCH + setMouseCursor(viewer->getCamera(), cursor); + for (unsigned i = 0; i < viewer->getNumSlaves(); ++i) + setMouseCursor(viewer->getSlave(i)._camera.get(), cursor); +#endif } int fgGetMouseCursor() { - return 0; + return _cursor; } void fgMakeCurrent() { - osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext(); + if (!mainCamera.valid()) + return; + osg::GraphicsContext* gc = mainCamera->getGraphicsContext(); + if (!gc) + return; gc->makeCurrent(); } + +bool fgOSIsMainContext(const osg::GraphicsContext* context) +{ + if (!mainCamera.valid()) + return false; + return context == mainCamera->getGraphicsContext(); +} + +bool fgOSIsMainCamera(const osg::Camera* camera) +{ + if (!camera) + return false; + if (camera == mainCamera.get()) + return true; + if (!viewer.valid()) + return false; + if (camera == viewer->getCamera()) + return true; + return false; +} diff --git a/src/Main/fg_os_sdl.cxx b/src/Main/fg_os_sdl.cxx index e9ad6f775..791783207 100644 --- a/src/Main/fg_os_sdl.cxx +++ b/src/Main/fg_os_sdl.cxx @@ -226,7 +226,7 @@ void fgOSMainLoop() if(MouseClickHandler) (*MouseClickHandler)(e.button.button - 1, e.button.state == SDL_RELEASED, - e.button.x, e.button.y); + e.button.x, e.button.y, true, 0); break; case SDL_MOUSEMOTION: CurrentMouseX = e.motion.x; @@ -412,3 +412,13 @@ static void initCursors() void fgMakeCurrent() { } + +bool fgOSIsMainCamera(const osg::Camera*) +{ + return true; +} + +bool fgOSIsMainContext(const osg::GraphicsContext*) +{ + return true; +} diff --git a/src/Main/renderer.cxx b/src/Main/renderer.cxx index a6ab199bb..b4dcbc9e7 100644 --- a/src/Main/renderer.cxx +++ b/src/Main/renderer.cxx @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -125,6 +126,9 @@ public: { drawImplementation(*renderInfo.getState()); } void drawImplementation(osg::State& state) const { + if (!fgOSIsMainContext(state.getGraphicsContext())) + return; + state.pushStateSet(getStateSet()); state.apply(); state.setActiveTextureUnit(0); @@ -174,6 +178,10 @@ public: { drawImplementation(*renderInfo.getState()); } void drawImplementation(osg::State& state) const { +// std::cout << state.getGraphicsContext() << std::endl; + if (!fgOSIsMainContext(state.getGraphicsContext())) + return; + state.pushStateSet(getStateSet()); state.apply(); state.setActiveTextureUnit(0); @@ -428,7 +436,7 @@ FGRenderer::init( void ) { glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE); if (viewer) { - viewer->getCamera() + viewer->getCamera() ->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); } else { sceneView->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); @@ -797,6 +805,7 @@ FGRenderer::update( bool refresh_camera_settings ) { // need to call the update visitor once if (!viewer) { mFrameStamp->setReferenceTime(globals->get_sim_time_sec()); + mFrameStamp->setSimulationTime(globals->get_sim_time_sec()); mFrameStamp->setFrameNumber(1+mFrameStamp->getFrameNumber()); } mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt()); @@ -845,8 +854,9 @@ FGRenderer::resize( int width, int height ) { } osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); if (viewer) - viewer->getCamera()->getViewport()->setViewport(0, height - view_h, - width, view_h); + ; + // viewer->getCamera()->getViewport()->setViewport(0, height - view_h, +// width, view_h); else sceneView->getViewport()->setViewport(0, height - view_h, width, view_h); @@ -874,84 +884,6 @@ FGRenderer::resize( int width, int height ) { } -// These are wrapper functions around ssgSetNearFar() and ssgSetFOV() -// which will post process and rewrite the resulting frustum if we -// want to do asymmetric view frustums. - -static void fgHackFrustum() { - - // specify a percent of the configured view frustum to actually - // display. This is a bit of a hack to achieve asymmetric view - // frustums. For instance, if you want to display two monitors - // side by side, you could specify each with a double fov, a 0.5 - // aspect ratio multiplier, and then the left side monitor would - // have a left_pct = 0.0, a right_pct = 0.5, a bottom_pct = 0.0, - // and a top_pct = 1.0. The right side monitor would have a - // left_pct = 0.5 and a right_pct = 1.0. - - static SGPropertyNode *left_pct - = fgGetNode("/sim/current-view/frustum-left-pct"); - static SGPropertyNode *right_pct - = fgGetNode("/sim/current-view/frustum-right-pct"); - static SGPropertyNode *bottom_pct - = fgGetNode("/sim/current-view/frustum-bottom-pct"); - static SGPropertyNode *top_pct - = fgGetNode("/sim/current-view/frustum-top-pct"); - osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); - double left, right; - double bottom, top; - double zNear, zFar; - if (viewer) - viewer->getCamera()->getProjectionMatrixAsFrustum(left, right, - bottom, top, - zNear, zFar); - else - sceneView->getProjectionMatrixAsFrustum(left, right, bottom, top, - zNear, zFar); - // cout << " l = " << f->getLeft() - // << " r = " << f->getRight() - // << " b = " << f->getBot() - // << " t = " << f->getTop() - // << " n = " << f->getNear() - // << " f = " << f->getFar() - // << endl; - - double width = right - left; - double height = top - bottom; - - double l, r, t, b; - - if ( left_pct != NULL ) { - l = left + width * left_pct->getDoubleValue(); - } else { - l = left; - } - - if ( right_pct != NULL ) { - r = left + width * right_pct->getDoubleValue(); - } else { - r = right; - } - - if ( bottom_pct != NULL ) { - b = bottom + height * bottom_pct->getDoubleValue(); - } else { - b = bottom; - } - - if ( top_pct != NULL ) { - t = bottom + height * top_pct->getDoubleValue(); - } else { - t = top; - } - if (viewer) - viewer->getCamera()->setProjectionMatrixAsFrustum(l, r, b, t, - zNear, zFar); - else - sceneView->setProjectionMatrixAsFrustum(l, r, b, t, zNear, zFar); -} - - // we need some static storage space for these values. However, we // can't store it in a renderer class object because the functions // that manipulate these are static. They are static so they can @@ -972,17 +904,11 @@ void FGRenderer::setFOV( float w, float h ) { fov_height = h; osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); if (viewer) - viewer->getCamera()->setProjectionMatrixAsPerspective(fov_height, - fov_width/fov_height, - fov_near, fov_far); + viewer->getCamera()->setProjectionMatrixAsPerspective(fov_height, 4.0/3.0, fov_near, fov_far); else sceneView->setProjectionMatrixAsPerspective(fov_height, fov_width/fov_height, fov_near, fov_far); - // fully specify the view frustum before hacking it (so we don't - // accumulate hacked effects - fgHackFrustum(); -// sgEnviro.setFOV( w, h ); } @@ -996,36 +922,29 @@ n = 0.1; fov_far = f; osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); if (viewer) - viewer->getCamera()->setProjectionMatrixAsPerspective(fov_height, - fov_width/fov_height, - fov_near, fov_far); - else + viewer->getCamera()->setProjectionMatrixAsPerspective(fov_height, 4.0/3.0, fov_near, fov_far); + else sceneView->setProjectionMatrixAsPerspective(fov_height, fov_width/fov_height, fov_near, fov_far); - // fully specify the view frustum before hacking it (so we don't - // accumulate hacked effects - fgHackFrustum(); } bool FGRenderer::pick( unsigned x, unsigned y, - std::vector& pickList ) + std::vector& pickList, + const osgGA::GUIEventAdapter* ea ) { osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); // wipe out the return ... pickList.resize(0); - osg::Node* sceneData = globals->get_scenery()->get_scene_graph(); - if (!sceneData) - return false; - osg::Viewport* viewport = 0; - osg::Matrix projection; - osg::Matrix modelview; - if (sceneView.valid()) { - viewport = sceneView->getViewport(); + osg::Node* sceneData = globals->get_scenery()->get_scene_graph(); + if (!sceneData) + return false; + + osg::Viewport* viewport = sceneView->getViewport(); if (!viewport) return false; // don't know why, but the update has partly happened somehow, @@ -1047,40 +966,64 @@ FGRenderer::pick( unsigned x, unsigned y, // accumulated transform if (!nodePath.empty()) modelview.preMult(computeLocalToWorld(nodePath.front())); - } else if (viewer) { - // I don't think the Viewer case needs to update the camera - // matrices before picking. The user has clicked on the old scene - // -- that which is displayed in the front buffer -- so we need to - // use the camera state in effect for that view of the scene. - osg::Camera *camera = viewer->getCamera(); - viewport = camera->getViewport(); - projection = camera->getProjectionMatrix(); - modelview = camera->getViewMatrix(); - // Accumulated transforms? Don't think that applies for the - // Viewer's camera. - } else { // we can get called early ... - return false; - } - // swap the y values ... - y = viewport->height() - y; - // set up the pick visitor - osgUtil::PickVisitor pickVisitor(viewport, projection, modelview, x, y); - sceneData->accept(pickVisitor); - if (!pickVisitor.hits()) - return false; - // collect all interaction callbacks on the pick ray. - // They get stored in the pickCallbacks list where they are sorted back - // to front and croasest to finest wrt the scenery node they are attached to - osgUtil::PickVisitor::LineSegmentHitListMap::const_iterator mi; - for (mi = pickVisitor.getSegHitList().begin(); - mi != pickVisitor.getSegHitList().end(); - ++mi) { - osgUtil::IntersectVisitor::HitList::const_iterator hi; - for (hi = mi->second.begin(); hi != mi->second.end(); ++hi) { - // ok, go back the nodes and ask for intersection callbacks, - // execute them in top down order - const osg::NodePath& np = hi->getNodePath(); + // swap the y values ... + y = viewport->height() - y; + // set up the pick visitor + osgUtil::PickVisitor pickVisitor(viewport, projection, modelview, x, y); + sceneData->accept(pickVisitor); + if (!pickVisitor.hits()) + return false; + + // collect all interaction callbacks on the pick ray. + // They get stored in the pickCallbacks list where they are sorted back + // to front and croasest to finest wrt the scenery node they are attached to + osgUtil::PickVisitor::LineSegmentHitListMap::const_iterator mi; + for (mi = pickVisitor.getSegHitList().begin(); + mi != pickVisitor.getSegHitList().end(); + ++mi) { + osgUtil::IntersectVisitor::HitList::const_iterator hi; + for (hi = mi->second.begin(); hi != mi->second.end(); ++hi) { + // ok, go back the nodes and ask for intersection callbacks, + // execute them in top down order + const osg::NodePath& np = hi->getNodePath(); + osg::NodePath::const_reverse_iterator npi; + for (npi = np.rbegin(); npi != np.rend(); ++npi) { + SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi); + if (!ud) + continue; + for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) { + SGPickCallback* pickCallback = ud->getPickCallback(i); + if (!pickCallback) + continue; + SGSceneryPick sceneryPick; + /// note that this is done totally in doubles instead of + /// just using getWorldIntersectionPoint + osg::Vec3d localPt = hi->getLocalIntersectPoint(); + sceneryPick.info.local = SGVec3d(localPt); + if (hi->getMatrix()) + sceneryPick.info.wgs84 = SGVec3d(localPt*(*hi->getMatrix())); + else + sceneryPick.info.wgs84 = SGVec3d(localPt); + sceneryPick.callback = pickCallback; + pickList.push_back(sceneryPick); + } + } + } + } + + return !pickList.empty(); + + } else if (viewer) { + + // just compute intersections in the viewers method ... + typedef osgUtil::LineSegmentIntersector::Intersections Intersections; + Intersections intersections; + viewer->computeIntersections(ea->getX(), ea->getY(), intersections); + + Intersections::iterator hit; + for (hit = intersections.begin(); hit != intersections.end(); ++hit) { + const osg::NodePath& np = hit->nodePath; osg::NodePath::const_reverse_iterator npi; for (npi = np.rbegin(); npi != np.rend(); ++npi) { SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi); @@ -1091,22 +1034,18 @@ FGRenderer::pick( unsigned x, unsigned y, if (!pickCallback) continue; SGSceneryPick sceneryPick; - /// note that this is done totally in doubles instead of - /// just using getWorldIntersectionPoint - osg::Vec3d localPt = hi->getLocalIntersectPoint(); - sceneryPick.info.local = SGVec3d(localPt); - if (hi->getMatrix()) - sceneryPick.info.wgs84 = SGVec3d(localPt*(*hi->getMatrix())); - else - sceneryPick.info.wgs84 = SGVec3d(localPt); + sceneryPick.info.local = SGVec3d(hit->getLocalIntersectPoint()); + sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint()); sceneryPick.callback = pickCallback; pickList.push_back(sceneryPick); } } } - } - return !pickList.empty(); + return !pickList.empty(); + } else { // we can get called early ... + return false; + } } bool fgDumpSceneGraphToFile(const char* filename) diff --git a/src/Main/renderer.hxx b/src/Main/renderer.hxx index 1ac1af354..ea14d3534 100644 --- a/src/Main/renderer.hxx +++ b/src/Main/renderer.hxx @@ -54,7 +54,8 @@ public: /** Just pick into the scene and return the pick callbacks on the way ... */ static bool pick( unsigned x, unsigned y, - std::vector& pickList ); + std::vector& pickList, + const osgGA::GUIEventAdapter* ea ); /** Get and set the OSG Viewer object, if any. */