"Fossies" - the Fresh Open Source Software Archive

Member "flightgear-2020.3.8/src/Viewer/fg_os_osgviewer.cxx" (24 Mar 2021, 19917 Bytes) of package /linux/privat/flightgear-2020.3.8.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fg_os_osgviewer.cxx" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2020.3.7_vs_2020.3.8.

    1 // fg_os_osgviewer.cxx -- common functions for fg_os interface
    2 // implemented as an osgViewer
    3 //
    4 // Copyright (C) 2007  Tim Moore timoore@redhat.com
    5 // Copyright (C) 2007 Mathias Froehlich
    6 //
    7 // This program is free software; you can redistribute it and/or
    8 // modify it under the terms of the GNU General Public License as
    9 // published by the Free Software Foundation; either version 2 of the
   10 // License, or (at your option) any later version.
   11 //
   12 // This program is distributed in the hope that it will be useful, but
   13 // WITHOUT ANY WARRANTY; without even the implied warranty of
   14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15 // General Public License for more details.
   16 //
   17 // You should have received a copy of the GNU General Public License
   18 // along with this program; if not, write to the Free Software
   19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   20 
   21 #include <config.h>
   22 
   23 #include <algorithm>
   24 #include <iostream>
   25 #include <sstream>
   26 #include <string>
   27 #include <cstdlib>
   28 
   29 #include <simgear/compiler.h>
   30 #include <simgear/structure/exception.hxx>
   31 #include <simgear/debug/logstream.hxx>
   32 #include <simgear/debug/OsgIoCapture.hxx>
   33 #include <simgear/props/props_io.hxx>
   34 
   35 #include <osg/Camera>
   36 #include <osg/GraphicsContext>
   37 #include <osg/Group>
   38 #include <osg/Matrixd>
   39 #include <osg/Viewport>
   40 #include <osg/Version>
   41 #include <osg/Notify>
   42 #include <osg/View>
   43 #include <osgViewer/ViewerEventHandlers>
   44 #include <osgViewer/Viewer>
   45 #include <osgViewer/GraphicsWindow>
   46 
   47 #include <Scenery/scenery.hxx>
   48 #include <Main/fg_os.hxx>
   49 #include <Main/fg_props.hxx>
   50 #include <Main/util.hxx>
   51 #include <Main/globals.hxx>
   52 #include "renderer.hxx"
   53 #include "CameraGroup.hxx"
   54 #include "FGEventHandler.hxx"
   55 #include "WindowBuilder.hxx"
   56 #include "WindowSystemAdapter.hxx"
   57 #include <Main/sentryIntegration.hxx>
   58 
   59 #if defined(HAVE_QT)
   60 #include "GraphicsWindowQt5.hxx"
   61 #include <GUI/QtLauncher.hxx>
   62 #include <QCoreApplication>
   63 #endif
   64 
   65 #if defined(SG_MAC)
   66 #  include <GUI/CocoaHelpers.h>
   67 #endif
   68 
   69 // Static linking of OSG needs special macros
   70 #ifdef OSG_LIBRARY_STATIC
   71 #include <osgDB/Registry>
   72 USE_GRAPHICSWINDOW();
   73 // Image formats
   74 USE_OSGPLUGIN(bmp);
   75 USE_OSGPLUGIN(dds);
   76 USE_OSGPLUGIN(hdr);
   77 USE_OSGPLUGIN(pic);
   78 USE_OSGPLUGIN(pnm);
   79 USE_OSGPLUGIN(rgb);
   80 USE_OSGPLUGIN(tga);
   81 #ifdef OSG_JPEG_ENABLED
   82   USE_OSGPLUGIN(jpeg);
   83 #endif
   84 #ifdef OSG_PNG_ENABLED
   85   USE_OSGPLUGIN(png);
   86 #endif
   87 #ifdef OSG_TIFF_ENABLED
   88   USE_OSGPLUGIN(tiff);
   89 #endif
   90 // Model formats
   91 USE_OSGPLUGIN(3ds);
   92 USE_OSGPLUGIN(ac);
   93 USE_OSGPLUGIN(ive);
   94 USE_OSGPLUGIN(osg);
   95 USE_OSGPLUGIN(txf);
   96 #endif
   97 
   98 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
   99 // to create the graphics window and run the event/update/render loop.
  100 
  101 //
  102 // fg_os implementation
  103 //
  104 
  105 using namespace std;
  106 using namespace flightgear;
  107 using namespace osg;
  108 
  109 osg::ref_ptr<osgViewer::Viewer> viewer;
  110 
  111 bool global_usingGraphicsWindowQt = false;
  112 
  113 static void setStereoMode( const char * mode )
  114 {
  115     DisplaySettings::StereoMode stereoMode = DisplaySettings::QUAD_BUFFER;
  116     bool stereoOn = true;
  117 
  118     if (strcmp(mode,"QUAD_BUFFER")==0)
  119     {
  120         stereoMode = DisplaySettings::QUAD_BUFFER;
  121     }
  122     else if (strcmp(mode,"ANAGLYPHIC")==0)
  123     {
  124         stereoMode = DisplaySettings::ANAGLYPHIC;
  125     }
  126     else if (strcmp(mode,"HORIZONTAL_SPLIT")==0)
  127     {
  128         stereoMode = DisplaySettings::HORIZONTAL_SPLIT;
  129     }
  130     else if (strcmp(mode,"VERTICAL_SPLIT")==0)
  131     {
  132         stereoMode = DisplaySettings::VERTICAL_SPLIT;
  133     }
  134     else if (strcmp(mode,"LEFT_EYE")==0)
  135     {
  136         stereoMode = DisplaySettings::LEFT_EYE;
  137     }
  138     else if (strcmp(mode,"RIGHT_EYE")==0)
  139     {
  140         stereoMode = DisplaySettings::RIGHT_EYE;
  141     }
  142     else if (strcmp(mode,"HORIZONTAL_INTERLACE")==0)
  143     {
  144         stereoMode = DisplaySettings::HORIZONTAL_INTERLACE;
  145     }
  146     else if (strcmp(mode,"VERTICAL_INTERLACE")==0)
  147     {
  148         stereoMode = DisplaySettings::VERTICAL_INTERLACE;
  149     }
  150     else if (strcmp(mode,"CHECKERBOARD")==0)
  151     {
  152         stereoMode = DisplaySettings::CHECKERBOARD;
  153     } else {
  154         stereoOn = false;
  155     }
  156     DisplaySettings::instance()->setStereo( stereoOn );
  157     DisplaySettings::instance()->setStereoMode( stereoMode );
  158 }
  159 
  160 static const char * getStereoMode()
  161 {
  162     DisplaySettings::StereoMode stereoMode = DisplaySettings::instance()->getStereoMode();
  163     bool stereoOn = DisplaySettings::instance()->getStereo();
  164     if( !stereoOn ) return "OFF";
  165     if( stereoMode == DisplaySettings::QUAD_BUFFER ) {
  166         return "QUAD_BUFFER";
  167     } else if( stereoMode == DisplaySettings::ANAGLYPHIC ) {
  168         return "ANAGLYPHIC";
  169     } else if( stereoMode == DisplaySettings::HORIZONTAL_SPLIT ) {
  170         return "HORIZONTAL_SPLIT";
  171     } else if( stereoMode == DisplaySettings::VERTICAL_SPLIT ) {
  172         return "VERTICAL_SPLIT";
  173     } else if( stereoMode == DisplaySettings::LEFT_EYE ) {
  174         return "LEFT_EYE";
  175     } else if( stereoMode == DisplaySettings::RIGHT_EYE ) {
  176         return "RIGHT_EYE";
  177     } else if( stereoMode == DisplaySettings::HORIZONTAL_INTERLACE ) {
  178         return "HORIZONTAL_INTERLACE";
  179     } else if( stereoMode == DisplaySettings::VERTICAL_INTERLACE ) {
  180         return "VERTICAL_INTERLACE";
  181     } else if( stereoMode == DisplaySettings::CHECKERBOARD ) {
  182         return "CHECKERBOARD";
  183     }
  184     return "OFF";
  185 }
  186 
  187 class NotifyLevelListener : public SGPropertyChangeListener
  188 {
  189 public:
  190     void valueChanged(SGPropertyNode* node)
  191     {
  192         osg::NotifySeverity severity = osg::WARN;
  193         string val = simgear::strutils::lowercase(node->getStringValue());
  194 
  195         if (val == "fatal") {
  196             severity = osg::FATAL;
  197         } else if (val == "warn") {
  198             severity = osg::WARN;
  199         } else if (val == "notice") {
  200             severity = osg::NOTICE;
  201         } else if (val == "info") {
  202             severity = osg::INFO;
  203         } else if ((val == "debug") || (val == "debug-info")) {
  204             severity = osg::DEBUG_INFO;
  205         }
  206 
  207         osg::setNotifyLevel(severity);
  208     }
  209 };
  210 
  211 void updateOSGNotifyLevel()
  212 {
  213    }
  214 
  215 void fgOSOpenWindow(bool stencil)
  216 {
  217     osg::setNotifyHandler(new NotifyLogger);
  218 
  219     viewer = new osgViewer::Viewer;
  220     viewer->setDatabasePager(FGScenery::getPagerSingleton());
  221 
  222     std::string mode;
  223     mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
  224     flightgear::addSentryTag("osg-thread-mode", mode);
  225 
  226     if (mode == "AutomaticSelection")
  227       viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
  228     else if (mode == "CullDrawThreadPerContext")
  229       viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
  230     else if (mode == "DrawThreadPerContext")
  231       viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
  232     else if (mode == "CullThreadPerCameraDrawThreadPerContext")
  233       viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
  234     else
  235       viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
  236     WindowBuilder::initWindowBuilder(stencil);
  237     CameraGroup::buildDefaultGroup(viewer.get());
  238 
  239     FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
  240     WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
  241     if (wsa->windows.size() != 1) {
  242         manipulator->setResizable(false);
  243     }
  244     viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
  245     viewer->addEventHandler(manipulator);
  246     // Let FG handle the escape key with a confirmation
  247     viewer->setKeyEventSetsDone(0);
  248     // The viewer won't start without some root.
  249     viewer->setSceneData(new osg::Group);
  250     globals->get_renderer()->setViewer(viewer.get());
  251 }
  252 SGPropertyNode* simHost = 0, *simFrameCount, *simTotalHostTime, *simFrameResetCount, *frameWait;
  253 void fgOSResetProperties()
  254 {
  255     SGPropertyNode* osgLevel = fgGetNode("/sim/rendering/osg-notify-level", true);
  256     simTotalHostTime = fgGetNode("/sim/rendering/sim-host-total-ms", true);
  257     simHost = fgGetNode("/sim/rendering/sim-host-avg-ms", true);
  258     simFrameCount = fgGetNode("/sim/rendering/sim-frame-count", true);
  259     simFrameResetCount = fgGetNode("/sim/rendering/sim-frame-count-reset", true);
  260     frameWait = fgGetNode("/sim/time/frame-wait-ms", true);
  261     simFrameResetCount->setBoolValue(false);
  262     NotifyLevelListener* l = new NotifyLevelListener;
  263     globals->addListenerToCleanup(l);
  264     osgLevel->addChangeListener(l, true);
  265 
  266     osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
  267     if (guiCamera) {
  268         Viewport* guiViewport = guiCamera->getViewport();
  269         fgSetInt("/sim/startup/xsize", guiViewport->width());
  270         fgSetInt("/sim/startup/ysize", guiViewport->height());
  271     }
  272 
  273     DisplaySettings * displaySettings = DisplaySettings::instance();
  274     fgTie("/sim/rendering/osg-displaysettings/eye-separation", displaySettings, &DisplaySettings::getEyeSeparation, &DisplaySettings::setEyeSeparation );
  275     fgTie("/sim/rendering/osg-displaysettings/screen-distance", displaySettings, &DisplaySettings::getScreenDistance, &DisplaySettings::setScreenDistance );
  276     fgTie("/sim/rendering/osg-displaysettings/screen-width", displaySettings, &DisplaySettings::getScreenWidth, &DisplaySettings::setScreenWidth );
  277     fgTie("/sim/rendering/osg-displaysettings/screen-height", displaySettings, &DisplaySettings::getScreenHeight, &DisplaySettings::setScreenHeight );
  278     fgTie("/sim/rendering/osg-displaysettings/stereo-mode", getStereoMode, setStereoMode );
  279     fgTie("/sim/rendering/osg-displaysettings/double-buffer", displaySettings, &DisplaySettings::getDoubleBuffer, &DisplaySettings::setDoubleBuffer );
  280     fgTie("/sim/rendering/osg-displaysettings/depth-buffer", displaySettings, &DisplaySettings::getDepthBuffer, &DisplaySettings::setDepthBuffer );
  281     fgTie("/sim/rendering/osg-displaysettings/rgb", displaySettings, &DisplaySettings::getRGB, &DisplaySettings::setRGB );
  282 }
  283 
  284 
  285 static int status = 0;
  286 
  287 void fgOSExit(int code)
  288 {
  289     viewer->setDone(true);
  290     viewer->getDatabasePager()->cancel();
  291     status = code;
  292 
  293     // otherwise we crash if OSG does logging during static destruction, eg
  294     // GraphicsWindowX11, since OSG statics may have been created before the
  295     // sglog static, despite our best efforts in boostrap.cxx
  296     osg::setNotifyHandler(new osg::StandardNotifyHandler);
  297 }
  298 SGTimeStamp _lastUpdate;
  299 
  300 int fgOSMainLoop()
  301 {
  302     viewer->setReleaseContextAtEndOfFrameHint(false);
  303     if (!viewer->isRealized()) {
  304         viewer->realize();
  305     }
  306 
  307     while (!viewer->done()) {
  308         fgIdleHandler idleFunc = globals->get_renderer()->getEventHandler()->getIdleHandler();
  309         if (idleFunc)
  310         {
  311             _lastUpdate.stamp();
  312             (*idleFunc)();
  313             if (fgGetBool("/sim/position-finalized", false))
  314             {
  315                 if (simHost && simFrameCount && simTotalHostTime && simFrameResetCount)
  316                 {
  317                     int curFrameCount = simFrameCount->getIntValue();
  318                     double totalSimTime = simTotalHostTime->getDoubleValue();
  319                     if (simFrameResetCount->getBoolValue())
  320                     {
  321                         curFrameCount = 0;
  322                         totalSimTime = 0;
  323                         simFrameResetCount->setBoolValue(false);
  324                     }
  325                     double lastSimFrame_ms = _lastUpdate.elapsedMSec();
  326                     double idle_wait = 0;
  327                     if (frameWait)
  328                         idle_wait = frameWait->getDoubleValue();
  329                     if (lastSimFrame_ms > 0)
  330                     {
  331                         totalSimTime += lastSimFrame_ms - idle_wait;
  332                         simTotalHostTime->setDoubleValue(totalSimTime);
  333                         curFrameCount++;
  334                         simFrameCount->setIntValue(curFrameCount);
  335                         simHost->setDoubleValue(totalSimTime / curFrameCount);
  336                     }
  337                 }
  338             }
  339         }
  340         globals->get_renderer()->update();
  341         viewer->frame( globals->get_sim_time_sec() );
  342     }
  343 
  344     flightgear::addSentryBreadcrumb("main loop exited", "info");
  345     return status;
  346 }
  347 
  348 int fgGetKeyModifiers()
  349 {
  350     FGRenderer* r = globals->get_renderer();
  351     if (!r || !r->getEventHandler()) { // happens during shutdown
  352       return 0;
  353     }
  354 
  355     return r->getEventHandler()->getCurrentModifiers();
  356 }
  357 
  358 void fgWarpMouse(int x, int y)
  359 {
  360     warpGUIPointer(CameraGroup::getDefault(), x, y);
  361 }
  362 
  363 void fgOSInit(int* argc, char** argv)
  364 {
  365 #if defined(HAVE_QT)
  366     global_usingGraphicsWindowQt = fgGetBool("/sim/rendering/graphics-window-qt", false);
  367     if (global_usingGraphicsWindowQt) {
  368         SG_LOG(SG_GL, SG_INFO, "Using Qt implementation of GraphicsWindow");
  369         flightgear::initQtWindowingSystem();
  370     } else {
  371         // stock OSG windows are not Hi-DPI aware
  372         fgSetDouble("/sim/rendering/gui-pixel-ratio", 1.0);
  373         SG_LOG(SG_GL, SG_INFO, "Using stock OSG implementation of GraphicsWindow");
  374     }
  375 #endif
  376 #if defined(SG_MAC)
  377     cocoaRegisterTerminateHandler();
  378 #endif
  379     
  380     globals->get_renderer()->init();
  381     WindowSystemAdapter::setWSA(new WindowSystemAdapter);
  382 }
  383 
  384 void fgOSCloseWindow()
  385 {
  386     if (viewer) {
  387         // https://code.google.com/p/flightgear-bugs/issues/detail?id=1291
  388         // https://sourceforge.net/p/flightgear/codetickets/1830/
  389         // explicitly stop threading before we delete the renderer or
  390         // viewMgr (which ultimately holds refs to the CameraGroup, and
  391         // GraphicsContext)
  392         viewer->stopThreading();
  393     }
  394     FGScenery::resetPagerSingleton();
  395     flightgear::addSentryBreadcrumb("fgOSCloseWindow, clearing camera group", "info");
  396     flightgear::CameraGroup::setDefault(NULL);
  397     WindowSystemAdapter::setWSA(NULL);
  398     viewer = NULL;
  399 }
  400 
  401 void fgOSFullScreen()
  402 {
  403     std::vector<osgViewer::GraphicsWindow*> windows;
  404     viewer->getWindows(windows);
  405 
  406     if (windows.empty())
  407         return; // Huh?!?
  408 
  409     /* Toggling window fullscreen is only supported for the main GUI window.
  410      * The other windows should use fixed setup from the camera.xml file anyway. */
  411     osgViewer::GraphicsWindow* window = windows[0];
  412 
  413 #if defined(HAVE_QT)
  414     if (global_usingGraphicsWindowQt) {
  415         const bool wasFullscreen = fgGetBool("/sim/startup/fullscreen");
  416         auto qtWin = static_cast<flightgear::GraphicsWindowQt5*>(window);
  417         qtWin->setFullscreen(!wasFullscreen);
  418         fgSetBool("/sim/startup/fullscreen", !wasFullscreen);
  419 
  420         // FIXME tell lies here for HiDPI sizing?
  421         fgSetInt("/sim/startup/xsize", qtWin->getGLWindow()->width());
  422         fgSetInt("/sim/startup/ysize", qtWin->getGLWindow()->height());
  423     } else
  424 #endif
  425     {
  426         osg::GraphicsContext::WindowingSystemInterface    *wsi = osg::GraphicsContext::getWindowingSystemInterface();
  427         if (wsi == NULL)
  428         {
  429             SG_LOG(SG_VIEW, SG_ALERT, "ERROR: No WindowSystemInterface available. Cannot toggle window fullscreen.");
  430             return;
  431         }
  432 
  433         static int previous_x = 0;
  434         static int previous_y = 0;
  435         static int previous_width = 800;
  436         static int previous_height = 600;
  437 
  438         unsigned int screenWidth;
  439         unsigned int screenHeight;
  440         wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight);
  441 
  442         int x;
  443         int y;
  444         int width;
  445         int height;
  446         window->getWindowRectangle(x, y, width, height);
  447 
  448         /* Note: the simple "is window size == screen size" check to detect full screen state doesn't work with
  449          * X screen servers in Xinerama mode, since the reported screen width (or height) exceeds the maximum width
  450          * (or height) usable by a single window (Xserver automatically shrinks/moves the full screen window to fit a
  451          * single display) - so we detect full screen mode using "WindowDecoration" state instead.
  452          * "false" - even when a single window is display in fullscreen */
  453         //bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight;
  454         bool isFullScreen = !window->getWindowDecoration();
  455 
  456         SG_LOG(SG_VIEW, SG_DEBUG, "Toggling fullscreen. Previous window rectangle ("
  457                << x << ", " << y << ") x (" << width << ", " << height << "), fullscreen: " << isFullScreen
  458                << ", number of screens: " << wsi->getNumScreens());
  459         if (isFullScreen)
  460         {
  461             // limit x,y coordinates and window size to screen area
  462             if (previous_x + previous_width > (int)screenWidth)
  463                 previous_x = 0;
  464             if (previous_y + previous_height > (int)screenHeight)
  465                 previous_y = 0;
  466 
  467             // disable fullscreen mode, restore previous window size/coordinates
  468             x = previous_x;
  469             y = previous_y;
  470             width = previous_width;
  471             height = previous_height;
  472         }
  473         else
  474         {
  475             // remember previous setting
  476             previous_x = x;
  477             previous_y = y;
  478             previous_width = width;
  479             previous_height = height;
  480 
  481             // enable fullscreen mode, set new width/height
  482             x = 0;
  483             y = 0;
  484             width = screenWidth;
  485             height = screenHeight;
  486         }
  487 
  488         // set xsize/ysize properties to adapt GUI planes
  489         fgSetInt("/sim/startup/xsize", width);
  490         fgSetInt("/sim/startup/ysize", height);
  491         fgSetBool("/sim/startup/fullscreen", !isFullScreen);
  492 
  493         // reconfigure window
  494         window->setWindowDecoration(isFullScreen);
  495         window->setWindowRectangle(x, y, width, height);
  496         window->grabFocusIfPointerInWindow();
  497     } // of stock GraphicsWindow verison (OSG has no native fullscreen mode)
  498 }
  499 
  500 static void setMouseCursor(osgViewer::GraphicsWindow* gw, int cursor)
  501 {
  502     if (!gw) {
  503         return;
  504     }
  505 
  506     osgViewer::GraphicsWindow::MouseCursor mouseCursor;
  507     mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
  508     if (cursor == MOUSE_CURSOR_NONE)
  509         mouseCursor = osgViewer::GraphicsWindow::NoCursor;
  510     else if(cursor == MOUSE_CURSOR_POINTER)
  511 #ifdef SG_MAC
  512         // osgViewer-Cocoa lacks RightArrowCursor, use Left
  513         mouseCursor = osgViewer::GraphicsWindow::LeftArrowCursor;
  514 #else
  515         mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
  516 #endif
  517     else if(cursor == MOUSE_CURSOR_WAIT)
  518         mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
  519     else if(cursor == MOUSE_CURSOR_CROSSHAIR)
  520         mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
  521     else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
  522         mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
  523     else if(cursor == MOUSE_CURSOR_TOPSIDE)
  524         mouseCursor = osgViewer::GraphicsWindow::TopSideCursor;
  525     else if(cursor == MOUSE_CURSOR_BOTTOMSIDE)
  526         mouseCursor = osgViewer::GraphicsWindow::BottomSideCursor;
  527     else if(cursor == MOUSE_CURSOR_LEFTSIDE)
  528         mouseCursor = osgViewer::GraphicsWindow::LeftSideCursor;
  529     else if(cursor == MOUSE_CURSOR_RIGHTSIDE)
  530         mouseCursor = osgViewer::GraphicsWindow::RightSideCursor;
  531     else if(cursor == MOUSE_CURSOR_TOPLEFT)
  532         mouseCursor = osgViewer::GraphicsWindow::TopLeftCorner;
  533     else if(cursor == MOUSE_CURSOR_TOPRIGHT)
  534         mouseCursor = osgViewer::GraphicsWindow::TopRightCorner;
  535     else if(cursor == MOUSE_CURSOR_BOTTOMLEFT)
  536         mouseCursor = osgViewer::GraphicsWindow::BottomLeftCorner;
  537     else if(cursor == MOUSE_CURSOR_BOTTOMRIGHT)
  538         mouseCursor = osgViewer::GraphicsWindow::BottomRightCorner;
  539 
  540     gw->setCursor(mouseCursor);
  541 }
  542 
  543 static int _cursor = -1;
  544 
  545 void fgSetMouseCursor(int cursor)
  546 {
  547     _cursor = cursor;
  548     if (!viewer)
  549         return;
  550 
  551     std::vector<osgViewer::GraphicsWindow*> windows;
  552     viewer->getWindows(windows);
  553     for (osgViewer::GraphicsWindow* gw : windows) {
  554         setMouseCursor(gw, cursor);
  555     }
  556 }
  557 
  558 int fgGetMouseCursor()
  559 {
  560     return _cursor;
  561 }