#include <stdlib.h>
+// Boost
+#include <boost/algorithm/string/case_conv.hpp>
#include <boost/foreach.hpp>
#include <simgear/compiler.h>
#include <osg/Matrixd>
#include <osg/Viewport>
#include <osg/Version>
+#include <osg/Notify>
#include <osg/View>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Viewer>
using namespace flightgear;
using namespace osg;
-static osg::ref_ptr<osgViewer::Viewer> viewer;
-static osg::ref_ptr<osg::Camera> mainCamera;
+osg::ref_ptr<osgViewer::Viewer> viewer;
static void setStereoMode( const char * mode )
{
return "OFF";
}
+/**
+ * merge OSG output into our logging system, so it gets recorded to file,
+ * and so we can display a GUI console with renderer issues, especially
+ * shader compilation warnings and errors.
+ */
+class NotifyLogger : public osg::NotifyHandler
+{
+public:
+ // note this callback will be invoked by OSG from multiple threads.
+ // fortunately our Simgear logging implementation already handles
+ // that internally, so we simply pass the message on.
+ virtual void notify(osg::NotifySeverity severity, const char *message)
+ {
+ SG_LOG(SG_GL, translateSeverity(severity), message);
+
+ // Detect whether a osg::Reference derived object is deleted with a non-zero
+ // reference count. In this case trigger a segfault to get a stack trace.
+ if( strstr(message, "the final reference count was") )
+ {
+
+ int* trigger_segfault = 0;
+ *trigger_segfault = 0;
+ }
+ }
+
+private:
+ sgDebugPriority translateSeverity(osg::NotifySeverity severity)
+ {
+ switch (severity) {
+ case osg::ALWAYS:
+ case osg::FATAL: return SG_ALERT;
+ case osg::WARN: return SG_WARN;
+ case osg::NOTICE:
+ case osg::INFO: return SG_INFO;
+ case osg::DEBUG_FP:
+ case osg::DEBUG_INFO: return SG_DEBUG;
+ default: return SG_ALERT;
+ }
+ }
+};
+
+class NotifyLevelListener : public SGPropertyChangeListener
+{
+public:
+ void valueChanged(SGPropertyNode* node)
+ {
+ osg::NotifySeverity severity = osg::WARN;
+ string val = boost::to_lower_copy(string(node->getStringValue()));
+
+ if (val == "fatal") {
+ severity = osg::FATAL;
+ } else if (val == "warn") {
+ severity = osg::WARN;
+ } else if (val == "notice") {
+ severity = osg::NOTICE;
+ } else if (val == "info") {
+ severity = osg::INFO;
+ } else if ((val == "debug") || (val == "debug-info")) {
+ severity = osg::DEBUG_INFO;
+ }
+
+ osg::setNotifyLevel(severity);
+ }
+};
+
+void updateOSGNotifyLevel()
+{
+ }
+
void fgOSOpenWindow(bool stencil)
{
+ osg::setNotifyHandler(new NotifyLogger);
+
viewer = new osgViewer::Viewer;
viewer->setDatabasePager(FGScenery::getPagerSingleton());
- CameraGroup* cameraGroup = 0;
+
std::string mode;
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
if (mode == "AutomaticSelection")
else
viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
WindowBuilder::initWindowBuilder(stencil);
- WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
-
- // Look for windows, camera groups, and the old syntax of
- // top-level cameras
- SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
- SGPropertyNode* cgroupNode = renderingNode->getNode("camera-group", true);
- bool oldSyntax = !cgroupNode->hasChild("camera");
- if (oldSyntax) {
- 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<SGPropertyNode_ptr> 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());
- }
- 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());
- }
+ CameraGroup::buildDefaultGroup(viewer.get());
+
FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
if (wsa->windows.size() != 1) {
// The viewer won't start without some root.
viewer->setSceneData(new osg::Group);
globals->get_renderer()->setViewer(viewer.get());
- CameraGroup::setDefault(cameraGroup);
+}
+void fgOSResetProperties()
+{
+ SGPropertyNode* osgLevel = fgGetNode("/sim/rendering/osg-notify-level", true);
+ NotifyLevelListener* l = new NotifyLevelListener;
+ globals->addListenerToCleanup(l);
+ osgLevel->addChangeListener(l, true);
+
+ osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+ if (guiCamera) {
+ Viewport* guiViewport = guiCamera->getViewport();
+ fgSetInt("/sim/startup/xsize", guiViewport->width());
+ fgSetInt("/sim/startup/ysize", guiViewport->height());
+ }
+
DisplaySettings * displaySettings = DisplaySettings::instance();
fgTie("/sim/rendering/osg-displaysettings/eye-separation", displaySettings, &DisplaySettings::getEyeSeparation, &DisplaySettings::setEyeSeparation );
fgTie("/sim/rendering/osg-displaysettings/screen-distance", displaySettings, &DisplaySettings::getScreenDistance, &DisplaySettings::setScreenDistance );
viewer->setDone(true);
viewer->getDatabasePager()->cancel();
status = code;
+
+ // otherwise we crash if OSG does logging during static destruction, eg
+ // GraphicsWindowX11, since OSG statics may have been created before the
+ // sglog static, despite our best efforts in boostrap.cxx
+ osg::setNotifyHandler(new osg::StandardNotifyHandler);
}
int fgOSMainLoop()
{
- ref_ptr<FGEventHandler> manipulator
- = globals->get_renderer()->getEventHandler();
viewer->setReleaseContextAtEndOfFrameHint(false);
if (!viewer->isRealized())
viewer->realize();
while (!viewer->done()) {
- fgIdleHandler idleFunc = manipulator->getIdleHandler();
+ fgIdleHandler idleFunc = globals->get_renderer()->getEventHandler()->getIdleHandler();
if (idleFunc)
(*idleFunc)();
globals->get_renderer()->update();
- viewer->frame();
+ viewer->frame( globals->get_sim_time_sec() );
}
return status;
WindowSystemAdapter::setWSA(new WindowSystemAdapter);
}
-// Noop
+void fgOSCloseWindow()
+{
+ FGScenery::resetPagerSingleton();
+ flightgear::CameraGroup::setDefault(NULL);
+ WindowSystemAdapter::setWSA(NULL);
+ viewer = NULL;
+}
+
void fgOSFullScreen()
{
+ std::vector<osgViewer::GraphicsWindow*> windows;
+ viewer->getWindows(windows);
+
+ if (windows.empty())
+ return; // Huh?!?
+
+ /* Toggling window fullscreen is only supported for the main GUI window.
+ * The other windows should use fixed setup from the camera.xml file anyway. */
+ osgViewer::GraphicsWindow* window = windows[0];
+
+ {
+ osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface();
+
+ if (wsi == NULL)
+ {
+ SG_LOG(SG_VIEW, SG_ALERT, "ERROR: No WindowSystemInterface available. Cannot toggle window fullscreen.");
+ return;
+ }
+
+ static int previous_x = 0;
+ static int previous_y = 0;
+ static int previous_width = 800;
+ static int previous_height = 600;
+
+ unsigned int screenWidth;
+ unsigned int screenHeight;
+ wsi->getScreenResolution(*(window->getTraits()), screenWidth, screenHeight);
+
+ int x;
+ int y;
+ int width;
+ int height;
+ window->getWindowRectangle(x, y, width, height);
+
+ /* Note: the simple "is window size == screen size" check to detect full screen state doesn't work with
+ * X screen servers in Xinerama mode, since the reported screen width (or height) exceeds the maximum width
+ * (or height) usable by a single window (Xserver automatically shrinks/moves the full screen window to fit a
+ * single display) - so we detect full screen mode using "WindowDecoration" state instead.
+ * "false" - even when a single window is display in fullscreen */
+ //bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight;
+ bool isFullScreen = !window->getWindowDecoration();
+
+ SG_LOG(SG_VIEW, SG_DEBUG, "Toggling fullscreen. Previous window rectangle ("
+ << x << ", " << y << ") x (" << width << ", " << height << "), fullscreen: " << isFullScreen
+ << ", number of screens: " << wsi->getNumScreens());
+ if (isFullScreen)
+ {
+ // limit x,y coordinates and window size to screen area
+ if (previous_x + previous_width > (int)screenWidth)
+ previous_x = 0;
+ if (previous_y + previous_height > (int)screenHeight)
+ previous_y = 0;
+
+ // disable fullscreen mode, restore previous window size/coordinates
+ x = previous_x;
+ y = previous_y;
+ width = previous_width;
+ height = previous_height;
+ }
+ else
+ {
+ // remember previous setting
+ previous_x = x;
+ previous_y = y;
+ previous_width = width;
+ previous_height = height;
+
+ // enable fullscreen mode, set new width/height
+ x = 0;
+ y = 0;
+ width = screenWidth;
+ height = screenHeight;
+ }
+
+ // set xsize/ysize properties to adapt GUI planes
+ fgSetInt("/sim/startup/xsize", width);
+ fgSetInt("/sim/startup/ysize", height);
+
+ // reconfigure window
+ window->setWindowDecoration(isFullScreen);
+ window->setWindowRectangle(x, y, width, height);
+ window->grabFocusIfPointerInWindow();
+ }
}
static void setMouseCursor(osgViewer::GraphicsWindow* gw, int cursor)
void fgSetMouseCursor(int cursor)
{
_cursor = cursor;
-
+ if (!viewer)
+ return;
+
std::vector<osgViewer::GraphicsWindow*> windows;
viewer->getWindows(windows);
BOOST_FOREACH(osgViewer::GraphicsWindow* gw, windows) {