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 <osgEarth/CompositeTileSource> 00020 #include <osgEarth/ImageUtils> 00021 #include <osgDB/FileNameUtils> 00022 00023 #define LC "[CompositeTileSource] " 00024 00025 using namespace osgEarth; 00026 00027 //------------------------------------------------------------------------ 00028 00029 CompositeTileSourceOptions::CompositeTileSourceOptions( const TileSourceOptions& options ) : 00030 TileSourceOptions( options ) 00031 { 00032 setDriver( "composite" ); 00033 fromConfig( _conf ); 00034 } 00035 00036 void 00037 CompositeTileSourceOptions::add( const TileSourceOptions& options ) 00038 { 00039 Component c; 00040 c._tileSourceOptions = options; 00041 _components.push_back( c ); 00042 } 00043 00044 void 00045 CompositeTileSourceOptions::add( TileSource* source ) 00046 { 00047 Component c; 00048 c._tileSourceInstance = source; 00049 _components.push_back( c ); 00050 } 00051 00052 void 00053 CompositeTileSourceOptions::add( const ImageLayerOptions& options ) 00054 { 00055 Component c; 00056 c._imageLayerOptions = options; 00057 _components.push_back( c ); 00058 } 00059 00060 void 00061 CompositeTileSourceOptions::add( TileSource* source, const ImageLayerOptions& options ) 00062 { 00063 Component c; 00064 c._tileSourceInstance = source; 00065 c._imageLayerOptions = options; 00066 _components.push_back( c ); 00067 } 00068 00069 Config 00070 CompositeTileSourceOptions::getConfig() const 00071 { 00072 Config conf = TileSourceOptions::getConfig(); 00073 00074 for( ComponentVector::const_iterator i = _components.begin(); i != _components.end(); ++i ) 00075 { 00076 if ( i->_imageLayerOptions.isSet() ) 00077 conf.add( "image", i->_imageLayerOptions->getConfig() ); 00078 else if ( i->_tileSourceOptions.isSet() ) 00079 conf.add( "image", i->_tileSourceOptions->getConfig() ); 00080 } 00081 00082 return conf; 00083 } 00084 00085 void 00086 CompositeTileSourceOptions::mergeConfig( const Config& conf ) 00087 { 00088 TileSourceOptions::mergeConfig( conf ); 00089 fromConfig( conf ); 00090 } 00091 00092 void 00093 CompositeTileSourceOptions::fromConfig( const Config& conf ) 00094 { 00095 const ConfigSet& children = conf.children("image"); 00096 for( ConfigSet::const_iterator i = children.begin(); i != children.end(); ++i ) 00097 { 00098 add( ImageLayerOptions( *i ) ); 00099 } 00100 00101 if (conf.children("elevation").size() > 0 || conf.children("heightfield").size() > 0 || 00102 conf.children("model").size() > 0 || conf.children("overlay").size() > 0 ) 00103 { 00104 OE_WARN << LC << "Illegal - composite driver only supports image layers" << std::endl; 00105 } 00106 } 00107 00108 //------------------------------------------------------------------------ 00109 00110 namespace 00111 { 00112 // some helper types. 00113 typedef std::pair< osg::ref_ptr<osg::Image>, float> ImageOpacityPair; 00114 typedef std::vector<ImageOpacityPair> ImageMixVector; 00115 00116 // same op that occurs in ImageLayer.cpp ... maybe consilidate 00117 struct ImageLayerPreCacheOperation : public TileSource::ImageOperation 00118 { 00119 void operator()( osg::ref_ptr<osg::Image>& image ) 00120 { 00121 _processor.process( image ); 00122 } 00123 00124 ImageLayerTileProcessor _processor; 00125 }; 00126 } 00127 00128 //----------------------------------------------------------------------- 00129 00130 CompositeTileSource::CompositeTileSource( const TileSourceOptions& options ) : 00131 _options( options ), 00132 _initialized( false ), 00133 _dynamic( false ) 00134 { 00135 for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin(); 00136 i != _options._components.end(); ) 00137 00138 { 00139 if ( i->_imageLayerOptions.isSet() ) 00140 { 00141 if ( i->_imageLayerOptions->driver().isSet() ) 00142 i->_tileSourceOptions = i->_imageLayerOptions->driver().value(); 00143 } 00144 00145 if ( i->_tileSourceOptions.isSet() ) 00146 { 00147 if ( !i->_tileSourceInstance->valid() ) 00148 i->_tileSourceInstance = TileSourceFactory::create( i->_tileSourceOptions.value() ); 00149 00150 if ( !i->_tileSourceInstance->valid() ) 00151 OE_WARN << LC << "Could not find a TileSource for driver [" << i->_tileSourceOptions->getDriver() << "]" << std::endl; 00152 } 00153 00154 if ( !i->_tileSourceInstance->valid() ) 00155 { 00156 OE_WARN << LC << "A component has no valid TileSource ... removing." << std::endl; 00157 i = _options._components.erase( i ); 00158 } 00159 else 00160 { 00161 ++i; 00162 } 00163 } 00164 } 00165 00166 osg::Image* 00167 CompositeTileSource::createImage( const TileKey& key, ProgressCallback* progress ) 00168 { 00169 ImageMixVector images; 00170 images.reserve( _options._components.size() ); 00171 00172 for(CompositeTileSourceOptions::ComponentVector::const_iterator i = _options._components.begin(); 00173 i != _options._components.end(); 00174 ++i ) 00175 { 00176 if ( progress && progress->isCanceled() ) 00177 return 0L; 00178 00179 TileSource* source = i->_tileSourceInstance->get(); 00180 if ( source ) 00181 { 00182 00183 //TODO: This duplicates code in ImageLayer::isKeyValid. Maybe should move that to TileSource::isKeyValid instead 00184 int minLevel = 0; 00185 int maxLevel = INT_MAX; 00186 if (i->_imageLayerOptions->minLevel().isSet()) 00187 { 00188 minLevel = i->_imageLayerOptions->minLevel().value(); 00189 } 00190 else if (i->_imageLayerOptions->minLevelResolution().isSet()) 00191 { 00192 minLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->minLevelResolution().value(), source->getPixelsPerTile()); 00193 } 00194 00195 if (i->_imageLayerOptions->maxLevel().isSet()) 00196 { 00197 maxLevel = i->_imageLayerOptions->maxLevel().value(); 00198 } 00199 else if (i->_imageLayerOptions->maxLevelResolution().isSet()) 00200 { 00201 maxLevel = source->getProfile()->getLevelOfDetailForHorizResolution( i->_imageLayerOptions->maxLevelResolution().value(), source->getPixelsPerTile()); 00202 } 00203 00204 00205 00206 00207 // check that this source is within the level bounds: 00208 if (minLevel > key.getLevelOfDetail() || 00209 maxLevel < key.getLevelOfDetail() ) 00210 { 00211 continue; 00212 } 00213 00214 00215 00216 00217 00218 if ( !source->getBlacklist()->contains( key.getTileId() ) ) 00219 { 00220 //Only try to get data if the source actually has data 00221 if ( source->hasData( key ) ) 00222 { 00223 osg::ref_ptr< ImageLayerPreCacheOperation > preCacheOp; 00224 if ( i->_imageLayerOptions.isSet() ) 00225 { 00226 preCacheOp = new ImageLayerPreCacheOperation(); 00227 preCacheOp->_processor.init( i->_imageLayerOptions.value(), true ); 00228 } 00229 00230 00231 00232 ImageOpacityPair imagePair( 00233 source->createImage( key, preCacheOp.get(), progress ), 00234 1.0f ); 00235 00236 //If the image is not valid and the progress was not cancelled, blacklist 00237 if (!imagePair.first.valid() && (!progress || !progress->isCanceled())) 00238 { 00239 //Add the tile to the blacklist 00240 OE_DEBUG << LC << "Adding tile " << key.str() << " to the blacklist" << std::endl; 00241 source->getBlacklist()->add( key.getTileId() ); 00242 } 00243 00244 if ( imagePair.first.valid() ) 00245 { 00246 // check for opacity: 00247 imagePair.second = i->_imageLayerOptions.isSet() ? i->_imageLayerOptions->opacity().value() : 1.0f; 00248 00249 images.push_back( imagePair ); 00250 } 00251 } 00252 else 00253 { 00254 OE_DEBUG << LC << "Source has no data at " << key.str() << std::endl; 00255 } 00256 } 00257 else 00258 { 00259 OE_DEBUG << LC << "Tile " << key.str() << " is blacklisted, not checking" << std::endl; 00260 } 00261 } 00262 } 00263 00264 if ( progress && progress->isCanceled() ) 00265 { 00266 return 0L; 00267 } 00268 else if ( images.size() == 0 ) 00269 { 00270 return 0L; 00271 } 00272 else if ( images.size() == 1 ) 00273 { 00274 return images[0].first.release(); 00275 } 00276 else 00277 { 00278 osg::Image* result = new osg::Image( *images[0].first.get() ); 00279 for( unsigned int i=1; i<images.size(); ++i ) 00280 { 00281 ImageOpacityPair& pair = images[i]; 00282 if ( pair.first.valid() ) 00283 { 00284 ImageUtils::mix( result, pair.first.get(), pair.second ); 00285 } 00286 } 00287 return result; 00288 } 00289 } 00290 00291 void 00292 CompositeTileSource::initialize( const std::string& referenceURI, const Profile* overrideProfile ) 00293 { 00294 osg::ref_ptr<const Profile> profile = overrideProfile; 00295 00296 for(CompositeTileSourceOptions::ComponentVector::iterator i = _options._components.begin(); 00297 i != _options._components.end(); 00298 ++i) 00299 { 00300 TileSource* source = i->_tileSourceInstance->get(); //.get(); 00301 if ( source ) 00302 { 00303 osg::ref_ptr<const Profile> localOverrideProfile = overrideProfile; 00304 00305 const TileSourceOptions& opt = source->getOptions(); 00306 if ( opt.profile().isSet() ) 00307 localOverrideProfile = Profile::create( opt.profile().value() ); 00308 00309 source->initialize( referenceURI, localOverrideProfile.get() ); 00310 00311 if ( !profile.valid() ) 00312 { 00313 // assume the profile of the first source to be the overall profile. 00314 profile = source->getProfile(); 00315 } 00316 else if ( !profile->isEquivalentTo( source->getProfile() ) ) 00317 { 00318 // if sub-sources have different profiles, print a warning because this is 00319 // not supported! 00320 OE_WARN << LC << "Components with differing profiles are not supported. " 00321 << "Visual anomalies may result." << std::endl; 00322 } 00323 00324 _dynamic = _dynamic || source->isDynamic(); 00325 00326 // gather extents 00327 const DataExtentList& extents = source->getDataExtents(); 00328 for( DataExtentList::const_iterator j = extents.begin(); j != extents.end(); ++j ) 00329 { 00330 getDataExtents().push_back( *j ); 00331 } 00332 } 00333 } 00334 00335 setProfile( profile.get() ); 00336 00337 _initialized = true; 00338 } 00339 00340 //------------------------------------------------------------------------ 00341 00342 namespace 00343 { 00344 struct CompositeTileSourceDriver : public TileSourceDriver 00345 { 00346 CompositeTileSourceDriver() 00347 { 00348 supportsExtension( "osgearth_composite", "Composite tile source driver" ); 00349 } 00350 00351 virtual const char* className() 00352 { 00353 return "CompositeTileSourceDriver"; 00354 } 00355 00356 virtual ReadResult readObject(const std::string& file_name, const Options* options) const 00357 { 00358 if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name ))) 00359 return ReadResult::FILE_NOT_HANDLED; 00360 00361 return new CompositeTileSource( getTileSourceOptions(options) ); 00362 } 00363 }; 00364 } 00365 REGISTER_OSGPLUGIN(osgearth_composite, CompositeTileSourceDriver)