Thank J-S, changes merged and submitted to SVN.
On Fri, Dec 19, 2008 at 4:08 PM, Jean-Sébastien Guay <[email protected]> wrote: > Hi Robert, > > 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. > > Please find the changed files attached. Thanks, > > J-S > -- > ______________________________________________________ > Jean-Sebastien Guay [email protected] > http://www.cm-labs.com/ > http://whitestar02.webhop.org/ > > /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield > * > * This library is open source and may be redistributed and/or modified under > * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or > * (at your option) any later version. The full license is in LICENSE file > * included with this distribution, and on the openscenegraph.org website. > * > * This library is distributed in the hope that it will be useful, > * but WITHOUT ANY WARRANTY; without even the implied warranty of > * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > * OpenSceneGraph Public License for more details. > */ > > #ifndef OSGVIEWER_VIEWEREVENTHANDLERS > #define OSGVIEWER_VIEWEREVENTHANDLERS 1 > > #include <osg/AnimationPath> > #include <osgText/Text> > #include <osgGA/GUIEventHandler> > #include <osgGA/AnimationPathManipulator> > > #include <osgViewer/GraphicsWindow> > #include <osgViewer/Viewer> > > #include <osgDB/fstream> > > namespace osgViewer { > > /** Event handler for adding on screen help to Viewers.*/ > class OSGVIEWER_EXPORT HelpHandler : public osgGA::GUIEventHandler > { > public: > > HelpHandler(osg::ApplicationUsage* au=0); > > void setApplicationUsage(osg::ApplicationUsage* au) { > _applicationUsage = au; } > osg::ApplicationUsage* getApplicationUsage() { return > _applicationUsage.get(); } > const osg::ApplicationUsage* getApplicationUsage() const { return > _applicationUsage.get(); } > > void setKeyEventTogglesOnScreenHelp(int key) { > _keyEventTogglesOnScreenHelp = key; } > int getKeyEventTogglesOnScreenHelp() const { return > _keyEventTogglesOnScreenHelp; } > > void reset(); > > osg::Camera* getCamera() { return _camera.get(); } > const osg::Camera* getCamera() const { return _camera.get(); } > > bool handle(const osgGA::GUIEventAdapter& ea, > osgGA::GUIActionAdapter& aa); > > /** Get the keyboard and mouse usage of this manipulator.*/ > virtual void getUsage(osg::ApplicationUsage& usage) const; > > protected: > > void setUpHUDCamera(osgViewer::ViewerBase* viewer); > > void setUpScene(osgViewer::ViewerBase* viewer); > > osg::ref_ptr<osg::ApplicationUsage> _applicationUsage; > > int _keyEventTogglesOnScreenHelp; > > bool _helpEnabled; > > bool _initialized; > osg::ref_ptr<osg::Camera> _camera; > osg::ref_ptr<osg::Switch> _switch; > > }; > > /** Event handler for adding on screen stats reporting to Viewers.*/ > class OSGVIEWER_EXPORT StatsHandler : public osgGA::GUIEventHandler > { > public: > > StatsHandler(); > > enum StatsType > { > NO_STATS = 0, > FRAME_RATE = 1, > VIEWER_STATS = 2, > CAMERA_SCENE_STATS = 3, > VIEWER_SCENE_STATS = 4, > LAST = 5 > }; > > void setKeyEventTogglesOnScreenStats(int key) { > _keyEventTogglesOnScreenStats = key; } > int getKeyEventTogglesOnScreenStats() const { return > _keyEventTogglesOnScreenStats; } > > void setKeyEventPrintsOutStats(int key) { _keyEventPrintsOutStats = > key; } > int getKeyEventPrintsOutStats() const { return > _keyEventPrintsOutStats; } > > double getBlockMultiplier() const { return _blockMultiplier; } > > void reset(); > > osg::Camera* getCamera() { return _camera.get(); } > const osg::Camera* getCamera() const { return _camera.get(); } > > virtual bool handle(const osgGA::GUIEventAdapter& ea, > osgGA::GUIActionAdapter& aa); > > /** Get the keyboard and mouse usage of this manipulator.*/ > virtual void getUsage(osg::ApplicationUsage& usage) const; > > protected: > > void setUpHUDCamera(osgViewer::ViewerBase* viewer); > > osg::Geometry* createBackgroundRectangle(const osg::Vec3& pos, const > float width, const float height, osg::Vec4& color); > > osg::Geometry* createGeometry(const osg::Vec3& pos, float height, > const osg::Vec4& colour, unsigned int numBlocks); > > osg::Geometry* createFrameMarkers(const osg::Vec3& pos, float height, > const osg::Vec4& colour, unsigned int numBlocks); > > osg::Geometry* createTick(const osg::Vec3& pos, float height, const > osg::Vec4& colour, unsigned int numTicks); > > osg::Node* createCameraTimeStats(const std::string& font, osg::Vec3& > pos, float startBlocks, bool acquireGPUStats, float characterSize, > osg::Stats* viewerStats, osg::Camera* camera); > > void setUpScene(osgViewer::ViewerBase* viewer); > > void updateThreadingModelText(); > > int _keyEventTogglesOnScreenStats; > int _keyEventPrintsOutStats; > > int _statsType; > > bool _initialized; > osg::ref_ptr<osg::Camera> _camera; > > osg::ref_ptr<osg::Switch> _switch; > > ViewerBase::ThreadingModel _threadingModel; > osg::ref_ptr<osgText::Text> _threadingModelText; > > unsigned int _frameRateChildNum; > unsigned int _viewerChildNum; > unsigned int _cameraSceneChildNum; > unsigned int _viewerSceneChildNum; > unsigned int _numBlocks; > double _blockMultiplier; > > > }; > > /** Event handler allowing to change the screen resolution (in windowed > mode) and toggle between fullscreen and windowed mode. */ > class OSGVIEWER_EXPORT WindowSizeHandler : public osgGA::GUIEventHandler > { > public: > > WindowSizeHandler(); > > /** Get the keyboard and mouse usage of this manipulator.*/ > virtual void getUsage(osg::ApplicationUsage &usage) const; > > void setKeyEventToggleFullscreen(int key) { _keyEventToggleFullscreen > = key; } > int getKeyEventToggleFullscreen() const { return > _keyEventToggleFullscreen; } > > void setToggleFullscreen(bool flag) { _toggleFullscreen = flag; } > bool getToggleFullscreen() const { return _toggleFullscreen; } > > void setKeyEventWindowedResolutionUp(int key) { > _keyEventWindowedResolutionUp = key; } > int getKeyEventWindowedResolutionUp() const { return > _keyEventWindowedResolutionUp; } > void setKeyEventWindowedResolutionDown(int key) { > _keyEventWindowedResolutionDown = key; } > int getKeyEventWindowedResolutionDown() const { return > _keyEventWindowedResolutionUp; } > > void setChangeWindowedResolution(bool flag) { > _changeWindowedResolution = flag; } > bool getChangeWindowedResolution() const { return > _changeWindowedResolution; } > > virtual bool handle(const osgGA::GUIEventAdapter &ea, > osgGA::GUIActionAdapter &aa); > > protected: > > void toggleFullscreen(osgViewer::GraphicsWindow *window); > void changeWindowedResolution(osgViewer::GraphicsWindow *window, bool > increase); > > unsigned int getNearestResolution(int screenWidth, int screenHeight, > int width, int height) const; > > int _keyEventToggleFullscreen; > bool _toggleFullscreen; > > int _keyEventWindowedResolutionUp; > int _keyEventWindowedResolutionDown; > bool _changeWindowedResolution; > std::vector<osg::Vec2> _resolutionList; > int _currentResolutionIndex; > }; > > /** Event handler allowing to change the viewer threading model */ > class OSGVIEWER_EXPORT ThreadingHandler : public osgGA::GUIEventHandler > { > public: > > ThreadingHandler(); > > /** Get the keyboard and mouse usage of this manipulator.*/ > virtual void getUsage(osg::ApplicationUsage &usage) const; > > void setKeyEventChangeThreadingModel(int key) { > _keyEventChangeThreadingModel = key; } > int getKeyEventChangeThreadingModel() const { return > _keyEventChangeThreadingModel; } > > void setChangeThreadingModel(bool flag) { _changeThreadingModel = > flag; } > bool getChangeThreadingModel() const { return _changeThreadingModel; > } > > void setKeyEventChangeEndBarrierPosition(int key) { > _keyEventChangeEndBarrierPosition = key; } > int getKeyEventChangeEndBarrierPosition() const { return > _keyEventChangeEndBarrierPosition; } > > void setChangeEndBarrierPosition(bool flag) { > _changeEndBarrierPosition = flag; } > bool getChangeEndBarrierPosition() const { return > _changeEndBarrierPosition; } > > bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter > &aa); > > protected: > > int _keyEventChangeThreadingModel; > bool _changeThreadingModel; > > int _keyEventChangeEndBarrierPosition; > bool _changeEndBarrierPosition; > > osg::Timer_t _tickOrLastKeyPress; > bool _done; > }; > > /** > * Event handler allowing the user to record the animation "path" of a > camera. In it's current > * implementation, this handler cannot guarantee the final view matrix is > correct; it is > * conceivable that the matrix may be one frame off. Eh--not a big deal! :) > * TODO: Write the file as we go, not when it's all done. > * TODO: Create an osgviewer on-screen indication that animation is taking > place. > */ > class OSGVIEWER_EXPORT RecordCameraPathHandler : public > osgGA::GUIEventHandler > { > public: > > RecordCameraPathHandler(const std::string &filename = > "saved_animation.path", float fps = 25.0f); > > void setKeyEventToggleRecord(int key) { _keyEventToggleRecord = key; > } > int getKeyEventToggleRecord() const { return _keyEventToggleRecord; } > > void setKeyEventTogglePlayback(int key) { _keyEventTogglePlayback = > key; } > int getKeyEventTogglePlayback() const { return > _keyEventTogglePlayback; } > > void setAutoIncrementFilename( bool autoinc = true ) { _autoinc = > autoinc?0:-1; } > > virtual void getUsage(osg::ApplicationUsage &usage) const; > > bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter > &aa); > > protected: > > std::string _filename; > int _autoinc; > osgDB::ofstream _fout; > > int > _keyEventToggleRecord; > int > _keyEventTogglePlayback; > > > bool _currentlyRecording; > bool _currentlyPlaying; > double _interval; > double _delta; > osg::Timer_t _animStartTime; > osg::Timer_t _lastFrameTime; > osg::ref_ptr<osg::AnimationPath> _animPath; > osg::ref_ptr<osgGA::AnimationPathManipulator> _animPathManipulator; > osg::ref_ptr<osgGA::MatrixManipulator> _oldManipulator; > }; > > /** Event handler for increase/decreasing LODScale.*/ > class OSGVIEWER_EXPORT LODScaleHandler : public osgGA::GUIEventHandler > { > public: > > LODScaleHandler(); > > void setKeyEventIncreaseLODScale(int key) { _keyEventIncreaseLODScale > = key; } > int getKeyEventIncreaseLODScale() const { return > _keyEventIncreaseLODScale; } > > void setKeyEventDecreaseLODScale(int key) { _keyEventDecreaseLODScale > = key; } > int getKeyEventDecreaseLODScale() const { return > _keyEventDecreaseLODScale; } > > bool handle(const osgGA::GUIEventAdapter& ea, > osgGA::GUIActionAdapter& aa); > > /** Get the keyboard and mouse usage of this manipulator.*/ > virtual void getUsage(osg::ApplicationUsage& usage) const; > > protected: > > > int _keyEventIncreaseLODScale; > int _keyEventDecreaseLODScale; > > > }; > > > /** Event handler that will capture the screen on key press. */ > class OSGVIEWER_EXPORT ScreenCaptureHandler : public osgGA::GUIEventHandler > { > public: > > /** Abstract base class for what to do when a screen capture happens. > */ > class CaptureOperation : public osg::Referenced > { > public: > virtual void operator()(const osg::Image& image, const > unsigned int context_id) = 0; > }; > > /** Concrete implementation of a CaptureOperation that writes the > screen capture to a file. */ > class OSGVIEWER_EXPORT WriteToFile : public CaptureOperation > { > public: > enum SavePolicy > { > OVERWRITE, > SEQUENTIAL_NUMBER > // ... any others? > }; > > WriteToFile(const std::string& filename, const std::string& > extension, SavePolicy savePolicy = OVERWRITE); > > virtual void operator()(const osg::Image& image, const > unsigned int context_id); > > void setSavePolicy(SavePolicy savePolicy) { _savePolicy = > savePolicy; } > SavePolicy getSavePolicy() const { return _savePolicy; } > > protected: > const std::string _filename; > const std::string _extension; > > SavePolicy _savePolicy; > > std::vector<unsigned int> _contextSaveCounter; > }; > > > ScreenCaptureHandler(CaptureOperation* defaultOperation = 0); > > void setKeyEventTakeScreenShot(int key) { _keyEventTakeScreenShot = > key; } > int getKeyEventTakeScreenShot() const { return > _keyEventTakeScreenShot; } > > void setCaptureOperation(CaptureOperation* operation); > CaptureOperation* getCaptureOperation() const; > > // aa will point to an osgViewer::View, so we will take a screenshot > // of that view's graphics contexts. > virtual bool handle(const osgGA::GUIEventAdapter& ea, > osgGA::GUIActionAdapter& aa); > > /** Capture the given viewer's views on the next frame. */ > virtual void captureNextFrame(osgViewer::ViewerBase& viewer); > > /** Get the keyboard and mouse usage of this manipulator.*/ > virtual void getUsage(osg::ApplicationUsage& usage) const; > > protected: > int _keyEventTakeScreenShot; > // there could be a key to start taking screenshots every new frame > > osg::ref_ptr<CaptureOperation> _operation; > osg::ref_ptr<osg::Camera::DrawCallback> _callback; > > void addCallbackToViewer(osgViewer::ViewerBase& viewer); > }; > > /** InteractiveImage is an event handler that computes the mouse coordinates > in an images coordinate frame > * and then passes keyboard and mouse events to it. This event handler is > useful for vnc or browser > * surfaces in the 3D scene.*/ > class OSGVIEWER_EXPORT InteractiveImageHandler : public > osgGA::GUIEventHandler, public osg::Drawable::CullCallback > { > public: > > InteractiveImageHandler(osg::Image* image): > _image(image) {} > > META_Object(osgViewer, InteractiveImageHandler); > > virtual bool handle(const osgGA::GUIEventAdapter& > ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv); > > virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drawable, > osg::RenderInfo* renderInfo) const; > > protected: > > virtual ~InteractiveImageHandler() {} > > InteractiveImageHandler() {} > > InteractiveImageHandler(const InteractiveImageHandler& rhs,const > osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) {} > > bool mousePosition(osgViewer::View* view, osg::NodeVisitor* nv, const > osgGA::GUIEventAdapter& ea, int& x, int &y) const; > > osg::observer_ptr<osg::Image> _image; > bool _handleKeyboardEvents; > bool _handledOnKeyboardEvents; > bool _handleMouseEvents; > bool _handledOnMouseEvents; > > }; > > } > > #endif > > /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield > * > * This library is open source and may be redistributed and/or modified under > * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or > * (at your option) any later version. The full license is in LICENSE file > * included with this distribution, and on the openscenegraph.org website. > * > * This library is distributed in the hope that it will be useful, > * but WITHOUT ANY WARRANTY; without even the implied warranty of > * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > * OpenSceneGraph Public License for more details. > */ > > #include <sstream> > > #include <osgDB/WriteFile> > > #include <osgViewer/Viewer> > #include <osgViewer/ViewerEventHandlers> > > #include <string.h> > > namespace osgViewer > { > > /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// > // > // WindowCaptureCallback > // > > // From osgscreencapture example > /** Callback which will be added to a viewer's camera to do the actual > screen capture. */ > class WindowCaptureCallback : public osg::Camera::DrawCallback > { > public: > > enum Mode > { > READ_PIXELS, > SINGLE_PBO, > DOUBLE_PBO, > TRIPLE_PBO > }; > > enum FramePosition > { > START_FRAME, > END_FRAME > }; > > WindowCaptureCallback(Mode mode, FramePosition position, GLenum > readBuffer); > > FramePosition getFramePosition() const { return _position; } > > void setCaptureOperation(ScreenCaptureHandler::CaptureOperation* > operation); > ScreenCaptureHandler::CaptureOperation* getCaptureOperation() { > return _contextDataMap.begin()->second->_captureOperation.get(); } > > virtual void operator () (osg::RenderInfo& renderInfo) const; > > struct OSGVIEWER_EXPORT ContextData : public osg::Referenced > { > static unsigned int COUNTER; > > ContextData(osg::GraphicsContext* gc, Mode mode, GLenum > readBuffer); > > void getSize(osg::GraphicsContext* gc, int& width, int& height); > > void updateTimings(osg::Timer_t tick_start, > osg::Timer_t tick_afterReadPixels, > osg::Timer_t tick_afterMemCpy, > osg::Timer_t tick_afterCaptureOperation, > unsigned int dataSize); > > void read(); > void readPixels(); > void singlePBO(osg::BufferObject::Extensions* ext); > void multiPBO(osg::BufferObject::Extensions* ext); > > typedef std::vector< osg::ref_ptr<osg::Image> > > ImageBuffer; > typedef std::vector< GLuint > PBOBuffer; > > osg::GraphicsContext* _gc; > unsigned int _index; > Mode _mode; > GLenum _readBuffer; > > GLenum _pixelFormat; > GLenum _type; > int _width; > int _height; > > unsigned int _currentImageIndex; > ImageBuffer _imageBuffer; > > unsigned int _currentPboIndex; > PBOBuffer _pboBuffer; > > unsigned int _reportTimingFrequency; > unsigned int _numTimeValuesRecorded; > double _timeForReadPixels; > double _timeForMemCpy; > double _timeForCaptureOperation; > double _timeForFullCopy; > double _timeForFullCopyAndOperation; > osg::Timer_t _previousFrameTick; > > osg::ref_ptr<ScreenCaptureHandler::CaptureOperation> > _captureOperation; > }; > > typedef std::map<osg::GraphicsContext*, osg::ref_ptr<ContextData> > > ContextDataMap; > > ContextData* createContextData(osg::GraphicsContext* gc) const; > ContextData* getContextData(osg::GraphicsContext* gc) const; > > Mode _mode; > FramePosition _position; > GLenum _readBuffer; > mutable OpenThreads::Mutex _mutex; > mutable ContextDataMap _contextDataMap; > > osg::ref_ptr<ScreenCaptureHandler::CaptureOperation> > _defaultCaptureOperation; > }; > > > unsigned int WindowCaptureCallback::ContextData::COUNTER = 0; > > WindowCaptureCallback::ContextData::ContextData(osg::GraphicsContext* gc, > Mode mode, GLenum readBuffer) > : _gc(gc), > _index(COUNTER++), > _mode(mode), > _readBuffer(readBuffer), > _pixelFormat(GL_RGBA), > _type(GL_UNSIGNED_BYTE), > _width(0), > _height(0), > _currentImageIndex(0), > _currentPboIndex(0), > _reportTimingFrequency(100), > _numTimeValuesRecorded(0), > _timeForReadPixels(0.0), > _timeForMemCpy(0.0), > _timeForCaptureOperation(0.0), > _timeForFullCopy(0.0), > _timeForFullCopyAndOperation(0.0), > _previousFrameTick(0) > { > _previousFrameTick = osg::Timer::instance()->tick(); > > osg::NotifySeverity level = osg::INFO; > > if (gc->getTraits()) > { > if (gc->getTraits()->alpha) > { > osg::notify(level)<<"ScreenCaptureHandler: Selected GL_RGBA read > back format"<<std::endl; > _pixelFormat = GL_RGBA; > } > else > { > osg::notify(level)<<"ScreenCaptureHandler: Selected GL_RGB read > back format"<<std::endl; > _pixelFormat = GL_RGB; > } > } > > getSize(gc, _width, _height); > > //osg::notify(osg::NOTICE)<<"Window size "<<_width<<", > "<<_height<<std::endl; > > // single buffered image > _imageBuffer.push_back(new osg::Image); > > // double buffer PBO. > switch(_mode) > { > case(READ_PIXELS): > osg::notify(level)<<"ScreenCaptureHandler: Reading window using > glReadPixels, without PixelBufferObject."<<std::endl; > break; > case(SINGLE_PBO): > osg::notify(level)<<"ScreenCaptureHandler: Reading window using > glReadPixels, with a single PixelBufferObject."<<std::endl; > _pboBuffer.push_back(0); > break; > case(DOUBLE_PBO): > osg::notify(level)<<"ScreenCaptureHandler: Reading window using > glReadPixels, with a double buffer PixelBufferObject."<<std::endl; > _pboBuffer.push_back(0); > _pboBuffer.push_back(0); > break; > case(TRIPLE_PBO): > osg::notify(level)<<"ScreenCaptureHandler: Reading window using > glReadPixels, with a triple buffer PixelBufferObject."<<std::endl; > _pboBuffer.push_back(0); > _pboBuffer.push_back(0); > _pboBuffer.push_back(0); > break; > default: > break; > } > } > > void WindowCaptureCallback::ContextData::getSize(osg::GraphicsContext* gc, > int& width, int& height) > { > if (gc->getTraits()) > { > width = gc->getTraits()->width; > height = gc->getTraits()->height; > } > } > > void WindowCaptureCallback::ContextData::updateTimings(osg::Timer_t > tick_start, > osg::Timer_t > tick_afterReadPixels, > osg::Timer_t > tick_afterMemCpy, > osg::Timer_t > tick_afterCaptureOperation, > unsigned int dataSize) > { > _timeForReadPixels = osg::Timer::instance()->delta_s(tick_start, > tick_afterReadPixels); > _timeForMemCpy = osg::Timer::instance()->delta_s(tick_afterReadPixels, > tick_afterMemCpy); > _timeForCaptureOperation = > osg::Timer::instance()->delta_s(tick_afterMemCpy, > tick_afterCaptureOperation); > > _timeForFullCopy = osg::Timer::instance()->delta_s(tick_start, > tick_afterMemCpy); > _timeForFullCopyAndOperation = > osg::Timer::instance()->delta_s(tick_start, tick_afterCaptureOperation); > } > > void WindowCaptureCallback::ContextData::read() > { > osg::BufferObject::Extensions* ext = > osg::BufferObject::getExtensions(_gc->getState()->getContextID(),true); > > if (ext->isPBOSupported() && !_pboBuffer.empty()) > { > if (_pboBuffer.size()==1) > { > singlePBO(ext); > } > else > { > multiPBO(ext); > } > } > else > { > readPixels(); > } > } > > > void WindowCaptureCallback::ContextData::readPixels() > { > unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size(); > unsigned int nextPboIndex = _pboBuffer.empty() ? 0 : > (_currentPboIndex+1)%_pboBuffer.size(); > > int width=0, height=0; > getSize(_gc, width, height); > if (width!=_width || _height!=height) > { > //osg::notify(osg::NOTICE)<<" Window resized "<<width<<", > "<<height<<std::endl; > _width = width; > _height = height; > } > > osg::Image* image = _imageBuffer[_currentImageIndex].get(); > > osg::Timer_t tick_start = osg::Timer::instance()->tick(); > > #if 1 > image->readPixels(0,0,_width,_height, > _pixelFormat,_type); > #endif > > osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick(); > > if (_captureOperation.valid()) > { > (*_captureOperation)(*image, _index); > } > > osg::Timer_t tick_afterCaptureOperation = osg::Timer::instance()->tick(); > updateTimings(tick_start, tick_afterReadPixels, tick_afterReadPixels, > tick_afterCaptureOperation, image->getTotalSizeInBytes()); > > _currentImageIndex = nextImageIndex; > _currentPboIndex = nextPboIndex; > } > > void > WindowCaptureCallback::ContextData::singlePBO(osg::BufferObject::Extensions* > ext) > { > unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size(); > > int width=0, height=0; > getSize(_gc, width, height); > if (width!=_width || _height!=height) > { > //osg::notify(osg::NOTICE)<<" Window resized "<<width<<", > "<<height<<std::endl; > _width = width; > _height = height; > } > > GLuint& pbo = _pboBuffer[0]; > > osg::Image* image = _imageBuffer[_currentImageIndex].get(); > if (image->s() != _width || > image->t() != _height) > { > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Allocating image > "<<std::endl; > image->allocateImage(_width, _height, 1, _pixelFormat, _type); > > if (pbo!=0) > { > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: deleting pbo > "<<pbo<<std::endl; > ext->glDeleteBuffers (1, &pbo); > pbo = 0; > } > } > > > if (pbo==0) > { > ext->glGenBuffers(1, &pbo); > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); > ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, > image->getTotalSizeInBytes(), 0, GL_STREAM_READ); > > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Generating pbo > "<<pbo<<std::endl; > } > else > { > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); > } > > osg::Timer_t tick_start = osg::Timer::instance()->tick(); > > #if 1 > glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0); > #endif > > osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick(); > > GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, > GL_READ_ONLY_ARB); > if(src) > { > memcpy(image->data(), src, image->getTotalSizeInBytes()); > ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); > } > > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); > > osg::Timer_t tick_afterMemCpy = osg::Timer::instance()->tick(); > > if (_captureOperation.valid()) > { > (*_captureOperation)(*image, _index); > } > > osg::Timer_t tick_afterCaptureOperation = osg::Timer::instance()->tick(); > updateTimings(tick_start, tick_afterReadPixels, tick_afterMemCpy, > tick_afterCaptureOperation, image->getTotalSizeInBytes()); > > _currentImageIndex = nextImageIndex; > } > > void > WindowCaptureCallback::ContextData::multiPBO(osg::BufferObject::Extensions* > ext) > { > unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size(); > unsigned int nextPboIndex = (_currentPboIndex+1)%_pboBuffer.size(); > > int width=0, height=0; > getSize(_gc, width, height); > if (width!=_width || _height!=height) > { > //osg::notify(osg::NOTICE)<<" Window resized "<<width<<", > "<<height<<std::endl; > _width = width; > _height = height; > } > > GLuint& copy_pbo = _pboBuffer[_currentPboIndex]; > GLuint& read_pbo = _pboBuffer[nextPboIndex]; > > osg::Image* image = _imageBuffer[_currentImageIndex].get(); > if (image->s() != _width || > image->t() != _height) > { > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Allocating image > "<<std::endl; > image->allocateImage(_width, _height, 1, _pixelFormat, _type); > > if (read_pbo!=0) > { > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: deleting pbo > "<<read_pbo<<std::endl; > ext->glDeleteBuffers (1, &read_pbo); > read_pbo = 0; > } > > if (copy_pbo!=0) > { > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: deleting pbo > "<<copy_pbo<<std::endl; > ext->glDeleteBuffers (1, ©_pbo); > copy_pbo = 0; > } > } > > > bool doCopy = copy_pbo!=0; > if (copy_pbo==0) > { > ext->glGenBuffers(1, ©_pbo); > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo); > ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, > image->getTotalSizeInBytes(), 0, GL_STREAM_READ); > > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Generating pbo > "<<read_pbo<<std::endl; > } > > if (read_pbo==0) > { > ext->glGenBuffers(1, &read_pbo); > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo); > ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, > image->getTotalSizeInBytes(), 0, GL_STREAM_READ); > > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Generating pbo > "<<read_pbo<<std::endl; > } > else > { > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo); > } > > osg::Timer_t tick_start = osg::Timer::instance()->tick(); > > #if 1 > glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0); > #endif > > osg::Timer_t tick_afterReadPixels = osg::Timer::instance()->tick(); > > if (doCopy) > { > > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo); > > GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, > GL_READ_ONLY_ARB); > if(src) > { > memcpy(image->data(), src, image->getTotalSizeInBytes()); > ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB); > } > > if (_captureOperation.valid()) > { > (*_captureOperation)(*image, _index); > } > } > > ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); > > osg::Timer_t tick_afterMemCpy = osg::Timer::instance()->tick(); > > updateTimings(tick_start, tick_afterReadPixels, tick_afterMemCpy, > tick_afterMemCpy, image->getTotalSizeInBytes()); > > _currentImageIndex = nextImageIndex; > _currentPboIndex = nextPboIndex; > } > > > WindowCaptureCallback::WindowCaptureCallback(Mode mode, FramePosition > position, GLenum readBuffer) > : _mode(mode), > _position(position), > _readBuffer(readBuffer) > { > } > > WindowCaptureCallback::ContextData* > WindowCaptureCallback::createContextData(osg::GraphicsContext* gc) const > { > WindowCaptureCallback::ContextData* cd = new > WindowCaptureCallback::ContextData(gc, _mode, _readBuffer); > cd->_captureOperation = _defaultCaptureOperation; > return cd; > } > > WindowCaptureCallback::ContextData* > WindowCaptureCallback::getContextData(osg::GraphicsContext* gc) const > { > OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); > osg::ref_ptr<ContextData>& data = _contextDataMap[gc]; > if (!data) data = createContextData(gc); > > return data.get(); > } > > void > WindowCaptureCallback::setCaptureOperation(ScreenCaptureHandler::CaptureOperation* > operation) > { > _defaultCaptureOperation = operation; > > // Set the capture operation for each ContextData. > for (ContextDataMap::iterator it = _contextDataMap.begin(); it != > _contextDataMap.end(); ++it) > { > it->second->_captureOperation = operation; > } > } > > > void WindowCaptureCallback::operator () (osg::RenderInfo& renderInfo) const > { > glReadBuffer(_readBuffer); > > osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext(); > osg::ref_ptr<ContextData> cd = getContextData(gc); > cd->read(); > > // Since we just want to take one screenshot, the callback must remove > // itself when it's done. > if (_position == START_FRAME) > renderInfo.getCurrentCamera()->setInitialDrawCallback(0); > if (_position == END_FRAME) > renderInfo.getCurrentCamera()->setFinalDrawCallback(0); > > int prec = osg::notify(osg::INFO).precision(5); > osg::notify(osg::INFO) << "ScreenCaptureHandler: " > << "copy=" << (cd->_timeForFullCopy*1000.0f) > << "ms, " > << "operation=" << > (cd->_timeForCaptureOperation*1000.0f) << "ms, " > << "total=" << > (cd->_timeForFullCopyAndOperation*1000.0f) << std::endl; > osg::notify(osg::INFO).precision(prec); > > cd->_timeForFullCopy = 0; > } > > > > /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// > // > // ScreenCaptureHandler::WriteToFile > // > ScreenCaptureHandler::WriteToFile::WriteToFile(const std::string& filename, > const std::string& > extension, > SavePolicy > savePolicy) > : _filename(filename), _extension(extension), _savePolicy(savePolicy) > { > } > > void ScreenCaptureHandler::WriteToFile::operator () (const osg::Image& > image, const unsigned int context_id) > { > if (_savePolicy == SEQUENTIAL_NUMBER) > { > if (_contextSaveCounter.size() <= context_id) > { > _contextSaveCounter.resize(context_id + 1); > _contextSaveCounter[context_id] = 0; > } > } > > std::stringstream filename; > filename << _filename << "_" << context_id; > > if (_savePolicy == SEQUENTIAL_NUMBER) > filename << "_" << _contextSaveCounter[context_id]; > > filename << "." << _extension; > > osgDB::writeImageFile(image, filename.str()); > > osg::notify(osg::INFO)<<"ScreenCaptureHandler: Taking a screenshot, saved > as '"<<filename.str()<<"'"<<std::endl; > > if (_savePolicy == SEQUENTIAL_NUMBER) > { > _contextSaveCounter[context_id]++; > } > } > > > /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// > // > // ScreenCaptureHandler > // > ScreenCaptureHandler::ScreenCaptureHandler(CaptureOperation* > defaultOperation) > : _keyEventTakeScreenShot('c'), > _callback(new WindowCaptureCallback( > WindowCaptureCallback::READ_PIXELS, > // > WindowCaptureCallback::SINGLE_PBO, > // > WindowCaptureCallback::DOUBLE_PBO, > // > WindowCaptureCallback::TRIPLE_PBO, > WindowCaptureCallback::END_FRAME, > GL_BACK)) > { > if (defaultOperation) > setCaptureOperation(defaultOperation); > else > setCaptureOperation(new WriteToFile("screen_shot", "jpg")); > } > > void ScreenCaptureHandler::setCaptureOperation(CaptureOperation* operation) > { > > > static_cast<WindowCaptureCallback*>(_callback.get())->setCaptureOperation(operation); > } > > ScreenCaptureHandler::CaptureOperation* > ScreenCaptureHandler::getCaptureOperation() const > { > return > static_cast<WindowCaptureCallback*>(_callback.get())->getCaptureOperation(); > } > > > void ScreenCaptureHandler::addCallbackToViewer(osgViewer::ViewerBase& > viewer) > { > // Select either the first or the last active camera, depending on the > // frame position set in the callback. > // One case where testing the node mask is important is when the stats > // handler has been initialized, but stats are not displayed. In that > // case, there is a post render camera on the viewer, but its node mask > // is zero, so the callback added to that camera would never be called. > WindowCaptureCallback* callback = > static_cast<WindowCaptureCallback*>(_callback.get()); > > if (callback->getFramePosition() == WindowCaptureCallback::START_FRAME) > { > osgViewer::ViewerBase::Windows windows; > viewer.getWindows(windows); > for(osgViewer::ViewerBase::Windows::iterator itr = windows.begin(); > itr != windows.end(); > ++itr) > { > osgViewer::GraphicsWindow* window = *itr; > osg::GraphicsContext::Cameras& cameras = window->getCameras(); > osg::Camera* firstCamera = 0; > for(osg::GraphicsContext::Cameras::iterator cam_itr = > cameras.begin(); > cam_itr != cameras.end(); > ++cam_itr) > { > if (firstCamera) > { > if ((*cam_itr)->getRenderOrder() < > firstCamera->getRenderOrder()) > { > if ((*cam_itr)->getNodeMask() != 0x0) > firstCamera = (*cam_itr); > } > if ((*cam_itr)->getRenderOrder() == > firstCamera->getRenderOrder() && > (*cam_itr)->getRenderOrderNum() < > firstCamera->getRenderOrderNum()) > { > if ((*cam_itr)->getNodeMask() != 0x0) > firstCamera = (*cam_itr); > } > } > else > { > if ((*cam_itr)->getNodeMask() != 0x0) > firstCamera = *cam_itr; > } > } > > if (firstCamera) > { > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: First > camera "<<firstCamera<<std::endl; > > firstCamera->setInitialDrawCallback(_callback.get()); > } > else > { > osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: No camera > found"<<std::endl; > } > } > } > else > { > osgViewer::ViewerBase::Windows windows; > viewer.getWindows(windows); > for(osgViewer::ViewerBase::Windows::iterator itr = windows.begin(); > itr != windows.end(); > ++itr) > { > osgViewer::GraphicsWindow* window = *itr; > osg::GraphicsContext::Cameras& cameras = window->getCameras(); > osg::Camera* lastCamera = 0; > for(osg::GraphicsContext::Cameras::iterator cam_itr = > cameras.begin(); > cam_itr != cameras.end(); > ++cam_itr) > { > if (lastCamera) > { > if ((*cam_itr)->getRenderOrder() > > lastCamera->getRenderOrder()) > { > if ((*cam_itr)->getNodeMask() != 0x0) > lastCamera = (*cam_itr); > } > if ((*cam_itr)->getRenderOrder() == > lastCamera->getRenderOrder() && > (*cam_itr)->getRenderOrderNum() >= > lastCamera->getRenderOrderNum()) > { > if ((*cam_itr)->getNodeMask() != 0x0) > lastCamera = (*cam_itr); > } > } > else > { > if ((*cam_itr)->getNodeMask() != 0x0) > lastCamera = *cam_itr; > } > } > > if (lastCamera) > { > //osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: Last > camera "<<lastCamera<<std::endl; > > lastCamera->setFinalDrawCallback(_callback.get()); > } > else > { > osg::notify(osg::NOTICE)<<"ScreenCaptureHandler: No camera > found"<<std::endl; > } > } > } > } > > // aa will point to an osgViewer::View, so we will take a screenshot > // of that view's graphics contexts. > bool ScreenCaptureHandler::handle(const osgGA::GUIEventAdapter& ea, > osgGA::GUIActionAdapter& aa) > { > osgViewer::ViewerBase* viewer = > dynamic_cast<osgViewer::View*>(&aa)->getViewerBase(); > if (!viewer) return false; > > if (ea.getHandled()) return false; > > switch(ea.getEventType()) > { > case(osgGA::GUIEventAdapter::KEYUP): > { > if (ea.getKey() == _keyEventTakeScreenShot) > { > addCallbackToViewer(*viewer); > return true; > } > > break; > } > default: > break; > } > > return false; > } > > /** Capture the given viewer's views on the next frame. */ > void ScreenCaptureHandler::captureNextFrame(osgViewer::ViewerBase& viewer) > { > addCallbackToViewer(viewer); > } > > /** Get the keyboard and mouse usage of this manipulator.*/ > void ScreenCaptureHandler::getUsage(osg::ApplicationUsage& usage) const > { > { > std::ostringstream ostr; > ostr<<char(_keyEventTakeScreenShot); > usage.addKeyboardMouseBinding(ostr.str(),"Take screenshot."); > } > } > > > } > > _______________________________________________ > osg-submissions mailing list > [email protected] > http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org > > _______________________________________________ osg-submissions mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
