1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 #include <osg/GLExtensions>
15 #include <osg/TextureRectangle>
16 #include <osg/TextureCubeMap>
17 
18 #include <osgGA/TrackballManipulator>
19 #include <osgViewer/CompositeViewer>
20 #include <osgViewer/Renderer>
21 #include <osgDB/Registry>
22 #include <osgDB/ReadFile>
23 
24 #include <osg/io_utils>
25 
26 using namespace osgViewer;
27 
CompositeViewer()28 CompositeViewer::CompositeViewer()
29 {
30     constructorInit();
31 }
32 
CompositeViewer(const CompositeViewer & cv,const osg::CopyOp &)33 CompositeViewer::CompositeViewer(const CompositeViewer& cv,const osg::CopyOp& /*copyop*/):
34     osg::Object(true),
35     ViewerBase(cv)
36 {
37     constructorInit();
38 }
39 
CompositeViewer(osg::ArgumentParser & arguments)40 CompositeViewer::CompositeViewer(osg::ArgumentParser& arguments)
41 {
42     constructorInit();
43 
44     arguments.getApplicationUsage()->addCommandLineOption("--SingleThreaded","Select SingleThreaded threading model for viewer.");
45     arguments.getApplicationUsage()->addCommandLineOption("--CullDrawThreadPerContext","Select CullDrawThreadPerContext threading model for viewer.");
46     arguments.getApplicationUsage()->addCommandLineOption("--DrawThreadPerContext","Select DrawThreadPerContext threading model for viewer.");
47     arguments.getApplicationUsage()->addCommandLineOption("--CullThreadPerCameraDrawThreadPerContext","Select CullThreadPerCameraDrawThreadPerContext threading model for viewer.");
48 
49     arguments.getApplicationUsage()->addCommandLineOption("--run-on-demand","Set the run methods frame rate management to only rendering frames when required.");
50     arguments.getApplicationUsage()->addCommandLineOption("--run-continuous","Set the run methods frame rate management to rendering frames continuously.");
51     arguments.getApplicationUsage()->addCommandLineOption("--run-max-frame-rate","Set the run methods maximum permissible frame rate, 0.0 is default and switching off frame rate capping.");
52 
53 
54     std::string filename;
55     bool readConfig = false;
56     while (arguments.read("-c",filename))
57     {
58         readConfig = readConfiguration(filename) || readConfig;
59     }
60 
61     while (arguments.read("--SingleThreaded")) setThreadingModel(SingleThreaded);
62     while (arguments.read("--CullDrawThreadPerContext")) setThreadingModel(CullDrawThreadPerContext);
63     while (arguments.read("--DrawThreadPerContext")) setThreadingModel(DrawThreadPerContext);
64     while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) setThreadingModel(CullThreadPerCameraDrawThreadPerContext);
65 
66 
67     while(arguments.read("--run-on-demand")) { setRunFrameScheme(ON_DEMAND); }
68     while(arguments.read("--run-continuous")) { setRunFrameScheme(CONTINUOUS); }
69 
70     double runMaxFrameRate;
71     while(arguments.read("--run-max-frame-rate", runMaxFrameRate)) { setRunMaxFrameRate(runMaxFrameRate); }
72 
73 
74     osg::DisplaySettings::instance()->readCommandLine(arguments);
75     osgDB::readCommandLine(arguments);
76 }
77 
constructorInit()78 void CompositeViewer::constructorInit()
79 {
80     _endBarrierPosition = AfterSwapBuffers;
81     _startTick = 0;
82 
83     // make sure View is safe to reference multi-threaded.
84     setThreadSafeRefUnref(true);
85 
86     _frameStamp = new osg::FrameStamp;
87     _frameStamp->setFrameNumber(0);
88     _frameStamp->setReferenceTime(0);
89     _frameStamp->setSimulationTime(0);
90 
91     _eventVisitor = new osgGA::EventVisitor;
92     _eventVisitor->setFrameStamp(_frameStamp.get());
93 
94     _updateVisitor = new osgUtil::UpdateVisitor;
95     _updateVisitor->setFrameStamp(_frameStamp.get());
96 
97     setViewerStats(new osg::Stats("CompsiteViewer"));
98 }
99 
~CompositeViewer()100 CompositeViewer::~CompositeViewer()
101 {
102     OSG_INFO<<"CompositeViewer::~CompositeViewer()"<<std::endl;
103 
104     stopThreading();
105 
106     Scenes scenes;
107     getScenes(scenes);
108 
109     for(Scenes::iterator sitr = scenes.begin();
110         sitr != scenes.end();
111         ++sitr)
112     {
113         Scene* scene = *sitr;
114         if (scene->getDatabasePager())
115         {
116             scene->getDatabasePager()->cancel();
117             scene->setDatabasePager(0);
118         }
119     }
120 
121     Contexts contexts;
122     getContexts(contexts);
123 
124     // clear out all the previously assigned operations
125     for(Contexts::iterator citr = contexts.begin();
126         citr != contexts.end();
127         ++citr)
128     {
129         (*citr)->close();
130     }
131 
132     OSG_INFO<<"finished CompositeViewer::~CompositeViewer()"<<std::endl;
133 }
134 
readConfiguration(const std::string & filename)135 bool CompositeViewer::readConfiguration(const std::string& filename)
136 {
137     OSG_NOTICE<<"CompositeViewer::readConfiguration("<<filename<<")"<<std::endl;
138     osg::ref_ptr<osg::Object> obj = osgDB::readRefObjectFile(filename);
139     osgViewer::View * view = dynamic_cast<osgViewer::View *>(obj.get());
140     if (view)
141     {
142         addView(view);
143         return true;
144     }
145     return false;
146 }
147 
148 
addView(osgViewer::View * view)149 void CompositeViewer::addView(osgViewer::View* view)
150 {
151     if (!view) return;
152 
153     bool alreadyRealized = isRealized();
154 
155     bool threadsWereRunning = _threadsRunning;
156     if (threadsWereRunning) stopThreading();
157 
158     _views.push_back(view);
159 
160     view->_viewerBase = this;
161 
162     if (view->getSceneData())
163     {
164         // make sure that existing scene graph objects are allocated with thread safe ref/unref
165         if (getThreadingModel()!=ViewerBase::SingleThreaded)
166         {
167             view->getSceneData()->setThreadSafeRefUnref(true);
168         }
169 
170         // update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
171         view->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
172     }
173 
174     view->setFrameStamp(_frameStamp.get());
175 
176     if (alreadyRealized)
177     {
178         Contexts contexts;
179         if (view->getCamera()->getGraphicsContext())
180         {
181             contexts.push_back(view->getCamera()->getGraphicsContext());
182         }
183         for(unsigned int i=0; i<view->getNumSlaves(); ++i)
184         {
185             if (view->getSlave(i)._camera->getGraphicsContext())
186             {
187                 contexts.push_back(view->getSlave(i)._camera->getGraphicsContext());
188             }
189         }
190 
191         for(Contexts::iterator itr = contexts.begin();
192             itr != contexts.end();
193             ++itr)
194         {
195             if (!((*itr)->isRealized()))
196             {
197                 (*itr)->realize();
198             }
199         }
200 
201     }
202 
203     if (threadsWereRunning) startThreading();
204 }
205 
removeView(osgViewer::View * view)206 void CompositeViewer::removeView(osgViewer::View* view)
207 {
208     for(RefViews::iterator itr = _views.begin();
209         itr != _views.end();
210         ++itr)
211     {
212         if (*itr == view)
213         {
214             bool threadsWereRunning = _threadsRunning;
215             if (threadsWereRunning) stopThreading();
216 
217             view->_viewerBase = 0;
218 
219             _views.erase(itr);
220 
221             if (threadsWereRunning) startThreading();
222 
223             return;
224         }
225     }
226 }
227 
isRealized() const228 bool CompositeViewer::isRealized() const
229 {
230     Contexts contexts;
231     const_cast<CompositeViewer*>(this)->getContexts(contexts);
232 
233     unsigned int numRealizedWindows = 0;
234 
235     // clear out all the previously assigned operations
236     for(Contexts::iterator citr = contexts.begin();
237         citr != contexts.end();
238         ++citr)
239     {
240         if ((*citr)->isRealized()) ++numRealizedWindows;
241     }
242 
243     return numRealizedWindows > 0;
244 }
245 
checkNeedToDoFrame()246 bool CompositeViewer::checkNeedToDoFrame()
247 {
248     if (_requestRedraw) return true;
249     if (_requestContinousUpdate) return true;
250 
251     for(RefViews::iterator itr = _views.begin();
252         itr != _views.end();
253         ++itr)
254     {
255         osgViewer::View* view = itr->get();
256         if (view)
257         {
258             // check if the database pager needs to update the scene
259             if (view->getDatabasePager()->requiresUpdateSceneGraph() ||
260                 view->getDatabasePager()->getRequestsInProgress()) return true;
261 
262             // check if there are camera update callbacks
263             if (view->getCamera()->getUpdateCallback()) return true;
264 
265             // check if there are node update callbacks
266             if (view->getSceneData() != 0)
267             {
268                 if (view->getSceneData()->getUpdateCallback() || (view->getSceneData()->getNumChildrenRequiringUpdateTraversal()>0) ) return true;
269             }
270         }
271     }
272 
273     // check if events are available and need processing
274     if (checkEvents()) return true;
275 
276     if (_requestRedraw) return true;
277     if (_requestContinousUpdate) return true;
278 
279     return false;
280 }
281 
282 
checkEvents()283 bool CompositeViewer::checkEvents()
284 {
285     for(RefViews::iterator itr = _views.begin();
286         itr != _views.end();
287         ++itr)
288     {
289         osgViewer::View* view = itr->get();
290         if (view)
291         {
292             // check events from any attached sources
293             for(View::Devices::iterator eitr = view->getDevices().begin();
294                 eitr != view->getDevices().end();
295                 ++eitr)
296             {
297                 osgGA::Device* es = eitr->get();
298                 if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS)
299                 {
300                     if (es->checkEvents()) return true;
301                 }
302 
303             }
304         }
305     }
306 
307     // get events from all windows attached to Viewer.
308     Windows windows;
309     getWindows(windows);
310     for(Windows::iterator witr = windows.begin();
311         witr != windows.end();
312         ++witr)
313     {
314         if ((*witr)->checkEvents()) return true;
315     }
316 
317     return false;
318 }
319 
run()320 int CompositeViewer::run()
321 {
322     for(RefViews::iterator itr = _views.begin();
323         itr != _views.end();
324         ++itr)
325     {
326         osgViewer::View* view = itr->get();
327         if ((view->getCameraManipulator()==0) && view->getCamera()->getAllowEventFocus())
328         {
329             view->setCameraManipulator(new osgGA::TrackballManipulator());
330         }
331     }
332 
333     setReleaseContextAtEndOfFrameHint(false);
334 
335     return ViewerBase::run();
336 }
337 
setStartTick(osg::Timer_t tick)338 void CompositeViewer::setStartTick(osg::Timer_t tick)
339 {
340     _startTick = tick;
341 
342     for(RefViews::iterator vitr = _views.begin();
343         vitr != _views.end();
344         ++vitr)
345     {
346         (*vitr)->setStartTick(tick);
347     }
348 
349     Contexts contexts;
350     getContexts(contexts,false);
351 
352     for(Contexts::iterator citr = contexts.begin();
353         citr != contexts.end();
354         ++citr)
355     {
356         osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*citr);
357         if (gw)
358         {
359             gw->getEventQueue()->setStartTick(_startTick);
360         }
361     }
362 }
363 
364 
setReferenceTime(double time)365 void CompositeViewer::setReferenceTime(double time)
366 {
367     osg::Timer_t tick = osg::Timer::instance()->tick();
368     double currentTime = osg::Timer::instance()->delta_s(_startTick, tick);
369     double delta_ticks = (time-currentTime)/(osg::Timer::instance()->getSecondsPerTick());
370     if (delta_ticks>=0) tick += osg::Timer_t(delta_ticks);
371     else tick -= osg::Timer_t(-delta_ticks);
372 
373     // assign the new start tick
374     setStartTick(tick);
375 }
376 
377 
378 
viewerInit()379 void CompositeViewer::viewerInit()
380 {
381     OSG_INFO<<"CompositeViewer::init()"<<std::endl;
382 
383     for(RefViews::iterator itr = _views.begin();
384         itr != _views.end();
385         ++itr)
386     {
387         (*itr)->init();
388     }
389 }
390 
getContexts(Contexts & contexts,bool onlyValid)391 void CompositeViewer::getContexts(Contexts& contexts, bool onlyValid)
392 {
393     typedef std::set<osg::GraphicsContext*> ContextSet;
394     ContextSet contextSet;
395 
396     contexts.clear();
397 
398     for(RefViews::iterator vitr = _views.begin();
399         vitr != _views.end();
400         ++vitr)
401     {
402         osgViewer::View* view = vitr->get();
403         osg::GraphicsContext* gc = view->getCamera() ? view->getCamera()->getGraphicsContext() : 0;
404         if (gc && (gc->valid() || !onlyValid))
405         {
406             if (contextSet.count(gc)==0)
407             {
408                 contextSet.insert(gc);
409                 contexts.push_back(gc);
410             }
411         }
412 
413         for(unsigned int i=0; i<view->getNumSlaves(); ++i)
414         {
415             View::Slave& slave = view->getSlave(i);
416             osg::GraphicsContext* sgc = slave._camera.valid() ? slave._camera->getGraphicsContext() : 0;
417             if (sgc && (sgc->valid() || !onlyValid))
418             {
419                 if (contextSet.count(sgc)==0)
420                 {
421                     contextSet.insert(sgc);
422                     contexts.push_back(sgc);
423                 }
424             }
425         }
426     }
427 }
428 
getCameras(Cameras & cameras,bool onlyActive)429 void CompositeViewer::getCameras(Cameras& cameras, bool onlyActive)
430 {
431     cameras.clear();
432 
433     for(RefViews::iterator vitr = _views.begin();
434         vitr != _views.end();
435         ++vitr)
436     {
437         View* view = vitr->get();
438 
439         if (view->getCamera() &&
440             (!onlyActive || (view->getCamera()->getGraphicsContext() && view->getCamera()->getGraphicsContext()->valid())) ) cameras.push_back(view->getCamera());
441 
442         for(View::Slaves::iterator itr = view->_slaves.begin();
443             itr != view->_slaves.end();
444             ++itr)
445         {
446             if (itr->_camera.valid() &&
447                 (!onlyActive || (itr->_camera->getGraphicsContext() && itr->_camera->getGraphicsContext()->valid())) ) cameras.push_back(itr->_camera.get());
448         }
449     }
450 }
451 
getScenes(Scenes & scenes,bool onlyValid)452 void CompositeViewer::getScenes(Scenes& scenes, bool onlyValid)
453 {
454     scenes.clear();
455 
456     typedef std::set<osgViewer::Scene*> SceneSet;
457     SceneSet sceneSet;
458 
459     for(RefViews::iterator vitr = _views.begin();
460         vitr != _views.end();
461         ++vitr)
462     {
463         osgViewer::View* view = vitr->get();
464         if (view->getScene() && (!onlyValid || view->getScene()->getSceneData()))
465         {
466             if (sceneSet.count(view->getScene())==0)
467             {
468                 sceneSet.insert(view->getScene());
469                 scenes.push_back(view->getScene());
470             }
471         }
472     }
473 }
474 
getViews(Views & views,bool)475 void CompositeViewer::getViews(Views& views, bool /*onlyValid*/)
476 {
477     views.clear();
478 
479     for(RefViews::iterator vitr = _views.begin();
480         vitr != _views.end();
481         ++vitr)
482     {
483         views.push_back(vitr->get());
484     }
485 }
486 
getAllThreads(Threads & threads,bool onlyActive)487 void CompositeViewer::getAllThreads(Threads& threads, bool onlyActive)
488 {
489     threads.clear();
490 
491     OperationThreads operationThreads;
492     getOperationThreads(operationThreads);
493 
494     for(OperationThreads::iterator itr = operationThreads.begin();
495         itr != operationThreads.end();
496         ++itr)
497     {
498         threads.push_back(*itr);
499     }
500 
501     Scenes scenes;
502     getScenes(scenes);
503 
504     for(Scenes::iterator sitr = scenes.begin();
505         sitr != scenes.end();
506         ++sitr)
507     {
508         Scene* scene = *sitr;
509         osgDB::DatabasePager* dp = scene->getDatabasePager();
510         if (dp)
511         {
512             for(unsigned int i=0; i<dp->getNumDatabaseThreads(); ++i)
513             {
514                 osgDB::DatabasePager::DatabaseThread* dt = dp->getDatabaseThread(i);
515                 if (!onlyActive || dt->isRunning())
516                 {
517                     threads.push_back(dt);
518                 }
519             }
520         }
521     }
522 }
523 
524 
getOperationThreads(OperationThreads & threads,bool onlyActive)525 void CompositeViewer::getOperationThreads(OperationThreads& threads, bool onlyActive)
526 {
527     threads.clear();
528 
529     Contexts contexts;
530     getContexts(contexts);
531     for(Contexts::iterator gcitr = contexts.begin();
532         gcitr != contexts.end();
533         ++gcitr)
534     {
535         osg::GraphicsContext* gc = *gcitr;
536         if (gc->getGraphicsThread() &&
537             (!onlyActive || gc->getGraphicsThread()->isRunning()) )
538         {
539             threads.push_back(gc->getGraphicsThread());
540         }
541     }
542 
543     Cameras cameras;
544     getCameras(cameras);
545     for(Cameras::iterator citr = cameras.begin();
546         citr != cameras.end();
547         ++citr)
548     {
549         osg::Camera* camera = *citr;
550         if (camera->getCameraThread() &&
551             (!onlyActive || camera->getCameraThread()->isRunning()) )
552         {
553             threads.push_back(camera->getCameraThread());
554         }
555     }
556 
557 }
558 
realize()559 void CompositeViewer::realize()
560 {
561     //OSG_INFO<<"CompositeViewer::realize()"<<std::endl;
562 
563     setCameraWithFocus(0);
564 
565     if (_views.empty())
566     {
567         OSG_NOTICE<<"CompositeViewer::realize() - No views to realize."<<std::endl;
568         _done = true;
569         return;
570     }
571 
572     Contexts contexts;
573     getContexts(contexts);
574 
575     if (contexts.empty())
576     {
577         OSG_INFO<<"CompositeViewer::realize() - No valid contexts found, setting up view across all screens."<<std::endl;
578 
579         // no windows are already set up so set up a default view
580         _views[0]->setUpViewAcrossAllScreens();
581 
582         getContexts(contexts);
583     }
584 
585     if (contexts.empty())
586     {
587         OSG_NOTICE<<"CompositeViewer::realize() - failed to set up any windows"<<std::endl;
588         _done = true;
589         return;
590     }
591 
592     // get the display settings that will be active for this viewer
593     osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
594     osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
595 
596     // pass on the display settings to the WindowSystemInterface.
597     if (wsi && wsi->getDisplaySettings()==0) wsi->setDisplaySettings(ds);
598 
599     unsigned int maxTexturePoolSize = ds->getMaxTexturePoolSize();
600     unsigned int maxBufferObjectPoolSize = ds->getMaxBufferObjectPoolSize();
601 
602     for(Contexts::iterator citr = contexts.begin();
603         citr != contexts.end();
604         ++citr)
605     {
606         osg::GraphicsContext* gc = *citr;
607 
608         if (ds->getSyncSwapBuffers()) gc->setSwapCallback(new osg::SyncSwapBuffersCallback);
609 
610         // set the pool sizes, 0 the default will result in no GL object pools.
611         gc->getState()->setMaxTexturePoolSize(maxTexturePoolSize);
612         gc->getState()->setMaxBufferObjectPoolSize(maxBufferObjectPoolSize);
613 
614         gc->realize();
615 
616         if (_realizeOperation.valid() && gc->valid())
617         {
618             gc->makeCurrent();
619 
620             (*_realizeOperation)(gc);
621 
622             gc->releaseContext();
623         }
624     }
625 
626     // attach contexts to _incrementalCompileOperation if attached.
627     if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts);
628 
629 
630     bool grabFocus = true;
631     if (grabFocus)
632     {
633         for(Contexts::iterator citr = contexts.begin();
634             citr != contexts.end();
635             ++citr)
636         {
637             osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*citr);
638             if (gw)
639             {
640                 gw->grabFocusIfPointerInWindow();
641             }
642         }
643     }
644 
645 
646     // initialize the global timer to be relative to the current time.
647     osg::Timer::instance()->setStartTick();
648 
649     // pass on the start tick to all the associated eventqueues
650     setStartTick(osg::Timer::instance()->getStartTick());
651 
652     // configure threading.
653     setUpThreading();
654 
655     if (osg::DisplaySettings::instance()->getCompileContextsHint())
656     {
657         int numProcessors = OpenThreads::GetNumberOfProcessors();
658         int processNum = 0;
659 
660         for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i)
661         {
662             osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i);
663 
664             if (gc)
665             {
666                 gc->createGraphicsThread();
667                 gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
668                 gc->getGraphicsThread()->startThread();
669 
670                 ++processNum;
671             }
672         }
673     }
674 
675 }
676 
advance(double simulationTime)677 void CompositeViewer::advance(double simulationTime)
678 {
679     if (_done) return;
680 
681     double previousReferenceTime = _frameStamp->getReferenceTime();
682     unsigned int previousFrameNumber = _frameStamp->getFrameNumber();
683 
684 
685     _frameStamp->setFrameNumber(_frameStamp->getFrameNumber()+1);
686 
687     _frameStamp->setReferenceTime( osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()) );
688 
689     if (simulationTime==USE_REFERENCE_TIME)
690     {
691         _frameStamp->setSimulationTime(_frameStamp->getReferenceTime());
692     }
693     else
694     {
695         _frameStamp->setSimulationTime(simulationTime);
696     }
697 
698 
699     if (getViewerStats() && getViewerStats()->collectStats("frame_rate"))
700     {
701         // update previous frame stats
702         double deltaFrameTime = _frameStamp->getReferenceTime() - previousReferenceTime;
703         getViewerStats()->setAttribute(previousFrameNumber, "Frame duration", deltaFrameTime);
704         getViewerStats()->setAttribute(previousFrameNumber, "Frame rate", 1.0/deltaFrameTime);
705 
706         // update current frames stats
707         getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Reference time", _frameStamp->getReferenceTime());
708     }
709 
710 }
711 
setCameraWithFocus(osg::Camera * camera)712 void CompositeViewer::setCameraWithFocus(osg::Camera* camera)
713 {
714     _cameraWithFocus = camera;
715 
716     if (camera)
717     {
718         for(RefViews::iterator vitr = _views.begin();
719             vitr != _views.end();
720             ++vitr)
721         {
722             View* view = vitr->get();
723             if (view->containsCamera(camera))
724             {
725                 _viewWithFocus = view;
726                 return;
727             }
728         }
729     }
730 
731     _viewWithFocus = 0;
732 }
733 
734 
generateSlavePointerData(osg::Camera * camera,osgGA::GUIEventAdapter & event)735 void CompositeViewer::generateSlavePointerData(osg::Camera* camera, osgGA::GUIEventAdapter& event)
736 {
737     osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(event.getGraphicsContext());
738     if (!gw) return;
739 
740     // What type of Camera is it?
741     // 1) Master Camera : do nothin extra
742     // 2) Slave Camera, Relative RF, Same scene graph as master : transform coords into Master Camera and add to PointerData list
743     // 3) Slave Camera, Relative RF, Different scene graph from master : do nothing extra?
744     // 4) Slave Camera, Absolute RF, Same scene graph as master : do nothing extra?
745     // 5) Slave Camera, Absolute RF, Different scene graph : do nothing extra?
746     // 6) Slave Camera, Absolute RF, Different scene graph but a distortion correction subgraph depending upon RTT Camera (slave or master)
747     //                              : project ray into RTT Camera's clip space, and RTT Camera's is Relative RF and sharing same scene graph as master then transform coords.
748 
749     // if camera isn't the master it must be a slave and could need reprojecting.
750 
751 
752     osgViewer::View* view = dynamic_cast<osgViewer::View*>(camera->getView());
753     if (!view) return;
754 
755     osg::Camera* view_masterCamera = view->getCamera();
756     if (camera!=view_masterCamera)
757     {
758         float x = event.getX();
759         float y = event.getY();
760 
761         bool invert_y = event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS;
762         if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y;
763 
764         double master_min_x = -1.0;
765         double master_max_x = 1.0;
766         double master_min_y = -1.0;
767         double master_max_y = 1.0;
768 
769         osg::Matrix masterCameraVPW = view_masterCamera->getViewMatrix() * view_masterCamera->getProjectionMatrix();
770         if (view_masterCamera->getViewport())
771         {
772             osg::Viewport* viewport = view_masterCamera->getViewport();
773             master_min_x = viewport->x();
774             master_min_y = viewport->y();
775             master_max_x = viewport->x()+viewport->width();
776             master_max_y = viewport->y()+viewport->height();
777             masterCameraVPW *= viewport->computeWindowMatrix();
778         }
779 
780         // slave Camera tahnks to sharing the same View
781         osg::View::Slave* slave = view ? view->findSlaveForCamera(camera) : 0;
782         if (slave)
783         {
784             if (camera->getReferenceFrame()==osg::Camera::RELATIVE_RF && slave->_useMastersSceneData)
785             {
786                 osg::Viewport* viewport = camera->getViewport();
787                 osg::Matrix localCameraVPW = camera->getViewMatrix() * camera->getProjectionMatrix();
788                 if (viewport) localCameraVPW *= viewport->computeWindowMatrix();
789 
790                 osg::Matrix matrix( osg::Matrix::inverse(localCameraVPW) * masterCameraVPW );
791                 osg::Vec3d new_coord = osg::Vec3d(x,y,0.0) * matrix;
792                 //OSG_NOTICE<<"    pointer event new_coord.x()="<<new_coord.x()<<" new_coord.y()="<<new_coord.y()<<std::endl;
793                 event.addPointerData(new osgGA::PointerData(view_masterCamera, new_coord.x(), master_min_x, master_max_x,
794                                                                                new_coord.y(), master_min_y, master_max_y));
795             }
796             else if (!slave->_useMastersSceneData)
797             {
798                 // Are their any RTT Camera's that this Camera depends upon for textures?
799 
800                 osg::ref_ptr<osgUtil::LineSegmentIntersector> ray = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x,y);
801                 osgUtil::IntersectionVisitor iv(ray.get());
802                 camera->accept(iv);
803                 if (ray->containsIntersections())
804                 {
805                     osg::Vec3 tc;
806                     osg::Texture* texture = ray->getFirstIntersection().getTextureLookUp(tc);
807                     if (texture)
808                     {
809                         // look up Texture in RTT Camera's.
810                         for(unsigned int i=0; i<view->getNumSlaves();++i)
811                         {
812                             osg::Camera* slave_camera = view->getSlave(i)._camera.get();
813                             if (slave_camera)
814                             {
815                                 osg::Camera::BufferAttachmentMap::const_iterator ba_itr = slave_camera->getBufferAttachmentMap().find(osg::Camera::COLOR_BUFFER);
816                                 if (ba_itr != slave_camera->getBufferAttachmentMap().end())
817                                 {
818                                     if (ba_itr->second._texture == texture)
819                                     {
820                                         osg::TextureRectangle* tr = dynamic_cast<osg::TextureRectangle*>(ba_itr->second._texture.get());
821                                         osg::TextureCubeMap* tcm = dynamic_cast<osg::TextureCubeMap*>(ba_itr->second._texture.get());
822                                         if (tr)
823                                         {
824                                             event.addPointerData(new osgGA::PointerData(slave_camera, tc.x(), 0.0f, static_cast<float>(tr->getTextureWidth()),
825                                                                                                            tc.y(), 0.0f, static_cast<float>(tr->getTextureHeight())));
826                                         }
827                                         else if (tcm)
828                                         {
829                                             OSG_INFO<<"  Slave has matched texture cubemap"<<ba_itr->second._texture.get()<<", "<<ba_itr->second._face<<std::endl;
830                                         }
831                                         else
832                                         {
833                                             event.addPointerData(new osgGA::PointerData(slave_camera, tc.x(), 0.0f, 1.0f,
834                                                                                                            tc.y(), 0.0f, 1.0f));
835                                         }
836                                     }
837                                 }
838                             }
839                         }
840                     }
841                 }
842             }
843         }
844     }
845 }
846 
generatePointerData(osgGA::GUIEventAdapter & event)847 void CompositeViewer::generatePointerData(osgGA::GUIEventAdapter& event)
848 {
849     osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(event.getGraphicsContext());
850     if (!gw) return;
851 
852     float x = event.getX();
853     float y = event.getY();
854 
855     bool invert_y = event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS;
856     if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y;
857 
858     event.addPointerData(new osgGA::PointerData(gw, x, 0, gw->getTraits()->width,
859                                                     y, 0, gw->getTraits()->height));
860 
861     event.setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
862 
863     typedef std::vector<osg::Camera*> CameraVector;
864     CameraVector activeCameras;
865 
866     osg::GraphicsContext::Cameras& cameras = gw->getCameras();
867     for(osg::GraphicsContext::Cameras::iterator citr = cameras.begin();
868         citr != cameras.end();
869         ++citr)
870     {
871         osg::Camera* camera = *citr;
872         if (camera->getAllowEventFocus() &&
873             camera->getRenderTargetImplementation()==osg::Camera::FRAME_BUFFER)
874         {
875             osg::Viewport* viewport = camera ? camera->getViewport() : 0;
876             if (viewport &&
877                 x >= viewport->x() && y >= viewport->y() &&
878                 x <= (viewport->x()+viewport->width()) && y <= (viewport->y()+viewport->height()) )
879             {
880                 activeCameras.push_back(camera);
881             }
882         }
883     }
884 
885     std::sort(activeCameras.begin(), activeCameras.end(), osg::CameraRenderOrderSortOp());
886 
887     osg::Camera* camera = activeCameras.empty() ? 0 : activeCameras.back();
888 
889     if (camera)
890     {
891         osg::Viewport* viewport = camera ? camera->getViewport() : 0;
892 
893         event.addPointerData(new osgGA::PointerData(camera, (x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0,
894                                                             (y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0));
895 
896         osgViewer::View* view = dynamic_cast<osgViewer::View*>(camera->getView());
897         osg::Camera* view_masterCamera = view ? view->getCamera() : 0;
898 
899         // if camera isn't the master it must be a slave and could need reprojecting.
900         if (view && camera!=view_masterCamera)
901         {
902             generateSlavePointerData(camera, event);
903         }
904     }
905 }
906 
reprojectPointerData(osgGA::GUIEventAdapter & source_event,osgGA::GUIEventAdapter & dest_event)907 void CompositeViewer::reprojectPointerData(osgGA::GUIEventAdapter& source_event, osgGA::GUIEventAdapter& dest_event)
908 {
909     osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(dest_event.getGraphicsContext());
910     if (!gw) return;
911 
912     float x = dest_event.getX();
913     float y = dest_event.getY();
914 
915     bool invert_y = dest_event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS;
916     if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y;
917 
918     dest_event.addPointerData(new osgGA::PointerData(gw, x, 0, gw->getTraits()->width,
919                                                          y, 0, gw->getTraits()->height));
920 
921     dest_event.setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
922 
923     osg::Camera* camera = (source_event.getNumPointerData()>=2) ? dynamic_cast<osg::Camera*>(source_event.getPointerData(1)->object.get()) : 0;
924     osg::Viewport* viewport = camera ? camera->getViewport() : 0;
925 
926     if (!viewport) return;
927 
928     dest_event.addPointerData(new osgGA::PointerData(camera, (x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0,
929                                                              (y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0));
930 
931     osgViewer::View* view = dynamic_cast<osgViewer::View*>(camera->getView());
932     osg::Camera* view_masterCamera = view ? view->getCamera() : 0;
933 
934     // if camera isn't the master it must be a slave and could need reprojecting.
935     if (view && camera!=view_masterCamera)
936     {
937         generateSlavePointerData(camera, dest_event);
938     }
939 }
940 
941 struct SortEvents
942 {
operator ()SortEvents943     bool operator() (const osg::ref_ptr<osgGA::Event>& lhs,const osg::ref_ptr<osgGA::Event>& rhs) const
944     {
945         return lhs->getTime() < rhs->getTime();
946     }
947 };
948 
eventTraversal()949 void CompositeViewer::eventTraversal()
950 {
951     if (_done) return;
952 
953     if (_views.empty()) return;
954 
955     double cutOffTime = _frameStamp->getReferenceTime();
956 
957     double beginEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
958 
959     // need to copy events from the GraphicsWindow's into local EventQueue for each view;
960     typedef std::map<osgViewer::View*, osgGA::EventQueue::Events> ViewEventsMap;
961     ViewEventsMap viewEventsMap;
962 
963     Contexts contexts;
964     getContexts(contexts);
965 
966     // set done if there are no windows
967     checkWindowStatus(contexts);
968     if (_done) return;
969 
970     osgGA::EventQueue::Events all_events;
971 
972     for(Contexts::iterator citr = contexts.begin();
973         citr != contexts.end();
974         ++citr)
975     {
976         osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*citr);
977         if (gw)
978         {
979             gw->checkEvents();
980 
981             osgGA::EventQueue::Events gw_events;
982             gw->getEventQueue()->takeEvents(gw_events, cutOffTime);
983 
984             for(osgGA::EventQueue::Events::iterator itr = gw_events.begin();
985                 itr != gw_events.end();
986                 ++itr)
987             {
988                 osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter();
989                 if (ea) ea->setGraphicsContext(gw);
990             }
991 
992             all_events.insert(all_events.end(), gw_events.begin(), gw_events.end());
993         }
994     }
995 
996     // sort all the events in time order so we can make sure we pass them all on in the correct order.
997     all_events.sort(SortEvents());
998 
999     // pass on pointer data onto non mouse events to keep the position data usable by all recipients of all events.
1000     for(osgGA::EventQueue::Events::iterator itr = all_events.begin();
1001         itr != all_events.end();
1002         ++itr)
1003     {
1004         osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
1005         if (!event) continue;
1006 
1007         switch(event->getEventType())
1008         {
1009             case(osgGA::GUIEventAdapter::PUSH):
1010             case(osgGA::GUIEventAdapter::RELEASE):
1011             case(osgGA::GUIEventAdapter::DOUBLECLICK):
1012             case(osgGA::GUIEventAdapter::MOVE):
1013             case(osgGA::GUIEventAdapter::DRAG):
1014             {
1015                 if ((event->getEventType()!=osgGA::GUIEventAdapter::DRAG && event->getEventType()!=osgGA::GUIEventAdapter::RELEASE) ||
1016                     !_previousEvent ||
1017                     _previousEvent->getGraphicsContext()!=event->getGraphicsContext() ||
1018                     _previousEvent->getNumPointerData()<2)
1019                 {
1020                     generatePointerData(*event);
1021                 }
1022                 else
1023                 {
1024                     reprojectPointerData(*_previousEvent, *event);
1025                 }
1026 
1027                 _previousEvent = event;
1028 
1029                 break;
1030             }
1031             default:
1032                 if (_previousEvent.valid()) event->copyPointerDataFrom(*_previousEvent);
1033                 break;
1034         }
1035 
1036         osgGA::PointerData* pd = event->getNumPointerData()>0 ? event->getPointerData(event->getNumPointerData()-1) : 0;
1037         osg::Camera* camera = pd ? dynamic_cast<osg::Camera*>(pd->object.get()) : 0;
1038         osgViewer::View* view = camera ? dynamic_cast<osgViewer::View*>(camera->getView()) : 0;
1039 
1040         if (!view)
1041         {
1042             if (_viewWithFocus.valid())
1043             {
1044                 // OSG_NOTICE<<"Falling back to using _viewWithFocus"<<std::endl;
1045                 view = _viewWithFocus.get();
1046             }
1047             else if (!_views.empty())
1048             {
1049                 // OSG_NOTICE<<"Falling back to using first view as one with focus"<<std::endl;
1050                 view = _views[0].get();
1051             }
1052         }
1053 
1054         // reassign view with focus
1055         if (_viewWithFocus != view)  _viewWithFocus = view;
1056 
1057         if (view)
1058         {
1059             viewEventsMap[view].push_back( event );
1060 
1061             osgGA::GUIEventAdapter* eventState = view->getEventQueue()->getCurrentEventState();
1062             eventState->copyPointerDataFrom(*event);
1063         }
1064 
1065         _previousEvent = event;
1066     }
1067 
1068     // handle any close windows
1069     for(osgGA::EventQueue::Events::iterator itr = all_events.begin();
1070         itr != all_events.end();
1071         ++itr)
1072     {
1073         osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
1074         if (!event) continue;
1075 
1076         switch(event->getEventType())
1077         {
1078             case(osgGA::GUIEventAdapter::CLOSE_WINDOW):
1079             {
1080                 bool wasThreading = areThreadsRunning();
1081                 if (wasThreading) stopThreading();
1082 
1083                 if (event->getGraphicsContext())
1084                 {
1085                     event->getGraphicsContext()->close();
1086                 }
1087 
1088                 if (wasThreading) startThreading();
1089 
1090                 break;
1091             }
1092             default:
1093                 break;
1094         }
1095     }
1096 
1097 
1098     for(RefViews::iterator vitr = _views.begin();
1099         vitr != _views.end();
1100         ++vitr)
1101     {
1102         View* view = vitr->get();
1103 
1104         // get events from user Devices attached to Viewer.
1105         for(osgViewer::View::Devices::iterator eitr = view->getDevices().begin();
1106             eitr != view->getDevices().end();
1107             ++eitr)
1108         {
1109             osgGA::Device* es = eitr->get();
1110             if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS)
1111                 es->checkEvents();
1112 
1113             // open question, will we need to reproject mouse coordinates into current view's coordinate frame as is down for GraphicsWindow provided events?
1114             // for now assume now and just get the events directly without any reprojection.
1115             es->getEventQueue()->takeEvents(viewEventsMap[view], cutOffTime);
1116         }
1117 
1118         // create a frame event for the new frame.
1119         {
1120             osg::ref_ptr<osgGA::GUIEventAdapter> event = view->getEventQueue()->frame( getFrameStamp()->getReferenceTime() );
1121 
1122             if (!_previousEvent || _previousEvent->getNumPointerData()<2)
1123             {
1124                 generatePointerData(*event);
1125             }
1126             else
1127             {
1128                 reprojectPointerData(*_previousEvent, *event);
1129             }
1130         }
1131 
1132 
1133         view->getEventQueue()->takeEvents(viewEventsMap[view], cutOffTime);
1134     }
1135 
1136     if ((_keyEventSetsDone!=0) || _quitEventSetsDone)
1137     {
1138         for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
1139             veitr != viewEventsMap.end();
1140             ++veitr)
1141         {
1142             for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin();
1143                 itr != veitr->second.end();
1144                 ++itr)
1145             {
1146                 osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
1147                 if (!event) continue;
1148 
1149                 // ignore event if it's already been handled.
1150                 if (event->getHandled()) continue;
1151 
1152                 switch(event->getEventType())
1153                 {
1154                     case(osgGA::GUIEventAdapter::KEYUP):
1155                         if (_keyEventSetsDone && event->getKey()==_keyEventSetsDone) _done = true;
1156                         break;
1157 
1158                     case(osgGA::GUIEventAdapter::QUIT_APPLICATION):
1159                         if (_quitEventSetsDone) _done = true;
1160                         break;
1161 
1162                     default:
1163                         break;
1164                 }
1165             }
1166         }
1167     }
1168 
1169     if (_done) return;
1170 
1171     if (_eventVisitor.valid())
1172     {
1173         _eventVisitor->setFrameStamp(getFrameStamp());
1174         _eventVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber());
1175 
1176         for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
1177             veitr != viewEventsMap.end();
1178             ++veitr)
1179         {
1180             View* view = veitr->first;
1181             _eventVisitor->setActionAdapter(view);
1182 
1183             if (view && view->getSceneData())
1184             {
1185                 for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin();
1186                     itr != veitr->second.end();
1187                     ++itr)
1188                 {
1189                     osgGA::Event* event = itr->get();
1190 
1191                     _eventVisitor->reset();
1192                     _eventVisitor->addEvent( event );
1193 
1194                     view->getSceneData()->accept(*_eventVisitor);
1195 
1196                     // Do EventTraversal for slaves with their own subgraph
1197                     for(unsigned int i=0; i<view->getNumSlaves(); ++i)
1198                     {
1199                         osg::View::Slave& slave = view->getSlave(i);
1200                         osg::Camera* camera = slave._camera.get();
1201                         if(camera && !slave._useMastersSceneData)
1202                         {
1203                             camera->accept(*_eventVisitor);
1204                         }
1205                     }
1206 
1207                     // call any camera event callbacks, but only traverse that callback, don't traverse its subgraph
1208                     // leave that to the scene update traversal.
1209                     osg::NodeVisitor::TraversalMode tm = _eventVisitor->getTraversalMode();
1210                     _eventVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE);
1211 
1212                     if (view->getCamera() && view->getCamera()->getEventCallback()) view->getCamera()->accept(*_eventVisitor);
1213 
1214                     for(unsigned int i=0; i<view->getNumSlaves(); ++i)
1215                     {
1216                         osg::View::Slave& slave = view->getSlave(i);
1217                         osg::Camera* camera = view->getSlave(i)._camera.get();
1218                         if (camera && slave._useMastersSceneData && camera->getEventCallback())
1219                         {
1220                             camera->accept(*_eventVisitor);
1221                         }
1222                     }
1223 
1224                     _eventVisitor->setTraversalMode(tm);
1225 
1226                 }
1227             }
1228         }
1229 
1230     }
1231 
1232     for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
1233         veitr != viewEventsMap.end();
1234         ++veitr)
1235     {
1236         View* view = veitr->first;
1237         _eventVisitor->setActionAdapter(view);
1238 
1239         for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin();
1240             itr != veitr->second.end();
1241             ++itr)
1242         {
1243             osgGA::Event* event = itr->get();
1244             for(View::EventHandlers::iterator hitr = view->getEventHandlers().begin();
1245                 hitr != view->getEventHandlers().end();
1246                 ++hitr)
1247             {
1248                 (*hitr)->handle( event, view, _eventVisitor.get());
1249             }
1250         }
1251     }
1252 
1253     for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
1254         veitr != viewEventsMap.end();
1255         ++veitr)
1256     {
1257         View* view = veitr->first;
1258         _eventVisitor->setActionAdapter(view);
1259 
1260         for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin();
1261             itr != veitr->second.end();
1262             ++itr)
1263         {
1264             osgGA::Event* event = itr->get();
1265             if (view->getCameraManipulator())
1266             {
1267                 view->getCameraManipulator()->handle( event, view, _eventVisitor.get());
1268             }
1269         }
1270     }
1271 
1272     if (getViewerStats() && getViewerStats()->collectStats("event"))
1273     {
1274         double endEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
1275 
1276         // update current frames stats
1277         getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal begin time", beginEventTraversal);
1278         getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal end time", endEventTraversal);
1279         getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event traversal time taken", endEventTraversal-beginEventTraversal);
1280     }
1281 }
1282 
updateTraversal()1283 void CompositeViewer::updateTraversal()
1284 {
1285     if (_done) return;
1286 
1287     double beginUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
1288 
1289     _updateVisitor->reset();
1290     _updateVisitor->setFrameStamp(getFrameStamp());
1291     _updateVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber());
1292 
1293     Scenes scenes;
1294     getScenes(scenes);
1295     for(Scenes::iterator sitr = scenes.begin();
1296         sitr != scenes.end();
1297         ++sitr)
1298     {
1299         Scene* scene = *sitr;
1300         scene->updateSceneGraph(*_updateVisitor);
1301     }
1302 
1303     // if we have a shared state manager prune any unused entries
1304     if (osgDB::Registry::instance()->getSharedStateManager())
1305         osgDB::Registry::instance()->getSharedStateManager()->prune();
1306 
1307     // update the Registry object cache.
1308     osgDB::Registry::instance()->updateTimeStampOfObjectsInCacheWithExternalReferences(*getFrameStamp());
1309     osgDB::Registry::instance()->removeExpiredObjectsInCache(*getFrameStamp());
1310 
1311 
1312     if (_incrementalCompileOperation.valid())
1313     {
1314         // merge subgraphs that have been compiled by the incremental compiler operation.
1315         _incrementalCompileOperation->mergeCompiledSubgraphs(getFrameStamp());
1316     }
1317 
1318     if (_updateOperations.valid())
1319     {
1320         _updateOperations->runOperations(this);
1321     }
1322 
1323     for(RefViews::iterator vitr = _views.begin();
1324         vitr != _views.end();
1325         ++vitr)
1326     {
1327         View* view = vitr->get();
1328 
1329         {
1330             // Do UpdateTraversal for slaves with their own subgraph
1331             for(unsigned int i=0; i<view->getNumSlaves(); ++i)
1332             {
1333                 osg::View::Slave& slave = view->getSlave(i);
1334                 osg::Camera* camera = slave._camera.get();
1335                 if(camera && !slave._useMastersSceneData)
1336                 {
1337                     camera->accept(*_updateVisitor);
1338                 }
1339             }
1340 
1341             // call any camera update callbacks, but only traverse that callback, don't traverse its subgraph
1342             // leave that to the scene update traversal.
1343             osg::NodeVisitor::TraversalMode tm = _updateVisitor->getTraversalMode();
1344             _updateVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE);
1345 
1346             if (view->getCamera() && view->getCamera()->getUpdateCallback()) view->getCamera()->accept(*_updateVisitor);
1347 
1348             for(unsigned int i=0; i<view->getNumSlaves(); ++i)
1349             {
1350                 osg::View::Slave& slave = view->getSlave(i);
1351                 osg::Camera* camera = slave._camera.get();
1352                 if (camera && slave._useMastersSceneData && camera->getUpdateCallback())
1353                 {
1354                     camera->accept(*_updateVisitor);
1355                 }
1356             }
1357 
1358             _updateVisitor->setTraversalMode(tm);
1359         }
1360 
1361 
1362         if (view->getCameraManipulator())
1363         {
1364             view->setFusionDistance( view->getCameraManipulator()->getFusionDistanceMode(),
1365                                     view->getCameraManipulator()->getFusionDistanceValue() );
1366 
1367             view->getCameraManipulator()->updateCamera(*(view->getCamera()));
1368 
1369         }
1370         view->updateSlaves();
1371 
1372     }
1373 
1374     if (getViewerStats() && getViewerStats()->collectStats("update"))
1375     {
1376         double endUpdateTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
1377 
1378         // update current frames stats
1379         getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal begin time", beginUpdateTraversal);
1380         getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal end time", endUpdateTraversal);
1381         getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Update traversal time taken", endUpdateTraversal-beginUpdateTraversal);
1382     }
1383 
1384 }
1385 
elapsedTime()1386 double CompositeViewer::elapsedTime()
1387 {
1388     return osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick());
1389 }
1390 
getUsage(osg::ApplicationUsage & usage) const1391 void CompositeViewer::getUsage(osg::ApplicationUsage& usage) const
1392 {
1393     for(RefViews::const_iterator vitr = _views.begin();
1394         vitr != _views.end();
1395         ++vitr)
1396     {
1397         const View* view = vitr->get();
1398         if (view->getCameraManipulator())
1399         {
1400             view->getCameraManipulator()->getUsage(usage);
1401         }
1402 
1403         for(View::EventHandlers::const_iterator hitr = view->_eventHandlers.begin();
1404             hitr != view->_eventHandlers.end();
1405             ++hitr)
1406         {
1407             (*hitr)->getUsage(usage);
1408         }
1409     }
1410 }
1411