From: timoore Date: Tue, 18 Nov 2008 22:45:57 +0000 (+0000) Subject: Cleanup of camera code in preperation for shadows X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=4f4434787fb40e02a35b401171f2a7370e0d5463;p=flightgear.git Cleanup of camera code in preperation for shadows Partition depth in CameraGroup: Remove the ViewPartionNode scenegraph node. The split rendering of the scene, done to avoid Z buffer precision problems, is now done by two slave cameras of the viewer. Rename FGManipulator to FGEventHandler. Remove virtual member functions that aren't required for event handlers. Begin using camera group properties to update cameras at runtime; Initially only the viewport properties are used. When no camera group is found in the property tree (the default), create the properties for one. Expose the default window by name. Add a test for Boost headers to configure.ac. Boost is now a dependency. Remove GLUT and SDL versions of the OSG graphics. --- diff --git a/configure.ac b/configure.ac index 600621681..377725771 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,14 @@ if test "x$with_osg" != "x" ; then EXTRA_DIRS="${EXTRA_DIRS} $with_osg" fi +# specify Boost location +AC_ARG_WITH(osg, [ --with-boost=PREFIX Specify the prefix path to Boost]) + +if test "x$with_boost" != "x" ; then + echo "Boost prefix is $with_boost" + EXTRA_DIRS="${EXTRA_DIRS} $with_boost" +fi + dnl Determine an extra directories to add to include/lib search paths case "${host}" in *-apple-darwin* | *-*-mingw32*) @@ -505,6 +513,15 @@ if test "x$ac_cv_header_osg_Version" != "xyes"; then exit fi +AC_CHECK_HEADER(boost/foreach.hpp) +if test "x$ac_cv_header_boost_foreach_hpp" != "xyes"; then + echo + echo "You *must* have the Boost libraries installed." + echo + echo "configure aborted." + exit +fi + # Find the OSG libraries. Note special handling for OS X frameworks case "${host}" in *-apple-darwin*) diff --git a/src/Main/CameraGroup.cxx b/src/Main/CameraGroup.cxx index 4c00ab6db..f218466bb 100644 --- a/src/Main/CameraGroup.cxx +++ b/src/Main/CameraGroup.cxx @@ -18,10 +18,11 @@ #include "globals.hxx" #include "renderer.hxx" -#include "FGManipulator.hxx" +#include "FGEventHandler.hxx" #include "WindowBuilder.hxx" #include "WindowSystemAdapter.hxx" #include +#include #include #include @@ -53,50 +54,149 @@ CameraGroup::CameraGroup(osgViewer::Viewer* viewer) : { } +} + +namespace +{ +using namespace osg; + +// Given a projection matrix, return a new one with the same frustum +// sides and new near / far values. + +void makeNewProjMat(Matrixd& oldProj, double znear, + double zfar, Matrixd& projection) +{ + projection = oldProj; + // Slightly inflate the near & far planes to avoid objects at the + // extremes being clipped out. + znear *= 0.999; + zfar *= 1.001; + + // Clamp the projection matrix z values to the range (near, far) + double epsilon = 1.0e-6; + if (fabs(projection(0,3)) < epsilon && + fabs(projection(1,3)) < epsilon && + fabs(projection(2,3)) < epsilon) { + // Projection is Orthographic + epsilon = -1.0/(zfar - znear); // Used as a temp variable + projection(2,2) = 2.0*epsilon; + projection(3,2) = (zfar + znear)*epsilon; + } else { + // Projection is Perspective + double trans_near = (-znear*projection(2,2) + projection(3,2)) / + (-znear*projection(2,3) + projection(3,3)); + double trans_far = (-zfar*projection(2,2) + projection(3,2)) / + (-zfar*projection(2,3) + projection(3,3)); + double ratio = fabs(2.0/(trans_near - trans_far)); + double center = -0.5*(trans_near + trans_far); + + projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, ratio, 0.0, + 0.0, 0.0, center*ratio, 1.0)); + } +} + +void installCullVisitor(Camera* camera) +{ +#if 0 // Not yet + osgViewer::Renderer* renderer + = static_cast(camera->getRenderer()); + for (int i = 0; i < 2; ++i) { + osgUtil::SceneView* sceneView = renderer->getSceneView(i); + sceneView->setCullVisitor(new simgear::EffectCullVisitor); + } +#endif +} +} + +namespace flightgear +{ CameraInfo* CameraGroup::addCamera(unsigned flags, Camera* camera, const Matrix& view, const Matrix& projection, bool useMasterSceneData) { - if ((flags & (VIEW_ABSOLUTE | PROJECTION_ABSOLUTE)) != 0) - camera->setReferenceFrame(Transform::ABSOLUTE_RF); - else - camera->setReferenceFrame(Transform::RELATIVE_RF); - CameraInfo* info = new CameraInfo(flags, camera); - _cameras.push_back(info); + CameraInfo* info = new CameraInfo(flags); + // The camera group will always update the camera + camera->setReferenceFrame(Transform::ABSOLUTE_RF); + + Camera* farCamera = 0; + if ((flags & (GUI | ORTHO)) == 0) { + farCamera = osg::clone(camera); + farCamera->setGraphicsContext(camera->getGraphicsContext()); + // Each camera's viewport is written when the window is + // resized; if the the viewport isn't copied here, it gets updated + // twice and ends up with the wrong value. + farCamera->setViewport(osg::clone(camera->getViewport())); + _viewer->addSlave(farCamera, view, projection, useMasterSceneData); + installCullVisitor(farCamera); + info->farCamera = farCamera; + info->farSlaveIndex = _viewer->getNumSlaves() - 1; + farCamera->setRenderOrder(Camera::NESTED_RENDER, info->farSlaveIndex); + camera->setCullMask(camera->getCullMask() & ~simgear::BACKGROUND_BIT); + } + camera->setClearMask(GL_DEPTH_BUFFER_BIT); _viewer->addSlave(camera, view, projection, useMasterSceneData); + installCullVisitor(camera); + info->camera = camera; info->slaveIndex = _viewer->getNumSlaves() - 1; + camera->setRenderOrder(Camera::NESTED_RENDER, info->slaveIndex); + _cameras.push_back(info); return info; } void CameraGroup::update(const osg::Vec3d& position, const osg::Quat& orientation) { - FGManipulator *manipulator - = dynamic_cast(_viewer->getCameraManipulator()); - if (!manipulator) - return; - manipulator->setPosition(position); - manipulator->setAttitude(orientation); - const Matrix masterView(manipulator->getInverseMatrix()); + const Matrix masterView(osg::Matrix::translate(-position) + * osg::Matrix::rotate(orientation.inverse())); + _viewer->getCamera()->setViewMatrix(masterView); const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix(); for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) { const CameraInfo* info = i->get(); - if ((info->flags & (VIEW_ABSOLUTE | PROJECTION_ABSOLUTE)) == 0) { - // Camera has relative reference frame and is updated by - // osg::View. - continue; - } const View::Slave& slave = _viewer->getSlave(info->slaveIndex); Camera* camera = info->camera.get(); + camera->getViewport()->setViewport(info->x, info->y, info->width, + info->height); + Matrix viewMatrix; if ((info->flags & VIEW_ABSOLUTE) != 0) - camera->setViewMatrix(slave._viewOffset); + viewMatrix = slave._viewOffset; else - camera->setViewMatrix(masterView * slave._viewOffset); + viewMatrix = masterView * slave._viewOffset; + camera->setViewMatrix(viewMatrix); + Matrix projectionMatrix; if ((info->flags & PROJECTION_ABSOLUTE) != 0) - camera->setProjectionMatrix(slave._projectionOffset); + projectionMatrix = slave._projectionOffset; else - camera->setViewMatrix(masterProj * slave._projectionOffset); + projectionMatrix = masterProj * slave._projectionOffset; + + if (!info->farCamera.valid()) { + camera->setProjectionMatrix(projectionMatrix); + } else { + Camera* farCamera = info->farCamera.get(); + farCamera->getViewport()->setViewport(info->x, info->y, info->width, + info->height); + farCamera->setViewMatrix(viewMatrix); + double left, right, bottom, top, parentNear, parentFar; + projectionMatrix.getFrustum(left, right, bottom, top, + parentNear, parentFar); + if (parentFar < 100.0) { + camera->setProjectionMatrix(projectionMatrix); + camera->setCullMask(camera->getCullMask() + | simgear::BACKGROUND_BIT); + farCamera->setNodeMask(0); + } else { + Matrix nearProj, farProj; + makeNewProjMat(projectionMatrix, parentNear, 100.0, nearProj); + makeNewProjMat(projectionMatrix, 100.0, parentFar, farProj); + camera->setProjectionMatrix(nearProj); + camera->setCullMask(camera->getCullMask() + & ~simgear::BACKGROUND_BIT); + farCamera->setProjectionMatrix(farProj); + farCamera->setNodeMask(camera->getNodeMask()); + } + } } } @@ -112,19 +212,71 @@ void CameraGroup::setCameraParameters(float vfov, float aspectRatio) namespace { -osg::Viewport* buildViewport(const SGPropertyNode* viewportNode) +// A raw value for property nodes that references a class member via +// an osg::ref_ptr. +template +class RefMember : public SGRawValue { - double x = viewportNode->getDoubleValue("x", 0.0); - double y = viewportNode->getDoubleValue("y", 0.0); - double width = viewportNode->getDoubleValue("width", 0.0); - double height = viewportNode->getDoubleValue("height", 0.0); - return new osg::Viewport(x, y, width, height); +public: + RefMember (C *obj, T C::*ptr) + : _obj(obj), _ptr(ptr) {} + virtual ~RefMember () {} + virtual T getValue () const + { + return _obj.get()->*_ptr; + } + virtual bool setValue (T value) + { + _obj.get()->*_ptr = value; + return true; + } + virtual SGRawValue * clone () const + { + return new RefMember(_obj.get(), _ptr); + } +private: + ref_ptr _obj; + T C::* const _ptr; +}; + +template +RefMember makeRefMember(C *obj, T C::*ptr) +{ + return RefMember(obj, ptr); +} + +template +void bindMemberToNode(SGPropertyNode* parent, const char* childName, + C* obj, T C::*ptr, T value) +{ + SGPropertyNode* valNode = parent->getNode(childName); + RefMember refMember = makeRefMember(obj, ptr); + if (!valNode) { + valNode = parent->getNode(childName, true); + valNode->tie(refMember, false); + setValue(valNode, value); + } else { + valNode->tie(refMember, true); + } +} + +void buildViewport(flightgear::CameraInfo* info, SGPropertyNode* viewportNode, + const osg::GraphicsContext::Traits *traits) +{ + using namespace flightgear; + bindMemberToNode(viewportNode, "x", info, &CameraInfo::x, 0.0); + bindMemberToNode(viewportNode, "y", info, &CameraInfo::y, 0.0); + bindMemberToNode(viewportNode, "width", info, &CameraInfo::width, + static_cast(traits->width)); + bindMemberToNode(viewportNode, "height", info, &CameraInfo::height, + static_cast(traits->height)); } } namespace flightgear { -CameraInfo* CameraGroup::buildCamera(const SGPropertyNode* cameraNode) + +CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode) { WindowBuilder *wBuild = WindowBuilder::getWindowBuilder(); const SGPropertyNode* windowNode = cameraNode->getNode("window"); @@ -144,18 +296,13 @@ CameraInfo* CameraGroup::buildCamera(const SGPropertyNode* cameraNode) Camera* camera = new Camera; camera->setAllowEventFocus(false); camera->setGraphicsContext(window->gc.get()); - // 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. - const SGPropertyNode* viewportNode = cameraNode->getNode("viewport"); - Viewport* viewport = 0; - if (viewportNode) { - viewport = buildViewport(viewportNode); - } else { - const GraphicsContext::Traits *traits = window->gc->getTraits(); - viewport = new Viewport(0, 0, traits->width, traits->height); - } - camera->setViewport(viewport); + camera->setViewport(new Viewport); + camera->setCullingMode(CullSettings::SMALL_FEATURE_CULLING + | CullSettings::VIEW_FRUSTUM_CULLING); + camera->setInheritanceMask(CullSettings::ALL_VARIABLES + & ~(CullSettings::CULL_MASK + | CullSettings::CULLING_MODE)); + osg::Matrix pOff; osg::Matrix vOff; const SGPropertyNode* viewNode = cameraNode->getNode("view"); @@ -219,10 +366,16 @@ CameraInfo* CameraGroup::buildCamera(const SGPropertyNode* cameraNode) double sheary = cameraNode->getDoubleValue("shear-y", 0); pOff.makeTranslate(-shearx, -sheary, 0); } - return addCamera(cameraFlags, camera, pOff, vOff); + CameraInfo* info = addCamera(cameraFlags, camera, pOff, vOff); + // 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. + SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true); + buildViewport(info, viewportNode, window->gc->getTraits()); + return info; } -CameraInfo* CameraGroup::buildGUICamera(const SGPropertyNode* cameraNode, +CameraInfo* CameraGroup::buildGUICamera(SGPropertyNode* cameraNode, GraphicsWindow* window) { WindowBuilder *wBuild = WindowBuilder::getWindowBuilder(); @@ -242,17 +395,7 @@ CameraInfo* CameraGroup::buildGUICamera(const SGPropertyNode* cameraNode, Camera* camera = new Camera; camera->setAllowEventFocus(false); camera->setGraphicsContext(window->gc.get()); - const SGPropertyNode* viewportNode = (cameraNode - ? cameraNode->getNode("viewport") - : 0); - Viewport* viewport = 0; - if (viewportNode) { - viewport = buildViewport(viewportNode); - } else { - const GraphicsContext::Traits *traits = window->gc->getTraits(); - viewport = new Viewport(0, 0, traits->width, traits->height); - } - camera->setViewport(viewport); + camera->setViewport(new Viewport); // XXX Camera needs to be drawn last; eventually the render order // should be assigned by a camera manager. camera->setRenderOrder(osg::Camera::POST_RENDER, 100); @@ -267,17 +410,20 @@ CameraInfo* CameraGroup::buildGUICamera(const SGPropertyNode* cameraNode, const int cameraFlags = GUI; CameraInfo* result = addCamera(cameraFlags, camera, Matrixd::identity(), Matrixd::identity(), false); + SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true); + buildViewport(result, viewportNode, window->gc->getTraits()); + // Disable statistics for the GUI camera. result->camera->setStats(0); return result; } CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer, - const SGPropertyNode* gnode) + SGPropertyNode* gnode) { CameraGroup* cgroup = new CameraGroup(viewer); for (int i = 0; i < gnode->nChildren(); ++i) { - const SGPropertyNode* pNode = gnode->getChild(i); + SGPropertyNode* pNode = gnode->getChild(i); const char* name = pNode->getName(); if (!strcmp(name, "camera")) { cgroup->buildCamera(pNode); @@ -290,6 +436,16 @@ CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer, return cgroup; } +void CameraGroup::setCameraCullMasks(Node::NodeMask nm) +{ + for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) { + if ((*i)->flags & GUI) + continue; + (*i)->camera->setCullMask(nm & ~simgear::BACKGROUND_BIT); + (*i)->farCamera->setCullMask(nm); + } +} + Camera* getGUICamera(CameraGroup* cgroup) { CameraGroup::CameraIterator end = cgroup->camerasEnd(); @@ -355,7 +511,7 @@ void warpGUIPointer(CameraGroup* cgroup, int x, int y) = dynamic_cast(guiCamera->getGraphicsContext()); if (!gw) return; - globals->get_renderer()->getManipulator()->setMouseWarped(); + globals->get_renderer()->getEventHandler()->setMouseWarped(); // Translate the warp request into the viewport of the GUI camera, // send the request to the window, then transform the coordinates // for the Viewer's event queue. diff --git a/src/Main/CameraGroup.hxx b/src/Main/CameraGroup.hxx index e76f3a5fa..19b8a9920 100644 --- a/src/Main/CameraGroup.hxx +++ b/src/Main/CameraGroup.hxx @@ -23,6 +23,7 @@ #include #include #include +#include // For osgUtil::LineSegmentIntersector::Intersections, which is a typedef. #include @@ -47,8 +48,9 @@ class GraphicsWindow; */ struct CameraInfo : public osg::Referenced { - CameraInfo(unsigned flags_, osg::Camera* camera_) - : flags(flags_), camera(camera_), slaveIndex(-1) + CameraInfo(unsigned flags_, osg::Camera* camera_ = 0) + : flags(flags_), camera(camera_), slaveIndex(-1), farSlaveIndex(-1), + x(0.0), y(0.0), width(0.0), height(0.0) { } /** Properties of the camera. @see CameraGroup::Flags. @@ -57,9 +59,21 @@ struct CameraInfo : public osg::Referenced /** the camera object */ osg::ref_ptr camera; + /** camera for rendering far field, if needed + */ + osg::ref_ptr farCamera; /** Index of this camera in the osgViewer::Viewer slave list. */ int slaveIndex; + /** index of far camera in slave list + */ + int farSlaveIndex; + /** Viewport parameters. + */ + double x; + double y; + double width; + double height; }; class CameraGroup : public osg::Referenced @@ -103,7 +117,7 @@ public: * @param cameraNode the property node. * @return a CameraInfo object for the camera. */ - CameraInfo* buildCamera(const SGPropertyNode* cameraNode); + CameraInfo* buildCamera(SGPropertyNode* cameraNode); /** Create a camera from properties that will draw the GUI and add * it to the camera group. * @param cameraNode the property node. This can be 0, in which @@ -112,7 +126,7 @@ public: * this is 0, the window is determined from the property node. * @return a CameraInfo object for the GUI camera. */ - CameraInfo* buildGUICamera(const SGPropertyNode* cameraNode, + CameraInfo* buildGUICamera(SGPropertyNode* cameraNode, GraphicsWindow* window = 0); /** Update the view for the camera group. * @param position the world position of the view @@ -153,7 +167,11 @@ public: * @param the camera group property node. */ static CameraGroup* buildCameraGroup(osgViewer::Viewer* viewer, - const SGPropertyNode* node); + SGPropertyNode* node); + /** Set the cull mask on all non-GUI cameras + */ + void setCameraCullMasks(osg::Node::NodeMask nm); + protected: CameraList _cameras; osg::ref_ptr _viewer; diff --git a/src/Main/FGEventHandler.cxx b/src/Main/FGEventHandler.cxx new file mode 100644 index 000000000..56dcb564c --- /dev/null +++ b/src/Main/FGEventHandler.cxx @@ -0,0 +1,361 @@ +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include + +#include +#include
+#include "CameraGroup.hxx" +#include "FGEventHandler.hxx" +#include "WindowSystemAdapter.hxx" + +#if !defined(X_DISPLAY_MISSING) +#define X_DOUBLE_SCROLL_BUG 1 +#endif + +namespace flightgear +{ +const int displayStatsKey = 1; +const int printStatsKey = 2; + + +// The manipulator is responsible for updating a Viewer's camera. Its +// event handling method is also a convenient place to run the FG idle +// and draw handlers. + +FGEventHandler::FGEventHandler() : + idleHandler(0), + drawHandler(0), + windowResizeHandler(0), + keyHandler(0), + mouseClickHandler(0), + mouseMotionHandler(0), + statsHandler(new osgViewer::StatsHandler), + statsEvent(new osgGA::GUIEventAdapter), + statsType(osgViewer::StatsHandler::NO_STATS), + currentModifiers(0), + resizable(true), + mouseWarped(false), + scrollButtonPressed(false) +{ + using namespace osgGA; + statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey); + statsHandler->setKeyEventPrintsOutStats(printStatsKey); + statsEvent->setEventType(GUIEventAdapter::KEYDOWN); + + // OSG reports NumPad keycodes independent of the NumLock modifier. + // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we + // have to generate the locked keys ourselves. + numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0'; + numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8'; + numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9'; + + for (int i = 0; i < 128; i++) + release_keys[i] = i; +} + +namespace +{ +// Translate OSG modifier mask to FG modifier mask. +int osgToFGModifiers(int modifiers) +{ + int result = 0; + if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT) + result |= KEYMOD_SHIFT; + + if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL) + result |= KEYMOD_CTRL; + + if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT) + result |= KEYMOD_ALT; + + if (modifiers & osgGA::GUIEventAdapter::MODKEY_META) + result |= KEYMOD_META; + + if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER) + result |= KEYMOD_SUPER; + + if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER) + result |= KEYMOD_HYPER; + return result; +} +} + +#if 0 +void FGEventHandler::init(const osgGA::GUIEventAdapter& ea, + osgGA::GUIActionAdapter& us) +{ + currentModifiers = osgToFGModifiers(ea.getModKeyMask()); + (void)handle(ea, us); +} +#endif + +// Calculate event coordinates in the viewport of the GUI camera, if +// possible. Otherwise return false and (-1, -1). +namespace +{ +bool +eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us, + int& x, int& y) +{ + x = -1; + y = -1; + + const osg::GraphicsContext* eventGC = ea.getGraphicsContext(); + const osg::GraphicsContext::Traits* traits = eventGC->getTraits(); + osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault()); + if (!guiCamera) + return false; + osg::Viewport* vport = guiCamera->getViewport(); + if (!vport) + return false; + + // Scale x, y to the dimensions of the window + double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin())) + * (float)traits->width); + double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin())) + * (float)traits->height); + if (vport->x() <= wx && wx <= vport->x() + vport->width() + && vport->y() <= wy && wy <= vport->y() + vport->height()) { + // Finally, into viewport coordinates. Change y to "increasing + // downwards". + x = wx - vport->x(); + y = vport->height() - (wy - vport->y()); + return true; + } else { + return false; + } +} +} + +bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea, + osgGA::GUIActionAdapter& us) +{ + int x = 0; + int y = 0; + + switch (ea.getEventType()) { + case osgGA::GUIEventAdapter::FRAME: + if (idleHandler) + (*idleHandler)(); + if (drawHandler) + (*drawHandler)(); + mouseWarped = false; + handleStats(us); + return true; + case osgGA::GUIEventAdapter::KEYDOWN: + case osgGA::GUIEventAdapter::KEYUP: + { + int key, modmask; + handleKey(ea, key, modmask); + eventToViewport(ea, us, x, y); + if (keyHandler) + (*keyHandler)(key, modmask, x, y); + return true; + } + case osgGA::GUIEventAdapter::PUSH: + case osgGA::GUIEventAdapter::RELEASE: + { + bool mainWindow = eventToViewport(ea, us, x, y); + int button = 0; + switch (ea.getButton()) { + case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON: + button = 0; + break; + case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON: + button = 1; + break; + case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON: + button = 2; + break; + } + if (mouseClickHandler) + (*mouseClickHandler)(button, + (ea.getEventType() + == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea); + return true; + } + case osgGA::GUIEventAdapter::SCROLL: + { + bool mainWindow = eventToViewport(ea, us, x, y); +#ifdef X_DOUBLE_SCROLL_BUG + scrollButtonPressed = !scrollButtonPressed; + if (!scrollButtonPressed) // Drop the button release event + return true; +#endif + int button; + if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP) + button = 3; + else + button = 4; + if (mouseClickHandler) { + (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea); + (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea); + } + return true; + } + case osgGA::GUIEventAdapter::MOVE: + case osgGA::GUIEventAdapter::DRAG: + // If we warped the mouse, then disregard all pointer motion + // events for this frame. We really want to flush the event + // queue of mouse events, but don't have the ability to do + // that with osgViewer. + if (mouseWarped) + return true; + if (eventToViewport(ea, us, x, y) && mouseMotionHandler) + (*mouseMotionHandler)(x, y); + return true; + case osgGA::GUIEventAdapter::RESIZE: + if (resizable && windowResizeHandler) + (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight()); + return true; + case osgGA::GUIEventAdapter::CLOSE_WINDOW: + case osgGA::GUIEventAdapter::QUIT_APPLICATION: + fgOSExit(0); + return true; + default: + return false; + } +} + +void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key, + int& modifiers) +{ + using namespace osgGA; + key = ea.getKey(); + // XXX Probably other translations are needed too. + switch (key) { + case GUIEventAdapter::KEY_Escape: key = 0x1b; break; + case GUIEventAdapter::KEY_Return: key = '\n'; break; + case GUIEventAdapter::KEY_BackSpace: key = '\b'; break; + case GUIEventAdapter::KEY_Delete: key = 0x7f; break; + case GUIEventAdapter::KEY_Tab: key = '\t'; break; + case GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break; + case GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break; + case GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break; + case GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break; + case GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break; + case GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break; + case GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break; + case GUIEventAdapter::KEY_End: key = PU_KEY_END; break; + case GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break; + case GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break; + case GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break; + case GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break; + case GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break; + case GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break; + case GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break; + case GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break; + case GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break; + case GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break; + case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break; + case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break; + case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break; + case GUIEventAdapter::KEY_KP_Delete: key = '.'; break; + case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break; + case GUIEventAdapter::KEY_KP_Add: key = '+'; break; + case GUIEventAdapter::KEY_KP_Divide: key = '/'; break; + case GUIEventAdapter::KEY_KP_Multiply: key = '*'; break; + case GUIEventAdapter::KEY_KP_Subtract: key = '-'; break; + } + osgGA::GUIEventAdapter::EventType eventType = ea.getEventType(); + + std::map::iterator numPadIter = numlockKeyMap.find(key); + + if (numPadIter != numlockKeyMap.end()) { + if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) { + key = numPadIter->second; + } + } + + modifiers = osgToFGModifiers(ea.getModKeyMask()); + currentModifiers = modifiers; + if (eventType == osgGA::GUIEventAdapter::KEYUP) + modifiers |= KEYMOD_RELEASED; + + // Release the letter key, for which the key press was reported. This + // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release + // correctly. + if (key >= 0 && key < 128) { + if (modifiers & KEYMOD_RELEASED) { + key = release_keys[key]; + } else { + release_keys[key] = key; + if (key >= 1 && key <= 26) { + release_keys[key + '@'] = key; + release_keys[key + '`'] = key; + } else if (key >= 'A' && key <= 'Z') { + release_keys[key - '@'] = key; + release_keys[tolower(key)] = key; + } else if (key >= 'a' && key <= 'z') { + release_keys[key - '`'] = key; + release_keys[toupper(key)] = key; + } + } + } +} + +void FGEventHandler::handleStats(osgGA::GUIActionAdapter& us) +{ + static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true); + static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true); + + int type = display->getIntValue() % osgViewer::StatsHandler::LAST; + if (type != statsType) { + statsEvent->setKey(displayStatsKey); + do { + statsType = (statsType + 1) % osgViewer::StatsHandler::LAST; + statsHandler->handle(*statsEvent, us); + } while (statsType != type); + + display->setIntValue(statsType); + } + + if (print->getBoolValue()) { + statsEvent->setKey(printStatsKey); + statsHandler->handle(*statsEvent, us); + print->setBoolValue(false); + } +} + +void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, + double& x, double& y) +{ + using namespace osg; + const GraphicsContext* gc = ea->getGraphicsContext(); + const GraphicsContext::Traits* traits = gc->getTraits() ; + // Scale x, y to the dimensions of the window + x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin())) + * (double)traits->width); + y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin())) + * (double)traits->height); + if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) + y = (double)traits->height - y; +} + +void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea, + double& x, double& y) +{ + using namespace osg; + const GraphicsContext* gc = ea->getGraphicsContext(); + const GraphicsContext::Traits* traits = gc->getTraits() ; + // Scale x, y to the dimensions of the window + x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin())) + * (double)traits->width); + y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin())) + * (double)traits->height); + if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) + y = (double)traits->height - y; +} +} diff --git a/src/Main/FGEventHandler.hxx b/src/Main/FGEventHandler.hxx new file mode 100644 index 000000000..080d5afa1 --- /dev/null +++ b/src/Main/FGEventHandler.hxx @@ -0,0 +1,129 @@ +#ifndef FGEVENTHANDLER_H +#define FGEVENTHANDLER_H 1 + +#include +#include +#include +#include + +#include "fg_os.hxx" + +namespace flightgear +{ +class FGEventHandler : public osgGA::GUIEventHandler { +public: + FGEventHandler(); + + virtual ~FGEventHandler() {} + + virtual const char* className() const {return "FGEventHandler"; } +#if 0 + virtual void init(const osgGA::GUIEventAdapter& ea, + osgGA::GUIActionAdapter& us); +#endif + virtual bool handle(const osgGA::GUIEventAdapter& ea, + osgGA::GUIActionAdapter& us); + + void setIdleHandler(fgIdleHandler idleHandler) + { + this->idleHandler = idleHandler; + } + + fgIdleHandler getIdleHandler() const + { + return idleHandler; + } + + void setDrawHandler(fgDrawHandler drawHandler) + { + this->drawHandler = drawHandler; + } + + fgDrawHandler getDrawHandler() const + { + return drawHandler; + } + + void setWindowResizeHandler(fgWindowResizeHandler windowResizeHandler) + { + this->windowResizeHandler = windowResizeHandler; + } + + fgWindowResizeHandler getWindowResizeHandler() const + { + return windowResizeHandler; + } + + void setKeyHandler(fgKeyHandler keyHandler) + { + this->keyHandler = keyHandler; + } + + fgKeyHandler getKeyHandler() const + { + return keyHandler; + } + + void setMouseClickHandler(fgMouseClickHandler mouseClickHandler) + { + this->mouseClickHandler = mouseClickHandler; + } + + fgMouseClickHandler getMouseClickHandler() + { + return mouseClickHandler; + } + + void setMouseMotionHandler(fgMouseMotionHandler mouseMotionHandler) + { + this->mouseMotionHandler = mouseMotionHandler; + } + + fgMouseMotionHandler getMouseMotionHandler() + { + return mouseMotionHandler; + } + + int getCurrentModifiers() const + { + return currentModifiers; + } + + void setMouseWarped() + { + mouseWarped = true; + } + + /** Whether or not resizing is supported. It might not be when + * using multiple displays. + */ + bool getResizable() { return resizable; } + void setResizable(bool _resizable) { resizable = _resizable; } + +protected: + osg::ref_ptr _node; + fgIdleHandler idleHandler; + fgDrawHandler drawHandler; + fgWindowResizeHandler windowResizeHandler; + fgKeyHandler keyHandler; + fgMouseClickHandler mouseClickHandler; + fgMouseMotionHandler mouseMotionHandler; + osg::ref_ptr statsHandler; + osg::ref_ptr statsEvent; + int statsType; + int currentModifiers; + std::map numlockKeyMap; + void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers); + bool resizable; + bool mouseWarped; + // workaround for osgViewer double scroll events + bool scrollButtonPressed; + int release_keys[128]; + void handleStats(osgGA::GUIActionAdapter& us); +}; + +void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y); +void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea, + double& x, double& y); +} +#endif diff --git a/src/Main/FGManipulator.cxx b/src/Main/FGManipulator.cxx deleted file mode 100644 index b6d761f48..000000000 --- a/src/Main/FGManipulator.cxx +++ /dev/null @@ -1,393 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include -#endif -#include -#include -#include -#include -#include - -#include -#include
-#include "CameraGroup.hxx" -#include "FGManipulator.hxx" -#include "WindowSystemAdapter.hxx" - -#if !defined(X_DISPLAY_MISSING) -#define X_DOUBLE_SCROLL_BUG 1 -#endif - -namespace flightgear -{ -const int displayStatsKey = 1; -const int printStatsKey = 2; - - -// The manipulator is responsible for updating a Viewer's camera. Its -// event handling method is also a convenient place to run the FG idle -// and draw handlers. - -FGManipulator::FGManipulator() : - idleHandler(0), - drawHandler(0), - windowResizeHandler(0), - keyHandler(0), - mouseClickHandler(0), - mouseMotionHandler(0), - statsHandler(new osgViewer::StatsHandler), - statsEvent(new osgGA::GUIEventAdapter), - statsType(osgViewer::StatsHandler::NO_STATS), - currentModifiers(0), - resizable(true), - mouseWarped(false), - scrollButtonPressed(false) -{ - using namespace osgGA; - statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey); - statsHandler->setKeyEventPrintsOutStats(printStatsKey); - statsEvent->setEventType(GUIEventAdapter::KEYDOWN); - - // OSG reports NumPad keycodes independent of the NumLock modifier. - // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we - // have to generate the locked keys ourselves. - numlockKeyMap[GUIEventAdapter::KEY_KP_Insert] = '0'; - numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8'; - numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9'; - - for (int i = 0; i < 128; i++) - release_keys[i] = i; -} - -void FGManipulator::setByMatrix(const osg::Matrixd& matrix) -{ - // Yuck - position = matrix.getTrans(); - attitude = matrix.getRotate(); -} - -osg::Matrixd FGManipulator::getMatrix() const -{ - return osg::Matrixd::rotate(attitude) * osg::Matrixd::translate(position); -} - -osg::Matrixd FGManipulator::getInverseMatrix() const -{ - return (osg::Matrixd::translate(-position) - * osg::Matrixd::rotate(attitude.inverse())) ; -} - -// Not used, but part of the interface. -void FGManipulator::setNode(osg::Node* node) -{ - _node = node; -} - -const osg::Node* FGManipulator::getNode() const -{ - return _node.get(); -} - -osg::Node* FGManipulator::getNode() -{ - return _node.get(); -} - -namespace -{ -// Translate OSG modifier mask to FG modifier mask. -int osgToFGModifiers(int modifiers) -{ - int result = 0; - if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT) - result |= KEYMOD_SHIFT; - - if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL) - result |= KEYMOD_CTRL; - - if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT) - result |= KEYMOD_ALT; - - if (modifiers & osgGA::GUIEventAdapter::MODKEY_META) - result |= KEYMOD_META; - - if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER) - result |= KEYMOD_SUPER; - - if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER) - result |= KEYMOD_HYPER; - return result; -} -} - -void FGManipulator::init(const osgGA::GUIEventAdapter& ea, - osgGA::GUIActionAdapter& us) -{ - currentModifiers = osgToFGModifiers(ea.getModKeyMask()); - (void)handle(ea, us); -} - -// Calculate event coordinates in the viewport of the GUI camera, if -// possible. Otherwise return false and (-1, -1). -namespace -{ -bool -eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us, - int& x, int& y) -{ - x = -1; - y = -1; - - const osg::GraphicsContext* eventGC = ea.getGraphicsContext(); - const osg::GraphicsContext::Traits* traits = eventGC->getTraits(); - osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault()); - if (!guiCamera) - return false; - osg::Viewport* vport = guiCamera->getViewport(); - if (!vport) - return false; - - // Scale x, y to the dimensions of the window - double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin())) - * (float)traits->width); - double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin())) - * (float)traits->height); - if (vport->x() <= wx && wx <= vport->x() + vport->width() - && vport->y() <= wy && wy <= vport->y() + vport->height()) { - // Finally, into viewport coordinates. Change y to "increasing - // downwards". - x = wx - vport->x(); - y = vport->height() - (wy - vport->y()); - return true; - } else { - return false; - } -} -} - -bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea, - osgGA::GUIActionAdapter& us) -{ - int x = 0; - int y = 0; - - switch (ea.getEventType()) { - case osgGA::GUIEventAdapter::FRAME: - if (idleHandler) - (*idleHandler)(); - if (drawHandler) - (*drawHandler)(); - mouseWarped = false; - handleStats(us); - return true; - case osgGA::GUIEventAdapter::KEYDOWN: - case osgGA::GUIEventAdapter::KEYUP: - { - int key, modmask; - handleKey(ea, key, modmask); - eventToViewport(ea, us, x, y); - if (keyHandler) - (*keyHandler)(key, modmask, x, y); - return true; - } - case osgGA::GUIEventAdapter::PUSH: - case osgGA::GUIEventAdapter::RELEASE: - { - bool mainWindow = eventToViewport(ea, us, x, y); - int button = 0; - switch (ea.getButton()) { - case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON: - button = 0; - break; - case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON: - button = 1; - break; - case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON: - button = 2; - break; - } - if (mouseClickHandler) - (*mouseClickHandler)(button, - (ea.getEventType() - == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea); - return true; - } - case osgGA::GUIEventAdapter::SCROLL: - { - bool mainWindow = eventToViewport(ea, us, x, y); -#ifdef X_DOUBLE_SCROLL_BUG - scrollButtonPressed = !scrollButtonPressed; - if (!scrollButtonPressed) // Drop the button release event - return true; -#endif - int button; - if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP) - button = 3; - else - button = 4; - if (mouseClickHandler) { - (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea); - (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea); - } - return true; - } - case osgGA::GUIEventAdapter::MOVE: - case osgGA::GUIEventAdapter::DRAG: - // If we warped the mouse, then disregard all pointer motion - // events for this frame. We really want to flush the event - // queue of mouse events, but don't have the ability to do - // that with osgViewer. - if (mouseWarped) - return true; - if (eventToViewport(ea, us, x, y) && mouseMotionHandler) - (*mouseMotionHandler)(x, y); - return true; - case osgGA::GUIEventAdapter::RESIZE: - if (resizable && windowResizeHandler) - (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight()); - return true; - case osgGA::GUIEventAdapter::CLOSE_WINDOW: - case osgGA::GUIEventAdapter::QUIT_APPLICATION: - fgOSExit(0); - return true; - default: - return false; - } -} - -void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key, - int& modifiers) -{ - using namespace osgGA; - key = ea.getKey(); - // XXX Probably other translations are needed too. - switch (key) { - case GUIEventAdapter::KEY_Escape: key = 0x1b; break; - case GUIEventAdapter::KEY_Return: key = '\n'; break; - case GUIEventAdapter::KEY_BackSpace: key = '\b'; break; - case GUIEventAdapter::KEY_Delete: key = 0x7f; break; - case GUIEventAdapter::KEY_Tab: key = '\t'; break; - case GUIEventAdapter::KEY_Left: key = PU_KEY_LEFT; break; - case GUIEventAdapter::KEY_Up: key = PU_KEY_UP; break; - case GUIEventAdapter::KEY_Right: key = PU_KEY_RIGHT; break; - case GUIEventAdapter::KEY_Down: key = PU_KEY_DOWN; break; - case GUIEventAdapter::KEY_Page_Up: key = PU_KEY_PAGE_UP; break; - case GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break; - case GUIEventAdapter::KEY_Home: key = PU_KEY_HOME; break; - case GUIEventAdapter::KEY_End: key = PU_KEY_END; break; - case GUIEventAdapter::KEY_Insert: key = PU_KEY_INSERT; break; - case GUIEventAdapter::KEY_F1: key = PU_KEY_F1; break; - case GUIEventAdapter::KEY_F2: key = PU_KEY_F2; break; - case GUIEventAdapter::KEY_F3: key = PU_KEY_F3; break; - case GUIEventAdapter::KEY_F4: key = PU_KEY_F4; break; - case GUIEventAdapter::KEY_F5: key = PU_KEY_F5; break; - case GUIEventAdapter::KEY_F6: key = PU_KEY_F6; break; - case GUIEventAdapter::KEY_F7: key = PU_KEY_F7; break; - case GUIEventAdapter::KEY_F8: key = PU_KEY_F8; break; - case GUIEventAdapter::KEY_F9: key = PU_KEY_F9; break; - case GUIEventAdapter::KEY_F10: key = PU_KEY_F10; break; - case GUIEventAdapter::KEY_F11: key = PU_KEY_F11; break; - case GUIEventAdapter::KEY_F12: key = PU_KEY_F12; break; - case GUIEventAdapter::KEY_KP_Delete: key = '.'; break; - case GUIEventAdapter::KEY_KP_Enter: key = '\r'; break; - case GUIEventAdapter::KEY_KP_Add: key = '+'; break; - case GUIEventAdapter::KEY_KP_Divide: key = '/'; break; - case GUIEventAdapter::KEY_KP_Multiply: key = '*'; break; - case GUIEventAdapter::KEY_KP_Subtract: key = '-'; break; - } - osgGA::GUIEventAdapter::EventType eventType = ea.getEventType(); - - std::map::iterator numPadIter = numlockKeyMap.find(key); - - if (numPadIter != numlockKeyMap.end()) { - if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) { - key = numPadIter->second; - } - } - - modifiers = osgToFGModifiers(ea.getModKeyMask()); - currentModifiers = modifiers; - if (eventType == osgGA::GUIEventAdapter::KEYUP) - modifiers |= KEYMOD_RELEASED; - - // Release the letter key, for which the key press was reported. This - // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release - // correctly. - if (key >= 0 && key < 128) { - if (modifiers & KEYMOD_RELEASED) { - key = release_keys[key]; - } else { - release_keys[key] = key; - if (key >= 1 && key <= 26) { - release_keys[key + '@'] = key; - release_keys[key + '`'] = key; - } else if (key >= 'A' && key <= 'Z') { - release_keys[key - '@'] = key; - release_keys[tolower(key)] = key; - } else if (key >= 'a' && key <= 'z') { - release_keys[key - '`'] = key; - release_keys[toupper(key)] = key; - } - } - } -} - -void FGManipulator::handleStats(osgGA::GUIActionAdapter& us) -{ - static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true); - static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true); - - int type = display->getIntValue() % osgViewer::StatsHandler::LAST; - if (type != statsType) { - statsEvent->setKey(displayStatsKey); - do { - statsType = (statsType + 1) % osgViewer::StatsHandler::LAST; - statsHandler->handle(*statsEvent, us); - } while (statsType != type); - - display->setIntValue(statsType); - } - - if (print->getBoolValue()) { - statsEvent->setKey(printStatsKey); - statsHandler->handle(*statsEvent, us); - print->setBoolValue(false); - } -} - -void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, - double& x, double& y) -{ - using namespace osg; - const GraphicsContext* gc = ea->getGraphicsContext(); - const GraphicsContext::Traits* traits = gc->getTraits() ; - // Scale x, y to the dimensions of the window - x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin())) - * (double)traits->width); - y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin())) - * (double)traits->height); - if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) - y = (double)traits->height - y; -} - -void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea, - double& x, double& y) -{ - using namespace osg; - const GraphicsContext* gc = ea->getGraphicsContext(); - const GraphicsContext::Traits* traits = gc->getTraits() ; - // Scale x, y to the dimensions of the window - x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin())) - * (double)traits->width); - y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin())) - * (double)traits->height); - if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) - y = (double)traits->height - y; -} -} diff --git a/src/Main/FGManipulator.hxx b/src/Main/FGManipulator.hxx deleted file mode 100644 index cc1c5f552..000000000 --- a/src/Main/FGManipulator.hxx +++ /dev/null @@ -1,152 +0,0 @@ -#ifndef FGMANIPULATOR_H -#define FGMANIPULATOR_H 1 - -#include -#include -#include -#include - -#include "fg_os.hxx" - -namespace flightgear -{ -class FGManipulator : public osgGA::MatrixManipulator { -public: - FGManipulator(); - - virtual ~FGManipulator() {} - - virtual const char* className() const {return "FGManipulator"; } - - /** set the position of the matrix manipulator using a 4x4 Matrix.*/ - virtual void setByMatrix(const osg::Matrixd& matrix); - - virtual void setByInverseMatrix(const osg::Matrixd& matrix) - { setByMatrix(osg::Matrixd::inverse(matrix)); } - - /** get the position of the manipulator as 4x4 Matrix.*/ - virtual osg::Matrixd getMatrix() const; - - /** get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ - virtual osg::Matrixd getInverseMatrix() const; - - virtual void setNode(osg::Node* node); - - const osg::Node* getNode() const; - - osg::Node* getNode(); - - virtual void init(const osgGA::GUIEventAdapter& ea, - osgGA::GUIActionAdapter& us); - - virtual bool handle(const osgGA::GUIEventAdapter& ea, - osgGA::GUIActionAdapter& us); - - void setIdleHandler(fgIdleHandler idleHandler) - { - this->idleHandler = idleHandler; - } - - fgIdleHandler getIdleHandler() const - { - return idleHandler; - } - - void setDrawHandler(fgDrawHandler drawHandler) - { - this->drawHandler = drawHandler; - } - - fgDrawHandler getDrawHandler() const - { - return drawHandler; - } - - void setWindowResizeHandler(fgWindowResizeHandler windowResizeHandler) - { - this->windowResizeHandler = windowResizeHandler; - } - - fgWindowResizeHandler getWindowResizeHandler() const - { - return windowResizeHandler; - } - - void setKeyHandler(fgKeyHandler keyHandler) - { - this->keyHandler = keyHandler; - } - - fgKeyHandler getKeyHandler() const - { - return keyHandler; - } - - void setMouseClickHandler(fgMouseClickHandler mouseClickHandler) - { - this->mouseClickHandler = mouseClickHandler; - } - - fgMouseClickHandler getMouseClickHandler() - { - return mouseClickHandler; - } - - void setMouseMotionHandler(fgMouseMotionHandler mouseMotionHandler) - { - this->mouseMotionHandler = mouseMotionHandler; - } - - fgMouseMotionHandler getMouseMotionHandler() - { - return mouseMotionHandler; - } - - int getCurrentModifiers() const - { - return currentModifiers; - } - - void setMouseWarped() - { - mouseWarped = true; - } - - void setPosition(const osg::Vec3d position) { this->position = position; } - void setAttitude(const osg::Quat attitude) { this->attitude = attitude; } - - /** Whether or not resizing is supported. It might not be when - * using multiple displays. - */ - bool getResizable() { return resizable; } - void setResizable(bool _resizable) { resizable = _resizable; } - -protected: - osg::ref_ptr _node; - fgIdleHandler idleHandler; - fgDrawHandler drawHandler; - fgWindowResizeHandler windowResizeHandler; - fgKeyHandler keyHandler; - fgMouseClickHandler mouseClickHandler; - fgMouseMotionHandler mouseMotionHandler; - osg::ref_ptr statsHandler; - osg::ref_ptr statsEvent; - int statsType; - int currentModifiers; - std::map numlockKeyMap; - osg::Vec3d position; - osg::Quat attitude; - void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers); - bool resizable; - bool mouseWarped; - // workaround for osgViewer double scroll events - bool scrollButtonPressed; - int release_keys[128]; - void handleStats(osgGA::GUIActionAdapter& us); -}; - -void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y); -void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea, - double& x, double& y); -} -#endif diff --git a/src/Main/Makefile.am b/src/Main/Makefile.am index 0930f3121..0af345bad 100644 --- a/src/Main/Makefile.am +++ b/src/Main/Makefile.am @@ -1,5 +1,5 @@ EXTRA_DIST = 3dfx.sh runfgfs.in runfgfs.bat.in \ - fg_os_sdl.cxx fg_os.cxx fg_os_osgviewer.cxx fg_os.hxx + fg_os_osgviewer.cxx fg_os.hxx MPLAYER_LIBS = $(top_builddir)/src/MultiPlayer/libMultiPlayer.a @@ -15,16 +15,7 @@ else THREAD_LIBS = endif -GFX_COMMON = fg_os_common.cxx fg_os.hxx -if USE_SDL -GFX_CODE = fg_os_sdl.cxx $(GFX_COMMON) -else -if USE_GLUT -GFX_CODE = fg_os.cxx $(GFX_COMMON) -else -GFX_CODE = fg_os_osgviewer.cxx $(GFX_COMMON) -endif -endif +GFX_CODE = fg_os_osgviewer.cxx fg_os_common.cxx fg_os.hxx JSBSIM_LIBS = \ $(top_builddir)/src/FDM/JSBSim/libJSBSim.a \ @@ -61,7 +52,7 @@ libMain_a_SOURCES = \ viewer.cxx viewer.hxx \ viewmgr.cxx viewmgr.hxx \ CameraGroup.cxx CameraGroup.hxx \ - FGManipulator.cxx FGManipulator.hxx \ + FGEventHandler.cxx FGEventHandler.hxx \ ViewPartitionNode.cxx ViewPartitionNode.hxx \ WindowSystemAdapter.hxx WindowSystemAdapter.cxx \ WindowBuilder.hxx WindowBuilder.cxx \ diff --git a/src/Main/WindowBuilder.cxx b/src/Main/WindowBuilder.cxx index aaabbb2db..40ee6a5b0 100644 --- a/src/Main/WindowBuilder.cxx +++ b/src/Main/WindowBuilder.cxx @@ -35,6 +35,8 @@ string makeName(const string& prefix, int num) ref_ptr WindowBuilder::windowBuilder; +const string WindowBuilder::defaultWindowName("FlightGear"); + void WindowBuilder::initWindowBuilder(bool stencil) { windowBuilder = new WindowBuilder(stencil); @@ -204,14 +206,18 @@ GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode) return 0; } } else { + // XXX What if the window has no traits, but does have a name? + // We should create a "default window" registered with that name. return getDefaultWindow(); } } GraphicsWindow* WindowBuilder::getDefaultWindow() { - if (defaultWindow.valid()) - return defaultWindow.get(); + GraphicsWindow* defaultWindow + = WindowSystemAdapter::getWSA()->findWindow(defaultWindowName); + if (defaultWindow) + return defaultWindow; GraphicsContext::Traits* traits = new GraphicsContext::Traits(*defaultTraits); traits->windowName = "FlightGear"; @@ -219,8 +225,8 @@ GraphicsWindow* WindowBuilder::getDefaultWindow() if (gc) { gc->realize(); defaultWindow = WindowSystemAdapter::getWSA() - ->registerWindow(gc, traits->windowName); - return defaultWindow.get(); + ->registerWindow(gc, defaultWindowName); + return defaultWindow; } else { return 0; } diff --git a/src/Main/WindowBuilder.hxx b/src/Main/WindowBuilder.hxx index 287d4cee8..92e158bb8 100644 --- a/src/Main/WindowBuilder.hxx +++ b/src/Main/WindowBuilder.hxx @@ -54,13 +54,16 @@ public: * @return the default graphics window */ GraphicsWindow* getDefaultWindow(); + /** Get the name used to look up the default window. + */ + const std::string& getDefaultWindowName() { return defaultWindowName; } protected: WindowBuilder(bool stencil); static osg::GraphicsContext::Traits* makeDefaultTraits(bool stencil); osg::ref_ptr defaultTraits; int defaultCounter; static osg::ref_ptr windowBuilder; - osg::ref_ptr defaultWindow; + static const std::string defaultWindowName; }; /** Silly function for making the default window and camera diff --git a/src/Main/fg_os.cxx b/src/Main/fg_os.cxx deleted file mode 100644 index dfce9b2aa..000000000 --- a/src/Main/fg_os.cxx +++ /dev/null @@ -1,299 +0,0 @@ -#ifndef _MSC_VER // MSVC really needs a definition for wchar_t -#define _WCHAR_T_DEFINED 1 // Glut needs this, or else it tries to - // redefine it -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include - -#include - -#if defined( __APPLE__) -# include -#else -# include -#endif -#include - -#include -#include "fg_os.hxx" -#include "globals.hxx" -#include "renderer.hxx" -#include "fg_props.hxx" -#include "WindowSystemAdapter.hxx" -#include "CameraGroup.hxx" - -using namespace flightgear; - -// -// Native glut callbacks. -// These translate the glut event model into osgGA events -// - -static osg::ref_ptr viewer; -static osg::ref_ptr gw; - -static int GlutModifiers = 0; -static unsigned int getOSGModifiers(int modifiers); - -static void callKeyHandler(int k, int mods, int x, int y) -{ - - int key = 0; - switch (k) { - case 0x1b: key = osgGA::GUIEventAdapter::KEY_Escape; break; - case '\n': key = osgGA::GUIEventAdapter::KEY_Return; break; - case '\b': key = osgGA::GUIEventAdapter::KEY_BackSpace; break; - case 0x7f: key = osgGA::GUIEventAdapter::KEY_Delete; break; - case '\t': key = osgGA::GUIEventAdapter::KEY_Tab; break; - case PU_KEY_LEFT: key = osgGA::GUIEventAdapter::KEY_Left; break; - case PU_KEY_UP: key = osgGA::GUIEventAdapter::KEY_Up; break; - case PU_KEY_RIGHT: key = osgGA::GUIEventAdapter::KEY_Right; break; - case PU_KEY_DOWN: key = osgGA::GUIEventAdapter::KEY_Down; break; - case PU_KEY_PAGE_UP: key = osgGA::GUIEventAdapter::KEY_Page_Up; break; - case PU_KEY_PAGE_DOWN: key = osgGA::GUIEventAdapter::KEY_Page_Down; break; - case PU_KEY_HOME: key = osgGA::GUIEventAdapter::KEY_Home; break; - case PU_KEY_END: key = osgGA::GUIEventAdapter::KEY_End; break; - case PU_KEY_INSERT: key = osgGA::GUIEventAdapter::KEY_Insert; break; - case PU_KEY_F1: key = osgGA::GUIEventAdapter::KEY_F1; break; - case PU_KEY_F2: key = osgGA::GUIEventAdapter::KEY_F2; break; - case PU_KEY_F3: key = osgGA::GUIEventAdapter::KEY_F3; break; - case PU_KEY_F4: key = osgGA::GUIEventAdapter::KEY_F4; break; - case PU_KEY_F5: key = osgGA::GUIEventAdapter::KEY_F5; break; - case PU_KEY_F6: key = osgGA::GUIEventAdapter::KEY_F6; break; - case PU_KEY_F7: key = osgGA::GUIEventAdapter::KEY_F7; break; - case PU_KEY_F8: key = osgGA::GUIEventAdapter::KEY_F8; break; - case PU_KEY_F9: key = osgGA::GUIEventAdapter::KEY_F9; break; - case PU_KEY_F10: key = osgGA::GUIEventAdapter::KEY_F10; break; - case PU_KEY_F11: key = osgGA::GUIEventAdapter::KEY_F11; break; - case PU_KEY_F12: key = osgGA::GUIEventAdapter::KEY_F12; break; - default: key = k; break; - } - unsigned int osgModifiers = getOSGModifiers(mods); - osgGA::EventQueue& queue = *gw->getEventQueue(); - queue.getCurrentEventState()->setModKeyMask(osgModifiers); - if (mods & KEYMOD_RELEASED) - queue.keyRelease((osgGA::GUIEventAdapter::KeySymbol)key); - else - queue.keyPress((osgGA::GUIEventAdapter::KeySymbol)key); -} - -static void GLUTmotion (int x, int y) -{ - if (!gw.valid()) - return; - gw->getEventQueue()->mouseMotion(x, y); -} - -static void GLUTmouse (int button, int updown, int x, int y) -{ - GlutModifiers = glutGetModifiers(); - if (gw.valid()) { - if (updown == 0) - gw->getEventQueue()->mouseButtonPress(x, y, button+1); - else - gw->getEventQueue()->mouseButtonRelease(x, y, button+1); - } -} - -static void GLUTspecialkeyup(int k, int x, int y) -{ - GlutModifiers = glutGetModifiers(); - callKeyHandler(256 + k, fgGetKeyModifiers() | KEYMOD_RELEASED, x, y); -} - -static void GLUTspecialkey(int k, int x, int y) -{ - GlutModifiers = glutGetModifiers(); - callKeyHandler(256 + k, fgGetKeyModifiers(), x, y); -} - -static unsigned char release_keys[256]; - -static void GLUTkeyup(unsigned char k, int x, int y) -{ - GlutModifiers = glutGetModifiers(); - callKeyHandler(release_keys[k], fgGetKeyModifiers() | KEYMOD_RELEASED, x, y); -} - -static void GLUTkey(unsigned char k, int x, int y) -{ - GlutModifiers = glutGetModifiers(); - release_keys[k] = k; - if (k >= 1 && k <= 26) { - release_keys[k + '@'] = k; - release_keys[k + '`'] = k; - } else if (k >= 'A' && k <= 'Z') { - release_keys[k - '@'] = k; - release_keys[tolower(k)] = k; - } else if (k >= 'a' && k <= 'z') { - release_keys[k - '`'] = k; - release_keys[toupper(k)] = k; - } - callKeyHandler(k, fgGetKeyModifiers(), x, y); -} - -static void GLUTdraw() -{ - viewer->frame(); - glutSwapBuffers(); - glutPostRedisplay(); -} - -static void GLUTreshape(int w, int h) -{ - // update the window dimensions, in case the window has been resized. - gw->resized(gw->getTraits()->x, gw->getTraits()->y, w, h); - gw->getEventQueue()->windowResize(gw->getTraits()->x, gw->getTraits()->y, - w, h); -} - -// -// fg_os API definition -// - -void fgOSInit(int* argc, char** argv) -{ - glutInit(argc, argv); - WindowSystemAdapter::setWSA(new WindowSystemAdapter); -} - -void fgOSFullScreen() -{ - glutFullScreen(); -} - -void fgOSMainLoop() -{ - glutMainLoop(); -} - -void fgOSExit(int code) -{ - exit(code); -} - -static int CurrentCursor = MOUSE_CURSOR_POINTER; - -int fgGetMouseCursor() -{ - return CurrentCursor; -} - -void fgSetMouseCursor(int cursor) -{ - CurrentCursor = cursor; - if (cursor == MOUSE_CURSOR_NONE) cursor = GLUT_CURSOR_NONE; - else if(cursor == MOUSE_CURSOR_POINTER) cursor = GLUT_CURSOR_INHERIT; - else if(cursor == MOUSE_CURSOR_WAIT) cursor = GLUT_CURSOR_WAIT; - else if(cursor == MOUSE_CURSOR_CROSSHAIR) cursor = GLUT_CURSOR_CROSSHAIR; - else if(cursor == MOUSE_CURSOR_LEFTRIGHT) cursor = GLUT_CURSOR_LEFT_RIGHT; - // Otherwise, pass it through unchanged... - glutSetCursor(cursor); -} - -void fgWarpMouse(int x, int y) -{ - globals->get_renderer()->getManipulator()->setMouseWarped(); - glutWarpPointer(x, y); -} - -int fgGetKeyModifiers() -{ - int result = 0; - if(GlutModifiers & GLUT_ACTIVE_SHIFT) result |= KEYMOD_SHIFT; - if(GlutModifiers & GLUT_ACTIVE_CTRL) result |= KEYMOD_CTRL; - if(GlutModifiers & GLUT_ACTIVE_ALT) result |= KEYMOD_ALT; - return result; -} - -static unsigned int getOSGModifiers(int glutModifiers) -{ - unsigned int result = 0; - if (glutModifiers & GLUT_ACTIVE_SHIFT) - result |= osgGA::GUIEventAdapter::MODKEY_SHIFT; - if (glutModifiers & GLUT_ACTIVE_CTRL) - result |= osgGA::GUIEventAdapter::MODKEY_CTRL; - if(glutModifiers & GLUT_ACTIVE_ALT) - result |= osgGA::GUIEventAdapter::MODKEY_ALT; - return result; -} - -void fgOSOpenWindow(bool stencil) -{ - int w = fgGetInt("/sim/startup/xsize"); - int h = fgGetInt("/sim/startup/ysize"); - int bpp = fgGetInt("/sim/rendering/bits-per-pixel"); - bool alpha = fgGetBool("/sim/rendering/clouds3d-enable"); - bool fullscreen = fgGetBool("/sim/startup/fullscreen"); - WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); - int mode = GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE; - - if(alpha) mode |= GLUT_ALPHA; - if(stencil && bpp > 16) mode |= GLUT_STENCIL; - - glutInitDisplayMode(mode); - glutInitWindowSize(w, h); - if(!fgGetBool("/sim/startup/game-mode")) { - glutCreateWindow("FlightGear"); - } else { - char game_mode_str[20]; - SGPropertyNode *p = fgGetNode("/sim/frame-rate-throttle-hz", false); - if (p) { - int hz = p->getIntValue(); - snprintf(game_mode_str, 20, "%dx%d:%d@%d", w, h, bpp, hz); - } else { - snprintf(game_mode_str, 20, "%dx%d:%d", w, h, bpp); - } - glutGameModeString( game_mode_str ); - glutEnterGameMode(); - } - - // Register these here. Calling them before the window is open - // crashes. - glutMotionFunc(GLUTmotion); - glutPassiveMotionFunc(GLUTmotion); - glutMouseFunc(GLUTmouse); - glutSpecialUpFunc(GLUTspecialkeyup); - glutSpecialFunc(GLUTspecialkey); - glutKeyboardUpFunc(GLUTkeyup); - glutKeyboardFunc(GLUTkey); - glutDisplayFunc(GLUTdraw); - glutReshapeFunc(GLUTreshape); - // XXX - int realw = w; - int realh = h; - viewer = new osgViewer::Viewer; - gw = viewer->setUpViewerAsEmbeddedInWindow(0, 0, realw, realh); - GraphicsWindow* window = wsa->registerWindow(gw.get(), string("main")); - window->flags |= GraphicsWindow::GUI; - viewer->setDatabasePager(FGScenery::getPagerSingleton()); - // now the main camera ... - osg::Camera* camera = new osg::Camera; - // 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, realw, realh)); - camera->setProjectionResizePolicy(osg::Camera::FIXED); - CameraGroup* cgroup = new CameraGroup(viewer.get()); - cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera, - osg::Matrixd::identity(), osg::Matrixd::identity(), - true); - cgroup->buildGUICamera(0, window); - CameraGroup::setDefault(cgroup); - viewer->setCameraManipulator(globals->get_renderer()->getManipulator()); - // Let FG handle the escape key with a confirmation - viewer->setKeyEventSetsDone(0); - osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler; - statsHandler->setKeyEventTogglesOnScreenStats('*'); - statsHandler->setKeyEventPrintsOutStats(0); - viewer->addEventHandler(statsHandler); - // The viewer won't start without some root. - viewer->setSceneData(new osg::Group); - globals->get_renderer()->setViewer(viewer.get()); -} diff --git a/src/Main/fg_os_common.cxx b/src/Main/fg_os_common.cxx index a50be105f..91041c3cc 100644 --- a/src/Main/fg_os_common.cxx +++ b/src/Main/fg_os_common.cxx @@ -27,40 +27,41 @@ #include "fg_os.hxx" #include "globals.hxx" #include "renderer.hxx" +#include "FGEventHandler.hxx" // fg_os callback registration APIs // // Event handling and scene graph update is all handled by a -// manipulator. See FGManipulator.cpp +// manipulator. See FGEventHandler.cpp void fgRegisterIdleHandler(fgIdleHandler func) { - globals->get_renderer()->getManipulator()->setIdleHandler(func); + globals->get_renderer()->getEventHandler()->setIdleHandler(func); } void fgRegisterDrawHandler(fgDrawHandler func) { - globals->get_renderer()->getManipulator()->setDrawHandler(func); + globals->get_renderer()->getEventHandler()->setDrawHandler(func); } void fgRegisterWindowResizeHandler(fgWindowResizeHandler func) { - globals->get_renderer()->getManipulator()->setWindowResizeHandler(func); + globals->get_renderer()->getEventHandler()->setWindowResizeHandler(func); } void fgRegisterKeyHandler(fgKeyHandler func) { - globals->get_renderer()->getManipulator()->setKeyHandler(func); + globals->get_renderer()->getEventHandler()->setKeyHandler(func); } void fgRegisterMouseClickHandler(fgMouseClickHandler func) { - globals->get_renderer()->getManipulator()->setMouseClickHandler(func); + globals->get_renderer()->getEventHandler()->setMouseClickHandler(func); } void fgRegisterMouseMotionHandler(fgMouseMotionHandler func) { - globals->get_renderer()->getManipulator()->setMouseMotionHandler(func); + globals->get_renderer()->getEventHandler()->setMouseMotionHandler(func); } // Redraw "happens" every frame whether you want it or not. diff --git a/src/Main/fg_os_osgviewer.cxx b/src/Main/fg_os_osgviewer.cxx index bfee9f57b..628be1612 100644 --- a/src/Main/fg_os_osgviewer.cxx +++ b/src/Main/fg_os_osgviewer.cxx @@ -29,9 +29,12 @@ #include +#include + #include #include #include +#include #include #include @@ -52,6 +55,7 @@ #include "globals.hxx" #include "renderer.hxx" #include "CameraGroup.hxx" +#include "FGEventHandler.hxx" #include "WindowBuilder.hxx" #include "WindowSystemAdapter.hxx" @@ -73,55 +77,6 @@ using namespace osg; static osg::ref_ptr viewer; static osg::ref_ptr mainCamera; -namespace -{ -// If a camera group isn't specified, build one from the top-level -// camera specs and then add a camera aligned with the master camera -// if it doesn't seem to exist. -CameraGroup* buildDefaultCameraGroup(osgViewer::Viewer* viewer, - const SGPropertyNode* gnode) -{ - WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); - CameraGroup* cgroup = CameraGroup::buildCameraGroup(viewer, gnode); - // Look for a camera with no shear - Camera* masterCamera = 0; - for (CameraGroup::CameraIterator citer = cgroup->camerasBegin(), - e = cgroup->camerasEnd(); - citer != e; - ++citer) { - const View::Slave& slave = viewer->getSlave((*citer)->slaveIndex); - if (slave._projectionOffset.isIdentity()) { - masterCamera = (*citer)->camera.get(); - break; - } - } - if (!masterCamera) { - // No master camera found; better add one. - GraphicsWindow* window - = WindowBuilder::getWindowBuilder()->getDefaultWindow(); - masterCamera = new Camera(); - masterCamera->setGraphicsContext(window->gc.get()); - const GraphicsContext::Traits *traits = window->gc->getTraits(); - masterCamera->setViewport(new Viewport(0, 0, - traits->width, traits->height)); - cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, masterCamera, - Matrix(), Matrix()); - } - // Find window on which the GUI is drawn. - WindowVector::iterator iter = wsa->windows.begin(); - WindowVector::iterator end = wsa->windows.end(); - for (; iter != end; ++iter) { - if ((*iter)->gc.get() == masterCamera->getGraphicsContext()) - break; - } - if (iter != end) { // Better not happen - (*iter)->flags |= GraphicsWindow::GUI; - cgroup->buildGUICamera(0, iter->get()); - } - return cgroup; -} -} - void fgOSOpenWindow(bool stencil) { osg::GraphicsContext::WindowingSystemInterface* wsi @@ -147,31 +102,52 @@ void fgOSOpenWindow(bool stencil) // Look for windows, camera groups, and the old syntax of // top-level cameras - const SGPropertyNode* renderingNode = fgGetNode("/sim/rendering"); - for (int i = 0; i < renderingNode->nChildren(); ++i) { - const SGPropertyNode* propNode = renderingNode->getChild(i); - const char* propName = propNode->getName(); - if (!strcmp(propName, "window")) { - windowBuilder->buildWindow(propNode); - } else if (!strcmp(propName, "camera-group")) { - cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), propNode); + SGPropertyNode* renderingNode = fgGetNode("/sim/rendering"); + SGPropertyNode* cgroupNode = renderingNode->getChild("camera-group"); + if (!cgroupNode) { + cgroupNode = renderingNode->getNode("camera-group", true); + for (int i = 0; i < renderingNode->nChildren(); ++i) { + SGPropertyNode* propNode = renderingNode->getChild(i); + const char* propName = propNode->getName(); + if (!strcmp(propName, "window") || !strcmp(propName, "camera")) { + SGPropertyNode* copiedNode + = cgroupNode->getNode(propName, propNode->getIndex(), true); + copyProperties(propNode, copiedNode); + } } + vector cameras = cgroupNode->getChildren("camera"); + SGPropertyNode* masterCamera = 0; + BOOST_FOREACH(SGPropertyNode_ptr& camera, cameras) { + if (camera->getDoubleValue("shear-x", 0.0) == 0.0 + && camera->getDoubleValue("shear-y", 0.0) == 0.0) { + masterCamera = camera.ptr(); + break; + } + } + if (!masterCamera) { + masterCamera = cgroupNode->getChild("camera", cameras.size(), true); + setValue(masterCamera->getNode("window/name", true), + windowBuilder->getDefaultWindowName()); + } + SGPropertyNode* nameNode = masterCamera->getNode("window/name"); + if (nameNode) + setValue(cgroupNode->getNode("gui/window/name", true), + nameNode->getStringValue()); } - if (!cameraGroup) - cameraGroup = buildDefaultCameraGroup(viewer.get(), renderingNode); + cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), cgroupNode); Camera* guiCamera = getGUICamera(cameraGroup); if (guiCamera) { Viewport* guiViewport = guiCamera->getViewport(); fgSetInt("/sim/startup/xsize", guiViewport->width()); fgSetInt("/sim/startup/ysize", guiViewport->height()); } - FGManipulator* manipulator = globals->get_renderer()->getManipulator(); + FGEventHandler* manipulator = globals->get_renderer()->getEventHandler(); WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); if (wsa->windows.size() != 1) { manipulator->setResizable(false); } viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED); - viewer->setCameraManipulator(manipulator); + viewer->addEventHandler(manipulator); // Let FG handle the escape key with a confirmation viewer->setKeyEventSetsDone(0); // The viewer won't start without some root. @@ -191,13 +167,24 @@ void fgOSExit(int code) void fgOSMainLoop() { - viewer->run(); + ref_ptr manipulator + = globals->get_renderer()->getEventHandler(); + viewer->setReleaseContextAtEndOfFrameHint(false); + while (!viewer->done()) { + fgIdleHandler idleFunc = manipulator->getIdleHandler(); + fgDrawHandler drawFunc = manipulator->getDrawHandler(); + if (idleFunc) + (*idleFunc)(); + if (drawFunc) + (*drawFunc)(); + viewer->frame(); + } fgExit(status); } int fgGetKeyModifiers() { - return globals->get_renderer()->getManipulator()->getCurrentModifiers(); + return globals->get_renderer()->getEventHandler()->getCurrentModifiers(); } void fgWarpMouse(int x, int y) diff --git a/src/Main/fg_os_sdl.cxx b/src/Main/fg_os_sdl.cxx deleted file mode 100644 index 687788e05..000000000 --- a/src/Main/fg_os_sdl.cxx +++ /dev/null @@ -1,413 +0,0 @@ -#include - -#include -#include - -#include -#include -#include - -#include - -#include -#include "fg_os.hxx" -#include "globals.hxx" -#include "renderer.hxx" -#include "fg_props.hxx" -#include "CameraGroup.hxx" -#include "WindowSystemAdapter.hxx" - -using namespace flightgear; - -// -// fg_os callback registration APIs -// - -static int CurrentModifiers = 0; -static int CurrentMouseX = 0; -static int CurrentMouseY = 0; -static int CurrentMouseCursor = MOUSE_CURSOR_POINTER; -static int VidMask = SDL_OPENGL|SDL_RESIZABLE; - -// -// fg_os implementation -// -static void initCursors(); - -static osg::ref_ptr viewer; -static osg::ref_ptr gw; - -void fgOSOpenWindow(bool stencil) -{ - int w = fgGetInt("/sim/startup/xsize"); - int h = fgGetInt("/sim/startup/ysize"); - int bpp = fgGetInt("/sim/rendering/bits-per-pixel"); - bool alpha = fgGetBool("/sim/rendering/clouds3d-enable"); - bool fullscreen = fgGetBool("/sim/startup/fullscreen"); - int cbits = (bpp <= 16) ? 5 : 8; - int zbits = (bpp <= 16) ? 16 : 24; - WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); - - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) == -1) - throw sg_throwable(string("Failed to initialize SDL: ") - + SDL_GetError()); - atexit(SDL_Quit); - - SDL_WM_SetCaption("FlightGear", "FlightGear"); - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, cbits); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, cbits); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, cbits); - if(alpha) - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - if(bpp > 16 && stencil) - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, zbits); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - - if(fullscreen) { - VidMask |= SDL_FULLSCREEN; - } - SDL_Surface* screen = SDL_SetVideoMode(w, h, 16, VidMask); - if ( screen == 0) - throw sg_throwable(string("Failed to set SDL video mode: ") - + SDL_GetError()); - - // This enables keycode translation (e.g. capital letters when - // shift is pressed, as well as i18n input methods). Eventually, - // we may want to port the input maps to specify - // explicitly, and will turn this off. - SDL_EnableUNICODE(1); - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - initCursors(); - fgSetMouseCursor(MOUSE_CURSOR_POINTER); - - // FIXME: we may not get what we asked for (especially in full - // screen modes), so these need to be propagated back to the - // property tree for the rest of the code to inspect... - // - int realw = screen->w; - int realh = screen->h; - viewer = new osgViewer::Viewer; - viewer->setDatabasePager(FGScenery::getPagerSingleton()); - gw = viewer->setUpViewerAsEmbeddedInWindow(0, 0, realw, realh); - GraphicsWindow* window = wsa->registerWindow(gw.get(), string("main")); - window->flags |= GraphicsWindow::GUI; - // now the main camera ... - osg::Camera* camera = new osg::Camera; - // 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, realw, realh)); - camera->setProjectionResizePolicy(osg::Camera::FIXED); - CameraGroup* cgroup = new CameraGroup(viewer.get()); - cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera, - osg::Matrixd::identity(), osg::Matrixd::identity(), - true); - cgroup->buildGUICamera(0, window); - CameraGroup::setDefault(cgroup); - viewer->setCameraManipulator(globals->get_renderer()->getManipulator()); - // Let FG handle the escape key with a confirmation - viewer->setKeyEventSetsDone(0); - osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler; - statsHandler->setKeyEventTogglesOnScreenStats('*'); - statsHandler->setKeyEventPrintsOutStats(0); - viewer->addEventHandler(statsHandler); - // The viewer won't start without some root. - viewer->setSceneData(new osg::Group); - globals->get_renderer()->setViewer(viewer.get()); -} - -// Cheap trick to avoid typing GUIEventAdapter over and over... -class SDLKeyTranslator : osgGA::GUIEventAdapter -{ -public: - static int handleKey(int key, int raw, int keyup); -}; - -int SDLKeyTranslator::handleKey(int key, int raw, int keyup) -{ - using namespace osgGA; - - int modmask = 0; - int osgKey = 0; - if (key == 0) - key = raw; - // Don't pass capslock or numlock to the FGManipulator; SDL - // already transforms the key properly, so FGManipulator will get - // confused. - if (key == SDLK_CAPSLOCK || key == SDLK_NUMLOCK) - return -1; - switch(key) { - case SDLK_RSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_R; break; - case SDLK_LSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_L; break; - case SDLK_RCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_R; break; - case SDLK_LCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_L; break; - case SDLK_RALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_R; break; - case SDLK_LALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_L; break; - case SDLK_RMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_R; break; - case SDLK_LMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_L; break; - case SDLK_RSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_R; break; - case SDLK_LSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_L; break; - - case SDLK_LEFT: osgKey = KEY_Left; break; - case SDLK_UP: osgKey = KEY_Up; break; - case SDLK_RIGHT: osgKey = KEY_Right; break; - case SDLK_DOWN: osgKey = KEY_Down; break; - case SDLK_PAGEUP: osgKey = KEY_Page_Up; break; - case SDLK_PAGEDOWN: osgKey = KEY_Page_Down; break; - case SDLK_HOME: osgKey = KEY_Home; break; - case SDLK_END: osgKey = KEY_End; break; - case SDLK_INSERT: osgKey = KEY_Insert; break; - case SDLK_F1: osgKey = KEY_F1; break; - case SDLK_F2: osgKey = KEY_F2; break; - case SDLK_F3: osgKey = KEY_F3; break; - case SDLK_F4: osgKey = KEY_F4; break; - case SDLK_F5: osgKey = KEY_F5; break; - case SDLK_F6: osgKey = KEY_F6; break; - case SDLK_F7: osgKey = KEY_F7; break; - case SDLK_F8: osgKey = KEY_F8; break; - case SDLK_F9: osgKey = KEY_F9; break; - case SDLK_F10: osgKey = KEY_F10; break; - case SDLK_F11: osgKey = KEY_F11; break; - case SDLK_F12: osgKey = KEY_F12; break; - default: - osgKey = key; - } - int keymod = 0; - if(keyup) { - CurrentModifiers &= ~modmask; - keymod = CurrentModifiers | KEYMOD_RELEASED; - } else { - CurrentModifiers |= modmask; - keymod = CurrentModifiers & ~KEYMOD_RELEASED; - } - return osgKey; -} - -// FIXME: Integrate with existing fgExit() in util.cxx. -void fgOSExit(int code) -{ - viewer->setDone(true); - exit(code); -} - -// originally from osgexamples/osgviewerSDL.cpp -bool convertEvent(SDL_Event& event, osgGA::EventQueue& eventQueue) -{ - using namespace osgGA; - switch (event.type) { - - case SDL_MOUSEMOTION: - eventQueue.mouseMotion(event.motion.x, event.motion.y); - return true; - - case SDL_MOUSEBUTTONDOWN: - eventQueue.mouseButtonPress(event.button.x, event.button.y, event.button.button); - return true; - - case SDL_MOUSEBUTTONUP: - eventQueue.mouseButtonRelease(event.button.x, event.button.y, event.button.button); - return true; - - case SDL_KEYUP: - case SDL_KEYDOWN: - { - int realKey = SDLKeyTranslator::handleKey(event.key.keysym.unicode, - event.key.keysym.sym, - event.type == SDL_KEYUP); - if (realKey < -1) - return true; - if (event.type == SDL_KEYUP) - eventQueue.keyRelease((osgGA::GUIEventAdapter::KeySymbol)realKey); - else - eventQueue.keyPress((osgGA::GUIEventAdapter::KeySymbol)realKey); - return true; - } - case SDL_VIDEORESIZE: - if (SDL_SetVideoMode(event.resize.w, event.resize.h, 16, VidMask) == 0) - throw sg_throwable(string("Failed to set SDL video mode: ") - + SDL_GetError()); - eventQueue.windowResize(0, 0, event.resize.w, event.resize.h ); - return true; - - default: - break; - } - return false; -} - -void fgOSMainLoop() -{ - while(1) { - SDL_Event e; - int key; - while(SDL_PollEvent(&e)) { - // pass the SDL event into the viewers event queue - convertEvent(e, *(gw->getEventQueue())); - - switch(e.type) { - case SDL_QUIT: - fgOSExit(0); - break; - case SDL_VIDEORESIZE: - gw->resized(0, 0, e.resize.w, e.resize.h ); - break; - } - } - // draw the new frame - viewer->frame(); - - // Swap Buffers - SDL_GL_SwapBuffers(); - } -} - -int fgGetKeyModifiers() -{ - return CurrentModifiers; -} - -void fgWarpMouse(int x, int y) -{ - globals->get_renderer()->getManipulator()->setMouseWarped(); - SDL_WarpMouse(x, y); -} - -void fgOSInit(int* argc, char** argv) -{ - WindowSystemAdapter::setWSA(new WindowSystemAdapter); -} - -void fgOSFullScreen() -{ - // Noop. SDL must set fullscreen at window open time and cannot - // change modes. -} - -static struct cursor_rec { - int name; - SDL_Cursor* sdlCursor; - int w; - int h; - int hotx; - int hoty; - const char *img[32]; // '.' == white, '#' == black, ' ' == transparent -} cursors[] = { - { MOUSE_CURSOR_POINTER, 0, // must be first! - 10, 16, 1, 1, - { ".. ", - ".#. ", - ".##. ", - ".###. ", - ".####. ", - ".#####. ", - ".######. ", - ".#######. ", - ".########.", - ".#####....", - ".##.##. ", - ".#. .##. ", - ".. .##. ", - " .##. ", - " .##. ", - " .. " } }, - { MOUSE_CURSOR_CROSSHAIR, 0, - 17, 17, 8, 8, - { " ... ", - " .#. ", - " .#. ", - " .#. ", - " .#. ", - " .#. ", - " .#. ", - "........#........", - ".#######.#######.", - "........#........", - " .#. ", - " .#. ", - " .#. ", - " .#. ", - " .#. ", - " .#. ", - " ... " } }, - { MOUSE_CURSOR_WAIT, 0, - 16, 16, 7, 7, - { " .########. ", - " .########. ", - " .########. ", - " .##########. ", - ".##....#...##. ", - "##.....#....##..", - "#......#.....###", - "#.....###....###", - "#.....###....###", - "#....#.......###", - "##..#.......##..", - ".##........##. ", - " .##########. ", - " .########. ", - " .########. ", - " .########. " } }, - { MOUSE_CURSOR_LEFTRIGHT, 0, - 17, 9, 8, 4, - { " .. .. ", - " .#. .#. ", - " .##.......##. ", - " .#############. ", - ".####.......####.", - " .#############. ", - " .##.......##. ", - " .#. .#. ", - " .. .. " } }, - { MOUSE_CURSOR_NONE, 0, // must come last! - 1, 1, 0, 0, { " " } }, -}; - -#define NCURSORS (sizeof(cursors)/sizeof(struct cursor_rec)) - -void fgSetMouseCursor(int cursor) -{ - if(cursor == MOUSE_CURSOR_NONE) { - SDL_ShowCursor(SDL_DISABLE); - return; - } - SDL_ShowCursor(SDL_ENABLE); - for(unsigned int i=0; i> 3); - int bit = 1 << (7 - (x & 7)); - int pix = cursors[i].img[y][x]; - if(pix != ' ') { mask[byte] |= bit; } - if(pix == '#') { img[byte] |= bit; } - } - } - cursors[i].sdlCursor = SDL_CreateCursor(img, mask, 32, 32, - cursors[i].hotx, - cursors[i].hoty); - } -} diff --git a/src/Main/renderer.cxx b/src/Main/renderer.cxx index 97fbcb989..26762df32 100644 --- a/src/Main/renderer.cxx +++ b/src/Main/renderer.cxx @@ -97,7 +97,7 @@ #include "renderer.hxx" #include "main.hxx" #include "CameraGroup.hxx" -#include "ViewPartitionNode.hxx" +#include "FGEventHandler.hxx" // XXX Make this go away when OSG 2.2 is released. #if (FG_OSG_VERSION >= 21004) @@ -371,14 +371,12 @@ static osg::ref_ptr mRealRoot = new osg::Group; static osg::ref_ptr mRoot = new osg::Group; -static osg::ref_ptr viewPartition = new ViewPartitionNode; - FGRenderer::FGRenderer() { #ifdef FG_JPEG_SERVER jpgRenderFrame = FGRenderer::update; #endif - manipulator = new FGManipulator; + eventHandler = new FGEventHandler; } FGRenderer::~FGRenderer() @@ -519,10 +517,8 @@ FGRenderer::init( void ) osg::Switch* sw = new osg::Switch; sw->setUpdateCallback(new FGScenerySwitchCallback); sw->addChild(mRoot.get()); - viewPartition->addChild(sw); - viewPartition->addChild(thesky->getCloudRoot()); - - mRealRoot->addChild(viewPartition.get()); + mRealRoot->addChild(sw); + mRealRoot->addChild(thesky->getCloudRoot()); mRealRoot->addChild(FGCreateRedoutNode()); } @@ -738,7 +734,6 @@ FGRenderer::update( bool refresh_camera_settings ) { l->adj_fog_color(), l->get_sun_angle()*SGD_RADIANS_TO_DEGREES); mUpdateVisitor->setVisibility(actual_visibility); - viewPartition->setVisibility(actual_visibility); simgear::GroundLightManager::instance()->update(mUpdateVisitor.get()); bool hotspots = fgGetBool("/sim/panel-hotspots"); osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT; @@ -746,10 +741,7 @@ FGRenderer::update( bool refresh_camera_settings ) { ->getLightNodeMask(mUpdateVisitor.get()); if (hotspots) cullMask |= simgear::PICK_BIT; - camera->setCullMask(cullMask); - // XXX - for (int i = 0; i < viewer->getNumSlaves(); ++i) - viewer->getSlave(i)._camera->setCullMask(cullMask); + CameraGroup::getDefault()->setCameraCullMasks(cullMask); } @@ -832,6 +824,18 @@ FGRenderer::pick(std::vector& pickList, return !pickList.empty(); } +void +FGRenderer::setViewer(osgViewer::Viewer* viewer_) +{ + viewer = viewer_; +} + +void +FGRenderer::setEventHandler(FGEventHandler* eventHandler_) +{ + eventHandler = eventHandler_; +} + void FGRenderer::addCamera(osg::Camera* camera, bool useSceneData) { diff --git a/src/Main/renderer.hxx b/src/Main/renderer.hxx index f126f2feb..0a8096cd4 100644 --- a/src/Main/renderer.hxx +++ b/src/Main/renderer.hxx @@ -5,10 +5,33 @@ #include #include -#include -#include - -#include "FGManipulator.hxx" +#include + +namespace osg +{ +class Camera; +class Group; +} + +namespace osgGA +{ +class GUIEventAdapter; +} + +namespace osgShadow +{ +class ShadowedScene; +} + +namespace osgViewer +{ +class Viewer; +} + +namespace flightgear +{ +class FGEventHandler; +} #define FG_ENABLE_MULTIPASS_CLOUDS 1 @@ -52,14 +75,12 @@ public: */ osgViewer::Viewer* getViewer() { return viewer.get(); } const osgViewer::Viewer* getViewer() const { return viewer.get(); } - void setViewer(osgViewer::Viewer* viewer) { this->viewer = viewer; } + void setViewer(osgViewer::Viewer* viewer); /** Get and set the manipulator object, if any. */ - flightgear::FGManipulator* getManipulator() { return manipulator.get(); } - const flightgear::FGManipulator* getManipulator() const { return manipulator.get(); } - void setManipulator(flightgear::FGManipulator* manipulator) { - this->manipulator = manipulator; - } + flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); } + const flightgear::FGEventHandler* getEventHandler() const { return eventHandler.get(); } + void setEventHandler(flightgear::FGEventHandler* manipulator); /** Add a top level camera. */ @@ -67,7 +88,7 @@ public: protected: osg::ref_ptr viewer; - osg::ref_ptr manipulator; + osg::ref_ptr eventHandler; }; bool fgDumpSceneGraphToFile(const char* filename); diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index c7965719a..503b397d1 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include