diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp index 55b1ff058c4..2efea506deb 100644 --- a/src/mbgl/style/layer_impl.hpp +++ b/src/mbgl/style/layer_impl.hpp @@ -85,6 +85,7 @@ class Layer::Impl { float minZoom = -std::numeric_limits::infinity(); float maxZoom = std::numeric_limits::infinity(); VisibilityType visibility = VisibilityType::Visible; + bool enabled = false; LayerObserver nullObserver; LayerObserver* observer = &nullObserver; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index a00c5e4efcc..19baf702095 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -267,10 +267,20 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) { hasPendingTransitions = false; for (const auto& layer : layers) { - hasPendingTransitions |= layer->baseImpl->recalculate(parameters); + const bool hasTransitions = layer->baseImpl->recalculate(parameters); - Source* source = getSource(layer->baseImpl->source); - if (source && layer->baseImpl->needsRendering(z)) { + // Disable this layer if it doesn't need to be rendered. + const bool needsRendering = layer->baseImpl->needsRendering(z); + if (!needsRendering) { + layer->baseImpl->enabled = false; + continue; + } + + hasPendingTransitions |= hasTransitions; + layer->baseImpl->enabled = true; + + // If this layer has a source, make sure that it gets loaded. + if (Source* source = getSource(layer->baseImpl->source)) { source->baseImpl->enabled = true; if (!source->baseImpl->loaded) { source->baseImpl->loadDescription(fileSource); @@ -319,8 +329,9 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions) const { } for (const auto& layer : layers) { - if (layer->baseImpl->visibility == VisibilityType::None) + if (!layer->baseImpl->enabled) { continue; + } if (const BackgroundLayer* background = layer->as()) { if (debugOptions & MapDebugOptions::Overdraw) { @@ -400,6 +411,9 @@ std::vector Style::queryRenderedFeatures(const QueryParameters& paramet // Combine all results based on the style layer order. for (const auto& layer : layers) { + if (!layer->baseImpl->enabled) { + continue; + } auto it = resultsByLayer.find(layer->baseImpl->id); if (it != resultsByLayer.end()) { std::move(it->second.begin(), it->second.end(), std::back_inserter(result)); @@ -412,6 +426,9 @@ std::vector Style::queryRenderedFeatures(const QueryParameters& paramet float Style::getQueryRadius() const { float additionalRadius = 0; for (auto& layer : layers) { + if (!layer->baseImpl->enabled) { + continue; + } additionalRadius = util::max(additionalRadius, layer->baseImpl->getQueryRadius()); } return additionalRadius; diff --git a/test/fixtures/map/disabled_layers/first/expected.png b/test/fixtures/map/disabled_layers/first/expected.png new file mode 100644 index 00000000000..388180c6d15 Binary files /dev/null and b/test/fixtures/map/disabled_layers/first/expected.png differ diff --git a/test/fixtures/map/disabled_layers/second/expected.png b/test/fixtures/map/disabled_layers/second/expected.png new file mode 100644 index 00000000000..089ac0dde95 Binary files /dev/null and b/test/fixtures/map/disabled_layers/second/expected.png differ diff --git a/test/fixtures/map/disabled_layers/tile.png b/test/fixtures/map/disabled_layers/tile.png new file mode 100644 index 00000000000..089ac0dde95 Binary files /dev/null and b/test/fixtures/map/disabled_layers/tile.png differ diff --git a/test/map/map.cpp b/test/map/map.cpp index e78160a3246..1f4916873b2 100644 --- a/test/map/map.cpp +++ b/test/map/map.cpp @@ -229,6 +229,67 @@ TEST(Map, RemoveLayer) { test::checkImage("test/fixtures/map/remove_layer", test::render(map)); } +TEST(Map, DisabledSources) { + MapTest test; + + // Always load the same image tile for raster layers. + test.fileSource.response = [] (const Resource& res) -> optional { + if (res.url == "asset://tile.png") { + Response response; + response.data = std::make_shared( + util::read_file("test/fixtures/map/disabled_layers/tile.png")); + return {std::move(response)}; + } + return {}; + }; + + Map map(test.view, test.fileSource, MapMode::Still); + map.setZoom(1); + + // This stylesheet has two raster layers, one that starts at zoom 1, the other at zoom 0. + // We first render a map at zoom level 1, which should show both layers (both are "visible" due + // to an opacity of 0.5). Then, we are zooming back out to a zoom level of 0.5 and rerender. + // The "raster1" layer should not be visible anymore since it has minzoom 1, while "raster2" + // should still be there. Both layers have a distinct color through "raster-hue-rotate". + map.setStyleJSON(R"STYLE( +{ + "version": 8, + "name": "Test", + "sources": { + "raster": { + "type": "raster", + "tiles": [ "asset://tile.png" ], + "tileSize": 256 + } + }, + "layers": [{ + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, { + "id": "raster1", + "type": "raster", + "source": "raster", + "minzoom": 0 + }, { + "id": "raster2", + "type": "raster", + "source": "raster", + "minzoom": 1, + "paint": { + "raster-hue-rotate": 180 + } + }] +} +)STYLE"); + + test::checkImage("test/fixtures/map/disabled_layers/first", test::render(map)); + map.setZoom(0.5); + test::checkImage("test/fixtures/map/disabled_layers/second", test::render(map)); +} + TEST(Map, Classes) { MapTest test;