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