1 /* -*-c++-*- */ 2 /* osgEarth - Geospatial SDK for OpenSceneGraph 3 * Copyright 2019 Pelican Mapping 4 * http://osgearth.org 5 * 6 * osgEarth is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/> 18 */ 19 #include "OSGOptions" 20 21 #include <osgEarth/FileUtils> 22 #include <osgEarth/ImageUtils> 23 #include <osgEarth/Registry> 24 #include <osgEarth/URI> 25 #include <osgDB/FileNameUtils> 26 27 #include <cstring> 28 29 #define LC "[OSG Driver] " 30 31 #define LOG2(X) (::log((double)(X))/::log(2.0)) 32 33 using namespace osgEarth; 34 using namespace osgEarth::Drivers; 35 36 namespace 37 { 38 struct CopyAndSetAlpha 39 { operator ()__anonab047dcc0111::CopyAndSetAlpha40 bool operator()( const osg::Vec4& in, osg::Vec4& out ) { 41 out = in; 42 out.a() = 0.3333*(in.r() + in.g() + in.b()); 43 return true; 44 } 45 }; 46 makeRGBAandComputeAlpha(osg::Image * image)47 osg::Image* makeRGBAandComputeAlpha(osg::Image* image) 48 { 49 osg::Image* result = new osg::Image(); 50 result->allocateImage( image->s(), image->t(), image->r(), GL_RGBA, GL_UNSIGNED_BYTE ); 51 memset(result->data(), 0, result->getTotalSizeInBytes()); 52 result->setInternalTextureFormat( GL_RGBA8 ); 53 ImageUtils::PixelVisitor<CopyAndSetAlpha>().accept( image, result ); 54 return result; 55 } 56 } 57 58 class OSGTileSource : public TileSource 59 { 60 public: OSGTileSource(const TileSourceOptions & options)61 OSGTileSource( const TileSourceOptions& options ) : 62 TileSource( options ), 63 _options( options ) 64 { 65 //nop 66 } 67 68 // By default don't cache local data from this layer getCachePolicyHint(const Profile * targetProfile) const69 CachePolicy getCachePolicyHint(const Profile* targetProfile) const 70 { 71 if (_options.url()->isRemote() == false) 72 return CachePolicy::NO_CACHE; 73 else 74 return CachePolicy::DEFAULT; 75 } 76 initialize(const osgDB::Options * dbOptions)77 Status initialize( const osgDB::Options* dbOptions ) 78 { 79 osg::ref_ptr<osgDB::Options> localOptions = Registry::instance()->cloneOrCreateOptions(dbOptions); 80 81 if ( !getProfile() ) 82 { 83 return Status::Error( Status::ConfigurationError, "An explicit profile definition is required by the OSG driver." ); 84 } 85 86 osg::ref_ptr<osg::Image> image; 87 88 if ( !_options.url()->empty() ) 89 { 90 ReadResult r = _options.url()->readImage( localOptions.get() ); 91 if ( r.succeeded() ) 92 { 93 image = r.getImage(); 94 } 95 } 96 97 if ( !image.valid() ) 98 { 99 return Status::Error( Status::ResourceUnavailable, Stringify() << "Failed to load data from \"" << _options.url()->full() << "\"" ); 100 } 101 102 // calculate and store the maximum LOD for which to return data 103 if ( image.valid() ) 104 { 105 int minSpan = osg::minimum( image->s(), image->t() ); 106 int tileSize = getPixelsPerTile(); 107 _maxLOD = (int)LOG2((minSpan/tileSize)+1); 108 109 getDataExtents().push_back( DataExtent(getProfile()->getExtent(), 0, _maxLOD) ); 110 111 bool computeAlpha = 112 (_options.convertLuminanceToRGBA() == true && image->getPixelFormat() == GL_LUMINANCE) || 113 (_options.addAlpha() == true && !ImageUtils::hasAlphaChannel( image.get() ) ); 114 115 if ( computeAlpha ) 116 { 117 image = makeRGBAandComputeAlpha( image.get() ); 118 } 119 else if ( ImageUtils::hasAlphaChannel( image.get() )) 120 { 121 image = ImageUtils::convertToRGBA8( image.get() ); 122 } 123 else 124 { 125 image = ImageUtils::convertToRGB8( image.get() ); 126 } 127 128 _image = GeoImage( image.get(), getProfile()->getExtent() ); 129 } 130 131 _extension = osgDB::getFileExtension( _options.url()->full() ); 132 133 return STATUS_OK; 134 } 135 136 osg::Image* createImage(const TileKey & key,ProgressCallback * progress)137 createImage( const TileKey& key, ProgressCallback* progress ) 138 { 139 if (!_image.valid() || key.getLOD() > _maxLOD) 140 return NULL; 141 142 GeoImage cropped = _image.crop( key.getExtent(), true, getPixelsPerTile(), getPixelsPerTile(), *_options.bilinearReprojection() ); 143 return cropped.valid() ? cropped.takeImage() : 0L; 144 } 145 146 std::string getExtension() const147 getExtension() const 148 { 149 return _extension; 150 } 151 152 private: 153 std::string _extension; 154 GeoImage _image; 155 const OSGOptions _options; 156 unsigned _maxLOD; 157 }; 158 159 160 /** 161 * This driver defers loading of the source data to the appropriate OSG plugin. You 162 * must explicitly set an override profile when using this driver. 163 * 164 * For example, use this driver to load a simple jpeg file; then set the profile to 165 * tell osgEarth its projection. 166 */ 167 class OSGTileSourceFactory : public TileSourceDriver 168 { 169 public: OSGTileSourceFactory()170 OSGTileSourceFactory() 171 { 172 supportsExtension( "osgearth_osg", "OSG image driver for osgEarth" ); 173 } 174 className() const175 virtual const char* className() const 176 { 177 return "OSG Image Driver"; 178 } 179 readObject(const std::string & file_name,const Options * options) const180 virtual ReadResult readObject(const std::string& file_name, const Options* options) const 181 { 182 if ( !acceptsExtension(osgDB::getLowerCaseFileExtension( file_name ))) 183 return ReadResult::FILE_NOT_HANDLED; 184 185 return new OSGTileSource( getTileSourceOptions(options) ); 186 } 187 }; 188 189 REGISTER_OSGPLUGIN(osgearth_osg, OSGTileSourceFactory) 190 191