From f30bdfca9c5ae139d58f93bbcbc4f167577e21f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 14 Oct 2016 14:53:57 +0200 Subject: [core] implement terrain rendering --- cmake/core-files.cmake | 20 +- cmake/shaders.cmake | 2 + include/mbgl/style/conversion/layer.hpp | 29 +++ .../style/conversion/make_property_setters.hpp | 9 + include/mbgl/style/layer.hpp | 4 + include/mbgl/style/layers/terrain_layer.hpp | 68 +++++ package.json | 4 +- .../mapbox/mapboxsdk/style/layers/Property.java | 21 ++ .../mapboxsdk/style/layers/PropertyFactory.java | 150 +++++++++++ .../mapboxsdk/style/layers/TerrainLayer.java | 248 ++++++++++++++++++ .../mapboxsdk/testapp/style/TerrainLayerTest.java | 276 +++++++++++++++++++++ .../android/src/style/layers/terrain_layer.cpp | 88 +++++++ .../android/src/style/layers/terrain_layer.hpp | 45 ++++ src/mbgl/annotation/annotation_tile.hpp | 1 + src/mbgl/geometry/dem_pyramid.cpp | 48 ++++ src/mbgl/geometry/dem_pyramid.hpp | 54 ++++ src/mbgl/renderer/painter.hpp | 3 + src/mbgl/renderer/painter_terrain.cpp | 84 +++++++ src/mbgl/renderer/terrain_bucket.cpp | 44 ++++ src/mbgl/renderer/terrain_bucket.hpp | 39 +++ src/mbgl/shader/mesh.cpp | 18 ++ src/mbgl/shader/mesh.hpp | 31 +++ src/mbgl/shader/shaders.hpp | 6 + src/mbgl/shader/terrain_prepare_shader.cpp | 15 ++ src/mbgl/shader/terrain_prepare_shader.hpp | 24 ++ src/mbgl/shader/terrain_shader.cpp | 16 ++ src/mbgl/shader/terrain_shader.hpp | 24 ++ src/mbgl/shader/terrain_uniforms.hpp | 39 +++ src/mbgl/style/bucket_parameters.cpp | 20 -- src/mbgl/style/bucket_parameters.hpp | 50 +--- src/mbgl/style/geometry_bucket_parameters.cpp | 20 ++ src/mbgl/style/geometry_bucket_parameters.hpp | 55 ++++ src/mbgl/style/layer_impl.hpp | 2 +- src/mbgl/style/layers/circle_layer_impl.cpp | 6 +- src/mbgl/style/layers/fill_layer_impl.cpp | 5 +- src/mbgl/style/layers/line_layer_impl.cpp | 5 +- src/mbgl/style/layers/raster_layer_impl.cpp | 9 +- src/mbgl/style/layers/symbol_layer_impl.cpp | 5 +- src/mbgl/style/layers/terrain_layer.cpp | 156 ++++++++++++ src/mbgl/style/layers/terrain_layer_impl.cpp | 47 ++++ src/mbgl/style/layers/terrain_layer_impl.hpp | 24 ++ src/mbgl/style/layers/terrain_layer_properties.cpp | 31 +++ src/mbgl/style/layers/terrain_layer_properties.hpp | 29 +++ src/mbgl/style/raster_bucket_parameters.hpp | 24 ++ src/mbgl/style/source_impl.cpp | 1 + src/mbgl/style/sources/raster_source_impl.cpp | 2 +- src/mbgl/style/style.cpp | 2 + src/mbgl/tile/geojson_tile.cpp | 4 + src/mbgl/tile/geometry_tile.cpp | 2 + src/mbgl/tile/geometry_tile_data.hpp | 2 + src/mbgl/tile/geometry_tile_worker.cpp | 15 +- src/mbgl/tile/raster_tile.cpp | 43 +++- src/mbgl/tile/raster_tile.hpp | 21 +- src/mbgl/tile/raster_tile_worker.cpp | 37 ++- src/mbgl/tile/raster_tile_worker.hpp | 15 +- src/mbgl/tile/vector_tile.cpp | 72 ++++++ 56 files changed, 2004 insertions(+), 110 deletions(-) create mode 100644 include/mbgl/style/layers/terrain_layer.hpp create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TerrainLayer.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/TerrainLayerTest.java create mode 100644 platform/android/src/style/layers/terrain_layer.cpp create mode 100644 platform/android/src/style/layers/terrain_layer.hpp create mode 100644 src/mbgl/geometry/dem_pyramid.cpp create mode 100644 src/mbgl/geometry/dem_pyramid.hpp create mode 100644 src/mbgl/renderer/painter_terrain.cpp create mode 100644 src/mbgl/renderer/terrain_bucket.cpp create mode 100644 src/mbgl/renderer/terrain_bucket.hpp create mode 100644 src/mbgl/shader/mesh.cpp create mode 100644 src/mbgl/shader/mesh.hpp create mode 100644 src/mbgl/shader/terrain_prepare_shader.cpp create mode 100644 src/mbgl/shader/terrain_prepare_shader.hpp create mode 100644 src/mbgl/shader/terrain_shader.cpp create mode 100644 src/mbgl/shader/terrain_shader.hpp create mode 100644 src/mbgl/shader/terrain_uniforms.hpp delete mode 100644 src/mbgl/style/bucket_parameters.cpp create mode 100644 src/mbgl/style/geometry_bucket_parameters.cpp create mode 100644 src/mbgl/style/geometry_bucket_parameters.hpp create mode 100644 src/mbgl/style/layers/terrain_layer.cpp create mode 100644 src/mbgl/style/layers/terrain_layer_impl.cpp create mode 100644 src/mbgl/style/layers/terrain_layer_impl.hpp create mode 100644 src/mbgl/style/layers/terrain_layer_properties.cpp create mode 100644 src/mbgl/style/layers/terrain_layer_properties.hpp create mode 100644 src/mbgl/style/raster_bucket_parameters.hpp 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 #include #include +#include #include #include #include @@ -95,6 +96,8 @@ public: converted = convertVectorLayer(*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 { @@ -197,6 +200,32 @@ private: return std::make_unique(id, *source); } + template + Result> convertTerrainLayer(const std::string& id, const V& value) const { + auto sourceValue = objectMember(value, "source"); + if (!sourceValue) { + return Error { "layer must have a source" }; + } + + optional source = toString(*sourceValue); + if (!source) { + return Error { "layer source must be a string" }; + } + + auto layer = std::make_unique(id, *source); + + auto sourceLayerValue = objectMember(value, "source-layer"); + if (sourceLayerValue) { + optional sourceLayer = toString(*sourceLayerValue); + if (!sourceLayer) { + return Error { "layer source-layer must be a string" }; + } + layer->setSourceLayer(*sourceLayer); + } + + return std::move(layer); + } + template Result> convertBackgroundLayer(const std::string& id, const V&) const { return std::make_unique(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 #include #include +#include #include #include @@ -67,6 +68,7 @@ auto makeLayoutPropertySetters() { + return result; } @@ -124,6 +126,13 @@ auto makePaintPropertySetters() { result["raster-contrast"] = makePropertySetter(&RasterLayer::setRasterContrast); result["raster-fade-duration"] = makePropertySetter(&RasterLayer::setRasterFadeDuration); + result["terrain-shadow-color"] = makePropertySetter(&TerrainLayer::setTerrainShadowColor); + result["terrain-highlight-color"] = makePropertySetter(&TerrainLayer::setTerrainHighlightColor); + result["terrain-accent-color"] = makePropertySetter(&TerrainLayer::setTerrainAccentColor); + result["terrain-illumination-direction"] = makePropertySetter(&TerrainLayer::setTerrainIlluminationDirection); + result["terrain-illumination-alignment"] = makePropertySetter(&TerrainLayer::setTerrainIlluminationAlignment); + result["terrain-exaggeration"] = makePropertySetter(&TerrainLayer::setTerrainExaggeration); + result["background-color"] = makePropertySetter(&BackgroundLayer::setBackgroundColor); result["background-pattern"] = makePropertySetter(&BackgroundLayer::setBackgroundPattern); result["background-opacity"] = makePropertySetter(&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()); case Type::Raster: return visitor(*as()); + case Type::Terrain: + return visitor(*as()); case Type::Background: return visitor(*as()); 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 +#include +#include + +#include + +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 getDefaultTerrainShadowColor(); + PropertyValue getTerrainShadowColor(const optional& klass = {}) const; + void setTerrainShadowColor(PropertyValue, const optional& klass = {}); + + static PropertyValue getDefaultTerrainHighlightColor(); + PropertyValue getTerrainHighlightColor(const optional& klass = {}) const; + void setTerrainHighlightColor(PropertyValue, const optional& klass = {}); + + static PropertyValue getDefaultTerrainAccentColor(); + PropertyValue getTerrainAccentColor(const optional& klass = {}) const; + void setTerrainAccentColor(PropertyValue, const optional& klass = {}); + + static PropertyValue getDefaultTerrainIlluminationDirection(); + PropertyValue getTerrainIlluminationDirection(const optional& klass = {}) const; + void setTerrainIlluminationDirection(PropertyValue, const optional& klass = {}); + + static PropertyValue getDefaultTerrainIlluminationAlignment(); + PropertyValue getTerrainIlluminationAlignment(const optional& klass = {}) const; + void setTerrainIlluminationAlignment(PropertyValue, const optional& klass = {}); + + static PropertyValue getDefaultTerrainExaggeration(); + PropertyValue getTerrainExaggeration(const optional& klass = {}) const; + void setTerrainExaggeration(PropertyValue, const optional& klass = {}); + + // Private implementation + + class Impl; + Impl* const impl; + + TerrainLayer(const Impl&); + TerrainLayer(const TerrainLayer&) = delete; +}; + +template <> +inline bool Layer::is() 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 { @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 @@ -1011,6 +1011,156 @@ public class PropertyFactory { return new PaintProperty<>("raster-fade-duration", function); } + /** + * 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 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 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> terrainShadowColor(Function 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 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 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> terrainHighlightColor(Function 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 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 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> terrainAccentColor(Function 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 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> terrainIlluminationDirection(Function 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 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> terrainIlluminationAlignment(Function 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 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> terrainExaggeration(Function function) { + return new PaintProperty<>("terrain-exaggeration", function); + } + /** * The color with which the background will be drawn. * 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 The online documentation + */ +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 getTerrainShadowColor() { + checkValidity(); + return (PropertyValue) 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 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 getTerrainHighlightColor() { + checkValidity(); + return (PropertyValue) 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 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 getTerrainAccentColor() { + checkValidity(); + return (PropertyValue) 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 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 getTerrainIlluminationDirection() { + checkValidity(); + return (PropertyValue) new PropertyValue(nativeGetTerrainIlluminationDirection()); + } + + /** + * Get the TerrainIlluminationAlignment property + * + * @return property wrapper value around String + */ + @SuppressWarnings("unchecked") + public PropertyValue getTerrainIlluminationAlignment() { + checkValidity(); + return (PropertyValue) new PropertyValue(nativeGetTerrainIlluminationAlignment()); + } + + /** + * Get the TerrainExaggeration property + * + * @return property wrapper value around Float + */ + @SuppressWarnings("unchecked") + public PropertyValue getTerrainExaggeration() { + checkValidity(); + return (PropertyValue) 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 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 + +#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(jni::Make(env, layerId), jni::Make(env, sourceId))) { + } + + TerrainLayer::TerrainLayer(mbgl::Map& map, mbgl::style::TerrainLayer& coreLayer) + : Layer(map, coreLayer) { + } + + TerrainLayer::~TerrainLayer() = default; + + // Property getters + + jni::Object TerrainLayer::getTerrainShadowColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result converted = convert(env, layer.as()->TerrainLayer::getTerrainShadowColor()); + return jni::Object(*converted); + } + + jni::Object TerrainLayer::getTerrainHighlightColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result converted = convert(env, layer.as()->TerrainLayer::getTerrainHighlightColor()); + return jni::Object(*converted); + } + + jni::Object TerrainLayer::getTerrainAccentColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result converted = convert(env, layer.as()->TerrainLayer::getTerrainAccentColor()); + return jni::Object(*converted); + } + + jni::Object TerrainLayer::getTerrainIlluminationDirection(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result converted = convert(env, layer.as()->TerrainLayer::getTerrainIlluminationDirection()); + return jni::Object(*converted); + } + + jni::Object TerrainLayer::getTerrainIlluminationAlignment(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result converted = convert(env, layer.as()->TerrainLayer::getTerrainIlluminationAlignment()); + return jni::Object(*converted); + } + + jni::Object TerrainLayer::getTerrainExaggeration(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result converted = convert(env, layer.as()->TerrainLayer::getTerrainExaggeration()); + return jni::Object(*converted); + } + + jni::Class TerrainLayer::javaClass; + + jni::jobject* TerrainLayer::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = TerrainLayer::javaClass.template GetConstructor(env); + return TerrainLayer::javaClass.New(env, constructor, reinterpret_cast(this)); + } + + void TerrainLayer::registerNative(jni::JNIEnv& env) { + //Lookup the class + TerrainLayer::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + //Register the peer + jni::RegisterNativePeer( + env, TerrainLayer::javaClass, "nativePtr", + std::make_unique, + "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 +#include + +namespace mbgl { +namespace android { + +class TerrainLayer : public Layer { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/TerrainLayer"; }; + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + + TerrainLayer(jni::JNIEnv&, jni::String, jni::String); + + TerrainLayer(mbgl::Map&, mbgl::style::TerrainLayer&); + + ~TerrainLayer(); + + // Property getters + jni::Object getTerrainShadowColor(jni::JNIEnv&); + + jni::Object getTerrainHighlightColor(jni::JNIEnv&); + + jni::Object getTerrainAccentColor(jni::JNIEnv&); + + jni::Object getTerrainIlluminationDirection(jni::JNIEnv&); + + jni::Object getTerrainIlluminationAlignment(jni::JNIEnv&); + + jni::Object 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 getValue(const std::string&) const override; optional 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 + +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(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(width + 2 * border), + static_cast(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 +#include + +#include +#include +#include +#include + +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(image.data.get())[idx(x, y)] = value + 65536; + } + + int32_t get(const int32_t x, const int32_t y) const { + return reinterpret_cast(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 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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(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(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 +#include +#include +#include +#include +#include +#include + +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(), 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 +#include +#include +#include +#include + +namespace mbgl { + +class TerrainPrepareShader; +class TerrainShader; +class RasterShader; +class RasterVertex; + +namespace gl { +class Context; +template 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 dem; + optional 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 + +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 +#include +#include +#include +#include + +namespace mbgl { +namespace gl { + +namespace gl { +class Context; +} // namespace gl + +class Mesh { +public: + Mesh(Size size); + + void upload(gl::Context&); + + std::vector vertices; + std::vector triangles; + std::vector triangleSegments { { 0, 0 } }; + + optional> vertexBuffer; + optional> 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 #include #include +#include +#include #include #include @@ -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 +#include +#include + +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 +#include +#include + +namespace mbgl { + +class RasterVertex; + +class TerrainPrepareShader : public gl::Shader { +public: + TerrainPrepareShader(gl::Context&, Defines defines = None); + + using VertexType = RasterVertex; + using UniformsType = TerrainPrepareUniforms; + + gl::Attribute a_pos = { "a_pos", *this }; + gl::Attribute 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 +#include +#include +#include + +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 +#include +#include + +namespace mbgl { + +class RasterVertex; + +class TerrainShader : public gl::Shader { +public: + TerrainShader(gl::Context&, Defines defines = None); + + using VertexType = RasterVertex; + using UniformsType = TerrainUniforms; + + gl::Attribute a_pos = { "a_pos", *this }; + gl::Attribute 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 + +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.cpp b/src/mbgl/style/bucket_parameters.cpp deleted file mode 100644 index 64f53babcd..0000000000 --- a/src/mbgl/style/bucket_parameters.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include - -namespace mbgl { -namespace style { - -void BucketParameters::eachFilteredFeature(const Filter& filter, - std::function function) { - auto name = layer.getName(); - for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) { - auto feature = layer.getFeature(i); - if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); })) - continue; - function(*feature, i, name); - } -} - -} // namespace style -} // 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 -#include -#include - -#include -#include +#include +#include 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& 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); +class GeometryBucketParameters; +class RasterBucketParameters; - const OverscaledTileID& tileID; - const GeometryTileLayer& layer; - const std::atomic& obsolete; - uintptr_t tileUID; - GlyphAtlas& glyphAtlas; - FeatureIndex& featureIndex; - const MapMode mode; -}; +using BucketParameters = variant, + mapbox::util::recursive_wrapper>; } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/geometry_bucket_parameters.cpp b/src/mbgl/style/geometry_bucket_parameters.cpp new file mode 100644 index 0000000000..acbd20b073 --- /dev/null +++ b/src/mbgl/style/geometry_bucket_parameters.cpp @@ -0,0 +1,20 @@ +#include +#include +#include + +namespace mbgl { +namespace style { + +void GeometryBucketParameters::eachFilteredFeature(const Filter& filter, + std::function function) { + auto name = layer.getName(); + for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) { + auto feature = layer.getFeature(i); + if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); })) + continue; + function(*feature, i, name); + } +} + +} // namespace style +} // namespace mbgl 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 +#include +#include +#include + +#include +#include + +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& 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); + + const OverscaledTileID& tileID; + const GeometryTileLayer& layer; + const std::atomic& 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 #include #include +#include #include #include #include @@ -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 -#include +#include #include #include #include @@ -21,7 +21,9 @@ bool CircleLayer::Impl::recalculate(const CalculationParameters& parameters) { return hasTransitions; } -std::unique_ptr CircleLayer::Impl::createBucket(BucketParameters& parameters) const { +std::unique_ptr CircleLayer::Impl::createBucket(BucketParameters& params) const { + auto& parameters = params.get(); + auto bucket = std::make_unique(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 -#include +#include #include #include #include @@ -30,7 +30,8 @@ bool FillLayer::Impl::recalculate(const CalculationParameters& parameters) { return hasTransitions; } -std::unique_ptr FillLayer::Impl::createBucket(BucketParameters& parameters) const { +std::unique_ptr FillLayer::Impl::createBucket(BucketParameters& params) const { + auto& parameters = params.get(); auto bucket = std::make_unique(); 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 -#include +#include #include #include #include @@ -27,7 +27,8 @@ bool LineLayer::Impl::recalculate(const CalculationParameters& parameters) { return hasTransitions; } -std::unique_ptr LineLayer::Impl::createBucket(BucketParameters& parameters) const { +std::unique_ptr LineLayer::Impl::createBucket(BucketParameters& params) const { + auto& parameters = params.get(); auto bucket = std::make_unique(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 -#include +#include +#include +#include namespace mbgl { namespace style { @@ -16,8 +18,9 @@ bool RasterLayer::Impl::recalculate(const CalculationParameters& parameters) { return hasTransitions; } -std::unique_ptr RasterLayer::Impl::createBucket(BucketParameters&) const { - return nullptr; +std::unique_ptr RasterLayer::Impl::createBucket(BucketParameters& params) const { + auto& parameters = params.get(); + return std::make_unique(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 -#include +#include #include #include @@ -31,7 +31,8 @@ std::unique_ptr SymbolLayer::Impl::createBucket(BucketParameters&) const return nullptr; } -std::unique_ptr SymbolLayer::Impl::createLayout(BucketParameters& parameters) const { +std::unique_ptr SymbolLayer::Impl::createLayout(BucketParameters& params) const { + auto& parameters = params.get(); 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 +#include + +namespace mbgl { +namespace style { + +TerrainLayer::TerrainLayer(const std::string& layerID, const std::string& sourceID) + : Layer(Type::Terrain, std::make_unique()) + , impl(static_cast(baseImpl.get())) { + impl->id = layerID; + impl->source = sourceID; +} + +TerrainLayer::TerrainLayer(const Impl& other) + : Layer(Type::Terrain, std::make_unique(other)) + , impl(static_cast(baseImpl.get())) { +} + +TerrainLayer::~TerrainLayer() = default; + +std::unique_ptr TerrainLayer::Impl::clone() const { + return std::make_unique(*this); +} + +std::unique_ptr TerrainLayer::Impl::cloneRef(const std::string& id_) const { + auto result = std::make_unique(*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 TerrainLayer::getDefaultTerrainShadowColor() { + return { { 0, 0, 1, 1 } }; +} + +PropertyValue TerrainLayer::getTerrainShadowColor(const optional& klass) const { + return impl->paint.terrainShadowColor.get(klass); +} + +void TerrainLayer::setTerrainShadowColor(PropertyValue value, const optional& klass) { + if (value == getTerrainShadowColor(klass)) + return; + impl->paint.terrainShadowColor.set(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue TerrainLayer::getDefaultTerrainHighlightColor() { + return { { 1, 1, 0, 1 } }; +} + +PropertyValue TerrainLayer::getTerrainHighlightColor(const optional& klass) const { + return impl->paint.terrainHighlightColor.get(klass); +} + +void TerrainLayer::setTerrainHighlightColor(PropertyValue value, const optional& klass) { + if (value == getTerrainHighlightColor(klass)) + return; + impl->paint.terrainHighlightColor.set(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue TerrainLayer::getDefaultTerrainAccentColor() { + return { Color::black() }; +} + +PropertyValue TerrainLayer::getTerrainAccentColor(const optional& klass) const { + return impl->paint.terrainAccentColor.get(klass); +} + +void TerrainLayer::setTerrainAccentColor(PropertyValue value, const optional& klass) { + if (value == getTerrainAccentColor(klass)) + return; + impl->paint.terrainAccentColor.set(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue TerrainLayer::getDefaultTerrainIlluminationDirection() { + return { 135 }; +} + +PropertyValue TerrainLayer::getTerrainIlluminationDirection(const optional& klass) const { + return impl->paint.terrainIlluminationDirection.get(klass); +} + +void TerrainLayer::setTerrainIlluminationDirection(PropertyValue value, const optional& klass) { + if (value == getTerrainIlluminationDirection(klass)) + return; + impl->paint.terrainIlluminationDirection.set(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue TerrainLayer::getDefaultTerrainIlluminationAlignment() { + return { AlignmentType::Viewport }; +} + +PropertyValue TerrainLayer::getTerrainIlluminationAlignment(const optional& klass) const { + return impl->paint.terrainIlluminationAlignment.get(klass); +} + +void TerrainLayer::setTerrainIlluminationAlignment(PropertyValue value, const optional& klass) { + if (value == getTerrainIlluminationAlignment(klass)) + return; + impl->paint.terrainIlluminationAlignment.set(value, klass); + impl->observer->onLayerPaintPropertyChanged(*this); +} + +PropertyValue TerrainLayer::getDefaultTerrainExaggeration() { + return { 1 }; +} + +PropertyValue TerrainLayer::getTerrainExaggeration(const optional& klass) const { + return impl->paint.terrainExaggeration.get(klass); +} + +void TerrainLayer::setTerrainExaggeration(PropertyValue value, const optional& 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 +#include +#include +#include + +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 TerrainLayer::Impl::createBucket(BucketParameters& params) const { + if (params.is>()) { + // DEM data encoded into vector tile + auto& parameters = params.get(); + 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(feature->getDEMPyramid()); + } else { + // Trying to create a DEM from another feature type. + } + } + } else if (params.is>()) { + // DEM data from raster tile + auto& parameters = params.get(); + if (parameters.data) { + return std::make_unique(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 +#include +#include + +namespace mbgl { +namespace style { + +class TerrainLayer::Impl : public Layer::Impl { +public: + std::unique_ptr clone() const override; + std::unique_ptr cloneRef(const std::string& id) const override; + + void cascade(const CascadeParameters&) override; + bool recalculate(const CalculationParameters&) override; + + std::unique_ptr 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 + +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 +#include +#include + +namespace mbgl { +namespace style { + +class CascadeParameters; +class CalculationParameters; + +class TerrainPaintProperties { +public: + void cascade(const CascadeParameters&); + bool recalculate(const CalculationParameters&); + + PaintProperty terrainShadowColor { { 0, 0, 1, 1 } }; + PaintProperty terrainHighlightColor { { 1, 1, 0, 1 } }; + PaintProperty terrainAccentColor { Color::black() }; + PaintProperty terrainIlluminationDirection { 135 }; + PaintProperty terrainIlluminationAlignment { AlignmentType::Viewport }; + PaintProperty 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 +#include + +#include +#include + +namespace mbgl { +namespace style { + +class RasterBucketParameters { +public: + RasterBucketParameters(const OverscaledTileID& tileID_, + std::shared_ptr data_) + : tileID(tileID_), data(data_) { + } + + const OverscaledTileID& tileID; + std::shared_ptr 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 RasterSource::Impl::createTile(const OverscaledTileID& tileID, const UpdateParameters& parameters) { - return std::make_unique(tileID, parameters, tileset); + return std::make_unique(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 #include #include +#include #include #include #include @@ -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 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 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 #include #include +#include #include #include #include @@ -78,6 +79,7 @@ void GeometryTile::redoLayout() { // Avoid cloning and including irrelevant layers. if (layer->is() || layer->is() || + layer->is() || 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 #include #include +#include #include #include @@ -38,6 +39,7 @@ public: virtual PropertyMap getProperties() const { return PropertyMap(); } virtual optional 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 #include #include -#include +#include +#include #include #include #include @@ -210,19 +211,15 @@ void GeometryTileWorker::redoLayout() { continue; } - BucketParameters parameters(id, - *geometryLayer, - obsolete, - reinterpret_cast(this), - glyphAtlas, - *featureIndex, - mode); + BucketParameters parameters = GeometryBucketParameters{id, *geometryLayer, obsolete, + reinterpret_cast(this), + glyphAtlas, *featureIndex, mode}; if (layer->is()) { symbolLayouts.push_back(layer->as()->impl->createLayout(parameters)); } else { std::unique_ptr 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 #include #include +#include +#include +#include +#include #include #include #include @@ -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(*util::RunLoop::Get())), - worker(parameters.workerScheduler, - ActorRef(*this, mailbox)) { + worker(parameters.workerScheduler, ActorRef(*this, mailbox), id_) { } RasterTile::~RasterTile() = default; @@ -36,23 +44,44 @@ void RasterTile::setData(std::shared_ptr data, optional expires_) { modified = modified_; expires = expires_; + + std::vector> copy; + + for (const Layer* layer : style.getLayers()) { + // Avoid cloning and including irrelevant layers. + if (!(layer->is() || layer->is()) || + 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 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 expires_); void cancel() override; + + class ParseResult { + public: + std::unordered_map> buckets; + }; + Bucket* getBucket(const style::Layer&) override; - void onParsed(std::unique_ptr result); + void onParsed(ParseResult); void onError(std::exception_ptr); private: TileLoader loader; + const std::string sourceID; + style::Style& style; + std::shared_ptr mailbox; Actor worker; - // Contains the Bucket object for the tile. Buckets are render - // objects and they get added by tile parsing operations. - std::unique_ptr bucket; + std::unordered_map> 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 #include -#include +#include +#include +#include #include namespace mbgl { -RasterTileWorker::RasterTileWorker(ActorRef, ActorRef parent_) - : parent(std::move(parent_)) { +using namespace style; + +RasterTileWorker::RasterTileWorker(ActorRef, + ActorRef parent_, + OverscaledTileID id_) + : parent(std::move(parent_)), id(std::move(id_)) { +} + +RasterTileWorker::~RasterTileWorker() = default; + +void RasterTileWorker::setLayers(std::vector> layers_) { + layers = std::move(layers_); } void RasterTileWorker::parse(std::shared_ptr data) { - if (!data) { - parent.invoke(&RasterTile::onParsed, nullptr); // No data; empty tile. + if (!layers) { return; } try { - auto bucket = std::make_unique(decodeImage(*data)); - parent.invoke(&RasterTile::onParsed, std::move(bucket)); + std::unordered_map> buckets; + + BucketParameters parameters = RasterBucketParameters{id, data}; + + for (auto& layer : *layers) { + std::unique_ptr 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 #include +#include #include #include @@ -9,14 +11,25 @@ namespace mbgl { class RasterTile; +namespace style { +class Layer; +} // namespace style + class RasterTileWorker { public: - RasterTileWorker(ActorRef, ActorRef); + RasterTileWorker(ActorRef, ActorRef, OverscaledTileID); + ~RasterTileWorker(); + void setLayers(std::vector>); void parse(std::shared_ptr data); private: ActorRef parent; + + const OverscaledTileID id; + + // Outer optional indicates whether we've received it or not. + optional>> 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 #include #include +#include #include @@ -24,6 +25,7 @@ public: std::unordered_map getProperties() const override; optional 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 data_) : data(std::move(data_)) { } -- cgit v1.2.1