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

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

From Jean-Sebastein Guay, I recently had to reimplement screen capture functionality into our framework (which was broken since the switch from OSG 1.2 to 2.2 over a year and a half ago). I used the ScreenCaptureHandler? which I had contributed right before OSG 2.6 shipped, bit I had to trigger the screen capture programatically instead of by a key press in some cases, so I added a convenience method to do that.

It's a minimal change, it just calls an already existing protected method. It was trivial to subclass the handler to do it in our code, but pushing the change into OSG makes sense as it's generally useful to have it in the handler itself.

I also noticed that the handle() method was overridden from osgGA::GUIEventHandler but wasn't marked virtual. It wasn't intended that subclasses not be able to override it in turn, so I've added the keyword.""

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::BufferObject::Extensions* ext);
77            void multiPBO(osg::BufferObject::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::BufferObject::Extensions* ext = osg::BufferObject::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::BufferObject::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::BufferObject::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.