summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordanswick <dan.swick@gmail.com>2019-09-18 11:39:43 -0700
committerdanswick <dan.swick@gmail.com>2019-09-18 11:39:43 -0700
commit46914ecff8b3f2a1945b33358a879c2aac074f17 (patch)
tree697cf276a43ae4c18c0ad7029c00e7d771448822
parent47ea84ad1a5fed3431d026c5765c17c507d4623e (diff)
parent8805defe57aa0d8886c7828d39b1b9b1f17f21b8 (diff)
downloadqtlocation-mapboxgl-upstream/android-docs-automation.tar.gz
Merge branch 'master' into android-docs-automationupstream/android-docs-automation
-rw-r--r--.clang-format2
-rw-r--r--circle.yml4
-rw-r--r--include/mbgl/renderer/renderer.hpp9
-rw-r--r--include/mbgl/style/expression/expression.hpp8
-rw-r--r--include/mbgl/style/layer.hpp6
-rw-r--r--include/mbgl/style/property_expression.hpp4
-rw-r--r--include/mbgl/style/source.hpp3
-rw-r--r--include/mbgl/style/sources/custom_geometry_source.hpp1
-rw-r--r--include/mbgl/style/sources/geojson_source.hpp2
-rw-r--r--include/mbgl/style/sources/image_source.hpp2
-rw-r--r--include/mbgl/style/sources/raster_dem_source.hpp2
-rw-r--r--include/mbgl/style/sources/raster_source.hpp2
-rw-r--r--include/mbgl/style/sources/vector_source.hpp2
-rw-r--r--include/mbgl/util/feature.hpp15
m---------mapbox-gl-js0
-rw-r--r--next/CMakeLists.txt2
-rw-r--r--platform/android/CHANGELOG.md1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java2
-rw-r--r--platform/darwin/src/MGLRasterDEMSource.mm11
-rw-r--r--platform/darwin/src/MGLRasterTileSource.mm15
-rw-r--r--platform/darwin/src/MGLRasterTileSource_Private.h4
-rw-r--r--platform/darwin/test/MGLStyleTests.mm95
-rw-r--r--platform/glfw/glfw_view.cpp103
-rw-r--r--platform/glfw/glfw_view.hpp4
-rw-r--r--platform/ios/CHANGELOG.md1
-rw-r--r--platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m16
-rw-r--r--platform/node/CHANGELOG.md3
-rw-r--r--platform/node/src/node_feature.cpp6
-rw-r--r--platform/node/src/node_map.cpp221
-rw-r--r--platform/node/src/node_map.hpp4
-rw-r--r--platform/node/test/ignores.json15
-rw-r--r--platform/node/test/js/map.test.js3
-rw-r--r--platform/node/test/suite_implementation.js6
-rw-r--r--render-test/runner.cpp143
-rw-r--r--src/core-files.json2
-rw-r--r--src/mbgl/annotation/annotation_source.cpp7
-rw-r--r--src/mbgl/annotation/annotation_source.hpp7
-rw-r--r--src/mbgl/annotation/render_annotation_source.cpp2
-rw-r--r--src/mbgl/geometry/feature_index.cpp71
-rw-r--r--src/mbgl/geometry/feature_index.hpp33
-rw-r--r--src/mbgl/gfx/vertex_vector.hpp5
-rw-r--r--src/mbgl/layout/pattern_layout.hpp2
-rw-r--r--src/mbgl/layout/symbol_layout.cpp6
-rw-r--r--src/mbgl/renderer/bucket.hpp8
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.cpp23
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.hpp8
-rw-r--r--src/mbgl/renderer/buckets/fill_bucket.cpp29
-rw-r--r--src/mbgl/renderer/buckets/fill_bucket.hpp8
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp26
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp8
-rw-r--r--src/mbgl/renderer/buckets/heatmap_bucket.cpp8
-rw-r--r--src/mbgl/renderer/buckets/heatmap_bucket.hpp6
-rw-r--r--src/mbgl/renderer/buckets/line_bucket.cpp27
-rw-r--r--src/mbgl/renderer/buckets/line_bucket.hpp8
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.cpp15
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.hpp9
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp12
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp9
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.cpp12
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.hpp9
-rw-r--r--src/mbgl/renderer/layers/render_heatmap_layer.cpp11
-rw-r--r--src/mbgl/renderer/layers/render_heatmap_layer.hpp9
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp29
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.hpp11
-rw-r--r--src/mbgl/renderer/paint_property_binder.hpp137
-rw-r--r--src/mbgl/renderer/possibly_evaluated_property_value.hpp8
-rw-r--r--src/mbgl/renderer/render_layer.hpp11
-rw-r--r--src/mbgl/renderer/render_orchestrator.cpp23
-rw-r--r--src/mbgl/renderer/render_orchestrator.hpp9
-rw-r--r--src/mbgl/renderer/render_source.hpp7
-rw-r--r--src/mbgl/renderer/render_tile.cpp4
-rw-r--r--src/mbgl/renderer/render_tile.hpp3
-rw-r--r--src/mbgl/renderer/renderer.cpp15
-rw-r--r--src/mbgl/renderer/source_state.cpp132
-rw-r--r--src/mbgl/renderer/source_state.hpp29
-rw-r--r--src/mbgl/renderer/sources/render_tile_source.cpp19
-rw-r--r--src/mbgl/renderer/sources/render_tile_source.hpp13
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp18
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp10
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp167
-rw-r--r--src/mbgl/style/expression/is_constant.cpp6
-rw-r--r--src/mbgl/style/layer.cpp14
-rw-r--r--src/mbgl/style/layers/background_layer.cpp15
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp15
-rw-r--r--src/mbgl/style/layers/custom_layer.cpp14
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer.cpp15
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp15
-rw-r--r--src/mbgl/style/layers/heatmap_layer.cpp15
-rw-r--r--src/mbgl/style/layers/hillshade_layer.cpp15
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs36
-rw-r--r--src/mbgl/style/layers/line_layer.cpp15
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp15
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp15
-rw-r--r--src/mbgl/style/properties.hpp12
-rw-r--r--src/mbgl/style/sources/custom_geometry_source.cpp17
-rw-r--r--src/mbgl/style/sources/geojson_source.cpp14
-rw-r--r--src/mbgl/style/sources/image_source.cpp10
-rw-r--r--src/mbgl/style/sources/raster_dem_source.cpp12
-rw-r--r--src/mbgl/style/sources/raster_source.cpp16
-rw-r--r--src/mbgl/style/sources/vector_source.cpp16
-rw-r--r--src/mbgl/style/style_impl.cpp38
-rw-r--r--src/mbgl/tile/geometry_tile.cpp56
-rw-r--r--src/mbgl/tile/geometry_tile.hpp16
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp2
-rw-r--r--src/mbgl/tile/tile.cpp10
-rw-r--r--src/mbgl/tile/tile.hpp17
-rw-r--r--test/api/query.test.cpp16
-rw-r--r--test/gl/bucket.test.cpp15
-rw-r--r--test/style/expression/expression.test.cpp3
-rw-r--r--test/style/style_layer.test.cpp18
m---------vendor/mapbox-base0
111 files changed, 1625 insertions, 610 deletions
diff --git a/.clang-format b/.clang-format
index cacdf25308..956884c1b6 100644
--- a/.clang-format
+++ b/.clang-format
@@ -3,6 +3,8 @@ Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -4
AllowShortFunctionsOnASingleLine: Inline
+BinPackArguments: false
+BinPackParameters: false
ColumnLimit: 120
IndentWidth: 4
SpacesBeforeTrailingComments: 1
diff --git a/circle.yml b/circle.yml
index 53f3c79c3a..2d1e7e3f73 100644
--- a/circle.yml
+++ b/circle.yml
@@ -725,10 +725,6 @@ jobs:
git diff -U0 --no-color origin/master... *.cpp *.hpp | clang-format-diff-8 -p1 -i
git diff --exit-code
- run:
- name: Clang Tidy
- command: |
- git diff -U0 --no-color origin/master... src include | clang-tidy-diff-8.py -clang-tidy-binary clang-tidy-8 -p1 -path build
- - run:
name: Code Generators
command: |
platform/android/scripts/generate-style-code.js
diff --git a/include/mbgl/renderer/renderer.hpp b/include/mbgl/renderer/renderer.hpp
index f1800dbfb8..7a1ddde1c1 100644
--- a/include/mbgl/renderer/renderer.hpp
+++ b/include/mbgl/renderer/renderer.hpp
@@ -49,6 +49,15 @@ public:
const std::string& extensionField,
const optional<std::map<std::string, Value>>& args = {}) const;
+ void setFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const std::string& featureID, const FeatureState& state);
+
+ void getFeatureState(FeatureState& state, const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const std::string& featureID) const;
+
+ void removeFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const optional<std::string>& featureID, const optional<std::string>& stateKey);
+
// Debug
void dumpDebugLogs();
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp
index ad57748677..1341a8d041 100644
--- a/include/mbgl/style/expression/expression.hpp
+++ b/include/mbgl/style/expression/expression.hpp
@@ -34,6 +34,8 @@ public:
EvaluationContext(optional<mbgl::Value> accumulated_, GeometryTileFeature const * feature_) :
accumulated(std::move(accumulated_)), feature(feature_)
{}
+ EvaluationContext(float zoom_, GeometryTileFeature const* feature_, const FeatureState* state_)
+ : zoom(zoom_), feature(feature_), featureState(state_) {}
EvaluationContext(optional<float> zoom_, GeometryTileFeature const * feature_, optional<double> colorRampParameter_) :
zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_))
{}
@@ -43,12 +45,18 @@ public:
return *this;
};
+ EvaluationContext& withFeatureState(const FeatureState* featureState_) noexcept {
+ featureState = featureState_;
+ return *this;
+ };
+
optional<float> zoom;
optional<mbgl::Value> accumulated;
GeometryTileFeature const * feature = nullptr;
optional<double> colorRampParameter;
// Contains formatted section object, std::unordered_map<std::string, Value>.
const Value* formattedSection = nullptr;
+ const FeatureState* featureState = nullptr;
};
template <typename T>
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp
index ecd3f01f70..35577411eb 100644
--- a/include/mbgl/style/layer.hpp
+++ b/include/mbgl/style/layer.hpp
@@ -57,6 +57,12 @@ struct LayerTypeInfo {
* requires cross-tile indexing and placement. Contains \c CrossTileIndex::NotRequired otherwise.
*/
const enum class CrossTileIndex { Required, NotRequired } crossTileIndex;
+
+ /**
+ * @brief contains the Id of the supported tile type. Used for internal checks.
+ * The contained values correspond to \c Tile::Kind enum.
+ */
+ const enum class TileKind : uint8_t { Geometry, Raster, RasterDEM, NotRequired } tileKind;
};
/**
diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp
index 32983e2380..f68285fb1b 100644
--- a/include/mbgl/style/property_expression.hpp
+++ b/include/mbgl/style/property_expression.hpp
@@ -61,6 +61,10 @@ public:
return evaluate(expression::EvaluationContext(zoom, &feature), finalDefaultValue);
}
+ T evaluate(float zoom, const GeometryTileFeature& feature, const FeatureState& state, T finalDefaultValue) const {
+ return evaluate(expression::EvaluationContext(zoom, &feature, &state), finalDefaultValue);
+ }
+
std::vector<optional<T>> possibleOutputs() const {
return expression::fromExpressionValues<T>(expression->possibleOutputs());
}
diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp
index 2507b67fdc..c3c0609a9f 100644
--- a/include/mbgl/style/source.hpp
+++ b/include/mbgl/style/source.hpp
@@ -22,6 +22,7 @@ class RasterSource;
class RasterDEMSource;
class GeoJSONSource;
class SourceObserver;
+struct LayerTypeInfo;
/**
* The runtime representation of a [source](https://www.mapbox.com/mapbox-gl-style-spec/#sources) from the Mapbox Style
@@ -74,6 +75,8 @@ public:
virtual void loadDescription(FileSource&) = 0;
void dumpDebugLogs() const;
+ virtual bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const = 0;
+
bool loaded = false;
// For use in SDK bindings, which store a reference to a platform-native peer
diff --git a/include/mbgl/style/sources/custom_geometry_source.hpp b/include/mbgl/style/sources/custom_geometry_source.hpp
index a5e545f445..ff04505699 100644
--- a/include/mbgl/style/sources/custom_geometry_source.hpp
+++ b/include/mbgl/style/sources/custom_geometry_source.hpp
@@ -46,6 +46,7 @@ public:
// Private implementation
class Impl;
const Impl& impl() const;
+ bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
mapbox::base::WeakPtr<Source> makeWeakPtr() override {
return weakFactory.makeWeakPtr();
}
diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp
index c99687fad6..a256ad6f15 100644
--- a/include/mbgl/style/sources/geojson_source.hpp
+++ b/include/mbgl/style/sources/geojson_source.hpp
@@ -50,6 +50,8 @@ public:
void loadDescription(FileSource&) final;
+ bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
+
mapbox::base::WeakPtr<Source> makeWeakPtr() override {
return weakFactory.makeWeakPtr();
}
diff --git a/include/mbgl/style/sources/image_source.hpp b/include/mbgl/style/sources/image_source.hpp
index 84faab33c9..699a3c6494 100644
--- a/include/mbgl/style/sources/image_source.hpp
+++ b/include/mbgl/style/sources/image_source.hpp
@@ -28,6 +28,8 @@ public:
void loadDescription(FileSource&) final;
+ bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
+
mapbox::base::WeakPtr<Source> makeWeakPtr() override {
return weakFactory.makeWeakPtr();
}
diff --git a/include/mbgl/style/sources/raster_dem_source.hpp b/include/mbgl/style/sources/raster_dem_source.hpp
index 82588613bc..42e27cd078 100644
--- a/include/mbgl/style/sources/raster_dem_source.hpp
+++ b/include/mbgl/style/sources/raster_dem_source.hpp
@@ -13,7 +13,7 @@ namespace style {
class RasterDEMSource : public RasterSource {
public:
RasterDEMSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize);
-
+ bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
};
template <>
diff --git a/include/mbgl/style/sources/raster_source.hpp b/include/mbgl/style/sources/raster_source.hpp
index 1bdced8da7..00a3b788c2 100644
--- a/include/mbgl/style/sources/raster_source.hpp
+++ b/include/mbgl/style/sources/raster_source.hpp
@@ -25,6 +25,8 @@ public:
void loadDescription(FileSource&) final;
+ bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
+
mapbox::base::WeakPtr<Source> makeWeakPtr() final {
return weakFactory.makeWeakPtr();
}
diff --git a/include/mbgl/style/sources/vector_source.hpp b/include/mbgl/style/sources/vector_source.hpp
index 97f0a7e5a8..4165af0a61 100644
--- a/include/mbgl/style/sources/vector_source.hpp
+++ b/include/mbgl/style/sources/vector_source.hpp
@@ -24,6 +24,8 @@ public:
void loadDescription(FileSource&) final;
+ bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
+
mapbox::base::WeakPtr<Source> makeWeakPtr() override {
return weakFactory.makeWeakPtr();
}
diff --git a/include/mbgl/util/feature.hpp b/include/mbgl/util/feature.hpp
index 9e2286018c..390cc65720 100644
--- a/include/mbgl/util/feature.hpp
+++ b/include/mbgl/util/feature.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/string.hpp>
#include <mapbox/feature.hpp>
@@ -11,6 +12,9 @@ using NullValue = mapbox::feature::null_value_t;
using PropertyMap = mapbox::feature::property_map;
using FeatureIdentifier = mapbox::feature::identifier;
using Feature = mapbox::feature::feature<double>;
+using FeatureState = PropertyMap;
+using FeatureStates = std::unordered_map<std::string, FeatureState>; // <featureID, FeatureState>
+using LayerFeatureStates = std::unordered_map<std::string, FeatureStates>; // <sourceLayer, FeatureStates>
template <class T>
optional<T> numericValue(const Value& value) {
@@ -29,4 +33,15 @@ optional<T> numericValue(const Value& value) {
});
}
+inline optional<std::string> featureIDtoString(const FeatureIdentifier& id) {
+ if (id.is<NullValue>()) {
+ return nullopt;
+ }
+
+ return id.match(
+ [](const std::string& value_) { return value_; }, [](uint64_t value_) { return util::toString(value_); },
+ [](int64_t value_) { return util::toString(value_); }, [](double value_) { return util::toString(value_); },
+ [](const auto&) -> optional<std::string> { return nullopt; });
+}
+
} // namespace mbgl
diff --git a/mapbox-gl-js b/mapbox-gl-js
-Subproject 572bbb55757c93a9f11fa9b0d0ca099bc4ec361
+Subproject 7ea73ed381a81c3ff7e48b523b25d50793baf1f
diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt
index 150dbc6dbd..e1fd442d48 100644
--- a/next/CMakeLists.txt
+++ b/next/CMakeLists.txt
@@ -539,6 +539,8 @@ add_library(
${MBGL_ROOT}/src/mbgl/renderer/sources/render_tile_source.hpp
${MBGL_ROOT}/src/mbgl/renderer/sources/render_vector_source.cpp
${MBGL_ROOT}/src/mbgl/renderer/sources/render_vector_source.hpp
+ ${MBGL_ROOT}/src/mbgl/renderer/source_state.cpp
+ ${MBGL_ROOT}/src/mbgl/renderer/source_state.hpp
${MBGL_ROOT}/src/mbgl/renderer/style_diff.cpp
${MBGL_ROOT}/src/mbgl/renderer/style_diff.hpp
${MBGL_ROOT}/src/mbgl/renderer/tile_mask.hpp
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 734647e4c8..76704a44cf 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -8,6 +8,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
- Fixed constant repainting for the sources with invisible layers, caused by `RenderSource::hasFadingTiles()` returning `true` all the time. [#15600](https://github.com/mapbox/mapbox-gl-native/pull/15600)
- Fixed an issue that caused the state of CompassView not up to date when `UiSettings.setCompassEnabled()` is set to true. [#15606](https://github.com/mapbox/mapbox-gl-native/pull/15606)
- Fixed an issue that `maxzoom` in style `Sources` option was ignored when URL resource is provided. It may cause problems such as extra tiles downloading at higher zoom level than `maxzoom`, or problems that wrong setting of `overscaledZ` in `OverscaledTileID` that will be passed to `SymbolLayout`, leading wrong rendering appearance. [#15581](https://github.com/mapbox/mapbox-gl-native/pull/15581)
+ - Fixed an assertion hit caused by possibility of adding a layer to an incompatible source. [#15644](https://github.com/mapbox/mapbox-gl-native/pull/15644)
## 8.4.0-alpha.2 - September 11, 2019
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1):
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
index 1e0069c25f..990bd32262 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
@@ -235,7 +235,7 @@ public class MapSnapshotter {
*/
@NonNull
public Options withApiBaseUri(String apiBaseUri) {
- this.apiBaseUrl = apiBaseUrl;
+ this.apiBaseUrl = apiBaseUri;
return this;
}
diff --git a/platform/darwin/src/MGLRasterDEMSource.mm b/platform/darwin/src/MGLRasterDEMSource.mm
index 27614b9ef4..753499ff94 100644
--- a/platform/darwin/src/MGLRasterDEMSource.mm
+++ b/platform/darwin/src/MGLRasterDEMSource.mm
@@ -7,11 +7,10 @@
@implementation MGLRasterDEMSource
-- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
- return std::make_unique<mbgl::style::RasterDEMSource>(identifier.UTF8String,
- configurationURLString.UTF8String,
- uint16_t(round(tileSize)));
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier urlOrTileset:(mbgl::variant<std::string, mbgl::Tileset>)urlOrTileset tileSize:(uint16_t)tileSize {
+ auto source = std::make_unique<mbgl::style::RasterDEMSource>(identifier.UTF8String,
+ urlOrTileset,
+ tileSize);
+ return source;
}
-
@end
diff --git a/platform/darwin/src/MGLRasterTileSource.mm b/platform/darwin/src/MGLRasterTileSource.mm
index e89367711e..b31cee296f 100644
--- a/platform/darwin/src/MGLRasterTileSource.mm
+++ b/platform/darwin/src/MGLRasterTileSource.mm
@@ -33,15 +33,16 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
}
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- auto source = [self pendingSourceWithIdentifier:identifier configurationURL:configurationURL tileSize:tileSize];
+ NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
+ auto source = [self pendingSourceWithIdentifier:identifier urlOrTileset:configurationURLString.UTF8String tileSize:uint16_t(round(tileSize))];
return self = [super initWithPendingSource:std::move(source)];
}
-- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
- return std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
- configurationURLString.UTF8String,
- uint16_t(round(tileSize)));
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier urlOrTileset:(mbgl::variant<std::string, mbgl::Tileset>)urlOrTileset tileSize:(uint16_t)tileSize {
+ auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
+ urlOrTileset,
+ tileSize);
+ return source;
}
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options {
@@ -56,7 +57,7 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
tileSize = static_cast<uint16_t>(round(tileSizeNumber.doubleValue));
}
- auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, tileSet, tileSize);
+ auto source = [self pendingSourceWithIdentifier:identifier urlOrTileset:tileSet tileSize:tileSize];
return self = [super initWithPendingSource:std::move(source)];
}
diff --git a/platform/darwin/src/MGLRasterTileSource_Private.h b/platform/darwin/src/MGLRasterTileSource_Private.h
index 8502b811e2..55f342c7ff 100644
--- a/platform/darwin/src/MGLRasterTileSource_Private.h
+++ b/platform/darwin/src/MGLRasterTileSource_Private.h
@@ -1,8 +1,10 @@
#import "MGLRasterTileSource.h"
#include <memory>
+#include <mbgl/util/variant.hpp>
namespace mbgl {
+ class Tileset;
namespace style {
class RasterSource;
}
@@ -14,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, nullable) mbgl::style::RasterSource *rawSource;
-- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize;
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier urlOrTileset:(mbgl::variant<std::string, mbgl::Tileset>)urlOrTileset tileSize:(uint16_t)tileSize;
@end
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index 7aaf70a80a..ec2605646c 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -229,23 +229,23 @@
- (void)testRemovingSourceInUse {
// Add a raster tile source
- MGLRasterTileSource *rasterTileSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
- [self.style addSource:rasterTileSource];
+ MGLVectorTileSource *vectorTileSource = [[MGLVectorTileSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
+ [self.style addSource:vectorTileSource];
// Add a layer using it
- MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:rasterTileSource];
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:vectorTileSource];
[self.style addLayer:fillLayer];
// Attempt to remove the raster tile source
NSError *error;
- BOOL result = [self.style removeSource:rasterTileSource error:&error];
+ BOOL result = [self.style removeSource:vectorTileSource error:&error];
XCTAssertFalse(result);
XCTAssertEqualObjects(error.domain, MGLErrorDomain);
XCTAssertEqual(error.code, MGLErrorCodeSourceIsInUseCannotRemove);
// Ensure it is still there
- XCTAssertTrue([[self.style sourceWithIdentifier:rasterTileSource.identifier] isMemberOfClass:[MGLRasterTileSource class]]);
+ XCTAssertTrue([[self.style sourceWithIdentifier:vectorTileSource.identifier] isMemberOfClass:[MGLVectorTileSource class]]);
}
- (void)testLayers {
@@ -311,54 +311,61 @@
}
- (void)testRemovingLayerBeforeAddingSameLayer {
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-removing-before-adding" shape:nil options:nil];
-
- // Attempting to find a layer with identifier will trigger an exception if the source associated with the layer is not added
- [self.style addSource:source];
-
- MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:source];
- [self.style removeLayer:fillLayer];
- [self.style addLayer:fillLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:fillLayer.identifier]);
-
- MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"raster-layer" source:source];
- [self.style removeLayer:rasterLayer];
- [self.style addLayer:rasterLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:rasterLayer.identifier]);
-
- MGLSymbolStyleLayer *symbolLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbol-layer" source:source];
- [self.style removeLayer:symbolLayer];
- [self.style addLayer:symbolLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:symbolLayer.identifier]);
-
- MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"line-layer" source:source];
- [self.style removeLayer:lineLayer];
- [self.style addLayer:lineLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:lineLayer.identifier]);
-
- MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circle-layer" source:source];
- [self.style removeLayer:circleLayer];
- [self.style addLayer:circleLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:circleLayer.identifier]);
-
- MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"background-layer"];
- [self.style removeLayer:backgroundLayer];
- [self.style addLayer:backgroundLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:backgroundLayer.identifier]);
+ {
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-removing-before-adding" shape:nil options:nil];
+
+ // Attempting to find a layer with identifier will trigger an exception if the source associated with the layer is not added
+ [self.style addSource:source];
+
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:source];
+ [self.style removeLayer:fillLayer];
+ [self.style addLayer:fillLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:fillLayer.identifier]);
+
+ MGLSymbolStyleLayer *symbolLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbol-layer" source:source];
+ [self.style removeLayer:symbolLayer];
+ [self.style addLayer:symbolLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:symbolLayer.identifier]);
+
+ MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"line-layer" source:source];
+ [self.style removeLayer:lineLayer];
+ [self.style addLayer:lineLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:lineLayer.identifier]);
+
+ MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circle-layer" source:source];
+ [self.style removeLayer:circleLayer];
+ [self.style addLayer:circleLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:circleLayer.identifier]);
+
+ MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"background-layer"];
+ [self.style removeLayer:backgroundLayer];
+ [self.style addLayer:backgroundLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:backgroundLayer.identifier]);
+ }
+
+ {
+ MGLRasterTileSource *rasterSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"raster-tile-source" tileURLTemplates:@[] options:nil];
+ [self.style addSource:rasterSource];
+
+ MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"raster-layer" source:rasterSource];
+ [self.style removeLayer:rasterLayer];
+ [self.style addLayer:rasterLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:rasterLayer.identifier]);
+ }
}
- (void)testAddingLayerOfTypeABeforeRemovingLayerOfTypeBWithSameIdentifier {
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-identifier" shape:nil options:nil];
[self.style addSource:source];
-
+
// Add a fill layer
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"some-identifier" source:source];
[self.style addLayer:fillLayer];
-
+
// Attempt to remove a line layer with the same identifier as the fill layer
MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:fillLayer.identifier source:source];
[self.style removeLayer:lineLayer];
-
+
XCTAssertTrue([[self.style layerWithIdentifier:fillLayer.identifier] isMemberOfClass:[MGLFillStyleLayer class]]);
}
@@ -382,10 +389,10 @@
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:imageName];
#endif
XCTAssertNotNil(image);
-
+
[self.style setImage:image forName:imageName];
MGLImage *styleImage = [self.style imageForName:imageName];
-
+
XCTAssertNotNil(styleImage);
XCTAssertEqual(image.size.width, styleImage.size.width);
XCTAssertEqual(image.size.height, styleImage.size.height);
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp
index 43c4de9759..c39b2c904a 100644
--- a/platform/glfw/glfw_view.cpp
+++ b/platform/glfw/glfw_view.cpp
@@ -4,22 +4,24 @@
#include "ny_route.hpp"
#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/gfx/backend.hpp>
+#include <mbgl/gfx/backend_scope.hpp>
+#include <mbgl/map/camera.hpp>
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/style/expression/dsl.hpp>
#include <mbgl/style/image.hpp>
-#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
-#include <mbgl/style/expression/dsl.hpp>
+#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/geo.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/geo.hpp>
-#include <mbgl/renderer/renderer.hpp>
-#include <mbgl/gfx/backend.hpp>
-#include <mbgl/gfx/backend_scope.hpp>
-#include <mbgl/map/camera.hpp>
#include <mapbox/cheap_ruler.hpp>
#include <mapbox/geometry.hpp>
@@ -323,6 +325,52 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
case GLFW_KEY_T:
view->toggleCustomSource();
break;
+ case GLFW_KEY_F: {
+ using namespace mbgl;
+ using namespace mbgl::style;
+ using namespace mbgl::style::expression::dsl;
+
+ auto &style = view->map->getStyle();
+ if (!style.getSource("states")) {
+ std::string url = "https://docs.mapbox.com/mapbox-gl-js/assets/us_states.geojson";
+ auto source = std::make_unique<GeoJSONSource>("states");
+ source->setURL(url);
+ style.addSource(std::move(source));
+
+ mbgl::CameraOptions cameraOptions;
+ cameraOptions.center = mbgl::LatLng{42.619626, -103.523181};
+ cameraOptions.zoom = 3;
+ cameraOptions.pitch = 0;
+ cameraOptions.bearing = 0;
+ view->map->jumpTo(cameraOptions);
+ }
+
+ auto layer = style.getLayer("state-fills");
+ if (!layer) {
+ auto fillLayer = std::make_unique<FillLayer>("state-fills", "states");
+ fillLayer->setFillColor(mbgl::Color{0.0, 0.0, 1.0, 0.5});
+ fillLayer->setFillOpacity(PropertyExpression<float>(
+ createExpression(R"(["case", ["boolean", ["feature-state", "hover"], false], 1, 0.5])")));
+ style.addLayer(std::move(fillLayer));
+ } else {
+ layer->setVisibility(layer->getVisibility() == mbgl::style::VisibilityType::Visible
+ ? mbgl::style::VisibilityType::None
+ : mbgl::style::VisibilityType::Visible);
+ }
+
+ layer = style.getLayer("state-borders");
+ if (!layer) {
+ auto borderLayer = std::make_unique<LineLayer>("state-borders", "states");
+ borderLayer->setLineColor(mbgl::Color{0.0, 0.0, 1.0, 1.0});
+ borderLayer->setLineWidth(PropertyExpression<float>(
+ createExpression(R"(["case", ["boolean", ["feature-state", "hover"], false], 2, 1])")));
+ style.addLayer(std::move(borderLayer));
+ } else {
+ layer->setVisibility(layer->getVisibility() == mbgl::style::VisibilityType::Visible
+ ? mbgl::style::VisibilityType::None
+ : mbgl::style::VisibilityType::Visible);
+ }
+ } break;
}
}
@@ -558,6 +606,41 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
}
view->lastX = x;
view->lastY = y;
+
+ auto &style = view->map->getStyle();
+ if (style.getLayer("state-fills")) {
+ auto screenCoordinate = mbgl::ScreenCoordinate{view->lastX, view->lastY};
+ const mbgl::RenderedQueryOptions queryOptions({{{"state-fills"}}, {}});
+ auto result = view->rendererFrontend->getRenderer()->queryRenderedFeatures(screenCoordinate, queryOptions);
+ using namespace mbgl;
+ FeatureState newState;
+
+ if (result.size() > 0) {
+ FeatureIdentifier id = result[0].id;
+ optional<std::string> idStr = featureIDtoString(id);
+
+ if (idStr) {
+ if (view->featureID && (*view->featureID != *idStr)) {
+ newState["hover"] = false;
+ view->rendererFrontend->getRenderer()->setFeatureState("states", {}, *view->featureID, newState);
+ view->featureID = nullopt;
+ }
+
+ if (!view->featureID) {
+ newState["hover"] = true;
+ view->featureID = featureIDtoString(id);
+ view->rendererFrontend->getRenderer()->setFeatureState("states", {}, *view->featureID, newState);
+ }
+ }
+ } else {
+ if (view->featureID) {
+ newState["hover"] = false;
+ view->rendererFrontend->getRenderer()->setFeatureState("states", {}, *view->featureID, newState);
+ view->featureID = nullopt;
+ }
+ }
+ view->invalidate();
+ }
}
void GLFWView::onWindowFocus(GLFWwindow *window, int focused) {
diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp
index 54b89ba2d9..dbe6ceb046 100644
--- a/platform/glfw/glfw_view.hpp
+++ b/platform/glfw/glfw_view.hpp
@@ -1,9 +1,10 @@
#pragma once
#include <mbgl/map/map.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/optional.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/timer.hpp>
-#include <mbgl/util/geometry.hpp>
struct GLFWwindow;
class GLFWBackend;
@@ -134,4 +135,5 @@ private:
GLFWwindow *window = nullptr;
bool dirty = false;
+ mbgl::optional<std::string> featureID;
};
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index f2394d1b84..089cc18606 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -7,6 +7,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Styles and rendering
* Added an `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]` method to provide the snapshot's current `CGContext` in order to perform custom drawing on `MGLMapSnapShot` objects. ([#15530](https://github.com/mapbox/mapbox-gl-native/pull/15530))
* Fixed an issue that `maxzoom` in style `Sources` option was ignored when URL resource is provided. It may cause problems such as extra tiles downloading at higher zoom level than `maxzoom`, or problems that wrong setting of `overscaledZ` in `OverscaledTileID` that will be passed to `SymbolLayout`, leading wrong rendering appearance. ([#15581](https://github.com/mapbox/mapbox-gl-native/pull/15581))
+* Fixed an assertion hit caused by possibility of adding a layer to an incompatible source. ([#15644](https://github.com/mapbox/mapbox-gl-native/pull/15644))
### Performance improvements
diff --git a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m b/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
index c018c457b9..f5f2f957d3 100644
--- a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
+++ b/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
@@ -82,31 +82,31 @@
// Testing generated layers
MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"lineLayerID" source:source];
- MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"rasterLayerID" source:source];
+ MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circleLayerID" source:source];
[self.mapView.style addSource:source];
[self.mapView.style addLayer:lineLayer];
- [self.mapView.style addLayer:rasterLayer];
+ [self.mapView.style addLayer:circleLayer];
XCTAssertNoThrow(lineLayer.isVisible);
- XCTAssertNoThrow(rasterLayer.isVisible);
+ XCTAssertNoThrow(circleLayer.isVisible);
XCTAssert(![source.description containsString:@"<unknown>"]);
XCTAssert(![lineLayer.description containsString:@"<unknown>"]);
- XCTAssert(![rasterLayer.description containsString:@"<unknown>"]);
+ XCTAssert(![circleLayer.description containsString:@"<unknown>"]);
self.styleLoadingExpectation = nil;
[self.mapView setStyleURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]];
[self waitForMapViewToFinishLoadingStyleWithTimeout:10];
-
+
XCTAssert([source.description containsString:@"<unknown>"]);
XCTAssert([lineLayer.description containsString:@"<unknown>"]);
- XCTAssert([rasterLayer.description containsString:@"<unknown>"]);
+ XCTAssert([circleLayer.description containsString:@"<unknown>"]);
XCTAssertThrowsSpecificNamed(lineLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
- XCTAssertThrowsSpecificNamed(rasterLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
+ XCTAssertThrowsSpecificNamed(circleLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:lineLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
- XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:rasterLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
+ XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:circleLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
}
@end
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index 486dd44e10..84fbff741c 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,3 +1,6 @@
+# master
+* Add support for feature state APIs. ([#15480](https://github.com/mapbox/mapbox-gl-native/pull/15480))
+
# 4.3.0
* Introduce `text-writing-mode` layout property for symbol layer ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932)). The `text-writing-mode` layout property allows control over symbol's preferred writing mode. The new property value is an array, whose values are enumeration values from a ( `horizontal` | `vertical` ) set.
* Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367)).
diff --git a/platform/node/src/node_feature.cpp b/platform/node/src/node_feature.cpp
index 2dfab686a7..646cc23338 100644
--- a/platform/node/src/node_feature.cpp
+++ b/platform/node/src/node_feature.cpp
@@ -167,6 +167,12 @@ v8::Local<v8::Object> toJS(const Feature& feature) {
Nan::Set(result, Nan::New("id").ToLocalChecked(), FeatureIdentifier::visit(feature.id, ToValue()));
}
+ Nan::Set(result, Nan::New("source").ToLocalChecked(), toJS(feature.source));
+ if (!feature.sourceLayer.empty()) {
+ Nan::Set(result, Nan::New("sourceLayer").ToLocalChecked(), toJS(feature.sourceLayer));
+ }
+ Nan::Set(result, Nan::New("state").ToLocalChecked(), toJS(feature.state));
+
return scope.Escape(result);
}
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 641816dc00..7450f461f8 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -117,6 +117,9 @@ ParseError)JS").ToLocalChecked()).ToLocalChecked();
Nan::SetPrototypeMethod(tpl, "setAxonometric", SetAxonometric);
Nan::SetPrototypeMethod(tpl, "setXSkew", SetXSkew);
Nan::SetPrototypeMethod(tpl, "setYSkew", SetYSkew);
+ Nan::SetPrototypeMethod(tpl, "setFeatureState", SetFeatureState);
+ Nan::SetPrototypeMethod(tpl, "getFeatureState", GetFeatureState);
+ Nan::SetPrototypeMethod(tpl, "removeFeatureState", RemoveFeatureState);
Nan::SetPrototypeMethod(tpl, "dumpDebugLogs", DumpDebugLogs);
Nan::SetPrototypeMethod(tpl, "queryRenderedFeatures", QueryRenderedFeatures);
@@ -1099,6 +1102,224 @@ void NodeMap::SetYSkew(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().SetUndefined();
}
+void NodeMap::SetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 2) {
+ return Nan::ThrowTypeError("Two arguments required");
+ }
+
+ if (!info[0]->IsObject() || !info[1]->IsObject()) {
+ return Nan::ThrowTypeError("Both arguments must be objects");
+ }
+
+ std::string sourceID, featureID;
+ mbgl::optional<std::string> sourceLayerID;
+ auto feature = Nan::To<v8::Object>(info[0]).ToLocalChecked();
+ if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) {
+ auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked();
+ if (!sourceOption->IsString()) {
+ return Nan::ThrowTypeError("Requires feature.source property to be a string");
+ }
+ sourceID = *Nan::Utf8String(sourceOption);
+ } else {
+ return Nan::ThrowTypeError("SetFeatureState: Requires feature.source property");
+ }
+
+ if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) {
+ auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked();
+ if (!sourceLayerOption->IsString()) {
+ return Nan::ThrowTypeError("SetFeatureState: Requires feature.sourceLayer property to be a string");
+ }
+ sourceLayerID = {*Nan::Utf8String(sourceLayerOption)};
+ }
+
+ if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) {
+ auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked();
+ if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) {
+ return Nan::ThrowTypeError("Requires feature.id property to be a string or a number");
+ }
+ featureID = *Nan::Utf8String(idOption);
+ } else {
+ return Nan::ThrowTypeError("SetFeatureState: Requires feature.id property");
+ }
+
+ Convertible state(info[1]);
+
+ if (!isObject(state)) {
+ return Nan::ThrowTypeError("Feature state must be an object");
+ }
+
+ std::string sourceLayer = sourceLayerID.value_or(std::string());
+ std::string stateKey;
+ Value stateValue;
+ bool valueParsed = false;
+ FeatureState newState;
+
+ const std::function<optional<Error>(const std::string&, const Convertible&)> convertFn =
+ [&](const std::string& k, const Convertible& v) -> optional<Error> {
+ optional<Value> value = toValue(v);
+ if (value) {
+ stateValue = std::move(*value);
+ valueParsed = true;
+ } else if (isArray(v)) {
+ std::vector<Value> array;
+ std::size_t length = arrayLength(v);
+ array.reserve(length);
+ for (size_t i = 0; i < length; ++i) {
+ optional<Value> arrayVal = toValue(arrayMember(v, i));
+ if (arrayVal) {
+ array.emplace_back(*arrayVal);
+ }
+ }
+ std::unordered_map<std::string, Value> result;
+ result[k] = std::move(array);
+ stateValue = std::move(result);
+ valueParsed = true;
+ return {};
+
+ } else if (isObject(v)) {
+ eachMember(v, convertFn);
+ }
+ if (!valueParsed) {
+ Nan::ThrowTypeError("Could not get feature state value");
+ return nullopt;
+ }
+ stateKey = k;
+ newState[stateKey] = stateValue;
+ return nullopt;
+ };
+
+ eachMember(state, convertFn);
+
+ try {
+ nodeMap->frontend->getRenderer()->setFeatureState(sourceID, sourceLayerID, featureID, newState);
+ } catch (const std::exception& ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().SetUndefined();
+}
+
+void NodeMap::GetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 1) {
+ return Nan::ThrowTypeError("One argument required");
+ }
+
+ if (!info[0]->IsObject() || !info[1]->IsObject()) {
+ return Nan::ThrowTypeError("Argument must be object");
+ }
+
+ std::string sourceID, featureID;
+ mbgl::optional<std::string> sourceLayerID;
+ auto feature = Nan::To<v8::Object>(info[0]).ToLocalChecked();
+ if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) {
+ auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked();
+ if (!sourceOption->IsString()) {
+ return Nan::ThrowTypeError("Requires feature.source property to be a string");
+ }
+ sourceID = *Nan::Utf8String(sourceOption);
+ } else {
+ return Nan::ThrowTypeError("GetFeatureState: Requires feature.source property");
+ }
+
+ if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) {
+ auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked();
+ if (!sourceLayerOption->IsString()) {
+ return Nan::ThrowTypeError("GetFeatureState: Requires feature.sourceLayer property to be a string");
+ }
+ sourceLayerID = {*Nan::Utf8String(sourceLayerOption)};
+ }
+
+ if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) {
+ auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked();
+ if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) {
+ return Nan::ThrowTypeError("Requires feature.id property to be a string or a number");
+ }
+ featureID = *Nan::Utf8String(idOption);
+ } else {
+ return Nan::ThrowTypeError("GetFeatureState: Requires feature.id property");
+ }
+
+ mbgl::FeatureState state;
+ try {
+ nodeMap->frontend->getRenderer()->getFeatureState(state, sourceID, sourceLayerID, featureID);
+ } catch (const std::exception& ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().SetUndefined();
+}
+
+void NodeMap::RemoveFeatureState(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 1) {
+ return Nan::ThrowTypeError("At least one argument required");
+ }
+
+ if (!info[0]->IsObject()) {
+ return Nan::ThrowTypeError("Argument 1 must be object");
+ }
+
+ if (info.Length() == 2 && !info[1]->IsString()) {
+ return Nan::ThrowTypeError("argument 2 must be string");
+ }
+
+ std::string sourceID;
+ mbgl::optional<std::string> sourceLayerID, featureID, stateKey;
+ auto feature = Nan::To<v8::Object>(info[0]).ToLocalChecked();
+ if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) {
+ auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked();
+ if (!sourceOption->IsString()) {
+ return Nan::ThrowTypeError("Requires feature.source property to be a string");
+ }
+ sourceID = *Nan::Utf8String(sourceOption);
+ } else {
+ return Nan::ThrowTypeError("RemoveFeatureState: Requires feature.source property");
+ }
+
+ if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) {
+ auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked();
+ if (!sourceLayerOption->IsString()) {
+ return Nan::ThrowTypeError("RemoveFeatureState: Requires feature.sourceLayer property to be a string");
+ }
+ sourceLayerID = {*Nan::Utf8String(sourceLayerOption)};
+ }
+
+ if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) {
+ auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked();
+ if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) {
+ return Nan::ThrowTypeError("Requires feature.id property to be a string or a number");
+ }
+ featureID = {*Nan::Utf8String(idOption)};
+ }
+
+ if (info.Length() == 2) {
+ auto keyParam = Nan::To<v8::String>(info[1]).ToLocalChecked();
+ if (!keyParam->IsString()) {
+ return Nan::ThrowTypeError("RemoveFeatureState: Requires feature key property to be a string");
+ }
+ stateKey = {*Nan::Utf8String(keyParam)};
+ }
+
+ try {
+ nodeMap->frontend->getRenderer()->removeFeatureState(sourceID, sourceLayerID, featureID, stateKey);
+ } catch (const std::exception& ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().SetUndefined();
+}
+
void NodeMap::DumpDebugLogs(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index 486754c1c3..381e10381b 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -64,6 +64,10 @@ public:
static void DumpDebugLogs(const Nan::FunctionCallbackInfo<v8::Value>&);
static void QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void SetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void GetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void RemoveFeatureState(const Nan::FunctionCallbackInfo<v8::Value>&);
+
static v8::Local<v8::Value> ParseError(const char* msg);
void startRender(RenderOptions options);
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index d32fb6b0c4..f053b2add1 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -20,15 +20,8 @@
"query-tests/geometry/multipolygon": "needs investigation",
"query-tests/geometry/polygon": "needs investigation",
"query-tests/world-wrapping/box": "skip - needs issue",
- "query-tests/circle-radius/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/circle-stroke-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
"query-tests/fill-extrusion-translate/multiple-layers": "https://github.com/mapbox/mapbox-gl-native/issues/12701",
"query-tests/fill-translate/multiple-layers": "https://github.com/mapbox/mapbox-gl-native/issues/12701",
- "query-tests/line-gap-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/line-offset/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/line-offset/pattern-feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/line-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/feature-state/default": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
"query-tests/regressions/mapbox-gl-js#6555": "skip - no querySourceFeatures in mbgl-node; needs issue",
"render-tests/background-color/transition": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/canvas/default": "skip - js specific",
@@ -52,7 +45,6 @@
"render-tests/fill-extrusion-pattern/opacity": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/fill-extrusion-pattern/feature-expression": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/fill-extrusion-pattern/tile-buffer": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
- "render-tests/fill-pattern/update-feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
"render-tests/geojson/inline-linestring-fill": "current behavior is arbitrary",
"render-tests/mixed-zoom/z10-z11": "https://github.com/mapbox/mapbox-gl-native/issues/10397",
"render-tests/raster-masking/overlapping-zoom": "https://github.com/mapbox/mapbox-gl-native/issues/10195",
@@ -73,19 +65,12 @@
"render-tests/symbol-cross-fade/chinese": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/video/default": "skip - https://github.com/mapbox/mapbox-gl-native/issues/601",
"render-tests/background-color/colorSpace-hcl": "needs issue",
- "render-tests/feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
- "render-tests/feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
- "render-tests/feature-state/vector-source": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
"render-tests/text-variable-anchor/remember-last-placement": "skip - fails on gl-native, as symbol index is not functional at static map mode - needs issue",
- "render-tests/remove-feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
- "render-tests/remove-feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
- "render-tests/remove-feature-state/vector-source": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
"render-tests/regressions/mapbox-gl-js#8026": "skip - js specific",
"render-tests/fill-extrusion-geometry/linestring": "https://github.com/mapbox/mapbox-gl-native/pull/14240",
"render-tests/circle-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008",
"render-tests/fill-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008",
"render-tests/line-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008",
- "query-tests/remove-feature-state/default": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
"query-tests/fill-extrusion/base-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
"query-tests/fill-extrusion/box-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
"query-tests/fill-extrusion/side-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
diff --git a/platform/node/test/js/map.test.js b/platform/node/test/js/map.test.js
index b21c1519e3..d085e32f4c 100644
--- a/platform/node/test/js/map.test.js
+++ b/platform/node/test/js/map.test.js
@@ -126,6 +126,9 @@ test('Map', function(t) {
'setAxonometric',
'setXSkew',
'setYSkew',
+ 'setFeatureState',
+ 'getFeatureState',
+ 'removeFeatureState',
'dumpDebugLogs',
'queryRenderedFeatures'
]);
diff --git a/platform/node/test/suite_implementation.js b/platform/node/test/suite_implementation.js
index f868af8ece..386bd41092 100644
--- a/platform/node/test/suite_implementation.js
+++ b/platform/node/test/suite_implementation.js
@@ -122,6 +122,12 @@ export default function (style, options, callback) {
map.load(operation[1]);
applyOperations(operations.slice(1), callback);
+ } else if (operation[0] ==='setFeatureState' || operation[0] ==='getFeatureState' || operation[0] ==='removeFeatureState') {
+ map.render(options, function () {
+ map[operation[0]].apply(map, operation.slice(1));
+ applyOperations(operations.slice(1), callback);
+ });
+
} else {
// Ensure that the next `map.render(options)` does not overwrite this change.
if (operation[0] === 'setCenter') {
diff --git a/render-test/runner.cpp b/render-test/runner.cpp
index 54660979cf..5c8f53759f 100644
--- a/render-test/runner.cpp
+++ b/render-test/runner.cpp
@@ -1,5 +1,6 @@
#include <mbgl/map/camera.hpp>
#include <mbgl/map/map_observer.hpp>
+#include <mbgl/renderer/renderer.hpp>
#include <mbgl/style/conversion/filter.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/light.hpp>
@@ -7,11 +8,11 @@
#include <mbgl/style/image.hpp>
#include <mbgl/style/layer.hpp>
#include <mbgl/style/light.hpp>
-#include <mbgl/style/style.hpp>
#include <mbgl/style/rapidjson_conversion.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/io.hpp>
#include <mbgl/util/image.hpp>
+#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/timer.hpp>
@@ -197,6 +198,9 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) {
static const std::string memoryProbeOp("probeMemory");
static const std::string memoryProbeStartOp("probeMemoryStart");
static const std::string memoryProbeEndOp("probeMemoryEnd");
+ static const std::string setFeatureStateOp("setFeatureState");
+ static const std::string getFeatureStateOp("getFeatureState");
+ static const std::string removeFeatureStateOp("removeFeatureState");
// wait
if (operationArray[0].GetString() == waitOp) {
@@ -453,6 +457,141 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) {
assert(AllocationIndex::isActive());
AllocationIndex::setActive(false);
AllocationIndex::reset();
+
+ // setFeatureState
+ } else if (operationArray[0].GetString() == setFeatureStateOp) {
+ assert(operationArray.Size() >= 3u);
+ assert(operationArray[1].IsObject());
+ assert(operationArray[2].IsObject());
+
+ using namespace mbgl;
+ using namespace mbgl::style::conversion;
+
+ std::string sourceID;
+ mbgl::optional<std::string> sourceLayer;
+ std::string featureID;
+ std::string stateKey;
+ Value stateValue;
+ bool valueParsed = false;
+ FeatureState parsedState;
+
+ const auto& featureOptions = operationArray[1].GetObject();
+ if (featureOptions.HasMember("source")) {
+ sourceID = featureOptions["source"].GetString();
+ }
+ if (featureOptions.HasMember("sourceLayer")) {
+ sourceLayer = {featureOptions["sourceLayer"].GetString()};
+ }
+ if (featureOptions.HasMember("id")) {
+ featureID = featureOptions["id"].GetString();
+ }
+ const JSValue* state = &operationArray[2];
+
+ const std::function<optional<Error>(const std::string&, const Convertible&)> convertFn =
+ [&](const std::string& k, const Convertible& v) -> optional<Error> {
+ optional<Value> value = toValue(v);
+ if (value) {
+ stateValue = std::move(*value);
+ valueParsed = true;
+ } else if (isArray(v)) {
+ std::vector<Value> array;
+ std::size_t length = arrayLength(v);
+ array.reserve(length);
+ for (size_t i = 0; i < length; ++i) {
+ optional<Value> arrayVal = toValue(arrayMember(v, i));
+ if (arrayVal) {
+ array.emplace_back(*arrayVal);
+ }
+ }
+ std::unordered_map<std::string, Value> result;
+ result[k] = std::move(array);
+ stateValue = std::move(result);
+ valueParsed = true;
+ return {};
+
+ } else if (isObject(v)) {
+ eachMember(v, convertFn);
+ }
+
+ if (!valueParsed) {
+ metadata.errorMessage = std::string("Could not get feature state value, state key: ") + k;
+ return nullopt;
+ }
+ stateKey = k;
+ parsedState[stateKey] = stateValue;
+ return nullopt;
+ };
+
+ eachMember(state, convertFn);
+
+ try {
+ frontend.render(map);
+ } catch (const std::exception&) {
+ return false;
+ }
+ frontend.getRenderer()->setFeatureState(sourceID, sourceLayer, featureID, parsedState);
+
+ // getFeatureState
+ } else if (operationArray[0].GetString() == getFeatureStateOp) {
+ assert(operationArray.Size() >= 2u);
+ assert(operationArray[1].IsObject());
+
+ std::string sourceID;
+ mbgl::optional<std::string> sourceLayer;
+ std::string featureID;
+
+ const auto& featureOptions = operationArray[1].GetObject();
+ if (featureOptions.HasMember("source")) {
+ sourceID = featureOptions["source"].GetString();
+ }
+ if (featureOptions.HasMember("sourceLayer")) {
+ sourceLayer = {featureOptions["sourceLayer"].GetString()};
+ }
+ if (featureOptions.HasMember("id")) {
+ featureID = featureOptions["id"].GetString();
+ }
+
+ try {
+ frontend.render(map);
+ } catch (const std::exception&) {
+ return false;
+ }
+ mbgl::FeatureState state;
+ frontend.getRenderer()->getFeatureState(state, sourceID, sourceLayer, featureID);
+
+ // removeFeatureState
+ } else if (operationArray[0].GetString() == removeFeatureStateOp) {
+ assert(operationArray.Size() >= 2u);
+ assert(operationArray[1].IsObject());
+
+ std::string sourceID;
+ mbgl::optional<std::string> sourceLayer;
+ std::string featureID;
+ mbgl::optional<std::string> stateKey;
+
+ const auto& featureOptions = operationArray[1].GetObject();
+ if (featureOptions.HasMember("source")) {
+ sourceID = featureOptions["source"].GetString();
+ }
+ if (featureOptions.HasMember("sourceLayer")) {
+ sourceLayer = {featureOptions["sourceLayer"].GetString()};
+ }
+ if (featureOptions.HasMember("id")) {
+ featureID = featureOptions["id"].GetString();
+ }
+
+ if (operationArray.Size() >= 3u) {
+ assert(operationArray[2].IsString());
+ stateKey = {operationArray[2].GetString()};
+ }
+
+ try {
+ frontend.render(map);
+ } catch (const std::exception&) {
+ return false;
+ }
+ frontend.getRenderer()->removeFeatureState(sourceID, sourceLayer, featureID, stateKey);
+
} else {
metadata.errorMessage = std::string("Unsupported operation: ") + operationArray[0].GetString();
return false;
diff --git a/src/core-files.json b/src/core-files.json
index f4f2dd2c40..4867bd3dc4 100644
--- a/src/core-files.json
+++ b/src/core-files.json
@@ -134,6 +134,7 @@
"src/mbgl/renderer/renderer.cpp",
"src/mbgl/renderer/renderer_impl.cpp",
"src/mbgl/renderer/renderer_state.cpp",
+ "src/mbgl/renderer/source_state.cpp",
"src/mbgl/renderer/sources/render_custom_geometry_source.cpp",
"src/mbgl/renderer/sources/render_geojson_source.cpp",
"src/mbgl/renderer/sources/render_image_source.cpp",
@@ -656,6 +657,7 @@
"mbgl/renderer/render_tile.hpp": "src/mbgl/renderer/render_tile.hpp",
"mbgl/renderer/render_tree.hpp": "src/mbgl/renderer/render_tree.hpp",
"mbgl/renderer/renderer_impl.hpp": "src/mbgl/renderer/renderer_impl.hpp",
+ "mbgl/renderer/source_state.hpp": "src/mbgl/renderer/source_state.hpp",
"mbgl/renderer/sources/render_custom_geometry_source.hpp": "src/mbgl/renderer/sources/render_custom_geometry_source.hpp",
"mbgl/renderer/sources/render_geojson_source.hpp": "src/mbgl/renderer/sources/render_geojson_source.hpp",
"mbgl/renderer/sources/render_image_source.hpp": "src/mbgl/renderer/sources/render_image_source.hpp",
diff --git a/src/mbgl/annotation/annotation_source.cpp b/src/mbgl/annotation/annotation_source.cpp
index 68f36f2d3a..7a137f1881 100644
--- a/src/mbgl/annotation/annotation_source.cpp
+++ b/src/mbgl/annotation/annotation_source.cpp
@@ -1,5 +1,6 @@
-#include <mbgl/annotation/annotation_source.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/annotation/annotation_source.hpp>
+#include <mbgl/style/layer.hpp>
namespace mbgl {
@@ -21,4 +22,8 @@ optional<std::string> AnnotationSource::Impl::getAttribution() const {
return {};
}
+bool AnnotationSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const {
+ return !std::strcmp(info->type, "line") || !std::strcmp(info->type, "symbol") || !std::strcmp(info->type, "fill");
+}
+
} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_source.hpp b/src/mbgl/annotation/annotation_source.hpp
index 018e2136ea..0379426b3e 100644
--- a/src/mbgl/annotation/annotation_source.hpp
+++ b/src/mbgl/annotation/annotation_source.hpp
@@ -12,13 +12,12 @@ public:
class Impl;
const Impl& impl() const;
+private:
+ void loadDescription(FileSource&) final;
+ bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
mapbox::base::WeakPtr<Source> makeWeakPtr() override {
return weakFactory.makeWeakPtr();
}
-
-private:
- void loadDescription(FileSource&) final;
-
Mutable<Impl> mutableImpl() const;
mapbox::base::WeakPtrFactory<Source> weakFactory {this};
};
diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp
index 903825d5f5..e3acfcb3c0 100644
--- a/src/mbgl/annotation/render_annotation_source.cpp
+++ b/src/mbgl/annotation/render_annotation_source.cpp
@@ -49,7 +49,7 @@ RenderAnnotationSource::queryRenderedFeatures(const ScreenLineString& geometry,
const std::unordered_map<std::string, const RenderLayer*>& layers,
const RenderedQueryOptions& options,
const mat4& projMatrix) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix, {});
}
std::vector<Feature> RenderAnnotationSource::querySourceFeatures(const SourceQueryOptions&) const {
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp
index b76e02be3f..20026dd117 100644
--- a/src/mbgl/geometry/feature_index.cpp
+++ b/src/mbgl/geometry/feature_index.cpp
@@ -1,13 +1,14 @@
#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/renderer/query.hpp>
+#include <mbgl/math/minmax.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/renderer/query.hpp>
+#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/renderer/source_state.hpp>
+#include <mbgl/style/filter.hpp>
#include <mbgl/text/collision_index.hpp>
+#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/math.hpp>
-#include <mbgl/math/minmax.hpp>
-#include <mbgl/style/filter.hpp>
-#include <mbgl/tile/tile_id.hpp>
#include <mapbox/geometry/envelope.hpp>
@@ -38,18 +39,12 @@ void FeatureIndex::insert(const GeometryCollection& geometries,
}
}
-void FeatureIndex::query(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState& transformState,
- const mat4& posMatrix,
- const double tileSize,
- const double scale,
- const RenderedQueryOptions& queryOptions,
- const UnwrappedTileID& tileID,
- const std::unordered_map<std::string, const RenderLayer*>& layers,
- const float additionalQueryPadding) const {
-
+void FeatureIndex::query(std::unordered_map<std::string, std::vector<Feature>>& result,
+ const GeometryCoordinates& queryGeometry, const TransformState& transformState,
+ const mat4& posMatrix, const double tileSize, const double scale,
+ const RenderedQueryOptions& queryOptions, const UnwrappedTileID& tileID,
+ const std::unordered_map<std::string, const RenderLayer*>& layers,
+ const float additionalQueryPadding, const SourceFeatureState& sourceFeatureState) const {
if (!tileData) {
return;
}
@@ -74,10 +69,11 @@ void FeatureIndex::query(
if (indexedFeature.sortIndex == previousSortIndex) continue;
previousSortIndex = indexedFeature.sortIndex;
- addFeature(result, indexedFeature, queryOptions, tileID.canonical, layers, queryGeometry, transformState, pixelsToTileUnits, posMatrix);
+ addFeature(result, indexedFeature, queryOptions, tileID.canonical, layers, queryGeometry, transformState,
+ pixelsToTileUnits, posMatrix, &sourceFeatureState);
}
}
-
+
std::unordered_map<std::string, std::vector<Feature>>
FeatureIndex::lookupSymbolFeatures(const std::vector<IndexedSubfeature>& symbolFeatures,
const RenderedQueryOptions& queryOptions,
@@ -113,22 +109,19 @@ FeatureIndex::lookupSymbolFeatures(const std::vector<IndexedSubfeature>& symbolF
for (const auto& symbolFeature : sortedFeatures) {
mat4 unusedMatrix;
- addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), {}, 0, unusedMatrix);
+ addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), {}, 0,
+ unusedMatrix, nullptr);
}
return result;
}
-void FeatureIndex::addFeature(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const IndexedSubfeature& indexedFeature,
- const RenderedQueryOptions& options,
- const CanonicalTileID& tileID,
- const std::unordered_map<std::string, const RenderLayer*>& layers,
- const GeometryCoordinates& queryGeometry,
- const TransformState& transformState,
- const float pixelsToTileUnits,
- const mat4& posMatrix) const {
-
+void FeatureIndex::addFeature(std::unordered_map<std::string, std::vector<Feature>>& result,
+ const IndexedSubfeature& indexedFeature, const RenderedQueryOptions& options,
+ const CanonicalTileID& tileID,
+ const std::unordered_map<std::string, const RenderLayer*>& layers,
+ const GeometryCoordinates& queryGeometry, const TransformState& transformState,
+ const float pixelsToTileUnits, const mat4& posMatrix,
+ const SourceFeatureState* sourceFeatureState) const {
// Lazily calculated.
std::unique_ptr<GeometryTileLayer> sourceLayer;
std::unique_ptr<GeometryTileFeature> geometryTileFeature;
@@ -148,10 +141,18 @@ void FeatureIndex::addFeature(
geometryTileFeature = sourceLayer->getFeature(indexedFeature.index);
assert(geometryTileFeature);
}
+ FeatureState state;
+ if (sourceFeatureState != nullptr) {
+ optional<std::string> idStr = featureIDtoString(geometryTileFeature->getID());
+ if (idStr) {
+ sourceFeatureState->getState(state, sourceLayer->getName(), *idStr);
+ }
+ }
bool needsCrossTileIndex = renderLayer->baseImpl->getTypeInfo()->crossTileIndex == style::LayerTypeInfo::CrossTileIndex::Required;
if (!needsCrossTileIndex &&
- !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, transformState, pixelsToTileUnits, posMatrix)) {
+ !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, transformState,
+ pixelsToTileUnits, posMatrix, state)) {
continue;
}
@@ -159,7 +160,11 @@ void FeatureIndex::addFeature(
continue;
}
- result[layerID].emplace_back(convertFeature(*geometryTileFeature, tileID));
+ Feature feature = convertFeature(*geometryTileFeature, tileID);
+ feature.source = renderLayer->baseImpl->source;
+ feature.sourceLayer = sourceLayer->getName();
+ feature.state = state;
+ result[layerID].emplace_back(feature);
}
}
diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp
index 1a212761fa..5a006a51bc 100644
--- a/src/mbgl/geometry/feature_index.hpp
+++ b/src/mbgl/geometry/feature_index.hpp
@@ -16,6 +16,7 @@ namespace mbgl {
class RenderedQueryOptions;
class RenderLayer;
class TransformState;
+class SourceFeatureState;
class CollisionIndex;
@@ -58,17 +59,11 @@ public:
void insert(const GeometryCollection&, std::size_t index, const std::string& sourceLayerName, const std::string& bucketLeaderID);
- void query(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState&,
- const mat4& posMatrix,
- const double tileSize,
- const double scale,
- const RenderedQueryOptions& options,
- const UnwrappedTileID&,
- const std::unordered_map<std::string, const RenderLayer*>&,
- const float additionalQueryPadding) const;
+ void query(std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry,
+ const TransformState&, const mat4& posMatrix, const double tileSize, const double scale,
+ const RenderedQueryOptions& options, const UnwrappedTileID&,
+ const std::unordered_map<std::string, const RenderLayer*>&, const float additionalQueryPadding,
+ const SourceFeatureState& sourceFeatureState) const;
static optional<GeometryCoordinates> translateQueryGeometry(
const GeometryCoordinates& queryGeometry,
@@ -87,16 +82,12 @@ public:
const std::shared_ptr<std::vector<size_t>>& featureSortOrder) const;
private:
- void addFeature(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const IndexedSubfeature&,
- const RenderedQueryOptions& options,
- const CanonicalTileID&,
- const std::unordered_map<std::string, const RenderLayer*>&,
- const GeometryCoordinates& queryGeometry,
- const TransformState& transformState,
- const float pixelsToTileUnits,
- const mat4& posMatrix) const;
+ void addFeature(std::unordered_map<std::string, std::vector<Feature>>& result, const IndexedSubfeature&,
+ const RenderedQueryOptions& options, const CanonicalTileID&,
+ const std::unordered_map<std::string, const RenderLayer*>&,
+ const GeometryCoordinates& queryGeometry, const TransformState& transformState,
+ const float pixelsToTileUnits, const mat4& posMatrix,
+ const SourceFeatureState* sourceFeatureState) const;
GridIndex<IndexedSubfeature> grid;
unsigned int sortIndex = 0;
diff --git a/src/mbgl/gfx/vertex_vector.hpp b/src/mbgl/gfx/vertex_vector.hpp
index 59fe67586b..091ecb912e 100644
--- a/src/mbgl/gfx/vertex_vector.hpp
+++ b/src/mbgl/gfx/vertex_vector.hpp
@@ -20,6 +20,11 @@ public:
v.resize(v.size() + n, val);
}
+ Vertex& at(std::size_t n) {
+ assert(n < v.size());
+ return v.at(n);
+ }
+
std::size_t elements() const {
return v.size();
}
diff --git a/src/mbgl/layout/pattern_layout.hpp b/src/mbgl/layout/pattern_layout.hpp
index 858d515347..d6d878955f 100644
--- a/src/mbgl/layout/pattern_layout.hpp
+++ b/src/mbgl/layout/pattern_layout.hpp
@@ -108,7 +108,7 @@ public:
const PatternLayerMap& patterns = patternFeature.patterns;
const GeometryCollection& geometries = feature->getGeometries();
- bucket->addFeature(*feature, geometries, patternPositions, patterns);
+ bucket->addFeature(*feature, geometries, patternPositions, patterns, i);
featureIndex->insert(geometries, i, sourceLayerID, bucketLeaderID);
}
if (bucket->hasData()) {
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 1dbb5d91dc..81d1d9a5b6 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -713,7 +713,8 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
}
for (auto& pair : bucket->paintProperties) {
- pair.second.iconBinders.populateVertexVectors(feature, iconBuffer.vertices.elements(), {}, {});
+ pair.second.iconBinders.populateVertexVectors(feature, iconBuffer.vertices.elements(),
+ symbolInstance.dataFeatureIndex, {}, {});
}
}
@@ -765,7 +766,8 @@ void SymbolLayout::updatePaintPropertiesForSection(SymbolBucket& bucket,
std::size_t sectionIndex) {
const auto& formattedSection = sectionOptionsToValue((*feature.formattedText).sectionAt(sectionIndex));
for (auto& pair : bucket.paintProperties) {
- pair.second.textBinders.populateVertexVectors(feature, bucket.text.vertices.elements(), {}, {}, formattedSection);
+ pair.second.textBinders.populateVertexVectors(feature, bucket.text.vertices.elements(), feature.index, {}, {},
+ formattedSection);
}
}
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index a978c06d6b..6c74b8309f 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -32,10 +32,10 @@ public:
// Feature geometries are also used to populate the feature index.
// Obtaining these is a costly operation, so we do it only once, and
// pass-by-const-ref the geometries as a second parameter.
- virtual void addFeature(const GeometryTileFeature&,
- const GeometryCollection&,
- const ImagePositions&,
- const PatternLayerMap&) {};
+ virtual void addFeature(const GeometryTileFeature&, const GeometryCollection&, const ImagePositions&,
+ const PatternLayerMap&, std::size_t){};
+
+ virtual void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) {}
// As long as this bucket has a Prepare render pass, this function is getting called. Typically,
// this only happens once when the bucket is being rendered for the first time.
diff --git a/src/mbgl/renderer/buckets/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp
index 7ba130da64..560a74781a 100644
--- a/src/mbgl/renderer/buckets/circle_bucket.cpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.cpp
@@ -25,8 +25,10 @@ CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector
CircleBucket::~CircleBucket() = default;
void CircleBucket::upload(gfx::UploadPass& uploadPass) {
- vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
- indexBuffer = uploadPass.createIndexBuffer(std::move(triangles));
+ if (!uploaded) {
+ vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
+ indexBuffer = uploadPass.createIndexBuffer(std::move(triangles));
+ }
for (auto& pair : paintPropertyBinders) {
pair.second.upload(uploadPass);
@@ -39,10 +41,8 @@ bool CircleBucket::hasData() const {
return !segments.empty();
}
-void CircleBucket::addFeature(const GeometryTileFeature& feature,
- const GeometryCollection& geometry,
- const ImagePositions&,
- const PatternLayerMap&) {
+void CircleBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry,
+ const ImagePositions&, const PatternLayerMap&, std::size_t featureIndex) {
constexpr const uint16_t vertexLength = 4;
for (auto& circle : geometry) {
@@ -90,7 +90,7 @@ void CircleBucket::addFeature(const GeometryTileFeature& feature,
}
for (auto& pair : paintPropertyBinders) {
- pair.second.populateVertexVectors(feature, vertices.elements(), {}, {});
+ pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {});
}
}
@@ -112,4 +112,13 @@ float CircleBucket::getQueryRadius(const RenderLayer& layer) const {
return radius + stroke + util::length(translate[0], translate[1]);
}
+void CircleBucket::update(const FeatureStates& states, const GeometryTileLayer& layer, const std::string& layerID,
+ const ImagePositions& imagePositions) {
+ auto it = paintPropertyBinders.find(layerID);
+ if (it != paintPropertyBinders.end()) {
+ it->second.updateVertexVectors(states, layer, imagePositions);
+ uploaded = false;
+ }
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp
index 27423bc568..e514f8a5f2 100644
--- a/src/mbgl/renderer/buckets/circle_bucket.hpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.hpp
@@ -18,10 +18,8 @@ public:
CircleBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&);
~CircleBucket() override;
- void addFeature(const GeometryTileFeature&,
- const GeometryCollection&,
- const ImagePositions&,
- const PatternLayerMap&) override;
+ void addFeature(const GeometryTileFeature&, const GeometryCollection&, const ImagePositions&,
+ const PatternLayerMap&, std::size_t) override;
bool hasData() const override;
@@ -29,6 +27,8 @@ public:
float getQueryRadius(const RenderLayer&) const override;
+ void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override;
+
gfx::VertexVector<CircleLayoutVertex> vertices;
gfx::IndexVector<gfx::Triangles> triangles;
SegmentVector<CircleAttributes> segments;
diff --git a/src/mbgl/renderer/buckets/fill_bucket.cpp b/src/mbgl/renderer/buckets/fill_bucket.cpp
index 8a089c679e..6660934f8d 100644
--- a/src/mbgl/renderer/buckets/fill_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_bucket.cpp
@@ -44,10 +44,9 @@ FillBucket::FillBucket(const FillBucket::PossiblyEvaluatedLayoutProperties,
FillBucket::~FillBucket() = default;
-void FillBucket::addFeature(const GeometryTileFeature& feature,
- const GeometryCollection& geometry,
- const ImagePositions& patternPositions,
- const PatternLayerMap& patternDependencies) {
+void FillBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry,
+ const ImagePositions& patternPositions, const PatternLayerMap& patternDependencies,
+ std::size_t index) {
for (auto& polygon : classifyRings(geometry)) {
// Optimize polygons with many interior rings for earcut tesselation.
limitHoles(polygon, 500);
@@ -114,17 +113,20 @@ void FillBucket::addFeature(const GeometryTileFeature& feature,
for (auto& pair : paintPropertyBinders) {
const auto it = patternDependencies.find(pair.first);
if (it != patternDependencies.end()){
- pair.second.populateVertexVectors(feature, vertices.elements(), patternPositions, it->second);
+ pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, it->second);
} else {
- pair.second.populateVertexVectors(feature, vertices.elements(), patternPositions, {});
+ pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {});
}
}
}
void FillBucket::upload(gfx::UploadPass& uploadPass) {
- vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
- lineIndexBuffer = uploadPass.createIndexBuffer(std::move(lines));
- triangleIndexBuffer = triangles.empty() ? optional<gfx::IndexBuffer> {} : uploadPass.createIndexBuffer(std::move(triangles));
+ if (!uploaded) {
+ vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
+ lineIndexBuffer = uploadPass.createIndexBuffer(std::move(lines));
+ triangleIndexBuffer =
+ triangles.empty() ? optional<gfx::IndexBuffer>{} : uploadPass.createIndexBuffer(std::move(triangles));
+ }
for (auto& pair : paintPropertyBinders) {
pair.second.upload(uploadPass);
@@ -143,4 +145,13 @@ float FillBucket::getQueryRadius(const RenderLayer& layer) const {
return util::length(translate[0], translate[1]);
}
+void FillBucket::update(const FeatureStates& states, const GeometryTileLayer& layer, const std::string& layerID,
+ const ImagePositions& imagePositions) {
+ auto it = paintPropertyBinders.find(layerID);
+ if (it != paintPropertyBinders.end()) {
+ it->second.updateVertexVectors(states, layer, imagePositions);
+ uploaded = false;
+ }
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp
index 6747c1083f..9f65e774ca 100644
--- a/src/mbgl/renderer/buckets/fill_bucket.hpp
+++ b/src/mbgl/renderer/buckets/fill_bucket.hpp
@@ -26,10 +26,8 @@ public:
const float zoom,
const uint32_t overscaling);
- void addFeature(const GeometryTileFeature&,
- const GeometryCollection&,
- const mbgl::ImagePositions&,
- const PatternLayerMap&) override;
+ void addFeature(const GeometryTileFeature&, const GeometryCollection&, const mbgl::ImagePositions&,
+ const PatternLayerMap&, std::size_t) override;
bool hasData() const override;
@@ -37,6 +35,8 @@ public:
float getQueryRadius(const RenderLayer&) const override;
+ void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override;
+
gfx::VertexVector<FillLayoutVertex> vertices;
gfx::IndexVector<gfx::Lines> lines;
gfx::IndexVector<gfx::Triangles> triangles;
diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
index be13850e55..698895fdcf 100644
--- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
@@ -50,10 +50,9 @@ FillExtrusionBucket::FillExtrusionBucket(const FillExtrusionBucket::PossiblyEval
FillExtrusionBucket::~FillExtrusionBucket() = default;
-void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
- const GeometryCollection& geometry,
- const ImagePositions& patternPositions,
- const PatternLayerMap& patternDependencies) {
+void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry,
+ const ImagePositions& patternPositions, const PatternLayerMap& patternDependencies,
+ std::size_t index) {
for (auto& polygon : classifyRings(geometry)) {
// Optimize polygons with many interior rings for earcut tesselation.
limitHoles(polygon, 500);
@@ -158,16 +157,18 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
for (auto& pair : paintPropertyBinders) {
const auto it = patternDependencies.find(pair.first);
if (it != patternDependencies.end()){
- pair.second.populateVertexVectors(feature, vertices.elements(), patternPositions, it->second);
+ pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, it->second);
} else {
- pair.second.populateVertexVectors(feature, vertices.elements(), patternPositions, {});
+ pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {});
}
}
}
void FillExtrusionBucket::upload(gfx::UploadPass& uploadPass) {
- vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
- indexBuffer = uploadPass.createIndexBuffer(std::move(triangles));
+ if (!uploaded) {
+ vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
+ indexBuffer = uploadPass.createIndexBuffer(std::move(triangles));
+ }
for (auto& pair : paintPropertyBinders) {
pair.second.upload(uploadPass);
@@ -186,4 +187,13 @@ float FillExtrusionBucket::getQueryRadius(const RenderLayer& layer) const {
return util::length(translate[0], translate[1]);
}
+void FillExtrusionBucket::update(const FeatureStates& states, const GeometryTileLayer& layer,
+ const std::string& layerID, const ImagePositions& imagePositions) {
+ auto it = paintPropertyBinders.find(layerID);
+ if (it != paintPropertyBinders.end()) {
+ it->second.updateVertexVectors(states, layer, imagePositions);
+ uploaded = false;
+ }
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
index 4c97618a77..8535f99b70 100644
--- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
@@ -24,10 +24,8 @@ public:
const float,
const uint32_t);
- void addFeature(const GeometryTileFeature&,
- const GeometryCollection&,
- const mbgl::ImagePositions&,
- const PatternLayerMap&) override;
+ void addFeature(const GeometryTileFeature&, const GeometryCollection&, const mbgl::ImagePositions&,
+ const PatternLayerMap&, std::size_t) override;
bool hasData() const override;
@@ -35,6 +33,8 @@ public:
float getQueryRadius(const RenderLayer&) const override;
+ void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override;
+
gfx::VertexVector<FillExtrusionLayoutVertex> vertices;
gfx::IndexVector<gfx::Triangles> triangles;
SegmentVector<FillExtrusionAttributes> triangleSegments;
diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.cpp b/src/mbgl/renderer/buckets/heatmap_bucket.cpp
index fad78f6cec..78c4fb7507 100644
--- a/src/mbgl/renderer/buckets/heatmap_bucket.cpp
+++ b/src/mbgl/renderer/buckets/heatmap_bucket.cpp
@@ -39,10 +39,8 @@ bool HeatmapBucket::hasData() const {
return !segments.empty();
}
-void HeatmapBucket::addFeature(const GeometryTileFeature& feature,
- const GeometryCollection& geometry,
- const ImagePositions&,
- const PatternLayerMap&) {
+void HeatmapBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry,
+ const ImagePositions&, const PatternLayerMap&, std::size_t featureIndex) {
constexpr const uint16_t vertexLength = 4;
for (auto& points : geometry) {
@@ -89,7 +87,7 @@ void HeatmapBucket::addFeature(const GeometryTileFeature& feature,
}
for (auto& pair : paintPropertyBinders) {
- pair.second.populateVertexVectors(feature, vertices.elements(), {}, {});
+ pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {});
}
}
diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.hpp b/src/mbgl/renderer/buckets/heatmap_bucket.hpp
index 68790bf5bf..04d4170b50 100644
--- a/src/mbgl/renderer/buckets/heatmap_bucket.hpp
+++ b/src/mbgl/renderer/buckets/heatmap_bucket.hpp
@@ -18,10 +18,8 @@ public:
HeatmapBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&);
~HeatmapBucket() override;
- void addFeature(const GeometryTileFeature&,
- const GeometryCollection&,
- const ImagePositions&,
- const PatternLayerMap&) override;
+ void addFeature(const GeometryTileFeature&, const GeometryCollection&, const ImagePositions&,
+ const PatternLayerMap&, std::size_t) override;
bool hasData() const override;
void upload(gfx::UploadPass&) override;
diff --git a/src/mbgl/renderer/buckets/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp
index 9019e76d3b..f65c239968 100644
--- a/src/mbgl/renderer/buckets/line_bucket.cpp
+++ b/src/mbgl/renderer/buckets/line_bucket.cpp
@@ -30,10 +30,9 @@ LineBucket::LineBucket(const style::LineLayoutProperties::PossiblyEvaluated layo
LineBucket::~LineBucket() = default;
-void LineBucket::addFeature(const GeometryTileFeature& feature,
- const GeometryCollection& geometryCollection,
- const ImagePositions& patternPositions,
- const PatternLayerMap& patternDependencies) {
+void LineBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometryCollection,
+ const ImagePositions& patternPositions, const PatternLayerMap& patternDependencies,
+ std::size_t index) {
for (auto& line : geometryCollection) {
addGeometry(line, feature);
}
@@ -41,14 +40,13 @@ void LineBucket::addFeature(const GeometryTileFeature& feature,
for (auto& pair : paintPropertyBinders) {
const auto it = patternDependencies.find(pair.first);
if (it != patternDependencies.end()){
- pair.second.populateVertexVectors(feature, vertices.elements(), patternPositions, it->second);
+ pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, it->second);
} else {
- pair.second.populateVertexVectors(feature, vertices.elements(), patternPositions, {});
+ pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {});
}
}
}
-
/*
* Sharp corners cause dashed lines to tilt because the distance along the line
* is the same at both the inner and outer corners. To improve the appearance of
@@ -517,8 +515,10 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex,
}
void LineBucket::upload(gfx::UploadPass& uploadPass) {
- vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
- indexBuffer = uploadPass.createIndexBuffer(std::move(triangles));
+ if (!uploaded) {
+ vertexBuffer = uploadPass.createVertexBuffer(std::move(vertices));
+ indexBuffer = uploadPass.createIndexBuffer(std::move(triangles));
+ }
for (auto& pair : paintPropertyBinders) {
pair.second.upload(uploadPass);
@@ -554,4 +554,13 @@ float LineBucket::getQueryRadius(const RenderLayer& layer) const {
return lineWidth / 2.0f + std::abs(offset) + util::length(translate[0], translate[1]);
}
+void LineBucket::update(const FeatureStates& states, const GeometryTileLayer& layer, const std::string& layerID,
+ const ImagePositions& imagePositions) {
+ auto it = paintPropertyBinders.find(layerID);
+ if (it != paintPropertyBinders.end()) {
+ it->second.updateVertexVectors(states, layer, imagePositions);
+ uploaded = false;
+ }
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp
index eac9e14e4c..6343aab2be 100644
--- a/src/mbgl/renderer/buckets/line_bucket.hpp
+++ b/src/mbgl/renderer/buckets/line_bucket.hpp
@@ -26,10 +26,8 @@ public:
const uint32_t overscaling);
~LineBucket() override;
- void addFeature(const GeometryTileFeature&,
- const GeometryCollection&,
- const mbgl::ImagePositions& patternPositions,
- const PatternLayerMap&) override;
+ void addFeature(const GeometryTileFeature&, const GeometryCollection&, const mbgl::ImagePositions& patternPositions,
+ const PatternLayerMap&, std::size_t) override;
bool hasData() const override;
@@ -37,6 +35,8 @@ public:
float getQueryRadius(const RenderLayer&) const override;
+ void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override;
+
PossiblyEvaluatedLayoutProperties layout;
gfx::VertexVector<LineLayoutVertex> vertices;
diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp
index ea0c20f124..b88a026e11 100644
--- a/src/mbgl/renderer/layers/render_circle_layer.cpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.cpp
@@ -141,13 +141,10 @@ GeometryCoordinates projectQueryGeometry(const GeometryCoordinates& queryGeometr
return projectedGeometry;
}
-bool RenderCircleLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float zoom,
- const TransformState& transformState,
- const float pixelsToTileUnits,
- const mat4& posMatrix) const {
+bool RenderCircleLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature, const float zoom,
+ const TransformState& transformState, const float pixelsToTileUnits,
+ const mat4& posMatrix, const FeatureState& featureState) const {
const auto& evaluated = static_cast<const CircleLayerProperties&>(*evaluatedProperties).evaluated;
// Translate query geometry
const GeometryCoordinates& translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
@@ -158,8 +155,8 @@ bool RenderCircleLayer::queryIntersectsFeature(
pixelsToTileUnits).value_or(queryGeometry);
// Evaluate functions
- auto radius = evaluated.evaluate<style::CircleRadius>(zoom, feature);
- auto stroke = evaluated.evaluate<style::CircleStrokeWidth>(zoom, feature);
+ auto radius = evaluated.evaluate<style::CircleRadius>(zoom, feature, featureState);
+ auto stroke = evaluated.evaluate<style::CircleStrokeWidth>(zoom, feature, featureState);
auto size = radius + stroke;
// For pitch-alignment: map, compare feature geometry to query geometry in the plane of the tile
diff --git a/src/mbgl/renderer/layers/render_circle_layer.hpp b/src/mbgl/renderer/layers/render_circle_layer.hpp
index 9348e48929..70af20f0cf 100644
--- a/src/mbgl/renderer/layers/render_circle_layer.hpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.hpp
@@ -18,13 +18,8 @@ private:
bool hasCrossfade() const override;
void render(PaintParameters&) override;
- bool queryIntersectsFeature(
- const GeometryCoordinates&,
- const GeometryTileFeature&,
- const float,
- const TransformState&,
- const float,
- const mat4&) const override;
+ bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, const float,
+ const TransformState&, const float, const mat4&, const FeatureState&) const override;
// Paint properties
style::CirclePaintProperties::Unevaluated unevaluated;
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
index 835e8c8ee5..fc830e462c 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -224,13 +224,11 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) {
}
}
-bool RenderFillExtrusionLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float,
- const TransformState& transformState,
- const float pixelsToTileUnits,
- const mat4&) const {
+bool RenderFillExtrusionLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature, const float,
+ const TransformState& transformState,
+ const float pixelsToTileUnits, const mat4&,
+ const FeatureState&) const {
const auto& evaluated = static_cast<const FillExtrusionLayerProperties&>(*evaluatedProperties).evaluated;
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry,
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
index 8bd1f52adf..0e6a747c71 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
@@ -20,13 +20,8 @@ private:
bool is3D() const override;
void render(PaintParameters&) override;
- bool queryIntersectsFeature(
- const GeometryCoordinates&,
- const GeometryTileFeature&,
- const float,
- const TransformState&,
- const float,
- const mat4&) const override;
+ bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, const float,
+ const TransformState&, const float, const mat4&, const FeatureState&) const override;
// Paint properties
style::FillExtrusionPaintProperties::Unevaluated unevaluated;
diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp
index 27cb76fede..e855866eea 100644
--- a/src/mbgl/renderer/layers/render_fill_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.cpp
@@ -249,13 +249,10 @@ void RenderFillLayer::render(PaintParameters& parameters) {
}
}
-bool RenderFillLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float,
- const TransformState& transformState,
- const float pixelsToTileUnits,
- const mat4&) const {
+bool RenderFillLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature, const float,
+ const TransformState& transformState, const float pixelsToTileUnits,
+ const mat4&, const FeatureState&) const {
const auto& evaluated = getEvaluated<FillLayerProperties>(evaluatedProperties);
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry,
@@ -267,5 +264,4 @@ bool RenderFillLayer::queryIntersectsFeature(
return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
}
-
} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_fill_layer.hpp b/src/mbgl/renderer/layers/render_fill_layer.hpp
index 79adc9dab4..12484dbfb1 100644
--- a/src/mbgl/renderer/layers/render_fill_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.hpp
@@ -21,13 +21,8 @@ private:
bool hasCrossfade() const override;
void render(PaintParameters&) override;
- bool queryIntersectsFeature(
- const GeometryCoordinates&,
- const GeometryTileFeature&,
- const float,
- const TransformState&,
- const float,
- const mat4&) const override;
+ bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, const float,
+ const TransformState&, const float, const mat4&, const FeatureState&) const override;
// Paint properties
style::FillPaintProperties::Unevaluated unevaluated;
diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
index 4fa20ffd13..797aedd297 100644
--- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp
+++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
@@ -219,13 +219,10 @@ void RenderHeatmapLayer::updateColorRamp() {
}
}
-bool RenderHeatmapLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float zoom,
- const TransformState&,
- const float pixelsToTileUnits,
- const mat4&) const {
+bool RenderHeatmapLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature, const float zoom,
+ const TransformState&, const float pixelsToTileUnits, const mat4&,
+ const FeatureState&) const {
(void) queryGeometry;
(void) feature;
(void) zoom;
diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp
index 27e27adb28..1e9b1063ae 100644
--- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp
+++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp
@@ -22,13 +22,8 @@ private:
void upload(gfx::UploadPass&) override;
void render(PaintParameters&) override;
- bool queryIntersectsFeature(
- const GeometryCoordinates&,
- const GeometryTileFeature&,
- const float,
- const TransformState&,
- const float,
- const mat4&) const override;
+ bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, const float,
+ const TransformState&, const float, const mat4&, const FeatureState&) const override;
// Paint properties
style::HeatmapPaintProperties::Unevaluated unevaluated;
diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp
index 6d635f65e7..36665c1db4 100644
--- a/src/mbgl/renderer/layers/render_line_layer.cpp
+++ b/src/mbgl/renderer/layers/render_line_layer.cpp
@@ -257,13 +257,10 @@ GeometryCollection offsetLine(const GeometryCollection& rings, double offset) {
} // namespace
-bool RenderLineLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float zoom,
- const TransformState& transformState,
- const float pixelsToTileUnits,
- const mat4&) const {
+bool RenderLineLayer::queryIntersectsFeature(const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature, const float zoom,
+ const TransformState& transformState, const float pixelsToTileUnits,
+ const mat4&, const FeatureState& featureState) const {
const auto& evaluated = static_cast<const LineLayerProperties&>(*evaluatedProperties).evaluated;
// Translate query geometry
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
@@ -274,10 +271,11 @@ bool RenderLineLayer::queryIntersectsFeature(
pixelsToTileUnits);
// Evaluate function
- auto offset = evaluated.get<style::LineOffset>()
- .evaluate(feature, zoom, style::LineOffset::defaultValue()) * pixelsToTileUnits;
+ auto offset =
+ evaluated.get<style::LineOffset>().evaluate(feature, zoom, featureState, style::LineOffset::defaultValue()) *
+ pixelsToTileUnits;
// Test intersection
- const float halfWidth = getLineWidth(feature, zoom) / 2.0 * pixelsToTileUnits;
+ const auto halfWidth = static_cast<float>(getLineWidth(feature, zoom, featureState) / 2.0 * pixelsToTileUnits);
// Apply offset to geometry
if (offset != 0.0f && !feature.getGeometries().empty()) {
@@ -314,12 +312,13 @@ void RenderLineLayer::updateColorRamp() {
}
}
-float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const {
+float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom,
+ const FeatureState& featureState) const {
const auto& evaluated = static_cast<const LineLayerProperties&>(*evaluatedProperties).evaluated;
- float lineWidth = evaluated.get<style::LineWidth>()
- .evaluate(feature, zoom, style::LineWidth::defaultValue());
- float gapWidth = evaluated.get<style::LineGapWidth>()
- .evaluate(feature, zoom, style::LineGapWidth::defaultValue());
+ float lineWidth =
+ evaluated.get<style::LineWidth>().evaluate(feature, zoom, featureState, style::LineWidth::defaultValue());
+ float gapWidth =
+ evaluated.get<style::LineGapWidth>().evaluate(feature, zoom, featureState, style::LineGapWidth::defaultValue());
if (gapWidth) {
return gapWidth + 2 * lineWidth;
} else {
diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp
index 4454d215d9..1914a82b77 100644
--- a/src/mbgl/renderer/layers/render_line_layer.hpp
+++ b/src/mbgl/renderer/layers/render_line_layer.hpp
@@ -24,18 +24,13 @@ private:
void upload(gfx::UploadPass&) override;
void render(PaintParameters&) override;
- bool queryIntersectsFeature(
- const GeometryCoordinates&,
- const GeometryTileFeature&,
- const float,
- const TransformState&,
- const float,
- const mat4&) const override;
+ bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, const float,
+ const TransformState&, const float, const mat4&, const FeatureState&) const override;
// Paint properties
style::LinePaintProperties::Unevaluated unevaluated;
- float getLineWidth(const GeometryTileFeature&, const float) const;
+ float getLineWidth(const GeometryTileFeature&, const float, const FeatureState&) const;
void updateColorRamp();
PremultipliedImage colorRamp;
diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp
index cd6b259e88..1a36f8a2e5 100644
--- a/src/mbgl/renderer/paint_property_binder.hpp
+++ b/src/mbgl/renderer/paint_property_binder.hpp
@@ -19,6 +19,15 @@
namespace mbgl {
+// Maps vertex range to feature index
+struct FeatureVertexRange {
+ std::size_t featureIndex;
+ std::size_t start;
+ std::size_t end;
+};
+
+using FeatureVertexRangeMap = std::map<std::string, std::vector<FeatureVertexRange>>;
+
/*
ZoomInterpolatedAttribute<Attr> is a 'compound' attribute, representing two values of the
the base attribute Attr. These two values are provided to the shader to allow interpolation
@@ -96,10 +105,14 @@ public:
virtual ~PaintPropertyBinder() = default;
- virtual void populateVertexVector(const GeometryTileFeature& feature,
- std::size_t length, const ImagePositions&,
- const optional<PatternDependency>&,
+ virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, std::size_t index,
+ const ImagePositions&, const optional<PatternDependency>&,
const style::expression::Value&) = 0;
+
+ virtual void updateVertexVectors(const FeatureStates&, const GeometryTileLayer&, const ImagePositions&) {}
+
+ virtual void updateVertexVector(std::size_t, std::size_t, const GeometryTileFeature&, const FeatureState&) = 0;
+
virtual void upload(gfx::UploadPass&) = 0;
virtual void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, const CrossfadeParameters&) = 0;
virtual std::tuple<ExpandToType<As, optional<gfx::AttributeBinding>>...> attributeBinding(const PossiblyEvaluatedType& currentValue) const = 0;
@@ -118,7 +131,9 @@ public:
: constant(std::move(constant_)) {
}
- void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value&) override {}
+ void populateVertexVector(const GeometryTileFeature&, std::size_t, std::size_t, const ImagePositions&,
+ const optional<PatternDependency>&, const style::expression::Value&) override {}
+ void updateVertexVector(std::size_t, std::size_t, const GeometryTileFeature&, const FeatureState&) override {}
void upload(gfx::UploadPass&) override {}
void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, const CrossfadeParameters&) override {};
@@ -145,7 +160,9 @@ public:
: constant(std::move(constant_)), constantPatternPositions({}) {
}
- void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value&) override {}
+ void populateVertexVector(const GeometryTileFeature&, std::size_t, std::size_t, const ImagePositions&,
+ const optional<PatternDependency>&, const style::expression::Value&) override {}
+ void updateVertexVector(std::size_t, std::size_t, const GeometryTileFeature&, const FeatureState&) override {}
void upload(gfx::UploadPass&) override {}
void setPatternParameters(const optional<ImagePosition>& posA, const optional<ImagePosition>& posB, const CrossfadeParameters&) override {
@@ -187,14 +204,50 @@ public:
defaultValue(std::move(defaultValue_)) {
}
void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, const CrossfadeParameters&) override {};
- void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value& formattedSection) override {
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, std::size_t index,
+ const ImagePositions&, const optional<PatternDependency>&,
+ const style::expression::Value& formattedSection) override {
using style::expression::EvaluationContext;
auto evaluated = expression.evaluate(EvaluationContext(&feature).withFormattedSection(&formattedSection), defaultValue);
this->statistics.add(evaluated);
auto value = attributeValue(evaluated);
- for (std::size_t i = vertexVector.elements(); i < length; ++i) {
+ auto elements = vertexVector.elements();
+ for (std::size_t i = elements; i < length; ++i) {
vertexVector.emplace_back(BaseVertex { value });
}
+ optional<std::string> idStr = featureIDtoString(feature.getID());
+ if (idStr) {
+ featureMap[*idStr].emplace_back(FeatureVertexRange{index, elements, length});
+ }
+ }
+
+ void updateVertexVectors(const FeatureStates& states, const GeometryTileLayer& layer,
+ const ImagePositions&) override {
+ for (const auto& it : states) {
+ const auto positions = featureMap.find(it.first);
+ if (positions == featureMap.end()) {
+ continue;
+ }
+
+ for (const auto& pos : positions->second) {
+ std::unique_ptr<GeometryTileFeature> feature = layer.getFeature(pos.featureIndex);
+ if (feature) {
+ updateVertexVector(pos.start, pos.end, *feature, it.second);
+ }
+ }
+ }
+ }
+
+ void updateVertexVector(std::size_t start, std::size_t end, const GeometryTileFeature& feature,
+ const FeatureState& state) override {
+ using style::expression::EvaluationContext;
+
+ auto evaluated = expression.evaluate(EvaluationContext(&feature).withFeatureState(&state), defaultValue);
+ this->statistics.add(evaluated);
+ auto value = attributeValue(evaluated);
+ for (std::size_t i = start; i < end; ++i) {
+ vertexVector.at(i) = BaseVertex{value};
+ }
}
void upload(gfx::UploadPass& uploadPass) override {
@@ -229,6 +282,7 @@ private:
T defaultValue;
gfx::VertexVector<BaseVertex> vertexVector;
optional<gfx::VertexBuffer<BaseVertex>> vertexBuffer;
+ FeatureVertexRangeMap featureMap;
};
template <class T, class A>
@@ -245,7 +299,9 @@ public:
zoomRange({zoom, zoom + 1}) {
}
void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, const CrossfadeParameters&) override {};
- void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value& formattedSection) override {
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, std::size_t index,
+ const ImagePositions&, const optional<PatternDependency>&,
+ const style::expression::Value& formattedSection) override {
using style::expression::EvaluationContext;
Range<T> range = {
expression.evaluate(EvaluationContext(zoomRange.min, &feature).withFormattedSection(&formattedSection), defaultValue),
@@ -256,9 +312,47 @@ public:
AttributeValue value = zoomInterpolatedAttributeValue(
attributeValue(range.min),
attributeValue(range.max));
- for (std::size_t i = vertexVector.elements(); i < length; ++i) {
+ auto elements = vertexVector.elements();
+ for (std::size_t i = elements; i < length; ++i) {
vertexVector.emplace_back(Vertex { value });
}
+ optional<std::string> idStr = featureIDtoString(feature.getID());
+ if (idStr) {
+ featureMap[*idStr].emplace_back(FeatureVertexRange{index, elements, length});
+ }
+ }
+
+ void updateVertexVectors(const FeatureStates& states, const GeometryTileLayer& layer,
+ const ImagePositions&) override {
+ for (const auto& it : states) {
+ const auto positions = featureMap.find(it.first);
+ if (positions == featureMap.end()) {
+ continue;
+ }
+
+ for (const auto& pos : positions->second) {
+ std::unique_ptr<GeometryTileFeature> feature = layer.getFeature(pos.featureIndex);
+ if (feature) {
+ updateVertexVector(pos.start, pos.end, *feature, it.second);
+ }
+ }
+ }
+ }
+
+ void updateVertexVector(std::size_t start, std::size_t end, const GeometryTileFeature& feature,
+ const FeatureState& state) override {
+ using style::expression::EvaluationContext;
+ Range<T> range = {
+ expression.evaluate(EvaluationContext(zoomRange.min, &feature, &state), defaultValue),
+ expression.evaluate(EvaluationContext(zoomRange.max, &feature, &state), defaultValue),
+ };
+ this->statistics.add(range.min);
+ this->statistics.add(range.max);
+ AttributeValue value = zoomInterpolatedAttributeValue(attributeValue(range.min), attributeValue(range.max));
+
+ for (std::size_t i = start; i < end; ++i) {
+ vertexVector.at(i) = Vertex{value};
+ }
}
void upload(gfx::UploadPass& uploadPass) override {
@@ -298,6 +392,7 @@ private:
Range<float> zoomRange;
gfx::VertexVector<Vertex> vertexVector;
optional<gfx::VertexBuffer<Vertex>> vertexBuffer;
+ FeatureVertexRangeMap featureMap;
};
template <class T, class A1, class A2>
@@ -322,8 +417,10 @@ public:
crossfade = crossfade_;
};
- void populateVertexVector(const GeometryTileFeature&, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies, const style::expression::Value&) override {
-
+ void populateVertexVector(const GeometryTileFeature&, std::size_t length, std::size_t /* index */,
+ const ImagePositions& patternPositions,
+ const optional<PatternDependency>& patternDependencies,
+ const style::expression::Value&) override {
if (!patternDependencies || patternDependencies->mid.empty()) {
// Unlike other propperties with expressions that evaluate to null, the default value for `*-pattern` properties is an empty
// string and will not have a valid entry in patternPositions. We still need to populate the attribute buffers to avoid crashes
@@ -353,6 +450,8 @@ public:
}
}
+ void updateVertexVector(std::size_t, std::size_t, const GeometryTileFeature&, const FeatureState&) override {}
+
void upload(gfx::UploadPass& uploadPass) override {
if (!patternToVertexVector.empty()) {
assert(!zoomInVertexVector.empty());
@@ -491,10 +590,18 @@ public:
PaintPropertyBinders(PaintPropertyBinders&&) = default;
PaintPropertyBinders(const PaintPropertyBinders&) = delete;
- void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies, const style::expression::Value& formattedSection = {}) {
- util::ignore({
- (binders.template get<Ps>()->populateVertexVector(feature, length, patternPositions, patternDependencies, formattedSection), 0)...
- });
+ void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, std::size_t index,
+ const ImagePositions& patternPositions,
+ const optional<PatternDependency>& patternDependencies,
+ const style::expression::Value& formattedSection = {}) {
+ util::ignore({(binders.template get<Ps>()->populateVertexVector(feature, length, index, patternPositions,
+ patternDependencies, formattedSection),
+ 0)...});
+ }
+
+ void updateVertexVectors(const FeatureStates& states, const GeometryTileLayer& layer,
+ const ImagePositions& imagePositions) {
+ util::ignore({(binders.template get<Ps>()->updateVertexVectors(states, layer, imagePositions), 0)...});
}
void setPatternParameters(const optional<ImagePosition>& posA, const optional<ImagePosition>& posB, const CrossfadeParameters& crossfade) const {
diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp
index 625235011c..1198e43aae 100644
--- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp
+++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp
@@ -49,6 +49,14 @@ public:
}
);
}
+
+ template <class Feature>
+ T evaluate(const Feature& feature, float zoom, const FeatureState& featureState, T defaultValue) const {
+ return this->match([&](const T& constant_) { return constant_; },
+ [&](const style::PropertyExpression<T>& expression) {
+ return expression.evaluate(zoom, feature, featureState, defaultValue);
+ });
+ }
};
template <class T>
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index 75c729444b..ba3c638f88 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -88,13 +88,10 @@ public:
// Check wether the given geometry intersects
// with the feature
- virtual bool queryIntersectsFeature(
- const GeometryCoordinates&,
- const GeometryTileFeature&,
- const float,
- const TransformState&,
- const float,
- const mat4&) const { return false; };
+ virtual bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, const float,
+ const TransformState&, const float, const mat4&, const FeatureState&) const {
+ return false;
+ };
virtual void prepare(const LayerPrepareParameters&);
diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp
index a62ccb0a0a..a1280331b1 100644
--- a/src/mbgl/renderer/render_orchestrator.cpp
+++ b/src/mbgl/renderer/render_orchestrator.cpp
@@ -562,6 +562,29 @@ FeatureExtensionValue RenderOrchestrator::queryFeatureExtensions(const std::stri
return {};
}
+void RenderOrchestrator::setFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const std::string& featureID, const FeatureState& state) {
+ if (RenderSource* renderSource = getRenderSource(sourceID)) {
+ renderSource->setFeatureState(sourceLayerID, featureID, state);
+ }
+}
+
+void RenderOrchestrator::getFeatureState(FeatureState& state, const std::string& sourceID,
+ const optional<std::string>& sourceLayerID,
+ const std::string& featureID) const {
+ if (RenderSource* renderSource = getRenderSource(sourceID)) {
+ renderSource->getFeatureState(state, sourceLayerID, featureID);
+ }
+}
+
+void RenderOrchestrator::removeFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const optional<std::string>& featureID,
+ const optional<std::string>& stateKey) {
+ if (RenderSource* renderSource = getRenderSource(sourceID)) {
+ renderSource->removeFeatureState(sourceLayerID, featureID, stateKey);
+ }
+}
+
void RenderOrchestrator::reduceMemoryUse() {
filteredLayersForSource.shrink_to_fit();
for (const auto& entry : renderSources) {
diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp
index 884bd21b7b..34b623348f 100644
--- a/src/mbgl/renderer/render_orchestrator.hpp
+++ b/src/mbgl/renderer/render_orchestrator.hpp
@@ -64,6 +64,15 @@ public:
const std::string& extensionField,
const optional<std::map<std::string, Value>>& args) const;
+ void setFeatureState(const std::string& sourceID, const optional<std::string>& layerID,
+ const std::string& featureID, const FeatureState& state);
+
+ void getFeatureState(FeatureState& state, const std::string& sourceID, const optional<std::string>& layerID,
+ const std::string& featureID) const;
+
+ void removeFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const optional<std::string>& featureID, const optional<std::string>& stateKey);
+
void reduceMemoryUse();
void dumpDebugLogs();
diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp
index cd471223a8..ee90e1c4d0 100644
--- a/src/mbgl/renderer/render_source.hpp
+++ b/src/mbgl/renderer/render_source.hpp
@@ -93,6 +93,13 @@ public:
return {};
}
+ virtual void setFeatureState(const optional<std::string>&, const std::string&, const FeatureState&) {}
+
+ virtual void getFeatureState(FeatureState&, const optional<std::string>&, const std::string&) const {}
+
+ virtual void removeFeatureState(const optional<std::string>&, const optional<std::string>&,
+ const optional<std::string>&) {}
+
virtual void reduceMemoryUse() = 0;
virtual void dumpDebugLogs() const = 0;
diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp
index 65a6cb9f30..0d63e5b265 100644
--- a/src/mbgl/renderer/render_tile.cpp
+++ b/src/mbgl/renderer/render_tile.cpp
@@ -227,4 +227,8 @@ void RenderTile::finishRender(PaintParameters& parameters) const {
}
}
+void RenderTile::setFeatureState(const LayerFeatureStates& states) {
+ tile.setFeatureState(states);
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp
index 34d027cae5..483dbf7413 100644
--- a/src/mbgl/renderer/render_tile.hpp
+++ b/src/mbgl/renderer/render_tile.hpp
@@ -68,6 +68,9 @@ public:
style::TranslateAnchorType anchor,
const TransformState& state,
const bool inViewportPixelUnits) const;
+
+ void setFeatureState(const LayerFeatureStates&);
+
private:
Tile& tile;
// The following members are reset at placement stage.
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
index 52cd7a4351..cf4072036c 100644
--- a/src/mbgl/renderer/renderer.cpp
+++ b/src/mbgl/renderer/renderer.cpp
@@ -109,6 +109,21 @@ FeatureExtensionValue Renderer::queryFeatureExtensions(const std::string& source
return impl->orchestrator.queryFeatureExtensions(sourceID, feature, extension, extensionField, args);
}
+void Renderer::setFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const std::string& featureID, const FeatureState& state) {
+ impl->orchestrator.setFeatureState(sourceID, sourceLayerID, featureID, state);
+}
+
+void Renderer::getFeatureState(FeatureState& state, const std::string& sourceID,
+ const optional<std::string>& sourceLayerID, const std::string& featureID) const {
+ impl->orchestrator.getFeatureState(state, sourceID, sourceLayerID, featureID);
+}
+
+void Renderer::removeFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
+ const optional<std::string>& featureID, const optional<std::string>& stateKey) {
+ impl->orchestrator.removeFeatureState(sourceID, sourceLayerID, featureID, stateKey);
+}
+
void Renderer::dumpDebugLogs() {
impl->orchestrator.dumpDebugLogs();
}
diff --git a/src/mbgl/renderer/source_state.cpp b/src/mbgl/renderer/source_state.cpp
new file mode 100644
index 0000000000..d057c211b5
--- /dev/null
+++ b/src/mbgl/renderer/source_state.cpp
@@ -0,0 +1,132 @@
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/source_state.hpp>
+#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/util/logging.hpp>
+
+namespace mbgl {
+
+void SourceFeatureState::updateState(const optional<std::string>& sourceLayerID, const std::string& featureID,
+ const FeatureState& newState) {
+ std::string sourceLayer = sourceLayerID.value_or(std::string());
+ for (const auto& state : newState) {
+ auto& layerStates = stateChanges[sourceLayer];
+ auto& featureStates = layerStates[featureID];
+ featureStates[state.first] = state.second;
+ }
+}
+
+void SourceFeatureState::getState(FeatureState& result, const optional<std::string>& sourceLayerID,
+ const std::string& featureID) const {
+ std::string sourceLayer = sourceLayerID.value_or(std::string());
+ FeatureState current;
+ FeatureState changes;
+ auto layerStates = currentStates.find(sourceLayer);
+ if (layerStates != currentStates.end()) {
+ const auto currentStateEntry = layerStates->second.find(featureID);
+ if (currentStateEntry != layerStates->second.end()) {
+ current = currentStateEntry->second;
+ }
+ }
+
+ layerStates = stateChanges.find(sourceLayer);
+ if (layerStates != stateChanges.end()) {
+ const auto stateChangesEntry = layerStates->second.find(featureID);
+ if (stateChangesEntry != layerStates->second.end()) {
+ changes = stateChangesEntry->second;
+ }
+ }
+ result = std::move(changes);
+ result.insert(current.begin(), current.end());
+}
+
+void SourceFeatureState::coalesceChanges(std::vector<RenderTile>& tiles) {
+ LayerFeatureStates changes;
+ for (const auto& layerStatesEntry : stateChanges) {
+ const auto& sourceLayer = layerStatesEntry.first;
+ FeatureStates layerStates;
+ for (const auto& featureStatesEntry : stateChanges[sourceLayer]) {
+ const auto& featureID = featureStatesEntry.first;
+ for (const auto& stateEntry : stateChanges[sourceLayer][featureID]) {
+ const auto& stateKey = stateEntry.first;
+ const auto& stateVal = stateEntry.second;
+
+ auto currentState = currentStates[sourceLayer][featureID].find(stateKey);
+ if (currentState != currentStates[sourceLayer][featureID].end()) {
+ currentState->second = stateVal;
+ } else {
+ currentStates[sourceLayer][featureID].insert(std::make_pair(stateKey, stateVal));
+ }
+ }
+ layerStates[featureID] = currentStates[sourceLayer][featureID];
+ }
+ changes[sourceLayer] = std::move(layerStates);
+ }
+
+ for (const auto& layerStatesEntry : deletedStates) {
+ const auto& sourceLayer = layerStatesEntry.first;
+ FeatureStates layerStates = {{}, {}};
+
+ if (deletedStates[sourceLayer].empty()) {
+ for (const auto& featureStatesEntry : currentStates[sourceLayer]) {
+ const auto& featureID = featureStatesEntry.first;
+ layerStates[featureID] = {};
+ currentStates[sourceLayer][featureID] = {};
+ }
+ } else {
+ for (const auto& feature : deletedStates[sourceLayer]) {
+ const auto& featureID = feature.first;
+ bool deleteWholeFeatureState = deletedStates[sourceLayer][featureID].empty();
+ if (deleteWholeFeatureState) {
+ currentStates[sourceLayer][featureID] = {};
+ } else {
+ for (const auto& stateEntry : deletedStates[sourceLayer][featureID]) {
+ currentStates[sourceLayer][featureID].erase(stateEntry.first);
+ }
+ }
+ layerStates[featureID] = currentStates[sourceLayer][featureID];
+ }
+ }
+ changes[sourceLayer] = std::move(layerStates);
+ }
+
+ stateChanges.clear();
+ deletedStates.clear();
+
+ if (changes.empty()) {
+ return;
+ }
+
+ for (auto& tile : tiles) {
+ tile.setFeatureState(changes);
+ }
+}
+
+void SourceFeatureState::removeState(const optional<std::string>& sourceLayerID, const optional<std::string>& featureID,
+ const optional<std::string>& stateKey) {
+ std::string sourceLayer = sourceLayerID.value_or(std::string());
+
+ bool sourceLayerDeleted = (deletedStates.count(sourceLayer) > 0) && deletedStates[sourceLayer].empty();
+ if (sourceLayerDeleted) {
+ return;
+ }
+
+ if (stateKey && featureID) {
+ if ((deletedStates.count(sourceLayer) == 0) && (deletedStates[sourceLayer].count(*featureID)) == 0) {
+ deletedStates[sourceLayer][*featureID][*stateKey] = {};
+ }
+ } else if (featureID) {
+ bool updateInQueue =
+ (stateChanges.count(sourceLayer) != 0U) && (stateChanges[sourceLayer].count(*featureID) != 0U);
+ if (updateInQueue) {
+ for (const auto& changeEntry : stateChanges[sourceLayer][*featureID]) {
+ deletedStates[sourceLayer][*featureID][changeEntry.first] = {};
+ }
+ } else {
+ deletedStates[sourceLayer][*featureID] = {};
+ }
+ } else {
+ deletedStates[sourceLayer] = {};
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/source_state.hpp b/src/mbgl/renderer/source_state.hpp
new file mode 100644
index 0000000000..7217302630
--- /dev/null
+++ b/src/mbgl/renderer/source_state.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/feature.hpp>
+
+namespace mbgl {
+
+class RenderTile;
+
+class SourceFeatureState {
+public:
+ SourceFeatureState() = default;
+ ~SourceFeatureState() = default;
+
+ void updateState(const optional<std::string>& sourceLayerID, const std::string& featureID,
+ const FeatureState& newState);
+ void getState(FeatureState& result, const optional<std::string>& sourceLayerID, const std::string& featureID) const;
+ void removeState(const optional<std::string>& sourceLayerID, const optional<std::string>& featureID,
+ const optional<std::string>& stateKey);
+
+ void coalesceChanges(std::vector<RenderTile>& tiles);
+
+private:
+ LayerFeatureStates currentStates;
+ LayerFeatureStates stateChanges;
+ LayerFeatureStates deletedStates;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_tile_source.cpp b/src/mbgl/renderer/sources/render_tile_source.cpp
index c5afb38435..221f976c50 100644
--- a/src/mbgl/renderer/sources/render_tile_source.cpp
+++ b/src/mbgl/renderer/sources/render_tile_source.cpp
@@ -68,6 +68,7 @@ void RenderTileSource::prepare(const SourcePrepareParameters& parameters) {
tiles->emplace_back(entry.first, entry.second);
tiles->back().prepare(parameters);
}
+ featureState.coalesceChanges(*tiles);
renderTiles = std::move(tiles);
}
@@ -126,13 +127,29 @@ RenderTileSource::queryRenderedFeatures(const ScreenLineString& geometry,
const std::unordered_map<std::string, const RenderLayer*>& layers,
const RenderedQueryOptions& options,
const mat4& projMatrix) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix, featureState);
}
std::vector<Feature> RenderTileSource::querySourceFeatures(const SourceQueryOptions& options) const {
return tilePyramid.querySourceFeatures(options);
}
+void RenderTileSource::setFeatureState(const optional<std::string>& sourceLayerID, const std::string& featureID,
+ const FeatureState& state) {
+ featureState.updateState(sourceLayerID, featureID, state);
+}
+
+void RenderTileSource::getFeatureState(FeatureState& state, const optional<std::string>& sourceLayerID,
+ const std::string& featureID) const {
+ featureState.getState(state, sourceLayerID, featureID);
+}
+
+void RenderTileSource::removeFeatureState(const optional<std::string>& sourceLayerID,
+ const optional<std::string>& featureID,
+ const optional<std::string>& stateKey) {
+ featureState.removeState(sourceLayerID, featureID, stateKey);
+}
+
void RenderTileSource::reduceMemoryUse() {
tilePyramid.reduceMemoryUse();
}
diff --git a/src/mbgl/renderer/sources/render_tile_source.hpp b/src/mbgl/renderer/sources/render_tile_source.hpp
index 7edff726d5..7756bd8ed0 100644
--- a/src/mbgl/renderer/sources/render_tile_source.hpp
+++ b/src/mbgl/renderer/sources/render_tile_source.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/source_state.hpp>
#include <mbgl/renderer/tile_pyramid.hpp>
#include <mbgl/style/sources/vector_source_impl.hpp>
@@ -34,6 +35,13 @@ public:
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const override;
+ void setFeatureState(const optional<std::string>&, const std::string&, const FeatureState&) override;
+
+ void getFeatureState(FeatureState& state, const optional<std::string>&, const std::string&) const override;
+
+ void removeFeatureState(const optional<std::string>&, const optional<std::string>&,
+ const optional<std::string>&) override;
+
void reduceMemoryUse() override;
void dumpDebugLogs() const override;
@@ -43,7 +51,10 @@ protected:
Immutable<std::vector<RenderTile>> renderTiles;
mutable RenderTiles filteredRenderTiles;
mutable RenderTiles renderTilesSortedByY;
- float bearing = 0.0f;
+
+private:
+ float bearing = 0.0F;
+ SourceFeatureState featureState;
};
/**
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index 7f0fad1500..2bf6e2e1a9 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -278,12 +278,10 @@ void TilePyramid::handleWrapJump(float lng) {
}
}
-
-std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry,
- const TransformState& transformState,
- const std::unordered_map<std::string, const RenderLayer*>& layers,
- const RenderedQueryOptions& options,
- const mat4& projMatrix) const {
+std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(
+ const ScreenLineString& geometry, const TransformState& transformState,
+ const std::unordered_map<std::string, const RenderLayer*>& layers, const RenderedQueryOptions& options,
+ const mat4& projMatrix, const SourceFeatureState& featureState) const {
std::unordered_map<std::string, std::vector<Feature>> result;
if (renderedTiles.empty() || geometry.empty()) {
return result;
@@ -331,12 +329,8 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
tileSpaceQueryGeometry.push_back(TileCoordinate::toGeometryCoordinate(id, c));
}
- tile.queryRenderedFeatures(result,
- tileSpaceQueryGeometry,
- transformState,
- layers,
- options,
- projMatrix);
+ tile.queryRenderedFeatures(result, tileSpaceQueryGeometry, transformState, layers, options, projMatrix,
+ featureState);
}
return result;
diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp
index f80eb0db78..3b5cab5d6c 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -49,12 +49,10 @@ public:
void handleWrapJump(float lng);
- std::unordered_map<std::string, std::vector<Feature>>
- queryRenderedFeatures(const ScreenLineString& geometry,
- const TransformState& transformState,
- const std::unordered_map<std::string, const RenderLayer*>&,
- const RenderedQueryOptions& options,
- const mat4& projMatrix) const;
+ std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(
+ const ScreenLineString& geometry, const TransformState& transformState,
+ const std::unordered_map<std::string, const RenderLayer*>&, const RenderedQueryOptions& options,
+ const mat4& projMatrix, const mbgl::SourceFeatureState& featureState) const;
std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const;
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index c637856ad9..c2bc511e41 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -675,6 +675,21 @@ const auto& errorCompoundExpression() {
return signature;
}
+const auto& featureStateCompoundExpression() {
+ static auto signature = detail::makeSignature(
+ "feature-state", [](const EvaluationContext& params, const std::string& key) -> Result<Value> {
+ mbgl::Value state;
+ if (params.featureState != nullptr) {
+ auto it = params.featureState->find(key);
+ if (it != params.featureState->end()) {
+ state = mbgl::Value(it->second);
+ }
+ }
+ return toExpressionValue(state);
+ });
+ return signature;
+}
+
// Legacy Filters
const auto& filterEqualsCompoundExpression() {
static auto signature = detail::makeSignature("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result<bool> {
@@ -872,81 +887,83 @@ const auto& filterInCompoundExpression() {
}
using ParseCompoundFunction = const std::unique_ptr<detail::SignatureBase>& (*)();
-MAPBOX_ETERNAL_CONSTEXPR const auto compoundExpressionRegistry = mapbox::eternal::hash_map<mapbox::eternal::string, ParseCompoundFunction>({
- { "e", eCompoundExpression },
- { "pi", piCompoundExpression },
- { "ln2", ln2CompoundExpression },
- { "typeof", typeofCompoundExpression },
- { "to-rgba", toRgbaCompoundExpression },
- { "rgba", rgbaCompoundExpression },
- { "rgb", rgbCompoundExpression },
- { "zoom", zoomCompoundExpression },
- { "heatmap-density", heatmapDensityCompoundExpression },
- { "line-progress", lineProgressCompoundExpression },
- { "accumulated", accumulatedCompoundExpression },
- { "has", hasContextCompoundExpression },
- { "has", hasObjectCompoundExpression },
- { "get", getContextCompoundExpression },
- { "get", getObjectCompoundExpression },
- { "properties", propertiesCompoundExpression },
- { "geometry-type", geometryTypeCompoundExpression },
- { "id", idCompoundExpression },
- { "+", plusCompoundExpression },
- { "-", minusCompoundExpression },
- { "-", negateCompoundExpression },
- { "*", multiplyCompoundExpression },
- { "/", divideCompoundExpression },
- { "%", modCompoundExpression },
- { "^", powCompoundExpression },
- { "sqrt", sqrtCompoundExpression },
- { "log10", log10CompoundExpression },
- { "ln", lnCompoundExpression },
- { "log2", log2CompoundExpression },
- { "sin", sinCompoundExpression },
- { "cos", cosCompoundExpression },
- { "tan", tanCompoundExpression },
- { "asin", asinCompoundExpression },
- { "acos", acosCompoundExpression },
- { "atan", atanCompoundExpression },
- { "min", minCompoundExpression },
- { "max", maxCompoundExpression },
- { "round", roundCompoundExpression },
- { "floor", floorCompoundExpression },
- { "ceil", ceilCompoundExpression },
- { "abs", absCompoundExpression },
- { "!", notCompoundExpression },
- { "is-supported-script", isSupportedScriptCompoundExpression },
- { "upcase", upcaseCompoundExpression },
- { "downcase", downcaseCompoundExpression },
- { "concat", concatCompoundExpression },
- { "resolved-locale", resolvedLocaleCompoundExpression },
- { "error", errorCompoundExpression },
- // Legacy Filters
- { "filter-==", filterEqualsCompoundExpression },
- { "filter-id-==", filterIdEqualsCompoundExpression },
- { "filter-type-==", filterTypeEqualsCompoundExpression },
- { "filter-<", filterLessThanNumberCompoundExpression },
- { "filter-<", filterLessThanStringCompoundExpression },
- { "filter-id-<", filterIdLessThanNumberCompoundExpression },
- { "filter-id-<", filterIdLessThanStringCompoundExpression },
- { "filter->", filterMoreThanNumberCompoundExpression },
- { "filter->", filterMoreThanStringCompoundExpression },
- { "filter-id->", filterIdMoreThanNumberCompoundExpression },
- { "filter-id->", filterIdMoreThanStringCompoundExpression },
- { "filter-<=", filterLessOrEqualThanNumberCompoundExpression },
- { "filter-<=", filterLessOrEqualThanStringCompoundExpression },
- { "filter-id-<=", filterIdLessOrEqualThanNumberCompoundExpression },
- { "filter-id-<=", filterIdLessOrEqualThanStringCompoundExpression },
- { "filter->=", filterGreaterOrEqualThanNumberCompoundExpression },
- { "filter->=", filterGreaterOrEqualThanStringCompoundExpression },
- { "filter-id->=", filterIdGreaterOrEqualThanNumberCompoundExpression },
- { "filter-id->=", filterIdGreaterOrEqualThanStringCompoundExpression },
- { "filter-has", filterHasCompoundExpression },
- { "filter-has-id", filterHasIdCompoundExpression },
- { "filter-type-in", filterTypeInCompoundExpression },
- { "filter-id-in", filterIdInCompoundExpression },
- { "filter-in", filterInCompoundExpression },
-});
+MAPBOX_ETERNAL_CONSTEXPR const auto compoundExpressionRegistry =
+ mapbox::eternal::hash_map<mapbox::eternal::string, ParseCompoundFunction>({
+ {"e", eCompoundExpression},
+ {"pi", piCompoundExpression},
+ {"ln2", ln2CompoundExpression},
+ {"typeof", typeofCompoundExpression},
+ {"to-rgba", toRgbaCompoundExpression},
+ {"rgba", rgbaCompoundExpression},
+ {"rgb", rgbCompoundExpression},
+ {"zoom", zoomCompoundExpression},
+ {"heatmap-density", heatmapDensityCompoundExpression},
+ {"line-progress", lineProgressCompoundExpression},
+ {"accumulated", accumulatedCompoundExpression},
+ {"has", hasContextCompoundExpression},
+ {"has", hasObjectCompoundExpression},
+ {"get", getContextCompoundExpression},
+ {"get", getObjectCompoundExpression},
+ {"properties", propertiesCompoundExpression},
+ {"geometry-type", geometryTypeCompoundExpression},
+ {"id", idCompoundExpression},
+ {"+", plusCompoundExpression},
+ {"-", minusCompoundExpression},
+ {"-", negateCompoundExpression},
+ {"*", multiplyCompoundExpression},
+ {"/", divideCompoundExpression},
+ {"%", modCompoundExpression},
+ {"^", powCompoundExpression},
+ {"sqrt", sqrtCompoundExpression},
+ {"log10", log10CompoundExpression},
+ {"ln", lnCompoundExpression},
+ {"log2", log2CompoundExpression},
+ {"sin", sinCompoundExpression},
+ {"cos", cosCompoundExpression},
+ {"tan", tanCompoundExpression},
+ {"asin", asinCompoundExpression},
+ {"acos", acosCompoundExpression},
+ {"atan", atanCompoundExpression},
+ {"min", minCompoundExpression},
+ {"max", maxCompoundExpression},
+ {"round", roundCompoundExpression},
+ {"floor", floorCompoundExpression},
+ {"ceil", ceilCompoundExpression},
+ {"abs", absCompoundExpression},
+ {"!", notCompoundExpression},
+ {"is-supported-script", isSupportedScriptCompoundExpression},
+ {"upcase", upcaseCompoundExpression},
+ {"downcase", downcaseCompoundExpression},
+ {"concat", concatCompoundExpression},
+ {"resolved-locale", resolvedLocaleCompoundExpression},
+ {"error", errorCompoundExpression},
+ {"feature-state", featureStateCompoundExpression},
+ // Legacy Filters
+ {"filter-==", filterEqualsCompoundExpression},
+ {"filter-id-==", filterIdEqualsCompoundExpression},
+ {"filter-type-==", filterTypeEqualsCompoundExpression},
+ {"filter-<", filterLessThanNumberCompoundExpression},
+ {"filter-<", filterLessThanStringCompoundExpression},
+ {"filter-id-<", filterIdLessThanNumberCompoundExpression},
+ {"filter-id-<", filterIdLessThanStringCompoundExpression},
+ {"filter->", filterMoreThanNumberCompoundExpression},
+ {"filter->", filterMoreThanStringCompoundExpression},
+ {"filter-id->", filterIdMoreThanNumberCompoundExpression},
+ {"filter-id->", filterIdMoreThanStringCompoundExpression},
+ {"filter-<=", filterLessOrEqualThanNumberCompoundExpression},
+ {"filter-<=", filterLessOrEqualThanStringCompoundExpression},
+ {"filter-id-<=", filterIdLessOrEqualThanNumberCompoundExpression},
+ {"filter-id-<=", filterIdLessOrEqualThanStringCompoundExpression},
+ {"filter->=", filterGreaterOrEqualThanNumberCompoundExpression},
+ {"filter->=", filterGreaterOrEqualThanStringCompoundExpression},
+ {"filter-id->=", filterIdGreaterOrEqualThanNumberCompoundExpression},
+ {"filter-id->=", filterIdGreaterOrEqualThanStringCompoundExpression},
+ {"filter-has", filterHasCompoundExpression},
+ {"filter-has-id", filterHasIdCompoundExpression},
+ {"filter-type-in", filterTypeInCompoundExpression},
+ {"filter-id-in", filterIdInCompoundExpression},
+ {"filter-in", filterInCompoundExpression},
+ });
using namespace mbgl::style::conversion;
diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp
index 9704168a41..4c4684c86a 100644
--- a/src/mbgl/style/expression/is_constant.cpp
+++ b/src/mbgl/style/expression/is_constant.cpp
@@ -17,11 +17,7 @@ bool isFeatureConstant(const Expression& expression) {
return false;
} else if (name == "has" && parameterCount && *parameterCount == 1) {
return false;
- } else if (
- name == "properties" ||
- name == "geometry-type" ||
- name == "id"
- ) {
+ } else if (name == "properties" || name == "geometry-type" || name == "id" || name == "feature-state") {
return false;
} else if (0u == name.rfind(filter, 0u)) {
// Legacy filters begin with "filter-" and are never constant.
diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp
index 328cd47555..04a897022c 100644
--- a/src/mbgl/style/layer.cpp
+++ b/src/mbgl/style/layer.cpp
@@ -1,15 +1,23 @@
-#include <mbgl/style/layer.hpp>
-#include <mbgl/style/layer_impl.hpp>
-#include <mbgl/style/layer_observer.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/filter.hpp>
#include <mbgl/style/conversion_impl.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/layer_observer.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/renderer/render_layer.hpp>
namespace mbgl {
namespace style {
+static_assert(mbgl::underlying_type(Tile::Kind::Geometry) == mbgl::underlying_type(LayerTypeInfo::TileKind::Geometry),
+ "tile kind error");
+static_assert(mbgl::underlying_type(Tile::Kind::Raster) == mbgl::underlying_type(LayerTypeInfo::TileKind::Raster),
+ "tile kind error");
+static_assert(mbgl::underlying_type(Tile::Kind::RasterDEM) == mbgl::underlying_type(LayerTypeInfo::TileKind::RasterDEM),
+ "tile kind error");
+
static LayerObserver nullObserver;
Layer::Layer(Immutable<Impl> impl)
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index 1693c47204..2b33b0b3d0 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* BackgroundLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"background",
- LayerTypeInfo::Source::NotRequired,
- LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::NotRequired,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"background",
+ LayerTypeInfo::Source::NotRequired,
+ LayerTypeInfo::Pass3D::NotRequired,
+ LayerTypeInfo::Layout::NotRequired,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::NotRequired};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index 2293ed222e..baabe5c8bf 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* CircleLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"circle",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::NotRequired,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"circle",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::NotRequired,
+ LayerTypeInfo::Layout::NotRequired,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::Geometry};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp
index e77d6590f7..8b9e17ea25 100644
--- a/src/mbgl/style/layers/custom_layer.cpp
+++ b/src/mbgl/style/layers/custom_layer.cpp
@@ -8,13 +8,13 @@ namespace mbgl {
namespace style {
namespace {
- const LayerTypeInfo typeInfoCustom
- { "",
- LayerTypeInfo::Source::NotRequired,
- LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::NotRequired,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired };
+const LayerTypeInfo typeInfoCustom{"",
+ LayerTypeInfo::Source::NotRequired,
+ LayerTypeInfo::Pass3D::NotRequired,
+ LayerTypeInfo::Layout::NotRequired,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::NotRequired};
} // namespace
CustomLayer::CustomLayer(const std::string& layerID,
diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp
index 50e32cf812..b22f0a3075 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* FillExtrusionLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"fill-extrusion",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::Required,
- LayerTypeInfo::Layout::Required,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"fill-extrusion",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::Required,
+ LayerTypeInfo::Layout::Required,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::Geometry};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index e08c8f3962..2c3ee42fae 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* FillLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"fill",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::Required,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"fill",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::NotRequired,
+ LayerTypeInfo::Layout::Required,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::Geometry};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp
index cb99f76a51..a3cedd3747 100644
--- a/src/mbgl/style/layers/heatmap_layer.cpp
+++ b/src/mbgl/style/layers/heatmap_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* HeatmapLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"heatmap",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::Required,
- LayerTypeInfo::Layout::NotRequired,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"heatmap",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::Required,
+ LayerTypeInfo::Layout::NotRequired,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::Geometry};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp
index 95a395ef25..05dd009d25 100644
--- a/src/mbgl/style/layers/hillshade_layer.cpp
+++ b/src/mbgl/style/layers/hillshade_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* HillshadeLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"hillshade",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::Required,
- LayerTypeInfo::Layout::NotRequired,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"hillshade",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::Required,
+ LayerTypeInfo::Layout::NotRequired,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::RasterDEM};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index da34565461..eee2d0583e 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -27,13 +27,20 @@ let defaults = { caps: { 'Source': 'NotRequired',
'Pass3D': 'NotRequired',
'Layout': 'NotRequired',
'FadingTiles': 'NotRequired',
- 'CrossTileIndex': 'NotRequired'
+ 'CrossTileIndex': 'NotRequired',
+ 'TileKind' : 'NotRequired'
},
require: function(cap) {
- let copy = Object.assign({}, this);
- copy.caps = Object.assign({}, this.caps);
- copy.caps[cap] = 'Required';
- return copy;
+ let copy = Object.assign({}, this);
+ copy.caps = Object.assign({}, this.caps);
+ copy.caps[cap] = 'Required';
+ return copy;
+ },
+ set: function(cap, value) {
+ let copy = Object.assign({}, this);
+ copy.caps = Object.assign({}, this.caps);
+ copy.caps[cap] = value;
+ return copy;
},
finalize: function() {
return Object.keys(this.caps).reduce((acc, key) => {
@@ -46,30 +53,35 @@ let defaults = { caps: { 'Source': 'NotRequired',
layerCapabilities['background'] = defaults.finalize();
layerCapabilities['fill'] = defaults.require('Source')
.require('Layout')
+ .set('TileKind', 'Geometry')
.finalize();
layerCapabilities['fill-extrusion'] = defaults.require('Source')
.require('Pass3D')
.require('Layout')
+ .set('TileKind', 'Geometry')
.finalize();
layerCapabilities['hillshade'] = defaults.require('Source')
.require('Pass3D')
+ .set('TileKind', 'RasterDEM')
.finalize();
layerCapabilities['symbol'] = defaults.require('Source')
.require('Layout')
.require('FadingTiles')
.require('CrossTileIndex')
+ .set('TileKind', 'Geometry')
.finalize();
-layerCapabilities['circle'] = defaults.require('Source').finalize();
+layerCapabilities['circle'] = defaults.require('Source').set('TileKind', 'Geometry').finalize();
layerCapabilities['line'] = layerCapabilities['fill'];
-layerCapabilities['heatmap'] = layerCapabilities['hillshade'];
-layerCapabilities['raster'] = layerCapabilities['circle'];
+layerCapabilities['heatmap'] = defaults.require('Source')
+ .require('Pass3D')
+ .set('TileKind', 'Geometry')
+ .finalize();
+layerCapabilities['raster'] = defaults.require('Source').set('TileKind', 'Raster').finalize();
%>
// static
const LayerTypeInfo* <%- camelize(type) %>Layer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"<%- type %>",
- <%-`${layerCapabilities[type].map(cap => `LayerTypeInfo::${cap}`).join(',\n ')}` %>
- };
+ const static LayerTypeInfo typeInfo{"<%- type %>",
+ <%-`${layerCapabilities[type].map(cap => `LayerTypeInfo::${cap}`).join(',\n ')}` %>};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index deb85cad66..c148a66407 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* LineLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"line",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::Required,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"line",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::NotRequired,
+ LayerTypeInfo::Layout::Required,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::Geometry};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index ead2223ea6..b85d031938 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* RasterLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"raster",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::NotRequired,
- LayerTypeInfo::FadingTiles::NotRequired,
- LayerTypeInfo::CrossTileIndex::NotRequired
- };
+ const static LayerTypeInfo typeInfo{"raster",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::NotRequired,
+ LayerTypeInfo::Layout::NotRequired,
+ LayerTypeInfo::FadingTiles::NotRequired,
+ LayerTypeInfo::CrossTileIndex::NotRequired,
+ LayerTypeInfo::TileKind::Raster};
return &typeInfo;
}
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index 157d8c745f..35d75686af 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -19,14 +19,13 @@ namespace style {
// static
const LayerTypeInfo* SymbolLayer::Impl::staticTypeInfo() noexcept {
- const static LayerTypeInfo typeInfo
- {"symbol",
- LayerTypeInfo::Source::Required,
- LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::Required,
- LayerTypeInfo::FadingTiles::Required,
- LayerTypeInfo::CrossTileIndex::Required
- };
+ const static LayerTypeInfo typeInfo{"symbol",
+ LayerTypeInfo::Source::Required,
+ LayerTypeInfo::Pass3D::NotRequired,
+ LayerTypeInfo::Layout::Required,
+ LayerTypeInfo::FadingTiles::Required,
+ LayerTypeInfo::CrossTileIndex::Required,
+ LayerTypeInfo::TileKind::Geometry};
return &typeInfo;
}
diff --git a/src/mbgl/style/properties.hpp b/src/mbgl/style/properties.hpp
index 9d66f850de..db0e54330c 100644
--- a/src/mbgl/style/properties.hpp
+++ b/src/mbgl/style/properties.hpp
@@ -180,11 +180,23 @@ public:
});
}
+ template <class T>
+ static T evaluate(float z, const GeometryTileFeature& feature, const FeatureState& state,
+ const PossiblyEvaluatedPropertyValue<T>& v, const T& defaultValue) {
+ return v.match([&](const T& t) { return t; },
+ [&](const PropertyExpression<T>& t) { return t.evaluate(z, feature, state, defaultValue); });
+ }
+
template <class P>
auto evaluate(float z, const GeometryTileFeature& feature) const {
return evaluate(z, feature, this->template get<P>(), P::defaultValue());
}
+ template <class P>
+ auto evaluate(float z, const GeometryTileFeature& feature, const FeatureState& state) const {
+ return evaluate(z, feature, state, this->template get<P>(), P::defaultValue());
+ }
+
Evaluated evaluate(float z, const GeometryTileFeature& feature) const {
return Evaluated {
evaluate<Ps>(z, feature)...
diff --git a/src/mbgl/style/sources/custom_geometry_source.cpp b/src/mbgl/style/sources/custom_geometry_source.cpp
index 73675c056f..1076cbf417 100644
--- a/src/mbgl/style/sources/custom_geometry_source.cpp
+++ b/src/mbgl/style/sources/custom_geometry_source.cpp
@@ -1,12 +1,15 @@
-#include <mbgl/style/sources/custom_geometry_source.hpp>
-#include <mbgl/style/custom_tile_loader.hpp>
-#include <mbgl/style/sources/custom_geometry_source_impl.hpp>
-#include <mbgl/style/source_observer.hpp>
+#include <cstring>
+#include <map>
#include <mbgl/actor/actor.hpp>
#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/style/custom_tile_loader.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/style/sources/custom_geometry_source_impl.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <tuple>
-#include <map>
namespace mbgl {
namespace style {
@@ -29,6 +32,10 @@ void CustomGeometrySource::loadDescription(FileSource&) {
observer->onSourceLoaded(*this);
}
+bool CustomGeometrySource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const {
+ return mbgl::underlying_type(Tile::Kind::Geometry) == mbgl::underlying_type(info->tileKind);
+}
+
void CustomGeometrySource::setTileData(const CanonicalTileID& tileID,
const GeoJSON& data) {
loader->self().invoke(&CustomTileLoader::setTileData, tileID, data);
diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp
index 72a51e212f..baf76d8224 100644
--- a/src/mbgl/style/sources/geojson_source.cpp
+++ b/src/mbgl/style/sources/geojson_source.cpp
@@ -1,9 +1,11 @@
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/source_observer.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/geojson_source_impl.hpp>
-#include <mbgl/style/source_observer.hpp>
-#include <mbgl/style/conversion/json.hpp>
-#include <mbgl/style/conversion/geojson.hpp>
-#include <mbgl/storage/file_source.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/util/logging.hpp>
namespace mbgl {
@@ -78,5 +80,9 @@ void GeoJSONSource::loadDescription(FileSource& fileSource) {
});
}
+bool GeoJSONSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const {
+ return mbgl::underlying_type(Tile::Kind::Geometry) == mbgl::underlying_type(info->tileKind);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/sources/image_source.cpp b/src/mbgl/style/sources/image_source.cpp
index fa268da0ef..baadc86e7c 100644
--- a/src/mbgl/style/sources/image_source.cpp
+++ b/src/mbgl/style/sources/image_source.cpp
@@ -1,9 +1,11 @@
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/source_observer.hpp>
#include <mbgl/style/sources/image_source.hpp>
#include <mbgl/style/sources/image_source_impl.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/util/geo.hpp>
-#include <mbgl/style/source_observer.hpp>
#include <mbgl/util/premultiply.hpp>
-#include <mbgl/storage/file_source.hpp>
namespace mbgl {
namespace style {
@@ -80,5 +82,9 @@ void ImageSource::loadDescription(FileSource& fileSource) {
});
}
+bool ImageSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const {
+ return mbgl::underlying_type(Tile::Kind::Raster) == mbgl::underlying_type(info->tileKind);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/sources/raster_dem_source.cpp b/src/mbgl/style/sources/raster_dem_source.cpp
index bb745561b1..dd859cc6d1 100644
--- a/src/mbgl/style/sources/raster_dem_source.cpp
+++ b/src/mbgl/style/sources/raster_dem_source.cpp
@@ -1,8 +1,10 @@
-#include <mbgl/style/sources/raster_dem_source.hpp>
-#include <mbgl/style/sources/raster_source_impl.hpp>
-#include <mbgl/style/source_observer.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/sources/raster_dem_source.hpp>
+#include <mbgl/style/sources/raster_source_impl.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/util/mapbox.hpp>
namespace mbgl {
@@ -12,5 +14,9 @@ RasterDEMSource::RasterDEMSource(std::string id, variant<std::string, Tileset> u
: RasterSource(std::move(id), urlOrTileset_, tileSize, SourceType::RasterDEM){
}
+bool RasterDEMSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const {
+ return mbgl::underlying_type(Tile::Kind::RasterDEM) == mbgl::underlying_type(info->tileKind);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/sources/raster_source.cpp b/src/mbgl/style/sources/raster_source.cpp
index 115887d004..851f32573e 100644
--- a/src/mbgl/style/sources/raster_source.cpp
+++ b/src/mbgl/style/sources/raster_source.cpp
@@ -1,11 +1,13 @@
-#include <mbgl/style/sources/raster_source.hpp>
-#include <mbgl/style/sources/raster_source_impl.hpp>
-#include <mbgl/style/source_observer.hpp>
+#include <mbgl/storage/file_source.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/tileset.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/mapbox.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/raster_source_impl.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/util/exception.hpp>
+#include <mbgl/util/mapbox.hpp>
namespace mbgl {
namespace style {
@@ -80,5 +82,9 @@ void RasterSource::loadDescription(FileSource& fileSource) {
});
}
+bool RasterSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const {
+ return mbgl::underlying_type(Tile::Kind::Raster) == mbgl::underlying_type(info->tileKind);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/sources/vector_source.cpp b/src/mbgl/style/sources/vector_source.cpp
index a69ff632d8..dc1a45fdff 100644
--- a/src/mbgl/style/sources/vector_source.cpp
+++ b/src/mbgl/style/sources/vector_source.cpp
@@ -1,12 +1,14 @@
-#include <mbgl/style/sources/vector_source.hpp>
-#include <mbgl/style/sources/vector_source_impl.hpp>
-#include <mbgl/style/source_observer.hpp>
+#include <mbgl/storage/file_source.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/tileset.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/mapbox.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/source_observer.hpp>
+#include <mbgl/style/sources/vector_source.hpp>
+#include <mbgl/style/sources/vector_source_impl.hpp>
+#include <mbgl/tile/tile.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/exception.hpp>
+#include <mbgl/util/mapbox.hpp>
namespace mbgl {
namespace style {
@@ -84,5 +86,9 @@ void VectorSource::loadDescription(FileSource& fileSource) {
});
}
+bool VectorSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info) const {
+ return mbgl::underlying_type(Tile::Kind::Geometry) == mbgl::underlying_type(info->tileKind);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp
index d3298c5cac..95a39819fc 100644
--- a/src/mbgl/style/style_impl.cpp
+++ b/src/mbgl/style/style_impl.cpp
@@ -1,26 +1,27 @@
-#include <mbgl/style/style_impl.hpp>
-#include <mbgl/style/observer.hpp>
-#include <mbgl/style/source_impl.hpp>
-#include <mbgl/style/layers/symbol_layer.hpp>
-#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/sprite/sprite_loader.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
+#include <mbgl/style/layers/hillshade_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
-#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
-#include <mbgl/style/layers/hillshade_layer.hpp>
-#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/observer.hpp>
#include <mbgl/style/parser.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/transition_options.hpp>
-#include <mbgl/sprite/sprite_loader.hpp>
#include <mbgl/util/exception.hpp>
-#include <mbgl/util/string.hpp>
#include <mbgl/util/logging.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/storage/resource.hpp>
-#include <mbgl/storage/response.hpp>
+#include <mbgl/util/string.hpp>
+#include <sstream>
namespace mbgl {
namespace style {
@@ -177,6 +178,15 @@ Layer* Style::Impl::getLayer(const std::string& id) const {
Layer* Style::Impl::addLayer(std::unique_ptr<Layer> layer, optional<std::string> before) {
// TODO: verify source
+ if (Source* source = sources.get(layer->getSourceID())) {
+ if (!source->supportsLayerType(layer->baseImpl->getTypeInfo())) {
+ std::ostringstream message;
+ message << "Layer '" << layer->getID() << "' is not compatible with source '" << layer->getSourceID()
+ << "'";
+
+ throw std::runtime_error(message.str());
+ }
+ }
if (layers.get(layer->getID())) {
throw std::runtime_error(std::string{"Layer "} + layer->getID() + " already exists");
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 3087b4fc6a..9f9c41d229 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -302,14 +302,11 @@ float GeometryTile::getQueryPadding(const std::unordered_map<std::string, const
return queryPadding;
}
-void GeometryTile::queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState& transformState,
- const std::unordered_map<std::string, const RenderLayer*>& layers,
- const RenderedQueryOptions& options,
- const mat4& projMatrix) {
-
+void GeometryTile::queryRenderedFeatures(std::unordered_map<std::string, std::vector<Feature>>& result,
+ const GeometryCoordinates& queryGeometry, const TransformState& transformState,
+ const std::unordered_map<std::string, const RenderLayer*>& layers,
+ const RenderedQueryOptions& options, const mat4& projMatrix,
+ const SourceFeatureState& featureState) {
if (!getData()) return;
const float queryPadding = getQueryPadding(layers);
@@ -318,16 +315,10 @@ void GeometryTile::queryRenderedFeatures(
transformState.matrixFor(posMatrix, id.toUnwrapped());
matrix::multiply(posMatrix, projMatrix, posMatrix);
- layoutResult->featureIndex->query(result,
- queryGeometry,
- transformState,
- posMatrix,
- util::tileSize * id.overscaleFactor(),
- std::pow(2, transformState.getZoom() - id.overscaledZ),
- options,
- id.toUnwrapped(),
- layers,
- queryPadding * transformState.maxPitchScaleFactor());
+ layoutResult->featureIndex->query(result, queryGeometry, transformState, posMatrix,
+ util::tileSize * id.overscaleFactor(),
+ std::pow(2, transformState.getZoom() - id.overscaledZ), options, id.toUnwrapped(),
+ layers, queryPadding * transformState.maxPitchScaleFactor(), featureState);
}
void GeometryTile::querySourceFeatures(
@@ -387,4 +378,33 @@ void GeometryTile::performedFadePlacement() {
}
}
+void GeometryTile::setFeatureState(const LayerFeatureStates& states) {
+ auto layers = getData();
+ if ((layers == nullptr) || states.empty() || !layoutResult) {
+ return;
+ }
+
+ auto& layerIdToLayerRenderData = layoutResult->layerRenderData;
+ for (auto& layer : layerIdToLayerRenderData) {
+ const auto& layerID = layer.first;
+ const auto sourceLayer = layers->getLayer(layerID);
+ if (sourceLayer) {
+ const auto& sourceLayerID = sourceLayer->getName();
+ auto entry = states.find(sourceLayerID);
+ if (entry == states.end()) {
+ continue;
+ }
+ const auto& featureStates = entry->second;
+ if (featureStates.empty()) {
+ continue;
+ }
+
+ auto bucket = layer.second.bucket;
+ if (bucket && bucket->hasData()) {
+ bucket->update(featureStates, *sourceLayer, layerID, layoutResult->iconAtlas.patternPositions);
+ }
+ }
+ }
+}
+
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 8682c8c76b..566b359547 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -48,13 +48,11 @@ public:
bool layerPropertiesUpdated(const Immutable<style::LayerProperties>&) override;
- void queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState&,
- const std::unordered_map<std::string, const RenderLayer*>& layers,
- const RenderedQueryOptions& options,
- const mat4& projMatrix) override;
+ void queryRenderedFeatures(std::unordered_map<std::string, std::vector<Feature>>& result,
+ const GeometryCoordinates& queryGeometry, const TransformState&,
+ const std::unordered_map<std::string, const RenderLayer*>& layers,
+ const RenderedQueryOptions& options, const mat4& projMatrix,
+ const SourceFeatureState& featureState) override;
void querySourceFeatures(
std::vector<Feature>& result,
@@ -93,7 +91,9 @@ public:
const std::shared_ptr<FeatureIndex> getFeatureIndex() const;
const std::string sourceID;
-
+
+ void setFeatureState(const LayerFeatureStates&) override;
+
protected:
const GeometryTileData* getData() const;
LayerRenderData* getLayerRenderData(const style::Layer::Impl&);
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index 428a5b0d5e..f6af61eb3c 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -384,7 +384,7 @@ void GeometryTileWorker::parse() {
continue;
const GeometryCollection& geometries = feature->getGeometries();
- bucket->addFeature(*feature, geometries, {}, PatternLayerMap ());
+ bucket->addFeature(*feature, geometries, {}, PatternLayerMap(), i);
featureIndex->insert(geometries, i, sourceLayerID, leaderImpl.id);
}
diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp
index 2f342c092d..2ebbf76c2a 100644
--- a/src/mbgl/tile/tile.cpp
+++ b/src/mbgl/tile/tile.cpp
@@ -39,13 +39,9 @@ void Tile::dumpDebugLogs() const {
Log::Info(Event::General, "Tile::complete: %s", isComplete() ? "yes" : "no");
}
-void Tile::queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>&,
- const GeometryCoordinates&,
- const TransformState&,
- const std::unordered_map<std::string, const RenderLayer*>&,
- const RenderedQueryOptions&,
- const mat4&) {}
+void Tile::queryRenderedFeatures(std::unordered_map<std::string, std::vector<Feature>>&, const GeometryCoordinates&,
+ const TransformState&, const std::unordered_map<std::string, const RenderLayer*>&,
+ const RenderedQueryOptions&, const mat4&, const SourceFeatureState&) {}
float Tile::getQueryPadding(const std::unordered_map<std::string, const RenderLayer*>&) {
return 0;
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index 7a7d246aa6..b73383f989 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -28,6 +28,7 @@ class TileRenderData;
class RenderedQueryOptions;
class SourceQueryOptions;
class CollisionIndex;
+class SourceFeatureState;
namespace gfx {
class UploadPass;
@@ -67,13 +68,11 @@ public:
virtual void setLayers(const std::vector<Immutable<style::LayerProperties>>&) {}
virtual void setMask(TileMask&&) {}
- virtual void queryRenderedFeatures(
- std::unordered_map<std::string, std::vector<Feature>>& result,
- const GeometryCoordinates& queryGeometry,
- const TransformState&,
- const std::unordered_map<std::string, const RenderLayer*>&,
- const RenderedQueryOptions& options,
- const mat4& projMatrix);
+ virtual void queryRenderedFeatures(std::unordered_map<std::string, std::vector<Feature>>& result,
+ const GeometryCoordinates& queryGeometry, const TransformState&,
+ const std::unordered_map<std::string, const RenderLayer*>&,
+ const RenderedQueryOptions& options, const mat4& projMatrix,
+ const SourceFeatureState& featureState);
virtual void querySourceFeatures(
std::vector<Feature>& result,
@@ -125,7 +124,9 @@ public:
// We hold onto a tile for two placements: fading starts with the first placement
// and will have time to finish by the second placement.
virtual void performedFadePlacement() {}
-
+
+ virtual void setFeatureState(const LayerFeatureStates&) {}
+
void dumpDebugLogs() const;
const Kind kind;
diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp
index bf3f64a0c8..83aeec81ec 100644
--- a/test/api/query.test.cpp
+++ b/test/api/query.test.cpp
@@ -126,6 +126,22 @@ TEST(Query, QuerySourceFeatures) {
EXPECT_EQ(features1.size(), 1u);
}
+TEST(Query, QuerySourceFeatureStates) {
+ QueryTest test;
+
+ FeatureState newState;
+ newState["hover"] = true;
+ newState["radius"].set<uint64_t>(20);
+ test.frontend.getRenderer()->setFeatureState("source1", {}, "feature1", newState);
+
+ FeatureState states;
+ test.frontend.getRenderer()->getFeatureState(states, "source1", {}, "feature1");
+ ASSERT_EQ(states.size(), 2u);
+ ASSERT_EQ(states["hover"], true);
+ ASSERT_EQ(states["radius"].get<uint64_t>(), 20u);
+ ASSERT_EQ(newState, states);
+}
+
TEST(Query, QuerySourceFeaturesOptionValidation) {
QueryTest test;
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index a3dbdb8f99..13b30eb75d 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -52,7 +52,8 @@ TEST(Buckets, CircleBucket) {
ASSERT_FALSE(bucket.needsUpload());
GeometryCollection point { { { 0, 0 } } };
- bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Point, point, properties }, point, {}, PatternLayerMap());
+ bucket.addFeature(StubGeometryTileFeature{{}, FeatureType::Point, point, properties}, point, {}, PatternLayerMap(),
+ 0);
ASSERT_TRUE(bucket.hasData());
ASSERT_TRUE(bucket.needsUpload());
@@ -74,7 +75,8 @@ TEST(Buckets, FillBucket) {
ASSERT_FALSE(bucket.needsUpload());
GeometryCollection polygon { { { 0, 0 }, { 0, 1 }, { 1, 1 } } };
- bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Polygon, polygon, properties }, polygon, {}, PatternLayerMap());
+ bucket.addFeature(StubGeometryTileFeature{{}, FeatureType::Polygon, polygon, properties}, polygon, {},
+ PatternLayerMap(), 0);
ASSERT_TRUE(bucket.hasData());
ASSERT_TRUE(bucket.needsUpload());
@@ -96,11 +98,13 @@ TEST(Buckets, LineBucket) {
// Ignore invalid feature type.
GeometryCollection point { { { 0, 0 } } };
- bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Point, point, properties }, point, {}, PatternLayerMap());
+ bucket.addFeature(StubGeometryTileFeature{{}, FeatureType::Point, point, properties}, point, {}, PatternLayerMap(),
+ 0);
ASSERT_FALSE(bucket.hasData());
GeometryCollection line { { { 0, 0 }, { 1, 1 } } };
- bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::LineString, line, properties }, line, {}, PatternLayerMap());
+ bucket.addFeature(StubGeometryTileFeature{{}, FeatureType::LineString, line, properties}, line, {},
+ PatternLayerMap(), 1);
ASSERT_TRUE(bucket.hasData());
ASSERT_TRUE(bucket.needsUpload());
@@ -134,7 +138,8 @@ TEST(Buckets, SymbolBucket) {
// SymbolBucket::addFeature() is a no-op.
GeometryCollection point { { { 0, 0 } } };
- bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Point, std::move(point), properties }, point, {}, PatternLayerMap());
+ bucket.addFeature(StubGeometryTileFeature{{}, FeatureType::Point, std::move(point), properties}, point, {},
+ PatternLayerMap(), 0);
ASSERT_FALSE(bucket.hasData());
ASSERT_FALSE(bucket.needsUpload());
diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp
index dd986c98f5..ef9f7b7930 100644
--- a/test/style/expression/expression.test.cpp
+++ b/test/style/expression/expression.test.cpp
@@ -33,10 +33,9 @@ TEST(Expression, IsExpression) {
document.Parse<0>(R"([")" + name + R"("])");
const JSValue* expression = &document;
- // TODO: "feature-state": https://github.com/mapbox/mapbox-gl-native/issues/12613
// TODO: "interpolate-hcl": https://github.com/mapbox/mapbox-gl-native/issues/8720
// TODO: "interpolate-lab": https://github.com/mapbox/mapbox-gl-native/issues/8720
- if (name == "feature-state" || name == "interpolate-hcl" || name == "interpolate-lab") {
+ if (name == "interpolate-hcl" || name == "interpolate-lab") {
if (expression::isExpression(conversion::Convertible(expression))) {
ASSERT_TRUE(false) << "Expression name" << name << "is implemented - please update Expression.IsExpression test.";
}
diff --git a/test/style/style_layer.test.cpp b/test/style/style_layer.test.cpp
index d6a926c631..dfced634b7 100644
--- a/test/style/style_layer.test.cpp
+++ b/test/style/style_layer.test.cpp
@@ -299,6 +299,24 @@ TEST(Layer, DuplicateLayer) {
}
}
+TEST(Layer, IncompatibleLayer) {
+ util::RunLoop loop;
+
+ // Setup style
+ StubFileSource fileSource;
+ Style::Impl style{fileSource, 1.0};
+ style.loadJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
+
+ // Try to add duplicate
+ try {
+ style.addLayer(std::make_unique<RasterLayer>("raster", "unusedsource"));
+ FAIL() << "Should not have been allowed to add an incompatible layer to the source";
+ } catch (const std::runtime_error& e) {
+ // Expected
+ ASSERT_STREQ("Layer 'raster' is not compatible with source 'unusedsource'", e.what());
+ }
+}
+
namespace {
template<template<typename> class PropertyValueType, typename LayoutType>
diff --git a/vendor/mapbox-base b/vendor/mapbox-base
-Subproject 8ca46e8f8ebd212d7e55bd2b076b7ee42eaca5b
+Subproject 89997045511baf975dce1a3153d32b1fdd8bc69