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

Revision 5836, 17.6 kB (checked in by robert, 7 years ago)

Moved the implementation of GraphicsWindowX11 from the head into the src/osgViewer directory.

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