root/OpenSceneGraph/trunk/examples/osgscreencapture/osgscreencapture.cpp @ 8334

Revision 8334, 17.3 kB (checked in by robert, 6 years ago)

Changed default format to GL_BGR

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This application is open source and may be redistributed and/or modified   
4 * freely and without restriction, both in commericial and non commericial applications,
5 * as long as this copyright notice is maintained.
6 *
7 * This application is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10*/
11
12#include <osgDB/ReadFile>
13#include <osgDB/WriteFile>
14
15#include <osgUtil/Optimizer>
16#include <osg/CoordinateSystemNode>
17
18#include <osg/Switch>
19#include <osgText/Text>
20
21#include <osgViewer/Viewer>
22#include <osgViewer/ViewerEventHandlers>
23
24#include <osgGA/TrackballManipulator>
25#include <osgGA/FlightManipulator>
26#include <osgGA/DriveManipulator>
27#include <osgGA/KeySwitchMatrixManipulator>
28#include <osgGA/StateSetManipulator>
29#include <osgGA/AnimationPathManipulator>
30#include <osgGA/TerrainManipulator>
31
32#include <iostream>
33#include <sstream>
34
35class WindowCaptureCallback : public osg::Camera::DrawCallback
36{
37    public:
38   
39        enum Mode
40        {
41            READ_PIXELS,
42            SINGLE_PBO,
43            DOUBLE_PBO
44        };
45   
46        struct ContextData : public osg::Referenced
47        {
48       
49            ContextData(osg::GraphicsContext* gc, Mode mode, const std::string& name):
50                _gc(gc),
51                _mode(mode),
52                _fileName(name),
53                _pixelFormat(GL_BGR),
54                _type(GL_UNSIGNED_BYTE),
55                _width(0),
56                _height(0),
57                _currentImageIndex(0),
58                _currentPboIndex(0)
59            {
60                getSize(gc, _width, _height);
61               
62                std::cout<<"Window size "<<_width<<", "<<_height<<std::endl;
63           
64                // single buffered image
65                _imageBuffer.push_back(new osg::Image);
66               
67                // double buffer PBO.
68                switch(_mode)
69                {
70                    case(READ_PIXELS):
71                        osg::notify(osg::NOTICE)<<"Reading window usig glReadPixels, with out PixelBufferObject."<<std::endl;
72                        break;
73                    case(SINGLE_PBO):
74                        osg::notify(osg::NOTICE)<<"Reading window usig glReadPixels, with a single PixelBufferObject."<<std::endl;
75                        _pboBuffer.push_back(0);
76                        break;
77                    case(DOUBLE_PBO):
78                        osg::notify(osg::NOTICE)<<"Reading window usig glReadPixels, with a double buffer PixelBufferObject."<<std::endl;
79                        _pboBuffer.push_back(0);
80                        _pboBuffer.push_back(0);
81                        break;
82                    default:
83                        break;                               
84                }
85            }
86           
87            void getSize(osg::GraphicsContext* gc, int& width, int& height)
88            {
89                if (gc->getTraits())
90                {
91                    width = gc->getTraits()->width;
92                    height = gc->getTraits()->height;
93                }
94            }
95           
96            void read()
97            {
98                osg::BufferObject::Extensions* ext = osg::BufferObject::getExtensions(_gc->getState()->getContextID(),true);
99
100                if (ext->isPBOSupported() && !_pboBuffer.empty())
101                {
102                    if (_pboBuffer.size()==1)
103                    {
104                        singlePBO(ext);
105                    }
106                    else
107                    {
108                        multiPBO(ext);
109                    }
110                }
111                else
112                {
113                    readPixels();
114                }
115            }
116           
117            void readPixels();
118
119            void singlePBO(osg::BufferObject::Extensions* ext);
120
121            void multiPBO(osg::BufferObject::Extensions* ext);
122       
123            typedef std::vector< osg::ref_ptr<osg::Image> >             ImageBuffer;
124            typedef std::vector< GLuint > PBOBuffer;
125       
126            osg::GraphicsContext*   _gc;
127            Mode                    _mode;
128            std::string             _fileName;
129           
130            GLenum                  _pixelFormat;
131            GLenum                  _type;
132            int                     _width;
133            int                     _height;
134           
135            unsigned int            _currentImageIndex;
136            ImageBuffer             _imageBuffer;
137           
138            unsigned int            _currentPboIndex;
139            PBOBuffer               _pboBuffer;
140        };
141   
142        WindowCaptureCallback(Mode mode):
143            _mode(mode)
144        {
145        }
146
147        ContextData* createContextData(osg::GraphicsContext* gc) const
148        {
149            std::stringstream filename;
150            filename << "test_"<<_contextDataMap.size()<<".jpg";
151            return new ContextData(gc, _mode, filename.str());
152        }
153       
154        ContextData* getContextData(osg::GraphicsContext* gc) const
155        {
156            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
157            osg::ref_ptr<ContextData>& data = _contextDataMap[gc];
158            if (!data) data = createContextData(gc);
159           
160            return data.get();
161        }
162
163        virtual void operator () (osg::RenderInfo& renderInfo) const
164        {
165            osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext();
166            osg::ref_ptr<ContextData> cd = getContextData(gc);
167            cd->read();
168        }
169       
170        typedef std::map<osg::GraphicsContext*, osg::ref_ptr<ContextData> > ContextDataMap;
171
172        Mode                        _mode;       
173        mutable OpenThreads::Mutex  _mutex;
174        mutable ContextDataMap      _contextDataMap;
175       
176};
177
178void WindowCaptureCallback::ContextData::readPixels()
179{
180    // std::cout<<"readPixels("<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<<std::endl;
181
182    unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
183    unsigned int nextPboIndex = _pboBuffer.empty() ? 0 : (_currentPboIndex+1)%_pboBuffer.size();
184
185    int width=0, height=0;
186    getSize(_gc, width, height);
187    if (width!=_width || _height!=height)
188    {
189        std::cout<<"   Window resized "<<width<<", "<<height<<std::endl;
190        _width = width;
191        _height = height;
192    }
193
194    osg::Image* image = _imageBuffer[_currentImageIndex].get();
195
196#if 1
197    image->readPixels(0,0,_width,_height,
198                      _pixelFormat,_type);
199#endif
200
201    if (!_fileName.empty())
202    {
203        // osgDB::writeImageFile(*image, _fileName);
204    }
205
206    _currentImageIndex = nextImageIndex;
207    _currentPboIndex = nextPboIndex;
208}
209
210void WindowCaptureCallback::ContextData::singlePBO(osg::BufferObject::Extensions* ext)
211{
212    // std::cout<<"singelPBO(  "<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<<std::endl;
213
214    unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
215
216    int width=0, height=0;
217    getSize(_gc, width, height);
218    if (width!=_width || _height!=height)
219    {
220        std::cout<<"   Window resized "<<width<<", "<<height<<std::endl;
221        _width = width;
222        _height = height;
223    }
224
225    GLuint& pbo = _pboBuffer[0];
226   
227    osg::Image* image = _imageBuffer[_currentImageIndex].get();
228    if (image->s() != _width ||
229        image->t() != _height)
230    {
231        osg::notify(osg::NOTICE)<<"Allocating image "<<std::endl;
232        image->allocateImage(_width, _height, 1, _pixelFormat, _type);
233       
234        if (pbo!=0)
235        {
236            osg::notify(osg::NOTICE)<<"deleting pbo "<<pbo<<std::endl;
237            ext->glDeleteBuffers (1, &pbo);
238            pbo = 0;
239        }
240    }
241   
242   
243    if (pbo==0)
244    {
245        ext->glGenBuffers(1, &pbo);
246        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
247        ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
248
249        osg::notify(osg::NOTICE)<<"Generating pbo "<<pbo<<std::endl;
250    }
251    else
252    {
253        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
254    }
255
256#if 1
257    glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0);
258#endif
259
260    GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
261                                              GL_READ_ONLY_ARB);
262
263    if(src)
264    {
265        memcpy(image->data(), src, image->getTotalSizeInBytes());
266
267        ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
268    }
269
270    if (!_fileName.empty())
271    {
272        // osgDB::writeImageFile(*image, _fileName);
273    }
274
275    ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
276
277    _currentImageIndex = nextImageIndex;
278}
279
280void WindowCaptureCallback::ContextData::multiPBO(osg::BufferObject::Extensions* ext)
281{
282    // std::cout<<"multiPBO(  "<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<<std::endl;
283    unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
284    unsigned int nextPboIndex = (_currentPboIndex+1)%_pboBuffer.size();
285
286    int width=0, height=0;
287    getSize(_gc, width, height);
288    if (width!=_width || _height!=height)
289    {
290        std::cout<<"   Window resized "<<width<<", "<<height<<std::endl;
291        _width = width;
292        _height = height;
293    }
294
295    GLuint& copy_pbo = _pboBuffer[_currentPboIndex];
296    GLuint& read_pbo = _pboBuffer[nextPboIndex];
297   
298    osg::Image* image = _imageBuffer[_currentImageIndex].get();
299    if (image->s() != _width ||
300        image->t() != _height)
301    {
302        osg::notify(osg::NOTICE)<<"Allocating image "<<std::endl;
303        image->allocateImage(_width, _height, 1, _pixelFormat, _type);
304       
305        if (read_pbo!=0)
306        {
307            osg::notify(osg::NOTICE)<<"deleting pbo "<<read_pbo<<std::endl;
308            ext->glDeleteBuffers (1, &read_pbo);
309            read_pbo = 0;
310        }
311
312        if (copy_pbo!=0)
313        {
314            osg::notify(osg::NOTICE)<<"deleting pbo "<<copy_pbo<<std::endl;
315            ext->glDeleteBuffers (1, &copy_pbo);
316            copy_pbo = 0;
317        }
318    }
319   
320   
321    bool doCopy = copy_pbo!=0;
322    if (copy_pbo==0)
323    {
324        ext->glGenBuffers(1, &copy_pbo);
325        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo);
326        ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
327
328        osg::notify(osg::NOTICE)<<"Generating pbo "<<read_pbo<<std::endl;
329    }
330
331    if (read_pbo==0)
332    {
333        ext->glGenBuffers(1, &read_pbo);
334        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo);
335        ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
336
337        osg::notify(osg::NOTICE)<<"Generating pbo "<<read_pbo<<std::endl;
338    }
339    else
340    {
341        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo);
342    }
343
344#if 1
345    glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0);
346#endif
347
348    if (doCopy)
349    {
350
351        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo);
352
353        GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
354                                                  GL_READ_ONLY_ARB);
355
356        if(src)
357        {
358            memcpy(image->data(), src, image->getTotalSizeInBytes());
359
360            ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
361        }
362
363        if (!_fileName.empty())
364        {
365            // osgDB::writeImageFile(*image, _fileName);
366        }
367    }
368   
369    ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
370
371    _currentImageIndex = nextImageIndex;
372    _currentPboIndex = nextPboIndex;
373}
374
375void addCallbackToViewer(osgViewer::ViewerBase& viewer, WindowCaptureCallback* callback)
376{
377    osgViewer::ViewerBase::Windows windows;
378    viewer.getWindows(windows);
379    for(osgViewer::ViewerBase::Windows::iterator itr = windows.begin();
380        itr != windows.end();
381        ++itr)
382    {
383        osgViewer::GraphicsWindow* window = *itr;
384        osg::GraphicsContext::Cameras& cameras = window->getCameras();
385        osg::Camera* lastCamera = 0;
386        for(osg::GraphicsContext::Cameras::iterator cam_itr = cameras.begin();
387            cam_itr != cameras.end();
388            ++cam_itr)
389        {
390            if (lastCamera)
391            {
392                if ((*cam_itr)->getRenderOrder() > (*cam_itr)->getRenderOrder())
393                {
394                    lastCamera = (*cam_itr);
395                }
396                if ((*cam_itr)->getRenderOrder() == lastCamera->getRenderOrder() &&
397                    (*cam_itr)->getRenderOrderNum() >= lastCamera->getRenderOrderNum())
398                {
399                    lastCamera = (*cam_itr);
400                }
401            }
402            else
403            {
404                lastCamera = *cam_itr;
405            }
406        }
407       
408        if (lastCamera)
409        {
410            osg::notify(osg::NOTICE)<<"Last camera "<<lastCamera<<std::endl;
411           
412            lastCamera->setFinalDrawCallback(callback);
413        }
414        else
415        {
416            osg::notify(osg::NOTICE)<<"No camera found"<<std::endl;
417        }
418    }
419}
420
421int main(int argc, char** argv)
422{
423    // use an ArgumentParser object to manage the program arguments.
424    osg::ArgumentParser arguments(&argc,argv);
425
426    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
427    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
428    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
429    arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad");
430    arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField");
431
432    osgViewer::Viewer viewer(arguments);
433
434    unsigned int helpType = 0;
435    if ((helpType = arguments.readHelpType()))
436    {
437        arguments.getApplicationUsage()->write(std::cout, helpType);
438        return 1;
439    }
440   
441    // report any errors if they have occurred when parsing the program arguments.
442    if (arguments.errors())
443    {
444        arguments.writeErrorMessages(std::cout);
445        return 1;
446    }
447   
448    if (arguments.argc()<=1)
449    {
450        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
451        return 1;
452    }
453
454    // set up the camera manipulators.
455    {
456        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
457
458        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
459        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
460        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
461        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
462
463        std::string pathfile;
464        char keyForAnimationPath = '5';
465        while (arguments.read("-p",pathfile))
466        {
467            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
468            if (apm || !apm->valid())
469            {
470                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
471                keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
472                keyswitchManipulator->selectMatrixManipulator(num);
473                ++keyForAnimationPath;
474            }
475        }
476
477        viewer.setCameraManipulator( keyswitchManipulator.get() );
478    }
479
480    // add the state manipulator
481    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
482   
483    // add the thread model handler
484    viewer.addEventHandler(new osgViewer::ThreadingHandler);
485
486    // add the window size toggle handler
487    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
488       
489    // add the stats handler
490    viewer.addEventHandler(new osgViewer::StatsHandler);
491
492    // add the help handler
493    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
494
495    // add the record camera path handler
496    viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
497
498    // add the LOD Scale handler
499    viewer.addEventHandler(new osgViewer::LODScaleHandler);
500
501    WindowCaptureCallback::Mode mode = WindowCaptureCallback::DOUBLE_PBO;
502    while (arguments.read("--no-pbo")) mode = WindowCaptureCallback::READ_PIXELS;
503    while (arguments.read("--single-pbo")) mode = WindowCaptureCallback::SINGLE_PBO;
504    while (arguments.read("--double-pbo")) mode = WindowCaptureCallback::DOUBLE_PBO;
505       
506    // load the data
507    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
508    if (!loadedModel)
509    {
510        std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
511        return 1;
512    }
513
514    // any option left unread are converted into errors to write out later.
515    arguments.reportRemainingOptionsAsUnrecognized();
516
517    // report any errors if they have occurred when parsing the program arguments.
518    if (arguments.errors())
519    {
520        arguments.writeErrorMessages(std::cout);
521        return 1;
522    }
523
524
525    // optimize the scene graph, remove redundant nodes and state etc.
526    osgUtil::Optimizer optimizer;
527    optimizer.optimize(loadedModel.get());
528
529    viewer.setSceneData( loadedModel.get() );
530
531    viewer.realize();
532   
533    addCallbackToViewer(viewer, new WindowCaptureCallback(mode));
534
535    return viewer.run();
536
537}
Note: See TracBrowser for help on using the browser.