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

Revision 5824, 17.4 kB (checked in by robert, 8 years ago)

Added osgViewer::Viewer / osgViewer::GraphicsWindowsX11 usage.

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