summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2016-10-14 14:53:57 +0200
committerKonstantin Käfer <mail@kkaefer.com>2016-11-02 18:24:32 +0100
commitf30bdfca9c5ae139d58f93bbcbc4f167577e21f4 (patch)
tree37ffaa11d45d0580d3577fd95d877a21fd65d165
parent549929cefd7073708e64e49da93e8b49fbc0db99 (diff)
downloadqtlocation-mapboxgl-upstream/terrain-rendering.tar.gz
[core] implement terrain renderingupstream/terrain-rendering
-rw-r--r--cmake/core-files.cmake20
-rw-r--r--cmake/shaders.cmake2
-rw-r--r--include/mbgl/style/conversion/layer.hpp29
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp9
-rw-r--r--include/mbgl/style/layer.hpp4
-rw-r--r--include/mbgl/style/layers/terrain_layer.hpp68
-rw-r--r--package.json4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java150
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TerrainLayer.java248
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/TerrainLayerTest.java276
-rw-r--r--platform/android/src/style/layers/terrain_layer.cpp88
-rw-r--r--platform/android/src/style/layers/terrain_layer.hpp45
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp1
-rw-r--r--src/mbgl/geometry/dem_pyramid.cpp48
-rw-r--r--src/mbgl/geometry/dem_pyramid.hpp54
-rw-r--r--src/mbgl/renderer/painter.hpp3
-rw-r--r--src/mbgl/renderer/painter_terrain.cpp84
-rw-r--r--src/mbgl/renderer/terrain_bucket.cpp44
-rw-r--r--src/mbgl/renderer/terrain_bucket.hpp39
-rw-r--r--src/mbgl/shader/mesh.cpp18
-rw-r--r--src/mbgl/shader/mesh.hpp31
-rw-r--r--src/mbgl/shader/shaders.hpp6
-rw-r--r--src/mbgl/shader/terrain_prepare_shader.cpp15
-rw-r--r--src/mbgl/shader/terrain_prepare_shader.hpp24
-rw-r--r--src/mbgl/shader/terrain_shader.cpp16
-rw-r--r--src/mbgl/shader/terrain_shader.hpp24
-rw-r--r--src/mbgl/shader/terrain_uniforms.hpp39
-rw-r--r--src/mbgl/style/bucket_parameters.hpp50
-rw-r--r--src/mbgl/style/geometry_bucket_parameters.cpp (renamed from src/mbgl/style/bucket_parameters.cpp)4
-rw-r--r--src/mbgl/style/geometry_bucket_parameters.hpp55
-rw-r--r--src/mbgl/style/layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.cpp6
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp5
-rw-r--r--src/mbgl/style/layers/line_layer_impl.cpp5
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.cpp9
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp5
-rw-r--r--src/mbgl/style/layers/terrain_layer.cpp156
-rw-r--r--src/mbgl/style/layers/terrain_layer_impl.cpp47
-rw-r--r--src/mbgl/style/layers/terrain_layer_impl.hpp24
-rw-r--r--src/mbgl/style/layers/terrain_layer_properties.cpp31
-rw-r--r--src/mbgl/style/layers/terrain_layer_properties.hpp29
-rw-r--r--src/mbgl/style/raster_bucket_parameters.hpp24
-rw-r--r--src/mbgl/style/source_impl.cpp1
-rw-r--r--src/mbgl/style/sources/raster_source_impl.cpp2
-rw-r--r--src/mbgl/style/style.cpp2
-rw-r--r--src/mbgl/tile/geojson_tile.cpp4
-rw-r--r--src/mbgl/tile/geometry_tile.cpp2
-rw-r--r--src/mbgl/tile/geometry_tile_data.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp15
-rw-r--r--src/mbgl/tile/raster_tile.cpp43
-rw-r--r--src/mbgl/tile/raster_tile.hpp21
-rw-r--r--src/mbgl/tile/raster_tile_worker.cpp37
-rw-r--r--src/mbgl/tile/raster_tile_worker.hpp15
-rw-r--r--src/mbgl/tile/vector_tile.cpp72
55 files changed, 1986 insertions, 92 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index a89c0d7f4f..fa41a0a0f3 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -47,6 +47,8 @@ set(MBGL_CORE_FILES
src/mbgl/geometry/anchor.hpp
src/mbgl/geometry/binpack.hpp
src/mbgl/geometry/debug_font_data.hpp
+ src/mbgl/geometry/dem_pyramid.cpp
+ src/mbgl/geometry/dem_pyramid.hpp
src/mbgl/geometry/feature_index.cpp
src/mbgl/geometry/feature_index.hpp
src/mbgl/geometry/line_atlas.cpp
@@ -172,6 +174,7 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/painter_line.cpp
src/mbgl/renderer/painter_raster.cpp
src/mbgl/renderer/painter_symbol.cpp
+ src/mbgl/renderer/painter_terrain.cpp
src/mbgl/renderer/raster_bucket.cpp
src/mbgl/renderer/raster_bucket.hpp
src/mbgl/renderer/render_item.hpp
@@ -180,6 +183,8 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/render_tile.hpp
src/mbgl/renderer/symbol_bucket.cpp
src/mbgl/renderer/symbol_bucket.hpp
+ src/mbgl/renderer/terrain_bucket.cpp
+ src/mbgl/renderer/terrain_bucket.hpp
# shader
src/mbgl/shader/circle_shader.cpp
@@ -228,6 +233,11 @@ set(MBGL_CORE_FILES
src/mbgl/shader/symbol_uniforms.hpp
src/mbgl/shader/symbol_vertex.cpp
src/mbgl/shader/symbol_vertex.hpp
+ src/mbgl/shader/terrain_prepare_shader.cpp
+ src/mbgl/shader/terrain_prepare_shader.hpp
+ src/mbgl/shader/terrain_shader.cpp
+ src/mbgl/shader/terrain_shader.hpp
+ src/mbgl/shader/terrain_uniforms.hpp
src/mbgl/shader/uniforms.hpp
# sprite
@@ -264,12 +274,13 @@ set(MBGL_CORE_FILES
include/mbgl/style/source.hpp
include/mbgl/style/transition_options.hpp
include/mbgl/style/types.hpp
- src/mbgl/style/bucket_parameters.cpp
src/mbgl/style/bucket_parameters.hpp
src/mbgl/style/calculation_parameters.hpp
src/mbgl/style/cascade_parameters.hpp
src/mbgl/style/class_dictionary.cpp
src/mbgl/style/class_dictionary.hpp
+ src/mbgl/style/geometry_bucket_parameters.cpp
+ src/mbgl/style/geometry_bucket_parameters.hpp
src/mbgl/style/layer.cpp
src/mbgl/style/layer_impl.cpp
src/mbgl/style/layer_impl.hpp
@@ -285,6 +296,7 @@ set(MBGL_CORE_FILES
src/mbgl/style/property_parsing.hpp
src/mbgl/style/query_parameters.hpp
src/mbgl/style/rapidjson_conversion.hpp
+ src/mbgl/style/raster_bucket_parameters.hpp
src/mbgl/style/source.cpp
src/mbgl/style/source_impl.cpp
src/mbgl/style/source_impl.hpp
@@ -318,6 +330,7 @@ set(MBGL_CORE_FILES
include/mbgl/style/layers/line_layer.hpp
include/mbgl/style/layers/raster_layer.hpp
include/mbgl/style/layers/symbol_layer.hpp
+ include/mbgl/style/layers/terrain_layer.hpp
src/mbgl/style/layers/background_layer.cpp
src/mbgl/style/layers/background_layer_impl.cpp
src/mbgl/style/layers/background_layer_impl.hpp
@@ -351,6 +364,11 @@ set(MBGL_CORE_FILES
src/mbgl/style/layers/symbol_layer_impl.hpp
src/mbgl/style/layers/symbol_layer_properties.cpp
src/mbgl/style/layers/symbol_layer_properties.hpp
+ src/mbgl/style/layers/terrain_layer.cpp
+ src/mbgl/style/layers/terrain_layer_impl.cpp
+ src/mbgl/style/layers/terrain_layer_impl.hpp
+ src/mbgl/style/layers/terrain_layer_properties.cpp
+ src/mbgl/style/layers/terrain_layer_properties.hpp
# style/sources
include/mbgl/style/sources/geojson_source.hpp
diff --git a/cmake/shaders.cmake b/cmake/shaders.cmake
index bebf476bbf..2af098f70a 100644
--- a/cmake/shaders.cmake
+++ b/cmake/shaders.cmake
@@ -25,5 +25,7 @@ add_shader(MBGL_SHADER_FILES line)
add_shader(MBGL_SHADER_FILES line_pattern)
add_shader(MBGL_SHADER_FILES line_sdf)
add_shader(MBGL_SHADER_FILES raster)
+add_shader(MBGL_SHADER_FILES terrain_prepare)
+add_shader(MBGL_SHADER_FILES terrain)
add_shader(MBGL_SHADER_FILES symbol_icon)
add_shader(MBGL_SHADER_FILES symbol_sdf)
diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp
index 0539dcf9ad..bf100a96d1 100644
--- a/include/mbgl/style/conversion/layer.hpp
+++ b/include/mbgl/style/conversion/layer.hpp
@@ -6,6 +6,7 @@
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
@@ -95,6 +96,8 @@ public:
converted = convertVectorLayer<SymbolLayer>(*id, value);
} else if (*type == "raster") {
converted = convertRasterLayer(*id, value);
+ } else if (*type == "terrain") {
+ converted = convertTerrainLayer(*id, value);
} else if (*type == "background") {
converted = convertBackgroundLayer(*id, value);
} else {
@@ -198,6 +201,32 @@ private:
}
template <class V>
+ Result<std::unique_ptr<Layer>> convertTerrainLayer(const std::string& id, const V& value) const {
+ auto sourceValue = objectMember(value, "source");
+ if (!sourceValue) {
+ return Error { "layer must have a source" };
+ }
+
+ optional<std::string> source = toString(*sourceValue);
+ if (!source) {
+ return Error { "layer source must be a string" };
+ }
+
+ auto layer = std::make_unique<TerrainLayer>(id, *source);
+
+ auto sourceLayerValue = objectMember(value, "source-layer");
+ if (sourceLayerValue) {
+ optional<std::string> sourceLayer = toString(*sourceLayerValue);
+ if (!sourceLayer) {
+ return Error { "layer source-layer must be a string" };
+ }
+ layer->setSourceLayer(*sourceLayer);
+ }
+
+ return std::move(layer);
+ }
+
+ template <class V>
Result<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const V&) const {
return std::make_unique<BackgroundLayer>(id);
}
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp
index a3ba5e5d5a..3047eb271d 100644
--- a/include/mbgl/style/conversion/make_property_setters.hpp
+++ b/include/mbgl/style/conversion/make_property_setters.hpp
@@ -9,6 +9,7 @@
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/terrain_layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <unordered_map>
@@ -67,6 +68,7 @@ auto makeLayoutPropertySetters() {
+
return result;
}
@@ -124,6 +126,13 @@ auto makePaintPropertySetters() {
result["raster-contrast"] = makePropertySetter<V>(&RasterLayer::setRasterContrast);
result["raster-fade-duration"] = makePropertySetter<V>(&RasterLayer::setRasterFadeDuration);
+ result["terrain-shadow-color"] = makePropertySetter<V>(&TerrainLayer::setTerrainShadowColor);
+ result["terrain-highlight-color"] = makePropertySetter<V>(&TerrainLayer::setTerrainHighlightColor);
+ result["terrain-accent-color"] = makePropertySetter<V>(&TerrainLayer::setTerrainAccentColor);
+ result["terrain-illumination-direction"] = makePropertySetter<V>(&TerrainLayer::setTerrainIlluminationDirection);
+ result["terrain-illumination-alignment"] = makePropertySetter<V>(&TerrainLayer::setTerrainIlluminationAlignment);
+ result["terrain-exaggeration"] = makePropertySetter<V>(&TerrainLayer::setTerrainExaggeration);
+
result["background-color"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundColor);
result["background-pattern"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundPattern);
result["background-opacity"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundOpacity);
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp
index 925629a349..2b07038cd7 100644
--- a/include/mbgl/style/layer.hpp
+++ b/include/mbgl/style/layer.hpp
@@ -13,6 +13,7 @@ class LineLayer;
class CircleLayer;
class SymbolLayer;
class RasterLayer;
+class TerrainLayer;
class BackgroundLayer;
class CustomLayer;
@@ -40,6 +41,7 @@ protected:
Circle,
Symbol,
Raster,
+ Terrain,
Background,
Custom,
};
@@ -91,6 +93,8 @@ public:
return visitor(*as<SymbolLayer>());
case Type::Raster:
return visitor(*as<RasterLayer>());
+ case Type::Terrain:
+ return visitor(*as<TerrainLayer>());
case Type::Background:
return visitor(*as<BackgroundLayer>());
case Type::Custom:
diff --git a/include/mbgl/style/layers/terrain_layer.hpp b/include/mbgl/style/layers/terrain_layer.hpp
new file mode 100644
index 0000000000..412fe7cd56
--- /dev/null
+++ b/include/mbgl/style/layers/terrain_layer.hpp
@@ -0,0 +1,68 @@
+// This file is generated. Do not edit.
+
+#pragma once
+
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/filter.hpp>
+#include <mbgl/style/property_value.hpp>
+
+#include <mbgl/util/color.hpp>
+
+namespace mbgl {
+namespace style {
+
+class TerrainLayer : public Layer {
+public:
+ TerrainLayer(const std::string& layerID, const std::string& sourceID);
+ ~TerrainLayer() final;
+
+ // Source
+ const std::string& getSourceID() const;
+ const std::string& getSourceLayer() const;
+ void setSourceLayer(const std::string& sourceLayer);
+
+ void setFilter(const Filter&);
+ const Filter& getFilter() const;
+
+ // Paint properties
+
+ static PropertyValue<Color> getDefaultTerrainShadowColor();
+ PropertyValue<Color> getTerrainShadowColor(const optional<std::string>& klass = {}) const;
+ void setTerrainShadowColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+
+ static PropertyValue<Color> getDefaultTerrainHighlightColor();
+ PropertyValue<Color> getTerrainHighlightColor(const optional<std::string>& klass = {}) const;
+ void setTerrainHighlightColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+
+ static PropertyValue<Color> getDefaultTerrainAccentColor();
+ PropertyValue<Color> getTerrainAccentColor(const optional<std::string>& klass = {}) const;
+ void setTerrainAccentColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+
+ static PropertyValue<float> getDefaultTerrainIlluminationDirection();
+ PropertyValue<float> getTerrainIlluminationDirection(const optional<std::string>& klass = {}) const;
+ void setTerrainIlluminationDirection(PropertyValue<float>, const optional<std::string>& klass = {});
+
+ static PropertyValue<AlignmentType> getDefaultTerrainIlluminationAlignment();
+ PropertyValue<AlignmentType> getTerrainIlluminationAlignment(const optional<std::string>& klass = {}) const;
+ void setTerrainIlluminationAlignment(PropertyValue<AlignmentType>, const optional<std::string>& klass = {});
+
+ static PropertyValue<float> getDefaultTerrainExaggeration();
+ PropertyValue<float> getTerrainExaggeration(const optional<std::string>& klass = {}) const;
+ void setTerrainExaggeration(PropertyValue<float>, const optional<std::string>& klass = {});
+
+ // Private implementation
+
+ class Impl;
+ Impl* const impl;
+
+ TerrainLayer(const Impl&);
+ TerrainLayer(const TerrainLayer&) = delete;
+};
+
+template <>
+inline bool Layer::is<TerrainLayer>() const {
+ return type == Type::Terrain;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/package.json b/package.json
index de2f6ff39e..284712fb80 100644
--- a/package.json
+++ b/package.json
@@ -21,8 +21,8 @@
"ejs": "^2.4.1",
"express": "^4.11.1",
"lodash": "^4.16.4",
- "mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#98a56d538b11fb331aa67a6d632d6ecd6821b007",
- "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#7f62a4fc9f21e619824d68abbc4b03cbc1685572",
+ "mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#3ddf201e69291b844722002279832d903222b380",
+ "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#51fbd9ddb7f329c07d1f189500ab5604ad67adc1",
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#844ecd23c3314eec509dbcdaf0f956d5504e6fef",
"mkdirp": "^0.5.1",
"node-cmake": "^1.2.1",
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
index 383d4217a8..81d90ed3ec 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
@@ -445,6 +445,27 @@ public abstract class Property<T> {
@Retention(RetentionPolicy.SOURCE)
public @interface CIRCLE_PITCH_SCALE {}
+ //TERRAIN_ILLUMINATION_ALIGNMENT: Direction of light source when map is rotated.
+
+ /**
+ * The terrain illumination is relative to the north-west direction.
+ */
+ public static final String TERRAIN_ILLUMINATION_ALIGNMENT_MAP = "map";
+ /**
+ * The terrain illumination is relative to the top left of the viewport.
+ */
+ public static final String TERRAIN_ILLUMINATION_ALIGNMENT_VIEWPORT = "viewport";
+
+ /**
+ * Direction of light source when map is rotated.
+ */
+ @StringDef({
+ TERRAIN_ILLUMINATION_ALIGNMENT_MAP,
+ TERRAIN_ILLUMINATION_ALIGNMENT_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TERRAIN_ILLUMINATION_ALIGNMENT {}
+
//Class definition
public final String name;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
index 0cb8fdeff9..a3fbf2b93b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
@@ -1012,6 +1012,156 @@ public class PropertyFactory {
}
/**
+ * The color of the terrain that faces away from the light source.
+ *
+ * @param value a int color value
+ * @return property wrapper around String color
+ */
+ public static Property<String> terrainShadowColor(@ColorInt int value) {
+ return new PaintProperty<>("terrain-shadow-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color of the terrain that faces away from the light source.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static Property<String> terrainShadowColor(String value) {
+ return new PaintProperty<>("terrain-shadow-color", value);
+ }
+
+ /**
+ * The color of the terrain that faces away from the light source.
+ *
+ * @param function a wrapper function for String
+ * @return property wrapper around a String function
+ */
+ public static Property<Function<String>> terrainShadowColor(Function<String> function) {
+ return new PaintProperty<>("terrain-shadow-color", function);
+ }
+
+ /**
+ * The color of the terrain that faces towards the light source.
+ *
+ * @param value a int color value
+ * @return property wrapper around String color
+ */
+ public static Property<String> terrainHighlightColor(@ColorInt int value) {
+ return new PaintProperty<>("terrain-highlight-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color of the terrain that faces towards the light source.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static Property<String> terrainHighlightColor(String value) {
+ return new PaintProperty<>("terrain-highlight-color", value);
+ }
+
+ /**
+ * The color of the terrain that faces towards the light source.
+ *
+ * @param function a wrapper function for String
+ * @return property wrapper around a String function
+ */
+ public static Property<Function<String>> terrainHighlightColor(Function<String> function) {
+ return new PaintProperty<>("terrain-highlight-color", function);
+ }
+
+ /**
+ * The color used to accentuate rugged terrain with sharp cliffs and gorges.
+ *
+ * @param value a int color value
+ * @return property wrapper around String color
+ */
+ public static Property<String> terrainAccentColor(@ColorInt int value) {
+ return new PaintProperty<>("terrain-accent-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color used to accentuate rugged terrain with sharp cliffs and gorges.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static Property<String> terrainAccentColor(String value) {
+ return new PaintProperty<>("terrain-accent-color", value);
+ }
+
+ /**
+ * The color used to accentuate rugged terrain with sharp cliffs and gorges.
+ *
+ * @param function a wrapper function for String
+ * @return property wrapper around a String function
+ */
+ public static Property<Function<String>> terrainAccentColor(Function<String> function) {
+ return new PaintProperty<>("terrain-accent-color", function);
+ }
+
+ /**
+ * Direction of the lightsource. Defaults to top left.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static Property<Float> terrainIlluminationDirection(Float value) {
+ return new PaintProperty<>("terrain-illumination-direction", value);
+ }
+
+ /**
+ * Direction of the lightsource. Defaults to top left.
+ *
+ * @param function a wrapper function for Float
+ * @return property wrapper around a Float function
+ */
+ public static Property<Function<Float>> terrainIlluminationDirection(Function<Float> function) {
+ return new PaintProperty<>("terrain-illumination-direction", function);
+ }
+
+ /**
+ * Direction of light source when map is rotated.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static Property<String> terrainIlluminationAlignment(@Property.TERRAIN_ILLUMINATION_ALIGNMENT String value) {
+ return new PaintProperty<>("terrain-illumination-alignment", value);
+ }
+
+ /**
+ * Direction of light source when map is rotated.
+ *
+ * @param function a wrapper function for String
+ * @return property wrapper around a String function
+ */
+ public static Property<Function<String>> terrainIlluminationAlignment(Function<String> function) {
+ return new PaintProperty<>("terrain-illumination-alignment", function);
+ }
+
+ /**
+ * Intensity of the terrain
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static Property<Float> terrainExaggeration(Float value) {
+ return new PaintProperty<>("terrain-exaggeration", value);
+ }
+
+ /**
+ * Intensity of the terrain
+ *
+ * @param function a wrapper function for Float
+ * @return property wrapper around a Float function
+ */
+ public static Property<Function<Float>> terrainExaggeration(Function<Float> function) {
+ return new PaintProperty<>("terrain-exaggeration", function);
+ }
+
+ /**
* The color with which the background will be drawn.
*
* @param value a int color value
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TerrainLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TerrainLayer.java
new file mode 100644
index 0000000000..c4da42142f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TerrainLayer.java
@@ -0,0 +1,248 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.style.layers;
+
+import com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * Terrain visualization based on DEM data.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layers-terrain">The online documentation</a>
+ */
+public class TerrainLayer extends Layer {
+
+ /**
+ * Creates a TerrainLayer.
+ *
+ * @param nativePtr pointer used by core
+ */
+ public TerrainLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ /**
+ * Creates a TerrainLayer.
+ *
+ * @param layerId the id of the layer
+ * @param sourceId the id of the source
+ */
+ public TerrainLayer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ /**
+ * Set the source layer.
+ *
+ * @param sourceLayer the source layer to set
+ */
+ public void setSourceLayer(String sourceLayer) {
+ checkValidity();
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ /**
+ * Set the source Layer.
+ *
+ * @param sourceLayer the source layer to set
+ * @return This
+ */
+ public TerrainLayer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+ /**
+ * Set a single filter.
+ *
+ * @param filter the filter to set
+ */
+ public void setFilter(Filter.Statement filter) {
+ checkValidity();
+ this.setFilter(filter.toArray());
+ }
+
+ /**
+ * Set an array of filters.
+ *
+ * @param filter the filter array to set
+ */
+ public void setFilter(Object[] filter) {
+ checkValidity();
+ nativeSetFilter(filter);
+ }
+
+ /**
+ * Set an array of filters.
+ *
+ * @param filter tthe filter array to set
+ * @return This
+ */
+ public TerrainLayer withFilter(Object[] filter) {
+ setFilter(filter);
+ return this;
+ }
+
+ /**
+ * Set a single filter.
+ *
+ * @param filter the filter to set
+ * @return This
+ */
+ public TerrainLayer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
+
+
+ /**
+ * Set a property or properties.
+ *
+ * @param properties the var-args properties
+ * @return This
+ */
+ public TerrainLayer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ /**
+ * Get the TerrainShadowColor property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTerrainShadowColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTerrainShadowColor());
+ }
+ /**
+ * The color of the terrain that faces away from the light source.
+ *
+ * @return int representation of a rgba string color
+ * @throws RuntimeException thrown if property isn't a value
+ */
+ @ColorInt
+ public int getTerrainShadowColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getTerrainShadowColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("terrain-shadow-color was set as a Function");
+ }
+ }
+
+
+ /**
+ * Get the TerrainHighlightColor property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTerrainHighlightColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTerrainHighlightColor());
+ }
+ /**
+ * The color of the terrain that faces towards the light source.
+ *
+ * @return int representation of a rgba string color
+ * @throws RuntimeException thrown if property isn't a value
+ */
+ @ColorInt
+ public int getTerrainHighlightColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getTerrainHighlightColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("terrain-highlight-color was set as a Function");
+ }
+ }
+
+
+ /**
+ * Get the TerrainAccentColor property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTerrainAccentColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTerrainAccentColor());
+ }
+ /**
+ * The color used to accentuate rugged terrain with sharp cliffs and gorges.
+ *
+ * @return int representation of a rgba string color
+ * @throws RuntimeException thrown if property isn't a value
+ */
+ @ColorInt
+ public int getTerrainAccentColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getTerrainAccentColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("terrain-accent-color was set as a Function");
+ }
+ }
+
+
+ /**
+ * Get the TerrainIlluminationDirection property
+ *
+ * @return property wrapper value around Float
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTerrainIlluminationDirection() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTerrainIlluminationDirection());
+ }
+
+ /**
+ * Get the TerrainIlluminationAlignment property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTerrainIlluminationAlignment() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTerrainIlluminationAlignment());
+ }
+
+ /**
+ * Get the TerrainExaggeration property
+ *
+ * @return property wrapper value around Float
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTerrainExaggeration() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTerrainExaggeration());
+ }
+
+ private native Object nativeGetTerrainShadowColor();
+
+ private native Object nativeGetTerrainHighlightColor();
+
+ private native Object nativeGetTerrainAccentColor();
+
+ private native Object nativeGetTerrainIlluminationDirection();
+
+ private native Object nativeGetTerrainIlluminationAlignment();
+
+ private native Object nativeGetTerrainExaggeration();
+
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/TerrainLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/TerrainLayerTest.java
new file mode 100644
index 0000000000..9ac085f252
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/TerrainLayerTest.java
@@ -0,0 +1,276 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.TerrainLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+
+/**
+ * Basic smoke tests for TerrainLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class TerrainLayerTest extends BaseStyleTest {
+ private static final String TAG = TerrainLayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private TerrainLayer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testTerrainShadowColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-shadow-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainShadowColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getTerrainShadowColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testTerrainShadowColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-shadow-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainShadowColor(Color.RED));
+ assertEquals(layer.getTerrainShadowColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testTerrainHighlightColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-highlight-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainHighlightColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getTerrainHighlightColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testTerrainHighlightColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-highlight-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainHighlightColor(Color.RED));
+ assertEquals(layer.getTerrainHighlightColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testTerrainAccentColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-accent-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainAccentColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getTerrainAccentColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testTerrainAccentColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-accent-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainAccentColor(Color.RED));
+ assertEquals(layer.getTerrainAccentColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testTerrainIlluminationDirection() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-illumination-direction");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainIlluminationDirection(0.3f));
+ assertEquals((Float) layer.getTerrainIlluminationDirection().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTerrainIlluminationAlignment() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-illumination-alignment");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainIlluminationAlignment(TERRAIN_ILLUMINATION_ALIGNMENT_MAP));
+ assertEquals((String) layer.getTerrainIlluminationAlignment().getValue(), (String) TERRAIN_ILLUMINATION_ALIGNMENT_MAP);
+ }
+
+ @Test
+ public void testTerrainExaggeration() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new TerrainLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "terrain-exaggeration");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(terrainExaggeration(0.3f));
+ assertEquals((Float) layer.getTerrainExaggeration().getValue(), (Float) 0.3f);
+ }
+
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/src/style/layers/terrain_layer.cpp b/platform/android/src/style/layers/terrain_layer.cpp
new file mode 100644
index 0000000000..81b2ee258b
--- /dev/null
+++ b/platform/android/src/style/layers/terrain_layer.cpp
@@ -0,0 +1,88 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "terrain_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+
+namespace mbgl {
+namespace android {
+
+ TerrainLayer::TerrainLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
+ : Layer(env, std::make_unique<mbgl::style::TerrainLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
+ }
+
+ TerrainLayer::TerrainLayer(mbgl::Map& map, mbgl::style::TerrainLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ TerrainLayer::~TerrainLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> TerrainLayer::getTerrainShadowColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::TerrainLayer>()->TerrainLayer::getTerrainShadowColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> TerrainLayer::getTerrainHighlightColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::TerrainLayer>()->TerrainLayer::getTerrainHighlightColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> TerrainLayer::getTerrainAccentColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::TerrainLayer>()->TerrainLayer::getTerrainAccentColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> TerrainLayer::getTerrainIlluminationDirection(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::TerrainLayer>()->TerrainLayer::getTerrainIlluminationDirection());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> TerrainLayer::getTerrainIlluminationAlignment(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::TerrainLayer>()->TerrainLayer::getTerrainIlluminationAlignment());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> TerrainLayer::getTerrainExaggeration(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::TerrainLayer>()->TerrainLayer::getTerrainExaggeration());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Class<TerrainLayer> TerrainLayer::javaClass;
+
+ jni::jobject* TerrainLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = TerrainLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return TerrainLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void TerrainLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ TerrainLayer::javaClass = *jni::Class<TerrainLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<TerrainLayer>(
+ env, TerrainLayer::javaClass, "nativePtr",
+ std::make_unique<TerrainLayer, JNIEnv&, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&TerrainLayer::getTerrainShadowColor, "nativeGetTerrainShadowColor"),
+ METHOD(&TerrainLayer::getTerrainHighlightColor, "nativeGetTerrainHighlightColor"),
+ METHOD(&TerrainLayer::getTerrainAccentColor, "nativeGetTerrainAccentColor"),
+ METHOD(&TerrainLayer::getTerrainIlluminationDirection, "nativeGetTerrainIlluminationDirection"),
+ METHOD(&TerrainLayer::getTerrainIlluminationAlignment, "nativeGetTerrainIlluminationAlignment"),
+ METHOD(&TerrainLayer::getTerrainExaggeration, "nativeGetTerrainExaggeration"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/terrain_layer.hpp b/platform/android/src/style/layers/terrain_layer.hpp
new file mode 100644
index 0000000000..3c75a17274
--- /dev/null
+++ b/platform/android/src/style/layers/terrain_layer.hpp
@@ -0,0 +1,45 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#pragma once
+
+#include "layer.hpp"
+#include <mbgl/style/layers/terrain_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class TerrainLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/TerrainLayer"; };
+
+ static jni::Class<TerrainLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ TerrainLayer(jni::JNIEnv&, jni::String, jni::String);
+
+ TerrainLayer(mbgl::Map&, mbgl::style::TerrainLayer&);
+
+ ~TerrainLayer();
+
+ // Property getters
+ jni::Object<jni::ObjectTag> getTerrainShadowColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTerrainHighlightColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTerrainAccentColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTerrainIlluminationDirection(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTerrainIlluminationAlignment(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTerrainExaggeration(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class TerrainLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
index d43ec82d38..48c446dae4 100644
--- a/src/mbgl/annotation/annotation_tile.hpp
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -33,6 +33,7 @@ public:
optional<Value> getValue(const std::string&) const override;
optional<FeatureIdentifier> getID() const override { return { id }; }
GeometryCollection getGeometries() const override { return geometries; }
+ DEMPyramid getDEMPyramid() const override { return {}; }
const AnnotationID id;
const FeatureType type;
diff --git a/src/mbgl/geometry/dem_pyramid.cpp b/src/mbgl/geometry/dem_pyramid.cpp
new file mode 100644
index 0000000000..fb3a9d108e
--- /dev/null
+++ b/src/mbgl/geometry/dem_pyramid.cpp
@@ -0,0 +1,48 @@
+#include <mbgl/geometry/dem_pyramid.hpp>
+
+namespace mbgl {
+
+void DEMPyramid::buildLevels() {
+ while (true) {
+ auto& prev = levels.back();
+ const int32_t width = std::ceil(prev.width / 2);
+ const int32_t height = std::ceil(prev.height / 2);
+ const int32_t border = std::max<int32_t>(std::ceil(prev.border / 2), 1);
+
+ if (width == 1 || height == 1) {
+ break;
+ }
+ Level next(width, height, border);
+ prev.resample(next);
+ levels.emplace_back(std::move(next));
+ }
+
+ // Build remaining two levels. They aren't actually used in rendering, but we
+ // need them for OpenGL's mipmapping feature.
+ levels.emplace_back(2, 2, 0);
+ levels.emplace_back(1, 1, 0);
+}
+
+DEMPyramid::Level::Level(int32_t width_, int32_t height_, size_t border_)
+ : width(width_),
+ height(height_),
+ border(border_),
+ stride(width + 2 * border),
+ image({ static_cast<uint32_t>(width + 2 * border),
+ static_cast<uint32_t>(height + 2 * border) }) {
+ assert(width > 0);
+ assert(height > 0);
+ std::memset(image.data.get(), 0, image.bytes());
+}
+
+void DEMPyramid::Level::resample(Level& target) {
+ for (int32_t y = 0; y < target.height; y++) {
+ const int32_t fy = y * 2;
+ for (int32_t x = 0; x < target.width; x++) {
+ const int32_t fx = x * 2;
+ target.set(x, y, (get(fx, fy) + get(fx + 1, fy) + get(fx, fy + 1) + get(fx + 1, fy + 1)) / 4);
+ }
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/geometry/dem_pyramid.hpp b/src/mbgl/geometry/dem_pyramid.hpp
new file mode 100644
index 0000000000..d115f191c0
--- /dev/null
+++ b/src/mbgl/geometry/dem_pyramid.hpp
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <mbgl/math/clamp.hpp>
+#include <mbgl/util/image.hpp>
+
+#include <memory>
+#include <array>
+#include <cassert>
+#include <vector>
+
+namespace mbgl {
+
+class DEMPyramid {
+public:
+ class Level {
+ public:
+ Level(int32_t width, int32_t height, size_t border);
+
+ void set(const int32_t x, const int32_t y, const int32_t value) {
+ reinterpret_cast<int32_t*>(image.data.get())[idx(x, y)] = value + 65536;
+ }
+
+ int32_t get(const int32_t x, const int32_t y) const {
+ return reinterpret_cast<const int32_t*>(image.data.get())[idx(x, y)] - 65536;
+ }
+
+ void resample(Level& target);
+
+ private:
+ size_t idx(const int32_t x, const int32_t y) const {
+ assert(x >= -border);
+ assert(x < width + border);
+ assert(y >= -border);
+ assert(y < height + border);
+ return (y + border) * stride + (x + border);
+ }
+
+ public:
+ const int32_t width;
+ const int32_t height;
+ const int32_t border;
+ const int32_t stride;
+ PremultipliedImage image;
+ };
+
+
+ void buildLevels();
+
+ std::vector<Level> levels;
+
+
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index ea60f79801..d6065f0674 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -39,6 +39,7 @@ class LineBucket;
class CircleBucket;
class SymbolBucket;
class RasterBucket;
+class TerrainBucket;
class Shaders;
class SymbolSDFShader;
@@ -54,6 +55,7 @@ class LineLayer;
class CircleLayer;
class SymbolLayer;
class RasterLayer;
+class TerrainLayer;
class BackgroundLayer;
} // namespace style
@@ -84,6 +86,7 @@ public:
void renderCircle(PaintParameters&, CircleBucket&, const style::CircleLayer&, const RenderTile&);
void renderSymbol(PaintParameters&, SymbolBucket&, const style::SymbolLayer&, const RenderTile&);
void renderRaster(PaintParameters&, RasterBucket&, const style::RasterLayer&, const RenderTile&);
+ void renderTerrain(PaintParameters&, TerrainBucket&, const style::TerrainLayer&, const RenderTile&);
void renderBackground(PaintParameters&, const style::BackgroundLayer&);
#ifndef NDEBUG
diff --git a/src/mbgl/renderer/painter_terrain.cpp b/src/mbgl/renderer/painter_terrain.cpp
new file mode 100644
index 0000000000..c59182c2ee
--- /dev/null
+++ b/src/mbgl/renderer/painter_terrain.cpp
@@ -0,0 +1,84 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/renderer/terrain_bucket.hpp>
+#include <mbgl/style/layers/terrain_layer.hpp>
+#include <mbgl/style/layers/terrain_layer_impl.hpp>
+#include <mbgl/shader/shaders.hpp>
+#include <mbgl/util/offscreen_texture.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderTerrain(PaintParameters& parameters,
+ TerrainBucket& bucket,
+ const TerrainLayer& layer,
+ const RenderTile& tile) {
+ if (pass != RenderPass::Translucent) return;
+
+ if (!bucket.prepared) {
+ OffscreenTexture view(context, { 256, 256 });
+ view.bind();
+
+ context.bindTexture(*bucket.dem, 0, gl::TextureFilter::Linear, gl::TextureMipMap::Yes);
+
+ mat4 mat;
+ matrix::ortho(mat, 0, util::EXTENT, -util::EXTENT, 0, 0, 1);
+ matrix::translate(mat, mat, 0, -util::EXTENT, 0);
+
+ context.clear(Color::red(), {}, {});
+ context.draw({
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ gl::ColorMode::unblended(),
+ parameters.shaders.terrainPrepare,
+ TerrainPrepareUniforms::Values {
+ mat,
+ 0,
+ { {{ 512, 512 }} },
+ tile.id.canonical.z
+ },
+ gl::Unindexed<gl::TriangleStrip>(rasterVertexBuffer)
+ });
+
+ bucket.texture = std::move(view.getTexture());
+ bucket.prepared = true;
+
+ parameters.view.bind();
+ }
+
+ const TerrainPaintProperties& properties = layer.impl->paint;
+
+ double azimuth = (-properties.terrainIlluminationDirection - 90) * util::DEG2RAD;
+ if (properties.terrainIlluminationAlignment == style::AlignmentType::Viewport) {
+ azimuth -= state.getAngle();
+ }
+
+ context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
+
+ context.draw({
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ parameters.shaders.terrain,
+ TerrainUniforms::Values {
+ tile.matrix,
+ 0, // image
+ 8, // mode
+ { {{ 256, 256 }} },
+ tile.id.canonical.z,
+ azimuth,
+ 60 * util::DEG2RAD, // zenith
+ 0, // mipmap
+ properties.terrainExaggeration.value,
+ properties.terrainShadowColor.value,
+ properties.terrainHighlightColor.value,
+ properties.terrainAccentColor.value
+ },
+ gl::Unindexed<gl::TriangleStrip>(rasterVertexBuffer)
+ });
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/terrain_bucket.cpp b/src/mbgl/renderer/terrain_bucket.cpp
new file mode 100644
index 0000000000..5dc3ddf364
--- /dev/null
+++ b/src/mbgl/renderer/terrain_bucket.cpp
@@ -0,0 +1,44 @@
+#include <mbgl/renderer/terrain_bucket.hpp>
+#include <mbgl/style/layers/terrain_layer.hpp>
+#include <mbgl/shader/terrain_shader.hpp>
+#include <mbgl/shader/terrain_prepare_shader.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/context.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+TerrainBucket::TerrainBucket(PremultipliedImage&&) {
+ // TODO
+}
+
+TerrainBucket::TerrainBucket(DEMPyramid&& pyramid_) : pyramid(std::move(pyramid_)) {
+}
+
+void TerrainBucket::upload(gl::Context& context) {
+ if (!pyramid.levels.empty()) {
+ dem = context.createTexture(pyramid.levels.front().image);
+ for (size_t l = 1; l < pyramid.levels.size(); l++) {
+ auto& image = pyramid.levels[l].image;
+ MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, l, GL_RGBA, image.size.width, image.size.height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image.data.get()));
+ }
+ }
+
+ uploaded = true;
+}
+
+void TerrainBucket::render(Painter& painter,
+ PaintParameters& parameters,
+ const Layer& layer,
+ const RenderTile& tile) {
+ painter.renderTerrain(parameters, *this, *layer.as<TerrainLayer>(), tile);
+}
+
+bool TerrainBucket::hasData() const {
+ return true;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/terrain_bucket.hpp b/src/mbgl/renderer/terrain_bucket.hpp
new file mode 100644
index 0000000000..3a96372ff7
--- /dev/null
+++ b/src/mbgl/renderer/terrain_bucket.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/gl/texture.hpp>
+#include <mbgl/geometry/dem_pyramid.hpp>
+
+namespace mbgl {
+
+class TerrainPrepareShader;
+class TerrainShader;
+class RasterShader;
+class RasterVertex;
+
+namespace gl {
+class Context;
+template <class> class VertexBuffer;
+class VertexArrayObject;
+} // namespace gl
+
+class TerrainBucket : public Bucket {
+public:
+ TerrainBucket(PremultipliedImage&&);
+ TerrainBucket(DEMPyramid&&);
+
+ void upload(gl::Context&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
+ bool hasData() const override;
+
+ optional<gl::Texture> dem;
+ optional<gl::Texture> texture;
+ bool prepared = false;
+
+private:
+ DEMPyramid pyramid;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/mesh.cpp b/src/mbgl/shader/mesh.cpp
new file mode 100644
index 0000000000..6d1578a35c
--- /dev/null
+++ b/src/mbgl/shader/mesh.cpp
@@ -0,0 +1,18 @@
+#include <mbgl/gl/mesh.hpp>
+
+namespace mbgl {
+namespace gl {
+
+Mesh::Mesh(Size size) {
+
+
+}
+
+void Mesh::upload(gl::Context&) {
+
+
+
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/shader/mesh.hpp b/src/mbgl/shader/mesh.hpp
new file mode 100644
index 0000000000..3df0c74632
--- /dev/null
+++ b/src/mbgl/shader/mesh.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/size.hpp>
+#include <mbgl/gl/vertex_buffer.hpp>
+#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/gl/segment.hpp>
+#include <mbgl/shader/fill_vertex.hpp>
+
+namespace mbgl {
+namespace gl {
+
+namespace gl {
+class Context;
+} // namespace gl
+
+class Mesh {
+public:
+ Mesh(Size size);
+
+ void upload(gl::Context&);
+
+ std::vector<FillVertex> vertices;
+ std::vector<gl::Triangle> triangles;
+ std::vector<gl::Segment> triangleSegments { { 0, 0 } };
+
+ optional<gl::VertexBuffer<FillVertex>> vertexBuffer;
+ optional<gl::IndexBuffer<gl::Triangle>> triangleIndexBuffer;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/shader/shaders.hpp b/src/mbgl/shader/shaders.hpp
index 56b063ce29..6d5a37ae88 100644
--- a/src/mbgl/shader/shaders.hpp
+++ b/src/mbgl/shader/shaders.hpp
@@ -9,6 +9,8 @@
#include <mbgl/shader/line_sdf_shader.hpp>
#include <mbgl/shader/line_pattern_shader.hpp>
#include <mbgl/shader/raster_shader.hpp>
+#include <mbgl/shader/terrain_prepare_shader.hpp>
+#include <mbgl/shader/terrain_shader.hpp>
#include <mbgl/shader/symbol_icon_shader.hpp>
#include <mbgl/shader/symbol_sdf_shader.hpp>
@@ -28,6 +30,8 @@ public:
lineSDF(context, defines),
linePattern(context, defines),
raster(context, defines),
+ terrainPrepare(context, defines),
+ terrain(context, defines),
symbolIcon(context, defines),
symbolIconSDF(context, defines),
symbolGlyph(context, defines),
@@ -43,6 +47,8 @@ public:
LineSDFShader lineSDF;
LinePatternShader linePattern;
RasterShader raster;
+ TerrainPrepareShader terrainPrepare;
+ TerrainShader terrain;
SymbolIconShader symbolIcon;
SymbolSDFShader symbolIconSDF;
SymbolSDFShader symbolGlyph;
diff --git a/src/mbgl/shader/terrain_prepare_shader.cpp b/src/mbgl/shader/terrain_prepare_shader.cpp
new file mode 100644
index 0000000000..6bfa1f55f7
--- /dev/null
+++ b/src/mbgl/shader/terrain_prepare_shader.cpp
@@ -0,0 +1,15 @@
+#include <mbgl/shader/terrain_prepare_shader.hpp>
+#include <mbgl/shader/terrain_prepare.vertex.hpp>
+#include <mbgl/shader/terrain_prepare.fragment.hpp>
+
+namespace mbgl {
+
+TerrainPrepareShader::TerrainPrepareShader(gl::Context& context, Defines defines)
+ : Shader(shaders::terrain_prepare::name,
+ shaders::terrain_prepare::vertex,
+ shaders::terrain_prepare::fragment,
+ context, defines),
+ uniformsState(TerrainPrepareUniforms::state(*this)) {
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/terrain_prepare_shader.hpp b/src/mbgl/shader/terrain_prepare_shader.hpp
new file mode 100644
index 0000000000..dfb5707d6c
--- /dev/null
+++ b/src/mbgl/shader/terrain_prepare_shader.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mbgl/gl/shader.hpp>
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/shader/terrain_uniforms.hpp>
+
+namespace mbgl {
+
+class RasterVertex;
+
+class TerrainPrepareShader : public gl::Shader {
+public:
+ TerrainPrepareShader(gl::Context&, Defines defines = None);
+
+ using VertexType = RasterVertex;
+ using UniformsType = TerrainPrepareUniforms;
+
+ gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
+ gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this };
+
+ typename TerrainPrepareUniforms::State uniformsState;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/terrain_shader.cpp b/src/mbgl/shader/terrain_shader.cpp
new file mode 100644
index 0000000000..e8eedb9515
--- /dev/null
+++ b/src/mbgl/shader/terrain_shader.cpp
@@ -0,0 +1,16 @@
+#include <mbgl/shader/terrain_shader.hpp>
+#include <mbgl/shader/terrain.vertex.hpp>
+#include <mbgl/shader/terrain.fragment.hpp>
+#include <mbgl/shader/raster_vertex.hpp>
+
+namespace mbgl {
+
+TerrainShader::TerrainShader(gl::Context& context, Defines defines)
+ : Shader(shaders::terrain::name,
+ shaders::terrain::vertex,
+ shaders::terrain::fragment,
+ context, defines),
+ uniformsState(TerrainUniforms::state(*this)) {
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/terrain_shader.hpp b/src/mbgl/shader/terrain_shader.hpp
new file mode 100644
index 0000000000..32bdcd16d3
--- /dev/null
+++ b/src/mbgl/shader/terrain_shader.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mbgl/gl/shader.hpp>
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/shader/terrain_uniforms.hpp>
+
+namespace mbgl {
+
+class RasterVertex;
+
+class TerrainShader : public gl::Shader {
+public:
+ TerrainShader(gl::Context&, Defines defines = None);
+
+ using VertexType = RasterVertex;
+ using UniformsType = TerrainUniforms;
+
+ gl::Attribute<int16_t, 2> a_pos = { "a_pos", *this };
+ gl::Attribute<uint16_t, 2> a_texture_pos = { "a_texture_pos", *this };
+
+ typename TerrainUniforms::State uniformsState;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/shader/terrain_uniforms.hpp b/src/mbgl/shader/terrain_uniforms.hpp
new file mode 100644
index 0000000000..831d419c37
--- /dev/null
+++ b/src/mbgl/shader/terrain_uniforms.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <mbgl/shader/uniforms.hpp>
+
+namespace mbgl {
+
+namespace uniforms {
+MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_dimension);
+MBGL_DEFINE_UNIFORM_SCALAR(int32_t, u_mode);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_azimuth);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_zenith);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_mipmap);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_exaggeration);
+MBGL_DEFINE_UNIFORM_SCALAR(Color, u_shadow);
+MBGL_DEFINE_UNIFORM_SCALAR(Color, u_highlight);
+MBGL_DEFINE_UNIFORM_SCALAR(Color, u_accent);
+} // namespace uniforms
+
+struct TerrainPrepareUniforms : gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_image,
+ uniforms::u_dimension,
+ uniforms::u_zoom> {};
+
+struct TerrainUniforms : gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_image,
+ uniforms::u_mode,
+ uniforms::u_dimension,
+ uniforms::u_zoom,
+ uniforms::u_azimuth,
+ uniforms::u_zenith,
+ uniforms::u_mipmap,
+ uniforms::u_exaggeration,
+ uniforms::u_shadow,
+ uniforms::u_highlight,
+ uniforms::u_accent> {};
+
+} // namespace mbgl
diff --git a/src/mbgl/style/bucket_parameters.hpp b/src/mbgl/style/bucket_parameters.hpp
index 9aad35dcad..f608e000d2 100644
--- a/src/mbgl/style/bucket_parameters.hpp
+++ b/src/mbgl/style/bucket_parameters.hpp
@@ -1,54 +1,16 @@
#pragma once
-#include <mbgl/map/mode.hpp>
-#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/style/filter.hpp>
-
-#include <atomic>
-#include <functional>
+#include <mbgl/util/variant.hpp>
+#include <mapbox/recursive_wrapper.hpp>
namespace mbgl {
-
-class TileID;
-class GeometryTileLayer;
-class GeometryTileFeature;
-class GlyphAtlas;
-class CollisionTile;
-class FeatureIndex;
-
namespace style {
-class BucketParameters {
-public:
- BucketParameters(const OverscaledTileID& tileID_,
- const GeometryTileLayer& layer_,
- const std::atomic<bool>& obsolete_,
- uintptr_t tileUID_,
- GlyphAtlas& glyphAtlas_,
- FeatureIndex& featureIndex_,
- const MapMode mode_)
- : tileID(tileID_),
- layer(layer_),
- obsolete(obsolete_),
- tileUID(tileUID_),
- glyphAtlas(glyphAtlas_),
- featureIndex(featureIndex_),
- mode(mode_) {}
-
- bool cancelled() const {
- return obsolete;
- }
-
- void eachFilteredFeature(const Filter&, std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)>);
+class GeometryBucketParameters;
+class RasterBucketParameters;
- const OverscaledTileID& tileID;
- const GeometryTileLayer& layer;
- const std::atomic<bool>& obsolete;
- uintptr_t tileUID;
- GlyphAtlas& glyphAtlas;
- FeatureIndex& featureIndex;
- const MapMode mode;
-};
+using BucketParameters = variant<mapbox::util::recursive_wrapper<GeometryBucketParameters>,
+ mapbox::util::recursive_wrapper<RasterBucketParameters>>;
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/bucket_parameters.cpp b/src/mbgl/style/geometry_bucket_parameters.cpp
index 64f53babcd..acbd20b073 100644
--- a/src/mbgl/style/bucket_parameters.cpp
+++ b/src/mbgl/style/geometry_bucket_parameters.cpp
@@ -1,11 +1,11 @@
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace style {
-void BucketParameters::eachFilteredFeature(const Filter& filter,
+void GeometryBucketParameters::eachFilteredFeature(const Filter& filter,
std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)> function) {
auto name = layer.getName();
for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) {
diff --git a/src/mbgl/style/geometry_bucket_parameters.hpp b/src/mbgl/style/geometry_bucket_parameters.hpp
new file mode 100644
index 0000000000..dce205324d
--- /dev/null
+++ b/src/mbgl/style/geometry_bucket_parameters.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <mbgl/map/mode.hpp>
+#include <mbgl/tile/tile_id.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/filter.hpp>
+
+#include <atomic>
+#include <functional>
+
+namespace mbgl {
+
+class TileID;
+class GeometryTileLayer;
+class GeometryTileFeature;
+class GlyphAtlas;
+class CollisionTile;
+class FeatureIndex;
+
+namespace style {
+
+class GeometryBucketParameters {
+public:
+ GeometryBucketParameters(const OverscaledTileID& tileID_,
+ const GeometryTileLayer& layer_,
+ const std::atomic<bool>& obsolete_,
+ uintptr_t tileUID_,
+ GlyphAtlas& glyphAtlas_,
+ FeatureIndex& featureIndex_,
+ const MapMode mode_)
+ : tileID(tileID_),
+ layer(layer_),
+ obsolete(obsolete_),
+ tileUID(tileUID_),
+ glyphAtlas(glyphAtlas_),
+ featureIndex(featureIndex_),
+ mode(mode_) {}
+
+ bool cancelled() const {
+ return obsolete;
+ }
+
+ void eachFilteredFeature(const Filter&, std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)>);
+
+ const OverscaledTileID& tileID;
+ const GeometryTileLayer& layer;
+ const std::atomic<bool>& obsolete;
+ uintptr_t tileUID;
+ GlyphAtlas& glyphAtlas;
+ FeatureIndex& featureIndex;
+ const MapMode mode;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp
index 4bf2956a6d..52ce1e6176 100644
--- a/src/mbgl/style/layer_impl.hpp
+++ b/src/mbgl/style/layer_impl.hpp
@@ -3,6 +3,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/style/filter.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/layer_observer.hpp>
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/noncopyable.hpp>
@@ -20,7 +21,6 @@ namespace style {
class CascadeParameters;
class CalculationParameters;
-class BucketParameters;
/**
* `Layer::Impl` contains the internal implementation of `Layer`: the details that need to be accessible to other parts
diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp
index 33699b6665..fd121115a9 100644
--- a/src/mbgl/style/layers/circle_layer_impl.cpp
+++ b/src/mbgl/style/layers/circle_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -21,7 +21,9 @@ bool CircleLayer::Impl::recalculate(const CalculationParameters& parameters) {
return hasTransitions;
}
-std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parameters) const {
+std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& params) const {
+ auto& parameters = params.get<GeometryBucketParameters>();
+
auto bucket = std::make_unique<CircleBucket>(parameters.mode);
auto& name = bucketName();
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index fc439f1cd1..0e4873b3dc 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -30,7 +30,8 @@ bool FillLayer::Impl::recalculate(const CalculationParameters& parameters) {
return hasTransitions;
}
-std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& parameters) const {
+std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& params) const {
+ auto& parameters = params.get<GeometryBucketParameters>();
auto bucket = std::make_unique<FillBucket>();
auto& name = bucketName();
diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp
index c116af5fc2..4fc0ddef07 100644
--- a/src/mbgl/style/layers/line_layer_impl.cpp
+++ b/src/mbgl/style/layers/line_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -27,7 +27,8 @@ bool LineLayer::Impl::recalculate(const CalculationParameters& parameters) {
return hasTransitions;
}
-std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& parameters) const {
+std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& params) const {
+ auto& parameters = params.get<GeometryBucketParameters>();
auto bucket = std::make_unique<LineBucket>(parameters.tileID.overscaleFactor());
bucket->layout = layout;
diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp
index 879bfa4559..41370905e7 100644
--- a/src/mbgl/style/layers/raster_layer_impl.cpp
+++ b/src/mbgl/style/layers/raster_layer_impl.cpp
@@ -1,5 +1,7 @@
#include <mbgl/style/layers/raster_layer_impl.hpp>
-#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/style/raster_bucket_parameters.hpp>
+#include <mbgl/renderer/raster_bucket.hpp>
+#include <mbgl/util/image.hpp>
namespace mbgl {
namespace style {
@@ -16,8 +18,9 @@ bool RasterLayer::Impl::recalculate(const CalculationParameters& parameters) {
return hasTransitions;
}
-std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(BucketParameters&) const {
- return nullptr;
+std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(BucketParameters& params) const {
+ auto& parameters = params.get<RasterBucketParameters>();
+ return std::make_unique<RasterBucket>(decodeImage(*parameters.data));
}
} // namespace style
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index 0ac9ff832d..661a635809 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/renderer/bucket.hpp>
@@ -31,7 +31,8 @@ std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&) const
return nullptr;
}
-std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& parameters) const {
+std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& params) const {
+ auto& parameters = params.get<GeometryBucketParameters>();
SymbolLayoutProperties layoutProperties = layout;
CalculationParameters p(parameters.tileID.overscaledZ);
diff --git a/src/mbgl/style/layers/terrain_layer.cpp b/src/mbgl/style/layers/terrain_layer.cpp
new file mode 100644
index 0000000000..3d2a077477
--- /dev/null
+++ b/src/mbgl/style/layers/terrain_layer.cpp
@@ -0,0 +1,156 @@
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#include <mbgl/style/layers/terrain_layer.hpp>
+#include <mbgl/style/layers/terrain_layer_impl.hpp>
+
+namespace mbgl {
+namespace style {
+
+TerrainLayer::TerrainLayer(const std::string& layerID, const std::string& sourceID)
+ : Layer(Type::Terrain, std::make_unique<Impl>())
+ , impl(static_cast<Impl*>(baseImpl.get())) {
+ impl->id = layerID;
+ impl->source = sourceID;
+}
+
+TerrainLayer::TerrainLayer(const Impl& other)
+ : Layer(Type::Terrain, std::make_unique<Impl>(other))
+ , impl(static_cast<Impl*>(baseImpl.get())) {
+}
+
+TerrainLayer::~TerrainLayer() = default;
+
+std::unique_ptr<Layer> TerrainLayer::Impl::clone() const {
+ return std::make_unique<TerrainLayer>(*this);
+}
+
+std::unique_ptr<Layer> TerrainLayer::Impl::cloneRef(const std::string& id_) const {
+ auto result = std::make_unique<TerrainLayer>(*this);
+ result->impl->id = id_;
+ result->impl->ref = this->id;
+ result->impl->paint = TerrainPaintProperties();
+ return std::move(result);
+}
+
+// Source
+
+const std::string& TerrainLayer::getSourceID() const {
+ return impl->source;
+}
+
+void TerrainLayer::setSourceLayer(const std::string& sourceLayer) {
+ impl->sourceLayer = sourceLayer;
+}
+
+const std::string& TerrainLayer::getSourceLayer() const {
+ return impl->sourceLayer;
+}
+
+// Filter
+
+void TerrainLayer::setFilter(const Filter& filter) {
+ impl->filter = filter;
+ impl->observer->onLayerFilterChanged(*this);
+}
+
+const Filter& TerrainLayer::getFilter() const {
+ return impl->filter;
+}
+
+// Layout properties
+
+
+// Paint properties
+
+PropertyValue<Color> TerrainLayer::getDefaultTerrainShadowColor() {
+ return { { 0, 0, 1, 1 } };
+}
+
+PropertyValue<Color> TerrainLayer::getTerrainShadowColor(const optional<std::string>& klass) const {
+ return impl->paint.terrainShadowColor.get(klass);
+}
+
+void TerrainLayer::setTerrainShadowColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ if (value == getTerrainShadowColor(klass))
+ return;
+ impl->paint.terrainShadowColor.set(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<Color> TerrainLayer::getDefaultTerrainHighlightColor() {
+ return { { 1, 1, 0, 1 } };
+}
+
+PropertyValue<Color> TerrainLayer::getTerrainHighlightColor(const optional<std::string>& klass) const {
+ return impl->paint.terrainHighlightColor.get(klass);
+}
+
+void TerrainLayer::setTerrainHighlightColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ if (value == getTerrainHighlightColor(klass))
+ return;
+ impl->paint.terrainHighlightColor.set(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<Color> TerrainLayer::getDefaultTerrainAccentColor() {
+ return { Color::black() };
+}
+
+PropertyValue<Color> TerrainLayer::getTerrainAccentColor(const optional<std::string>& klass) const {
+ return impl->paint.terrainAccentColor.get(klass);
+}
+
+void TerrainLayer::setTerrainAccentColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+ if (value == getTerrainAccentColor(klass))
+ return;
+ impl->paint.terrainAccentColor.set(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<float> TerrainLayer::getDefaultTerrainIlluminationDirection() {
+ return { 135 };
+}
+
+PropertyValue<float> TerrainLayer::getTerrainIlluminationDirection(const optional<std::string>& klass) const {
+ return impl->paint.terrainIlluminationDirection.get(klass);
+}
+
+void TerrainLayer::setTerrainIlluminationDirection(PropertyValue<float> value, const optional<std::string>& klass) {
+ if (value == getTerrainIlluminationDirection(klass))
+ return;
+ impl->paint.terrainIlluminationDirection.set(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<AlignmentType> TerrainLayer::getDefaultTerrainIlluminationAlignment() {
+ return { AlignmentType::Viewport };
+}
+
+PropertyValue<AlignmentType> TerrainLayer::getTerrainIlluminationAlignment(const optional<std::string>& klass) const {
+ return impl->paint.terrainIlluminationAlignment.get(klass);
+}
+
+void TerrainLayer::setTerrainIlluminationAlignment(PropertyValue<AlignmentType> value, const optional<std::string>& klass) {
+ if (value == getTerrainIlluminationAlignment(klass))
+ return;
+ impl->paint.terrainIlluminationAlignment.set(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+PropertyValue<float> TerrainLayer::getDefaultTerrainExaggeration() {
+ return { 1 };
+}
+
+PropertyValue<float> TerrainLayer::getTerrainExaggeration(const optional<std::string>& klass) const {
+ return impl->paint.terrainExaggeration.get(klass);
+}
+
+void TerrainLayer::setTerrainExaggeration(PropertyValue<float> value, const optional<std::string>& klass) {
+ if (value == getTerrainExaggeration(klass))
+ return;
+ impl->paint.terrainExaggeration.set(value, klass);
+ impl->observer->onLayerPaintPropertyChanged(*this);
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/terrain_layer_impl.cpp b/src/mbgl/style/layers/terrain_layer_impl.cpp
new file mode 100644
index 0000000000..79e41fa935
--- /dev/null
+++ b/src/mbgl/style/layers/terrain_layer_impl.cpp
@@ -0,0 +1,47 @@
+#include <mbgl/style/layers/terrain_layer_impl.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
+#include <mbgl/style/raster_bucket_parameters.hpp>
+#include <mbgl/renderer/terrain_bucket.hpp>
+
+namespace mbgl {
+namespace style {
+
+void TerrainLayer::Impl::cascade(const CascadeParameters& parameters) {
+ paint.cascade(parameters);
+}
+
+bool TerrainLayer::Impl::recalculate(const CalculationParameters& parameters) {
+ bool hasTransitions = paint.recalculate(parameters);
+
+ passes = RenderPass::Translucent;
+
+ return hasTransitions;
+}
+
+std::unique_ptr<Bucket> TerrainLayer::Impl::createBucket(BucketParameters& params) const {
+ if (params.is<mapbox::util::recursive_wrapper<GeometryBucketParameters>>()) {
+ // DEM data encoded into vector tile
+ auto& parameters = params.get<GeometryBucketParameters>();
+ auto& layer = parameters.layer;
+
+ for (std::size_t i = 0; !parameters.cancelled() && i < layer.featureCount(); i++) {
+ auto feature = layer.getFeature(i);
+ if (feature->getType() == FeatureType(4)) {
+ return std::make_unique<TerrainBucket>(feature->getDEMPyramid());
+ } else {
+ // Trying to create a DEM from another feature type.
+ }
+ }
+ } else if (params.is<mapbox::util::recursive_wrapper<RasterBucketParameters>>()) {
+ // DEM data from raster tile
+ auto& parameters = params.get<RasterBucketParameters>();
+ if (parameters.data) {
+ return std::make_unique<TerrainBucket>(decodeImage(*parameters.data));
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/terrain_layer_impl.hpp b/src/mbgl/style/layers/terrain_layer_impl.hpp
new file mode 100644
index 0000000000..ce2c7a7e42
--- /dev/null
+++ b/src/mbgl/style/layers/terrain_layer_impl.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/layers/terrain_layer.hpp>
+#include <mbgl/style/layers/terrain_layer_properties.hpp>
+
+namespace mbgl {
+namespace style {
+
+class TerrainLayer::Impl : public Layer::Impl {
+public:
+ std::unique_ptr<Layer> clone() const override;
+ std::unique_ptr<Layer> cloneRef(const std::string& id) const override;
+
+ void cascade(const CascadeParameters&) override;
+ bool recalculate(const CalculationParameters&) override;
+
+ std::unique_ptr<Bucket> createBucket(BucketParameters&) const override;
+
+ TerrainPaintProperties paint;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/terrain_layer_properties.cpp b/src/mbgl/style/layers/terrain_layer_properties.cpp
new file mode 100644
index 0000000000..7373ef0f00
--- /dev/null
+++ b/src/mbgl/style/layers/terrain_layer_properties.cpp
@@ -0,0 +1,31 @@
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#include <mbgl/style/layers/terrain_layer_properties.hpp>
+
+namespace mbgl {
+namespace style {
+
+void TerrainPaintProperties::cascade(const CascadeParameters& parameters) {
+ terrainShadowColor.cascade(parameters);
+ terrainHighlightColor.cascade(parameters);
+ terrainAccentColor.cascade(parameters);
+ terrainIlluminationDirection.cascade(parameters);
+ terrainIlluminationAlignment.cascade(parameters);
+ terrainExaggeration.cascade(parameters);
+}
+
+bool TerrainPaintProperties::recalculate(const CalculationParameters& parameters) {
+ bool hasTransitions = false;
+
+ hasTransitions |= terrainShadowColor.calculate(parameters);
+ hasTransitions |= terrainHighlightColor.calculate(parameters);
+ hasTransitions |= terrainAccentColor.calculate(parameters);
+ hasTransitions |= terrainIlluminationDirection.calculate(parameters);
+ hasTransitions |= terrainIlluminationAlignment.calculate(parameters);
+ hasTransitions |= terrainExaggeration.calculate(parameters);
+
+ return hasTransitions;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layers/terrain_layer_properties.hpp b/src/mbgl/style/layers/terrain_layer_properties.hpp
new file mode 100644
index 0000000000..ad058b0e35
--- /dev/null
+++ b/src/mbgl/style/layers/terrain_layer_properties.hpp
@@ -0,0 +1,29 @@
+// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
+
+#pragma once
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/layout_property.hpp>
+#include <mbgl/style/paint_property.hpp>
+
+namespace mbgl {
+namespace style {
+
+class CascadeParameters;
+class CalculationParameters;
+
+class TerrainPaintProperties {
+public:
+ void cascade(const CascadeParameters&);
+ bool recalculate(const CalculationParameters&);
+
+ PaintProperty<Color> terrainShadowColor { { 0, 0, 1, 1 } };
+ PaintProperty<Color> terrainHighlightColor { { 1, 1, 0, 1 } };
+ PaintProperty<Color> terrainAccentColor { Color::black() };
+ PaintProperty<float> terrainIlluminationDirection { 135 };
+ PaintProperty<AlignmentType> terrainIlluminationAlignment { AlignmentType::Viewport };
+ PaintProperty<float> terrainExaggeration { 1 };
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/raster_bucket_parameters.hpp b/src/mbgl/style/raster_bucket_parameters.hpp
new file mode 100644
index 0000000000..cd2a7c5fd7
--- /dev/null
+++ b/src/mbgl/style/raster_bucket_parameters.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/tile/tile_id.hpp>
+
+#include <memory>
+#include <string>
+
+namespace mbgl {
+namespace style {
+
+class RasterBucketParameters {
+public:
+ RasterBucketParameters(const OverscaledTileID& tileID_,
+ std::shared_ptr<const std::string> data_)
+ : tileID(tileID_), data(data_) {
+ }
+
+ const OverscaledTileID& tileID;
+ std::shared_ptr<const std::string> data;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp
index afaa94878c..f601796c98 100644
--- a/src/mbgl/style/source_impl.cpp
+++ b/src/mbgl/style/source_impl.cpp
@@ -55,6 +55,7 @@ void Source::Impl::startRender(algorithm::ClipIDGenerator& generator,
const mat4& projMatrix,
const TransformState& transform) {
if (type == SourceType::Vector ||
+ type == SourceType::Raster ||
type == SourceType::GeoJSON ||
type == SourceType::Annotations) {
generator.update(renderTiles);
diff --git a/src/mbgl/style/sources/raster_source_impl.cpp b/src/mbgl/style/sources/raster_source_impl.cpp
index b727651260..91a93c800c 100644
--- a/src/mbgl/style/sources/raster_source_impl.cpp
+++ b/src/mbgl/style/sources/raster_source_impl.cpp
@@ -12,7 +12,7 @@ RasterSource::Impl::Impl(std::string id_, Source& base_,
std::unique_ptr<Tile> RasterSource::Impl::createTile(const OverscaledTileID& tileID,
const UpdateParameters& parameters) {
- return std::make_unique<RasterTile>(tileID, parameters, tileset);
+ return std::make_unique<RasterTile>(tileID, base.getID(), parameters, tileset);
}
} // namespace style
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index 3c2b97b65d..7781f6ecdd 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -11,6 +11,7 @@
#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/terrain_layer.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/parser.hpp>
#include <mbgl/style/query_parameters.hpp>
@@ -542,6 +543,7 @@ struct QueueSourceReloadVisitor {
// they don't participate in layout.
void operator()(CustomLayer&) {}
void operator()(RasterLayer&) {}
+ void operator()(TerrainLayer&) {}
void operator()(BackgroundLayer&) {}
template <class VectorLayer>
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 61437b79b1..b0d1132178 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -36,6 +36,10 @@ public:
return geometry;
}
+ DEMPyramid getDEMPyramid() const override {
+ return {};
+ }
+
optional<Value> getValue(const std::string& key) const override {
auto it = feature.properties.find(key);
if (it != feature.properties.end()) {
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 46e2b414fe..edc9094e7c 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -6,6 +6,7 @@
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/geometry/feature_index.hpp>
@@ -78,6 +79,7 @@ void GeometryTile::redoLayout() {
// Avoid cloning and including irrelevant layers.
if (layer->is<BackgroundLayer>() ||
layer->is<CustomLayer>() ||
+ layer->is<RasterLayer>() ||
layer->baseImpl->source != sourceID ||
id.overscaledZ < std::floor(layer->baseImpl->minZoom) ||
id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom) ||
diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp
index 8a10ec058a..903af0c892 100644
--- a/src/mbgl/tile/geometry_tile_data.hpp
+++ b/src/mbgl/tile/geometry_tile_data.hpp
@@ -3,6 +3,7 @@
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/geometry/dem_pyramid.hpp>
#include <cstdint>
#include <string>
@@ -38,6 +39,7 @@ public:
virtual PropertyMap getProperties() const { return PropertyMap(); }
virtual optional<FeatureIdentifier> getID() const { return {}; }
virtual GeometryCollection getGeometries() const = 0;
+ virtual DEMPyramid getDEMPyramid() const = 0;
};
class GeometryTileLayer {
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index b6f166be56..f46eab628c 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -4,7 +4,8 @@
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/layout/symbol_layout.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
+#include <mbgl/style/raster_bucket_parameters.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
@@ -210,19 +211,15 @@ void GeometryTileWorker::redoLayout() {
continue;
}
- BucketParameters parameters(id,
- *geometryLayer,
- obsolete,
- reinterpret_cast<uintptr_t>(this),
- glyphAtlas,
- *featureIndex,
- mode);
+ BucketParameters parameters = GeometryBucketParameters{id, *geometryLayer, obsolete,
+ reinterpret_cast<uintptr_t>(this),
+ glyphAtlas, *featureIndex, mode};
if (layer->is<SymbolLayer>()) {
symbolLayouts.push_back(layer->as<SymbolLayer>()->impl->createLayout(parameters));
} else {
std::unique_ptr<Bucket> bucket = layer->baseImpl->createBucket(parameters);
- if (bucket->hasData()) {
+ if (bucket && bucket->hasData()) {
buckets.emplace(layer->baseImpl->bucketName(), std::move(bucket));
}
}
diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp
index c7a051f841..e82b0c1485 100644
--- a/src/mbgl/tile/raster_tile.cpp
+++ b/src/mbgl/tile/raster_tile.cpp
@@ -4,6 +4,10 @@
#include <mbgl/tile/tile_loader_impl.hpp>
#include <mbgl/style/source.hpp>
#include <mbgl/style/update_parameters.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/terrain_layer.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/storage/file_source.hpp>
@@ -12,14 +16,18 @@
namespace mbgl {
+using namespace style;
+
RasterTile::RasterTile(const OverscaledTileID& id_,
+ std::string sourceID_,
const style::UpdateParameters& parameters,
const Tileset& tileset)
: Tile(id_),
loader(*this, id_, parameters, tileset),
+ sourceID(std::move(sourceID_)),
+ style(parameters.style),
mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())),
- worker(parameters.workerScheduler,
- ActorRef<RasterTile>(*this, mailbox)) {
+ worker(parameters.workerScheduler, ActorRef<RasterTile>(*this, mailbox), id_) {
}
RasterTile::~RasterTile() = default;
@@ -36,23 +44,44 @@ void RasterTile::setData(std::shared_ptr<const std::string> data,
optional<Timestamp> expires_) {
modified = modified_;
expires = expires_;
+
+ std::vector<std::unique_ptr<Layer>> copy;
+
+ for (const Layer* layer : style.getLayers()) {
+ // Avoid cloning and including irrelevant layers.
+ if (!(layer->is<RasterLayer>() || layer->is<TerrainLayer>()) ||
+ layer->baseImpl->source != sourceID ||
+ id.overscaledZ < std::floor(layer->baseImpl->minZoom) ||
+ id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom) ||
+ layer->baseImpl->visibility == VisibilityType::None) {
+ continue;
+ }
+
+ copy.push_back(layer->baseImpl->clone());
+ }
+ worker.invoke(&RasterTileWorker::setLayers, std::move(copy));
worker.invoke(&RasterTileWorker::parse, data);
}
-void RasterTile::onParsed(std::unique_ptr<Bucket> result) {
- bucket = std::move(result);
+void RasterTile::onParsed(ParseResult result) {
availableData = DataAvailability::All;
+ buckets = std::move(result.buckets);
observer->onTileChanged(*this);
}
void RasterTile::onError(std::exception_ptr err) {
- bucket.reset();
availableData = DataAvailability::All;
observer->onTileError(*this, err);
}
-Bucket* RasterTile::getBucket(const style::Layer&) {
- return bucket.get();
+Bucket* RasterTile::getBucket(const style::Layer& layer) {
+ const auto it = buckets.find(layer.baseImpl->bucketName());
+ if (it == buckets.end()) {
+ return nullptr;
+ }
+
+ assert(it->second);
+ return it->second.get();
}
void RasterTile::setNecessity(Necessity necessity) {
diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp
index 1f6ceef0db..ce13d2cafc 100644
--- a/src/mbgl/tile/raster_tile.hpp
+++ b/src/mbgl/tile/raster_tile.hpp
@@ -10,6 +10,7 @@ namespace mbgl {
class Tileset;
namespace style {
+class Style;
class Layer;
class UpdateParameters;
} // namespace style
@@ -17,8 +18,9 @@ class UpdateParameters;
class RasterTile : public Tile {
public:
RasterTile(const OverscaledTileID&,
- const style::UpdateParameters&,
- const Tileset&);
+ std::string sourceID,
+ const style::UpdateParameters&,
+ const Tileset&);
~RasterTile() final;
void setNecessity(Necessity) final;
@@ -29,20 +31,27 @@ public:
optional<Timestamp> expires_);
void cancel() override;
+
+ class ParseResult {
+ public:
+ std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
+ };
+
Bucket* getBucket(const style::Layer&) override;
- void onParsed(std::unique_ptr<Bucket> result);
+ void onParsed(ParseResult);
void onError(std::exception_ptr);
private:
TileLoader<RasterTile> loader;
+ const std::string sourceID;
+ style::Style& style;
+
std::shared_ptr<Mailbox> mailbox;
Actor<RasterTileWorker> worker;
- // Contains the Bucket object for the tile. Buckets are render
- // objects and they get added by tile parsing operations.
- std::unique_ptr<Bucket> bucket;
+ std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp
index 443ee10400..25cec516cc 100644
--- a/src/mbgl/tile/raster_tile_worker.cpp
+++ b/src/mbgl/tile/raster_tile_worker.cpp
@@ -1,23 +1,46 @@
#include <mbgl/tile/raster_tile_worker.hpp>
#include <mbgl/tile/raster_tile.hpp>
-#include <mbgl/renderer/raster_bucket.cpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/style/raster_bucket_parameters.hpp>
+#include <mbgl/style/geometry_bucket_parameters.hpp>
#include <mbgl/actor/actor.hpp>
namespace mbgl {
-RasterTileWorker::RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTile> parent_)
- : parent(std::move(parent_)) {
+using namespace style;
+
+RasterTileWorker::RasterTileWorker(ActorRef<RasterTileWorker>,
+ ActorRef<RasterTile> parent_,
+ OverscaledTileID id_)
+ : parent(std::move(parent_)), id(std::move(id_)) {
+}
+
+RasterTileWorker::~RasterTileWorker() = default;
+
+void RasterTileWorker::setLayers(std::vector<std::unique_ptr<Layer>> layers_) {
+ layers = std::move(layers_);
}
void RasterTileWorker::parse(std::shared_ptr<const std::string> data) {
- if (!data) {
- parent.invoke(&RasterTile::onParsed, nullptr); // No data; empty tile.
+ if (!layers) {
return;
}
try {
- auto bucket = std::make_unique<RasterBucket>(decodeImage(*data));
- parent.invoke(&RasterTile::onParsed, std::move(bucket));
+ std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
+
+ BucketParameters parameters = RasterBucketParameters{id, data};
+
+ for (auto& layer : *layers) {
+ std::unique_ptr<Bucket> bucket = layer->baseImpl->createBucket(parameters);
+ if (bucket && bucket->hasData()) {
+ buckets.emplace(layer->baseImpl->bucketName(), std::move(bucket));
+ }
+ }
+
+ parent.invoke(&RasterTile::onParsed, RasterTile::ParseResult {
+ std::move(buckets)
+ });
} catch (...) {
parent.invoke(&RasterTile::onError, std::current_exception());
}
diff --git a/src/mbgl/tile/raster_tile_worker.hpp b/src/mbgl/tile/raster_tile_worker.hpp
index 44bc37ca5d..c99b6269ec 100644
--- a/src/mbgl/tile/raster_tile_worker.hpp
+++ b/src/mbgl/tile/raster_tile_worker.hpp
@@ -1,6 +1,8 @@
#pragma once
+#include <mbgl/tile/tile_id.hpp>
#include <mbgl/actor/actor_ref.hpp>
+#include <mbgl/util/optional.hpp>
#include <memory>
#include <string>
@@ -9,14 +11,25 @@ namespace mbgl {
class RasterTile;
+namespace style {
+class Layer;
+} // namespace style
+
class RasterTileWorker {
public:
- RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTile>);
+ RasterTileWorker(ActorRef<RasterTileWorker>, ActorRef<RasterTile>, OverscaledTileID);
+ ~RasterTileWorker();
+ void setLayers(std::vector<std::unique_ptr<style::Layer>>);
void parse(std::shared_ptr<const std::string> data);
private:
ActorRef<RasterTile> parent;
+
+ const OverscaledTileID id;
+
+ // Outer optional indicates whether we've received it or not.
+ optional<std::vector<std::unique_ptr<style::Layer>>> layers;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index a195885415..db4b16da32 100644
--- a/src/mbgl/tile/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -1,6 +1,7 @@
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/platform/log.hpp>
#include <protozero/pbf_reader.hpp>
@@ -24,6 +25,7 @@ public:
std::unordered_map<std::string,Value> getProperties() const override;
optional<FeatureIdentifier> getID() const override;
GeometryCollection getGeometries() const override;
+ DEMPyramid getDEMPyramid() const override;
private:
const VectorTileLayer& layer;
@@ -241,6 +243,76 @@ GeometryCollection VectorTileFeature::getGeometries() const {
return fixupPolygons(lines);
}
+DEMPyramid VectorTileFeature::getDEMPyramid() const {
+ DEMPyramid pyramid;
+ if (layer.extent != 256) {
+ Log::Warning(Event::ParseTile, "DEM extent must be 256");
+ return pyramid;
+ }
+
+ auto decodeSVarint = [](auto& iter) {
+ if (iter.first == iter.second) {
+ fprintf(stderr, "reading beyond end\n");
+ }
+ return iter.first != iter.second ? protozero::decode_zigzag32(*iter.first++) : 0;
+ };
+
+ auto iter = geometry_iter;
+
+ // Decode main square
+ pyramid.levels.emplace_back(256, 256, 128);
+ {
+ auto& level = pyramid.levels.front();
+ for (int32_t y = 0; y < level.height; y++) {
+ for (int32_t x = 0; x < level.width; x++) {
+ const auto value = decodeSVarint(iter);
+ const auto value_left = x ? level.get(x - 1, y) : 0;
+ const auto value_up = y ? level.get(x, y - 1) : 0;
+ const auto value_up_left = x && y ? level.get(x - 1, y - 1) : 0;
+ level.set(x, y, value + value_left + value_up - value_up_left);
+ }
+ }
+ }
+
+ pyramid.buildLevels();
+
+ // Decode bleed
+ for (auto& level : pyramid.levels) {
+ if (level.width <= 2 || level.height <= 2) {
+ break;
+ }
+
+ int32_t x = -1;
+ int32_t y = -1;
+ int32_t prev = 0;
+ // Decode left column
+ while (y < level.height) {
+ level.set(x, y, (prev = decodeSVarint(iter) + prev));
+ y++;
+ }
+
+ // Decode bottom row
+ while (x < level.width) {
+ level.set(x, y, (prev = decodeSVarint(iter) + prev));
+ x++;
+ }
+
+ // Decode right column
+ while (y > -1) {
+ level.set(x, y, (prev = decodeSVarint(iter) + prev));
+ y--;
+ }
+
+ // Decode top row
+ while (x > -1) {
+ level.set(x, y, (prev = decodeSVarint(iter) + prev));
+ x--;
+ }
+ }
+
+ return pyramid;
+}
+
VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_)
: data(std::move(data_)) {
}