diff --git a/src/osgEarth/CMakeLists.txt b/src/osgEarth/CMakeLists.txt index 294919d0d5..ce83d6063a 100644 --- a/src/osgEarth/CMakeLists.txt +++ b/src/osgEarth/CMakeLists.txt @@ -114,6 +114,7 @@ SET(LIB_PUBLIC_HEADERS ColorFilter Common Composite + CompositeTiledModelLayer Config Containers Coverage @@ -260,7 +261,6 @@ SET(LIB_PUBLIC_HEADERS TileHandler TileMesher TileRasterizer - TiledFeatureModelGraph TiledFeatureModelLayer TiledModelLayer TileSource @@ -283,7 +283,6 @@ SET(LIB_PUBLIC_HEADERS WMS XmlUtils XYZ - XYZModelGraph XYZModelLayer ActivityMonitorTool @@ -551,6 +550,7 @@ set(TARGET_SRC Color.cpp ColorFilter.cpp Composite.cpp + CompositeTiledModelLayer.cpp Compressors.cpp Config.cpp CoverageLayer.cpp @@ -676,7 +676,6 @@ set(TARGET_SRC TileHandler.cpp TileMesher.cpp TileRasterizer.cpp - TiledFeatureModelGraph.cpp TiledFeatureModelLayer.cpp TiledModelLayer.cpp TileVisitor.cpp @@ -699,7 +698,6 @@ set(TARGET_SRC WMS.cpp XmlUtils.cpp XYZ.cpp - XYZModelGraph.cpp XYZModelLayer.cpp ActivityMonitorTool.cpp diff --git a/src/osgEarth/CompositeTiledModelLayer b/src/osgEarth/CompositeTiledModelLayer new file mode 100644 index 0000000000..05650aeeda --- /dev/null +++ b/src/osgEarth/CompositeTiledModelLayer @@ -0,0 +1,95 @@ +/* -*-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 + */ +#ifndef OSGEARTH_COMPOSITE_TILED_MODEL_LAYER +#define OSGEARTH_COMPOSITE_TILED_MODEL_LAYER 1 + +#include +#include +#include + +namespace osgEarth { + class Map; +} + +namespace osgEarth +{ + class OSGEARTH_EXPORT CompositeTiledModelLayer : public TiledModelLayer + { + public: // serialization + struct OSGEARTH_EXPORT Options : public TiledModelLayer::Options + { + META_LayerOptions(osgEarth, Options, TiledModelLayer::Options); + OE_OPTION(ProfileOptions, profile); + + OE_OPTION_VECTOR(ConfigOptions, layers); + + Config getConfig() const override; + void fromConfig(const Config& conf); + }; + + public: + META_Layer(osgEarth, CompositeTiledModelLayer, Options, TiledModelLayer, CompositeTiledModel); + + //! Tiling profile (required) + void setProfile(const Profile* profile); + const Profile* getProfile() const override { return _profile.get(); } + + unsigned getMinLevel() const override; + + //! Maximum level of detail to access + unsigned getMaxLevel() const override; + + public: // Layer + + //! opens the layer and returns the status + Status openImplementation() override; + + //! Serialization + Config getConfig() const override; + + public: // Layer + + //! called by the map when this layer is added + void addedToMap(const Map*) override; + + //! called by the map when this layer is removed + void removedFromMap(const Map*) override; + + protected: // TiledModelLayer + + //! Creates an OSG node from a tile key. + osg::ref_ptr createTileImplementation(const TileKey&, ProgressCallback*) const override; + + protected: + + virtual ~CompositeTiledModelLayer(); + + private: + osg::ref_ptr _profile; + osg::observer_ptr< const Map > _map; + + unsigned int _minLevel = 0; + unsigned int _maxLevel = 0; + + std::vector< osg::ref_ptr< TiledModelLayer > > _layers; + }; + +} // namespace osgEarth + +#endif // OSGEARTH_COMPOSITE_TILED_MODEL_LAYER diff --git a/src/osgEarth/CompositeTiledModelLayer.cpp b/src/osgEarth/CompositeTiledModelLayer.cpp new file mode 100644 index 0000000000..27893dc637 --- /dev/null +++ b/src/osgEarth/CompositeTiledModelLayer.cpp @@ -0,0 +1,191 @@ +/* -*-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 + */ +#include +#include +#include + +#include + +using namespace osgEarth; + +#define LC "[CompositeTiledModelLayer] " + +#define OE_TEST OE_NULL + +REGISTER_OSGEARTH_LAYER(CompositeTiledModel, CompositeTiledModelLayer); + +void CompositeTiledModelLayer::Options::fromConfig(const Config& conf) +{ + conf.get("profile", profile()); + + const ConfigSet& layers = conf.child("layers").children(); + for (ConfigSet::const_iterator i = layers.begin(); i != layers.end(); ++i) + { + _layers.push_back(ConfigOptions(*i)); + } +} + +Config +CompositeTiledModelLayer::Options::getConfig() const +{ + Config conf = TiledModelLayer::Options::getConfig(); + conf.set("profile", profile()); + + if (_layers.empty() == false) + { + Config layersConf("layers"); + for (std::vector::const_iterator i = _layers.begin(); i != _layers.end(); ++i) + { + layersConf.add(i->getConfig()); + } + conf.set(layersConf); + } + + return conf; +} + +//........................................................................... + +CompositeTiledModelLayer::~CompositeTiledModelLayer() +{ + //NOP +} + +void CompositeTiledModelLayer::setProfile(const Profile* profile) +{ + _profile = profile; + if (_profile) + { + options().profile() = profile->toProfileOptions(); + } +} + +Config +CompositeTiledModelLayer::getConfig() const +{ + Config conf = TiledModelLayer::getConfig(); + return conf; +} + +Status +CompositeTiledModelLayer::openImplementation() +{ + Status parent = super::openImplementation(); + if (parent.isError()) + return parent; + + _profile = Profile::create(*options().profile()); + + // Open all the layers + for (auto& layerConf : options().layers()) + { + osg::ref_ptr< Layer > layer = Layer::create(layerConf); + TiledModelLayer* tiledLayer = dynamic_cast(layer.get()); + if (tiledLayer) + { + tiledLayer->open(); + tiledLayer->setReadOptions(getReadOptions()); + _layers.push_back(tiledLayer); + } + else + { + OE_WARN << LC << "Layer is not a TiledModelLayer" << std::endl; + } + } + + return Status::NoError; +} + +void +CompositeTiledModelLayer::addedToMap(const Map* map) +{ + for (auto& layer : _layers) + { + layer->addedToMap(map); + } + + // Check to make sure the layers are all using the same profile + for (auto& layer : _layers) + { + if (!layer->getProfile()->isEquivalentTo(_profile)) + { + OE_WARN << LC << "Layer " << layer->getName() << " does not have the same profile as the composite layer" << std::endl; + } + } + + // Compute the min and max levels + if (!_layers.empty()) + { + _minLevel = 1000; + _maxLevel = 0; + for (auto& layer : _layers) + { + if (layer->getMinLevel() < _minLevel) + { + _minLevel = layer->getMinLevel(); + } + if (layer->getMaxLevel() > _maxLevel) + { + _maxLevel = layer->getMaxLevel(); + } + } + } + + super::addedToMap(map); +} + +void +CompositeTiledModelLayer::removedFromMap(const Map* map) +{ + super::removedFromMap(map); + + for (auto& layer : _layers) + { + layer->removedFromMap(map); + } +} + +osg::ref_ptr +CompositeTiledModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const +{ + osg::ref_ptr group = new osg::Group(); + + for (unsigned int i = 0; i < this->_layers.size(); i++) + { + osg::ref_ptr node = this->_layers[i]->createTile(key, progress); + if (node.valid()) + { + group->addChild(node); + } + } + return group; +} + +unsigned +CompositeTiledModelLayer::getMinLevel() const +{ + return _minLevel; +} + +unsigned +CompositeTiledModelLayer::getMaxLevel() const +{ + return _maxLevel; +} + diff --git a/src/osgEarth/TiledFeatureModelGraph.cpp b/src/osgEarth/TiledFeatureModelGraph.cpp deleted file mode 100644 index 1c95007d64..0000000000 --- a/src/osgEarth/TiledFeatureModelGraph.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* -*-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 - */ -#include -#include -#include -#include -#include - -using namespace osgEarth; - -TiledFeatureModelGraph::TiledFeatureModelGraph(const osgEarth::Map* map, - FeatureSource* features, - StyleSheet* styleSheet, - Session* session) : - SimplePager(map, (features && features->getFeatureProfile()) ? features->getFeatureProfile()->getTilingProfile() : nullptr), - _features(features), - _styleSheet(styleSheet), - _session(session) -{ - setMinLevel(features->getFeatureProfile()->getFirstLevel()); - setMaxLevel(features->getFeatureProfile()->getMaxLevel()); - - _session->setResourceCache(new ResourceCache()); - - - FeatureSourceIndexOptions indexOptions; - indexOptions.enabled() = true; - - _featureIndex = new FeatureSourceIndex( - features, - Registry::objectIndex(), - indexOptions); -} - -void -TiledFeatureModelGraph::setFilterChain(FeatureFilterChain* chain) -{ - _filterChain = chain; -} - -void -TiledFeatureModelGraph::setOwnerName(const std::string& value) -{ - _ownerName = value; -} - - -FeatureCursor* -TiledFeatureModelGraph::createCursor(FeatureSource* fs, FilterContext& cx, const Query& query, ProgressCallback* progress) const -{ - NetworkMonitor::ScopedRequestLayer layerRequest(_ownerName); - FeatureCursor* cursor = fs->createFeatureCursor(query, progress); - if (cursor && _filterChain.valid()) - { - cursor = new FilteredFeatureCursor(cursor, _filterChain.get(), &cx); - } - return cursor; -} - -osg::ref_ptr -TiledFeatureModelGraph::createNode(const TileKey& key, ProgressCallback* progress) -{ - if (progress && progress->isCanceled()) - return nullptr; - - NetworkMonitor::ScopedRequestLayer layerRequest(_ownerName); - // Get features for this key - Query query; - query.tileKey() = key; - - GeoExtent dataExtent = key.getExtent(); - - // set up for feature indexing if appropriate: - osg::ref_ptr< FeatureSourceIndexNode > index = 0L; - - if (_featureIndex.valid()) - { - index = new FeatureSourceIndexNode(_featureIndex.get()); - } - - FilterContext fc(_session.get(), new FeatureProfile(dataExtent), dataExtent, index); - - GeometryCompilerOptions options; - options.instancing() = true; - //options.mergeGeometry() = true; - GeometryCompiler gc(options); - - GeomFeatureNodeFactory factory(options); - - if (progress && progress->isCanceled()) - return nullptr; - - osg::ref_ptr< FeatureCursor > cursor = _features->createFeatureCursor( - query, - _filterChain.get(), - &fc, - progress); - - osg::ref_ptr node = new osg::Group; - if (cursor) - { - if (progress && progress->isCanceled()) - return nullptr; - - FeatureList features; - cursor->fill(features); - - if (_styleSheet->getSelectors().size() > 0) - { - osg::Group* group = new osg::Group; - - for (StyleSelectors::const_iterator i = _styleSheet->getSelectors().begin(); - i != _styleSheet->getSelectors().end(); - ++i) - { - typedef std::map< std::string, FeatureList > StyleToFeaturesMap; - StyleToFeaturesMap styleToFeatures; - - // pull the selected style... - const StyleSelector& sel = i->second; - - if (sel.styleExpression().isSet()) - { - // establish the working bounds and a context: - StringExpression styleExprCopy(sel.styleExpression().get()); - for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) - { - Feature* feature = itr->get(); - - feature->set("level", (long long)key.getLevelOfDetail()); - - const std::string& styleString = feature->eval(styleExprCopy, &fc); - if (!styleString.empty() && styleString != "null") - { - styleToFeatures[styleString].push_back(feature); - } - - if (progress && progress->isCanceled()) - return nullptr; - } - } - - std::unordered_map literal_styles; - - for (StyleToFeaturesMap::iterator itr = styleToFeatures.begin(); itr != styleToFeatures.end(); ++itr) - { - const std::string& styleString = itr->first; - Style* style = nullptr; - - if (styleString.length() > 0 && styleString[0] == '{') - { - Config conf("style", styleString); - conf.setReferrer(sel.styleExpression().get().uriContext().referrer()); - conf.set("type", "text/css"); - Style& literal_style = literal_styles[conf.toJSON()]; - if (literal_style.empty()) - literal_style = Style(conf); - style = &literal_style; - } - else - { - style = _styleSheet->getStyle(styleString); - } - - if (style) - { - osg::Group* styleGroup = factory.getOrCreateStyleGroup(*style, _session.get()); - osg::ref_ptr< osg::Node> styleNode; - osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(itr->second); - Query query; - factory.createOrUpdateNode(cursor.get(), *style, fc, styleNode, query); - if (styleNode.valid()) - { - styleGroup->addChild(styleNode); - if (!group->containsNode(styleGroup)) - { - group->addChild(styleGroup); - } - } - } - } - } - - - node = group; - } - else if (_styleSheet->getDefaultStyle()) - { - osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(features); - osg::ref_ptr< osg::Group > group = new osg::Group; - osg::ref_ptr< osg::Group > styleGroup = factory.getOrCreateStyleGroup(*_styleSheet->getDefaultStyle(), _session.get()); - osg::ref_ptr< osg::Node> styleNode; - factory.createOrUpdateNode(cursor.get(), *_styleSheet->getDefaultStyle(), fc, styleNode, query); - if (styleNode.valid()) - { - group->addChild(styleGroup); - styleGroup->addChild(styleNode); - node = group; - } - } - } - - if (!node->getBound().valid()) - { - return nullptr; - } - - if (index.valid()) - { - index->addChild(node); - return index; - } - - return node; -} \ No newline at end of file diff --git a/src/osgEarth/TiledFeatureModelLayer b/src/osgEarth/TiledFeatureModelLayer index 6829367bc1..09549c504c 100644 --- a/src/osgEarth/TiledFeatureModelLayer +++ b/src/osgEarth/TiledFeatureModelLayer @@ -76,10 +76,7 @@ namespace osgEarth //! Whether to support lighting void setEnableLighting(const bool& value); - const bool& getEnableLighting() const; - - //! Forces a rebuild on this FeatureModelLayer. - void dirty(); + const bool& getEnableLighting() const; public: // Layer @@ -89,9 +86,6 @@ namespace osgEarth // closes the layer Status closeImplementation() override; - // The Node representing this layer. - osg::Node* getNode() const override; - //! Extent of the feature layer, if available (INVALID if not) const GeoExtent& getExtent() const override; @@ -131,10 +125,8 @@ namespace osgEarth private: osg::ref_ptr _session; - osg::ref_ptr _root; - bool _graphDirty; - - void create(); + osg::ref_ptr _filters; + osg::ref_ptr< FeatureSourceIndex > _featureIndex; }; } // namespace osgEarth diff --git a/src/osgEarth/TiledFeatureModelLayer.cpp b/src/osgEarth/TiledFeatureModelLayer.cpp index e912238c1e..86ed286c5a 100644 --- a/src/osgEarth/TiledFeatureModelLayer.cpp +++ b/src/osgEarth/TiledFeatureModelLayer.cpp @@ -17,7 +17,8 @@ * along with this program. If not, see */ #include -#include +#include +#include using namespace osgEarth; @@ -86,26 +87,6 @@ void TiledFeatureModelLayer::init() { TiledModelLayer::init(); - - _root = new osg::Group(); - - // Assign the layer's state set to the root node: - _root->setStateSet(this->getOrCreateStateSet()); - - // Graph needs rebuilding - _graphDirty = true; - - // Depth sorting by default - getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); -} - -void TiledFeatureModelLayer::dirty() -{ - // feature source changed, so the graph needs rebuilding - _graphDirty = true; - - // create the scene graph - create(); } Config @@ -154,12 +135,6 @@ TiledFeatureModelLayer::getStyleSheet() const return options().styleSheet().getLayer(); } -osg::Node* -TiledFeatureModelLayer::getNode() const -{ - return _root.get(); -} - Status TiledFeatureModelLayer::openImplementation() { @@ -181,9 +156,9 @@ TiledFeatureModelLayer::openImplementation() Status TiledFeatureModelLayer::closeImplementation() { + super::closeImplementation(); options().featureSource().close(); options().styleSheet().close(); - _graphDirty = true; return getStatus(); } @@ -202,7 +177,7 @@ void TiledFeatureModelLayer::addedToMap(const Map* map) { OE_TEST << LC << "addedToMap" << std::endl; - TiledModelLayer::addedToMap(map); + options().featureSource().addedToMap(map); options().styleSheet().addedToMap(map); @@ -217,29 +192,36 @@ TiledFeatureModelLayer::addedToMap(const Map* map) getFeatureSource(), getReadOptions()); - // re-create the graph if necessary. - create(); + // connect the session to the features: + _session->setFeatureSource(getFeatureSource()); + _session->setResourceCache(new ResourceCache()); + + FeatureSourceIndexOptions indexOptions; + indexOptions.enabled() = true; + + _featureIndex = new FeatureSourceIndex( + getFeatureSource(), + Registry::objectIndex(), + indexOptions); } + + _filters = FeatureFilterChain::create(options().filters(), getReadOptions()); + + TiledModelLayer::addedToMap(map); } void TiledFeatureModelLayer::removedFromMap(const Map* map) { - TiledModelLayer::removedFromMap(map); + super::removedFromMap(map); options().featureSource().removedFromMap(map); options().styleSheet().removedFromMap(map); - if (_root.valid()) - { - osg::ref_ptr tfmg = findTopMostNodeOfType(_root.get()); - if (tfmg.valid()) tfmg->setDone(); - _root->removeChildren(0, _root->getNumChildren()); - } - _session = 0L; } +#if 0 void TiledFeatureModelLayer::create() { @@ -275,17 +257,163 @@ TiledFeatureModelLayer::create() } } } +#endif osg::ref_ptr TiledFeatureModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const { - osg::ref_ptr result; - auto fmg = osgEarth::findTopMostNodeOfType(_root.get()); - if (fmg) + if (progress && progress->isCanceled()) + return nullptr; + + NetworkMonitor::ScopedRequestLayer layerRequest(getName()); + // Get features for this key + Query query; + query.tileKey() = key; + + GeoExtent dataExtent = key.getExtent(); + + // set up for feature indexing if appropriate: + osg::ref_ptr< FeatureSourceIndexNode > index = 0L; + + if (_featureIndex.valid()) + { + index = new FeatureSourceIndexNode(_featureIndex.get()); + } + + FilterContext fc(_session.get(), new FeatureProfile(dataExtent), dataExtent, index); + + GeometryCompilerOptions options; + options.instancing() = true; + //options.mergeGeometry() = true; + GeometryCompiler gc(options); + + GeomFeatureNodeFactory factory(options); + + if (progress && progress->isCanceled()) + return nullptr; + + osg::ref_ptr< FeatureCursor > cursor = getFeatureSource()->createFeatureCursor( + query, + _filters.get(), + &fc, + progress); + + osg::ref_ptr node = new osg::Group; + if (cursor) + { + if (progress && progress->isCanceled()) + return nullptr; + + FeatureList features; + cursor->fill(features); + + if (getStyleSheet()->getSelectors().size() > 0) + { + osg::Group* group = new osg::Group; + + for (StyleSelectors::const_iterator i = getStyleSheet()->getSelectors().begin(); + i != getStyleSheet()->getSelectors().end(); + ++i) + { + typedef std::map< std::string, FeatureList > StyleToFeaturesMap; + StyleToFeaturesMap styleToFeatures; + + // pull the selected style... + const StyleSelector& sel = i->second; + + if (sel.styleExpression().isSet()) + { + // establish the working bounds and a context: + StringExpression styleExprCopy(sel.styleExpression().get()); + for (FeatureList::iterator itr = features.begin(); itr != features.end(); ++itr) + { + Feature* feature = itr->get(); + + feature->set("level", (long long)key.getLevelOfDetail()); + + const std::string& styleString = feature->eval(styleExprCopy, &fc); + if (!styleString.empty() && styleString != "null") + { + styleToFeatures[styleString].push_back(feature); + } + + if (progress && progress->isCanceled()) + return nullptr; + } + } + + std::unordered_map literal_styles; + + for (StyleToFeaturesMap::iterator itr = styleToFeatures.begin(); itr != styleToFeatures.end(); ++itr) + { + const std::string& styleString = itr->first; + Style* style = nullptr; + + if (styleString.length() > 0 && styleString[0] == '{') + { + Config conf("style", styleString); + conf.setReferrer(sel.styleExpression().get().uriContext().referrer()); + conf.set("type", "text/css"); + Style& literal_style = literal_styles[conf.toJSON()]; + if (literal_style.empty()) + literal_style = Style(conf); + style = &literal_style; + } + else + { + style = getStyleSheet()->getStyle(styleString); + } + + if (style) + { + osg::Group* styleGroup = factory.getOrCreateStyleGroup(*style, _session.get()); + osg::ref_ptr< osg::Node> styleNode; + osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(itr->second); + Query query; + factory.createOrUpdateNode(cursor.get(), *style, fc, styleNode, query); + if (styleNode.valid()) + { + styleGroup->addChild(styleNode); + if (!group->containsNode(styleGroup)) + { + group->addChild(styleGroup); + } + } + } + } + } + + + node = group; + } + else if (getStyleSheet()->getDefaultStyle()) + { + osg::ref_ptr< FeatureListCursor> cursor = new FeatureListCursor(features); + osg::ref_ptr< osg::Group > group = new osg::Group; + osg::ref_ptr< osg::Group > styleGroup = factory.getOrCreateStyleGroup(*getStyleSheet()->getDefaultStyle(), _session.get()); + osg::ref_ptr< osg::Node> styleNode; + factory.createOrUpdateNode(cursor.get(), *getStyleSheet()->getDefaultStyle(), fc, styleNode, query); + if (styleNode.valid()) + { + group->addChild(styleGroup); + styleGroup->addChild(styleNode); + node = group; + } + } + } + + if (!node->getBound().valid()) { - result = fmg->createNode(key, progress); + return nullptr; } - return result; + + if (index.valid()) + { + index->addChild(node); + return index; + } + + return node; } const Profile* diff --git a/src/osgEarth/TiledModelLayer b/src/osgEarth/TiledModelLayer index ce419e206e..66a6ca5336 100644 --- a/src/osgEarth/TiledModelLayer +++ b/src/osgEarth/TiledModelLayer @@ -68,10 +68,33 @@ namespace osgEarth void setRangeFactor(const float &value); const float& getRangeFactor() const; + //! Forces a rebuild on this layer. + void dirty(); + + public: // Layer + + // The Node representing this layer. + osg::Node* getNode() const override; + + // called by the map when this layer is added + void addedToMap(const Map*) override; + + // called by the map when this layer is removed + void removedFromMap(const Map*) override; + + // post-ctor initialization + void init() override; + protected: //! Subclasses must implement this to create a tile. //! @param key The tile key, in the underlying tiled data source's profile. //! @param progress A progress callback that can be checked for user cancellation. virtual osg::ref_ptr createTileImplementation(const TileKey& key, ProgressCallback* progress) const = 0; + + private: + osg::observer_ptr< const Map > _map; + osg::ref_ptr< osg::Group > _root; + bool _graphDirty; + void create(); }; } diff --git a/src/osgEarth/TiledModelLayer.cpp b/src/osgEarth/TiledModelLayer.cpp index 6cfae18c2a..4904ffd844 100644 --- a/src/osgEarth/TiledModelLayer.cpp +++ b/src/osgEarth/TiledModelLayer.cpp @@ -17,9 +17,29 @@ * along with this program. If not, see */ #include "TiledModelLayer" +#include +#include using namespace osgEarth; + +class TiledModelLayerPager : public SimplePager +{ +public: + TiledModelLayerPager(const Map* map, TiledModelLayer* layer): + SimplePager(map, layer->getProfile()), + _layer(layer) + { + } + + virtual osg::ref_ptr createNode(const TileKey& key, ProgressCallback* progress) override + { + return _layer->createTile(key, progress); + } + + osg::observer_ptr< TiledModelLayer > _layer; +}; + void TiledModelLayer::Options::fromConfig(const Config& conf) { additive().setDefault(false); @@ -79,3 +99,82 @@ TiledModelLayer::createTile(const TileKey& key, ProgressCallback* progress) cons return group; } } + +// The Node representing this layer. +osg::Node* TiledModelLayer::getNode() const +{ + return _root.get(); +} + +// called by the map when this layer is added +void +TiledModelLayer::addedToMap(const Map* map) +{ + super::addedToMap(map); + + _map = map; + + _graphDirty = true; + + // re-create the graph if necessary. + create(); +} + +// called by the map when this layer is removed +void +TiledModelLayer::removedFromMap(const Map* map) +{ + super::removedFromMap(map); + + if (_root.valid()) + { + osg::ref_ptr node = findTopMostNodeOfType(_root.get()); + if (node.valid()) node->setDone(); + _root->removeChildren(0, _root->getNumChildren()); + } +} + +void TiledModelLayer::dirty() +{ + _graphDirty = true; + + // create the scene graph + create(); +} + +// post-ctor initialization +void TiledModelLayer::init() +{ + super::init(); + + // Create the container group + + _root = new osg::Group(); + + // Assign the layer's state set to the root node: + _root->setStateSet(this->getOrCreateStateSet()); + + // Graph needs rebuilding + _graphDirty = true; + + // Depth sorting by default + getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); +} + +void TiledModelLayer::create() +{ + if (_map.valid() && _graphDirty) + { + _root->removeChildren(0, _root->getNumChildren()); + + TiledModelLayerPager* pager = new TiledModelLayerPager(_map.get(), this); + pager->setAdditive(this->getAdditive()); + pager->setRangeFactor(this->getRangeFactor()); + pager->setMinLevel(this->getMinLevel()); + pager->setMaxLevel(this->getMaxLevel()); + pager->build(); + // TODO: NVGL + _root->addChild(pager); + _graphDirty = false; + } +} \ No newline at end of file diff --git a/src/osgEarth/XYZModelGraph b/src/osgEarth/XYZModelGraph deleted file mode 100644 index a024ea51d8..0000000000 --- a/src/osgEarth/XYZModelGraph +++ /dev/null @@ -1,63 +0,0 @@ -/* --*-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 - */ - -#ifndef OSGEARTH_XYZ_MODEL_GRAPH_H -#define OSGEARTH_XYZ_MODEL_GRAPH_H 1 - -#include -#include -#include -#include -#include - -#include -#include - -namespace osgEarth { - - /** - * A scene graph node that loads pre-tiled quadtree model data. - */ - class OSGEARTH_EXPORT XYZModelGraph : public SimplePager - { - public: - XYZModelGraph(const osgEarth::Map* map, const Profile* profile, const URI& url, bool invertY, const osgDB::Options* options); - - void setOwnerName(const std::string& value); - - //! Whether to attempt to use NVGL extensions - void setUseNVGL(bool value); - - public: // SimplePager - - virtual osg::ref_ptr createNode(const TileKey& key, ProgressCallback* progress) override; - - private: - std::string _ownerName; - URI _url; - bool _invertY; - osg::ref_ptr< osgEarth::StateSetCache > _statesetCache; - osg::ref_ptr< osgDB::Options > _options; - osg::ref_ptr< TextureArena > _textures; - mutable std::vector _texturesCache; - mutable std::mutex _texturesCacheMutex; - }; -} - -#endif // OSGEARTH_XYZ_MODEL_GRAPH_H diff --git a/src/osgEarth/XYZModelGraph.cpp b/src/osgEarth/XYZModelGraph.cpp deleted file mode 100644 index 2563310146..0000000000 --- a/src/osgEarth/XYZModelGraph.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* -*-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 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace osgEarth; - -XYZModelGraph::XYZModelGraph(const osgEarth::Map* map, const Profile* profile, const URI& url, bool invertY, const osgDB::Options* options) : - SimplePager(map, profile), - _url(url), - _invertY(invertY) -{ - _options = osgEarth::Registry::instance()->cloneOrCreateOptions(options); - _options->setObjectCacheHint(osgDB::Options::CACHE_IMAGES); - - _statesetCache = new StateSetCache(); -} - -void -XYZModelGraph::setUseNVGL(bool value) -{ - if (value == true && GLUtils::useNVGL() && !_textures.valid()) - { - _textures = new TextureArena(); - getOrCreateStateSet()->setAttribute(_textures, 1); - - // auto release requires that we install this update callback! - _textures->setAutoRelease(true); - - addUpdateCallback(new LambdaCallback<>([this](osg::NodeVisitor& nv) - { - _textures->update(nv); - return true; - })); - - getOrCreateStateSet()->setAttributeAndModes( - new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - } -} - -void -XYZModelGraph::setOwnerName(const std::string& value) -{ - _ownerName = value; -} - -osg::ref_ptr -XYZModelGraph::createNode(const TileKey& key, ProgressCallback* progress) -{ - OE_PROFILING_ZONE; - if (progress && progress->isCanceled()) - return nullptr; - - NetworkMonitor::ScopedRequestLayer layerRequest(_ownerName); - - unsigned x, y; - key.getTileXY(x, y); - unsigned cols = 0, rows = 0; - key.getProfile()->getNumTiles(key.getLevelOfDetail(), cols, rows); - unsigned inverted_y = rows - y - 1; - - if (_invertY == true) - { - y = inverted_y; - } - - std::string location = _url.full(); - - // support OpenLayers template style: - replaceIn(location, "${x}", Stringify() << x); - replaceIn(location, "${y}", Stringify() << y); - replaceIn(location, "${-y}", Stringify() << inverted_y); - replaceIn(location, "${z}", Stringify() << key.getLevelOfDetail()); - - - // failing that, legacy osgearth style: - replaceIn(location, "{x}", Stringify() << x); - replaceIn(location, "{y}", Stringify() << y); - replaceIn(location, "{-y}", Stringify() << inverted_y); - replaceIn(location, "{z}", Stringify() << key.getLevelOfDetail()); - - URI myUri(location, _url.context()); - - osg::ref_ptr< osg::Node > node = myUri.readNode(_options.get()).getNode(); - if (node.valid()) - { - if (_textures.valid()) - { - auto xform = findTopMostNodeOfType(node.get()); - - // Convert the geometry into chonks - ChonkFactory factory(_textures); - - factory.setGetOrCreateFunction( - ChonkFactory::getWeakTextureCacheFunction( - _texturesCache, _texturesCacheMutex)); - - osg::ref_ptr drawable = new ChonkDrawable(); - - if (xform) - { - for (unsigned i = 0; i < xform->getNumChildren(); ++i) - { - drawable->add(xform->getChild(i), factory); - } - xform->removeChildren(0, xform->getNumChildren()); - xform->addChild(drawable); - node = xform; - } - else - { - if (drawable->add(node.get(), factory)) - { - node = drawable; - } - } - } - else - { - osgEarth::Registry::shaderGenerator().run(node.get(), _statesetCache); - } - return node.release(); - } - return nullptr; -} \ No newline at end of file diff --git a/src/osgEarth/XYZModelLayer b/src/osgEarth/XYZModelLayer index 79ebb12cb0..4714e167f2 100644 --- a/src/osgEarth/XYZModelLayer +++ b/src/osgEarth/XYZModelLayer @@ -23,20 +23,23 @@ #include #include #include +#include +#include + namespace osgEarth { class Map; } namespace osgEarth -{ +{ /** * Layer that loads a pregenerated quadtree of model files */ class OSGEARTH_EXPORT XYZModelLayer : public TiledModelLayer { public: // serialization - struct OSGEARTH_EXPORT Options : public TiledModelLayer::Options + struct OSGEARTH_EXPORT Options : public TiledModelLayer::Options { META_LayerOptions(osgEarth, Options, TiledModelLayer::Options); OE_OPTION(URI, url); @@ -77,32 +80,17 @@ namespace osgEarth void setMaxLevel(unsigned value); unsigned getMaxLevel() const override; - //! Forces a rebuild on this layer. - void dirty(); - public: // Layer //! opens the layer and returns the status Status openImplementation() override; - //! closes the layer - Status closeImplementation() override; - - //! The Node representing this layer. - osg::Node* getNode() const override; + void addedToMap(const Map* map) override; //! Serialization Config getConfig() const override; - public: // Layer - - //! called by the map when this layer is added - void addedToMap(const Map*) override; - - //! called by the map when this layer is removed - void removedFromMap(const Map*) override; - - //! post-ctor initialization + // post-ctor initialization void init() override; protected: // TiledModelLayer @@ -115,12 +103,13 @@ namespace osgEarth virtual ~XYZModelLayer(); private: - osg::ref_ptr _root; osg::ref_ptr _profile; - osg::observer_ptr< const Map > _map; - bool _graphDirty; - - void create(); + + osg::ref_ptr< osgEarth::StateSetCache > _statesetCache; + osg::ref_ptr< osgDB::Options > _readOptions; + osg::ref_ptr< TextureArena > _textures; + mutable std::vector _texturesCache; + mutable std::mutex _texturesCacheMutex; }; } // namespace osgEarth diff --git a/src/osgEarth/XYZModelLayer.cpp b/src/osgEarth/XYZModelLayer.cpp index fbeaa9e6ff..fdcd6a6678 100644 --- a/src/osgEarth/XYZModelLayer.cpp +++ b/src/osgEarth/XYZModelLayer.cpp @@ -17,8 +17,14 @@ * along with this program. If not, see */ #include -#include #include +#include +#include +#include +#include +#include +#include +#include using namespace osgEarth; @@ -75,44 +81,52 @@ XYZModelLayer::getMaxLevel() const { return options().maxLevel().get(); } - -XYZModelLayer::~XYZModelLayer() +void XYZModelLayer::init() { - //NOP + super::init(); } -void XYZModelLayer::setProfile(const Profile* profile) +void XYZModelLayer::addedToMap(const Map* map) { - _profile = profile; - if (_profile) - { - options().profile() = profile->toProfileOptions(); - } -} + _readOptions = osgEarth::Registry::instance()->cloneOrCreateOptions(getReadOptions()); + _readOptions->setObjectCacheHint(osgDB::Options::CACHE_IMAGES); -void -XYZModelLayer::init() -{ - super::init(); + _statesetCache = new StateSetCache(); - _root = new osg::Group(); + if (*options().useNVGL() == true && GLUtils::useNVGL() && !_textures.valid()) + { + _textures = new TextureArena(); + getOrCreateStateSet()->setAttribute(_textures, 1); - // Assign the layer's state set to the root node: - _root->setStateSet(this->getOrCreateStateSet()); + // auto release requires that we install this update callback! + _textures->setAutoRelease(true); - // Graph needs rebuilding - _graphDirty = true; + getNode()->addUpdateCallback(new LambdaCallback<>([this](osg::NodeVisitor& nv) + { + _textures->update(nv); + return true; + })); - // Depth sorting by default - getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + getOrCreateStateSet()->setAttributeAndModes( + new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } + + super::addedToMap(map); } -void XYZModelLayer::dirty() +XYZModelLayer::~XYZModelLayer() { - _graphDirty = true; + //NOP +} - // create the scene graph - create(); +void XYZModelLayer::setProfile(const Profile* profile) +{ + _profile = profile; + if (_profile) + { + options().profile() = profile->toProfileOptions(); + } } Config @@ -122,12 +136,6 @@ XYZModelLayer::getConfig() const return conf; } -osg::Node* -XYZModelLayer::getNode() const -{ - return _root.get(); -} - Status XYZModelLayer::openImplementation() { @@ -140,73 +148,82 @@ XYZModelLayer::openImplementation() return Status::NoError; } -Status -XYZModelLayer::closeImplementation() +osg::ref_ptr +XYZModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const { - _graphDirty = true; - return getStatus(); -} + OE_PROFILING_ZONE; + if (progress && progress->isCanceled()) + return nullptr; -void -XYZModelLayer::addedToMap(const Map* map) -{ - OE_TEST << LC << "addedToMap" << std::endl; - super::addedToMap(map); + NetworkMonitor::ScopedRequestLayer layerRequest(getName()); - _map = map; + unsigned x, y; + key.getTileXY(x, y); + unsigned cols = 0, rows = 0; + key.getProfile()->getNumTiles(key.getLevelOfDetail(), cols, rows); + unsigned inverted_y = rows - y - 1; - _graphDirty = true; + if (*options().invertY() == true) + { + y = inverted_y; + } - // re-create the graph if necessary. - create(); -} + std::string location = options().url()->full(); -void -XYZModelLayer::removedFromMap(const Map* map) -{ - super::removedFromMap(map); + // support OpenLayers template style: + replaceIn(location, "${x}", Stringify() << x); + replaceIn(location, "${y}", Stringify() << y); + replaceIn(location, "${-y}", Stringify() << inverted_y); + replaceIn(location, "${z}", Stringify() << key.getLevelOfDetail()); - if (_root.valid()) - { - osg::ref_ptr node = findTopMostNodeOfType(_root.get()); - if (node.valid()) node->setDone(); - _root->removeChildren(0, _root->getNumChildren()); - } -} -void -XYZModelLayer::create() -{ - OE_TEST << LC << "create" << std::endl; - - if (_graphDirty && _profile) - { - osg::ref_ptr xyzGraph = new XYZModelGraph(_map.get(), _profile.get(), *_options->url(), *_options->invertY(), getReadOptions()); - xyzGraph->setOwnerName(getName()); - xyzGraph->setAdditive(*_options->additive()); - xyzGraph->setMinLevel(*_options->minLevel()); - xyzGraph->setMaxLevel(*_options->maxLevel()); - xyzGraph->setRangeFactor(*_options->rangeFactor()); - xyzGraph->setSceneGraphCallbacks(getSceneGraphCallbacks()); - xyzGraph->setUseNVGL(options().useNVGL().get()); - xyzGraph->build(); - - _root->removeChildren(0, _root->getNumChildren()); - _root->addChild(xyzGraph.get()); - - // clear the dirty flag. - _graphDirty = false; - - setStatus(Status::OK()); - } -} + // failing that, legacy osgearth style: + replaceIn(location, "{x}", Stringify() << x); + replaceIn(location, "{y}", Stringify() << y); + replaceIn(location, "{-y}", Stringify() << inverted_y); + replaceIn(location, "{z}", Stringify() << key.getLevelOfDetail()); -osg::ref_ptr -XYZModelLayer::createTileImplementation(const TileKey& key, ProgressCallback* progress) const -{ - auto pager = osgEarth::findTopMostNodeOfType(_root.get()); - if (pager) - return pager->createNode(key, progress); - else - return {}; + URI myUri(location, options().url()->context()); + + osg::ref_ptr< osg::Node > node = myUri.readNode(_readOptions.get()).getNode(); + if (node.valid()) + { + if (_textures.valid()) + { + auto xform = findTopMostNodeOfType(node.get()); + + // Convert the geometry into chonks + ChonkFactory factory(_textures); + + factory.setGetOrCreateFunction( + ChonkFactory::getWeakTextureCacheFunction( + _texturesCache, _texturesCacheMutex)); + + osg::ref_ptr drawable = new ChonkDrawable(); + + if (xform) + { + for (unsigned i = 0; i < xform->getNumChildren(); ++i) + { + drawable->add(xform->getChild(i), factory); + } + xform->removeChildren(0, xform->getNumChildren()); + xform->addChild(drawable); + node = xform; + } + else + { + if (drawable->add(node.get(), factory)) + { + node = drawable; + } + } + } + else + { + osgEarth::Registry::shaderGenerator().run(node.get(), _statesetCache); + } + return node.release(); + } + return nullptr; }