diff options
author | Gali Nelle <galinelle.mapbox@gmail.com> | 2020-03-25 17:35:44 +0200 |
---|---|---|
committer | Gali Nelle <galinelle.mapbox@gmail.com> | 2020-03-31 23:56:59 +0300 |
commit | e12f3ddae9c4c0121e65dd580d8d880d5bbe6d17 (patch) | |
tree | 10a58e3f6b29312d92dc787a8ede52e38ecaf469 | |
parent | 349c6153de3c88f45b730be0d8ba9e2b14ab4d2a (diff) | |
download | qtlocation-mapboxgl-e12f3ddae9c4c0121e65dd580d8d880d5bbe6d17.tar.gz |
Add LocationComponentLayer
New key is "G" in mbgl-glfw, cycling between no puck, centered
in the viewport and positioned in Tokyo.
73 files changed, 3590 insertions, 13 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4357493cef..dc9dbf4989 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -808,6 +808,16 @@ if(MBGL_WITH_OPENGL) target_sources( mbgl-core PRIVATE + ${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/location_component_layer.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/location_component_layer_factory.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/location_component_layer_factory.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/location_component_layer.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/location_component_layer_impl.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/location_component_layer_impl.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/location_component_layer_properties.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/location_component_layer_properties.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_location_component_layer.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_location_component_layer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/backend.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/custom_layer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/custom_layer_factory.hpp diff --git a/include/mbgl/layermanager/location_component_layer_factory.hpp b/include/mbgl/layermanager/location_component_layer_factory.hpp new file mode 100644 index 0000000000..160a652cca --- /dev/null +++ b/include/mbgl/layermanager/location_component_layer_factory.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include <mbgl/layermanager/layer_factory.hpp> + +namespace mbgl { + +class LocationComponentLayerFactory : public LayerFactory { +protected: + const style::LayerTypeInfo* getTypeInfo() const noexcept final; + std::unique_ptr<style::Layer> createLayer(const std::string& id, + const style::conversion::Convertible& value) noexcept final; + std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final; +}; + +} // namespace mbgl diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 3a5833be64..4acddfb012 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -54,6 +54,11 @@ struct Converter<std::vector<float>> { optional<std::vector<float>> operator()(const Convertible& value, Error& error) const; }; +template <size_t N> +struct Converter<std::array<double, N>> { + optional<std::array<double, N>> operator()(const Convertible& value, Error& error) const; +}; + template <> struct Converter<std::vector<std::string>> { optional<std::vector<std::string>> operator()(const Convertible& value, Error& error) const; diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index 61360b7440..925f97af18 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -47,6 +47,10 @@ struct Converter<PropertyValue<T>> { } }; +template <> +struct Converter<PropertyValue<std::array<double, 3>>, void> { + optional<PropertyValue<std::array<double, 3>>> operator()(const Convertible& value, Error& error, bool, bool) const; +}; } // namespace conversion } // namespace style } // namespace mbgl diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs index 9cdd74737a..42cc12959f 100644 --- a/include/mbgl/style/layers/layer.hpp.ejs +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -29,7 +29,7 @@ class TransitionOptions; class <%- camelize(type) %>Layer : public Layer { public: -<% if (type === 'background') { -%> +<% if ((type === 'background') || (type === 'location-component')) { -%> <%- camelize(type) %>Layer(const std::string& layerID); <% } else { -%> <%- camelize(type) %>Layer(const std::string& layerID, const std::string& sourceID); diff --git a/include/mbgl/style/layers/location_component_layer.hpp b/include/mbgl/style/layers/location_component_layer.hpp new file mode 100644 index 0000000000..a0c55dce8c --- /dev/null +++ b/include/mbgl/style/layers/location_component_layer.hpp @@ -0,0 +1,105 @@ +// clang-format off + +// 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/style/expression/formatted.hpp> +#include <mbgl/util/color.hpp> + +namespace mbgl { +namespace style { + +class TransitionOptions; + +class LocationComponentLayer : public Layer { +public: + LocationComponentLayer(const std::string& layerID); + ~LocationComponentLayer() final; + + // Layout properties + + static PropertyValue<float> getDefaultAccuracyRadius(); + const PropertyValue<float>& getAccuracyRadius() const; + void setAccuracyRadius(const PropertyValue<float>&); + + static PropertyValue<float> getDefaultBearing(); + const PropertyValue<float>& getBearing() const; + void setBearing(const PropertyValue<float>&); + + static PropertyValue<expression::Image> getDefaultBearingImage(); + const PropertyValue<expression::Image>& getBearingImage() const; + void setBearingImage(const PropertyValue<expression::Image>&); + + static PropertyValue<float> getDefaultBearingImageSize(); + const PropertyValue<float>& getBearingImageSize() const; + void setBearingImageSize(const PropertyValue<float>&); + + static PropertyValue<float> getDefaultImageTiltDisplacement(); + const PropertyValue<float>& getImageTiltDisplacement() const; + void setImageTiltDisplacement(const PropertyValue<float>&); + + static PropertyValue<std::array<double, 3>> getDefaultLocation(); + const PropertyValue<std::array<double, 3>>& getLocation() const; + void setLocation(const PropertyValue<std::array<double, 3>>&); + + static PropertyValue<float> getDefaultPerspectiveCompensation(); + const PropertyValue<float>& getPerspectiveCompensation() const; + void setPerspectiveCompensation(const PropertyValue<float>&); + + static PropertyValue<expression::Image> getDefaultShadowImage(); + const PropertyValue<expression::Image>& getShadowImage() const; + void setShadowImage(const PropertyValue<expression::Image>&); + + static PropertyValue<float> getDefaultShadowImageSize(); + const PropertyValue<float>& getShadowImageSize() const; + void setShadowImageSize(const PropertyValue<float>&); + + static PropertyValue<expression::Image> getDefaultTopImage(); + const PropertyValue<expression::Image>& getTopImage() const; + void setTopImage(const PropertyValue<expression::Image>&); + + static PropertyValue<float> getDefaultTopImageSize(); + const PropertyValue<float>& getTopImageSize() const; + void setTopImageSize(const PropertyValue<float>&); + + // Paint properties + + static PropertyValue<Color> getDefaultAccuracyRadiusBorderColor(); + const PropertyValue<Color>& getAccuracyRadiusBorderColor() const; + void setAccuracyRadiusBorderColor(const PropertyValue<Color>&); + void setAccuracyRadiusBorderColorTransition(const TransitionOptions&); + TransitionOptions getAccuracyRadiusBorderColorTransition() const; + + static PropertyValue<Color> getDefaultAccuracyRadiusColor(); + const PropertyValue<Color>& getAccuracyRadiusColor() const; + void setAccuracyRadiusColor(const PropertyValue<Color>&); + void setAccuracyRadiusColorTransition(const TransitionOptions&); + TransitionOptions getAccuracyRadiusColorTransition() const; + + // Private implementation + + class Impl; + const Impl& impl() const; + + Mutable<Impl> mutableImpl() const; + LocationComponentLayer(Immutable<Impl>); + std::unique_ptr<Layer> cloneRef(const std::string& id) const final; + +protected: + // Dynamic properties + optional<conversion::Error> setPropertyInternal(const std::string& name, const conversion::Convertible& value) final; + + StyleProperty getProperty(const std::string& name) const final; + Value serialize() const final; + + Mutable<Layer::Impl> mutableBaseImpl() const final; +}; + +} // namespace style +} // namespace mbgl + +// clang-format on diff --git a/metrics/cache-metrics.db b/metrics/cache-metrics.db Binary files differindex b52622fb7f..53ddff9bf6 100644 --- a/metrics/cache-metrics.db +++ b/metrics/cache-metrics.db diff --git a/metrics/linux-gcc8-release/location_component/dateline/metrics.json b/metrics/linux-gcc8-release/location_component/dateline/metrics.json new file mode 100644 index 0000000000..a8b686bab4 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/dateline/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2030499, + 3176 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/default/metrics.json b/metrics/linux-gcc8-release/location_component/default/metrics.json new file mode 100644 index 0000000000..cf12bfdbdd --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/default/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2019459, + 3183 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/no_radius_border/metrics.json b/metrics/linux-gcc8-release/location_component/no_radius_border/metrics.json new file mode 100644 index 0000000000..448a15c30f --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/no_radius_border/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2027964, + 3148 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/no_radius_fill/metrics.json b/metrics/linux-gcc8-release/location_component/no_radius_fill/metrics.json new file mode 100644 index 0000000000..adb9c3079f --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/no_radius_fill/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2026685, + 3230 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/no_textures/metrics.json b/metrics/linux-gcc8-release/location_component/no_textures/metrics.json new file mode 100644 index 0000000000..afa2b9cfa2 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/no_textures/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2019537, + 2903 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/one_texture/metrics.json b/metrics/linux-gcc8-release/location_component/one_texture/metrics.json new file mode 100644 index 0000000000..1eff342890 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/one_texture/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2016330, + 3092 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/rotated/metrics.json b/metrics/linux-gcc8-release/location_component/rotated/metrics.json new file mode 100644 index 0000000000..bc0d83fa42 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/rotated/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2022474, + 3233 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/tilted/metrics.json b/metrics/linux-gcc8-release/location_component/tilted/metrics.json new file mode 100644 index 0000000000..50ce665ac8 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/tilted/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2054777, + 3404 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 9, + 5, + 1, + [ + 131072, + 131072 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/tilted_texture_shift/metrics.json b/metrics/linux-gcc8-release/location_component/tilted_texture_shift/metrics.json new file mode 100644 index 0000000000..1e8f85b822 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/tilted_texture_shift/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2052965, + 3306 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 8, + 5, + 1, + [ + 114688, + 114688 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/tilted_texture_shift_bottom_left/metrics.json b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_bottom_left/metrics.json new file mode 100644 index 0000000000..5cca7b84a7 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_bottom_left/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2050020, + 3367 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 9, + 5, + 1, + [ + 131072, + 131072 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/tilted_texture_shift_bottom_right/metrics.json b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_bottom_right/metrics.json new file mode 100644 index 0000000000..8a8d14205d --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_bottom_right/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2051851, + 3386 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 8, + 5, + 1, + [ + 114688, + 114688 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/tilted_texture_shift_top_left/metrics.json b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_top_left/metrics.json new file mode 100644 index 0000000000..555e5d633b --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_top_left/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2052276, + 3502 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 9, + 5, + 1, + [ + 131072, + 131072 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/tilted_texture_shift_top_right/metrics.json b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_top_right/metrics.json new file mode 100644 index 0000000000..79ad9f7fd2 --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/tilted_texture_shift_top_right/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2089360, + 3395 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 9, + 5, + 1, + [ + 131072, + 131072 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/linux-gcc8-release/location_component/two_textures/metrics.json b/metrics/linux-gcc8-release/location_component/two_textures/metrics.json new file mode 100644 index 0000000000..b65a8f2a4c --- /dev/null +++ b/metrics/linux-gcc8-release/location_component/two_textures/metrics.json @@ -0,0 +1,47 @@ +{ + "memory": [ + [ + "probeMemory - default - end", + 2022280, + 3143 + ], + [ + "probeMemory - default - start", + 0, + 0 + ] + ], + "network": [ + [ + "probeNetwork - default - end", + 3, + 40583 + ], + [ + "probeNetwork - default - start", + 0, + 0 + ] + ], + "gfx": [ + [ + "probeGFX - default - end", + 0, + 5, + 5, + 1, + [ + 65536, + 65536 + ], + [ + 22, + 22 + ], + [ + 64, + 64 + ] + ] + ] +}
\ No newline at end of file diff --git a/metrics/tests/location_component/dateline/expected.png b/metrics/tests/location_component/dateline/expected.png Binary files differnew file mode 100644 index 0000000000..301e1e18d4 --- /dev/null +++ b/metrics/tests/location_component/dateline/expected.png diff --git a/metrics/tests/location_component/dateline/style.json b/metrics/tests/location_component/dateline/style.json new file mode 100644 index 0000000000..d1b475c5dc --- /dev/null +++ b/metrics/tests/location_component/dateline/style.json @@ -0,0 +1,63 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ + 35.693055, + 139.766707 + ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/default/expected.png b/metrics/tests/location_component/default/expected.png Binary files differnew file mode 100644 index 0000000000..8b26f151cd --- /dev/null +++ b/metrics/tests/location_component/default/expected.png diff --git a/metrics/tests/location_component/default/style.json b/metrics/tests/location_component/default/style.json new file mode 100644 index 0000000000..b502d6ef2a --- /dev/null +++ b/metrics/tests/location_component/default/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/no_radius_border/expected.png b/metrics/tests/location_component/no_radius_border/expected.png Binary files differnew file mode 100644 index 0000000000..c5c12575b6 --- /dev/null +++ b/metrics/tests/location_component/no_radius_border/expected.png diff --git a/metrics/tests/location_component/no_radius_border/style.json b/metrics/tests/location_component/no_radius_border/style.json new file mode 100644 index 0000000000..4d4d7fe57b --- /dev/null +++ b/metrics/tests/location_component/no_radius_border/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "sprite" : {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)" + } + } + ] +} diff --git a/metrics/tests/location_component/no_radius_fill/expected.png b/metrics/tests/location_component/no_radius_fill/expected.png Binary files differnew file mode 100644 index 0000000000..bdd22e7197 --- /dev/null +++ b/metrics/tests/location_component/no_radius_fill/expected.png diff --git a/metrics/tests/location_component/no_radius_fill/style.json b/metrics/tests/location_component/no_radius_fill/style.json new file mode 100644 index 0000000000..f54bf2b710 --- /dev/null +++ b/metrics/tests/location_component/no_radius_fill/style.json @@ -0,0 +1,60 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/no_textures/expected.png b/metrics/tests/location_component/no_textures/expected.png Binary files differnew file mode 100644 index 0000000000..11044f9e8d --- /dev/null +++ b/metrics/tests/location_component/no_textures/expected.png diff --git a/metrics/tests/location_component/no_textures/style.json b/metrics/tests/location_component/no_textures/style.json new file mode 100644 index 0000000000..49efafa4bf --- /dev/null +++ b/metrics/tests/location_component/no_textures/style.json @@ -0,0 +1,58 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image-size" : 48, + "top-image-size" : 16, + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/one_texture/expected.png b/metrics/tests/location_component/one_texture/expected.png Binary files differnew file mode 100644 index 0000000000..6196a50f8e --- /dev/null +++ b/metrics/tests/location_component/one_texture/expected.png diff --git a/metrics/tests/location_component/one_texture/style.json b/metrics/tests/location_component/one_texture/style.json new file mode 100644 index 0000000000..76fd703bbd --- /dev/null +++ b/metrics/tests/location_component/one_texture/style.json @@ -0,0 +1,59 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image-size" : 16, + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/rotated/expected.png b/metrics/tests/location_component/rotated/expected.png Binary files differnew file mode 100644 index 0000000000..3d5ca56bb8 --- /dev/null +++ b/metrics/tests/location_component/rotated/expected.png diff --git a/metrics/tests/location_component/rotated/style.json b/metrics/tests/location_component/rotated/style.json new file mode 100644 index 0000000000..3b2545f099 --- /dev/null +++ b/metrics/tests/location_component/rotated/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 0, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/tilted/expected.png b/metrics/tests/location_component/tilted/expected.png Binary files differnew file mode 100644 index 0000000000..231190a0ee --- /dev/null +++ b/metrics/tests/location_component/tilted/expected.png diff --git a/metrics/tests/location_component/tilted/style.json b/metrics/tests/location_component/tilted/style.json new file mode 100644 index 0000000000..902eb480e1 --- /dev/null +++ b/metrics/tests/location_component/tilted/style.json @@ -0,0 +1,63 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ + 35.693055, + 139.766707 + ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 0 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/tilted_texture_shift/expected.png b/metrics/tests/location_component/tilted_texture_shift/expected.png Binary files differnew file mode 100644 index 0000000000..6d86abcc35 --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift/expected.png diff --git a/metrics/tests/location_component/tilted_texture_shift/style.json b/metrics/tests/location_component/tilted_texture_shift/style.json new file mode 100644 index 0000000000..ce87bed503 --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 55, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/tilted_texture_shift_bottom_left/expected.png b/metrics/tests/location_component/tilted_texture_shift_bottom_left/expected.png Binary files differnew file mode 100644 index 0000000000..3ab127d2b9 --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_bottom_left/expected.png diff --git a/metrics/tests/location_component/tilted_texture_shift_bottom_left/style.json b/metrics/tests/location_component/tilted_texture_shift_bottom_left/style.json new file mode 100644 index 0000000000..ef635d9d0e --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_bottom_left/style.json @@ -0,0 +1,62 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.768885, 35.693125 ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/tilted_texture_shift_bottom_right/expected.png b/metrics/tests/location_component/tilted_texture_shift_bottom_right/expected.png Binary files differnew file mode 100644 index 0000000000..4edc36178d --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_bottom_right/expected.png diff --git a/metrics/tests/location_component/tilted_texture_shift_bottom_right/style.json b/metrics/tests/location_component/tilted_texture_shift_bottom_right/style.json new file mode 100644 index 0000000000..b48545cacf --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_bottom_right/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766487, 35.694867 ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/tilted_texture_shift_top_left/expected.png b/metrics/tests/location_component/tilted_texture_shift_top_left/expected.png Binary files differnew file mode 100644 index 0000000000..935e36906c --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_top_left/expected.png diff --git a/metrics/tests/location_component/tilted_texture_shift_top_left/style.json b/metrics/tests/location_component/tilted_texture_shift_top_left/style.json new file mode 100644 index 0000000000..02872bddd5 --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_top_left/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766972, 35.687286 ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/tilted_texture_shift_top_right/expected.png b/metrics/tests/location_component/tilted_texture_shift_top_right/expected.png Binary files differnew file mode 100644 index 0000000000..ff4efb118a --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_top_right/expected.png diff --git a/metrics/tests/location_component/tilted_texture_shift_top_right/style.json b/metrics/tests/location_component/tilted_texture_shift_top_right/style.json new file mode 100644 index 0000000000..d1ba11747b --- /dev/null +++ b/metrics/tests/location_component/tilted_texture_shift_top_right/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.759723, 35.692799 ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image" : "puck_hat", + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 0, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_component/two_textures/expected.png b/metrics/tests/location_component/two_textures/expected.png Binary files differnew file mode 100644 index 0000000000..0e1c5fd270 --- /dev/null +++ b/metrics/tests/location_component/two_textures/expected.png diff --git a/metrics/tests/location_component/two_textures/style.json b/metrics/tests/location_component/two_textures/style.json new file mode 100644 index 0000000000..787d6d3e6e --- /dev/null +++ b/metrics/tests/location_component/two_textures/style.json @@ -0,0 +1,60 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 0, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-component", + "layout" : { + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image" : "puck", + "bearing-image-size" : 48, + "top-image-size" : 16, + "shadow-image" : "puck_shadow", + "shadow-image-size" : 112, + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 5 + }, + "paint" : { + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/platform/default/src/mbgl/layermanager/layer_manager.cpp b/platform/default/src/mbgl/layermanager/layer_manager.cpp index f9e46d78ab..78cd32881d 100644 --- a/platform/default/src/mbgl/layermanager/layer_manager.cpp +++ b/platform/default/src/mbgl/layermanager/layer_manager.cpp @@ -4,6 +4,7 @@ #include <mbgl/layermanager/circle_layer_factory.hpp> #ifdef MBGL_RENDER_BACKEND_OPENGL #include <mbgl/gl/custom_layer_factory.hpp> +#include <mbgl/layermanager/location_component_layer_factory.hpp> #endif #include <mbgl/layermanager/fill_extrusion_layer_factory.hpp> #include <mbgl/layermanager/fill_layer_factory.hpp> @@ -65,6 +66,9 @@ LayerManagerDefault::LayerManagerDefault() { #if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) addLayerType(std::make_unique<CustomLayerFactory>()); #endif +#if !defined(MBGL_LAYER_LOCATION_COMPONENT_DISABLE_ALL) + addLayerType(std::make_unique<LocationComponentLayerFactory>()); +#endif #endif } diff --git a/platform/glfw/CMakeLists.txt b/platform/glfw/CMakeLists.txt index 2a1524e115..cee0afb4c2 100644 --- a/platform/glfw/CMakeLists.txt +++ b/platform/glfw/CMakeLists.txt @@ -13,6 +13,11 @@ add_executable( ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/map/map_snapshotter.cpp ) +set_property( + SOURCE ${PROJECT_SOURCE_DIR}/platform/glfw/glfw_view.cpp + PROPERTY COMPILE_DEFINITIONS MAPBOX_PUCK_ASSETS_PATH=\"${PROJECT_SOURCE_DIR}/platform/glfw/assets/\" +) + if(MBGL_WITH_OPENGL) target_sources( mbgl-glfw diff --git a/platform/glfw/assets/puck.png b/platform/glfw/assets/puck.png Binary files differnew file mode 100644 index 0000000000..09d93ebec8 --- /dev/null +++ b/platform/glfw/assets/puck.png diff --git a/platform/glfw/assets/puck_hat.png b/platform/glfw/assets/puck_hat.png Binary files differnew file mode 100644 index 0000000000..e9411e0d02 --- /dev/null +++ b/platform/glfw/assets/puck_hat.png diff --git a/platform/glfw/assets/puck_shadow.png b/platform/glfw/assets/puck_shadow.png Binary files differnew file mode 100644 index 0000000000..baf848b597 --- /dev/null +++ b/platform/glfw/assets/puck_shadow.png diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index f59d44bd8c..9de51bbc4a 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -20,6 +20,7 @@ #include <mbgl/style/transition_options.hpp> #include <mbgl/util/chrono.hpp> #include <mbgl/util/geo.hpp> +#include <mbgl/util/io.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/platform.hpp> #include <mbgl/util/string.hpp> @@ -41,6 +42,29 @@ #include <iostream> #include <utility> +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) +#include <mbgl/style/layers/location_component_layer.hpp> + +namespace { +const std::string mbglPuckAssetsPath{MAPBOX_PUCK_ASSETS_PATH}; +} + +static mbgl::Color premultiply(mbgl::Color c) { + c.r *= c.a; + c.g *= c.a; + c.b *= c.a; + return c; +} + +static std::array<double, 3> toArray(const mbgl::LatLng &crd) { + std::array<double, 3> data; + data[0] = crd.latitude(); + data[1] = crd.longitude(); + data[2] = 0; + return data; +} +#endif + class SnapshotObserver final : public mbgl::MapSnapshotterObserver { public: ~SnapshotObserver() override = default; @@ -459,6 +483,9 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, // Snapshot with overlay view->makeSnapshot(true); } break; + case GLFW_KEY_G: { + view->toggleLocationComponentLayer(); + } break; } } @@ -689,6 +716,12 @@ void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) } view->map->scaleBy(scale, mbgl::ScreenCoordinate { view->lastX, view->lastY }); +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + if (view->puck && view->puckFollowsCameraCenter) { + mbgl::LatLng mapCenter = view->map->getCameraOptions().center.value(); + view->puck->setLocation(toArray(mapCenter)); + } +#endif } void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { @@ -755,7 +788,12 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) { } view->lastX = x; view->lastY = y; - +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + if (view->puck && view->puckFollowsCameraCenter) { + mbgl::LatLng mapCenter = view->map->getCameraOptions().center.value(); + view->puck->setLocation(toArray(mapCenter)); + } +#endif auto &style = view->map->getStyle(); if (style.getLayer("state-fills")) { auto screenCoordinate = mbgl::ScreenCoordinate{view->lastX, view->lastY}; @@ -879,6 +917,10 @@ void GLFWView::setWindowTitle(const std::string& title) { } void GLFWView::onDidFinishLoadingStyle() { +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + puck = nullptr; +#endif + if (show3DExtrusions) { toggle3DExtrusions(show3DExtrusions); } @@ -933,3 +975,71 @@ void GLFWView::toggleCustomSource() { mbgl::style::VisibilityType::None : mbgl::style::VisibilityType::Visible); } } + +void GLFWView::toggleLocationComponentLayer() { +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + puck = static_cast<mbgl::style::LocationComponentLayer *>(map->getStyle().getLayer("puck")); + static const mbgl::LatLng puckLocation{35.683389, 139.76525}; // A location on the crossing of 4 tiles + if (puck == nullptr) { + auto puckLayer = std::make_unique<mbgl::style::LocationComponentLayer>("puck"); + + puckLayer->setLocation(toArray(puckLocation)); + puckLayer->setAccuracyRadius(50); + puckLayer->setAccuracyRadiusColor( + premultiply(mbgl::Color{0.0, 1.0, 0.0, 0.2})); // Note: these must be fed premultiplied + + puckLayer->setBearing(0); + puckLayer->setAccuracyRadiusBorderColor(premultiply(mbgl::Color{0.0, 1.0, 0.2, 0.4})); + puckLayer->setTopImageSize(24); + puckLayer->setBearingImageSize(72); + puckLayer->setShadowImageSize(96); + puckLayer->setImageTiltDisplacement(8.0f); // set to 0 for a "flat" puck + puckLayer->setPerspectiveCompensation(0.9); + + map->getStyle().addImage(std::make_unique<mbgl::style::Image>( + "puck.png", mbgl::decodeImage(mbgl::util::read_file(mbglPuckAssetsPath + "puck.png")), 1.0)); + + map->getStyle().addImage(std::make_unique<mbgl::style::Image>( + "puck_shadow.png", mbgl::decodeImage(mbgl::util::read_file(mbglPuckAssetsPath + "puck_shadow.png")), 1.0)); + + map->getStyle().addImage(std::make_unique<mbgl::style::Image>( + "puck_hat.png", mbgl::decodeImage(mbgl::util::read_file(mbglPuckAssetsPath + "puck_hat.png")), 1.0)); + + puckLayer->setBearingImage(mbgl::style::expression::Image("puck.png")); + puckLayer->setShadowImage(mbgl::style::expression::Image("puck_shadow.png")); + puckLayer->setTopImage(mbgl::style::expression::Image("puck_hat.png")); + + puck = puckLayer.get(); + map->getStyle().addLayer(std::move(puckLayer)); + } else { + bool visible = puck->getVisibility() == mbgl::style::VisibilityType::Visible; + if (visible) { + if (!puckFollowsCameraCenter) { + mbgl::LatLng mapCenter = map->getCameraOptions().center.value(); + puck->setLocation(toArray(mapCenter)); + puckFollowsCameraCenter = true; + } else { + puckFollowsCameraCenter = false; + puck->setVisibility(mbgl::style::VisibilityType(mbgl::style::VisibilityType::None)); + } + } else { + puck->setLocation(toArray(puckLocation)); + puck->setVisibility(mbgl::style::VisibilityType(mbgl::style::VisibilityType::Visible)); + puckFollowsCameraCenter = false; + } + } +#endif +} + +using Nanoseconds = std::chrono::nanoseconds; + +void GLFWView::onWillStartRenderingFrame() { +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + puck = static_cast<mbgl::style::LocationComponentLayer *>(map->getStyle().getLayer("puck")); + if (puck) { + uint64_t ns = mbgl::Clock::now().time_since_epoch().count(); + const float bearing = float(ns % 2000000000) / 2000000000.0 * 360.0; + puck->setBearing(bearing); + } +#endif +} diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp index 21b54f87a9..8133594b3e 100644 --- a/platform/glfw/glfw_view.hpp +++ b/platform/glfw/glfw_view.hpp @@ -6,6 +6,9 @@ #include <mbgl/util/optional.hpp> #include <mbgl/util/run_loop.hpp> #include <mbgl/util/timer.hpp> +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) +#include <mbgl/style/layers/location_component_layer.hpp> +#endif struct GLFWwindow; class GLFWBackend; @@ -61,6 +64,7 @@ public: // mbgl::MapObserver implementation void onDidFinishLoadingStyle() override; + void onWillStartRenderingFrame() override; protected: // mbgl::Backend implementation @@ -91,6 +95,7 @@ private: void addAnimatedAnnotation(); void updateAnimatedAnnotations(); void toggleCustomSource(); + void toggleLocationComponentLayer(); void cycleDebugOptions(); void clearAnnotations(); @@ -148,4 +153,9 @@ private: std::unique_ptr<mbgl::MapSnapshotter> snapshotter; std::unique_ptr<SnapshotObserver> snapshotterObserver; mbgl::ResourceOptions mapResourceOptions; + + bool puckFollowsCameraCenter = false; +#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) + mbgl::style::LocationComponentLayer *puck = nullptr; +#endif }; diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 804d4a243f..08fd1fba19 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -64,7 +64,7 @@ global.evaluatedType = function (property) { case 'boolean': return 'bool'; case 'number': - return 'float'; + return /location$/.test(property.name) ? 'double' : 'float'; case 'resolvedImage': return 'expression::Image'; case 'formatted': @@ -77,7 +77,7 @@ global.evaluatedType = function (property) { return `Color`; case 'array': if (property.length) { - return `std::array<${evaluatedType({type: property.value})}, ${property.length}>`; + return `std::array<${evaluatedType({type: property.value, name: property.name})}, ${property.length}>`; } else { return `std::vector<${evaluatedType({type: property.value, name: property.name})}>`; } diff --git a/scripts/style-spec.js b/scripts/style-spec.js index 8a9c9d4144..4b5d05e2ea 100644 --- a/scripts/style-spec.js +++ b/scripts/style-spec.js @@ -1 +1,168 @@ -var spec = module.exports = require('../mapbox-gl-js/src/style-spec/reference/v8'); +const referenceSpec = require('../mapbox-gl-js/src/style-spec/reference/v8'); + +referenceSpec.layer.type.values["location-component"] = {}; +referenceSpec["layout_location-component"] = { + "top-image": { + "type": "resolvedImage", + "property-type": "data-constant", + "expression": { + "interpolated": false, + "parameters": [ + "zoom" + ] + }, + "doc": "Name of image in sprite to use as the top of the location component." + }, + "bearing-image": { + "type": "resolvedImage", + "property-type": "data-constant", + "expression": { + "interpolated": false, + "parameters": [ + "zoom" + ] + }, + "doc": "Name of image in sprite to use as the middle of the location component." + }, + "shadow-image": { + "type": "resolvedImage", + "property-type": "data-constant", + "expression": { + "interpolated": false, + "parameters": [ + "zoom" + ] + }, + "doc": "Name of image in sprite to use as the background of the location component." + }, + "location": { + "type": "array", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "length": 3, + "value": "number", + "property-type": "data-constant", + "expression": { + "interpolated": false, + "parameters": [] + }, + "doc": "An array of [latitude, longitude, altitude] position of the location component." + }, + "bearing": { + "type": "number", + "default": "0", + "property-type": "data-constant", + "expression": { + "interpolated": false, + "parameters": [ ] + }, + "doc": "The bearing of the location component." + }, + "accuracy-radius": { + "type": "number", + "default": "0", + "property-type": "data-constant", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "doc": "The accuracy, in meters, of the position source used to retrieve the position of the location component." + }, + "top-image-size": { + "type": "number", + "property-type": "data-constant", + "default": "1", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "doc": "The size of the top image, in pixels." + }, + "bearing-image-size": { + "type": "number", + "property-type": "data-constant", + "default": "1", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "doc": "The size of the bearing image, in pixels." + }, + "shadow-image-size": { + "type": "number", + "property-type": "data-constant", + "default": "1", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "doc": "The size of the shadow image, in pixels." + }, + "perspective-compensation": { + "type": "number", + "default": "0.85", + "property-type": "data-constant", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "doc": "The amount of the perspective compensation, between 0 and 1. A value of 1 produces a location component of constant width across the screen. A value of 0 makes it scale naturally according to the viewing projection." + }, + "image-tilt-displacement": { + "type": "number", + "property-type": "data-constant", + "default": "0", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "doc": "The displacement off the center of the top image and the shadow image when the pitch of the map is greater than 0. This helps producing a three-dimensional appearence." + } +}; + +referenceSpec["paint_location-component"] = { + "accuracy-radius-color": { + "type": "color", + "property-type": "data-constant", + "default": "#ffffff", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "transition": true, + "doc": "The color for drawing the accuracy radius, as a circle. To adjust transparency, set the alpha component of the color accordingly." + + }, + "accuracy-radius-border-color": { + "type": "color", + "property-type": "data-constant", + "default": "#ffffff", + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "transition": true, + "doc": "The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly." + } +}; + +var spec = module.exports = referenceSpec diff --git a/src/mbgl/gl/defines.hpp b/src/mbgl/gl/defines.hpp index 75325dfb75..1d9177d069 100644 --- a/src/mbgl/gl/defines.hpp +++ b/src/mbgl/gl/defines.hpp @@ -93,6 +93,7 @@ #define GL_LESS 0x0201 #define GL_LINEAR 0x2601 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_LINE_LOOP 0x0002 #define GL_LINES 0x0001 #define GL_LINE_STRIP 0x0003 @@ -102,6 +103,7 @@ #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_NEAREST 0x2600 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_NEVER 0x0200 #define GL_NO_ERROR 0 #define GL_NOTEQUAL 0x0205 @@ -161,7 +163,7 @@ #define GL_VERTEX_SHADER 0x8B31 #define GL_VIEWPORT 0x0BA2 #define GL_ZERO 0 - +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #ifdef MBGL_USE_GLES2 #define GL_HALF_FLOAT 0x8D61 #else @@ -176,4 +178,4 @@ #define GL_RGBA8 0x8058 #define GL_ZOOM_X 0x0D16 #define GL_ZOOM_Y 0x0D17 -#endif
\ No newline at end of file +#endif diff --git a/src/mbgl/layermanager/location_component_layer_factory.cpp b/src/mbgl/layermanager/location_component_layer_factory.cpp new file mode 100644 index 0000000000..26a58accf8 --- /dev/null +++ b/src/mbgl/layermanager/location_component_layer_factory.cpp @@ -0,0 +1,25 @@ +#include <mbgl/layermanager/location_component_layer_factory.hpp> +#include <mbgl/renderer/layers/render_location_component_layer.hpp> +#include <mbgl/style/layers/location_component_layer.hpp> +#include <mbgl/style/layers/location_component_layer_impl.hpp> + +namespace mbgl { + +const style::LayerTypeInfo* LocationComponentLayerFactory::getTypeInfo() const noexcept { + return style::LocationComponentLayer::Impl::staticTypeInfo(); +} + +std::unique_ptr<style::Layer> LocationComponentLayerFactory::createLayer( + const std::string& id, const style::conversion::Convertible& value) noexcept { + (void)value; + return std::unique_ptr<style::Layer>(new style::LocationComponentLayer(id)); // Need the map here. Or as a property? +} + +std::unique_ptr<RenderLayer> LocationComponentLayerFactory::createRenderLayer( + Immutable<style::Layer::Impl> impl) noexcept { + assert(impl->getTypeInfo() == getTypeInfo()); + return std::make_unique<RenderLocationComponentLayer>( + staticImmutableCast<style::LocationComponentLayer::Impl>(impl)); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_location_component_layer.cpp b/src/mbgl/renderer/layers/render_location_component_layer.cpp new file mode 100644 index 0000000000..b2f8b263b5 --- /dev/null +++ b/src/mbgl/renderer/layers/render_location_component_layer.cpp @@ -0,0 +1,802 @@ +#include <array> +#include <mapbox/cheap_ruler.hpp> +#include <mbgl/gfx/backend_scope.hpp> +#include <mbgl/gfx/renderer_backend.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/renderable_resource.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/platform/gl_functions.hpp> +#include <mbgl/renderer/bucket.hpp> +#include <mbgl/renderer/layers/render_location_component_layer.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/style/layers/location_component_layer.hpp> +#include <mbgl/style/layers/location_component_layer_impl.hpp> +#include <mbgl/style/layers/location_component_layer_properties.hpp> +#include <mbgl/util/mat4.hpp> + +#include <mapbox/eternal.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/defines.hpp> +#include <mbgl/gl/texture.hpp> +#include <mbgl/gl/texture_resource.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/platform/gl_functions.hpp> +#include <mbgl/renderer/image_manager.hpp> + +using namespace mbgl::platform; +namespace mbgl { + +struct LocationComponentRenderParameters { + LocationComponentRenderParameters() = default; + explicit LocationComponentRenderParameters(const TransformParameters& tp) : state(&tp.state) {} + LocationComponentRenderParameters(const LocationComponentRenderParameters& o) = default; + LocationComponentRenderParameters& operator=(const LocationComponentRenderParameters& o) = default; + + double width; + double height; + double latitude; + double longitude; + double zoom; + double bearing; + double pitch; + double fieldOfView; + std::array<double, 16> projectionMatrix; + const TransformState* state = nullptr; + ImageManager* imageManager = nullptr; + // some testing defaults, for before it gets updated via props + double puckBearing = 0.0; + LatLng puckPosition = {0, 0}; + double errorRadiusMeters; + mbgl::Color errorRadiusColor{0, 0, 0, 0}; + mbgl::Color errorRadiusBorderColor{0, 0, 0, 0}; + int puckSizePx = 0; + int puckHatSizePx = 0; + int puckShadowSizePx = 0; + float puckLayersDisplacement = 0; + float perspectiveCompensation = 0; + std::string puckImagePath; + std::string puckShadowImagePath; + std::string puckHatImagePath; +}; + +class RenderLocationComponentImpl { +protected: + struct vec2 { + GLfloat x = 0.0f; + GLfloat y = 0.0f; + + vec2(GLfloat x_, GLfloat y_) : x(x_), y(y_) {} + vec2() = default; + explicit vec2(const Point<double>& p) : x(p.x), y(p.y) {} + vec2(const vec2& o) = default; + vec2(const vec2&& o) noexcept : x(o.x), y(o.y) {} + vec2& operator=(vec2&& o) noexcept { + x = o.x; + y = o.y; + return *this; + } + vec2& operator=(vec2& o) = default; + float length() const { return std::sqrt(x * x + y * y); } + vec2 normalized() const { + const float size = length(); + return vec2(x / size, y / size); + } + void normalize() { *this = normalized(); } + vec2 mirrored(const vec2& mirror) const { + float k = dot(mirror) / mirror.length(); + return 2.0 * k * mirror - (*this); + } + float dot(const vec2& v2) const { return x * v2.x + y * v2.y; } + vec2 rotated(float degrees) const { + const float cs = std::cos(degrees * util::DEG2RAD); + const float sn = std::sin(degrees * util::DEG2RAD); + return vec2{x * cs + y * sn, x * sn + y * cs}.normalized(); + } + float bearing() const { + const vec2 norm = normalized(); + + // From theta to bearing + return util::wrap<float>(M_PI_2 - std::atan2(-norm.y, norm.x), 0, M_PI * 2.0) * util::RAD2DEG; + } + Point<double> point() const { return {x, y}; } + + friend vec2 operator-(const vec2& v) { return vec2(-v.x, -v.y); } + friend vec2 operator*(double a, const vec2& v) { return vec2(v.x * a, v.y * a); } + friend vec2 operator+(const vec2& v1, const vec2& v2) { return vec2(v1.x + v2.x, v1.y + v2.y); } + friend vec2 operator-(const vec2& v1, const vec2& v2) { return vec2(v1.x - v2.x, v1.y - v2.y); } + }; + + struct Shader { + virtual ~Shader() { release(); } + void release() { + if (!program) return; + MBGL_CHECK_ERROR(glDetachShader(program, vertexShader)); + MBGL_CHECK_ERROR(glDetachShader(program, fragmentShader)); + MBGL_CHECK_ERROR(glDeleteShader(vertexShader)); + MBGL_CHECK_ERROR(glDeleteShader(fragmentShader)); + MBGL_CHECK_ERROR(glDeleteProgram(program)); + program = vertexShader = fragmentShader = 0; + } + void initialize(const GLchar* const& vsSource, const GLchar* const& fsSource) { + if (program) return; + program = MBGL_CHECK_ERROR(glCreateProgram()); + vertexShader = MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)); + fragmentShader = MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)); + MBGL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vsSource, nullptr)); + MBGL_CHECK_ERROR(glCompileShader(vertexShader)); + MBGL_CHECK_ERROR(glAttachShader(program, vertexShader)); + MBGL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fsSource, nullptr)); + MBGL_CHECK_ERROR(glCompileShader(fragmentShader)); + MBGL_CHECK_ERROR(glAttachShader(program, fragmentShader)); + MBGL_CHECK_ERROR(glLinkProgram(program)); + pullLocations(); + } + virtual void bind() { MBGL_CHECK_ERROR(glUseProgram(program)); } + void detach() { MBGL_CHECK_ERROR(glUseProgram(0)); } + virtual void pullLocations(){}; + + GLuint program = 0; + GLuint vertexShader = 0; + GLuint fragmentShader = 0; + }; + + struct SimpleShader : public Shader { + // Note that custom layers need to draw geometry with a z value of 1 to take advantage of + // depth-based fragment culling. + const GLchar* vertexShaderSource = R"MBGL_SHADER( +attribute vec2 a_pos; +uniform mat4 u_matrix; +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); +// gl_Position = vec4(a_pos, 0, 1); +} +)MBGL_SHADER"; + + const GLchar* fragmentShaderSource = R"MBGL_SHADER( +uniform vec4 u_color; +void main() { + gl_FragColor = u_color; +} +)MBGL_SHADER"; + + void initialize() { Shader::initialize(SimpleShader::vertexShaderSource, SimpleShader::fragmentShaderSource); } + + void pullLocations() override { + a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); + u_color = MBGL_CHECK_ERROR(glGetUniformLocation(program, "u_color")); + u_matrix = MBGL_CHECK_ERROR(glGetUniformLocation(program, "u_matrix")); + } + void bind() override { + SimpleShader::initialize(); + Shader::bind(); + } + + GLuint a_pos = 0; + GLuint u_color = 0; + GLuint u_matrix = 0; + }; + + struct TexturedShader : public Shader { + const GLchar* vertexShaderSource = R"MBGL_SHADER( +#ifdef GL_ES +precision highp float; +#endif + +attribute vec2 a_pos; +attribute vec2 a_texCoord; +uniform mat4 u_matrix; +varying vec2 v_texCoord; +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); + v_texCoord = a_texCoord; +} +)MBGL_SHADER"; + + const GLchar* fragmentShaderSource = R"MBGL_SHADER( +#ifdef GL_ES +precision mediump float; +#endif + +uniform sampler2D u_image; +varying vec2 v_texCoord; +void main() { + vec4 color = texture2D(u_image, v_texCoord); + gl_FragColor = color; +} +)MBGL_SHADER"; + + void initialize() { Shader::initialize(vertexShaderSource, fragmentShaderSource); } + + void pullLocations() override { + a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); + a_texCoord = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_texCoord")); + u_image = MBGL_CHECK_ERROR(glGetUniformLocation(program, "u_image")); + u_matrix = MBGL_CHECK_ERROR(glGetUniformLocation(program, "u_matrix")); + } + void bind() override { + TexturedShader::initialize(); + Shader::bind(); + } + + GLuint a_pos = 0; + GLuint a_texCoord = 0; + GLuint u_image = 0; + GLuint u_matrix = 0; + }; + + struct Buffer { + virtual ~Buffer() { release(); } + void release() { + if (!bufferId) return; + MBGL_CHECK_ERROR(glDeleteBuffers(1, &bufferId)); + bufferId = 0; + } + void initialize() { + if (!bufferId) MBGL_CHECK_ERROR(glGenBuffers(1, &bufferId)); + } + void bind(const GLenum target = GL_ARRAY_BUFFER) { + initialize(); + MBGL_CHECK_ERROR(glBindBuffer(target, bufferId)); + } + void detach(const GLenum target = GL_ARRAY_BUFFER) { MBGL_CHECK_ERROR(glBindBuffer(target, 0)); } + template <typename T, std::size_t N> + void upload(const std::array<T, N>& data) { + bind(); + MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, N * sizeof(T), data.data(), GL_STATIC_DRAW)); + size = static_cast<unsigned int>(N * sizeof(T)); + elements = N; + } + template <typename T> + void upload(const std::vector<T>& data) { + bind(); + MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(T), data.data(), GL_STATIC_DRAW)); + size = data.size() * sizeof(T); + elements = data.size(); + } + + GLuint bufferId = 0; + unsigned int size = 0; + unsigned int elements = 0; + }; + +public: + struct Texture { + ~Texture() { release(); } + void release() { + MBGL_CHECK_ERROR(glDeleteTextures(1, &texId)); + texId = 0; + image = nullptr; + } + /* + Assign can be called any time. Conversely, upload must be called with a bound gl context. + */ + void assign(const Immutable<style::Image::Impl>* img) { + if ((img && &img->get()->image == image) || (!img && !image)) return; + imageDirty = true; + image = (img) ? &img->get()->image : nullptr; + if (img) + sharedImage = *img; // keep reference until uploaded + else + sharedImage = nullopt; + } + + void upload() { + if (!imageDirty) return; + imageDirty = false; + initialize(); + + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texId)); + if (!image || !image->valid()) { + MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + } else { + MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + image->size.width, + image->size.height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + image->data.get())); + MBGL_CHECK_ERROR(glGenerateMipmap(GL_TEXTURE_2D)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + if (RenderLocationComponentImpl::anisotropicFilteringAvailable) + MBGL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16)); + } + detach(); + sharedImage = nullopt; + } + void initialize() { + if (texId != 0) return; + MBGL_CHECK_ERROR(glGenTextures(1, &texId)); + } + void bind(int textureUnit = -1) { + initialize(); + if (!image && !imageDirty) return; + + upload(); + if (textureUnit >= 0) MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0 + textureUnit)); + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texId)); + } + void detach() { MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, 0)); } + bool isValid() { return imageDirty || image; } + GLuint texId = 0; + const mbgl::PremultipliedImage* image = nullptr; + optional<Immutable<style::Image::Impl>> sharedImage; + bool imageDirty = false; + }; + + RenderLocationComponentImpl() : ruler(0, mapbox::cheap_ruler::CheapRuler::Meters) {} + + static bool hasExtension(const std::string& ext) { + if (const auto* extensions = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { + if (strstr(extensions, ext.c_str()) != nullptr) return true; + } + return false; + } + void initialize() { + // Check if anisotropic filtering is available + if (initialized) return; + initialized = true; + if (hasExtension("GL_EXT_texture_filter_anisotropic")) anisotropicFilteringAvailable = true; + simpleShader.initialize(); + texturedShader.initialize(); + texCoords = {{{0.0f, 1.0f}, + {0.0f, 0.0f}, + {1.0f, 0.0f}, + {1.0f, 1.0f}}}; // Quads will be drawn as triangle fans. so bl, tl, tr, br + texCoordsBuffer.upload(texCoords); + } + + void render(const mbgl::LocationComponentRenderParameters& params) { + initialize(); + drawRadius(params); + drawShadow(); + drawPuck(); + drawHat(); + } + + void deinitialize() { + if (!simpleShader.program) return; + textures.clear(); + buffer.release(); + circleBuffer.release(); + puckBuffer.release(); + hatBuffer.release(); + texCoordsBuffer.release(); + simpleShader.release(); + texturedShader.release(); + } + + void updatePuckGeometry(const mbgl::LocationComponentRenderParameters& params) { + if (params.projectionMatrix != oldParams.projectionMatrix) positionChanged = true; + if (params.puckPosition != oldParams.puckPosition) { + positionChanged = true; + ruler = mapbox::cheap_ruler::CheapRuler(params.puckPosition.latitude(), + mapbox::cheap_ruler::CheapRuler::Meters); + } + if (params.puckBearing != oldParams.puckBearing) bearingChanged = true; + if (params.errorRadiusMeters != oldParams.errorRadiusMeters) radiusChanged = true; + if (params.puckImagePath != oldParams.puckImagePath) + setTextureFromImageID(params.puckImagePath, texPuck, params); + if (params.puckShadowImagePath != oldParams.puckShadowImagePath) + setTextureFromImageID(params.puckShadowImagePath, texShadow, params); + if (params.puckHatImagePath != oldParams.puckHatImagePath) + setTextureFromImageID(params.puckHatImagePath, texPuckHat, params); + + projectionCircle = params.projectionMatrix; + const Point<double> positionMercator = project(params.puckPosition, *params.state); + mat4 translation; + matrix::identity(translation); + matrix::translate(translation, translation, positionMercator.x, positionMercator.y, 0.0); + matrix::multiply(projectionCircle, projectionCircle, translation); + + if (positionChanged) { + updateRadius(params); + updatePuck(params); + positionChanged = false; + } else { + if (radiusChanged) { + updateRadius(params); + } + if (bearingChanged) { + updatePuck(params); + } + } + oldParams = params; + } + +protected: + static ScreenCoordinate latLngToScreenCoordinate(const LatLng& p, const TransformState& s) { + LatLng unwrappedLatLng = p.wrapped(); + unwrappedLatLng.unwrapForShortestPath(s.getLatLng(LatLng::Wrapped)); + ScreenCoordinate point = s.latLngToScreenCoordinate(unwrappedLatLng); + point.y = s.getSize().height - point.y; + return point; + } + + static Point<double> project(const LatLng& c, const TransformState& s) { + LatLng unwrappedLatLng = c.wrapped(); + unwrappedLatLng.unwrapForShortestPath(s.getLatLng(LatLng::Wrapped)); + return Projection::project(unwrappedLatLng, s.getScale()); + } + + static Point<double> unproject(const LatLng& c, const TransformState& s) { + LatLng unwrappedLatLng = c.wrapped(); + unwrappedLatLng.unwrapForShortestPath(s.getLatLng(LatLng::Wrapped)); + return Projection::project(unwrappedLatLng, s.getScale()); + } + + static void toMercator(mat4& mbgl_proj, const double zoom, const double latitude) { + // Scale by worldSize so that the values in the input coodinate system are between 0 and 1. + const double worldSize = std::pow(2, zoom) * 512; + for (size_t i = 0; i < 12; i++) { + mbgl_proj.at(i) *= worldSize; + } + + // Undo the z scaling done in GL native that makes z coordinates match altitude in meters. This makes the + // projection conformant, i.e., a cube in the input coordinate system is a cube in the output. + double zScale = mbgl::Projection::getMetersPerPixelAtLatitude(latitude, zoom); + for (size_t i = 8; i < 12; i++) { + mbgl_proj.at(i) *= zScale; + } + } + + void updateRadius(const mbgl::LocationComponentRenderParameters& params) { + const TransformState& s = *params.state; + const unsigned long numVtxCircumference = circle.size() - 1; + const float bearingStep = 360.0f / float(numVtxCircumference - 1); // first and last points are the same + const mapbox::cheap_ruler::point centerPoint(params.puckPosition.longitude(), params.puckPosition.latitude()); + Point<double> center = project(params.puckPosition, s); + circle[0] = {0, 0}; + + double mapBearing = util::wrap(util::RAD2DEG * params.bearing, 0.0, util::DEGREES_MAX); + for (unsigned long i = 1; i <= numVtxCircumference; ++i) { + const float bearing_ = float(i - 1) * bearingStep - mapBearing; + Point<double> poc = ruler.destination(centerPoint, params.errorRadiusMeters, bearing_); + circle[i] = vec2(project(LatLng(poc.y, poc.x), s) - center); + } + radiusChanged = false; + } + + // Size in "map pixels" for a screen pixel + static float pixelSizeToWorldSizeH(const LatLng& pos, const TransformState& s) { + ; + ScreenCoordinate posScreen = latLngToScreenCoordinate(pos, s); + ScreenCoordinate posScreenLeftPx = posScreen; + posScreenLeftPx.x -= 1; + LatLng posLeftPx = screenCoordinateToLatLng(posScreenLeftPx, s); + Point<double> posMerc = project(pos, s); + Point<double> posLeftPxMerc = project(posLeftPx, s); + return vec2(posMerc - posLeftPxMerc).length(); + } + + static vec2 verticalDirectionMercator(const LatLng& pos, const TransformState& s) { + ScreenCoordinate posScreen = latLngToScreenCoordinate(pos, s); + Point<double> posMerc = project(pos, s); + return verticalDirectionMercator(posScreen, posMerc, s); + } + + static vec2 verticalDirectionMercator(const ScreenCoordinate& pos, Point<double> posMerc, const TransformState& s) { + ScreenCoordinate screenDy = pos; + screenDy.y -= 1; + LatLng posDy = screenCoordinateToLatLng(screenDy, s); + Point<double> posMercDy = project(posDy, s); + return verticalDirectionMercator(posMerc, posMercDy); + } + + static vec2 verticalDirectionMercator(const Point<double>& posMerc, const Point<double>& posMercDy) { + Point<double> verticalShiftMercator = posMercDy - posMerc; + vec2 res(verticalShiftMercator); + return res.normalized(); + } + + static Point<double> hatShadowShiftVector(const LatLng& position, + const mbgl::LocationComponentRenderParameters& params) { + const TransformState& s = *params.state; + ScreenCoordinate posScreen = latLngToScreenCoordinate(position, s); + posScreen.y = params.height - 1; // moving it to bottom + Point<double> posMerc = project(screenCoordinateToLatLng(posScreen, s), s); + vec2 verticalShiftAtPos = verticalDirectionMercator(posScreen, posMerc, s); + return Point<double>(verticalShiftAtPos.x, verticalShiftAtPos.y); + } + + static vec2 directionAtPositionScreen(const LatLng& position, float bearing, const TransformState& s) { + const double scale = s.getScale(); + const vec2 rot = vec2(0.0, -1.0).rotated(-bearing); + Point<double> posMerc = project(position, s); + Point<double> posMercDelta = posMerc + rot.point(); + ScreenCoordinate posScreen = latLngToScreenCoordinate(position, s); + ScreenCoordinate posScreenDelta = latLngToScreenCoordinate(Projection::unproject(posMercDelta, scale), s); + return vec2(posScreenDelta - posScreen).normalized(); + } + + void updatePuck(const mbgl::LocationComponentRenderParameters& params) { return updatePuckPerspective(params); } + + void updatePuckPerspective(const mbgl::LocationComponentRenderParameters& params) { + const TransformState& s = *params.state; + projectionPuck = projectionCircle; // Duplicated as it might change, depending on what puck style is chosen. + const mapbox::cheap_ruler::point centerPoint(params.puckPosition.longitude(), params.puckPosition.latitude()); + static constexpr float bearings[]{ + 225.0f, 315.0f, 45.0f, 135.0f}; // Quads will be drawn as triangle fans. so bl, tl, tr, br +#ifndef M_SQRT2 + static constexpr const float M_SQRT2 = std::sqrt(2.0f); +#endif + // The puck has to stay square at all zoom levels. CheapRuler::destination does not guarantee this at low zoom + // levels, so the extent has to be produced in mercator space + const double tilt = s.getPitch(); + + // Point<double> verticalShiftAtCenter { float(std::sin(util::DEG2RAD * util::wrap<float>(-t.getBearing() * + // util::RAD2DEG, 0.0f, 360.0f) )), + // -float(std::cos(util::DEG2RAD * util::wrap<float>(-t.getBearing() * + // util::RAD2DEG, 0.0f, 360.0f))) }; + // would be correct only in the vertical center of the map. As soon as position goes away from that line, + // the shift direction is skewed by the perspective projection. + // So the way to have a shift aligned to the screen vertical axis is to find this direction in screen space, and + // convert it back to map space. This would yield an always straight up shift. However, going further (= the + // opposite direction of where the lines are converging in the projection) might produce an even more realistic + // effect. But in this case, it empirically seems that the largest shift that look acceptable is what is + // obtained at the bottom of the window, avoiding the wider converging lines that pass by the edge of the screen + // going toward the top. + + Point<double> verticalShift = hatShadowShiftVector(params.puckPosition, params); + const float horizontalScaleFactor = + (1.0f - params.perspectiveCompensation) + + util::clamp(pixelSizeToWorldSizeH(params.puckPosition, s), 0.8f, 100.1f) * + params.perspectiveCompensation; // Compensation factor for the perspective deformation + // ^ clamping this to 0.8 to avoid growing the puck too much close to the camera. + const double shadowRadius = + params.puckShadowSizePx * M_SQRT2 * 0.5 * + horizontalScaleFactor; // Technically it's not the radius, but the half diagonal of the quad. + const double puckRadius = params.puckSizePx * M_SQRT2 * 0.5 * horizontalScaleFactor; + const double hatRadius = params.puckHatSizePx * M_SQRT2 * 0.5 * horizontalScaleFactor; + + for (unsigned long i = 0; i < 4; ++i) { + const float b = util::wrap<float>(params.puckBearing + bearings[i], 0.0f, 360.0f); + + const Point<double> cornerDirection{float(std::sin(util::DEG2RAD * b)), + -float(std::cos(util::DEG2RAD * b))}; + + Point<double> shadowOffset = cornerDirection * shadowRadius; + Point<double> puckOffset = cornerDirection * puckRadius; + Point<double> hatOffset = cornerDirection * hatRadius; + + shadowGeometry[i] = + vec2(shadowOffset + (verticalShift * (tilt * -params.puckLayersDisplacement * horizontalScaleFactor))); + puckGeometry[i] = vec2(puckOffset); + hatGeometry[i] = + vec2(hatOffset + (verticalShift * (tilt * params.puckLayersDisplacement * horizontalScaleFactor))); + } + + bearingChanged = false; + } + + void drawRadius(const mbgl::LocationComponentRenderParameters& params) { + if (!(params.errorRadiusMeters > 0.0) || + (params.errorRadiusColor.a == 0.0 && params.errorRadiusBorderColor.a == 0.0)) + return; + + simpleShader.bind(); + mbgl::gl::bindUniform(simpleShader.u_color, params.errorRadiusColor); + mbgl::gl::bindUniform(simpleShader.u_matrix, projectionCircle); + + circleBuffer.upload(circle); + MBGL_CHECK_ERROR(glEnableVertexAttribArray(simpleShader.a_pos)); + MBGL_CHECK_ERROR(glVertexAttribPointer(simpleShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); + + MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_FAN, 0, circle.size())); + if (params.errorRadiusBorderColor.a > 0.0f) { + mbgl::gl::bindUniform(simpleShader.u_color, params.errorRadiusBorderColor); + MBGL_CHECK_ERROR(glDrawArrays(GL_LINE_STRIP, 1, circle.size() - 1)); // line width: 1 by default; + } + MBGL_CHECK_ERROR(glDisableVertexAttribArray(simpleShader.a_pos)); + circleBuffer.detach(); + simpleShader.detach(); + } + + void drawQuad(Buffer& buf, std::array<vec2, 4>& data, std::shared_ptr<Texture>& texture) { + if (!texture || !texture->isValid()) return; + texturedShader.bind(); + texture->bind(0); + glUniform1i(texturedShader.u_image, 0); + mbgl::gl::bindUniform(texturedShader.u_matrix, projectionPuck); + + buf.bind(); + buf.upload(data); + MBGL_CHECK_ERROR(glEnableVertexAttribArray(texturedShader.a_pos)); + MBGL_CHECK_ERROR(glVertexAttribPointer(texturedShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); + + texCoordsBuffer.bind(); + MBGL_CHECK_ERROR(glEnableVertexAttribArray(texturedShader.a_texCoord)); + MBGL_CHECK_ERROR(glVertexAttribPointer(texturedShader.a_texCoord, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); + + MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_FAN, 0, 4)); + texture->detach(); + texCoordsBuffer.detach(); + texturedShader.detach(); + } + + void drawShadow() { drawQuad(shadowBuffer, shadowGeometry, texShadow); } + + void drawPuck() { drawQuad(puckBuffer, puckGeometry, texPuck); } + + void drawHat() { drawQuad(hatBuffer, hatGeometry, texPuckHat); } + + static LatLng screenCoordinateToLatLng(const ScreenCoordinate& p, + const TransformState& s, + LatLng::WrapMode wrapMode = LatLng::Wrapped) { + ScreenCoordinate flippedPoint = p; + flippedPoint.y = s.getSize().height - flippedPoint.y; + return s.screenCoordinateToLatLng(flippedPoint, wrapMode); + } + + void setTextureFromImageID(const std::string& imagePath, + std::shared_ptr<Texture>& tex, + const mbgl::LocationComponentRenderParameters& params) { + if (textures.find(imagePath) == textures.end()) { + std::shared_ptr<Texture> tx = std::make_shared<Texture>(); + if (!imagePath.empty() && params.imageManager) + tx->assign(params.imageManager->getSharedImage(imagePath)); + else + tx->assign(nullptr); + textures[imagePath] = tx; + } + tex = textures.at(imagePath); + } + + std::map<std::string, std::shared_ptr<Texture>> textures; + mapbox::cheap_ruler::CheapRuler ruler; + SimpleShader simpleShader; + TexturedShader texturedShader; + Buffer buffer; + Buffer circleBuffer; + Buffer shadowBuffer; + Buffer puckBuffer; + Buffer hatBuffer; + Buffer texCoordsBuffer; + std::shared_ptr<Texture> texShadow; + std::shared_ptr<Texture> texPuck; + std::shared_ptr<Texture> texPuckHat; + + std::array<vec2, 73> circle; // 72 points + position + std::array<vec2, 4> shadowGeometry; + std::array<vec2, 4> puckGeometry; + std::array<vec2, 4> hatGeometry; + std::array<vec2, 4> texCoords; + mbgl::mat4 projectionCircle; + mbgl::mat4 projectionPuck; + + bool positionChanged = false; + bool radiusChanged = false; + bool bearingChanged = false; + mbgl::LocationComponentRenderParameters oldParams; + bool initialized = false; + +public: + mbgl::LocationComponentRenderParameters parameters; + static bool anisotropicFilteringAvailable; +}; + +bool RenderLocationComponentImpl::anisotropicFilteringAvailable = false; + +using namespace style; +namespace { + +inline const LocationComponentLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { + assert(impl->getTypeInfo() == LocationComponentLayer::Impl::staticTypeInfo()); + return static_cast<const LocationComponentLayer::Impl&>(*impl); +} +} // namespace + +RenderLocationComponentLayer::RenderLocationComponentLayer(Immutable<style::LocationComponentLayer::Impl> _impl) + : RenderLayer(makeMutable<LocationComponentLayerProperties>(std::move(_impl))), + renderImpl(new RenderLocationComponentImpl()), + unevaluated(impl(baseImpl).paint.untransitioned()) { + assert(gfx::BackendScope::exists()); +} + +RenderLocationComponentLayer::~RenderLocationComponentLayer() { + assert(gfx::BackendScope::exists()); + if (!contextDestroyed) MBGL_CHECK_ERROR(renderImpl->deinitialize()); +} + +void RenderLocationComponentLayer::transition(const TransitionParameters& parameters) { + unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); +} + +void RenderLocationComponentLayer::evaluate(const PropertyEvaluationParameters& parameters) { + passes = RenderPass::Translucent; + auto properties = makeMutable<LocationComponentLayerProperties>( + staticImmutableCast<LocationComponentLayer::Impl>(baseImpl), unevaluated.evaluate(parameters)); + const auto& evaluated = properties->evaluated; + auto& layout = impl(baseImpl).layout; + + properties->renderPasses = mbgl::underlying_type(passes); + + // paint + renderImpl->parameters.errorRadiusColor = evaluated.get<style::AccuracyRadiusColor>(); + renderImpl->parameters.errorRadiusBorderColor = evaluated.get<style::AccuracyRadiusBorderColor>(); + + // layout + if (!layout.get<style::Bearing>().isUndefined()) + renderImpl->parameters.puckBearing = layout.get<style::Bearing>().asConstant(); + if (!layout.get<style::AccuracyRadius>().isUndefined()) + renderImpl->parameters.errorRadiusMeters = layout.get<style::AccuracyRadius>().asConstant(); + if (!layout.get<style::BearingImageSize>().isUndefined()) + renderImpl->parameters.puckSizePx = layout.get<style::BearingImageSize>().asConstant(); + if (!layout.get<style::TopImageSize>().isUndefined()) + renderImpl->parameters.puckHatSizePx = layout.get<style::TopImageSize>().asConstant(); + if (!layout.get<style::ShadowImageSize>().isUndefined()) + renderImpl->parameters.puckShadowSizePx = layout.get<style::ShadowImageSize>().asConstant(); + if (!layout.get<style::ImageTiltDisplacement>().isUndefined()) + renderImpl->parameters.puckLayersDisplacement = layout.get<style::ImageTiltDisplacement>().asConstant(); + if (!layout.get<style::PerspectiveCompensation>().isUndefined()) + renderImpl->parameters.perspectiveCompensation = layout.get<style::PerspectiveCompensation>().asConstant(); + + if (!layout.get<style::Location>().isUndefined()) { + const std::array<double, 3> pos = layout.get<style::Location>().asConstant(); + renderImpl->parameters.puckPosition = LatLng{pos[0], pos[1]}; + } + if (!layout.get<style::BearingImage>().isUndefined()) + renderImpl->parameters.puckImagePath = layout.get<style::BearingImage>().asConstant().id(); + if (!layout.get<style::ShadowImage>().isUndefined()) + renderImpl->parameters.puckShadowImagePath = layout.get<style::ShadowImage>().asConstant().id(); + if (!layout.get<style::TopImage>().isUndefined()) + renderImpl->parameters.puckHatImagePath = layout.get<style::TopImage>().asConstant().id(); + + evaluatedProperties = std::move(properties); +} + +bool RenderLocationComponentLayer::hasTransition() const { + return unevaluated.hasTransition(); +} +bool RenderLocationComponentLayer::hasCrossfade() const { + return false; +} + +void RenderLocationComponentLayer::markContextDestroyed() { + contextDestroyed = true; +} + +void RenderLocationComponentLayer::prepare(const LayerPrepareParameters& p) { + renderImpl->parameters.imageManager = &p.imageManager; + const TransformState& state = p.state; + renderImpl->parameters.state = &state; + + renderImpl->parameters.width = state.getSize().width; + renderImpl->parameters.height = state.getSize().height; + renderImpl->parameters.latitude = state.getLatLng().latitude(); + renderImpl->parameters.longitude = state.getLatLng().longitude(); + renderImpl->parameters.zoom = state.getZoom(); + renderImpl->parameters.bearing = -state.getBearing() * util::RAD2DEG; + renderImpl->parameters.pitch = state.getPitch(); + renderImpl->parameters.fieldOfView = state.getFieldOfView(); + mat4 projMatrix; + state.getProjMatrix(projMatrix); + renderImpl->parameters.projectionMatrix = projMatrix; + + renderImpl->updatePuckGeometry(renderImpl->parameters); +} + +void RenderLocationComponentLayer::render(PaintParameters& paintParameters) { + auto& glContext = static_cast<gl::Context&>(paintParameters.context); + + // Reset GL state to a known state so the CustomLayer always has a clean slate. + glContext.bindVertexArray = 0; + glContext.setDepthMode(paintParameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly)); + glContext.setStencilMode(gfx::StencilMode::disabled()); + glContext.setColorMode(paintParameters.colorModeForRenderPass()); // this is gfx::ColorMode::alphaBlended() + glContext.setCullFaceMode(gfx::CullFaceMode::disabled()); + + MBGL_CHECK_ERROR(renderImpl->render(renderImpl->parameters)); + + // Reset the view back to our original one, just in case the CustomLayer changed + // the viewport or Framebuffer. + paintParameters.backend.getDefaultRenderable().getResource<gl::RenderableResource>().bind(); + glContext.setDirtyState(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_location_component_layer.hpp b/src/mbgl/renderer/layers/render_location_component_layer.hpp new file mode 100644 index 0000000000..1a5683231e --- /dev/null +++ b/src/mbgl/renderer/layers/render_location_component_layer.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include <mbgl/renderer/render_layer.hpp> +#include <mbgl/style/layers/location_component_layer.hpp> +#include <mbgl/style/layers/location_component_layer_impl.hpp> +#include <mbgl/style/layers/location_component_layer_properties.hpp> + +namespace mbgl { +class RenderLocationComponentImpl; +class RenderLocationComponentLayer final : public RenderLayer { +public: + explicit RenderLocationComponentLayer(Immutable<style::LocationComponentLayer::Impl>); + ~RenderLocationComponentLayer() override; + +private: + void transition(const TransitionParameters &) override; + void evaluate(const PropertyEvaluationParameters &) override; + bool hasTransition() const override; + bool hasCrossfade() const override; + void markContextDestroyed() override; + void prepare(const LayerPrepareParameters &) override; + + void render(PaintParameters &) override; + + bool contextDestroyed = false; + RenderLocationComponentImpl *renderImpl = nullptr; + style::LocationComponentPaintProperties::Unevaluated unevaluated; +}; + +} // namespace mbgl diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index ffdb17858d..0e4e29f689 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -127,6 +127,28 @@ template optional<std::array<float, 2>> Converter<std::array<float, 2>>::operato template optional<std::array<float, 3>> Converter<std::array<float, 3>>::operator()(const Convertible&, Error&) const; template optional<std::array<float, 4>> Converter<std::array<float, 4>>::operator()(const Convertible&, Error&) const; +template <size_t N> +optional<std::array<double, N>> Converter<std::array<double, N>>::operator()(const Convertible& value, + Error& error) const { + if (!isArray(value) || arrayLength(value) != N) { + error.message = "value must be an array of " + util::toString(N) + " numbers"; + return nullopt; + } + + std::array<double, N> result; + for (size_t i = 0; i < N; i++) { + optional<double> n = toDouble(arrayMember(value, i)); + if (!n) { + error.message = "value must be an array of " + util::toString(N) + " numbers"; + return nullopt; + } + result[i] = *n; + } + return result; +} + +template optional<std::array<double, 3>> Converter<std::array<double, 3>>::operator()(const Convertible&, Error&) const; + optional<std::vector<float>> Converter<std::vector<float>>::operator()(const Convertible& value, Error& error) const { if (!isArray(value)) { error.message = "value must be an array"; diff --git a/src/mbgl/style/conversion/property_value.cpp b/src/mbgl/style/conversion/property_value.cpp index 5e03189e64..1a0e686850 100644 --- a/src/mbgl/style/conversion/property_value.cpp +++ b/src/mbgl/style/conversion/property_value.cpp @@ -88,6 +88,25 @@ Converter<PropertyValue<mbgl::style::expression::Image>>::operator()(conversion: bool, bool) const; +optional<PropertyValue<std::array<double, 3>>> +mbgl::style::conversion::Converter<PropertyValue<std::array<double, 3>>, void>::operator()(const Convertible& value, + Error& error, + bool, + bool) const { + optional<std::array<double, 3>> a = convert<std::array<double, 3>>(value, error); + + if (!a) { + return nullopt; + } + std::array<double, 3> res; + res[0] = (*a)[0]; + res[1] = (*a)[1]; + res[2] = (*a)[2]; + + PropertyValue<std::array<double, 3>> r(res); + return r; +} + } // namespace conversion } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index 3816182450..d7908153f4 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -77,6 +77,15 @@ void stringify(Writer& writer, const std::array<float, 4>& v) { } template <class Writer> +void stringify(Writer& writer, const std::array<double, 3>& v) { + writer.StartArray(); + writer.Double(v[0]); + writer.Double(v[1]); + writer.Double(v[2]); + writer.EndArray(); +} + +template <class Writer> void stringify(Writer&, const Value&); template <class Writer, class T> diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index ab44a92784..397e85b51e 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -8,8 +8,8 @@ // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. -#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> -#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp> +#include <mbgl/style/layers/<%- type.replace(/-/g, '_') %>_layer.hpp> +#include <mbgl/style/layers/<%- type.replace(/-/g, '_') %>_layer_impl.hpp> #include <mbgl/style/layer_observer.hpp> #include <mbgl/style/conversion/color_ramp_property_value.hpp> #include <mbgl/style/conversion/constant.hpp> @@ -80,6 +80,7 @@ layerCapabilities['heatmap'] = defaults.require('Source') .set('TileKind', 'Geometry') .finalize(); layerCapabilities['raster'] = defaults.require('Source').set('TileKind', 'Raster').finalize(); +layerCapabilities['location-component'] = defaults.finalize(); // Splits lines that are over 120 characters at the firts occurance of '='. const split120Line = line => { @@ -99,7 +100,7 @@ const LayerTypeInfo* <%- camelize(type) %>Layer::Impl::staticTypeInfo() noexcept } -<% if (type === 'background') { -%> +<% if ((type === 'background') || (type === 'location-component')) { -%> <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(const std::string& layerID) : Layer(makeMutable<Impl>(layerID, std::string())) { } diff --git a/src/mbgl/style/layers/layer_properties.cpp.ejs b/src/mbgl/style/layers/layer_properties.cpp.ejs index 18b07efea8..09f4c48373 100644 --- a/src/mbgl/style/layers/layer_properties.cpp.ejs +++ b/src/mbgl/style/layers/layer_properties.cpp.ejs @@ -7,9 +7,9 @@ // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. -#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_properties.hpp> +#include <mbgl/style/layers/<%- type.replace(/-/g, '_') %>_layer_properties.hpp> -#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp> +#include <mbgl/style/layers/<%- type.replace(/-/g, '_') %>_layer_impl.hpp> namespace mbgl { namespace style { diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index af67f14b90..66cff8c3c0 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -11,7 +11,7 @@ #include <mbgl/style/types.hpp> #include <mbgl/style/layer_properties.hpp> -#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> +#include <mbgl/style/layers/<%- type.replace(/-/g, '_') %>_layer.hpp> #include <mbgl/style/layout_property.hpp> #include <mbgl/style/paint_property.hpp> #include <mbgl/style/properties.hpp> diff --git a/src/mbgl/style/layers/location_component_layer.cpp b/src/mbgl/style/layers/location_component_layer.cpp new file mode 100644 index 0000000000..b9cb20db14 --- /dev/null +++ b/src/mbgl/style/layers/location_component_layer.cpp @@ -0,0 +1,522 @@ +// clang-format off + +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/location_component_layer.hpp> +#include <mbgl/style/layers/location_component_layer_impl.hpp> +#include <mbgl/style/layer_observer.hpp> +#include <mbgl/style/conversion/color_ramp_property_value.hpp> +#include <mbgl/style/conversion/constant.hpp> +#include <mbgl/style/conversion/property_value.hpp> +#include <mbgl/style/conversion/transition_options.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion_impl.hpp> +#include <mbgl/util/traits.hpp> + +#include <mapbox/eternal.hpp> + +namespace mbgl { +namespace style { + + +// static +const LayerTypeInfo* LocationComponentLayer::Impl::staticTypeInfo() noexcept { + const static LayerTypeInfo typeInfo{"location-component", + LayerTypeInfo::Source::NotRequired, + LayerTypeInfo::Pass3D::NotRequired, + LayerTypeInfo::Layout::NotRequired, + LayerTypeInfo::FadingTiles::NotRequired, + LayerTypeInfo::CrossTileIndex::NotRequired, + LayerTypeInfo::TileKind::NotRequired}; + return &typeInfo; +} + + +LocationComponentLayer::LocationComponentLayer(const std::string& layerID) + : Layer(makeMutable<Impl>(layerID, std::string())) { +} + +LocationComponentLayer::LocationComponentLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { +} + +LocationComponentLayer::~LocationComponentLayer() = default; + +const LocationComponentLayer::Impl& LocationComponentLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +Mutable<LocationComponentLayer::Impl> LocationComponentLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> LocationComponentLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = LocationComponentPaintProperties::Transitionable(); + return std::make_unique<LocationComponentLayer>(std::move(impl_)); +} + +void LocationComponentLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const { + layout.stringify(writer); +} + +// Layout properties + +PropertyValue<float> LocationComponentLayer::getDefaultAccuracyRadius() { + return AccuracyRadius::defaultValue(); +} + +const PropertyValue<float>& LocationComponentLayer::getAccuracyRadius() const { + return impl().layout.get<AccuracyRadius>(); +} + +void LocationComponentLayer::setAccuracyRadius(const PropertyValue<float>& value) { + if (value == getAccuracyRadius()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<AccuracyRadius>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<float> LocationComponentLayer::getDefaultBearing() { + return Bearing::defaultValue(); +} + +const PropertyValue<float>& LocationComponentLayer::getBearing() const { + return impl().layout.get<Bearing>(); +} + +void LocationComponentLayer::setBearing(const PropertyValue<float>& value) { + if (value == getBearing()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<Bearing>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<expression::Image> LocationComponentLayer::getDefaultBearingImage() { + return BearingImage::defaultValue(); +} + +const PropertyValue<expression::Image>& LocationComponentLayer::getBearingImage() const { + return impl().layout.get<BearingImage>(); +} + +void LocationComponentLayer::setBearingImage(const PropertyValue<expression::Image>& value) { + if (value == getBearingImage()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<BearingImage>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<float> LocationComponentLayer::getDefaultBearingImageSize() { + return BearingImageSize::defaultValue(); +} + +const PropertyValue<float>& LocationComponentLayer::getBearingImageSize() const { + return impl().layout.get<BearingImageSize>(); +} + +void LocationComponentLayer::setBearingImageSize(const PropertyValue<float>& value) { + if (value == getBearingImageSize()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<BearingImageSize>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<float> LocationComponentLayer::getDefaultImageTiltDisplacement() { + return ImageTiltDisplacement::defaultValue(); +} + +const PropertyValue<float>& LocationComponentLayer::getImageTiltDisplacement() const { + return impl().layout.get<ImageTiltDisplacement>(); +} + +void LocationComponentLayer::setImageTiltDisplacement(const PropertyValue<float>& value) { + if (value == getImageTiltDisplacement()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<ImageTiltDisplacement>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<std::array<double, 3>> LocationComponentLayer::getDefaultLocation() { + return Location::defaultValue(); +} + +const PropertyValue<std::array<double, 3>>& LocationComponentLayer::getLocation() const { + return impl().layout.get<Location>(); +} + +void LocationComponentLayer::setLocation(const PropertyValue<std::array<double, 3>>& value) { + if (value == getLocation()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<Location>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<float> LocationComponentLayer::getDefaultPerspectiveCompensation() { + return PerspectiveCompensation::defaultValue(); +} + +const PropertyValue<float>& LocationComponentLayer::getPerspectiveCompensation() const { + return impl().layout.get<PerspectiveCompensation>(); +} + +void LocationComponentLayer::setPerspectiveCompensation(const PropertyValue<float>& value) { + if (value == getPerspectiveCompensation()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<PerspectiveCompensation>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<expression::Image> LocationComponentLayer::getDefaultShadowImage() { + return ShadowImage::defaultValue(); +} + +const PropertyValue<expression::Image>& LocationComponentLayer::getShadowImage() const { + return impl().layout.get<ShadowImage>(); +} + +void LocationComponentLayer::setShadowImage(const PropertyValue<expression::Image>& value) { + if (value == getShadowImage()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<ShadowImage>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<float> LocationComponentLayer::getDefaultShadowImageSize() { + return ShadowImageSize::defaultValue(); +} + +const PropertyValue<float>& LocationComponentLayer::getShadowImageSize() const { + return impl().layout.get<ShadowImageSize>(); +} + +void LocationComponentLayer::setShadowImageSize(const PropertyValue<float>& value) { + if (value == getShadowImageSize()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<ShadowImageSize>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<expression::Image> LocationComponentLayer::getDefaultTopImage() { + return TopImage::defaultValue(); +} + +const PropertyValue<expression::Image>& LocationComponentLayer::getTopImage() const { + return impl().layout.get<TopImage>(); +} + +void LocationComponentLayer::setTopImage(const PropertyValue<expression::Image>& value) { + if (value == getTopImage()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<TopImage>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<float> LocationComponentLayer::getDefaultTopImageSize() { + return TopImageSize::defaultValue(); +} + +const PropertyValue<float>& LocationComponentLayer::getTopImageSize() const { + return impl().layout.get<TopImageSize>(); +} + +void LocationComponentLayer::setTopImageSize(const PropertyValue<float>& value) { + if (value == getTopImageSize()) return; + auto impl_ = mutableImpl(); + impl_->layout.get<TopImageSize>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Paint properties + +PropertyValue<Color> LocationComponentLayer::getDefaultAccuracyRadiusBorderColor() { + return {Color::white()}; +} + +const PropertyValue<Color>& LocationComponentLayer::getAccuracyRadiusBorderColor() const { + return impl().paint.template get<AccuracyRadiusBorderColor>().value; +} + +void LocationComponentLayer::setAccuracyRadiusBorderColor(const PropertyValue<Color>& value) { + if (value == getAccuracyRadiusBorderColor()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<AccuracyRadiusBorderColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void LocationComponentLayer::setAccuracyRadiusBorderColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<AccuracyRadiusBorderColor>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions LocationComponentLayer::getAccuracyRadiusBorderColorTransition() const { + return impl().paint.template get<AccuracyRadiusBorderColor>().options; +} + +PropertyValue<Color> LocationComponentLayer::getDefaultAccuracyRadiusColor() { + return {Color::white()}; +} + +const PropertyValue<Color>& LocationComponentLayer::getAccuracyRadiusColor() const { + return impl().paint.template get<AccuracyRadiusColor>().value; +} + +void LocationComponentLayer::setAccuracyRadiusColor(const PropertyValue<Color>& value) { + if (value == getAccuracyRadiusColor()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<AccuracyRadiusColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void LocationComponentLayer::setAccuracyRadiusColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<AccuracyRadiusColor>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions LocationComponentLayer::getAccuracyRadiusColorTransition() const { + return impl().paint.template get<AccuracyRadiusColor>().options; +} + +using namespace conversion; + +namespace { + +constexpr uint8_t kPaintPropertyCount = 4u; + +enum class Property : uint8_t { + AccuracyRadiusBorderColor, + AccuracyRadiusColor, + AccuracyRadiusBorderColorTransition, + AccuracyRadiusColorTransition, + AccuracyRadius = kPaintPropertyCount, + Bearing, + BearingImage, + BearingImageSize, + ImageTiltDisplacement, + Location, + PerspectiveCompensation, + ShadowImage, + ShadowImageSize, + TopImage, + TopImageSize, +}; + +template <typename T> +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<mapbox::eternal::string, uint8_t>( + {{"accuracy-radius-border-color", toUint8(Property::AccuracyRadiusBorderColor)}, + {"accuracy-radius-color", toUint8(Property::AccuracyRadiusColor)}, + {"accuracy-radius-border-color-transition", toUint8(Property::AccuracyRadiusBorderColorTransition)}, + {"accuracy-radius-color-transition", toUint8(Property::AccuracyRadiusColorTransition)}, + {"accuracy-radius", toUint8(Property::AccuracyRadius)}, + {"bearing", toUint8(Property::Bearing)}, + {"bearing-image", toUint8(Property::BearingImage)}, + {"bearing-image-size", toUint8(Property::BearingImageSize)}, + {"image-tilt-displacement", toUint8(Property::ImageTiltDisplacement)}, + {"location", toUint8(Property::Location)}, + {"perspective-compensation", toUint8(Property::PerspectiveCompensation)}, + {"shadow-image", toUint8(Property::ShadowImage)}, + {"shadow-image-size", toUint8(Property::ShadowImageSize)}, + {"top-image", toUint8(Property::TopImage)}, + {"top-image-size", toUint8(Property::TopImageSize)}}); + +StyleProperty getLayerProperty(const LocationComponentLayer& layer, Property property) { + switch (property) { + case Property::AccuracyRadiusBorderColor: + return makeStyleProperty(layer.getAccuracyRadiusBorderColor()); + case Property::AccuracyRadiusColor: + return makeStyleProperty(layer.getAccuracyRadiusColor()); + case Property::AccuracyRadiusBorderColorTransition: + return makeStyleProperty(layer.getAccuracyRadiusBorderColorTransition()); + case Property::AccuracyRadiusColorTransition: + return makeStyleProperty(layer.getAccuracyRadiusColorTransition()); + case Property::AccuracyRadius: + return makeStyleProperty(layer.getAccuracyRadius()); + case Property::Bearing: + return makeStyleProperty(layer.getBearing()); + case Property::BearingImage: + return makeStyleProperty(layer.getBearingImage()); + case Property::BearingImageSize: + return makeStyleProperty(layer.getBearingImageSize()); + case Property::ImageTiltDisplacement: + return makeStyleProperty(layer.getImageTiltDisplacement()); + case Property::Location: + return makeStyleProperty(layer.getLocation()); + case Property::PerspectiveCompensation: + return makeStyleProperty(layer.getPerspectiveCompensation()); + case Property::ShadowImage: + return makeStyleProperty(layer.getShadowImage()); + case Property::ShadowImageSize: + return makeStyleProperty(layer.getShadowImageSize()); + case Property::TopImage: + return makeStyleProperty(layer.getTopImage()); + case Property::TopImageSize: + return makeStyleProperty(layer.getTopImageSize()); + } + return {}; +} + +StyleProperty getLayerProperty(const LocationComponentLayer& layer, const std::string& name) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { + return {}; + } + return getLayerProperty(layer, static_cast<Property>(it->second)); +} + +} // namespace + +Value LocationComponentLayer::serialize() const { + auto result = Layer::serialize(); + assert(result.getObject()); + for (const auto& property : layerProperties) { + auto styleProperty = getLayerProperty(*this, static_cast<Property>(property.second)); + if (styleProperty.getKind() == StyleProperty::Kind::Undefined) continue; + serializeProperty(result, styleProperty, property.first.c_str(), property.second < kPaintPropertyCount); + } + return result; +} + +optional<Error> LocationComponentLayer::setPropertyInternal(const std::string& name, const Convertible& value) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) return Error{"layer doesn't support this property"}; + + auto property = static_cast<Property>(it->second); + + if (property == Property::AccuracyRadiusBorderColor || property == Property::AccuracyRadiusColor) { + Error error; + const auto& typedValue = convert<PropertyValue<Color>>(value, error, false, false); + if (!typedValue) { + return error; + } + + if (property == Property::AccuracyRadiusBorderColor) { + setAccuracyRadiusBorderColor(*typedValue); + return nullopt; + } + + if (property == Property::AccuracyRadiusColor) { + setAccuracyRadiusColor(*typedValue); + return nullopt; + } + } + if (property == Property::AccuracyRadius || property == Property::Bearing || + property == Property::BearingImageSize || property == Property::ImageTiltDisplacement || + property == Property::PerspectiveCompensation || property == Property::ShadowImageSize || + property == Property::TopImageSize) { + Error error; + const auto& typedValue = convert<PropertyValue<float>>(value, error, false, false); + if (!typedValue) { + return error; + } + + if (property == Property::AccuracyRadius) { + setAccuracyRadius(*typedValue); + return nullopt; + } + + if (property == Property::Bearing) { + setBearing(*typedValue); + return nullopt; + } + + if (property == Property::BearingImageSize) { + setBearingImageSize(*typedValue); + return nullopt; + } + + if (property == Property::ImageTiltDisplacement) { + setImageTiltDisplacement(*typedValue); + return nullopt; + } + + if (property == Property::PerspectiveCompensation) { + setPerspectiveCompensation(*typedValue); + return nullopt; + } + + if (property == Property::ShadowImageSize) { + setShadowImageSize(*typedValue); + return nullopt; + } + + if (property == Property::TopImageSize) { + setTopImageSize(*typedValue); + return nullopt; + } + } + if (property == Property::BearingImage || property == Property::ShadowImage || property == Property::TopImage) { + Error error; + const auto& typedValue = convert<PropertyValue<expression::Image>>(value, error, false, false); + if (!typedValue) { + return error; + } + + if (property == Property::BearingImage) { + setBearingImage(*typedValue); + return nullopt; + } + + if (property == Property::ShadowImage) { + setShadowImage(*typedValue); + return nullopt; + } + + if (property == Property::TopImage) { + setTopImage(*typedValue); + return nullopt; + } + } + if (property == Property::Location) { + Error error; + const auto& typedValue = convert<PropertyValue<std::array<double, 3>>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLocation(*typedValue); + return nullopt; + } + + Error error; + optional<TransitionOptions> transition = convert<TransitionOptions>(value, error); + if (!transition) { + return error; + } + + if (property == Property::AccuracyRadiusBorderColorTransition) { + setAccuracyRadiusBorderColorTransition(*transition); + return nullopt; + } + + if (property == Property::AccuracyRadiusColorTransition) { + setAccuracyRadiusColorTransition(*transition); + return nullopt; + } + + return Error{"layer doesn't support this property"}; +} + +StyleProperty LocationComponentLayer::getProperty(const std::string& name) const { + return getLayerProperty(*this, name); +} + +Mutable<Layer::Impl> LocationComponentLayer::mutableBaseImpl() const { + return staticMutableCast<Layer::Impl>(mutableImpl()); +} + +} // namespace style +} // namespace mbgl + +// clang-format on diff --git a/src/mbgl/style/layers/location_component_layer_impl.cpp b/src/mbgl/style/layers/location_component_layer_impl.cpp new file mode 100644 index 0000000000..242c631cab --- /dev/null +++ b/src/mbgl/style/layers/location_component_layer_impl.cpp @@ -0,0 +1,12 @@ +#include <mbgl/style/layers/location_component_layer.hpp> +#include <mbgl/style/layers/location_component_layer_impl.hpp> + +namespace mbgl { +namespace style { + +bool LocationComponentLayer::Impl::hasLayoutDifference(const Layer::Impl&) const { + return false; +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/location_component_layer_impl.hpp b/src/mbgl/style/layers/location_component_layer_impl.hpp new file mode 100644 index 0000000000..cc61506f4c --- /dev/null +++ b/src/mbgl/style/layers/location_component_layer_impl.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <array> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/layer_properties.hpp> +#include <mbgl/style/layers/location_component_layer.hpp> +#include <mbgl/style/layers/location_component_layer_properties.hpp> +#include <mbgl/util/color.hpp> +#include <mbgl/util/geo.hpp> +#include <memory> +#include <string> + +namespace mbgl { + +class TransformState; + +namespace style { + +class LocationComponentLayer::Impl : public Layer::Impl { +public: + using Layer::Impl::Impl; + + bool hasLayoutDifference(const Layer::Impl &) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer> &) const override; + + LocationComponentLayoutProperties::Unevaluated layout; + LocationComponentPaintProperties::Transitionable paint; + DECLARE_LAYER_TYPE_INFO; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/location_component_layer_properties.cpp b/src/mbgl/style/layers/location_component_layer_properties.cpp new file mode 100644 index 0000000000..ca13a8caf0 --- /dev/null +++ b/src/mbgl/style/layers/location_component_layer_properties.cpp @@ -0,0 +1,35 @@ +// clang-format off + +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/location_component_layer_properties.hpp> + +#include <mbgl/style/layers/location_component_layer_impl.hpp> + +namespace mbgl { +namespace style { + +LocationComponentLayerProperties::LocationComponentLayerProperties( + Immutable<LocationComponentLayer::Impl> impl_) + : LayerProperties(std::move(impl_)) {} + +LocationComponentLayerProperties::LocationComponentLayerProperties( + Immutable<LocationComponentLayer::Impl> impl_, + LocationComponentPaintProperties::PossiblyEvaluated evaluated_) + : LayerProperties(std::move(impl_)), + evaluated(std::move(evaluated_)) {} + +LocationComponentLayerProperties::~LocationComponentLayerProperties() = default; + +unsigned long LocationComponentLayerProperties::constantsMask() const { + return evaluated.constantsMask(); +} + +const LocationComponentLayer::Impl& LocationComponentLayerProperties::layerImpl() const { + return static_cast<const LocationComponentLayer::Impl&>(*baseImpl); +} + +} // namespace style +} // namespace mbgl + +// clang-format on diff --git a/src/mbgl/style/layers/location_component_layer_properties.hpp b/src/mbgl/style/layers/location_component_layer_properties.hpp new file mode 100644 index 0000000000..7654569aa6 --- /dev/null +++ b/src/mbgl/style/layers/location_component_layer_properties.hpp @@ -0,0 +1,119 @@ +// clang-format off + +// 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/layer_properties.hpp> +#include <mbgl/style/layers/location_component_layer.hpp> +#include <mbgl/style/layout_property.hpp> +#include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> + +namespace mbgl { +namespace style { + +struct AccuracyRadius : LayoutProperty<float> { + static constexpr const char *name() { return "accuracy-radius"; } + static float defaultValue() { return 0; } +}; + +struct Bearing : LayoutProperty<float> { + static constexpr const char *name() { return "bearing"; } + static float defaultValue() { return 0; } +}; + +struct BearingImage : LayoutProperty<expression::Image> { + static constexpr const char *name() { return "bearing-image"; } + static expression::Image defaultValue() { return {}; } +}; + +struct BearingImageSize : LayoutProperty<float> { + static constexpr const char *name() { return "bearing-image-size"; } + static float defaultValue() { return 1; } +}; + +struct ImageTiltDisplacement : LayoutProperty<float> { + static constexpr const char *name() { return "image-tilt-displacement"; } + static float defaultValue() { return 0; } +}; + +struct Location : LayoutProperty<std::array<double, 3>> { + static constexpr const char *name() { return "location"; } + static std::array<double, 3> defaultValue() { return {{0, 0, 0}}; } +}; + +struct PerspectiveCompensation : LayoutProperty<float> { + static constexpr const char *name() { return "perspective-compensation"; } + static float defaultValue() { return 0.85; } +}; + +struct ShadowImage : LayoutProperty<expression::Image> { + static constexpr const char *name() { return "shadow-image"; } + static expression::Image defaultValue() { return {}; } +}; + +struct ShadowImageSize : LayoutProperty<float> { + static constexpr const char *name() { return "shadow-image-size"; } + static float defaultValue() { return 1; } +}; + +struct TopImage : LayoutProperty<expression::Image> { + static constexpr const char *name() { return "top-image"; } + static expression::Image defaultValue() { return {}; } +}; + +struct TopImageSize : LayoutProperty<float> { + static constexpr const char *name() { return "top-image-size"; } + static float defaultValue() { return 1; } +}; + +struct AccuracyRadiusBorderColor : PaintProperty<Color> { + static Color defaultValue() { return Color::white(); } +}; + +struct AccuracyRadiusColor : PaintProperty<Color> { + static Color defaultValue() { return Color::white(); } +}; + +class LocationComponentLayoutProperties : public Properties< + AccuracyRadius, + Bearing, + BearingImage, + BearingImageSize, + ImageTiltDisplacement, + Location, + PerspectiveCompensation, + ShadowImage, + ShadowImageSize, + TopImage, + TopImageSize +> {}; + +class LocationComponentPaintProperties : public Properties< + AccuracyRadiusBorderColor, + AccuracyRadiusColor +> {}; + +class LocationComponentLayerProperties final : public LayerProperties { +public: + explicit LocationComponentLayerProperties(Immutable<LocationComponentLayer::Impl>); + LocationComponentLayerProperties( + Immutable<LocationComponentLayer::Impl>, + LocationComponentPaintProperties::PossiblyEvaluated); + ~LocationComponentLayerProperties() override; + + unsigned long constantsMask() const override; + + const LocationComponentLayer::Impl& layerImpl() const; + // Data members. + LocationComponentPaintProperties::PossiblyEvaluated evaluated; +}; + +} // namespace style +} // namespace mbgl + +// clang-format on |