Nice, cheers J-S, K.
2009/9/2 Jean-Sébastien Guay <[email protected]>: > 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 [email protected] > 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 > [email protected] > http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org > > _______________________________________________ osg-users mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

