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