/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commericial and non commericial applications, * as long as this copyright notice is maintained. * * This application 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class WindowCaptureCallback : public osg::Camera::DrawCallback { public: enum Mode { READ_PIXELS, SINGLE_PBO, DOUBLE_PBO }; struct ContextData : public osg::Referenced { ContextData(osg::GraphicsContext* gc, Mode mode, const std::string& name): _gc(gc), _mode(mode), _fileName(name), _pixelFormat(GL_BGR), _type(GL_UNSIGNED_BYTE), _width(0), _height(0), _currentImageIndex(0), _currentPboIndex(0) { getSize(gc, _width, _height); std::cout<<"Window size "<<_width<<", "<<_height<getTraits()) { width = gc->getTraits()->width; height = gc->getTraits()->height; } } void 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 readPixels(); void singlePBO(osg::BufferObject::Extensions* ext); void multiPBO(osg::BufferObject::Extensions* ext); typedef std::vector< osg::ref_ptr > ImageBuffer; typedef std::vector< GLuint > PBOBuffer; osg::GraphicsContext* _gc; Mode _mode; std::string _fileName; GLenum _pixelFormat; GLenum _type; int _width; int _height; unsigned int _currentImageIndex; ImageBuffer _imageBuffer; unsigned int _currentPboIndex; PBOBuffer _pboBuffer; }; WindowCaptureCallback(Mode mode): _mode(mode) { } ContextData* createContextData(osg::GraphicsContext* gc) const { std::stringstream filename; filename << "test_"<<_contextDataMap.size()<<".jpg"; return new ContextData(gc, _mode, filename.str()); } ContextData* getContextData(osg::GraphicsContext* gc) const { OpenThreads::ScopedLock lock(_mutex); osg::ref_ptr& data = _contextDataMap[gc]; if (!data) data = createContextData(gc); return data.get(); } virtual void operator () (osg::RenderInfo& renderInfo) const { osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext(); osg::ref_ptr cd = getContextData(gc); cd->read(); } typedef std::map > ContextDataMap; Mode _mode; mutable OpenThreads::Mutex _mutex; mutable ContextDataMap _contextDataMap; }; void WindowCaptureCallback::ContextData::readPixels() { // std::cout<<"readPixels("<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<readPixels(0,0,_width,_height, _pixelFormat,_type); #endif if (!_fileName.empty()) { // osgDB::writeImageFile(*image, _fileName); } _currentImageIndex = nextImageIndex; _currentPboIndex = nextPboIndex; } void WindowCaptureCallback::ContextData::singlePBO(osg::BufferObject::Extensions* ext) { // std::cout<<"singelPBO( "<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<s() != _width || image->t() != _height) { osg::notify(osg::NOTICE)<<"Allocating image "<allocateImage(_width, _height, 1, _pixelFormat, _type); if (pbo!=0) { osg::notify(osg::NOTICE)<<"deleting pbo "<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)<<"Generating pbo "<glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); } #if 1 glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0); #endif 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 (!_fileName.empty()) { // osgDB::writeImageFile(*image, _fileName); } ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); _currentImageIndex = nextImageIndex; } void WindowCaptureCallback::ContextData::multiPBO(osg::BufferObject::Extensions* ext) { // std::cout<<"multiPBO( "<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<s() != _width || image->t() != _height) { osg::notify(osg::NOTICE)<<"Allocating image "<allocateImage(_width, _height, 1, _pixelFormat, _type); if (read_pbo!=0) { osg::notify(osg::NOTICE)<<"deleting pbo "<glDeleteBuffers (1, &read_pbo); read_pbo = 0; } if (copy_pbo!=0) { osg::notify(osg::NOTICE)<<"deleting pbo "<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)<<"Generating pbo "<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)<<"Generating pbo "<glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo); } #if 1 glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0); #endif 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 (!_fileName.empty()) { // osgDB::writeImageFile(*image, _fileName); } } ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); _currentImageIndex = nextImageIndex; _currentPboIndex = nextPboIndex; } void addCallbackToViewer(osgViewer::ViewerBase& viewer, WindowCaptureCallback* callback) { 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() > (*cam_itr)->getRenderOrder()) { lastCamera = (*cam_itr); } if ((*cam_itr)->getRenderOrder() == lastCamera->getRenderOrder() && (*cam_itr)->getRenderOrderNum() >= lastCamera->getRenderOrderNum()) { lastCamera = (*cam_itr); } } else { lastCamera = *cam_itr; } } if (lastCamera) { osg::notify(osg::NOTICE)<<"Last camera "<setFinalDrawCallback(callback); } else { osg::notify(osg::NOTICE)<<"No camera found"<setApplicationName(arguments.getApplicationName()); arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models."); arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); arguments.getApplicationUsage()->addCommandLineOption("--image ","Load an image and render it on a quad"); arguments.getApplicationUsage()->addCommandLineOption("--dem ","Load an image/DEM and render it on a HeightField"); osgViewer::Viewer viewer(arguments); unsigned int helpType = 0; if ((helpType = arguments.readHelpType())) { arguments.getApplicationUsage()->write(std::cout, helpType); return 1; } // report any errors if they have occurred when parsing the program arguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } if (arguments.argc()<=1) { arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); return 1; } // set up the camera manipulators. { osg::ref_ptr keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator; keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() ); keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() ); keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() ); keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() ); std::string pathfile; char keyForAnimationPath = '5'; while (arguments.read("-p",pathfile)) { osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile); if (apm || !apm->valid()) { unsigned int num = keyswitchManipulator->getNumMatrixManipulators(); keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm ); keyswitchManipulator->selectMatrixManipulator(num); ++keyForAnimationPath; } } viewer.setCameraManipulator( keyswitchManipulator.get() ); } // add the state manipulator viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); // add the thread model handler viewer.addEventHandler(new osgViewer::ThreadingHandler); // add the window size toggle handler viewer.addEventHandler(new osgViewer::WindowSizeHandler); // add the stats handler viewer.addEventHandler(new osgViewer::StatsHandler); // add the help handler viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage())); // add the record camera path handler viewer.addEventHandler(new osgViewer::RecordCameraPathHandler); // add the LOD Scale handler viewer.addEventHandler(new osgViewer::LODScaleHandler); WindowCaptureCallback::Mode mode = WindowCaptureCallback::DOUBLE_PBO; while (arguments.read("--no-pbo")) mode = WindowCaptureCallback::READ_PIXELS; while (arguments.read("--single-pbo")) mode = WindowCaptureCallback::SINGLE_PBO; while (arguments.read("--double-pbo")) mode = WindowCaptureCallback::DOUBLE_PBO; // load the data osg::ref_ptr loadedModel = osgDB::readNodeFiles(arguments); if (!loadedModel) { std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; return 1; } // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); // report any errors if they have occurred when parsing the program arguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } // optimize the scene graph, remove redundant nodes and state etc. osgUtil::Optimizer optimizer; optimizer.optimize(loadedModel.get()); viewer.setSceneData( loadedModel.get() ); viewer.realize(); addCallbackToViewer(viewer, new WindowCaptureCallback(mode)); return viewer.run(); }