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