Hi,
it was posted to submissions:
http://thread.gmane.org/gmane.comp.graphics.openscenegraph.cvs/6026
I also attach...
jp
Kim Bale wrote:
This looks really useful, I'm surprised I missed the original post.
Anyone know where I can get the attachment from?
Kim.
2009/9/2 Roland Smeenk <[email protected]>:
If you are interested in creating high resolution screenshots take a look at
the osgposter example recently submitted:
http://forum.openscenegraph.org/viewtopic.php?t=3482
Roland
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=16952#16952
_______________________________________________
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
--
This message is subject to the CSIR's copyright terms and conditions, e-mail legal notice, and implemented Open Document Format (ODF) standard.
The full disclaimer details can be found at http://www.csir.co.za/disclaimer.html.
This message has been scanned for viruses and dangerous content by MailScanner,
and is believed to be clean. MailScanner thanks Transtec Computers for their support.
/* 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