/* -*-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 using namespace osgViewer; CompositeViewer::CompositeViewer() { constructorInit(); } CompositeViewer::CompositeViewer(const CompositeViewer& cv,const osg::CopyOp& copyop): osg::Object(cv,copyop) { constructorInit(); } CompositeViewer::CompositeViewer(osg::ArgumentParser& arguments) { constructorInit(); while (arguments.read("--SingleThreaded")) setThreadingModel(SingleThreaded); while (arguments.read("--ThreadPerContext")) setThreadingModel(ThreadPerContext); osg::DisplaySettings::instance()->readCommandLine(arguments); osgDB::readCommandLine(arguments); } void CompositeViewer::constructorInit() { _firstFrame = true; _done = false; _keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape; _quitEventSetsDone = true; _threadingModel = ThreadPerContext; _threadsRunning = false; _endBarrierPosition = AfterSwapBuffers; _numThreadsOnBarrier = 0; _startTick = 0; // make sure View is safe to reference multi-threaded. setThreadSafeRefUnref(true); _frameStamp = new osg::FrameStamp; _frameStamp->setFrameNumber(0); _frameStamp->setReferenceTime(0); _frameStamp->setSimulationTime(0); setEventQueue(new osgGA::EventQueue); _eventVisitor = new osgGA::EventVisitor; _eventVisitor->setFrameStamp(_frameStamp.get()); _updateVisitor = new osgUtil::UpdateVisitor; _updateVisitor->setFrameStamp(_frameStamp.get()); } CompositeViewer::~CompositeViewer() { osg::notify(osg::INFO)<<"CompositeViewer::~CompositeViewer()"<getDatabasePager()) { scene->getDatabasePager()->cancel(); scene->setDatabasePager(0); } } Contexts contexts; getContexts(contexts); // clear out all the previously assigned operations for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { (*citr)->close(); } osg::notify(osg::INFO)<<"finished CompositeViewer::~CompsiteViewer()"<setFrameStamp(_frameStamp.get()); if (threadsWereRuinning) startThreading(); } void CompositeViewer::removeView(osgViewer::View* view) { for(Views::iterator itr = _views.begin(); itr != _views.end(); ++itr) { if (*itr == view) { bool threadsWereRuinning = _threadsRunning; if (threadsWereRuinning) stopThreading(); _views.erase(itr); if (threadsWereRuinning) startThreading(); return; } } } bool CompositeViewer::isRealized() const { Contexts contexts; const_cast(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 CompositeViewer::run() { for(Views::iterator itr = _views.begin(); itr != _views.end(); ++itr) { osgViewer::View* view = itr->get(); if ((view->getCameraManipulator()==0) && view->getCamera()->getAllowEventFocus()) { view->setCameraManipulator(new osgGA::TrackballManipulator()); } } if (!isRealized()) { realize(); } while (!done()) { frame(); } return 0; } void CompositeViewer::setStartTick(osg::Timer_t tick) { _startTick = tick; for(Views::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { (*vitr)->setStartTick(tick); } Contexts contexts; getContexts(contexts,false); for(Contexts::iterator citr = contexts.begin(); citr != contexts.end(); ++citr) { osgViewer::GraphicsWindow* gw = dynamic_cast(*citr); if (gw) { gw->getEventQueue()->setStartTick(_startTick); } } } void CompositeViewer::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 CompositeViewer::setThreadingModel(ThreadingModel threadingModel) { if (_threadingModel == threadingModel) return; if (_threadingModel!=SingleThreaded) stopThreading(); _threadingModel = threadingModel; if (isRealized() && _threadingModel!=SingleThreaded) startThreading(); } void CompositeViewer::setEndBarrierPosition(BarrierPosition bp) { if (_endBarrierPosition == bp) return; if (_threadingModel!=SingleThreaded) stopThreading(); _endBarrierPosition = bp; if (_threadingModel!=SingleThreaded) startThreading(); } void CompositeViewer::stopThreading() { if (!_threadsRunning) return; if (_numThreadsOnBarrier==0) return; osg::notify(osg::INFO)<<"CompositeViewer::stopThreading() - stopping threading"<setGraphicsThread(0); } _startRenderingBarrier = 0; _endRenderingDispatchBarrier = 0; _numThreadsOnBarrier = 0; } unsigned int CompositeViewer::computeNumberOfThreadsIncludingMainRequired() { Contexts contexts; getContexts(contexts); if (contexts.empty()) return 0; if (contexts.size()==1 || _threadingModel==SingleThreaded) { return 1; } bool firstContextAsMainThread = _threadingModel == ThreadPerContext; return firstContextAsMainThread ? contexts.size() : contexts.size()+1; } void CompositeViewer::startThreading() { if (_threadsRunning) return; unsigned int numThreadsIncludingMainThread = computeNumberOfThreadsIncludingMainRequired(); // return if we don't need multiple threads. if (numThreadsIncludingMainThread <= 1) return; // return if threading is already up and running if (numThreadsIncludingMainThread == _numThreadsOnBarrier) return; if (_numThreadsOnBarrier!=0) { // we already have threads running but not the right number, so stop them and then create new threads. stopThreading(); } osg::notify(osg::INFO)<<"CompositeViewer::startThreading() - starting threading"<getSceneData(); if (sceneData) { osg::notify(osg::INFO)<<"Making scene thread safe"<setThreadSafeRefUnref(true); // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it. sceneData->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts()); } } Contexts contexts; getContexts(contexts); int numProcessors = OpenThreads::GetNumberOfProcessors(); bool affinity = false; bool firstContextAsMainThread = numThreadsIncludingMainThread==contexts.size(); // osg::notify(osg::NOTICE)<<"numThreadsIncludingMainThread=="< swapOp = new osg::SwapBuffersOperation(); Contexts::iterator citr = contexts.begin(); unsigned int processNum = 0; if (firstContextAsMainThread) { ++processNum; ++citr; } for(; citr != contexts.end(); ++citr, ++processNum) { osg::GraphicsContext* gc = (*citr); // create the a graphics thread for this context gc->createGraphicsThread(); if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors); gc->getGraphicsThread()->add(new osgUtil::GLObjectsOperation()); // add the startRenderingBarrier gc->getGraphicsThread()->add(_startRenderingBarrier.get()); // add the rendering operation itself. gc->getGraphicsThread()->add(new osg::RunOperations()); if (_endBarrierPosition==BeforeSwapBuffers) { // add the endRenderingDispatchBarrier gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); } // add the swap buffers gc->getGraphicsThread()->add(swapOp.get()); if (_endBarrierPosition==AfterSwapBuffers) { // add the endRenderingDispatchBarrier gc->getGraphicsThread()->add(_endRenderingDispatchBarrier.get()); } } if (firstContextAsMainThread) { if (affinity) OpenThreads::SetProcessorAffinityOfCurrentThread(0); } for(citr = contexts.begin(); citr != contexts.end(); ++citr) { osg::GraphicsContext* gc = (*citr); if (gc->getGraphicsThread() && !gc->getGraphicsThread()->isRunning()) { //osg::notify(osg::NOTICE)<<" gc->getGraphicsThread()->startThread() "<getGraphicsThread()<getGraphicsThread()->startThread(); // OpenThreads::Thread::YieldCurrentThread(); } } _threadsRunning = true; } void CompositeViewer::checkWindowStatus() { Contexts contexts; getContexts(contexts); // osg::notify(osg::INFO)<<"Viewer::checkWindowStatus() - "<init(); } } void CompositeViewer::getContexts(Contexts& contexts, bool onlyValid) { typedef std::set ContextSet; ContextSet contextSet; for(Views::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { osgViewer::View* view = vitr->get(); if (view->getCamera() && view->getCamera()->getGraphicsContext() && (view->getCamera()->getGraphicsContext()->valid() || !onlyValid)) { contextSet.insert(view->getCamera()->getGraphicsContext()); } for(unsigned int i=0; igetNumSlaves(); ++i) { View::Slave& slave = view->getSlave(i); if (slave._camera.valid() && slave._camera->getGraphicsContext() && (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)); } } void CompositeViewer::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 CompositeViewer::getScenes(Scenes& scenes, bool onlyValid) { typedef std::set SceneSet; SceneSet sceneSet; for(Views::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { osgViewer::View* view = vitr->get(); if (view->getScene() && (!onlyValid || view->getScene()->getSceneData())) { sceneSet.insert(view->getScene()); } } for(SceneSet::iterator sitr = sceneSet.begin(); sitr != sceneSet.end(); ++sitr) { scenes.push_back(const_cast(*sitr)); } } void CompositeViewer::realize() { //osg::notify(osg::INFO)<<"CompositeViewer::realize()"<setUpViewAcrossAllScreens(); getContexts(contexts); } if (contexts.empty()) { osg::notify(osg::NOTICE)<<"CompositeViewer::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(); } } } startThreading(); // initialize the global timer to be relative to the current time. osg::Timer::instance()->setStartTick(); // pass on the start tick to all the associated eventqueues setStartTick(osg::Timer::instance()->getStartTick()); 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 CompositeViewer::frame(double simulationTime) { if (_done) return; // osg::notify(osg::NOTICE)<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); } } void CompositeViewer::setCameraWithFocus(osg::Camera* camera) { _cameraWithFocus = camera; if (camera) { for(Views::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { View* view = vitr->get(); if (view->containsCamera(camera)) { _viewWithFocus = view; return; } } } _viewWithFocus = 0; } void CompositeViewer::eventTraversal() { if (_done) return; if (_views.empty()) return; // osg::notify(osg::NOTICE)<<"CompositeViewer::frameEventTraversal()."< ViewEventsMap; ViewEventsMap viewEventsMap; Contexts contexts; getContexts(contexts); Scenes scenes; getScenes(scenes); osgViewer::View* masterView = getViewWithFocus() ? getViewWithFocus() : _views[0].get(); osg::Camera* masterCamera = masterView->getCamera(); osgGA::GUIEventAdapter* eventState = masterView->getEventQueue()->getCurrentEventState(); osg::Matrix masterCameraVPW = masterCamera->getViewMatrix() * masterCamera->getProjectionMatrix(); if (masterCamera->getViewport()) { osg::Viewport* viewport = masterCamera->getViewport(); masterCameraVPW *= viewport->computeWindowMatrix(); } 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::RESIZE): setCameraWithFocus(0); break; 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() && 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()) ) { setCameraWithFocus(camera); const osg::GraphicsContext::Traits* traits = gw ? gw->getTraits() : 0; if (traits) { eventState->setInputRange( 0, 0, traits->width, traits->height); } else { eventState->setInputRange(-1.0, -1.0, 1.0, 1.0); } if (getViewWithFocus()!=masterView) { // need to reset the masterView masterView = getViewWithFocus(); masterCamera = masterView->getCamera(); eventState = masterView->getEventQueue()->getCurrentEventState(); masterCameraVPW = masterCamera->getViewMatrix() * masterCamera->getProjectionMatrix(); if (masterCamera->getViewport()) { osg::Viewport* viewport = masterCamera->getViewport(); masterCameraVPW *= viewport->computeWindowMatrix(); } } } } } } break; } default: break; } if (pointerEvent) { if (getCameraWithFocus()) { osg::Viewport* viewport = getCameraWithFocus()->getViewport(); osg::Matrix localCameraVPW = getCameraWithFocus()->getViewMatrix() * getCameraWithFocus()->getProjectionMatrix(); if (viewport) localCameraVPW *= viewport->computeWindowMatrix(); osg::Matrix matrix( osg::Matrix::inverse(localCameraVPW) * masterCameraVPW ); osg::Vec3d new_coord = osg::Vec3d(x,y,0.0) * matrix; x = new_coord.x(); y = new_coord.y(); event->setInputRange(eventState->getXmin(), eventState->getYmin(), eventState->getXmax(), eventState->getYmax()); event->setX(x); event->setY(y); event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); } // pass along the new pointer events details to the eventState of the viewer eventState->setX(x); eventState->setY(y); eventState->setButtonMask(event->getButtonMask()); eventState->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); } else { event->setInputRange(eventState->getXmin(), eventState->getYmin(), eventState->getXmax(), eventState->getYmax()); event->setX(eventState->getX()); event->setY(eventState->getY()); event->setButtonMask(eventState->getButtonMask()); event->setMouseYOrientation(eventState->getMouseYOrientation()); } //osg::notify(osg::NOTICE)<<" mouse x = "<getX()<<" y="<getY()<second.begin(); itr != veitr->second.end(); ++itr) { osgGA::GUIEventAdapter* event = itr->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(ViewEventsMap::iterator veitr = viewEventsMap.begin(); veitr != viewEventsMap.end(); ++veitr) { View* view = veitr->first; _eventVisitor->setActionAdapter(view); for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); itr != veitr->second.end(); ++itr) { osgGA::GUIEventAdapter* event = itr->get(); for(View::EventHandlers::iterator hitr = view->getEventHandlers().begin(); hitr != view->getEventHandlers().end(); ++hitr) { (*hitr)->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *view, 0, 0); } if (view->getCameraManipulator()) { view->getCameraManipulator()->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *view); } } } if (_eventVisitor.valid()) { _eventVisitor->setFrameStamp(getFrameStamp()); _eventVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber()); for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); veitr != viewEventsMap.end(); ++veitr) { View* view = veitr->first; if (view->getSceneData()) { for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); itr != veitr->second.end(); ++itr) { osgGA::GUIEventAdapter* event = itr->get(); _eventVisitor->reset(); _eventVisitor->addEvent( event ); view->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 (view->getCamera() && view->getCamera()->getEventCallback()) view->getCamera()->accept(*_eventVisitor); for(unsigned int i=0; igetNumSlaves(); ++i) { osg::Camera* camera = view->getSlave(i)._camera.get(); if (camera && camera->getEventCallback()) camera->accept(*_eventVisitor); } _eventVisitor->setTraversalMode(tm); } } } } } void CompositeViewer::addUpdateOperation(osg::Operation* operation) { if (!operation) return; if (!_updateOperations) _updateOperations = new osg::OperationQueue; _updateOperations->add(operation); } void CompositeViewer::removeUpdateOperation(osg::Operation* operation) { if (!operation) return; if (_updateOperations.valid()) { _updateOperations->remove(operation); } } void CompositeViewer::updateTraversal() { if (_done) return; Scenes scenes; getScenes(scenes); for(Scenes::iterator sitr = scenes.begin(); sitr != scenes.end(); ++sitr) { Scene* scene = *sitr; if (scene->getSceneData()) { scene->getSceneData()->accept(*_updateVisitor); } if (scene->getDatabasePager()) { // syncronize changes required by the DatabasePager thread to the scene graph scene->getDatabasePager()->updateSceneGraph(_frameStamp->getReferenceTime()); } } if (_updateOperations.valid()) { _updateOperations->runOperations(this); } for(Views::iterator vitr = _views.begin(); vitr != _views.end(); ++vitr) { View* view = vitr->get(); Scene* scene = view->getScene(); { // 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 (view->getCamera() && view->getCamera()->getUpdateCallback()) view->getCamera()->accept(*_updateVisitor); for(unsigned int i=0; igetNumSlaves(); ++i) { osg::Camera* camera = view->getSlave(i)._camera.get(); if (camera && camera->getUpdateCallback()) camera->accept(*_updateVisitor); } _updateVisitor->setTraversalMode(tm); } if (view->getCameraManipulator()) { view->setFusionDistance( view->getCameraManipulator()->getFusionDistanceMode(), view->getCameraManipulator()->getFusionDistanceValue() ); view->getCamera()->setViewMatrix( view->getCameraManipulator()->getInverseMatrix()); } view->updateSlaves(); } } void CompositeViewer::renderingTraversals() { // check to see if windows are still valid checkWindowStatus(); if (_done) return; Scenes scenes; getScenes(scenes); for(Scenes::iterator sitr = scenes.begin(); sitr != scenes.end(); ++sitr) { Scene* scene = *sitr; osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0; if (dp) { dp->signalBeginFrame(getFrameStamp()); } } // osg::notify(osg::NOTICE)<block(); Contexts::iterator itr; for(itr = contexts.begin(); itr != contexts.end(); ++itr) { if (_done) return; if (!((*itr)->getGraphicsThread()) && (*itr)->valid()) { (*itr)->makeCurrent(); (*itr)->runOperations(); (*itr)->releaseContext(); } } // osg::notify(osg::NOTICE)<<"Joing _endRenderingDispatchBarrier block"<block(); for(itr = contexts.begin(); itr != contexts.end(); ++itr) { if (_done) return; if (!((*itr)->getGraphicsThread()) && (*itr)->valid()) { (*itr)->makeCurrent(); (*itr)->swapBuffers(); (*itr)->releaseContext(); } } for(Scenes::iterator sitr = scenes.begin(); sitr != scenes.end(); ++sitr) { Scene* scene = *sitr; osgDB::DatabasePager* dp = scene ? scene->getDatabasePager() : 0; if (dp) { dp->signalEndFrame(); } } }