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

Reply via email to