| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | #include <osg/ArgumentParser> |
|---|
| 20 | #include <osg/Texture2D> |
|---|
| 21 | #include <osg/Switch> |
|---|
| 22 | #include <osgDB/ReadFile> |
|---|
| 23 | #include <osgDB/WriteFile> |
|---|
| 24 | #include <osgGA/TrackballManipulator> |
|---|
| 25 | #include <osgGA/StateSetManipulator> |
|---|
| 26 | #include <osgViewer/Renderer> |
|---|
| 27 | #include <osgViewer/Viewer> |
|---|
| 28 | #include <osgViewer/ViewerEventHandlers> |
|---|
| 29 | #include <iostream> |
|---|
| 30 | #include "PosterPrinter.h" |
|---|
| 31 | |
|---|
| 32 | |
|---|
| 33 | template<class T> |
|---|
| 34 | class FindTopMostNodeOfTypeVisitor : public osg::NodeVisitor |
|---|
| 35 | { |
|---|
| 36 | public: |
|---|
| 37 | FindTopMostNodeOfTypeVisitor() |
|---|
| 38 | : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), |
|---|
| 39 | _foundNode(0) |
|---|
| 40 | {} |
|---|
| 41 | |
|---|
| 42 | void apply( osg::Node& node ) |
|---|
| 43 | { |
|---|
| 44 | T* result = dynamic_cast<T*>( &node ); |
|---|
| 45 | if ( result ) _foundNode = result; |
|---|
| 46 | else traverse( node ); |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | T* _foundNode; |
|---|
| 50 | }; |
|---|
| 51 | |
|---|
| 52 | template<class T> |
|---|
| 53 | T* findTopMostNodeOfType( osg::Node* node ) |
|---|
| 54 | { |
|---|
| 55 | if ( !node ) return 0; |
|---|
| 56 | |
|---|
| 57 | FindTopMostNodeOfTypeVisitor<T> fnotv; |
|---|
| 58 | node->accept( fnotv ); |
|---|
| 59 | return fnotv._foundNode; |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | |
|---|
| 63 | void computeViewMatrix( osg::Camera* camera, const osg::Vec3d& eye, const osg::Vec3d& hpr ) |
|---|
| 64 | { |
|---|
| 65 | osg::Matrixd matrix; |
|---|
| 66 | matrix.makeTranslate( eye ); |
|---|
| 67 | matrix.preMult( osg::Matrixd::rotate( hpr[0], 0.0, 1.0, 0.0) ); |
|---|
| 68 | matrix.preMult( osg::Matrixd::rotate( hpr[1], 1.0, 0.0, 0.0) ); |
|---|
| 69 | matrix.preMult( osg::Matrixd::rotate( hpr[2], 0.0, 0.0, 1.0) ); |
|---|
| 70 | camera->setViewMatrix( osg::Matrixd::inverse(matrix) ); |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | void computeViewMatrixOnEarth( osg::Camera* camera, osg::Node* scene, |
|---|
| 74 | const osg::Vec3d& latLongHeight, const osg::Vec3d& hpr ) |
|---|
| 75 | { |
|---|
| 76 | osg::CoordinateSystemNode* csn = findTopMostNodeOfType<osg::CoordinateSystemNode>(scene); |
|---|
| 77 | if ( !csn ) return; |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | osg::Vec3d eye; |
|---|
| 81 | csn->getEllipsoidModel()->convertLatLongHeightToXYZ( |
|---|
| 82 | latLongHeight.x(), latLongHeight.y(), latLongHeight.z(), eye.x(), eye.y(), eye.z() ); |
|---|
| 83 | |
|---|
| 84 | |
|---|
| 85 | osg::Matrixd target_matrix = |
|---|
| 86 | osg::Matrixd::rotate( -hpr.x(), osg::Vec3d(1,0,0), |
|---|
| 87 | -latLongHeight.x(), osg::Vec3d(0,1,0), |
|---|
| 88 | latLongHeight.y(), osg::Vec3d(0,0,1) ); |
|---|
| 89 | |
|---|
| 90 | |
|---|
| 91 | osg::Vec3d tangent = target_matrix.preMult( osg::Vec3d(0,0,1) ); |
|---|
| 92 | |
|---|
| 93 | |
|---|
| 94 | osg::Vec3d up( eye ); |
|---|
| 95 | up.normalize(); |
|---|
| 96 | |
|---|
| 97 | |
|---|
| 98 | |
|---|
| 99 | osg::Vec3d up_cross_tangent = up ^ tangent; |
|---|
| 100 | osg::Matrixd incline_matrix = osg::Matrixd::rotate( hpr.y(), up_cross_tangent ); |
|---|
| 101 | osg::Vec3d target = incline_matrix.preMult( tangent ); |
|---|
| 102 | |
|---|
| 103 | |
|---|
| 104 | osg::Matrixd roll_matrix = incline_matrix * osg::Matrixd::rotate( hpr.z(), target ); |
|---|
| 105 | up = roll_matrix.preMult( up ); |
|---|
| 106 | camera->setViewMatrixAsLookAt( eye, eye+target, up ); |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | class CustomRenderer : public osgViewer::Renderer |
|---|
| 111 | { |
|---|
| 112 | public: |
|---|
| 113 | CustomRenderer( osg::Camera* camera ) |
|---|
| 114 | : osgViewer::Renderer(camera), _cullOnly(true) |
|---|
| 115 | { |
|---|
| 116 | } |
|---|
| 117 | |
|---|
| 118 | void setCullOnly(bool on) { _cullOnly = on; } |
|---|
| 119 | |
|---|
| 120 | virtual void operator ()( osg::GraphicsContext* ) |
|---|
| 121 | { |
|---|
| 122 | if ( _graphicsThreadDoesCull ) |
|---|
| 123 | { |
|---|
| 124 | if (_cullOnly) cull(); |
|---|
| 125 | else cull_draw(); |
|---|
| 126 | } |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | virtual void cull() |
|---|
| 130 | { |
|---|
| 131 | osgUtil::SceneView* sceneView = _sceneView[0].get(); |
|---|
| 132 | if ( !sceneView || _done || _graphicsThreadDoesCull ) |
|---|
| 133 | return; |
|---|
| 134 | |
|---|
| 135 | updateSceneView( sceneView ); |
|---|
| 136 | |
|---|
| 137 | osgViewer::View* view = dynamic_cast<osgViewer::View*>( _camera->getView() ); |
|---|
| 138 | if ( view ) |
|---|
| 139 | sceneView->setFusionDistance( view->getFusionDistanceMode(), view->getFusionDistanceValue() ); |
|---|
| 140 | sceneView->inheritCullSettings( *(sceneView->getCamera()) ); |
|---|
| 141 | sceneView->cull(); |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | bool _cullOnly; |
|---|
| 145 | }; |
|---|
| 146 | |
|---|
| 147 | |
|---|
| 148 | class PrintPosterHandler : public osgGA::GUIEventHandler |
|---|
| 149 | { |
|---|
| 150 | public: |
|---|
| 151 | PrintPosterHandler( PosterPrinter* printer ) |
|---|
| 152 | : _printer(printer), _started(false) {} |
|---|
| 153 | |
|---|
| 154 | bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) |
|---|
| 155 | { |
|---|
| 156 | osgViewer::View* view = dynamic_cast<osgViewer::View*>( &aa ); |
|---|
| 157 | if ( !view ) return false; |
|---|
| 158 | |
|---|
| 159 | switch( ea.getEventType() ) |
|---|
| 160 | { |
|---|
| 161 | case osgGA::GUIEventAdapter::FRAME: |
|---|
| 162 | if ( view->getDatabasePager() ) |
|---|
| 163 | { |
|---|
| 164 | |
|---|
| 165 | if ( view->getDatabasePager()->getRequestsInProgress() ) |
|---|
| 166 | break; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | if ( _printer.valid() ) |
|---|
| 170 | { |
|---|
| 171 | _printer->frame( view->getFrameStamp(), view->getSceneData() ); |
|---|
| 172 | if ( _started && _printer->done() ) |
|---|
| 173 | { |
|---|
| 174 | osg::Switch* root = dynamic_cast<osg::Switch*>( view->getSceneData() ); |
|---|
| 175 | if ( root ) |
|---|
| 176 | { |
|---|
| 177 | |
|---|
| 178 | |
|---|
| 179 | root->setValue( 0, true ); |
|---|
| 180 | root->setValue( 1, false ); |
|---|
| 181 | } |
|---|
| 182 | _started = false; |
|---|
| 183 | } |
|---|
| 184 | } |
|---|
| 185 | break; |
|---|
| 186 | |
|---|
| 187 | case osgGA::GUIEventAdapter::KEYDOWN: |
|---|
| 188 | if ( ea.getKey()=='p' || ea.getKey()=='P' ) |
|---|
| 189 | { |
|---|
| 190 | if ( _printer.valid() ) |
|---|
| 191 | { |
|---|
| 192 | osg::Switch* root = dynamic_cast<osg::Switch*>( view->getSceneData() ); |
|---|
| 193 | if ( root ) |
|---|
| 194 | { |
|---|
| 195 | |
|---|
| 196 | root->setValue( 0, false ); |
|---|
| 197 | root->setValue( 1, true ); |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | _printer->init( view->getCamera() ); |
|---|
| 201 | _started = true; |
|---|
| 202 | } |
|---|
| 203 | return true; |
|---|
| 204 | } |
|---|
| 205 | break; |
|---|
| 206 | |
|---|
| 207 | default: |
|---|
| 208 | break; |
|---|
| 209 | } |
|---|
| 210 | return false; |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | protected: |
|---|
| 214 | osg::ref_ptr<PosterPrinter> _printer; |
|---|
| 215 | bool _started; |
|---|
| 216 | }; |
|---|
| 217 | |
|---|
| 218 | |
|---|
| 219 | int main( int argc, char** argv ) |
|---|
| 220 | { |
|---|
| 221 | osg::ArgumentParser arguments( &argc, argv ); |
|---|
| 222 | osg::ApplicationUsage* usage = arguments.getApplicationUsage(); |
|---|
| 223 | usage->setDescription( arguments.getApplicationName() + |
|---|
| 224 | " is the example which demonstrates how to render high-resolution images (posters)."); |
|---|
| 225 | usage->setCommandLineUsage( arguments.getApplicationName() + " [options] scene_file" ); |
|---|
| 226 | usage->addCommandLineOption( "-h or --help", "Display this information." ); |
|---|
| 227 | usage->addCommandLineOption( "--color <r> <g> <b>", "The background color." ); |
|---|
| 228 | usage->addCommandLineOption( "--ext <ext>", "The output tiles' extension (Default: bmp)." ); |
|---|
| 229 | usage->addCommandLineOption( "--poster <filename>", "The output poster's name (Default: poster.bmp)." ); |
|---|
| 230 | usage->addCommandLineOption( "--tilesize <w> <h>", "Size of each image tile (Default: 640 480)." ); |
|---|
| 231 | usage->addCommandLineOption( "--finalsize <w> <h>", "Size of the poster (Default: 6400 4800)." ); |
|---|
| 232 | usage->addCommandLineOption( "--enable-output-poster", "Output the final poster file (Default)." ); |
|---|
| 233 | usage->addCommandLineOption( "--disable-output-poster", "Don't output the final poster file." ); |
|---|
| 234 | |
|---|
| 235 | |
|---|
| 236 | usage->addCommandLineOption( "--use-fb", "Use Frame Buffer for rendering tiles (Default, recommended)."); |
|---|
| 237 | usage->addCommandLineOption( "--use-fbo", "Use Frame Buffer Object for rendering tiles."); |
|---|
| 238 | usage->addCommandLineOption( "--use-pbuffer","Use Pixel Buffer for rendering tiles."); |
|---|
| 239 | usage->addCommandLineOption( "--use-pbuffer-rtt","Use Pixel Buffer RTT for rendering tiles."); |
|---|
| 240 | usage->addCommandLineOption( "--inactive", "Inactive capturing mode." ); |
|---|
| 241 | usage->addCommandLineOption( "--camera-eye <x> <y> <z>", "Set eye position in inactive mode." ); |
|---|
| 242 | usage->addCommandLineOption( "--camera-latlongheight <lat> <lon> <h>", "Set eye position on earth in inactive mode." ); |
|---|
| 243 | usage->addCommandLineOption( "--camera-hpr <h> <p> <r>", "Set eye rotation in inactive mode." ); |
|---|
| 244 | |
|---|
| 245 | if ( arguments.read("-h") || arguments.read("--help") ) |
|---|
| 246 | { |
|---|
| 247 | usage->write( std::cout ); |
|---|
| 248 | return 1; |
|---|
| 249 | } |
|---|
| 250 | |
|---|
| 251 | |
|---|
| 252 | bool activeMode = true; |
|---|
| 253 | bool outputPoster = true; |
|---|
| 254 | |
|---|
| 255 | int tileWidth = 640, tileHeight = 480; |
|---|
| 256 | int posterWidth = 640*2, posterHeight = 480*2; |
|---|
| 257 | std::string posterName = "poster.bmp", extName = "bmp"; |
|---|
| 258 | osg::Vec4 bgColor(0.2f, 0.2f, 0.6f, 1.0f); |
|---|
| 259 | osg::Camera::RenderTargetImplementation renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; |
|---|
| 260 | |
|---|
| 261 | while ( arguments.read("--inactive") ) { activeMode = false; } |
|---|
| 262 | while ( arguments.read("--color", bgColor.r(), bgColor.g(), bgColor.b()) ) {} |
|---|
| 263 | while ( arguments.read("--tilesize", tileWidth, tileHeight) ) {} |
|---|
| 264 | while ( arguments.read("--finalsize", posterWidth, posterHeight) ) {} |
|---|
| 265 | while ( arguments.read("--poster", posterName) ) {} |
|---|
| 266 | while ( arguments.read("--ext", extName) ) {} |
|---|
| 267 | while ( arguments.read("--enable-output-poster") ) { outputPoster = true; } |
|---|
| 268 | while ( arguments.read("--disable-output-poster") ) { outputPoster = false; } |
|---|
| 269 | |
|---|
| 270 | |
|---|
| 271 | while ( arguments.read("--use-fbo")) { renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; } |
|---|
| 272 | while ( arguments.read("--use-pbuffer")) { renderImplementation = osg::Camera::PIXEL_BUFFER; } |
|---|
| 273 | while ( arguments.read("--use-pbuffer-rtt")) { renderImplementation = osg::Camera::PIXEL_BUFFER_RTT; } |
|---|
| 274 | while ( arguments.read("--use-fb")) { renderImplementation = osg::Camera::FRAME_BUFFER; } |
|---|
| 275 | |
|---|
| 276 | |
|---|
| 277 | bool useLatLongHeight = true; |
|---|
| 278 | osg::Vec3d eye; |
|---|
| 279 | osg::Vec3d latLongHeight( 50.0, 10.0, 2000.0 ); |
|---|
| 280 | osg::Vec3d hpr( 0.0, 0.0, 0.0 ); |
|---|
| 281 | if ( arguments.read("--camera-eye", eye.x(), eye.y(), eye.z()) ) |
|---|
| 282 | { |
|---|
| 283 | useLatLongHeight = false; |
|---|
| 284 | activeMode = false; |
|---|
| 285 | } |
|---|
| 286 | else if ( arguments.read("--camera-latlongheight", latLongHeight.x(), latLongHeight.y(), latLongHeight.z()) ) |
|---|
| 287 | { |
|---|
| 288 | activeMode = false; |
|---|
| 289 | latLongHeight.x() = osg::DegreesToRadians( latLongHeight.x() ); |
|---|
| 290 | latLongHeight.y() = osg::DegreesToRadians( latLongHeight.y() ); |
|---|
| 291 | } |
|---|
| 292 | if ( arguments.read("--camera-hpr", hpr.x(), hpr.y(), hpr.z()) ) |
|---|
| 293 | { |
|---|
| 294 | activeMode = false; |
|---|
| 295 | hpr.x() = osg::DegreesToRadians( hpr.x() ); |
|---|
| 296 | hpr.y() = osg::DegreesToRadians( hpr.y() ); |
|---|
| 297 | hpr.z() = osg::DegreesToRadians( hpr.z() ); |
|---|
| 298 | } |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | osg::Node* scene = osgDB::readNodeFiles( arguments ); |
|---|
| 302 | if ( !scene ) scene = osgDB::readNodeFile( "cow.osgt" ); |
|---|
| 303 | if ( !scene ) |
|---|
| 304 | { |
|---|
| 305 | std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; |
|---|
| 306 | return 1; |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | |
|---|
| 310 | osg::ref_ptr<osg::Camera> camera = new osg::Camera; |
|---|
| 311 | camera->setClearColor( bgColor ); |
|---|
| 312 | camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); |
|---|
| 313 | camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); |
|---|
| 314 | camera->setRenderOrder( osg::Camera::PRE_RENDER ); |
|---|
| 315 | camera->setRenderTargetImplementation( renderImplementation ); |
|---|
| 316 | camera->setViewport( 0, 0, tileWidth, tileHeight ); |
|---|
| 317 | camera->addChild( scene ); |
|---|
| 318 | |
|---|
| 319 | |
|---|
| 320 | osg::ref_ptr<PosterPrinter> printer = new PosterPrinter; |
|---|
| 321 | printer->setTileSize( tileWidth, tileHeight ); |
|---|
| 322 | printer->setPosterSize( posterWidth, posterHeight ); |
|---|
| 323 | printer->setCamera( camera.get() ); |
|---|
| 324 | |
|---|
| 325 | osg::ref_ptr<osg::Image> posterImage = 0; |
|---|
| 326 | if ( outputPoster ) |
|---|
| 327 | { |
|---|
| 328 | posterImage = new osg::Image; |
|---|
| 329 | posterImage->allocateImage( posterWidth, posterHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE ); |
|---|
| 330 | printer->setFinalPoster( posterImage.get() ); |
|---|
| 331 | printer->setOutputPosterName( posterName ); |
|---|
| 332 | } |
|---|
| 333 | |
|---|
| 334 | #if 0 |
|---|
| 335 | |
|---|
| 336 | |
|---|
| 337 | |
|---|
| 338 | |
|---|
| 339 | |
|---|
| 340 | osg::ref_ptr<osg::Switch> root = new osg::Switch; |
|---|
| 341 | root->addChild( scene, true ); |
|---|
| 342 | root->addChild( camera.get(), false ); |
|---|
| 343 | #else |
|---|
| 344 | osg::ref_ptr<osg::Group> root = new osg::Group; |
|---|
| 345 | root->addChild( scene ); |
|---|
| 346 | root->addChild( camera.get() ); |
|---|
| 347 | #endif |
|---|
| 348 | |
|---|
| 349 | osgViewer::Viewer viewer; |
|---|
| 350 | viewer.setSceneData( root.get() ); |
|---|
| 351 | viewer.getDatabasePager()->setDoPreCompile( false ); |
|---|
| 352 | |
|---|
| 353 | if ( renderImplementation==osg::Camera::FRAME_BUFFER ) |
|---|
| 354 | { |
|---|
| 355 | |
|---|
| 356 | viewer.setUpViewInWindow( 100, 100, tileWidth, tileHeight ); |
|---|
| 357 | } |
|---|
| 358 | else |
|---|
| 359 | { |
|---|
| 360 | |
|---|
| 361 | viewer.setUpViewInWindow( 100, 100, 800, 600 ); |
|---|
| 362 | } |
|---|
| 363 | |
|---|
| 364 | if ( activeMode ) |
|---|
| 365 | { |
|---|
| 366 | viewer.addEventHandler( new PrintPosterHandler(printer.get()) ); |
|---|
| 367 | viewer.addEventHandler( new osgViewer::StatsHandler ); |
|---|
| 368 | viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); |
|---|
| 369 | viewer.setCameraManipulator( new osgGA::TrackballManipulator ); |
|---|
| 370 | viewer.run(); |
|---|
| 371 | } |
|---|
| 372 | else |
|---|
| 373 | { |
|---|
| 374 | osg::Camera* camera = viewer.getCamera(); |
|---|
| 375 | if ( !useLatLongHeight ) computeViewMatrix( camera, eye, hpr ); |
|---|
| 376 | else computeViewMatrixOnEarth( camera, scene, latLongHeight, hpr ); |
|---|
| 377 | |
|---|
| 378 | osg::ref_ptr<CustomRenderer> renderer = new CustomRenderer( camera ); |
|---|
| 379 | camera->setRenderer( renderer.get() ); |
|---|
| 380 | viewer.setThreadingModel( osgViewer::Viewer::SingleThreaded ); |
|---|
| 381 | |
|---|
| 382 | |
|---|
| 383 | viewer.realize(); |
|---|
| 384 | viewer.frame(); |
|---|
| 385 | |
|---|
| 386 | printer->init( camera ); |
|---|
| 387 | while ( !printer->done() ) |
|---|
| 388 | { |
|---|
| 389 | viewer.advance(); |
|---|
| 390 | |
|---|
| 391 | |
|---|
| 392 | renderer->setCullOnly( true ); |
|---|
| 393 | while ( viewer.getDatabasePager()->getRequestsInProgress() ) |
|---|
| 394 | { |
|---|
| 395 | viewer.updateTraversal(); |
|---|
| 396 | viewer.renderingTraversals(); |
|---|
| 397 | } |
|---|
| 398 | |
|---|
| 399 | renderer->setCullOnly( false ); |
|---|
| 400 | printer->frame( viewer.getFrameStamp(), viewer.getSceneData() ); |
|---|
| 401 | viewer.renderingTraversals(); |
|---|
| 402 | } |
|---|
| 403 | } |
|---|
| 404 | return 0; |
|---|
| 405 | } |
|---|