]> git.mxchange.org Git - flightgear.git/blob - utils/fgviewer/Viewer.cxx
e84092342f226d23b0ecbb58915183360052459e
[flightgear.git] / utils / fgviewer / Viewer.cxx
1 // Viewer.cxx -- alternative flightgear viewer application
2 //
3 // Copyright (C) 2009 - 2012  Mathias Froehlich
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "Viewer.hxx"
24
25 #include <osg/ArgumentParser>
26 #include <osg/ProxyNode>
27 #include <osg/PagedLOD>
28 #include <osgDB/ReadFile>
29
30 #ifdef __linux__
31 #include <X11/Xlib.h>
32 #include <osgViewer/api/X11/GraphicsWindowX11>
33 #endif
34
35 #include "MEncoderCaptureOperation.hxx"
36
37 #include <cassert>
38
39 namespace fgviewer  {
40
41 Viewer::Viewer(osg::ArgumentParser& arguments) :
42     osgViewer::Viewer(arguments),
43     _sceneDataGroup(new osg::Group),
44     _timeIncrement(SGTimeStamp::fromSec(0)),
45     _simTime(SGTimeStamp::fromSec(0))
46 {
47     /// Careful: this method really assigns the sceneDataGroup to all cameras!
48     /// FIXME the 'useMasterScene' flag at the slave is able to get around that!!!
49     osgViewer::Viewer::setSceneData(_sceneDataGroup.get());
50     /// The only changed default that is renderer independent ...
51     getCamera()->setClearColor(osg::Vec4(0, 0, 0, 0));
52 }
53
54 Viewer::~Viewer()
55 {
56     stopThreading();
57
58 #ifdef FG_HAVE_HLA
59     if (_viewerFederate.valid())
60         _viewerFederate->shutdown();
61     _viewerFederate = 0;
62 #endif
63 }
64
65 bool
66 Viewer::readCameraConfig(const SGPropertyNode& viewerNode)
67 {
68     // Collect and realize all windows
69     for (int i = 0; i < viewerNode.nChildren(); ++i) {
70         // FIXME support window, fullscreen, offscreen
71         const SGPropertyNode* windowNode = viewerNode.getChild(i);
72         if (!windowNode || windowNode->getNameString() != "window")
73             continue;
74
75         std::string name = windowNode->getStringValue("name", "");
76         if (name.empty()) {
77             SG_LOG(SG_VIEW, SG_ALERT, "Ignoring unnamed window!");
78             return false;
79         }
80
81         Drawable* drawable = getOrCreateDrawable(name);
82
83         osg::GraphicsContext::ScreenIdentifier screenIdentifier;
84         screenIdentifier = getScreenIdentifier(windowNode->getStringValue("display", ""));
85         drawable->setScreenIdentifier(screenIdentifier.displayName());
86
87         if (windowNode->getBoolValue("fullscreen", false)) {
88             osg::GraphicsContext::ScreenSettings screenSettings;
89             screenSettings = getScreenSettings(screenIdentifier);
90             drawable->setPosition(SGVec2i(0, 0));
91             drawable->setSize(SGVec2i(screenSettings.width, screenSettings.height));
92             drawable->setFullscreen(true);
93             drawable->setOffscreen(false);
94
95         } else if (windowNode->getBoolValue("video", false)) {
96             drawable->setPosition(SGVec2i(0, 0));
97             SGVec2i size;
98             size[0] = windowNode->getIntValue("geometry/width", 1366);
99             size[1] = windowNode->getIntValue("geometry/height", 768);
100             drawable->setSize(size);
101             drawable->setFullscreen(true);
102             drawable->setOffscreen(true);
103
104             std::string outputFile = windowNode->getStringValue("output-file", "fgviewer.avi");
105             unsigned fps = windowNode->getIntValue("frames-per-second", 30);
106
107             /// This is the case for the video writers, have a fixed time increment
108             _timeIncrement = SGTimeStamp::fromSec(1.0/fps);
109
110             MEncoderCaptureOperation* captureOperation;
111             captureOperation = new MEncoderCaptureOperation(outputFile, fps);
112             osgViewer::ScreenCaptureHandler* captureHandler;
113             captureHandler = new osgViewer::ScreenCaptureHandler(captureOperation, -1);
114             addEventHandler(captureHandler);
115             captureHandler->startCapture();
116
117         } else {
118
119             SGVec2i position;
120             position[0] = windowNode->getIntValue("geometry/x", 0);
121             position[1] = windowNode->getIntValue("geometry/y", 0);
122             drawable->setPosition(position);
123             SGVec2i size;
124             size[0] = windowNode->getIntValue("geometry/width", 1366);
125             size[1] = windowNode->getIntValue("geometry/height", 768);
126             drawable->setSize(size);
127             drawable->setFullscreen(false);
128             drawable->setOffscreen(false);
129         }
130     }
131
132     for (int i = 0; i < viewerNode.nChildren(); ++i) {
133         const SGPropertyNode* cameraNode = viewerNode.getChild(i);
134         if (!cameraNode || cameraNode->getNameString() != "camera")
135             continue;
136
137         std::string name = cameraNode->getStringValue("name", "");
138         if (name.empty()) {
139             SG_LOG(SG_VIEW, SG_ALERT, "Camera configuration needs a name!");
140             return false;
141         }
142
143         SlaveCamera* slaveCamera = getOrCreateSlaveCamera(name);
144
145         std::string drawableName = cameraNode->getStringValue("window", "");
146         if (drawableName.empty()) {
147             SG_LOG(SG_VIEW, SG_ALERT, "Camera configuration needs an assigned window!");
148             return false;
149         }
150         Drawable* drawable = getDrawable(drawableName);
151         if (!drawable) {
152             SG_LOG(SG_VIEW, SG_ALERT, "Camera configuration \"" << name << "\" needs a drawable configured!");
153             return false;
154         }
155         slaveCamera->setDrawableName(drawableName);
156         drawable->attachSlaveCamera(slaveCamera);
157
158         SGVec2i size = drawable->getSize();
159         SGVec4i viewport(0, 0, size[0], size[1]);
160         viewport[0] = cameraNode->getIntValue("viewport/x", viewport[0]);
161         viewport[1] = cameraNode->getIntValue("viewport/y", viewport[1]);
162         viewport[2] = cameraNode->getIntValue("viewport/width", viewport[2]);
163         viewport[3] = cameraNode->getIntValue("viewport/height", viewport[3]);
164         slaveCamera->setViewport(viewport);
165
166         double headingDeg = cameraNode->getDoubleValue("view-offset/heading-deg", 0);
167         double pitchDeg = cameraNode->getDoubleValue("view-offset/pitch-deg", 0);
168         double rollDeg = cameraNode->getDoubleValue("view-offset/roll-deg", 0);
169         slaveCamera->setViewOffsetDeg(headingDeg, pitchDeg, rollDeg);
170
171         // Care for the reference points
172         if (const SGPropertyNode* referencePointsNode = cameraNode->getNode("reference-points")) {
173             for (int j = 0; j < referencePointsNode->nChildren(); ++j) {
174                 const SGPropertyNode* referencePointNode = cameraNode->getNode("reference-point");
175                 if (!referencePointNode)
176                     continue;
177                 std::string name = referencePointNode->getStringValue("name", "");
178                 if (name.empty())
179                     continue;
180                 osg::Vec2 point;
181                 point[0] = referencePointNode->getDoubleValue("x", 0);
182                 point[1] = referencePointNode->getDoubleValue("y", 0);
183                 slaveCamera->setProjectionReferencePoint(name, point);
184             }
185         }
186         // Define 4 reference points by monitor dimensions
187         else if (const SGPropertyNode* physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) {
188             double physicalWidth = physicalDimensionsNode->getDoubleValue("width", viewport[2]);
189             double physicalHeight = physicalDimensionsNode->getDoubleValue("height", viewport[3]);
190             if (const SGPropertyNode* bezelNode = physicalDimensionsNode->getNode("bezel")) {
191                 double bezelHeightTop = bezelNode->getDoubleValue("top", 0);
192                 double bezelHeightBottom = bezelNode->getDoubleValue("bottom", 0);
193                 double bezelWidthLeft = bezelNode->getDoubleValue("left", 0);
194                 double bezelWidthRight = bezelNode->getDoubleValue("right", 0);
195                 slaveCamera->setMonitorProjectionReferences(physicalWidth, physicalHeight,
196                                                             bezelHeightTop, bezelHeightBottom,
197                                                             bezelWidthLeft, bezelWidthRight);
198             }
199         }
200
201         // The frustum node takes precedence, as this is the most explicit one.
202         if (const SGPropertyNode* frustumNode = cameraNode->getNode("frustum")) {
203             Frustum frustum(slaveCamera->getAspectRatio());
204             frustum._near = frustumNode->getDoubleValue("near", frustum._near);
205             frustum._left = frustumNode->getDoubleValue("left", frustum._left);
206             frustum._right = frustumNode->getDoubleValue("right", frustum._right);
207             frustum._bottom = frustumNode->getDoubleValue("bottom", frustum._bottom);
208             frustum._top = frustumNode->getDoubleValue("top", frustum._top);
209             slaveCamera->setFrustum(frustum);
210
211         } else if (const SGPropertyNode* perspectiveNode = cameraNode->getNode("perspective")) {
212             double fieldOfViewDeg = perspectiveNode->getDoubleValue("field-of-view-deg", 55);
213             slaveCamera->setFustumByFieldOfViewDeg(fieldOfViewDeg);
214
215         } else if (const SGPropertyNode* monitorNode = cameraNode->getNode("monitor")) {
216
217             std::string referenceCameraName;
218             std::string names[2];
219             std::string referenceNames[2];
220
221             // FIXME??!!
222             if (const SGPropertyNode* leftOfNode = monitorNode->getNode("left-of")) {
223                 referenceCameraName = leftOfNode->getStringValue("");
224                 names[0] = "lowerRight";
225                 referenceNames[0] = "lowerLeft";
226                 names[1] = "upperRight";
227                 referenceNames[1] = "upperLeft";
228             } else if (const SGPropertyNode* rightOfNode = monitorNode->getNode("right-of")) {
229                 referenceCameraName = rightOfNode->getStringValue("");
230                 names[0] = "lowerLeft";
231                 referenceNames[0] = "lowerRight";
232                 names[1] = "upperLeft";
233                 referenceNames[1] = "upperRight";
234             } else if (const SGPropertyNode* aboveNode = monitorNode->getNode("above")) {
235                 referenceCameraName = aboveNode->getStringValue("");
236                 names[0] = "lowerLeft";
237                 referenceNames[0] = "upperLeft";
238                 names[1] = "lowerRight";
239                 referenceNames[1] = "upperRight";
240             } else if (const SGPropertyNode* belowNode = monitorNode->getNode("below")) {
241                 referenceCameraName = belowNode->getStringValue("");
242                 names[0] = "upperLeft";
243                 referenceNames[0] = "lowerLeft";
244                 names[1] = "upperRight";
245                 referenceNames[1] = "lowerRight";
246             } else {
247                 // names[0] = ;
248                 // referenceNames[0] = ;
249                 // names[1] = ;
250                 // referenceNames[1] = ;
251             }
252
253             // If we finally found a set of reference points that should match,
254             // then create a relative frustum matching these references
255             if (SlaveCamera* referenceSlaveCamera = getSlaveCamera(referenceCameraName)) {
256                 slaveCamera->setRelativeFrustum(names, *referenceSlaveCamera, referenceNames);
257             } else {
258                 SG_LOG(SG_VIEW, SG_ALERT, "Unable to find reference camera \"" << referenceCameraName
259                        << "\" for camera \"" << name << "\"!");
260             }
261         } else {
262             // Set a proper default taking the current aspect ratio into account
263             slaveCamera->setFustumByFieldOfViewDeg(55);
264         }
265     }
266
267     return true;
268 }
269
270 void
271 Viewer::setupDefaultCameraConfigIfUnset()
272 {
273     if (getNumDrawables() || getNumSlaveCameras())
274         return;
275
276     osg::GraphicsContext::ScreenIdentifier screenIdentifier;
277     screenIdentifier = getDefaultScreenIdentifier();
278
279     Drawable* drawable = getOrCreateDrawable("fgviewer");
280     drawable->setScreenIdentifier(screenIdentifier.displayName());
281     drawable->setPosition(SGVec2i(0, 0));
282     SGVec2i size(800, 600);
283     drawable->setSize(size);
284     drawable->setFullscreen(false);
285     drawable->setOffscreen(false);
286
287     SlaveCamera* slaveCamera = getOrCreateSlaveCamera(drawable->getName());
288     slaveCamera->setDrawableName(drawable->getName());
289     drawable->attachSlaveCamera(slaveCamera);
290     slaveCamera->setViewport(SGVec4i(0, 0, size[0], size[1]));
291     slaveCamera->setViewOffset(osg::Matrix::identity());
292     slaveCamera->setFustumByFieldOfViewDeg(55);
293 }
294
295 bool
296 Viewer::readConfiguration(const std::string&)
297 {
298     return false;
299 }
300
301 void
302 Viewer::setRenderer(Renderer* renderer)
303 {
304     if (!renderer) {
305         SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setRenderer(): Setting the renderer to zero is not supported!");
306         return;
307     }
308     if (_renderer.valid()) {
309         SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setRenderer(): Setting the renderer twice is not supported!");
310         return;
311     }
312     _renderer = renderer;
313 }
314
315 Renderer*
316 Viewer::getRenderer()
317 {
318     return _renderer.get();
319 }
320
321 Drawable*
322 Viewer::getOrCreateDrawable(const std::string& name)
323 {
324     Drawable* drawable = getDrawable(name);
325     if (drawable)
326         return drawable;
327     if (!_renderer.valid())
328         return 0;
329     drawable = _renderer->createDrawable(*this, name);
330     if (!drawable)
331         return 0;
332     _drawableVector.push_back(drawable);
333     return drawable;
334 }
335
336 Drawable*
337 Viewer::getDrawable(const std::string& name)
338 {
339     return getDrawable(getDrawableIndex(name));
340 }
341
342 unsigned
343 Viewer::getDrawableIndex(const std::string& name)
344 {
345     for (DrawableVector::size_type i = 0; i < _drawableVector.size(); ++i) {
346         if (_drawableVector[i]->getName() == name)
347             return i;
348     }
349     return ~0u;
350 }
351
352 Drawable*
353 Viewer::getDrawable(unsigned index)
354 {
355     if (_drawableVector.size() <= index)
356         return 0;
357     return _drawableVector[index].get();
358 }
359
360 unsigned
361 Viewer::getNumDrawables() const
362 {
363     return _drawableVector.size();
364 }
365
366 SlaveCamera*
367 Viewer::getOrCreateSlaveCamera(const std::string& name)
368 {
369     SlaveCamera* slaveCamera = getSlaveCamera(name);
370     if (slaveCamera)
371         return slaveCamera;
372     if (!_renderer.valid())
373         return 0;
374     slaveCamera = _renderer->createSlaveCamera(*this, name);
375     if (!slaveCamera)
376         return 0;
377     _slaveCameraVector.push_back(slaveCamera);
378     return slaveCamera;
379 }
380
381 SlaveCamera*
382 Viewer::getSlaveCamera(const std::string& name)
383 {
384     return getSlaveCamera(getSlaveCameraIndex(name));
385 }
386
387 unsigned
388 Viewer::getSlaveCameraIndex(const std::string& name)
389 {
390     for (SlaveCameraVector::size_type i = 0; i < _slaveCameraVector.size(); ++i) {
391         if (_slaveCameraVector[i]->getName() == name)
392             return i;
393     }
394     return ~0u;
395 }
396
397 SlaveCamera*
398 Viewer::getSlaveCamera(unsigned index)
399 {
400     if (_slaveCameraVector.size() <= index)
401         return 0;
402     return _slaveCameraVector[index].get();
403 }
404
405 unsigned
406 Viewer::getNumSlaveCameras() const
407 {
408     return _slaveCameraVector.size();
409 }
410
411 void
412 Viewer::realize()
413 {
414     if (isRealized())
415         return;
416
417     if (!_renderer.valid())
418         return;
419
420     // Setup a default config if there is none
421     setupDefaultCameraConfigIfUnset();
422
423     // Realize
424     if (!_renderer->realize(*this)) {
425         SG_LOG(SG_VIEW, SG_ALERT, "Renderer::realize() failed!");
426         return;
427     }
428
429     osgViewer::Viewer::realize();
430 }
431
432 bool
433 Viewer::realizeDrawables()
434 {
435     for (DrawableVector::iterator i = _drawableVector.begin(); i != _drawableVector.end(); ++i) {
436         if (!(*i)->realize(*this)) {
437             SG_LOG(SG_VIEW, SG_ALERT, "Unable to realize drawable \"" << (*i)->getName() << "\"!");
438             return false;
439         }
440     }
441
442     return true;
443 }
444
445 bool
446 Viewer::realizeSlaveCameras()
447 {
448     for (SlaveCameraVector::iterator i = _slaveCameraVector.begin(); i != _slaveCameraVector.end(); ++i) {
449         if (!(*i)->realize(*this)) {
450             SG_LOG(SG_VIEW, SG_ALERT, "Unable to realize camera \"" << (*i)->getName() << "\"!");
451             return false;
452         }
453     }
454
455     return true;
456 }
457
458 void
459 Viewer::advance(double)
460 {
461     if (_timeIncrement == SGTimeStamp::fromSec(0)) {
462         // Flightgears current scheme - could be improoved
463         _simTime = SGTimeStamp::now();
464     } else {
465         // Giving an explicit time increment makes sense in presence
466         // of the video capture where we need deterministic
467         // frame times and object positions for each picture.
468         _simTime += _timeIncrement;
469     }
470
471     // This sets the frame stamps simulation time to simTime
472     // and schedules a frame event
473     osgViewer::Viewer::advance(_simTime.toSecs());
474 }
475
476 void
477 Viewer::updateTraversal()
478 {
479 #ifdef FG_HAVE_HLA
480     if (_viewerFederate.valid()) {
481         if (_timeIncrement == SGTimeStamp::fromSec(0)) {
482             if (!_viewerFederate->timeAdvanceAvailable()) {
483                 SG_LOG(SG_NETWORK, SG_ALERT, "Got error from federate update!");
484                 _viewerFederate->shutdown();
485                 _viewerFederate = 0;
486             }
487         } else {
488             osg::FrameStamp* frameStamp = getViewerFrameStamp();
489             SGTimeStamp timeStamp = SGTimeStamp::fromSec(frameStamp->getSimulationTime());
490             if (!_viewerFederate->timeAdvance(timeStamp)) {
491                 SG_LOG(SG_NETWORK, SG_ALERT, "Got error from federate update!");
492                 _viewerFederate->shutdown();
493                 _viewerFederate = 0;
494             }
495         }
496     }
497 #endif
498
499     osgViewer::Viewer::updateTraversal();
500
501     if (!_renderer->update(*this)) {
502         SG_LOG(SG_VIEW, SG_ALERT, "Renderer::update() failed!");
503     }
504 }
505
506 bool
507 Viewer::updateSlaveCameras()
508 {
509     for (SlaveCameraVector::iterator i = _slaveCameraVector.begin(); i != _slaveCameraVector.end(); ++i) {
510         if (!(*i)->update(*this)) {
511             SG_LOG(SG_VIEW, SG_ALERT, "SlaveCamera::update() failed!");
512             return false;
513         }
514     }
515     return true;
516 }
517
518 void
519 Viewer::setReaderWriterOptions(simgear::SGReaderWriterOptions* readerWriterOptions)
520 {
521     _readerWriterOptions = readerWriterOptions;
522 }
523
524 simgear::SGReaderWriterOptions*
525 Viewer::getReaderWriterOptions()
526 {
527     return _readerWriterOptions.get();
528 }
529
530 void
531 Viewer::setSceneData(osg::Node* node)
532 {
533     _sceneDataGroup->removeChildren(0, _sceneDataGroup->getNumChildren());
534     insertSceneData(node);
535 }
536
537 void
538 Viewer::insertSceneData(osg::Node* node)
539 {
540     _sceneDataGroup->addChild(node);
541 }
542
543 bool
544 Viewer::insertSceneData(const std::string& fileName, const osgDB::Options* options)
545 {
546 #if 0
547     osg::ProxyNode* proxyNode = new osg::ProxyNode;
548     if (options)
549         proxyNode->setDatabaseOptions(options->clone(osg::CopyOp()));
550     else
551         proxyNode->setDatabaseOptions(_readerWriterOptions->clone(osg::CopyOp()));
552     proxyNode->setFileName(0, fileName);
553     insertSceneData(proxyNode);
554     return true;
555 #else
556     osg::ref_ptr<osg::Node> node = osgDB::readRefNodeFile(fileName, options);
557     if (!node.valid())
558         return false;
559     insertSceneData(node.get());
560     return true;
561 #endif
562 }
563
564 osg::Group*
565 Viewer::getSceneDataGroup()
566 {
567     return _sceneDataGroup.get();
568 }
569
570 class Viewer::_PurgeLevelOfDetailNodesVisitor : public osg::NodeVisitor {
571 public:
572     _PurgeLevelOfDetailNodesVisitor() :
573         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
574     { }
575     virtual ~_PurgeLevelOfDetailNodesVisitor()
576     { }
577   
578     virtual void apply(osg::ProxyNode& node)
579     {
580         for (unsigned i = 0; i < node.getNumChildren(); ++i) {
581             if (node.getFileName(i).empty())
582                 continue;
583             node.removeChildren(i, node.getNumChildren() - i);
584             break;
585         }
586
587         osg::NodeVisitor::apply(static_cast<osg::Group&>(node));
588     }
589     virtual void apply(osg::PagedLOD& node)
590     {
591         for (unsigned i = 0; i < node.getNumChildren(); ++i) {
592             if (node.getFileName(i).empty())
593                 continue;
594             node.removeChildren(i, node.getNumChildren() - i);
595             break;
596         }
597
598         osg::NodeVisitor::apply(static_cast<osg::Group&>(node));
599     }
600 };
601
602 void
603 Viewer::purgeLevelOfDetailNodes()
604 {
605     _PurgeLevelOfDetailNodesVisitor purgeLevelOfDetailNodesVisitor;
606     _sceneDataGroup->accept(purgeLevelOfDetailNodesVisitor);
607 }
608
609 osg::GraphicsContext::ScreenIdentifier
610 Viewer::getDefaultScreenIdentifier()
611 {
612     osg::GraphicsContext::ScreenIdentifier screenIdentifier;
613     screenIdentifier.readDISPLAY();
614     if (screenIdentifier.displayNum < 0)
615         screenIdentifier.displayNum = 0;
616     if (screenIdentifier.screenNum < 0)
617         screenIdentifier.screenNum = 0;
618     return screenIdentifier;
619 }
620
621 osg::GraphicsContext::ScreenIdentifier
622 Viewer::getScreenIdentifier(const std::string& display)
623 {
624     osg::GraphicsContext::ScreenIdentifier screenIdentifier;
625     screenIdentifier.setScreenIdentifier(display);
626
627     osg::GraphicsContext::ScreenIdentifier defaultScreenIdentifier;
628     defaultScreenIdentifier = getDefaultScreenIdentifier();
629     if (screenIdentifier.hostName.empty())
630         screenIdentifier.hostName = defaultScreenIdentifier.hostName;
631     if (screenIdentifier.displayNum < 0)
632         screenIdentifier.displayNum = defaultScreenIdentifier.displayNum;
633     if (screenIdentifier.screenNum < 0)
634         screenIdentifier.screenNum = defaultScreenIdentifier.screenNum;
635     
636     return screenIdentifier;
637 }
638
639 osg::GraphicsContext::ScreenSettings
640 Viewer::getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier)
641 {
642     osg::GraphicsContext::ScreenSettings screenSettings;
643
644     osg::GraphicsContext::WindowingSystemInterface* wsi;
645     wsi = osg::GraphicsContext::getWindowingSystemInterface();
646     if (!wsi) {
647         SG_LOG(SG_VIEW, SG_ALERT, "No windowing system interface defined!");
648         return screenSettings;
649     }
650
651     wsi->getScreenSettings(screenIdentifier, screenSettings);
652     return screenSettings;
653 }
654
655 osg::GraphicsContext::Traits*
656 Viewer::getTraits(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier)
657 {
658     osg::DisplaySettings* ds = _displaySettings.get();
659     if (!ds)
660         ds = osg::DisplaySettings::instance().get();
661
662     osg::GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits(ds);
663
664     traits->hostName = screenIdentifier.hostName;
665     traits->displayNum = screenIdentifier.displayNum;
666     traits->screenNum = screenIdentifier.screenNum;
667             
668     // not seriously consider something different
669     traits->doubleBuffer = true;
670
671     osg::GraphicsContext::ScreenSettings screenSettings;
672     screenSettings = getScreenSettings(screenIdentifier);
673
674     traits->x = 0;
675     traits->y = 0;
676     traits->width = screenSettings.width;
677     traits->height = screenSettings.height;
678
679     return traits;
680 }
681
682 #ifdef __linux__
683 class Viewer::_ResetScreenSaverSwapCallback : public osg::GraphicsContext::SwapCallback {
684 public:
685     _ResetScreenSaverSwapCallback() :
686         _timeStamp(SGTimeStamp::fromSec(0))
687     {
688     }
689     virtual ~_ResetScreenSaverSwapCallback()
690     {
691     }
692     virtual void swapBuffersImplementation(osg::GraphicsContext* graphicsContext)
693     {
694         graphicsContext->swapBuffersImplementation();
695
696         // This callback must be attached to this type of graphics context
697         assert(dynamic_cast<osgViewer::GraphicsWindowX11*>(graphicsContext));
698
699         // Reset the screen saver every 10 seconds
700         SGTimeStamp timeStamp = SGTimeStamp::now();
701         if (timeStamp < _timeStamp)
702             return;
703         _timeStamp = timeStamp + SGTimeStamp::fromSec(10);
704         // Obviously runs in the draw thread. Thus, use the draw display.
705         XResetScreenSaver(static_cast<osgViewer::GraphicsWindowX11*>(graphicsContext)->getDisplay());
706     }
707 private:
708     SGTimeStamp _timeStamp;
709 };
710 #endif
711
712 osg::GraphicsContext*
713 Viewer::createGraphicsContext(osg::GraphicsContext::Traits* traits)
714 {
715     osg::GraphicsContext::WindowingSystemInterface* wsi;
716     wsi = osg::GraphicsContext::getWindowingSystemInterface();
717     if (!wsi) {
718         SG_LOG(SG_VIEW, SG_ALERT, "No windowing system interface defined!");
719         return 0;
720     }
721
722     osg::GraphicsContext* graphicsContext = wsi->createGraphicsContext(traits);
723     if (!graphicsContext) {
724         SG_LOG(SG_VIEW, SG_ALERT, "Unable to create window \"" << traits->windowName << "\"!");
725         return 0;
726     }
727
728 #ifdef __linux__
729     if (dynamic_cast<osgViewer::GraphicsWindowX11*>(graphicsContext))
730         graphicsContext->setSwapCallback(new _ResetScreenSaverSwapCallback);
731 #endif
732
733     return graphicsContext;
734 }
735
736 #ifdef FG_HAVE_HLA
737 const HLAViewerFederate*
738 Viewer::getViewerFederate() const
739 {
740     return _viewerFederate.get();
741 }
742
743 HLAViewerFederate*
744 Viewer::getViewerFederate()
745 {
746     return _viewerFederate.get();
747 }
748
749 void
750 Viewer::setViewerFederate(HLAViewerFederate* viewerFederate)
751 {
752     if (!viewerFederate) {
753         SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setViewerFederate(): Setting the viewer federate to zero is not supported!");
754         return;
755     }
756     if (_viewerFederate.valid()) {
757         SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setViewerFederate(): Setting the viewer federate twice is not supported!");
758         return;
759     }
760     _viewerFederate = viewerFederate;
761     _viewerFederate->attachToViewer(this);
762 }
763 #endif
764
765 } // namespace fgviewer