/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2020 Pelican Mapping * http://osgearth.org * * osgEarth is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #pragma once #include #include #include #include #include #include #include namespace osgEarth { class Profile; } namespace osgEarth { /** * Texture paired with a scale/bias matrix defining a sub-window. */ class OSGEARTH_EXPORT TextureWindow { public: //! Empty/invalid texture window TextureWindow() : _texture(0L) { } //! Construct a texture window TextureWindow(osg::Texture* tex, const osg::Matrix& scalebias) : _texture(tex), _matrix(scalebias) { } //! Texture osg::Texture* getTexture() const { return _texture.get(); } //! Scale bias matrix defining subwindow const osg::Matrixf& getMatrix() const { return _matrix; } //! Is it valid? bool valid() const { return _texture.valid(); } protected: osg::ref_ptr _texture; osg::Matrixf _matrix; }; /** * A map terrain layer containing bitmap image data. */ class OSGEARTH_EXPORT ImageLayer : public TileLayer { public: // Serialization class OSGEARTH_EXPORT Options : public TileLayer::Options { public: META_LayerOptions(osgEarth, Options, TileLayer::Options); OE_OPTION(URI, noDataImageFilename); OE_OPTION(osg::Vec4ub, transparentColor, osg::Vec4ub(0, 0, 0, 0)); OE_OPTION(ColorFilterChain, colorFilters); OE_OPTION(osg::Texture::FilterMode, minFilter, osg::Texture::LINEAR_MIPMAP_LINEAR); OE_OPTION(osg::Texture::FilterMode, magFilter, osg::Texture::LINEAR); OE_OPTION(std::string, textureCompression); OE_OPTION(double, edgeBufferRatio, 0.0); OE_OPTION(unsigned, reprojectedTileSize, 256u); OE_OPTION(Distance, altitude); OE_OPTION(bool, coverage, false); OE_OPTION(bool, acceptDraping, false); OE_OPTION(bool, async, false); OE_OPTION(bool, shared, false); OE_OPTION(std::string, shareTexUniformName); OE_OPTION(std::string, shareTexMatUniformName); virtual Config getConfig() const; private: void fromConfig(const Config& conf); }; public: META_Layer_Abstract(osgEarth, ImageLayer, Options, TileLayer); //! Layer callbacks class OSGEARTH_EXPORT Callback : public osg::Referenced { public: //! Called when a new data is created. This callback fires //! before the data is cached, and does NOT fire if the data //! was read from a cache. //! NOTE: This may be invoked from a worker thread. Use caution. virtual void onCreate(const TileKey&, GeoImage&) { } }; public: //! Convenience function to create an ImageLayer from a ConfigOptions. static ImageLayer* create(const ConfigOptions& conf); //! @deprecated //! Adds a color filter to the filter chain. void addColorFilter(ColorFilter* filter); //! @deprecated //! Removes a color filter from the filter chain void removeColorFilter(ColorFilter* filter); //! @deprecated //! Accesses the color filter chain const ColorFilterChain& getColorFilters() const; //! Sets the altitude void setAltitude(const Distance& value); const Distance& getAltitude() const; //! Sets whether this layer should allow draped overlays //! to render on it. This is most applicable to layers with a //! non-zero altitude (setAltitude). Default is true. void setAcceptDraping(bool value); bool getAcceptDraping() const; //! Marks this layer for asynchronous loading. //! Usually all layers participating in a tile must load before the //! tile is displayed. This flag defers the current layer so it can //! load asynchronously and display when it is available. This can //! help keep a slow-loading layer from blocking the rest of the tile //! from displaying. The trade-off is possible visual artifacts //! (flashing, no mipmaps/compression) when the new data appears. void setAsyncLoading(bool value); bool getAsyncLoading() const; //! Whether this layer is marked for render sharing. //! Only set this before opening the layer or adding it to a map. void setShared(bool value); bool getShared() const; bool isShared() const { return getShared(); } //! Whether this layer represents coverage data that should not be subject //! to color-space filtering, interpolation, or compression. //! Only set this before opening the layer or adding it to a map. void setCoverage(bool value); bool getCoverage() const; bool isCoverage() const { return getCoverage(); } //! When isShared() == true, this will return the name of the uniform holding the //! image's texture. void setSharedTextureUniformName(const std::string& value); const std::string& getSharedTextureUniformName() const; //! When isShared() == true, this will return the name of the uniform holding the //! image's texture matrix. void setSharedTextureMatrixUniformName(const std::string& value); const std::string& getSharedTextureMatrixUniformName() const; //! When isShared() == true, the engine will call this function to bind the //! shared layer to a texture image unit. optional& sharedImageUnit() { return _shareImageUnit; } const optional& sharedImageUnit() const { return _shareImageUnit; } osg::Image* getEmptyImage() const { return _emptyImage.get(); } public: // methods //! Creates an image for the given tile key. //! @param key TileKey for which to create an image //! @param progress Optional progress/cancelation callback GeoImage createImage(const TileKey& key); //! Creates an image for the given tile key. //! @param key TileKey for which to create an image //! @param progress Optional progress/cancelation callback GeoImage createImage(const TileKey& key, ProgressCallback* progress); //! Stores an image in this layer (if writing is enabled). //! Returns a status value indicating whether the store succeeded. Status writeImage(const TileKey& key, const osg::Image* image, ProgressCallback* progress = 0L); //! Returns the compression method prefered by this layer //! that you can pass to ImageUtils::compressImage. const std::string getCompressionMethod() const; //! Install a user callback void addCallback(Callback* callback); //! Remove a user callback void removeCallback(Callback* callback); //! Add a post-processing layer void addPostLayer(Layer* layer); public: // Texture support //! Whether to use createTexture to create data for this layer //! instead of createImage and a TileSource driver bool useCreateTexture() const { return _useCreateTexture; } //! Override this method to create the texture when useCreateTexture is true virtual TextureWindow createTexture(const TileKey& key, ProgressCallback* progress) const { return TextureWindow(); } //! Subclass overrides this to generate image data for the key. //! The key will always be in the same profile as the layer. virtual GeoImage createImageImplementation(const TileKey&, ProgressCallback* progress) const { return GeoImage::INVALID; } protected: //! Subclass can override this to write data for a tile key. virtual Status writeImageImplementation(const TileKey&, const osg::Image*, ProgressCallback*) const; //! Modify the bbox if an altitude is set (for culling) virtual void modifyTileBoundingBox(const TileKey& key, osg::BoundingBox& box) const; //! Post processing image creation entry points GeoImage createImage( const GeoImage& canvas, const TileKey& key, ProgressCallback* progress); //! Override to write an image over top of an existing image virtual GeoImage createImageImplementation( const GeoImage& canvas, const TileKey& key, ProgressCallback* progress) const { return canvas; } //! Override to do something to an image before returning //! it from createImage (including a GeoImage read from the cache) virtual void postCreateImageImplementation( GeoImage& createdImage, const TileKey& key, ProgressCallback* progress) const { } protected: // Layer virtual void init() override; //! Open the layer for reading. virtual Status openImplementation() override; /** dtor */ virtual ~ImageLayer() { } //! Configure the layer to create textures via createTexture instead of //! using a createImage driver void setUseCreateTexture(); //! Apply a post-processing layers to the image virtual GeoImage applyPostLayer( const GeoImage& image, const TileKey& key, Layer* postLayer, ProgressCallback* progress) const; osg::ref_ptr _emptyImage; private: // Creates an image that's in the same profile as the provided key. GeoImage createImageInKeyProfile( const TileKey& key, ProgressCallback* progress); // Fetches multiple images from the TileSource; mosaics/reprojects/crops as necessary, and // returns a single tile. This is called by createImageFromTileSource() if the key profile // doesn't match the layer profile. GeoImage assembleImage( const TileKey& key, ProgressCallback* progress); // Creates an image that enhances the previous LOD's image // using a fractal algorithm. GeoImage createFractalUpsampledImage( const TileKey& key, ProgressCallback* p); optional _shareImageUnit; bool _useCreateTexture; void invoke_onCreate(const TileKey&, GeoImage&); typedef std::vector< osg::ref_ptr > Callbacks; Threading::Mutexed _callbacks; Mutexed>> _postLayers; Gate _sentry; osg::ref_ptr _nodataImage; }; typedef std::vector< osg::ref_ptr > ImageLayerVector; /** * Texture that loads its data asynchronously */ class OSGEARTH_EXPORT FutureTexture { public: virtual bool doneLoading() { update(); return _resolved; } virtual bool succeeded() { update(); return _resolved && !_failed; } virtual bool failed() { update(); return _resolved && _failed; } protected: FutureTexture() : _resolved(false), _failed(false) { } bool _resolved, _failed; virtual void update() = 0; }; class OSGEARTH_EXPORT FutureTexture2D : public osg::Texture2D, public FutureTexture { public: FutureTexture2D( ImageLayer* layer, const TileKey& key); protected: virtual ~FutureTexture2D() { } void update() override; private: TileKey _key; osg::ref_ptr _layer; mutable Future _result; void dispatch() const; }; } // namespace osgEarth OSGEARTH_SPECIALIZE_CONFIG(osgEarth::ImageLayer::Options);