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

Revision 5822, 14.2 kB (checked in by robert, 8 years ago)

Added support WindowingSystemInterface? for querring the number of screens, the screen size and creating GraphicsContexts?.

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