/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library 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 * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include using namespace osgViewer; Viewer::Viewer() { _viewerBase = this; constructorInit(); } Viewer::Viewer(osg::ArgumentParser& arguments) { _viewerBase = this; constructorInit(); std::string filename; bool readConfig = false; while (arguments.read("-c",filename)) { readConfig = readConfiguration(filename) || readConfig; } while (arguments.read("--SingleThreaded")) setThreadingModel(SingleThreaded); while (arguments.read("--CullDrawThreadPerContext")) setThreadingModel(CullDrawThreadPerContext); while (arguments.read("--DrawThreadPerContext")) setThreadingModel(DrawThreadPerContext); while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) setThreadingModel(CullThreadPerCameraDrawThreadPerContext); osg::DisplaySettings::instance()->readCommandLine(arguments); osgDB::readCommandLine(arguments); std::string colorStr; while (arguments.read("--clear-color",colorStr)) { float r, g, b; float a = 1.0f; int cnt = sscanf( colorStr.c_str(), "%f,%f,%f,%f", &r, &g, &b, &a ); if( cnt==3 || cnt==4 ) getCamera()->setClearColor( osg::Vec4(r,g,b,a) ); else osg::notify(osg::WARN)<<"Invalid clear color \""< intensityMap = intensityMapFilename.empty() ? 0 : osgDB::readImageFile(intensityMapFilename); if (screenNum<0) screenNum = 0; if (ss3d) { setThreadingModel(SingleThreaded); setUpViewFor3DSphericalDisplay(radius, collar, screenNum, intensityMap.get()); } else { setThreadingModel(SingleThreaded); setUpViewForPanoramicSphericalDisplay(radius, collar, screenNum, intensityMap.get()); } } else if (width>0 && height>0) { if (screenNum>=0) setUpViewInWindow(x, y, width, height, screenNum); else setUpViewInWindow(x,y,width,height); } else if (screenNum>=0) { setUpViewOnSingleScreen(screenNum); } } Viewer::Viewer(const osgViewer::Viewer& viewer, const osg::CopyOp& copyop): View(viewer,copyop) { _viewerBase = this; } void Viewer::constructorInit() { _eventVisitor = new osgGA::EventVisitor; _eventVisitor->setActionAdapter(this); _eventVisitor->setFrameStamp(_frameStamp.get()); _updateVisitor = new osgUtil::UpdateVisitor; _updateVisitor->setFrameStamp(_frameStamp.get()); setStats(new osg::Stats("Viewer")); } Viewer::~Viewer() { //osg::notify(osg::NOTICE)<<"Viewer::~Viewer()"< object = osgDB::readObjectFile(filename); if (!object) { osg::notify(osg::NOTICE)<<"Error: Unable to load configuration file \""<(object.get()); if (compositeViewer) { osg::notify(osg::NOTICE)<<"Error: Config file \""<(object.get()); if (view) { take(*view); return true; } else { osg::notify(osg::NOTICE)<<"Error: Config file \""<(this)->getContexts(contexts); unsigned int numRealizedWindows = 0; // clear out all the previously assigned operations for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { if ((*citr)->isRealized()) ++numRealizedWindows; } return numRealizedWindows > 0; } int Viewer::run() { if (!getCameraManipulator() && getCamera()->getAllowEventFocus()) { setCameraManipulator(new osgGA::TrackballManipulator()); } return ViewerBase::run(); } void Viewer::setStartTick(osg::Timer_t tick) { View::setStartTick(tick); Contexts contexts; getContexts(contexts,false); getEventQueue()->setStartTick(_startTick); for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->getEventQueue()->setStartTick(_startTick); } } } void Viewer::setReferenceTime(double time) { osg::Timer_t tick = osg::Timer::instance()->tick(); double currentTime = osg::Timer::instance()->delta_s(_startTick, tick); double delta_ticks = (time-currentTime)*(osg::Timer::instance()->getSecondsPerTick()); if (delta_ticks>=0) tick += osg::Timer_t(delta_ticks); else tick -= osg::Timer_t(-delta_ticks); // assign the new start tick setStartTick(tick); } void Viewer::setSceneData(osg::Node* node) { setReferenceTime(0.0); View::setSceneData(node); if (_threadingModel!=SingleThreaded) { // make sure that existing scene graph objects are allocated with thread safe ref/unref getSceneData()->setThreadSafeRefUnref(true); // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it. getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts()); } } GraphicsWindowEmbedded* Viewer::setUpViewerAsEmbeddedInWindow(int x, int y, int width, int height) { setThreadingModel(SingleThreaded); osgViewer::GraphicsWindowEmbedded* gw = new osgViewer::GraphicsWindowEmbedded(x,y,width,height); getCamera()->setViewport(new osg::Viewport(0,0,width,height)); getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(width)/static_cast(height), 1.0f, 10000.0f); getCamera()->setGraphicsContext(gw); return gw; } void Viewer::realize() { //osg::notify(osg::INFO)<<"Viewer::realize()"<> x >> y >> width >> height; } if (width>0 && height>0) { if (screenNum>=0) setUpViewInWindow(x, y, width, height, screenNum); else setUpViewInWindow(x,y,width,height); } else if (screenNum>=0) { setUpViewOnSingleScreen(screenNum); } else { setUpViewAcrossAllScreens(); } } getContexts(contexts); } if (contexts.empty()) { osg::notify(osg::NOTICE)<<"Viewer::realize() - failed to set up any windows"<realize(); if (_realizeOperation.valid() && gc->valid()) { gc->makeCurrent(); (*_realizeOperation)(gc); gc->releaseContext(); } } bool grabFocus = true; if (grabFocus) { for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->grabFocusIfPointerInWindow(); } } } // initialize the global timer to be relative to the current time. osg::Timer::instance()->setStartTick(); // pass on the start tick to all the associated event queues setStartTick(osg::Timer::instance()->getStartTick()); setUpThreading(); if (osg::DisplaySettings::instance()->getCompileContextsHint()) { int numProcessors = OpenThreads::GetNumberOfProcessors(); int processNum = 0; for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i) { osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i); if (gc) { gc->createGraphicsThread(); gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors); gc->getGraphicsThread()->startThread(); ++processNum; } } } } void Viewer::advance(double simulationTime) { if (_done) return; double prevousReferenceTime = _frameStamp->getReferenceTime(); int previousFrameNumber = _frameStamp->getFrameNumber(); _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1); _frameStamp->setReferenceTime( osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()) ); if (simulationTime==USE_REFERENCE_TIME) { _frameStamp->setSimulationTime(_frameStamp->getReferenceTime()); } else { _frameStamp->setSimulationTime(simulationTime); } if (getStats() && getStats()->collectStats("frame_rate")) { // update previous frame stats double deltaFrameTime = _frameStamp->getReferenceTime() - prevousReferenceTime; getStats()->setAttribute(previousFrameNumber, "Frame duration", deltaFrameTime); getStats()->setAttribute(previousFrameNumber, "Frame rate", 1.0/deltaFrameTime); // update current frames stats getStats()->setAttribute(_frameStamp->getFrameNumber(), "Reference time", _frameStamp->getReferenceTime()); } if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->flush(); osg::Referenced::getDeleteHandler()->setFrameNumber(_frameStamp->getFrameNumber()); } } void Viewer::eventTraversal() { if (_done) return; double beginEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // osg::notify(osg::NOTICE)<<"Viewer::frameEventTraversal()."<getCurrentEventState(); osg::Matrix masterCameraVPW = getCamera()->getViewMatrix() * getCamera()->getProjectionMatrix(); if (getCamera()->getViewport()) { osg::Viewport* viewport = getCamera()->getViewport(); masterCameraVPW *= viewport->computeWindowMatrix(); eventState->setInputRange( viewport->x(), viewport->y(), viewport->x() + viewport->width(), viewport->y() + viewport->height()); } else { eventState->setInputRange(-1.0, -1.0, 1.0, 1.0); } for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->checkEvents(); osgGA::EventQueue::Events gw_events; gw->getEventQueue()->takeEvents(gw_events); osgGA::EventQueue::Events::iterator itr; for(itr = gw_events.begin(); itr != gw_events.end(); ++itr) { osgGA::GUIEventAdapter* event = itr->get(); bool pointerEvent = false; float x = event->getX(); float y = event->getY(); bool invert_y = event->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y; switch(event->getEventType()) { case(osgGA::GUIEventAdapter::PUSH): case(osgGA::GUIEventAdapter::RELEASE): case(osgGA::GUIEventAdapter::DRAG): case(osgGA::GUIEventAdapter::MOVE): { pointerEvent = true; if (event->getEventType()!=osgGA::GUIEventAdapter::DRAG || !getCameraWithFocus()) { osg::GraphicsContext::Cameras& cameras = gw->getCameras(); for(osg::GraphicsContext::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { osg::Camera* camera = *citr; if (camera->getView()==this && camera->getAllowEventFocus() && camera->getRenderTargetImplementation()==osg::Camera::FRAME_BUFFER) { osg::Viewport* viewport = camera ? camera->getViewport() : 0; if (viewport && x >= viewport->x() && y >= viewport->y() && x <= (viewport->x()+viewport->width()) && y <= (viewport->y()+viewport->height()) ) { // osg::notify(osg::NOTICE)<<"setCamera with focus "<getName()<<" x="<get(); switch(event->getEventType()) { case(osgGA::GUIEventAdapter::PUSH): osg::notify(osg::NOTICE)<<" PUSH "<getButton()<<" x="<getX()<<" y="<getY()<getButton()<<" x="<getX()<<" y="<getY()<getButtonMask()<<" x="<getX()<<" y="<getY()<getButtonMask()<<" x="<getX()<<" y="<getY()<getScrollingMotion()<getKey()<<"'"<getKey()<<"'"<getWindowX()<<"/"<getWindowY()<<" x "<getWindowWidth()<<"/"<getWindowHeight() << std::endl; break; case(osgGA::GUIEventAdapter::QUIT_APPLICATION): osg::notify(osg::NOTICE)<<" QUIT_APPLICATION " << std::endl; break; case(osgGA::GUIEventAdapter::FRAME): // osg::notify(osg::NOTICE)<<" FRAME "<get(); switch(event->getEventType()) { case(osgGA::GUIEventAdapter::KEYUP): if (_keyEventSetsDone && event->getKey()==_keyEventSetsDone) _done = true; break; case(osgGA::GUIEventAdapter::QUIT_APPLICATION): if (_quitEventSetsDone) _done = true; break; default: break; } } } if (_done) return; for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::GUIEventAdapter* event = itr->get(); for(EventHandlers::iterator hitr = _eventHandlers.begin(); hitr != _eventHandlers.end(); ++hitr) { (*hitr)->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *this, 0, 0); } if (_cameraManipulator.valid()) { _cameraManipulator->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *this); } } if (_eventVisitor.valid() && _scene.valid()) { _eventVisitor->setFrameStamp(getFrameStamp()); _eventVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber()); for(osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr) { osgGA::GUIEventAdapter* event = itr->get(); _eventVisitor->reset(); _eventVisitor->addEvent( event ); getSceneData()->accept(*_eventVisitor); // call any camera update callbacks, but only traverse that callback, don't traverse its subgraph // leave that to the scene update traversal. osg::NodeVisitor::TraversalMode tm = _eventVisitor->getTraversalMode(); _eventVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE); if (_camera.valid() && _camera->getEventCallback()) _camera->accept(*_eventVisitor); for(unsigned int i=0; igetEventCallback()) camera->accept(*_eventVisitor); } _eventVisitor->setTraversalMode(tm); } } if (getStats() && getStats()->collectStats("event")) { double endEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // update current frames stats getStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal begin time", beginEventTraversal); getStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal end time", endEventTraversal); getStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal time taken", endEventTraversal-beginEventTraversal); } } void Viewer::updateTraversal() { if (_done) return; double beginUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); _updateVisitor->reset(); _updateVisitor->setFrameStamp(getFrameStamp()); _updateVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber()); if (getSceneData()) { getSceneData()->accept(*_updateVisitor); } if (_scene->getDatabasePager()) { // synchronize changes required by the DatabasePager thread to the scene graph _scene->getDatabasePager()->updateSceneGraph(_frameStamp->getReferenceTime()); } if (_updateOperations.valid()) { _updateOperations->runOperations(this); } { // call any camera update callbacks, but only traverse that callback, don't traverse its subgraph // leave that to the scene update traversal. osg::NodeVisitor::TraversalMode tm = _updateVisitor->getTraversalMode(); _updateVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE); if (_camera.valid() && _camera->getUpdateCallback()) _camera->accept(*_updateVisitor); for(unsigned int i=0; igetUpdateCallback()) camera->accept(*_updateVisitor); } _updateVisitor->setTraversalMode(tm); } if (_cameraManipulator.valid()) { setFusionDistance( getCameraManipulator()->getFusionDistanceMode(), getCameraManipulator()->getFusionDistanceValue() ); _camera->setViewMatrix(_cameraManipulator->getInverseMatrix()); } updateSlaves(); if (getStats() && getStats()->collectStats("update")) { double endUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // update current frames stats getStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal begin time", beginUpdateTraversal); getStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal end time", endUpdateTraversal); getStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal time taken", endUpdateTraversal-beginUpdateTraversal); } } void Viewer::getScenes(Scenes& scenes, bool onlyValid) { scenes.push_back(_scene.get()); } void Viewer::getViews(Views& views, bool onlyValid) { views.push_back(this); } void Viewer::getWindows(Windows& windows, bool onlyValid) { windows.clear(); Contexts contexts; getContexts(contexts, onlyValid); for(Contexts::iterator itr = contexts.begin(); itr != contexts.end(); ++itr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*itr); if (gw) windows.push_back(gw); } } void Viewer::getAllThreads(Threads& threads, bool onlyActive) { OperationThreads operationThreads; getOperationThreads(operationThreads); for(OperationThreads::iterator itr = operationThreads.begin(); itr != operationThreads.end(); ++itr) { threads.push_back(*itr); } if (_scene.valid() && _scene->getDatabasePager() && (!onlyActive || _scene->getDatabasePager()->isRunning())) { threads.push_back(_scene->getDatabasePager()); } } void Viewer::getOperationThreads(OperationThreads& threads, bool onlyActive) { threads.clear(); Contexts contexts; getContexts(contexts); for(Contexts::iterator gcitr = contexts.begin(); gcitr != contexts.end(); ++gcitr) { osg::GraphicsContext* gc = *gcitr; if (gc->getGraphicsThread() && (!onlyActive || gc->getGraphicsThread()->isRunning()) ) { threads.push_back(gc->getGraphicsThread()); } } Cameras cameras; getCameras(cameras); for(Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr) { osg::Camera* camera = *citr; if (camera->getCameraThread() && (!onlyActive || camera->getCameraThread()->isRunning()) ) { threads.push_back(camera->getCameraThread()); } } } struct LessGraphicsContext { bool operator () (const osg::GraphicsContext* lhs, const osg::GraphicsContext* rhs) const { int screenLeft = lhs->getTraits()? lhs->getTraits()->screenNum : 0; int screenRight = rhs->getTraits()? rhs->getTraits()->screenNum : 0; if (screenLeft < screenRight) return true; if (screenLeft > screenRight) return false; screenLeft = lhs->getTraits()? lhs->getTraits()->x : 0; screenRight = rhs->getTraits()? rhs->getTraits()->x : 0; if (screenLeft < screenRight) return true; if (screenLeft > screenRight) return false; screenLeft = lhs->getTraits()? lhs->getTraits()->y : 0; screenRight = rhs->getTraits()? rhs->getTraits()->y : 0; if (screenLeft < screenRight) return true; if (screenLeft > screenRight) return false; return lhs < rhs; } }; void Viewer::getContexts(Contexts& contexts, bool onlyValid) { typedef std::set ContextSet; ContextSet contextSet; if (_camera.valid() && _camera->getGraphicsContext() && (_camera->getGraphicsContext()->valid() || !onlyValid)) { contextSet.insert(_camera->getGraphicsContext()); } for(unsigned int i=0; igetGraphicsContext() && (slave._camera->getGraphicsContext()->valid() || !onlyValid)) { contextSet.insert(slave._camera->getGraphicsContext()); } } contexts.clear(); contexts.reserve(contextSet.size()); for(ContextSet::iterator itr = contextSet.begin(); itr != contextSet.end(); ++itr) { contexts.push_back(const_cast(*itr)); } if (contexts.size()>=2) { std::sort(contexts.begin(), contexts.end(), LessGraphicsContext()); } } void Viewer::getCameras(Cameras& cameras, bool onlyActive) { cameras.clear(); if (_camera.valid() && (!onlyActive || (_camera->getGraphicsContext() && _camera->getGraphicsContext()->valid())) ) cameras.push_back(_camera.get()); for(Slaves::iterator itr = _slaves.begin(); itr != _slaves.end(); ++itr) { if (itr->_camera.valid() && (!onlyActive || (itr->_camera->getGraphicsContext() && itr->_camera->getGraphicsContext()->valid())) ) cameras.push_back(itr->_camera.get()); } } double Viewer::elapsedTime() { return osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); } void Viewer::getUsage(osg::ApplicationUsage& usage) const { if (_cameraManipulator.valid()) { _cameraManipulator->getUsage(usage); } for(EventHandlers::const_iterator hitr = _eventHandlers.begin(); hitr != _eventHandlers.end(); ++hitr) { (*hitr)->getUsage(usage); } }