root/OpenSceneGraph/trunk/src/osgViewer/Viewer.cpp @ 13876

Revision 13876, 45.5 kB (checked in by robert, 14 hours ago)

Changed the osgUI behaviour so that events are set to be handled by Widgets that have focus even if they don't directly use them.

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