763 lines
25 KiB
C++
763 lines
25 KiB
C++
// Viewer.cxx -- alternative flightgear viewer application
|
|
//
|
|
// Copyright (C) 2009 - 2012 Mathias Froehlich
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License as
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "Viewer.hxx"
|
|
|
|
#include <osg/ArgumentParser>
|
|
#include <osg/ProxyNode>
|
|
#include <osg/PagedLOD>
|
|
#include <osgDB/ReadFile>
|
|
|
|
#ifdef __linux__
|
|
#include <X11/Xlib.h>
|
|
#include <osgViewer/api/X11/GraphicsWindowX11>
|
|
#endif
|
|
|
|
#include "MEncoderCaptureOperation.hxx"
|
|
|
|
namespace fgviewer {
|
|
|
|
Viewer::Viewer(osg::ArgumentParser& arguments) :
|
|
osgViewer::Viewer(arguments),
|
|
_sceneDataGroup(new osg::Group),
|
|
_timeIncrement(SGTimeStamp::fromSec(0)),
|
|
_simTime(SGTimeStamp::fromSec(0))
|
|
{
|
|
/// Careful: this method really assigns the sceneDataGroup to all cameras!
|
|
/// FIXME the 'useMasterScene' flag at the slave is able to get around that!!!
|
|
osgViewer::Viewer::setSceneData(_sceneDataGroup.get());
|
|
/// The only changed default that is renderer independent ...
|
|
getCamera()->setClearColor(osg::Vec4(0, 0, 0, 0));
|
|
}
|
|
|
|
Viewer::~Viewer()
|
|
{
|
|
stopThreading();
|
|
|
|
#ifdef FG_HAVE_HLA
|
|
if (_viewerFederate.valid())
|
|
_viewerFederate->shutdown();
|
|
_viewerFederate = 0;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
Viewer::readCameraConfig(const SGPropertyNode& viewerNode)
|
|
{
|
|
// Collect and realize all windows
|
|
for (int i = 0; i < viewerNode.nChildren(); ++i) {
|
|
// FIXME support window, fullscreen, offscreen
|
|
const SGPropertyNode* windowNode = viewerNode.getChild(i);
|
|
if (!windowNode || windowNode->getNameString() != "window")
|
|
continue;
|
|
|
|
std::string name = windowNode->getStringValue("name", "");
|
|
if (name.empty()) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Ignoring unnamed window!");
|
|
return false;
|
|
}
|
|
|
|
Drawable* drawable = getOrCreateDrawable(name);
|
|
|
|
osg::GraphicsContext::ScreenIdentifier screenIdentifier;
|
|
screenIdentifier = getScreenIdentifier(windowNode->getStringValue("display", ""));
|
|
drawable->setScreenIdentifier(screenIdentifier.displayName());
|
|
|
|
if (windowNode->getBoolValue("fullscreen", false)) {
|
|
osg::GraphicsContext::ScreenSettings screenSettings;
|
|
screenSettings = getScreenSettings(screenIdentifier);
|
|
drawable->setPosition(SGVec2i(0, 0));
|
|
drawable->setSize(SGVec2i(screenSettings.width, screenSettings.height));
|
|
drawable->setFullscreen(true);
|
|
drawable->setOffscreen(false);
|
|
|
|
} else if (windowNode->getBoolValue("video", false)) {
|
|
drawable->setPosition(SGVec2i(0, 0));
|
|
SGVec2i size;
|
|
size[0] = windowNode->getIntValue("geometry/width", 1366);
|
|
size[1] = windowNode->getIntValue("geometry/height", 768);
|
|
drawable->setSize(size);
|
|
drawable->setFullscreen(true);
|
|
drawable->setOffscreen(true);
|
|
|
|
std::string outputFile = windowNode->getStringValue("output-file", "fgviewer.avi");
|
|
unsigned fps = windowNode->getIntValue("frames-per-second", 30);
|
|
|
|
/// This is the case for the video writers, have a fixed time increment
|
|
_timeIncrement = SGTimeStamp::fromSec(1.0/fps);
|
|
|
|
MEncoderCaptureOperation* captureOperation;
|
|
captureOperation = new MEncoderCaptureOperation(outputFile, fps);
|
|
osgViewer::ScreenCaptureHandler* captureHandler;
|
|
captureHandler = new osgViewer::ScreenCaptureHandler(captureOperation, -1);
|
|
addEventHandler(captureHandler);
|
|
captureHandler->startCapture();
|
|
|
|
} else {
|
|
|
|
SGVec2i position;
|
|
position[0] = windowNode->getIntValue("geometry/x", 0);
|
|
position[1] = windowNode->getIntValue("geometry/y", 0);
|
|
drawable->setPosition(position);
|
|
SGVec2i size;
|
|
size[0] = windowNode->getIntValue("geometry/width", 1366);
|
|
size[1] = windowNode->getIntValue("geometry/height", 768);
|
|
drawable->setSize(size);
|
|
drawable->setFullscreen(false);
|
|
drawable->setOffscreen(false);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < viewerNode.nChildren(); ++i) {
|
|
const SGPropertyNode* cameraNode = viewerNode.getChild(i);
|
|
if (!cameraNode || cameraNode->getNameString() != "camera")
|
|
continue;
|
|
|
|
std::string name = cameraNode->getStringValue("name", "");
|
|
if (name.empty()) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Camera configuration needs a name!");
|
|
return false;
|
|
}
|
|
|
|
SlaveCamera* slaveCamera = getOrCreateSlaveCamera(name);
|
|
|
|
std::string drawableName = cameraNode->getStringValue("window", "");
|
|
if (drawableName.empty()) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Camera configuration needs an assigned window!");
|
|
return false;
|
|
}
|
|
Drawable* drawable = getDrawable(drawableName);
|
|
if (!drawable) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Camera configuration \"" << name << "\" needs a drawable configured!");
|
|
return false;
|
|
}
|
|
slaveCamera->setDrawableName(drawableName);
|
|
drawable->attachSlaveCamera(slaveCamera);
|
|
|
|
SGVec2i size = drawable->getSize();
|
|
SGVec4i viewport(0, 0, size[0], size[1]);
|
|
viewport[0] = cameraNode->getIntValue("viewport/x", viewport[0]);
|
|
viewport[1] = cameraNode->getIntValue("viewport/y", viewport[1]);
|
|
viewport[2] = cameraNode->getIntValue("viewport/width", viewport[2]);
|
|
viewport[3] = cameraNode->getIntValue("viewport/height", viewport[3]);
|
|
slaveCamera->setViewport(viewport);
|
|
|
|
double headingDeg = cameraNode->getDoubleValue("view-offset/heading-deg", 0);
|
|
double pitchDeg = cameraNode->getDoubleValue("view-offset/pitch-deg", 0);
|
|
double rollDeg = cameraNode->getDoubleValue("view-offset/roll-deg", 0);
|
|
slaveCamera->setViewOffsetDeg(headingDeg, pitchDeg, rollDeg);
|
|
|
|
// Care for the reference points
|
|
if (const SGPropertyNode* referencePointsNode = cameraNode->getNode("reference-points")) {
|
|
for (int j = 0; j < referencePointsNode->nChildren(); ++j) {
|
|
const SGPropertyNode* referencePointNode = cameraNode->getNode("reference-point");
|
|
if (!referencePointNode)
|
|
continue;
|
|
std::string name = referencePointNode->getStringValue("name", "");
|
|
if (name.empty())
|
|
continue;
|
|
osg::Vec2 point;
|
|
point[0] = referencePointNode->getDoubleValue("x", 0);
|
|
point[1] = referencePointNode->getDoubleValue("y", 0);
|
|
slaveCamera->setProjectionReferencePoint(name, point);
|
|
}
|
|
}
|
|
// Define 4 reference points by monitor dimensions
|
|
else if (const SGPropertyNode* physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) {
|
|
double physicalWidth = physicalDimensionsNode->getDoubleValue("width", viewport[2]);
|
|
double physicalHeight = physicalDimensionsNode->getDoubleValue("height", viewport[3]);
|
|
if (const SGPropertyNode* bezelNode = physicalDimensionsNode->getNode("bezel")) {
|
|
double bezelHeightTop = bezelNode->getDoubleValue("top", 0);
|
|
double bezelHeightBottom = bezelNode->getDoubleValue("bottom", 0);
|
|
double bezelWidthLeft = bezelNode->getDoubleValue("left", 0);
|
|
double bezelWidthRight = bezelNode->getDoubleValue("right", 0);
|
|
slaveCamera->setMonitorProjectionReferences(physicalWidth, physicalHeight,
|
|
bezelHeightTop, bezelHeightBottom,
|
|
bezelWidthLeft, bezelWidthRight);
|
|
}
|
|
}
|
|
|
|
// The frustum node takes precedence, as this is the most explicit one.
|
|
if (const SGPropertyNode* frustumNode = cameraNode->getNode("frustum")) {
|
|
Frustum frustum(slaveCamera->getAspectRatio());
|
|
frustum._near = frustumNode->getDoubleValue("near", frustum._near);
|
|
frustum._left = frustumNode->getDoubleValue("left", frustum._left);
|
|
frustum._right = frustumNode->getDoubleValue("right", frustum._right);
|
|
frustum._bottom = frustumNode->getDoubleValue("bottom", frustum._bottom);
|
|
frustum._top = frustumNode->getDoubleValue("top", frustum._top);
|
|
slaveCamera->setFrustum(frustum);
|
|
|
|
} else if (const SGPropertyNode* perspectiveNode = cameraNode->getNode("perspective")) {
|
|
double fieldOfViewDeg = perspectiveNode->getDoubleValue("field-of-view-deg", 55);
|
|
slaveCamera->setFustumByFieldOfViewDeg(fieldOfViewDeg);
|
|
|
|
} else if (const SGPropertyNode* monitorNode = cameraNode->getNode("monitor")) {
|
|
|
|
std::string referenceCameraName;
|
|
std::string names[2];
|
|
std::string referenceNames[2];
|
|
|
|
// FIXME??!!
|
|
if (const SGPropertyNode* leftOfNode = monitorNode->getNode("left-of")) {
|
|
referenceCameraName = leftOfNode->getStringValue("");
|
|
names[0] = "lowerRight";
|
|
referenceNames[0] = "lowerLeft";
|
|
names[1] = "upperRight";
|
|
referenceNames[1] = "upperLeft";
|
|
} else if (const SGPropertyNode* rightOfNode = monitorNode->getNode("right-of")) {
|
|
referenceCameraName = rightOfNode->getStringValue("");
|
|
names[0] = "lowerLeft";
|
|
referenceNames[0] = "lowerRight";
|
|
names[1] = "upperLeft";
|
|
referenceNames[1] = "upperRight";
|
|
} else if (const SGPropertyNode* aboveNode = monitorNode->getNode("above")) {
|
|
referenceCameraName = aboveNode->getStringValue("");
|
|
names[0] = "lowerLeft";
|
|
referenceNames[0] = "upperLeft";
|
|
names[1] = "lowerRight";
|
|
referenceNames[1] = "upperRight";
|
|
} else if (const SGPropertyNode* belowNode = monitorNode->getNode("below")) {
|
|
referenceCameraName = belowNode->getStringValue("");
|
|
names[0] = "upperLeft";
|
|
referenceNames[0] = "lowerLeft";
|
|
names[1] = "upperRight";
|
|
referenceNames[1] = "lowerRight";
|
|
} else {
|
|
// names[0] = ;
|
|
// referenceNames[0] = ;
|
|
// names[1] = ;
|
|
// referenceNames[1] = ;
|
|
}
|
|
|
|
// If we finally found a set of reference points that should match,
|
|
// then create a relative frustum matching these references
|
|
if (SlaveCamera* referenceSlaveCamera = getSlaveCamera(referenceCameraName)) {
|
|
slaveCamera->setRelativeFrustum(names, *referenceSlaveCamera, referenceNames);
|
|
} else {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Unable to find reference camera \"" << referenceCameraName
|
|
<< "\" for camera \"" << name << "\"!");
|
|
}
|
|
} else {
|
|
// Set a proper default taking the current aspect ratio into account
|
|
slaveCamera->setFustumByFieldOfViewDeg(55);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
Viewer::setupDefaultCameraConfigIfUnset()
|
|
{
|
|
if (getNumDrawables() || getNumSlaveCameras())
|
|
return;
|
|
|
|
osg::GraphicsContext::ScreenIdentifier screenIdentifier;
|
|
screenIdentifier = getDefaultScreenIdentifier();
|
|
|
|
Drawable* drawable = getOrCreateDrawable("fgviewer");
|
|
drawable->setScreenIdentifier(screenIdentifier.displayName());
|
|
drawable->setPosition(SGVec2i(0, 0));
|
|
SGVec2i size(800, 600);
|
|
drawable->setSize(size);
|
|
drawable->setFullscreen(false);
|
|
drawable->setOffscreen(false);
|
|
|
|
SlaveCamera* slaveCamera = getOrCreateSlaveCamera(drawable->getName());
|
|
slaveCamera->setDrawableName(drawable->getName());
|
|
drawable->attachSlaveCamera(slaveCamera);
|
|
slaveCamera->setViewport(SGVec4i(0, 0, size[0], size[1]));
|
|
slaveCamera->setViewOffset(osg::Matrix::identity());
|
|
slaveCamera->setFustumByFieldOfViewDeg(55);
|
|
}
|
|
|
|
bool
|
|
Viewer::readConfiguration(const std::string&)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void
|
|
Viewer::setRenderer(Renderer* renderer)
|
|
{
|
|
if (!renderer) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setRenderer(): Setting the renderer to zero is not supported!");
|
|
return;
|
|
}
|
|
if (_renderer.valid()) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setRenderer(): Setting the renderer twice is not supported!");
|
|
return;
|
|
}
|
|
_renderer = renderer;
|
|
}
|
|
|
|
Renderer*
|
|
Viewer::getRenderer()
|
|
{
|
|
return _renderer.get();
|
|
}
|
|
|
|
Drawable*
|
|
Viewer::getOrCreateDrawable(const std::string& name)
|
|
{
|
|
Drawable* drawable = getDrawable(name);
|
|
if (drawable)
|
|
return drawable;
|
|
if (!_renderer.valid())
|
|
return 0;
|
|
drawable = _renderer->createDrawable(*this, name);
|
|
if (!drawable)
|
|
return 0;
|
|
_drawableVector.push_back(drawable);
|
|
return drawable;
|
|
}
|
|
|
|
Drawable*
|
|
Viewer::getDrawable(const std::string& name)
|
|
{
|
|
return getDrawable(getDrawableIndex(name));
|
|
}
|
|
|
|
unsigned
|
|
Viewer::getDrawableIndex(const std::string& name)
|
|
{
|
|
for (DrawableVector::size_type i = 0; i < _drawableVector.size(); ++i) {
|
|
if (_drawableVector[i]->getName() == name)
|
|
return i;
|
|
}
|
|
return ~0u;
|
|
}
|
|
|
|
Drawable*
|
|
Viewer::getDrawable(unsigned index)
|
|
{
|
|
if (_drawableVector.size() <= index)
|
|
return 0;
|
|
return _drawableVector[index].get();
|
|
}
|
|
|
|
unsigned
|
|
Viewer::getNumDrawables() const
|
|
{
|
|
return _drawableVector.size();
|
|
}
|
|
|
|
SlaveCamera*
|
|
Viewer::getOrCreateSlaveCamera(const std::string& name)
|
|
{
|
|
SlaveCamera* slaveCamera = getSlaveCamera(name);
|
|
if (slaveCamera)
|
|
return slaveCamera;
|
|
if (!_renderer.valid())
|
|
return 0;
|
|
slaveCamera = _renderer->createSlaveCamera(*this, name);
|
|
if (!slaveCamera)
|
|
return 0;
|
|
_slaveCameraVector.push_back(slaveCamera);
|
|
return slaveCamera;
|
|
}
|
|
|
|
SlaveCamera*
|
|
Viewer::getSlaveCamera(const std::string& name)
|
|
{
|
|
return getSlaveCamera(getSlaveCameraIndex(name));
|
|
}
|
|
|
|
unsigned
|
|
Viewer::getSlaveCameraIndex(const std::string& name)
|
|
{
|
|
for (SlaveCameraVector::size_type i = 0; i < _slaveCameraVector.size(); ++i) {
|
|
if (_slaveCameraVector[i]->getName() == name)
|
|
return i;
|
|
}
|
|
return ~0u;
|
|
}
|
|
|
|
SlaveCamera*
|
|
Viewer::getSlaveCamera(unsigned index)
|
|
{
|
|
if (_slaveCameraVector.size() <= index)
|
|
return 0;
|
|
return _slaveCameraVector[index].get();
|
|
}
|
|
|
|
unsigned
|
|
Viewer::getNumSlaveCameras() const
|
|
{
|
|
return _slaveCameraVector.size();
|
|
}
|
|
|
|
void
|
|
Viewer::realize()
|
|
{
|
|
if (isRealized())
|
|
return;
|
|
|
|
if (!_renderer.valid())
|
|
return;
|
|
|
|
// Setup a default config if there is none
|
|
setupDefaultCameraConfigIfUnset();
|
|
|
|
// Realize
|
|
if (!_renderer->realize(*this)) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Renderer::realize() failed!");
|
|
return;
|
|
}
|
|
|
|
osgViewer::Viewer::realize();
|
|
}
|
|
|
|
bool
|
|
Viewer::realizeDrawables()
|
|
{
|
|
for (DrawableVector::iterator i = _drawableVector.begin(); i != _drawableVector.end(); ++i) {
|
|
if (!(*i)->realize(*this)) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Unable to realize drawable \"" << (*i)->getName() << "\"!");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
Viewer::realizeSlaveCameras()
|
|
{
|
|
for (SlaveCameraVector::iterator i = _slaveCameraVector.begin(); i != _slaveCameraVector.end(); ++i) {
|
|
if (!(*i)->realize(*this)) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Unable to realize camera \"" << (*i)->getName() << "\"!");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
Viewer::advance(double)
|
|
{
|
|
if (_timeIncrement == SGTimeStamp::fromSec(0)) {
|
|
// Flightgears current scheme - could be improoved
|
|
_simTime = SGTimeStamp::now();
|
|
} else {
|
|
// Giving an explicit time increment makes sense in presence
|
|
// of the video capture where we need deterministic
|
|
// frame times and object positions for each picture.
|
|
_simTime += _timeIncrement;
|
|
}
|
|
|
|
// This sets the frame stamps simulation time to simTime
|
|
// and schedules a frame event
|
|
osgViewer::Viewer::advance(_simTime.toSecs());
|
|
}
|
|
|
|
void
|
|
Viewer::updateTraversal()
|
|
{
|
|
#ifdef FG_HAVE_HLA
|
|
if (_viewerFederate.valid()) {
|
|
if (_timeIncrement == SGTimeStamp::fromSec(0)) {
|
|
if (!_viewerFederate->timeAdvanceAvailable()) {
|
|
SG_LOG(SG_NETWORK, SG_ALERT, "Got error from federate update!");
|
|
_viewerFederate->shutdown();
|
|
_viewerFederate = 0;
|
|
}
|
|
} else {
|
|
osg::FrameStamp* frameStamp = getViewerFrameStamp();
|
|
SGTimeStamp timeStamp = SGTimeStamp::fromSec(frameStamp->getSimulationTime());
|
|
if (!_viewerFederate->timeAdvance(timeStamp)) {
|
|
SG_LOG(SG_NETWORK, SG_ALERT, "Got error from federate update!");
|
|
_viewerFederate->shutdown();
|
|
_viewerFederate = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
osgViewer::Viewer::updateTraversal();
|
|
|
|
if (!_renderer->update(*this)) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Renderer::update() failed!");
|
|
}
|
|
}
|
|
|
|
bool
|
|
Viewer::updateSlaveCameras()
|
|
{
|
|
for (SlaveCameraVector::iterator i = _slaveCameraVector.begin(); i != _slaveCameraVector.end(); ++i) {
|
|
if (!(*i)->update(*this)) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "SlaveCamera::update() failed!");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
Viewer::setReaderWriterOptions(simgear::SGReaderWriterOptions* readerWriterOptions)
|
|
{
|
|
_readerWriterOptions = readerWriterOptions;
|
|
}
|
|
|
|
simgear::SGReaderWriterOptions*
|
|
Viewer::getReaderWriterOptions()
|
|
{
|
|
return _readerWriterOptions.get();
|
|
}
|
|
|
|
void
|
|
Viewer::setSceneData(osg::Node* node)
|
|
{
|
|
_sceneDataGroup->removeChildren(0, _sceneDataGroup->getNumChildren());
|
|
insertSceneData(node);
|
|
}
|
|
|
|
void
|
|
Viewer::insertSceneData(osg::Node* node)
|
|
{
|
|
_sceneDataGroup->addChild(node);
|
|
}
|
|
|
|
bool
|
|
Viewer::insertSceneData(const std::string& fileName, const osgDB::Options* options)
|
|
{
|
|
#if 0
|
|
osg::ProxyNode* proxyNode = new osg::ProxyNode;
|
|
if (options)
|
|
proxyNode->setDatabaseOptions(options->clone(osg::CopyOp()));
|
|
else
|
|
proxyNode->setDatabaseOptions(_readerWriterOptions->clone(osg::CopyOp()));
|
|
proxyNode->setFileName(0, fileName);
|
|
insertSceneData(proxyNode);
|
|
return true;
|
|
#else
|
|
osg::ref_ptr<osg::Node> node = osgDB::readRefNodeFile(fileName, options);
|
|
if (!node.valid())
|
|
return false;
|
|
insertSceneData(node.get());
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
osg::Group*
|
|
Viewer::getSceneDataGroup()
|
|
{
|
|
return _sceneDataGroup.get();
|
|
}
|
|
|
|
class Viewer::_PurgeLevelOfDetailNodesVisitor : public osg::NodeVisitor {
|
|
public:
|
|
_PurgeLevelOfDetailNodesVisitor() :
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
|
|
{ }
|
|
virtual ~_PurgeLevelOfDetailNodesVisitor()
|
|
{ }
|
|
|
|
virtual void apply(osg::ProxyNode& node)
|
|
{
|
|
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
|
|
if (node.getFileName(i).empty())
|
|
continue;
|
|
node.removeChildren(i, node.getNumChildren() - i);
|
|
break;
|
|
}
|
|
|
|
osg::NodeVisitor::apply(static_cast<osg::Group&>(node));
|
|
}
|
|
virtual void apply(osg::PagedLOD& node)
|
|
{
|
|
for (unsigned i = 0; i < node.getNumChildren(); ++i) {
|
|
if (node.getFileName(i).empty())
|
|
continue;
|
|
node.removeChildren(i, node.getNumChildren() - i);
|
|
break;
|
|
}
|
|
|
|
osg::NodeVisitor::apply(static_cast<osg::Group&>(node));
|
|
}
|
|
};
|
|
|
|
void
|
|
Viewer::purgeLevelOfDetailNodes()
|
|
{
|
|
_PurgeLevelOfDetailNodesVisitor purgeLevelOfDetailNodesVisitor;
|
|
_sceneDataGroup->accept(purgeLevelOfDetailNodesVisitor);
|
|
}
|
|
|
|
osg::GraphicsContext::ScreenIdentifier
|
|
Viewer::getDefaultScreenIdentifier()
|
|
{
|
|
osg::GraphicsContext::ScreenIdentifier screenIdentifier;
|
|
screenIdentifier.readDISPLAY();
|
|
if (screenIdentifier.displayNum < 0)
|
|
screenIdentifier.displayNum = 0;
|
|
if (screenIdentifier.screenNum < 0)
|
|
screenIdentifier.screenNum = 0;
|
|
return screenIdentifier;
|
|
}
|
|
|
|
osg::GraphicsContext::ScreenIdentifier
|
|
Viewer::getScreenIdentifier(const std::string& display)
|
|
{
|
|
osg::GraphicsContext::ScreenIdentifier screenIdentifier;
|
|
screenIdentifier.setScreenIdentifier(display);
|
|
|
|
osg::GraphicsContext::ScreenIdentifier defaultScreenIdentifier;
|
|
defaultScreenIdentifier = getDefaultScreenIdentifier();
|
|
if (screenIdentifier.hostName.empty())
|
|
screenIdentifier.hostName = defaultScreenIdentifier.hostName;
|
|
if (screenIdentifier.displayNum < 0)
|
|
screenIdentifier.displayNum = defaultScreenIdentifier.displayNum;
|
|
if (screenIdentifier.screenNum < 0)
|
|
screenIdentifier.screenNum = defaultScreenIdentifier.screenNum;
|
|
|
|
return screenIdentifier;
|
|
}
|
|
|
|
osg::GraphicsContext::ScreenSettings
|
|
Viewer::getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier)
|
|
{
|
|
osg::GraphicsContext::ScreenSettings screenSettings;
|
|
|
|
osg::GraphicsContext::WindowingSystemInterface* wsi;
|
|
wsi = osg::GraphicsContext::getWindowingSystemInterface();
|
|
if (!wsi) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "No windowing system interface defined!");
|
|
return screenSettings;
|
|
}
|
|
|
|
wsi->getScreenSettings(screenIdentifier, screenSettings);
|
|
return screenSettings;
|
|
}
|
|
|
|
osg::GraphicsContext::Traits*
|
|
Viewer::getTraits(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier)
|
|
{
|
|
osg::DisplaySettings* ds = _displaySettings.get();
|
|
if (!ds)
|
|
ds = osg::DisplaySettings::instance().get();
|
|
|
|
osg::GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits(ds);
|
|
|
|
traits->hostName = screenIdentifier.hostName;
|
|
traits->displayNum = screenIdentifier.displayNum;
|
|
traits->screenNum = screenIdentifier.screenNum;
|
|
|
|
// not seriously consider something different
|
|
traits->doubleBuffer = true;
|
|
|
|
osg::GraphicsContext::ScreenSettings screenSettings;
|
|
screenSettings = getScreenSettings(screenIdentifier);
|
|
|
|
traits->x = 0;
|
|
traits->y = 0;
|
|
traits->width = screenSettings.width;
|
|
traits->height = screenSettings.height;
|
|
|
|
return traits;
|
|
}
|
|
|
|
#ifdef __linux__
|
|
class Viewer::_ResetScreenSaverSwapCallback : public osg::GraphicsContext::SwapCallback {
|
|
public:
|
|
_ResetScreenSaverSwapCallback() :
|
|
_timeStamp(SGTimeStamp::fromSec(0))
|
|
{
|
|
}
|
|
virtual ~_ResetScreenSaverSwapCallback()
|
|
{
|
|
}
|
|
virtual void swapBuffersImplementation(osg::GraphicsContext* graphicsContext)
|
|
{
|
|
graphicsContext->swapBuffersImplementation();
|
|
|
|
// This callback must be attached to this type of graphics context
|
|
assert(dynamic_cast<osgViewer::GraphicsWindowX11*>(graphicsContext));
|
|
|
|
// Reset the screen saver every 10 seconds
|
|
SGTimeStamp timeStamp = SGTimeStamp::now();
|
|
if (timeStamp < _timeStamp)
|
|
return;
|
|
_timeStamp = timeStamp + SGTimeStamp::fromSec(10);
|
|
// Obviously runs in the draw thread. Thus, use the draw display.
|
|
XResetScreenSaver(static_cast<osgViewer::GraphicsWindowX11*>(graphicsContext)->getDisplay());
|
|
}
|
|
private:
|
|
SGTimeStamp _timeStamp;
|
|
};
|
|
#endif
|
|
|
|
osg::GraphicsContext*
|
|
Viewer::createGraphicsContext(osg::GraphicsContext::Traits* traits)
|
|
{
|
|
osg::GraphicsContext::WindowingSystemInterface* wsi;
|
|
wsi = osg::GraphicsContext::getWindowingSystemInterface();
|
|
if (!wsi) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "No windowing system interface defined!");
|
|
return 0;
|
|
}
|
|
|
|
osg::GraphicsContext* graphicsContext = wsi->createGraphicsContext(traits);
|
|
if (!graphicsContext) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Unable to create window \"" << traits->windowName << "\"!");
|
|
return 0;
|
|
}
|
|
|
|
#ifdef __linux__
|
|
if (dynamic_cast<osgViewer::GraphicsWindowX11*>(graphicsContext))
|
|
graphicsContext->setSwapCallback(new _ResetScreenSaverSwapCallback);
|
|
#endif
|
|
|
|
return graphicsContext;
|
|
}
|
|
|
|
#ifdef FG_HAVE_HLA
|
|
const HLAViewerFederate*
|
|
Viewer::getViewerFederate() const
|
|
{
|
|
return _viewerFederate.get();
|
|
}
|
|
|
|
HLAViewerFederate*
|
|
Viewer::getViewerFederate()
|
|
{
|
|
return _viewerFederate.get();
|
|
}
|
|
|
|
void
|
|
Viewer::setViewerFederate(HLAViewerFederate* viewerFederate)
|
|
{
|
|
if (!viewerFederate) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setViewerFederate(): Setting the viewer federate to zero is not supported!");
|
|
return;
|
|
}
|
|
if (_viewerFederate.valid()) {
|
|
SG_LOG(SG_VIEW, SG_ALERT, "Viewer::setViewerFederate(): Setting the viewer federate twice is not supported!");
|
|
return;
|
|
}
|
|
_viewerFederate = viewerFederate;
|
|
_viewerFederate->attachToViewer(this);
|
|
}
|
|
#endif
|
|
|
|
} // namespace fgviewer
|