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

Revision 5838, 15.7 kB (checked in by robert, 8 years ago)

Moved rendering support into GraphisContext?, osgViewer::Viewer/View, and
added frame stamp updating and update traversal to osgViewer::Scene/Viewer.

Updated osgcamera example to use new Viewer API calls instead of using local
rendering calls.

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