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