/* -*-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 #include #include #include #include #include #include namespace osg { class StateSet; } namespace osgDB { class Options; } //! Macro to use when defining a LayerOptions class #define META_LayerOptions(LIBRARY, MYCLASS, SUPERCLASS) \ protected: \ virtual void mergeConfig(const osgEarth::Config& conf) { \ SUPERCLASS ::mergeConfig(conf); \ fromConfig(conf); \ } \ using super = SUPERCLASS; \ public: \ OE_COMMENT("Construct empty layer options") \ MYCLASS () : SUPERCLASS() { fromConfig(_conf); } \ \ OE_COMMENT("Construct layer options from serialized data") \ MYCLASS (const osgEarth::ConfigOptions& opt) : SUPERCLASS(opt) { fromConfig(_conf); } \ \ osgEarth::Config& _internal() { return _conf; } \ const osgEarth::Config& _internal() const { return _conf; } //! Macro to use when defining a Layer class #define META_Layer(LIBRARY, MYCLASS, OPTIONS, SUPERCLASS, SLUG) \ private: \ OPTIONS * _options; \ OPTIONS _optionsConcrete; \ const OPTIONS * _options0; \ const OPTIONS _optionsConcrete0; \ MYCLASS ( const MYCLASS& rhs, const osg::CopyOp& op ) { } \ using super = SUPERCLASS; \ protected: \ OE_COMMENT("Construct a new layer with default options") \ MYCLASS (OPTIONS* optr, const OPTIONS* optr0) : \ SUPERCLASS (optr? optr: &_optionsConcrete, optr0? optr0 : &_optionsConcrete0), \ _options(optr ? optr : &_optionsConcrete), \ _options0(optr0 ? optr0 : &_optionsConcrete0) { } \ public: \ META_Object(LIBRARY, MYCLASS); \ \ OE_COMMENT("Construct a new layer with default options") \ MYCLASS () : \ SUPERCLASS (&_optionsConcrete, &_optionsConcrete0), \ _options(&_optionsConcrete), \ _options0(&_optionsConcrete0) { MYCLASS::init(); } \ \ OE_COMMENT("Construct a new layer with user-defined options") \ MYCLASS (const OPTIONS& o) : \ SUPERCLASS (&_optionsConcrete, &_optionsConcrete0), \ _options(&_optionsConcrete), _optionsConcrete(o), \ _options0(&_optionsConcrete0), _optionsConcrete0(o) { MYCLASS::init(); } \ \ OE_COMMENT("Mutable options for this layer") \ OPTIONS& options() { return *_options; } \ \ OE_COMMENT("Immutable options for this layer") \ const OPTIONS& options() const { return *_options; } \ \ OE_COMMENT("Immutable original (constructor) options for this layer") \ const OPTIONS& options_original() const { return *_options0; } \ \ OE_COMMENT("Configuration key for this layer (e.g. for earth files)") \ virtual const char* getConfigKey() const { return #SLUG ; } //! Macro for defining a layer with a default Options structure #define META_LayerNoOptions(LIBRARY, MYCLASS, SUPERCLASS, SLUG) \ public: \ struct Options : public SUPERCLASS::Options { \ META_LayerOptions(LIBRARY, Options, SUPERCLASS::Options); \ private: \ void fromConfig(const osgEarth::Config&) { } \ }; \ META_Layer(LIBRARY, MYCLASS, Options, SUPERCLASS, SLUG) //! Macro to use when defining a Layer class #define META_Layer_Abstract(LIBRARY, MYCLASS, OPTIONS, SUPERCLASS) \ private: \ OPTIONS * _options; \ const OPTIONS * _options0; \ MYCLASS ( const MYCLASS& rhs, const osg::CopyOp& op ) { } \ protected: \ OE_COMMENT("Construct a new layer with default options") \ MYCLASS (OPTIONS* optr, const OPTIONS* optr0) : \ SUPERCLASS (optr, optr0), \ _options(optr), \ _options0(optr0) { } \ MYCLASS () : SUPERCLASS () { } \ using super = SUPERCLASS; \ public: \ OE_COMMENT("Mutable options for this layer") \ OPTIONS& options() { return *_options; } \ \ OE_COMMENT("Immutable options for this layer") \ const OPTIONS& options() const { return *_options; } \ \ OE_COMMENT("Immutable original (constructor) options for this layer") \ const OPTIONS& options_original() const { return *_options0; } //! Templated inline property implementation macro #define OE_LAYER_PROPERTY_IMPL(CLASS, TYPE, FUNC, OPTION) \ void CLASS ::set ## FUNC (const TYPE & value) { options(). OPTION () = value; }\ const TYPE & CLASS ::get ## FUNC () const { return options(). OPTION ().get(); } namespace osgEarth { class GeoExtent; class SequenceControl; class TerrainEngine; class TerrainResources; class TileKey; //! Base class for layer property callbacks struct LayerCallback : public osg::Referenced { virtual void onOpen(class Layer*) { } virtual void onClose(class Layer*) { } typedef void (LayerCallback::*MethodPtr)(class Layer* layer); }; /** * Base class for all Map layers. * * Subclass Layer to create a new layer type. Use the META_Layer macro * to establish the standard options framework. * * When you create a Layer, init() is called. Do all one-time construction * activity where. * * When you add a Layer to a Map, the follow methods are called in order: * * setReadOptions() sets OSG options for IO activity; * open() to initialize any underlying data sources; * addedToMap() to signal to the layer that it is now a member of a Map. */ class OSGEARTH_EXPORT Layer : public osg::Object { public: META_Object(osgEarth, Layer); /** Layer options for serialization */ class OSGEARTH_EXPORT Options : public ConfigOptions { public: META_LayerOptions(osgEarth, Options, ConfigOptions); OE_OPTION(std::string, name); OE_OPTION(bool, openAutomatically, true); OE_OPTION(bool, terrainPatch, false); OE_OPTION(std::string, cacheId); OE_OPTION(CachePolicy, cachePolicy); OE_OPTION(std::string, shaderDefine); OE_OPTION(std::string, attribution); OE_OPTION(ShaderOptions, shader); OE_OPTION_VECTOR(ShaderOptions, shaders); OE_OPTION(ProxySettings, proxySettings); OE_OPTION(std::string, osgOptionString); OE_OPTION(unsigned, l2CacheSize, 0u); virtual Config getConfig() const; private: void fromConfig(const Config& conf); }; public: //! Hints that a layer can set to influence the operation of //! the map engine class Hints { public: OE_OPTION(CachePolicy, cachePolicy); OE_OPTION(unsigned, L2CacheSize); OE_OPTION(bool, dynamic); }; public: //! Constructs a map layer Layer(); //! This layer's unique ID. //! This value is generated automatically at runtime and is not //! guaranteed to be the same from one run to the next. UID getUID() const { return _uid; } //! osgDB read options for this Layer. //! If you set this, do so prior to calling open(). virtual void setReadOptions(const osgDB::Options* options); //! osgDB read options for this Layer. const osgDB::Options* getReadOptions() const; //! Open a layer. virtual Status open() final; //! Open a layer. Shortcut for calling setReadOptions() followed by open(). virtual Status open(const osgDB::Options* options) final; //! Close this layer. virtual Status close(); //! Whether the layer is open bool isOpen() const; //! Status of this layer const Status& getStatus() const; //! @deprecated (remove after 2.10) //! Sequence controller if the layer has one. virtual SequenceControl* getSequenceControl() { return 0L; } //! Serialize this layer into a Config object (if applicable) virtual Config getConfig() const; //! Whether to automatically open this layer (by calling open) when //! adding the layer to a Map or when opening a map containing this Layer. virtual void setOpenAutomatically(bool value); //! Whether to automatically open this layer (by calling open) when //! adding the layer to a Map or when opening a map containing this Layer. virtual bool getOpenAutomatically() const; //! Cacheing policy. Only set this before opening the layer or adding to a map. void setCachePolicy(const CachePolicy& value); const CachePolicy& getCachePolicy() const; //! Optional scene graph provided by the layer. //! When this layer is added to a Map, the MapNode will call this method and //! add the return value to its scene graph; and remove it when the Layer //! is removed from the Map. virtual osg::Node* getNode() const { return 0L; } //! Extent of this layer's data. //! This method may return GeoExtent::INVALID which means that the //! extent is unavailable (not necessarily that there is no data). virtual const GeoExtent& getExtent() const; //! Temporal extent of this layer's data. virtual DateTimeExtent getDateTimeExtent() const; //! Unique caching ID for this layer. //! Only set this before opening the layer or adding to a map. //! WARNING: You should be Very Careful when using this. The Layer will //! automatically generate a cache ID that is sufficient most of the time. //! Setting your own cache ID will require manual cache invalidation when //! you change certain properties. Use are your own risk! void setCacheID(const std::string& value); virtual std::string getCacheID() const; //! Callbacks that one can use to detect scene graph changes SceneGraphCallbacks* getSceneGraphCallbacks() const; //! Hints that a subclass can set to influence the engine const Hints& getHints() const; //! Options string to pass to OpenSceneGraph reader/writers const std::string& getOsgOptionString() const; public: //! Layer's stateset, creating it is necessary osg::StateSet* getOrCreateStateSet(); //! Layer's stateset, or NULL if none exists osg::StateSet* getStateSet() const; //! Stateset that should be applied to an entire terrain traversal virtual osg::StateSet* getSharedStateSet(osg::NodeVisitor* nv) const { return NULL; } //! How (and if) to use this layer when rendering terrain tiles. enum RenderType { //! Layer does not draw anything (directly) RENDERTYPE_NONE, //! Layer requires a terrain rendering pass that draws terrain tiles with texturing RENDERTYPE_TERRAIN_SURFACE, //! Layer requires a terrain rendering pass that emits terrian patches or //! invokes a custom drawing function RENDERTYPE_TERRAIN_PATCH, //! Layer that renders its own node graph or other geometry (no terrain) RENDERTYPE_CUSTOM = RENDERTYPE_NONE }; //! Rendering type of this layer RenderType getRenderType() const { return _renderType; } //! Rendering type of this layer void setRenderType(RenderType value) { _renderType = value; } //! Callback that modifies the layer's bounding box for a given tile key virtual void modifyTileBoundingBox(const TileKey& key, osg::BoundingBox& box) const; //! Class type name without namespace. For example if the leaf class type const char* getTypeName() const; //! Attribution to be displayed by the application virtual std::string getAttribution() const; //! Attribution to be displayed by the application virtual void setAttribution(const std::string& attribution); //! Set a serialized user property void setUserProperty( const std::string& key, const std::string& value); //! Get a serialized user property template inline T getUserProperty( const std::string& key, T fallback) const; public: //! Traversal callback class OSGEARTH_EXPORT TraversalCallback : public osg::Callback { public: virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) const =0; protected: void traverse(osg::Node* node, osg::NodeVisitor* nv) const; }; //! Callback invoked by the terrain engine on this layer before applying //! @deprecated replace with cull() override void setCullCallback(TraversalCallback* tc); const TraversalCallback* getCullCallback() const; //! Called to traverse this layer //! @deprecated Replace with cull() override void apply(osg::Node* node, osg::NodeVisitor* nv) const; //! Called by the terrain engine during the update traversal virtual void update(osg::NodeVisitor& nv) { } //! Map will call this function when this Layer is added to a Map. virtual void addedToMap(const class Map*) { } //! Map will call this function when this Layer is removed from a Map. virtual void removedFromMap(const class Map*) { } public: // osg::Object virtual void setName(const std::string& name); virtual void resizeGLObjectBuffers(unsigned maxSize); virtual void releaseGLObjects(osg::State* state) const; public: // Public internal methods //! Creates a layer from serialized data - internal use static osg::ref_ptr create(const ConfigOptions& options); //! Creates a layer from serialized data and attempt to cast it //! to a specific type template static osg::ref_ptr create_as(const ConfigOptions& options) { auto layer = create(options); return osg::ref_ptr(dynamic_cast(layer.get())); } //! Extracts config options from a DB options - internal use static const ConfigOptions& getConfigOptions(const osgDB::Options*); //! Adds a property notification callback to this layer void addCallback(LayerCallback* cb); //! Removes a property notification callback from this layer void removeCallback(LayerCallback* cb); //! Revision number of this layer int getRevision() const { return (int)_revision; } //! Increment the revision number for this layer, which will //! invalidate caches. virtual void dirty(); class Options; public: // deprecated //! @deprecated - use getOpenAutomatically bool getEnabled() const; //! @deprecated - use setOpenAutomatically void setEnabled(bool value); protected: //! Constructs a map layer by deserializing options. Layer( Layer::Options* options, const Layer::Options* options0); //! DTOR virtual ~Layer(); //! post-ctor initialization, chain to subclasses. //! MAKE SURE you call the superclass init() if you override this! virtual void init(); //! Called by open() to connect to external resources and return a status. //! MAKE SURE you call superclass openImplementation() if you override this! //! This is where you will connect to back-end data sources if //! appropriate. When added to a map, init() is called before open() //! and addedToMap() is called after open() if it succeeds. //! By default, returns STATUS_OK. virtual Status openImplementation(); //! Called by close() to shut down the resources associated with a layer. virtual Status closeImplementation(); //! Prepares the layer for rendering if necessary. virtual void prepareForRendering(TerrainEngine*); //! Sets the status for this layer - internal const Status& setStatus(const Status& status) const; //! Sets the status for this layer with a message - internal const Status& setStatus(const Status::Code& statusCode, const std::string& message) const; //! invoke layer callbacks void fireCallback(LayerCallback::MethodPtr); //! mutable layer hints for the subclass to optionally access Hints& layerHints(); //! MapNode will call this function when terrain resources are available. //! @deprecated Implement prepareForRendering instead virtual void setTerrainResources(TerrainResources*) { } private: const std::string& _layerName; UID _uid; osg::ref_ptr _stateSet; RenderType _renderType; mutable Status _status; osg::ref_ptr _sceneGraphCallbacks; osg::ref_ptr _traversalCallback; Hints _hints; std::atomic_int _revision = { 1 }; std::string _runtimeCacheId; osg::ref_ptr _readOptions; osg::ref_ptr _cacheSettings; std::vector > _shaders; mutable Threading::ReadWriteMutex _inuse_mutex; //! Prepares the layer for rendering if necessary. void invoke_prepareForRendering(TerrainEngine*); protected: typedef std::vector > CallbackVector; CallbackVector _callbacks; osgDB::Options* getMutableReadOptions() { return _readOptions.get(); } void bumpRevision(); // subclass can call this to change an option that requires // a re-opening of the layer. template void setOptionThatRequiresReopen(T& target, const V& value); // subclass can call this to change an option that requires // a re-opening of the layer. template void resetOptionThatRequiresReopen(T& target); //! internal cache information CacheSettings* getCacheSettings() { return _cacheSettings.get(); } const CacheSettings* getCacheSettings() const { return _cacheSettings.get(); } //! subclass access to a mutex that serializes the //! Layer open and close methods with respect to any asynchronous //! functions that require the layer to remain open Threading::ReadWriteMutex& inUseMutex() const { return _inuse_mutex; } //! Layers that this layer wants to add to the map std::vector> _sublayers; public: Layer::Options& options() { return *_options; } const Layer::Options& options() const { return *_options; } const Layer::Options& options_original() const { return *_options0; } virtual const char* getConfigKey() const { return "layer" ; } //! A layer can report statistics for debugging by overriding this function using Stats = std::vector>; virtual Stats reportStats() const { return {}; } private: Layer::Options * _options; Layer::Options _optionsConcrete; const Layer::Options * _options0; const Layer::Options _optionsConcrete0; // no copying Layer(const Layer& rhs, const osg::CopyOp& op); // allow the map access to the addedToMap/removedFromMap methods friend class Map; friend class MapNode; }; using LayerVector = std::vector>; template void Layer::setOptionThatRequiresReopen(T& target, const V& value) { if (target != value) { bool wasOpen = isOpen(); if (wasOpen) close(); target = value; if (wasOpen) open(); } } template void Layer::resetOptionThatRequiresReopen(T& target) { if (target.isSet()) { bool wasOpen = isOpen(); if (wasOpen) close(); target.unset(); if (wasOpen) open(); } } template T Layer::getUserProperty(const std::string& key, T fallback) const { return options()._internal().value(key, fallback); } #define REGISTER_OSGEARTH_LAYER(NAME,CLASS) \ extern "C" void osgdb_osgearth_##NAME(void) {} \ static osgEarth::RegisterPluginLoader< osgEarth::PluginLoader > g_proxy_##CLASS_##NAME(OE_STRINGIFY(osgearth_layer_##NAME)); #define USE_OSGEARTH_LAYER(NAME) \ extern "C" void osgdb_osgearth_##NAME(void); \ static osgDB::PluginFunctionProxy proxy_osgearth_layer_##NAME(OE_STRINGIFY(osgdb_osgearth_##NAME)); } // namespace osgEarth