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

Revision 4494, 13.0 kB (checked in by robert, 9 years ago)

Added commandline arguments for controlling number of cameras through to the windowing library to use.

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