root/OpenSceneGraph/trunk/src/osgViewer/ScreenCaptureHandler.cpp @ 10600

Revision 10600, 24.8 kB (checked in by robert, 5 years ago)

Introduced new BufferObject? design + implementation in preperation of implementing a pool system for buffer objects

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2*
3* This library is open source and may be redistributed and/or modified under 
4* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5* (at your option) any later version.  The full license is in LICENSE file
6* included with this distribution, and on the openscenegraph.org website.
7*
8* This library is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11* OpenSceneGraph Public License for more details.
12*/
13
14#include <sstream>
15
16#include <osgDB/WriteFile>
17
18#include <osgViewer/Viewer>
19#include <osgViewer/ViewerEventHandlers>
20
21#include <string.h>
22
23namespace osgViewer
24{
25
26///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
27//
28//  WindowCaptureCallback
29//
30
31// From osgscreencapture example
32/** Callback which will be added to a viewer's camera to do the actual screen capture. */
33class WindowCaptureCallback : public osg::Camera::DrawCallback
34{
35    public:
36
37        enum Mode
38        {
39            READ_PIXELS,
40            SINGLE_PBO,
41            DOUBLE_PBO,
42            TRIPLE_PBO
43        };
44
45        enum FramePosition
46        {
47            START_FRAME,
48            END_FRAME
49        };
50
51        WindowCaptureCallback(Mode mode, FramePosition position, GLenum readBuffer);
52
53        FramePosition getFramePosition() const { return _position; }
54
55        void setCaptureOperation(ScreenCaptureHandler::CaptureOperation* operation);
56        ScreenCaptureHandler::CaptureOperation* getCaptureOperation() { return _contextDataMap.begin()->second->_captureOperation.get(); }
57
58        virtual void operator () (osg::RenderInfo& renderInfo) const;
59
60        struct OSGVIEWER_EXPORT ContextData : public osg::Referenced
61        {
62            static unsigned int COUNTER;
63
64            ContextData(osg::GraphicsContext* gc, Mode mode, GLenum readBuffer);
65
66            void getSize(osg::GraphicsContext* gc, int& width, int& height);
67
68            void updateTimings(osg::Timer_t tick_start,
69                               osg::Timer_t tick_afterReadPixels,
70                               osg::Timer_t tick_afterMemCpy,
71                               osg::Timer_t tick_afterCaptureOperation,
72                               unsigned int dataSize);
73
74            void read();           
75            void readPixels();
76            void singlePBO(osg::GLBufferObject::Extensions* ext);
77            void multiPBO(osg::GLBufferObject::Extensions* ext);
78
79            typedef std::vector< osg::ref_ptr<osg::Image> >             ImageBuffer;
80            typedef std::vector< GLuint > PBOBuffer;
81
82            osg::GraphicsContext*   _gc;
83            unsigned int            _index;
84            Mode                    _mode;
85            GLenum                  _readBuffer;
86
87            GLenum                  _pixelFormat;
88            GLenum                  _type;
89            int                     _width;
90            int                     _height;
91
92            unsigned int            _currentImageIndex;
93            ImageBuffer             _imageBuffer;
94
95            unsigned int            _currentPboIndex;
96            PBOBuffer               _pboBuffer;
97
98            unsigned int            _reportTimingFrequency;
99            unsigned int            _numTimeValuesRecorded;
100            double                  _timeForReadPixels;
101            double                  _timeForMemCpy;
102            double                  _timeForCaptureOperation;
103            double                  _timeForFullCopy;
104            double                  _timeForFullCopyAndOperation;
105            osg::Timer_t            _previousFrameTick;
106
107            osg::ref_ptr<ScreenCaptureHandler::CaptureOperation> _captureOperation;
108        };
109
110        typedef std::map<osg::GraphicsContext*, osg::ref_ptr<ContextData> > ContextDataMap;
111
112        ContextData* createContextData(osg::GraphicsContext* gc) const;
113        ContextData* getContextData(osg::GraphicsContext* gc) const;
114
115        Mode                        _mode;       
116        FramePosition               _position;
117        GLenum                      _readBuffer;
118        mutable OpenThreads::Mutex  _mutex;
119        mutable ContextDataMap      _contextDataMap;
120
121        osg::ref_ptr<ScreenCaptureHandler::CaptureOperation> _defaultCaptureOperation;
122};
123
124
125unsigned int WindowCaptureCallback::ContextData::COUNTER = 0;
126
127WindowCaptureCallback::ContextData::ContextData(osg::GraphicsContext* gc, Mode mode, GLenum readBuffer)
128    : _gc(gc),
129      _index(COUNTER++),
130      _mode(mode),
131      _readBuffer(readBuffer),
132      _pixelFormat(GL_RGBA),
133      _type(GL_UNSIGNED_BYTE),
134      _width(0),
135      _height(0),
136      _currentImageIndex(0),
137      _currentPboIndex(0),
138      _reportTimingFrequency(100),
139      _numTimeValuesRecorded(0),
140      _timeForReadPixels(0.0),
141      _timeForMemCpy(0.0),
142      _timeForCaptureOperation(0.0),
143      _timeForFullCopy(0.0),
144      _timeForFullCopyAndOperation(0.0),
145      _previousFrameTick(0)
146{
147    _previousFrameTick = osg::Timer::instance()->tick();
148   
149    osg::NotifySeverity level = osg::INFO;
150
151    if (gc->getTraits())
152    {
153        if (gc->getTraits()->alpha)
154        {
155            osg::notify(level)<<"ScreenCaptureHandler: Selected GL_RGBA read back format"<<std::endl;
156            _pixelFormat = GL_RGBA;
157        }
158        else 
159        {
160            osg::notify(level)<<"ScreenCaptureHandler: Selected GL_RGB read back format"<<std::endl;
161            _pixelFormat = GL_RGB;
162        }
163    }
164
165    getSize(gc, _width, _height);
166
167    //osg::notify(osg::NOTICE)<<"Window size "<<_width<<", "<<_height<<std::endl;
168
169    // single buffered image
170    _imageBuffer.push_back(new osg::Image);
171
172    // double buffer PBO.
173    switch(_mode)
174    {
175        case(READ_PIXELS):
176            osg::notify(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, without PixelBufferObject."<<std::endl;
177            break;
178        case(SINGLE_PBO):
179            osg::notify(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, with a single PixelBufferObject."<<std::endl;
180            _pboBuffer.push_back(0);
181            break;
182        case(DOUBLE_PBO):
183            osg::notify(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, with a double buffer PixelBufferObject."<<std::endl;
184            _pboBuffer.push_back(0);
185            _pboBuffer.push_back(0);
186            break;
187        case(TRIPLE_PBO):
188            osg::notify(level)<<"ScreenCaptureHandler: Reading window using glReadPixels, with a triple buffer PixelBufferObject."<<std::endl;
189            _pboBuffer.push_back(0);
190            _pboBuffer.push_back(0);
191            _pboBuffer.push_back(0);
192            break;
193        default:
194            break;                               
195    }
196}
197
198void WindowCaptureCallback::ContextData::getSize(osg::GraphicsContext* gc, int& width, int& height)
199{
200    if (gc->getTraits())
201    {
202        width = gc->getTraits()->width;
203        height = gc->getTraits()->height;
204    }
205}
206
207void WindowCaptureCallback::ContextData::updateTimings(osg::Timer_t tick_start,
208                                                       osg::Timer_t tick_afterReadPixels,
209                                                       osg::Timer_t tick_afterMemCpy,
210                                                       osg::Timer_t tick_afterCaptureOperation,
211                                                       unsigned int dataSize)
212{
213    _timeForReadPixels = osg::Timer::instance()->delta_s(tick_start, tick_afterReadPixels);
214    _timeForMemCpy = osg::Timer::instance()->delta_s(tick_afterReadPixels, tick_afterMemCpy);
215    _timeForCaptureOperation = osg::Timer::instance()->delta_s(tick_afterMemCpy, tick_afterCaptureOperation);
216
217    _timeForFullCopy = osg::Timer::instance()->delta_s(tick_start, tick_afterMemCpy);
218    _timeForFullCopyAndOperation = osg::Timer::instance()->delta_s(tick_start, tick_afterCaptureOperation);
219}
220
221void WindowCaptureCallback::ContextData::read()
222{
223    osg::GLBufferObject::Extensions* ext = osg::GLBufferObject::getExtensions(_gc->getState()->getContextID(),true);
224
225    if (ext->isPBOSupported() && !_pboBuffer.empty())
226    {
227        if (_pboBuffer.size()==1)
228        {
229            singlePBO(ext);
230        }
231        else
232        {
233            multiPBO(ext);
234        }
235    }
236    else
237    {
238        readPixels();
239    }
240}
241
242
243void WindowCaptureCallback::ContextData::readPixels()
244{
245    unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
246    unsigned int nextPboIndex = _pboBuffer.empty() ? 0 : (_currentPboIndex+1)%_pboBuffer.size();
247
248    int width=0, height=0;
249    getSize(_gc, width, height);
250    if (width!=_width || _height!=height)
251    {
252        //osg::notify(osg::NOTICE)<<"   Window resized "<<width<<", "<<height<<std::endl;
253        _width = width;
254        _height = height;
255    }
256
257    osg::Image* image = _imageBuffer[_currentImageIndex].get();
258
259    osg::Timer_t tick_start = osg::Timer::instance()->tick();
260
261#if 1
262    image->readPixels(0,0,_width,_height,
263                      _pixelFormat,_type);
264#endif
265
266    osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick();
267
268    if (_captureOperation.valid())
269    {
270        (*_captureOperation)(*image, _index);
271    }
272
273    osg::Timer_t tick_afterCaptureOperation = osg::Timer::instance()->tick();
274    updateTimings(tick_start, tick_afterReadPixels, tick_afterReadPixels, tick_afterCaptureOperation, image->getTotalSizeInBytes());
275
276    _currentImageIndex = nextImageIndex;
277    _currentPboIndex = nextPboIndex;
278}
279
280void WindowCaptureCallback::ContextData::singlePBO(osg::GLBufferObject::Extensions* ext)
281{
282    unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
283
284    int width=0, height=0;
285    getSize(_gc, width, height);
286    if (width!=_width || _height!=height)
287    {
288        //osg::notify(osg::NOTICE)<<"   Window resized "<<width<<", "<<height<<std::endl;
289        _width = width;
290        _height = height;
291    }
292
293    GLuint& pbo = _pboBuffer[0];
294   
295    osg::Image* image = _imageBuffer[_currentImageIndex].get();
296    if (image->s() != _width ||
297        image->t() != _height)
298    {
299        //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Allocating image "<<std::endl;
300        image->allocateImage(_width, _height, 1, _pixelFormat, _type);
301       
302        if (pbo!=0)
303        {
304            //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: deleting pbo "<<pbo<<std::endl;
305            ext->glDeleteBuffers (1, &pbo);
306            pbo = 0;
307        }
308    }
309   
310   
311    if (pbo==0)
312    {
313        ext->glGenBuffers(1, &pbo);
314        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
315        ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
316
317        //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Generating pbo "<<pbo<<std::endl;
318    }
319    else
320    {
321        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
322    }
323
324    osg::Timer_t tick_start = osg::Timer::instance()->tick();
325
326#if 1
327    glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0);
328#endif
329
330    osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick();
331
332    GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
333                                              GL_READ_ONLY_ARB);
334    if(src)
335    {
336        memcpy(image->data(), src, image->getTotalSizeInBytes());
337        ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
338    }
339
340    ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
341
342    osg::Timer_t tick_afterMemCpy = osg::Timer::instance()->tick();
343
344    if (_captureOperation.valid())
345    {
346        (*_captureOperation)(*image, _index);
347    }
348
349    osg::Timer_t tick_afterCaptureOperation = osg::Timer::instance()->tick();
350    updateTimings(tick_start, tick_afterReadPixels, tick_afterMemCpy, tick_afterCaptureOperation, image->getTotalSizeInBytes());
351
352    _currentImageIndex = nextImageIndex;
353}
354
355void WindowCaptureCallback::ContextData::multiPBO(osg::GLBufferObject::Extensions* ext)
356{
357    unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
358    unsigned int nextPboIndex = (_currentPboIndex+1)%_pboBuffer.size();
359
360    int width=0, height=0;
361    getSize(_gc, width, height);
362    if (width!=_width || _height!=height)
363    {
364        //osg::notify(osg::NOTICE)<<"   Window resized "<<width<<", "<<height<<std::endl;
365        _width = width;
366        _height = height;
367    }
368
369    GLuint& copy_pbo = _pboBuffer[_currentPboIndex];
370    GLuint& read_pbo = _pboBuffer[nextPboIndex];
371   
372    osg::Image* image = _imageBuffer[_currentImageIndex].get();
373    if (image->s() != _width ||
374        image->t() != _height)
375    {
376        //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Allocating image "<<std::endl;
377        image->allocateImage(_width, _height, 1, _pixelFormat, _type);
378       
379        if (read_pbo!=0)
380        {
381            //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: deleting pbo "<<read_pbo<<std::endl;
382            ext->glDeleteBuffers (1, &read_pbo);
383            read_pbo = 0;
384        }
385
386        if (copy_pbo!=0)
387        {
388            //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: deleting pbo "<<copy_pbo<<std::endl;
389            ext->glDeleteBuffers (1, &copy_pbo);
390            copy_pbo = 0;
391        }
392    }
393   
394   
395    bool doCopy = copy_pbo!=0;
396    if (copy_pbo==0)
397    {
398        ext->glGenBuffers(1, &copy_pbo);
399        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo);
400        ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
401
402        //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Generating pbo "<<read_pbo<<std::endl;
403    }
404
405    if (read_pbo==0)
406    {
407        ext->glGenBuffers(1, &read_pbo);
408        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo);
409        ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
410
411        //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Generating pbo "<<read_pbo<<std::endl;
412    }
413    else
414    {
415        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo);
416    }
417
418    osg::Timer_t tick_start = osg::Timer::instance()->tick();
419
420#if 1
421    glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0);
422#endif
423
424    osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick();
425
426    if (doCopy)
427    {
428
429        ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo);
430
431        GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
432                                                  GL_READ_ONLY_ARB);
433        if(src)
434        {
435            memcpy(image->data(), src, image->getTotalSizeInBytes());
436            ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
437        }
438
439        if (_captureOperation.valid())
440        {
441            (*_captureOperation)(*image, _index);
442        }
443    }
444   
445    ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
446
447    osg::Timer_t tick_afterMemCpy = osg::Timer::instance()->tick();
448   
449    updateTimings(tick_start, tick_afterReadPixels, tick_afterMemCpy, tick_afterMemCpy, image->getTotalSizeInBytes());
450
451    _currentImageIndex = nextImageIndex;
452    _currentPboIndex = nextPboIndex;
453}
454
455
456WindowCaptureCallback::WindowCaptureCallback(Mode mode, FramePosition position, GLenum readBuffer)
457    : _mode(mode),
458      _position(position),
459      _readBuffer(readBuffer)
460{
461}
462
463WindowCaptureCallback::ContextData* WindowCaptureCallback::createContextData(osg::GraphicsContext* gc) const
464{
465    WindowCaptureCallback::ContextData* cd = new WindowCaptureCallback::ContextData(gc, _mode, _readBuffer);
466    cd->_captureOperation = _defaultCaptureOperation;
467    return cd;
468}
469
470WindowCaptureCallback::ContextData* WindowCaptureCallback::getContextData(osg::GraphicsContext* gc) const
471{
472    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
473    osg::ref_ptr<ContextData>& data = _contextDataMap[gc];
474    if (!data) data = createContextData(gc);
475   
476    return data.get();
477}
478
479void WindowCaptureCallback::setCaptureOperation(ScreenCaptureHandler::CaptureOperation* operation)
480{
481    _defaultCaptureOperation = operation;
482
483    // Set the capture operation for each ContextData.
484    for (ContextDataMap::iterator it = _contextDataMap.begin(); it != _contextDataMap.end(); ++it)
485    {
486        it->second->_captureOperation = operation;
487    }
488}
489
490
491void WindowCaptureCallback::operator () (osg::RenderInfo& renderInfo) const
492{
493    glReadBuffer(_readBuffer);
494
495    osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext();
496    osg::ref_ptr<ContextData> cd = getContextData(gc);
497    cd->read();
498
499    // Since we just want to take one screenshot, the callback must remove
500    // itself when it's done.
501    if (_position == START_FRAME)
502        renderInfo.getCurrentCamera()->setInitialDrawCallback(0);
503    if (_position == END_FRAME)
504        renderInfo.getCurrentCamera()->setFinalDrawCallback(0);
505
506    int prec = osg::notify(osg::INFO).precision(5);
507    osg::notify(osg::INFO) << "ScreenCaptureHandler: "
508                           << "copy="      << (cd->_timeForFullCopy*1000.0f)             << "ms, "
509                           << "operation=" << (cd->_timeForCaptureOperation*1000.0f)     << "ms, "
510                           << "total="     << (cd->_timeForFullCopyAndOperation*1000.0f) << std::endl;
511    osg::notify(osg::INFO).precision(prec);
512
513    cd->_timeForFullCopy = 0;
514}
515
516
517
518///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
519//
520//  ScreenCaptureHandler::WriteToFile
521//
522ScreenCaptureHandler::WriteToFile::WriteToFile(const std::string& filename,
523                                                         const std::string& extension,
524                                                         SavePolicy savePolicy)
525    : _filename(filename), _extension(extension), _savePolicy(savePolicy)
526{
527}
528
529void ScreenCaptureHandler::WriteToFile::operator () (const osg::Image& image, const unsigned int context_id)
530{
531    if (_savePolicy == SEQUENTIAL_NUMBER)
532    {
533        if (_contextSaveCounter.size() <= context_id)
534        {
535            _contextSaveCounter.resize(context_id + 1);
536            _contextSaveCounter[context_id] = 0;
537        }
538    }
539
540    std::stringstream filename;
541    filename << _filename << "_" << context_id;
542
543    if (_savePolicy == SEQUENTIAL_NUMBER)
544        filename << "_" << _contextSaveCounter[context_id];
545
546    filename << "." << _extension;
547
548    osgDB::writeImageFile(image, filename.str());
549
550    osg::notify(osg::INFO)<<"ScreenCaptureHandler: Taking a screenshot, saved as '"<<filename.str()<<"'"<<std::endl;
551
552    if (_savePolicy == SEQUENTIAL_NUMBER)
553    {
554        _contextSaveCounter[context_id]++;
555    }
556}
557
558
559///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
560//
561//  ScreenCaptureHandler
562//
563ScreenCaptureHandler::ScreenCaptureHandler(CaptureOperation* defaultOperation)
564    : _keyEventTakeScreenShot('c'),
565      _callback(new WindowCaptureCallback(
566                                          WindowCaptureCallback::READ_PIXELS,
567//                                          WindowCaptureCallback::SINGLE_PBO,
568//                                          WindowCaptureCallback::DOUBLE_PBO,
569//                                          WindowCaptureCallback::TRIPLE_PBO,
570                                          WindowCaptureCallback::END_FRAME, GL_BACK))
571{
572    if (defaultOperation)
573        setCaptureOperation(defaultOperation);
574    else
575        setCaptureOperation(new WriteToFile("screen_shot", "jpg"));
576}
577
578void ScreenCaptureHandler::setCaptureOperation(CaptureOperation* operation)
579{
580    static_cast<WindowCaptureCallback*>(_callback.get())->setCaptureOperation(operation);
581}
582
583ScreenCaptureHandler::CaptureOperation* ScreenCaptureHandler::getCaptureOperation() const
584{
585    return static_cast<WindowCaptureCallback*>(_callback.get())->getCaptureOperation();
586}
587
588
589void ScreenCaptureHandler::addCallbackToViewer(osgViewer::ViewerBase& viewer)
590{
591    // Select either the first or the last active camera, depending on the
592    // frame position set in the callback.
593    // One case where testing the node mask is important is when the stats
594    // handler has been initialized, but stats are not displayed. In that
595    // case, there is a post render camera on the viewer, but its node mask
596    // is zero, so the callback added to that camera would never be called.
597    WindowCaptureCallback* callback = static_cast<WindowCaptureCallback*>(_callback.get());
598
599    if (callback->getFramePosition() == WindowCaptureCallback::START_FRAME)
600    {
601        osgViewer::ViewerBase::Windows windows;
602        viewer.getWindows(windows);
603        for(osgViewer::ViewerBase::Windows::iterator itr = windows.begin();
604            itr != windows.end();
605            ++itr)
606        {
607            osgViewer::GraphicsWindow* window = *itr;
608            osg::GraphicsContext::Cameras& cameras = window->getCameras();
609            osg::Camera* firstCamera = 0;
610            for(osg::GraphicsContext::Cameras::iterator cam_itr = cameras.begin();
611                cam_itr != cameras.end();
612                ++cam_itr)
613            {
614                if (firstCamera)
615                {
616                    if ((*cam_itr)->getRenderOrder() < firstCamera->getRenderOrder())
617                    {
618                        if ((*cam_itr)->getNodeMask() != 0x0)
619                            firstCamera = (*cam_itr);
620                    }
621                    if ((*cam_itr)->getRenderOrder() == firstCamera->getRenderOrder() &&
622                        (*cam_itr)->getRenderOrderNum() < firstCamera->getRenderOrderNum())
623                    {
624                        if ((*cam_itr)->getNodeMask() != 0x0)
625                            firstCamera = (*cam_itr);
626                    }
627                }
628                else
629                {
630                    if ((*cam_itr)->getNodeMask() != 0x0)
631                        firstCamera = *cam_itr;
632                }
633            }
634
635            if (firstCamera)
636            {
637                //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: First camera "<<firstCamera<<std::endl;
638
639                firstCamera->setInitialDrawCallback(_callback.get());
640            }
641            else
642            {
643                osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: No camera found"<<std::endl;
644            }
645        }
646    }
647    else
648    {   
649        osgViewer::ViewerBase::Windows windows;
650        viewer.getWindows(windows);
651        for(osgViewer::ViewerBase::Windows::iterator itr = windows.begin();
652            itr != windows.end();
653            ++itr)
654        {
655            osgViewer::GraphicsWindow* window = *itr;
656            osg::GraphicsContext::Cameras& cameras = window->getCameras();
657            osg::Camera* lastCamera = 0;
658            for(osg::GraphicsContext::Cameras::iterator cam_itr = cameras.begin();
659                cam_itr != cameras.end();
660                ++cam_itr)
661            {
662                if (lastCamera)
663                {
664                    if ((*cam_itr)->getRenderOrder() > lastCamera->getRenderOrder())
665                    {
666                        if ((*cam_itr)->getNodeMask() != 0x0)
667                            lastCamera = (*cam_itr);
668                    }
669                    if ((*cam_itr)->getRenderOrder() == lastCamera->getRenderOrder() &&
670                        (*cam_itr)->getRenderOrderNum() >= lastCamera->getRenderOrderNum())
671                    {
672                        if ((*cam_itr)->getNodeMask() != 0x0)
673                            lastCamera = (*cam_itr);
674                    }
675                }
676                else
677                {
678                    if ((*cam_itr)->getNodeMask() != 0x0)
679                        lastCamera = *cam_itr;
680                }
681            }
682
683            if (lastCamera)
684            {
685                //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Last camera "<<lastCamera<<std::endl;
686
687                lastCamera->setFinalDrawCallback(_callback.get());
688            }
689            else
690            {
691                osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: No camera found"<<std::endl;
692            }
693        }
694    }
695}
696
697// aa will point to an osgViewer::View, so we will take a screenshot
698// of that view's graphics contexts.
699bool ScreenCaptureHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
700{
701    osgViewer::ViewerBase* viewer = dynamic_cast<osgViewer::View*>(&aa)->getViewerBase();
702    if (!viewer) return false;
703
704    if (ea.getHandled()) return false;
705
706    switch(ea.getEventType())
707    {
708        case(osgGA::GUIEventAdapter::KEYUP):
709        {
710            if (ea.getKey() == _keyEventTakeScreenShot)
711            {
712                addCallbackToViewer(*viewer);
713                return true;
714            }
715
716            break;
717        }
718    default:
719        break;
720    }
721
722    return false;
723}
724
725/** Capture the given viewer's views on the next frame. */
726void ScreenCaptureHandler::captureNextFrame(osgViewer::ViewerBase& viewer)
727{
728    addCallbackToViewer(viewer);
729}
730
731/** Get the keyboard and mouse usage of this manipulator.*/
732void ScreenCaptureHandler::getUsage(osg::ApplicationUsage& usage) const
733{
734    {
735        std::ostringstream ostr;
736        ostr<<char(_keyEventTakeScreenShot);
737        usage.addKeyboardMouseBinding(ostr.str(),"Take screenshot.");
738    }
739}
740
741
742}
Note: See TracBrowser for help on using the browser.