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