osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2010 Pelican Mapping 00004 * http://osgearth.org 00005 * 00006 * osgEarth is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 #include "SerialKeyNodeFactory" 00020 #include "DynamicLODScaleCallback" 00021 #include "FileLocationCallback" 00022 #include "LODFactorCallback" 00023 #include <osgEarth/Registry> 00024 #include <osg/PagedLOD> 00025 #include <osg/CullStack> 00026 #include <osg/Uniform> 00027 00028 #include <osgEarth/MapNode> 00029 00030 using namespace osgEarth; 00031 using namespace OpenThreads; 00032 00033 #define LC "[SerialKeyNodeFactory] " 00034 00035 SerialKeyNodeFactory::SerialKeyNodeFactory(TileBuilder* builder, 00036 const OSGTerrainOptions& options, 00037 const MapInfo& mapInfo, 00038 Terrain* terrain, 00039 UID engineUID ) : 00040 _builder( builder ), 00041 _options( options ), 00042 _mapInfo( mapInfo ), 00043 _terrain( terrain ), 00044 _engineUID( engineUID ) 00045 { 00046 //NOP 00047 } 00048 00049 void 00050 SerialKeyNodeFactory::addTile(Tile* tile, bool tileHasRealData, bool tileHasLodBlending, osg::Group* parent ) 00051 { 00052 // associate this tile with the terrain: 00053 tile->setTerrainTechnique( _terrain->cloneTechnique() ); 00054 tile->attachToTerrain( _terrain ); 00055 00056 // assemble a URI for this tile's child group: 00057 std::stringstream buf; 00058 buf << tile->getKey().str() << "." << _engineUID << ".osgearth_osgterrain_tile"; 00059 std::string uri; uri = buf.str(); 00060 00061 osg::Node* result = 0L; 00062 00063 // Only add the next tile if it hasn't been blacklisted 00064 bool wrapInPagedLOD = 00065 tileHasRealData && 00066 !osgEarth::Registry::instance()->isBlacklisted( uri ) && 00067 tile->getKey().getLevelOfDetail() < (unsigned)*_options.maxLOD(); 00068 00069 if ( wrapInPagedLOD ) 00070 { 00071 osg::BoundingSphere bs = tile->getBound(); 00072 double maxRange = 1e10; 00073 double minRange = bs.radius() * _options.minTileRangeFactor().value(); 00074 00075 // create a PLOD so we can keep subdividing: 00076 osg::PagedLOD* plod = new osg::PagedLOD(); 00077 plod->setCenter( bs.center() ); 00078 plod->addChild( tile, minRange, maxRange ); 00079 00080 plod->setFileName( 1, uri ); 00081 plod->setRange ( 1, 0, minRange ); 00082 00083 plod->setUserData( new MapNode::TileRangeData(minRange, maxRange) ); 00084 00085 #if USE_FILELOCATIONCALLBACK 00086 osgDB::Options* options = new osgDB::Options; 00087 options->setFileLocationCallback( new FileLocationCallback() ); 00088 plod->setDatabaseOptions( options ); 00089 00090 #endif 00091 result = plod; 00092 00093 if ( tileHasLodBlending ) 00094 { 00095 // Make the LOD transition distance, and a measure of how 00096 // close the tile is to an LOD change, to shaders. 00097 result->addCullCallback(new Drivers::LODFactorCallback); 00098 } 00099 } 00100 else 00101 { 00102 result = tile; 00103 } 00104 00105 // this cull callback dynamically adjusts the LOD scale based on distance-to-camera: 00106 if ( _options.lodFallOff().isSet() && *_options.lodFallOff() > 0.0 ) 00107 { 00108 result->addCullCallback( new DynamicLODScaleCallback(*_options.lodFallOff()) ); 00109 } 00110 00111 // this one rejects back-facing tiles: 00112 if ( _mapInfo.isGeocentric() ) 00113 { 00114 result->addCullCallback( HeightFieldUtils::createClusterCullingCallback( 00115 static_cast<osgTerrain::HeightFieldLayer*>(tile->getElevationLayer())->getHeightField(), 00116 tile->getLocator()->getEllipsoidModel(), 00117 tile->getVerticalScale() ) ); 00118 } 00119 00120 parent->addChild( result ); 00121 } 00122 00123 osg::Node* 00124 SerialKeyNodeFactory::createNode( const TileKey& key ) 00125 { 00126 osg::ref_ptr<Tile> tiles[4]; 00127 bool realData[4]; 00128 bool lodBlending[4]; 00129 bool tileHasAnyRealData = false; 00130 00131 for( unsigned i = 0; i < 4; ++i ) 00132 { 00133 TileKey child = key.createChildKey( i ); 00134 _builder->createTile( child, false, tiles[i], realData[i], lodBlending[i] ); 00135 if ( tiles[i].valid() && realData[i] ) 00136 tileHasAnyRealData = true; 00137 } 00138 00139 osg::Group* root = 0L; 00140 00141 if ( tileHasAnyRealData ) 00142 { 00143 // Now postprocess them and assemble into a tile group. 00144 root = new osg::Group(); 00145 00146 for( unsigned i = 0; i < 4; ++i ) 00147 { 00148 if ( tiles[i].valid() ) 00149 { 00150 addTile( tiles[i].get(), realData[i], lodBlending[i], root ); 00151 } 00152 } 00153 } 00154 00155 return root; 00156 }