root/OpenSceneGraph/trunk/examples/osgcamera/osgcamera.cpp @ 5832

Revision 5832, 17.9 kB (checked in by robert, 7 years ago)

Further work osgViewer::Viewer and related classes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// C++ source file - (C) 2003 Robert Osfield, released under the OSGPL.
2//
3// Simple example of use of Producer::RenderSurface to create an OpenGL
4// graphics window, and OSG for rendering.
5
6#include <osg/Timer>
7#include <osg/GraphicsContext>
8#include <osg/GraphicsThread>
9
10#include <osgUtil/UpdateVisitor>
11#include <osgUtil/CullVisitor>
12#include <osgUtil/SceneView>
13#include <osgUtil/GLObjectsVisitor>
14
15#include <osgDB/ReadFile>
16#include <osgDB/DynamicLibrary>
17#include <osgDB/Registry>
18
19#include <osgViewer/View>
20
21#include <map>
22#include <list>
23#include <iostream>
24
25
26#if !defined(_WIN32)
27
28#include <osgViewer/GraphicsWindowX11>
29#include <osgViewer/Viewer>
30
31#include <osgGA/TrackballManipulator>
32
33void renderCamera(osg::Camera* camera)
34{
35    osg::GraphicsContext* gc = camera->getGraphicsContext();
36    if (!gc) return;
37   
38#if 0   
39    osgViewer::GraphicsWindowX11* gwX11 =  dynamic_cast<osgViewer::GraphicsWindowX11*>(gc);
40    if (gwX11)
41    {
42        gwX11->checkEvents();
43
44        osgGA::EventQueue::Events events;
45        if (gwX11->getEventQueue()->takeEvents(events))
46        {
47        }
48    }
49#endif
50   
51    osgUtil::SceneView* sceneView = dynamic_cast<osgUtil::SceneView*>(camera->getRenderingCache(0));
52    if (!sceneView) return;
53
54    gc->makeCurrent();
55   
56    sceneView->cull();
57    sceneView->draw();
58   
59    gc->swapBuffers();
60}
61
62void setUpFrameStamp(osg::Camera* camera, osg::FrameStamp* frameStamp, osg::Node* loadedModel)
63{
64    osgUtil::SceneView* sceneView = dynamic_cast<osgUtil::SceneView*>(camera->getRenderingCache(0));
65    if (!sceneView) return;
66   
67    sceneView->setFrameStamp(frameStamp);
68   
69    sceneView->setSceneData(loadedModel);
70   
71}
72
73int main( int argc, char **argv )
74{
75    if (argc<2)
76    {
77        std::cout << argv[0] <<": requires filename argument." << std::endl;
78        return 1;
79    }
80
81    // load the scene.
82    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile(argv[1]);
83    if (!loadedModel)
84    {
85        std::cout << argv[0] <<": No data loaded." << std::endl;
86        return 1;
87    }
88   
89    // initialize the view to look at the center of the scene graph
90    const osg::BoundingSphere& bs = loadedModel->getBound();
91    osg::Matrix viewMatrix;
92    viewMatrix.makeLookAt(bs.center()-osg::Vec3(0.0,2.0f*bs.radius(),0.0),bs.center(),osg::Vec3(0.0f,0.0f,1.0f));
93
94    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
95    viewer->setSceneData(loadedModel.get());
96    viewer->setCameraManipulator(new osgGA::TrackballManipulator());
97    viewer->setUpViewAcrossAllScreens();
98    viewer->realize();
99   
100    viewer->getCamera()->setClearColor(osg::Vec4f(0.6f,0.6f,0.8f,1.0f));
101   
102    osg::ref_ptr<osg::FrameStamp> frameStamp = new osg::FrameStamp;
103
104    unsigned int frameNum = 0;
105
106    osgUtil::UpdateVisitor updateVisitor;
107    updateVisitor.setFrameStamp(frameStamp.get());
108   
109    setUpFrameStamp(viewer->getCamera(), frameStamp.get(), loadedModel.get());
110    for(unsigned i=0; i<viewer->getNumSlaves(); ++i)
111    {
112        osg::View::Slave& slave = viewer->getSlave(i);
113        setUpFrameStamp(slave._camera.get(), frameStamp.get(), loadedModel.get());
114    }
115
116    // record the timer tick at the start of rendering.   
117    osg::Timer_t start_tick = osg::Timer::instance()->tick();
118    osg::Timer_t previous_tick = start_tick;
119
120    while(true)
121    {
122        osg::Timer_t current_tick = osg::Timer::instance()->tick();
123
124        frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(start_tick,current_tick));
125        frameStamp->setFrameNumber(frameNum++);
126       
127        //std::cout<<"Frame rate "<<1.0/osg::Timer::instance()->delta_s(previous_tick,current_tick)<<std::endl;
128        previous_tick = current_tick;
129
130        // do the update traversal.
131        loadedModel->accept(updateVisitor);
132
133        viewer->frameAdvance();
134        viewer->frameEventTraversal();
135        viewer->frameUpdateTraversal();
136
137        // viewer->getCamera()->setViewMatrix(viewMatrix);
138
139
140        if (viewer->getCamera() && viewer->getCamera()->getGraphicsContext()) renderCamera(viewer->getCamera());
141       
142        for(unsigned i=0; i<viewer->getNumSlaves(); ++i)
143        {
144            osg::View::Slave& slave = viewer->getSlave(i);
145            if (slave._camera.valid() && slave._camera->getGraphicsContext()) renderCamera(slave._camera.get());
146        }
147       
148    }
149}
150
151
152#else
153
154
155//////////////////////////////////////////////////////////////////////////////////////////////////////////////
156// 
157//  ORIGINAL osgcamera example code.
158
159////////////////////////////////////////////////////////////////////////////////
160//
161//
162//  **************** THIS IS AN EXPERIMENTAL IMPLEMENTATION ***************
163//  ************************** PLEASE DO NOT COPY  ************************
164//
165//
166///////////////////////////////////////////////////////////////////////////////
167
168
169// Compile operation, that compile OpenGL objects.
170struct CompileOperation : public osg::GraphicsThread::Operation
171{
172    CompileOperation(osg::Node* scene):
173        osg::GraphicsThread::Operation("Compile",false),
174        _scene(scene)
175    {
176    }
177   
178    virtual void operator () (osg::GraphicsContext* context)
179    {
180        std::cout<<"Compile"<<std::endl;
181   
182        osgUtil::GLObjectsVisitor compileVisitor;
183        compileVisitor.setState(context->getState());
184
185        // do the compile traversal
186        _scene->accept(compileVisitor);
187    }
188   
189    osg::ref_ptr<osg::Node> _scene;
190};
191
192// Cull operation, that does a cull on the scene graph.
193struct CullOperation : public osg::GraphicsThread::Operation
194{
195    CullOperation(osgUtil::SceneView* sceneView):
196        osg::GraphicsThread::Operation("Cull",true),
197        _sceneView(sceneView)
198    {
199    }
200   
201    virtual void operator () (osg::GraphicsContext* context)
202    {
203        _sceneView->setState(context->getState());
204        _sceneView->cull();
205    }
206   
207    osg::ref_ptr<osgUtil::SceneView> _sceneView;
208};
209
210// Draw operation, that does a draw on the scene graph.
211struct DrawOperation : public osg::GraphicsThread::Operation
212{
213    DrawOperation(osgUtil::SceneView* sceneView):
214        osg::GraphicsThread::Operation("Draw",true),
215        _sceneView(sceneView)
216    {
217    }
218   
219    virtual void operator () (osg::GraphicsContext*)
220    {
221        _sceneView->draw();
222    }
223   
224    osg::ref_ptr<osgUtil::SceneView> _sceneView;
225};
226
227struct CleanUpOperation : public osg::GraphicsThread::Operation
228{
229    CleanUpOperation(osgUtil::SceneView* sceneView):
230        osg::GraphicsThread::Operation("CleanUp",false),
231        _sceneView(sceneView)
232    {
233    }
234   
235    virtual void operator () (osg::GraphicsContext*)
236    {
237        _sceneView->releaseAllGLObjects();
238        _sceneView->flushAllDeletedGLObjects();
239    }
240   
241    osg::ref_ptr<osgUtil::SceneView> _sceneView;
242};
243
244// main does the following steps to create a multi-thread, multiple camera/graphics context view of a scene graph.
245//
246// 1) load the scene graph
247//
248// 2) create a list of camera, each with their own graphis context, with a graphics thread for each context.
249//
250// 3) set up the graphic threads so that the do an initial compile OpenGL objects operation, this is done once, and then this compile op is disgarded
251//
252// 4) set up the graphics thread so that it has all the graphics ops required for the main loop, these ops are:
253// 4.a) frame begin barrair, syncronizes all the waiting graphic threads so they don't run while update is occuring
254// 4.b) frame operation - the cull and draw for each camera
255// 4.c) frame end barrier, releases the update thread once all graphic threads have dispatched all their OpenGL commands
256// 4.d) pre swap barrier, barrier which ensures that all graphics threads have sent their data down to the gfx card.
257// 4.e) swap buffers, do the swap buffers on all the graphics contexts.
258//
259// 5. The main loop:
260// 5.a) update
261// 5.b) join the frame begin barrrier, releasing all the graphics threads to do their stuff
262// 5.c) block on the frame end barrier, waiting till all the graphics threads have done their cull/draws.
263// 5.d) check to see if any of the windows has been closed.
264//
265int main( int argc, char **argv )
266{
267    osg::Referenced::setThreadSafeReferenceCounting(true);
268
269    // use an ArgumentParser object to manage the program arguments.
270    osg::ArgumentParser arguments(&argc,argv);
271
272    std::string windowingLibrary("osgProducer");
273    while (arguments.read("--windowing",windowingLibrary)) {}
274
275    // load the osgProducer library manually.
276    osg::ref_ptr<osgDB::DynamicLibrary> windowingLib =
277        osgDB::DynamicLibrary::loadLibrary(osgDB::Registry::instance()->createLibraryNameForNodeKit(windowingLibrary));
278
279
280    if (!windowingLib)
281    {
282        std::cout<<"Error: failed to loading windowing library: "<<windowingLibrary<<std::endl;
283    }
284
285    osg::GraphicsContext::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
286    if (!wsi)
287    {
288        std::cout<<"No WindowSystemInterface available, cannot create windows."<<std::endl;
289        return 1;
290    }
291
292
293    osg::ref_ptr<osgViewer::View> view = new osgViewer::View;
294    view->setUpViewAcrossAllScreens();
295
296
297
298
299    unsigned int numScreens = wsi->getNumScreens();
300
301    unsigned int numberCameras = numScreens;
302    while (arguments.read("--cameras",numberCameras)) {}
303
304    unsigned int xpos = 0;
305    unsigned int ypos = 400;
306    unsigned int width = 400;
307    unsigned int height = 400;
308
309    while (arguments.read("--xpos",xpos)) {}
310    while (arguments.read("--ypos",ypos)) {}
311    while (arguments.read("--height",height)) {}
312    while (arguments.read("--width",width)) {}
313
314    unsigned int maxNumFrames = 1000;
315    while (arguments.read("--max-num-frames",maxNumFrames)) {}
316
317    // load the scene.
318    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
319    if (!loadedModel)
320    {
321        std::cout << argv[0] <<": No data loaded." << std::endl;
322        return 1;
323    }
324
325   
326    // set up the frame stamp for current frame to record the current time and frame number so that animtion code can advance correctly
327    osg::ref_ptr<osg::FrameStamp> frameStamp = new osg::FrameStamp;
328
329    unsigned int frameNum = 0;
330
331    osgUtil::UpdateVisitor updateVisitor;
332    updateVisitor.setFrameStamp(frameStamp.get());
333   
334    typedef std::list< osg::ref_ptr<osg::Camera> > CameraList;
335    typedef std::set< osg::GraphicsContext* > GraphicsContextSet;
336
337    CameraList cameraList;
338    GraphicsContextSet graphicsContextSet;
339   
340   
341
342    // create the cameras, graphic contexts and graphic threads.
343    bool shareContexts = false;
344    osg::GraphicsContext* previousContext = 0;
345    for(unsigned int i=0; i< numberCameras; ++i)
346    {
347        osg::ref_ptr<osg::Camera> camera = new osg::Camera;
348        camera->addChild(loadedModel.get());
349
350        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
351        traits->_windowName = "osgcamera";
352        traits->_screenNum = i % numScreens;
353        traits->_x = xpos;
354        traits->_y = ypos;
355        traits->_width = width;
356        traits->_height = height;
357        traits->_windowDecoration = true;
358        traits->_doubleBuffer = true;
359        traits->_sharedContext = shareContexts ? previousContext : 0;
360       
361        xpos += width;
362
363        osg::ref_ptr<osg::GraphicsContext> gfxc = osg::GraphicsContext::createGraphicsContext(traits.get());
364
365        if (!gfxc)
366        {
367            std::cout<<"Unable to create window."<<std::endl;
368            return 1;
369        }
370
371        camera->setGraphicsContext(gfxc.get());
372
373        // initialize the view to look at the center of the scene graph
374        const osg::BoundingSphere& bs = loadedModel->getBound();
375        osg::Matrix viewMatrix;
376        viewMatrix.makeLookAt(bs.center()-osg::Vec3(0.0,2.0f*bs.radius(),0.0),bs.center(),osg::Vec3(0.0f,0.0f,1.0f));
377
378        camera->setViewport(0,0,traits->_width,traits->_height);
379        camera->setProjectionMatrixAsPerspective(50.0f,1.4f,1.0f,10000.0f);
380        camera->setViewMatrix(viewMatrix);
381
382        // graphics thread will realize the window.
383        gfxc->createGraphicsThread();
384
385        cameraList.push_back(camera);
386
387        previousContext = gfxc.get();
388    }
389
390
391    // build the list of unique graphics contexts.
392    CameraList::iterator citr;
393    for(citr = cameraList.begin();
394        citr != cameraList.end();
395        ++citr)
396    {
397        graphicsContextSet.insert(const_cast<osg::GraphicsContext*>((*citr)->getGraphicsContext()));
398    }
399
400
401    std::cout<<"Number of cameras = "<<cameraList.size()<<std::endl;
402    std::cout<<"Number of graphics contexts = "<<graphicsContextSet.size()<<std::endl;
403
404
405    // first the compile of the GL Objects, do it syncronously.
406    GraphicsContextSet::iterator gitr;
407    osg::ref_ptr<CompileOperation> compileOp = new CompileOperation(loadedModel.get());
408    for(gitr = graphicsContextSet.begin();
409        gitr != graphicsContextSet.end();
410        ++gitr)
411    {
412        osg::GraphicsContext* context = *gitr;
413        context->getGraphicsThread()->add(compileOp.get(), false);
414    }
415
416
417    // second the begin frame barrier to all graphics threads
418    osg::ref_ptr<osg::BarrierOperation> frameBeginBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
419    for(gitr = graphicsContextSet.begin();
420        gitr != graphicsContextSet.end();
421        ++gitr)
422    {
423        osg::GraphicsContext* context = *gitr;
424        context->getGraphicsThread()->add(frameBeginBarrierOp.get(), false);
425    }
426
427    osg::ref_ptr<osg::BarrierOperation> glFinishBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FINISH);
428
429    // we can put a finish in to gate rendering throughput, so that each new frame starts with a clean sheet.
430    // you should only enable one of these, doFinishBeforeNewDraw will allow for the better parallism of the two finish approaches
431    // note, both are disabled right now, as glFinish is spin locking the CPU, not something that we want...
432    bool doFinishBeforeNewDraw = false;
433    bool doFinishAfterSwap = false;
434
435    // third add the frame for each camera.
436    for(citr = cameraList.begin();
437        citr != cameraList.end();
438        ++citr)
439    {
440        osg::Camera* camera = citr->get();
441        osg::GraphicsThread* graphicsThread = camera->getGraphicsContext()->getGraphicsThread();
442       
443        // create a scene view to do the cull and draw
444        osgUtil::SceneView* sceneView = new osgUtil::SceneView;
445        sceneView->setDefaults();
446        sceneView->setFrameStamp(frameStamp.get());
447        sceneView->setCamera(camera);   
448
449        // cull traversal operation
450        graphicsThread->add( new CullOperation(sceneView), false);
451
452        // optionally add glFinish barrier to ensure that all OpenGL commands are completed before we start dispatching a new frame
453        if (doFinishBeforeNewDraw) graphicsThread->add( glFinishBarrierOp.get(), false);
454
455        // draw traversal operation.
456        graphicsThread->add( new DrawOperation(sceneView), false);
457    }
458
459    // fourth add the frame end barrier, the pre swap barrier and finally the swap buffers to each graphics thread.
460    // The frame end barrier tells the main thead that the draw dispatch/read phase of the scene graph is complete.
461    // The pre swap barrier is an optional extra, which does a flush before joining the barrier, using this all graphics threads
462    // are held back until they have all dispatched their fifo to the graphics hardware. 
463    // The swapOp just issues a swap buffers for each of the graphics contexts.
464    osg::ref_ptr<osg::BarrierOperation> frameEndBarrierOp = new osg::BarrierOperation(graphicsContextSet.size()+1, osg::BarrierOperation::NO_OPERATION);
465    osg::ref_ptr<osg::BarrierOperation> preSwapBarrierOp = new osg::BarrierOperation(graphicsContextSet.size(), osg::BarrierOperation::GL_FLUSH);
466    osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
467    for(gitr = graphicsContextSet.begin();
468        gitr != graphicsContextSet.end();
469        ++gitr)
470    {
471        osg::GraphicsContext* context = *gitr;
472
473        context->getGraphicsThread()->add(frameEndBarrierOp.get(), false);
474        // context->getGraphicsThread()->add(preSwapBarrierOp.get(), false);
475        context->getGraphicsThread()->add(swapOp.get(), false);
476       
477        // optionally add finish barrier to ensure that we don't do any other graphics work till the current OpenGL commands are complete.
478        if (doFinishAfterSwap) context->getGraphicsThread()->add(glFinishBarrierOp.get(), false);
479    }
480
481
482    // record the timer tick at the start of rendering.   
483    osg::Timer_t start_tick = osg::Timer::instance()->tick();
484    osg::Timer_t previous_tick = start_tick;
485   
486    bool done = false;
487
488    // main loop -  update scene graph, dispatch frame, wait for frame done.
489    while( !done && frameNum<maxNumFrames)
490    {
491
492        osg::Timer_t current_tick = osg::Timer::instance()->tick();
493
494        frameStamp->setReferenceTime(osg::Timer::instance()->delta_s(start_tick,current_tick));
495        frameStamp->setFrameNumber(frameNum++);
496       
497        //std::cout<<"Frame rate "<<1.0/osg::Timer::instance()->delta_s(previous_tick,current_tick)<<std::endl;
498        previous_tick = current_tick;
499
500
501        // do the update traversal.
502        loadedModel->accept(updateVisitor);
503
504        // dispatch the frame.
505        frameBeginBarrierOp->block();
506       
507        // wait till the frame is done.
508        frameEndBarrierOp->block();
509
510        // check if any of the windows are closed
511        for(gitr = graphicsContextSet.begin();
512            gitr != graphicsContextSet.end();
513            ++gitr)
514        {
515            osg::GraphicsContext* context = *gitr;
516            if (!context->isRealized()) done = true;
517        }
518
519    }
520
521   
522    std::cout<<"Exiting application"<<std::endl;
523
524    // start clean up.
525    for(gitr = graphicsContextSet.begin();
526        gitr != graphicsContextSet.end();
527        ++gitr)
528    {
529        osg::GraphicsContext* context = *gitr;
530        osg::GraphicsThread* thread = context->getGraphicsThread();
531        if (thread)
532        {
533            thread->removeAllOperations();
534            thread->setDone(true);
535        }
536    }
537
538    std::cout<<"Removed all operations"<<std::endl;
539
540    return 0;
541}
542
543#endif
Note: See TracBrowser for help on using the browser.