+
+///////////////////////////////////////////////////////////////////////////
+
+class WindowCaptureCallback : public osg::Camera::DrawCallback
+{
+public:
+
+ enum Mode
+ {
+ READ_PIXELS,
+ SINGLE_PBO,
+ DOUBLE_PBO,
+ TRIPLE_PBO
+ };
+
+ enum FramePosition
+ {
+ START_FRAME,
+ END_FRAME
+ };
+
+ struct ContextData : public osg::Referenced
+ {
+ ContextData(osg::GraphicsContext* gc, Mode mode, GLenum readBuffer, HttpdThread* httpd):
+ _gc(gc),
+ _mode(mode),
+ _readBuffer(readBuffer),
+ _pixelFormat(GL_RGB),
+ _type(GL_UNSIGNED_BYTE),
+ _width(0),
+ _height(0),
+ _currentImageIndex(0),
+ _httpd(httpd)
+ {
+ _previousFrameTick = osg::Timer::instance()->tick();
+
+ if (gc->getTraits() && gc->getTraits()->alpha) {
+ _pixelFormat = GL_RGBA;
+ }
+
+ getSize(gc, _width, _height);
+
+ // single buffered image
+ _imageBuffer.push_back(new osg::Image);
+ }
+
+ void getSize(osg::GraphicsContext* gc, int& width, int& height)
+ {
+ if (gc->getTraits())
+ {
+ width = gc->getTraits()->width;
+ height = gc->getTraits()->height;
+ }
+ }
+
+ void readPixels();
+
+ typedef std::vector< osg::ref_ptr<osg::Image> > ImageBuffer;
+
+ osg::GraphicsContext* _gc;
+ Mode _mode;
+ GLenum _readBuffer;
+ GLenum _pixelFormat;
+ GLenum _type;
+ int _width;
+ int _height;
+ unsigned int _currentImageIndex;
+ ImageBuffer _imageBuffer;
+ osg::Timer_t _previousFrameTick;
+ HttpdThread* _httpd;
+ };
+
+ WindowCaptureCallback(HttpdThread *thread, Mode mode, FramePosition position, GLenum readBuffer):
+ _mode(mode),
+ _position(position),
+ _readBuffer(readBuffer),
+ _thread(thread)
+ {
+ }
+
+ FramePosition getFramePosition() const { return _position; }
+
+ ContextData* createContextData(osg::GraphicsContext* gc) const
+ {
+ return new ContextData(gc, _mode, _readBuffer, _thread);
+ }
+
+ ContextData* 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();
+ }
+
+ virtual void operator () (osg::RenderInfo& renderInfo) const
+ {
+ glReadBuffer(_readBuffer);
+
+ osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext();
+ osg::ref_ptr<ContextData> cd = getContextData(gc);
+ cd->readPixels();
+ }
+
+ typedef std::map<osg::GraphicsContext*, osg::ref_ptr<ContextData> > ContextDataMap;
+
+ Mode _mode;
+ FramePosition _position;
+ GLenum _readBuffer;
+ mutable OpenThreads::Mutex _mutex;
+ mutable ContextDataMap _contextDataMap;
+ HttpdThread* _thread;
+};
+
+void WindowCaptureCallback::ContextData::readPixels()
+{
+ osg::Timer_t n = osg::Timer::instance()->tick();
+ double dt = osg::Timer::instance()->delta_s(n, _previousFrameTick);
+ double frameInterval = 1.0 / _httpd->getFrameHz();
+ if (dt < frameInterval)
+ return;
+
+ _previousFrameTick = n;
+ unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
+
+ int width=0, height=0;
+ getSize(_gc, width, height);
+ if (width!=_width || _height!=height)
+ {
+ _width = width;
+ _height = height;
+ }
+
+ osg::Image* image = _imageBuffer[_currentImageIndex].get();
+ image->readPixels(0,0,_width,_height,
+ _pixelFormat,_type);
+
+ _httpd->setNewFrameImage(image);
+ _currentImageIndex = nextImageIndex;
+}
+
+osg::Camera* findLastCamera(osgViewer::ViewerBase& viewer)
+{
+ 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())
+ {
+ lastCamera = (*cam_itr);
+ }
+ if ((*cam_itr)->getRenderOrder() == lastCamera->getRenderOrder() &&
+ (*cam_itr)->getRenderOrderNum() >= lastCamera->getRenderOrderNum())
+ {
+ lastCamera = (*cam_itr);
+ }
+ }
+ else
+ {
+ lastCamera = *cam_itr;
+ }
+ }
+
+ return lastCamera;
+ }
+
+ return NULL;