Hi Kim,
This looks really useful, I'm surprised I missed the original post.Anyone know where I can get the attachment from?
It's at the bottom of the post here: http://thread.gmane.org/gmane.comp.graphics.openscenegraph.cvs/6026 or I've attached it too, for your convenience. :-) J-S -- ______________________________________________________ Jean-Sebastien Guay jean-sebastien.g...@cm-labs.com http://www.cm-labs.com/ http://whitestar02.webhop.org/
/* OpenSceneGraph example, osgposter. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include <osg/ArgumentParser> #include <osg/Camera> #include <osg/Texture2D> #include <osgDB/ReadFile> #include <osgDB/WriteFile> #include <osgViewer/Viewer> #include <iostream> #include <sstream> class PrintPosterHandler : public osgGA::GUIEventHandler { public: typedef std::pair<unsigned int, unsigned int> TilePosition; typedef std::map< TilePosition, osg::ref_ptr<osg::Image> > TileImages; PrintPosterHandler() : _isRunning(false), _isFinished(false), _outputTiles(false), _outputTileExt("bmp"), _currentRow(0), _currentColumn(0), _cameraIndex(0), _cameraRoot(0), _finalPoster(0) {} inline void setOutputTiles( bool b ) { _outputTiles = b; } inline bool getOutputTiles() const { return _outputTiles; } inline void setOutputTileExtension( const std::string& ext ) { _outputTileExt = ext; } inline const std::string& getOutputTileExtension() const { return _outputTileExt; } inline void setTileSize( int w, int h ) { _tileSize.set(w, h); } inline const osg::Vec2& getTileSize() const { return _tileSize; } inline void setPosterSize( int w, int h ) { _posterSize.set(w, h); } inline const osg::Vec2& getPosterSize() const { return _posterSize; } inline void setCameraRoot( osg::Group* root ) { _cameraRoot = root; } inline const osg::Group* getCameraRoot() const { return _cameraRoot.get(); } inline void setFinalPoster( osg::Image* image ) { _finalPoster = image; } inline const osg::Image* getFinalPoster() const { return _finalPoster.get(); } bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) { osgViewer::View* view = dynamic_cast<osgViewer::View*>( &aa ); if ( !view ) return false; switch( ea.getEventType() ) { case osgGA::GUIEventAdapter::FRAME: { if ( view->getDatabasePager() ) { // Wait until all paged LOD are processed if ( view->getDatabasePager()->getRequestsInProgress() ) break; } if ( _isFinished ) { const osg::FrameStamp* fs = view->getFrameStamp(); if ( (fs->getFrameNumber()%2)==0 ) { // Record images and unref them to free memory recordImages(); } } if ( _isRunning ) { // Every "copy-to-image" process seems to be finished in 2 frames. // So record them and dispatch cameras to next tiles. const osg::FrameStamp* fs = view->getFrameStamp(); if ( (fs->getFrameNumber()%2)==0 ) { // Record images and unref them to free memory recordImages(); osg::Camera* camera = 0; while ( (camera=getAvailableCamera())!=NULL ) { std::cout << "Binding sub-camera " << _currentRow << "_" << _currentColumn << " to image..." << std::endl; bindCameraToImage( camera, _currentRow, _currentColumn ); if ( _currentColumn<_tileColumns-1 ) _currentColumn++; else { if ( _currentRow<_tileRows-1 ) { _currentRow++; _currentColumn = 0; } else { _isRunning = false; _isFinished = true; std::cout << "Sub-cameras dispatching finished." << std::endl; break; } } } _cameraIndex = _cameraRoot->getNumChildren(); } } break; } case osgGA::GUIEventAdapter::KEYDOWN: { if ( ea.getKey()=='p' || ea.getKey()=='P' ) { if ( !_isRunning && _cameraRoot.valid() ) { _tileRows = (int)(_posterSize.y() / _tileSize.y()); _tileColumns = (int)(_posterSize.x() / _tileSize.x()); _currentRow = 0; _currentColumn = 0; _cameraIndex = _cameraRoot->getNumChildren(); _currentViewMatrix = view->getCamera()->getViewMatrix(); _currentProjectionMatrix = view->getCamera()->getProjectionMatrix(); _images.clear(); _isRunning = true; _isFinished = false; } return true; } break; } default: break; } return false; } protected: osg::Camera* getAvailableCamera() { // Find an available camera for rendering current tile image. if ( !_cameraIndex || !_cameraRoot.valid() ) return NULL; return dynamic_cast<osg::Camera*>( _cameraRoot->getChild(--_cameraIndex) ); } void bindCameraToImage( osg::Camera* camera, int row, int col ) { std::stringstream stream; stream << "image_" << row << "_" << col; osg::ref_ptr<osg::Image> image = new osg::Image; image->setName( stream.str() ); image->allocateImage( (int)_tileSize.x(), (int)_tileSize.y(), 1, GL_RGBA, GL_UNSIGNED_BYTE ); _images[TilePosition(row,col)] = image.get(); // Calculate projection matrix offset of each tile osg::Matrix offsetMatrix = osg::Matrix::scale(_tileColumns, _tileRows, 1.0) * osg::Matrix::translate(_tileColumns-1-2*col, _tileRows-1-2*row, 0.0); camera->setViewMatrix( _currentViewMatrix ); camera->setProjectionMatrix( _currentProjectionMatrix * offsetMatrix ); // Reattach cameras and new allocated images camera->setRenderingCache( NULL ); // FIXME: Uses for reattaching camera with image, maybe inefficient? camera->detach( osg::Camera::COLOR_BUFFER ); camera->attach( osg::Camera::COLOR_BUFFER, image.get(), 0, 0 ); } void recordImages() { for ( TileImages::iterator itr=_images.begin(); itr!=_images.end(); ++itr ) { osg::Image* image = (itr->second).get(); if ( _finalPoster.valid() ) { // FIXME: A stupid way to combine tile images to final result. Any better ideas? unsigned int row = itr->first.first, col = itr->first.second; for ( int s=0; s<image->s(); ++s ) { for ( int t=0; t<image->t(); ++t ) { unsigned char* src = image->data(s, t); unsigned char* target = _finalPoster->data(s + col*(int)_tileSize.x(), t + row*(int)_tileSize.y()); for ( int u=0; u<4; ++u ) *(target + u) = *(src++); } } } if ( _outputTiles ) osgDB::writeImageFile( *image, image->getName()+"."+_outputTileExt ); } _images.clear(); } bool _isRunning; bool _isFinished; bool _outputTiles; std::string _outputTileExt; osg::Vec2 _tileSize; osg::Vec2 _posterSize; int _tileRows; int _tileColumns; int _currentRow; int _currentColumn; unsigned int _cameraIndex; osg::Matrixd _currentViewMatrix; osg::Matrixd _currentProjectionMatrix; osg::ref_ptr<osg::Group> _cameraRoot; osg::ref_ptr<osg::Image> _finalPoster; TileImages _images; }; int main( int argc, char** argv ) { osg::ArgumentParser arguments( &argc, argv ); arguments.getApplicationUsage()->setDescription( arguments.getApplicationName() + " is the example which demonstrates how to render high-resolution images (posters)."); arguments.getApplicationUsage()->setCommandLineUsage( arguments.getApplicationName()+" [options] scene_file" ); arguments.getApplicationUsage()->addCommandLineOption( "-h or --help", "Display this information." ); arguments.getApplicationUsage()->addCommandLineOption( "--color <r> <g> <b>", "The background color." ); arguments.getApplicationUsage()->addCommandLineOption( "--cameras <num>", "Number of cameras for rendering tiles." ); arguments.getApplicationUsage()->addCommandLineOption( "--ext <ext>", "The output tiles' extension." ); arguments.getApplicationUsage()->addCommandLineOption( "--poster <filename>", "The output high-resolution poster file." ); arguments.getApplicationUsage()->addCommandLineOption( "--tilesize <w> <h>", "Size of each image tile." ); arguments.getApplicationUsage()->addCommandLineOption( "--finalsize <w> <h>", "Size of the high-resolution poster." ); arguments.getApplicationUsage()->addCommandLineOption( "--output-poster", "Output the final poster file." ); arguments.getApplicationUsage()->addCommandLineOption( "--no-output-poster", "Don't output the final poster file." ); arguments.getApplicationUsage()->addCommandLineOption( "--output-tiles", "Output all tile files." ); arguments.getApplicationUsage()->addCommandLineOption( "--no-output-tiles", "Don't output all tile files." ); arguments.getApplicationUsage()->addCommandLineOption( "--use-fb", "Use Frame Buffer for rendering tiles (Recommended)."); arguments.getApplicationUsage()->addCommandLineOption( "--use-fbo", "Use Frame Buffer Object for rendering tiles."); arguments.getApplicationUsage()->addCommandLineOption( "--use-pbuffer","Use Pixel Buffer for rendering tiles."); arguments.getApplicationUsage()->addCommandLineOption( "--use-pbuffer-rtt","Use Pixel Buffer RTT for rendering tiles."); if ( arguments.read("-h") || arguments.read("--help") ) { arguments.getApplicationUsage()->write( std::cout ); return 1; } bool outputPoster = true, outputTiles = false; int tileWidth = 640, tileHeight = 480; int posterWidth = 6400, posterHeight = 4800; int numCameras = 4; std::string posterName = "poster.bmp", extName = "bmp"; osg::Vec4 bgColor(0.2f, 0.2f, 0.6f, 1.0f); osg::Camera::RenderTargetImplementation renderImplementation = osg::Camera::FRAME_BUFFER; while ( arguments.read("--color", bgColor.r(), bgColor.g(), bgColor.b()) ) {} while ( arguments.read("--cameras", numCameras) ) {} while ( arguments.read("--tilesize", tileWidth, tileHeight) ) {} while ( arguments.read("--finalsize", posterWidth, posterHeight) ) {} while ( arguments.read("--output-poster") ) { outputPoster = true; } while ( arguments.read("--no-output-poster") ) { outputPoster = false; } while ( arguments.read("--output-tiles") ) { outputTiles = true; } while ( arguments.read("--no-output-tiles") ) { outputTiles = false; } while ( arguments.read("--poster", posterName) ) {} while ( arguments.read("--ext", extName) ) {} while ( arguments.read("--use-fbo")) { renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; } while ( arguments.read("--use-pbuffer")) { renderImplementation = osg::Camera::PIXEL_BUFFER; } while ( arguments.read("--use-pbuffer-rtt")) { renderImplementation = osg::Camera::PIXEL_BUFFER_RTT; } while ( arguments.read("--use-fb")) { renderImplementation = osg::Camera::FRAME_BUFFER; } osg::Node* scene = osgDB::readNodeFiles( arguments ); if ( !scene ) scene = osgDB::readNodeFile( "cow.osg" ); if ( !scene ) { std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; return 1; } osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild( scene ); // Create cameras for rendering tiles offscreen. FrameBuffer is recommended because it requires less memory. osg::ref_ptr<osg::Group> cameraRoot = new osg::Group; for ( int i=0; i<numCameras; ++i ) { osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setClearColor( bgColor ); camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); camera->setRenderOrder( osg::Camera::PRE_RENDER ); camera->setRenderTargetImplementation( renderImplementation ); camera->setViewport( 0, 0, tileWidth, tileHeight ); camera->addChild( scene ); cameraRoot->addChild( camera.get() ); } root->addChild( cameraRoot.get() ); // Set the printing handler PrintPosterHandler* handler = new PrintPosterHandler; handler->setTileSize( tileWidth, tileHeight ); handler->setPosterSize( posterWidth, posterHeight ); handler->setCameraRoot( cameraRoot.get() ); osg::ref_ptr<osg::Image> posterImage = 0; if ( outputPoster ) { posterImage = new osg::Image; posterImage->allocateImage( posterWidth, posterHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE ); handler->setFinalPoster( posterImage.get() ); } // Start the viewer osgViewer::Viewer viewer; viewer.setSceneData( root.get() ); viewer.addEventHandler( handler ); viewer.setUpViewInWindow( 100, 100, tileWidth, tileHeight ); viewer.run(); if ( outputPoster ) { std::cout << "Writing final result to file..." << std::endl; osgDB::writeImageFile( *posterImage, posterName ); } return 0; }
SET(TARGET_SRC osgposter.cpp ) SETUP_EXAMPLE(osgposter)
_______________________________________________ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org