diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp index ae1066f38..e4f1cd26a 100644 --- a/android/cpp/jni.cpp +++ b/android/cpp/jni.cpp @@ -340,7 +340,7 @@ mbgl::AnnotationSegment annotation_segment_from_latlng_jlist(JNIEnv *env, jobjec return segment; } -std::pair annotation_std_pair_from_polygon_jobject(JNIEnv *env, jobject polygon) { +std::pair annotation_std_pair_from_polygon_jobject(JNIEnv *env, jobject polygon) { jfloat alpha = env->GetFloatField(polygon, polygonAlphaId); jint fillColor = env->GetIntField(polygon, polygonFillColorId); jint strokeColor = env->GetIntField(polygon, polygonStrokeColorId); @@ -355,7 +355,7 @@ std::pair annotation_std_pair_fr int bS = (strokeColor) & 0xFF; int aS = (strokeColor >> 24) & 0xFF; - mbgl::StyleProperties shapeProperties; + mbgl::ShapeAnnotation::Properties shapeProperties; mbgl::FillPaintProperties fillProperties; fillProperties.opacity = alpha; fillProperties.stroke_color = {{ static_cast(rS) / 255.0f, static_cast(gS) / 255.0f, static_cast(bS) / 255.0f, static_cast(aS) / 255.0f }}; @@ -939,7 +939,7 @@ jlong JNICALL nativeAddPolyline(JNIEnv *env, jobject obj, jlong nativeMapViewPtr return -1; } - mbgl::StyleProperties shapeProperties; + mbgl::ShapeAnnotation::Properties shapeProperties; mbgl::LinePaintProperties lineProperties; lineProperties.opacity = alpha; lineProperties.color = {{ static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f, static_cast(a) / 255.0f }}; @@ -964,7 +964,7 @@ jlong JNICALL nativeAddPolygon(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); std::vector shapes; - std::pair segment = annotation_std_pair_from_polygon_jobject(env, polygon); + std::pair segment = annotation_std_pair_from_polygon_jobject(env, polygon); if (env->ExceptionCheck()) { env->ExceptionDescribe(); @@ -1011,7 +1011,7 @@ jlongArray JNICALL nativeAddPolygons(JNIEnv *env, jobject obj, jlong nativeMapVi for (jsize i = 0; i < len; i++) { jobject polygon = reinterpret_cast(env->GetObjectArrayElement(jarray, i)); - std::pair segment = annotation_std_pair_from_polygon_jobject(env, polygon); + std::pair segment = annotation_std_pair_from_polygon_jobject(env, polygon); if (env->ExceptionCheck()) { env->ExceptionDescribe(); return nullptr; diff --git a/include/mbgl/annotation/shape_annotation.hpp b/include/mbgl/annotation/shape_annotation.hpp index dd8bf5e4d..5e6a13149 100644 --- a/include/mbgl/annotation/shape_annotation.hpp +++ b/include/mbgl/annotation/shape_annotation.hpp @@ -6,6 +6,8 @@ #include +#include + namespace mbgl { using AnnotationSegment = std::vector; @@ -13,12 +15,14 @@ using AnnotationSegments = std::vector; class ShapeAnnotation { public: - inline ShapeAnnotation(const AnnotationSegments& segments_, const StyleProperties& styleProperties_) + using Properties = mapbox::util::variant; + + inline ShapeAnnotation(const AnnotationSegments& segments_, const Properties& styleProperties_) : segments(segments_), styleProperties(styleProperties_) { } const AnnotationSegments segments; - const StyleProperties styleProperties; + const Properties styleProperties; }; } diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp index aacac3387..221649113 100644 --- a/include/mbgl/style/style_properties.hpp +++ b/include/mbgl/style/style_properties.hpp @@ -1,14 +1,10 @@ #ifndef MBGL_STYLE_STYLE_PROPERTIES #define MBGL_STYLE_STYLE_PROPERTIES -#include - #include #include #include -#include -#include #include namespace mbgl { @@ -169,22 +165,16 @@ public: float opacity = 1.0f; Color color = {{ 0, 0, 0, 1 }}; Faded image; + + inline bool isVisible() const { + return opacity > 0; + } }; class BackgroundLayoutProperties { public: }; -typedef mapbox::util::variant< - FillPaintProperties, - LinePaintProperties, - CirclePaintProperties, - SymbolPaintProperties, - RasterPaintProperties, - BackgroundPaintProperties, - std::false_type -> StyleProperties; - } #endif diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 78461462d..cbc872313 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -223,11 +223,8 @@ void GLFWView::addRandomPointAnnotations(int count) { void GLFWView::addRandomShapeAnnotations(int count) { std::vector shapes; - mbgl::FillPaintProperties fillProperties; - fillProperties.opacity = .1; - - mbgl::StyleProperties properties; - properties.set(fillProperties); + mbgl::FillPaintProperties properties; + properties.opacity = .1; for (int i = 0; i < count; i++) { mbgl::AnnotationSegment triangle; diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 4165cd397..ffe91f15f 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -2167,7 +2167,7 @@ CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) [strokeColor getRed:&r green:&g blue:&b alpha:&a]; mbgl::Color strokeNativeColor({{ (float)r, (float)g, (float)b, (float)a }}); - mbgl::StyleProperties shapeProperties; + mbgl::ShapeAnnotation::Properties shapeProperties; if ([annotation isKindOfClass:[MGLPolyline class]]) { diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index 45fb1218f..b8e9f973f 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include @@ -112,20 +112,19 @@ void AnnotationManager::updateStyle(Style& style) { source->enabled = true; style.addSource(std::move(source)); - std::map pointPaints; - pointPaints.emplace(ClassID::Default, ClassProperties()); - std::unique_ptr pointLayer = std::make_unique(PointLayerID, std::move(pointPaints)); - pointLayer->type = StyleLayerType::Symbol; + std::unique_ptr layer = std::make_unique(); + layer->id = PointLayerID; + layer->type = StyleLayerType::Symbol; + layer->styles.emplace(ClassID::Default, ClassProperties()); - util::ptr pointBucket = std::make_shared(pointLayer->type); - pointBucket->name = pointLayer->id; - pointBucket->source = SourceID; - pointBucket->source_layer = PointLayerID; - pointBucket->layout.set(PropertyKey::IconImage, ConstantFunction("{sprite}")); - pointBucket->layout.set(PropertyKey::IconAllowOverlap, ConstantFunction(true)); + layer->bucket = std::make_shared(layer->type); + layer->bucket->name = layer->id; + layer->bucket->source = SourceID; + layer->bucket->source_layer = PointLayerID; + layer->bucket->layout.set(PropertyKey::IconImage, ConstantFunction("{sprite}")); + layer->bucket->layout.set(PropertyKey::IconAllowOverlap, ConstantFunction(true)); - pointLayer->bucket = pointBucket; - style.addLayer(std::move(pointLayer)); + style.addLayer(std::move(layer)); } for (const auto& shape : shapeAnnotations) { diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp index 74daf849e..5b3c07fbc 100644 --- a/src/mbgl/annotation/shape_annotation_impl.cpp +++ b/src/mbgl/annotation/shape_annotation_impl.cpp @@ -6,7 +6,8 @@ #include #include #include -#include +#include +#include namespace mbgl { @@ -55,35 +56,47 @@ void ShapeAnnotationImpl::updateStyle(Style& style) { if (style.getLayer(layerID)) return; - ClassProperties paintProperties; - if (shape.styleProperties.is()) { - const LinePaintProperties& lineProperties = shape.styleProperties.get(); - paintProperties.set(PropertyKey::LineOpacity, ConstantFunction(lineProperties.opacity)); - paintProperties.set(PropertyKey::LineWidth, ConstantFunction(lineProperties.width)); - paintProperties.set(PropertyKey::LineColor, ConstantFunction(lineProperties.color)); + const LinePaintProperties& properties = shape.styleProperties.get(); + + std::unique_ptr layer = std::make_unique(); + layer->id = layerID; + layer->type = StyleLayerType::Line; + + ClassProperties paintProperties; + paintProperties.set(PropertyKey::LineOpacity, ConstantFunction(properties.opacity)); + paintProperties.set(PropertyKey::LineWidth, ConstantFunction(properties.width)); + paintProperties.set(PropertyKey::LineColor, ConstantFunction(properties.color)); + layer->styles.emplace(ClassID::Default, std::move(paintProperties)); + + layer->bucket = std::make_shared(layer->type); + layer->bucket->name = layer->id; + layer->bucket->source = AnnotationManager::SourceID; + layer->bucket->source_layer = layer->id; + layer->bucket->layout.set(PropertyKey::LineJoin, ConstantFunction(JoinType::Round)); + + style.addLayer(std::move(layer), AnnotationManager::PointLayerID); + } else if (shape.styleProperties.is()) { - const FillPaintProperties& fillProperties = shape.styleProperties.get(); - paintProperties.set(PropertyKey::FillOpacity, ConstantFunction(fillProperties.opacity)); - paintProperties.set(PropertyKey::FillColor, ConstantFunction(fillProperties.fill_color)); - paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction(fillProperties.stroke_color)); + const FillPaintProperties& properties = shape.styleProperties.get(); + + std::unique_ptr layer = std::make_unique(); + layer->id = layerID; + layer->type = StyleLayerType::Fill; + + ClassProperties paintProperties; + paintProperties.set(PropertyKey::FillOpacity, ConstantFunction(properties.opacity)); + paintProperties.set(PropertyKey::FillColor, ConstantFunction(properties.fill_color)); + paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction(properties.stroke_color)); + layer->styles.emplace(ClassID::Default, std::move(paintProperties)); + + layer->bucket = std::make_shared(layer->type); + layer->bucket->name = layer->id; + layer->bucket->source = AnnotationManager::SourceID; + layer->bucket->source_layer = layer->id; + + style.addLayer(std::move(layer), AnnotationManager::PointLayerID); } - - std::map shapePaints; - shapePaints.emplace(ClassID::Default, std::move(paintProperties)); - std::unique_ptr shapeLayer = std::make_unique(layerID, std::move(shapePaints)); - shapeLayer->type = (shape.styleProperties.is() ? StyleLayerType::Line : StyleLayerType::Fill); - - util::ptr shapeBucket = std::make_shared(shapeLayer->type); - shapeBucket->name = shapeLayer->id; - shapeBucket->source = AnnotationManager::SourceID; - shapeBucket->source_layer = shapeLayer->id; - if (shape.styleProperties.is()) { - shapeBucket->layout.set(PropertyKey::LineJoin, ConstantFunction(JoinType::Round)); - } - - shapeLayer->bucket = shapeBucket; - style.addLayer(std::move(shapeLayer), AnnotationManager::PointLayerID); } void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile) { diff --git a/src/mbgl/annotation/shape_annotation_impl.hpp b/src/mbgl/annotation/shape_annotation_impl.hpp index 19eb05f89..4cf6c23f6 100644 --- a/src/mbgl/annotation/shape_annotation_impl.hpp +++ b/src/mbgl/annotation/shape_annotation_impl.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/src/mbgl/layer/background_layer.cpp b/src/mbgl/layer/background_layer.cpp new file mode 100644 index 000000000..c97124feb --- /dev/null +++ b/src/mbgl/layer/background_layer.cpp @@ -0,0 +1,12 @@ +#include + +namespace mbgl { + +RenderPass BackgroundLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + applyTransitionedStyleProperty(PropertyKey::BackgroundOpacity, properties.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::BackgroundColor, properties.color, z, now, zoomHistory); + applyStyleProperty(PropertyKey::BackgroundImage, properties.image, z, now, zoomHistory); + return properties.isVisible() ? RenderPass::Translucent : RenderPass::None; +} + +} diff --git a/src/mbgl/layer/background_layer.hpp b/src/mbgl/layer/background_layer.hpp new file mode 100644 index 000000000..817c23423 --- /dev/null +++ b/src/mbgl/layer/background_layer.hpp @@ -0,0 +1,18 @@ +#ifndef MBGL_BACKGROUND_LAYER +#define MBGL_BACKGROUND_LAYER + +#include +#include + +namespace mbgl { + +class BackgroundLayer : public StyleLayer { +public: + RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override; + + BackgroundPaintProperties properties; +}; + +} + +#endif diff --git a/src/mbgl/layer/circle_layer.cpp b/src/mbgl/layer/circle_layer.cpp new file mode 100644 index 000000000..384d56dfb --- /dev/null +++ b/src/mbgl/layer/circle_layer.cpp @@ -0,0 +1,15 @@ +#include + +namespace mbgl { + +RenderPass CircleLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + applyTransitionedStyleProperty(PropertyKey::CircleRadius, properties.radius, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::CircleColor, properties.color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::CircleOpacity, properties.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::CircleTranslate, properties.translate, z, now, zoomHistory); + applyStyleProperty(PropertyKey::CircleTranslateAnchor, properties.translateAnchor, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::CircleBlur, properties.blur, z, now, zoomHistory); + return properties.isVisible() ? RenderPass::Translucent : RenderPass::None; +} + +} diff --git a/src/mbgl/layer/circle_layer.hpp b/src/mbgl/layer/circle_layer.hpp new file mode 100644 index 000000000..f3a1cf973 --- /dev/null +++ b/src/mbgl/layer/circle_layer.hpp @@ -0,0 +1,18 @@ +#ifndef MBGL_CIRCLE_LAYER +#define MBGL_CIRCLE_LAYER + +#include +#include + +namespace mbgl { + +class CircleLayer : public StyleLayer { +public: + RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override; + + CirclePaintProperties properties; +}; + +} + +#endif diff --git a/src/mbgl/layer/fill_layer.cpp b/src/mbgl/layer/fill_layer.cpp new file mode 100644 index 000000000..7a45774c2 --- /dev/null +++ b/src/mbgl/layer/fill_layer.cpp @@ -0,0 +1,29 @@ +#include + +namespace mbgl { + +RenderPass FillLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + applyStyleProperty(PropertyKey::FillAntialias, properties.antialias, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillOpacity, properties.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillColor, properties.fill_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillOutlineColor, properties.stroke_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillTranslate, properties.translate, z, now, zoomHistory); + applyStyleProperty(PropertyKey::FillTranslateAnchor, properties.translateAnchor, z, now, zoomHistory); + applyStyleProperty(PropertyKey::FillImage, properties.image, z, now, zoomHistory); + + RenderPass result = RenderPass::None; + + if (properties.antialias) { + result |= RenderPass::Translucent; + } + + if (!properties.image.from.empty() || (properties.fill_color[3] * properties.opacity) < 1.0f) { + result |= RenderPass::Translucent; + } else { + result |= RenderPass::Opaque; + } + + return result; +} + +} diff --git a/src/mbgl/layer/fill_layer.hpp b/src/mbgl/layer/fill_layer.hpp new file mode 100644 index 000000000..d8e8e6d37 --- /dev/null +++ b/src/mbgl/layer/fill_layer.hpp @@ -0,0 +1,18 @@ +#ifndef MBGL_FILL_LAYER +#define MBGL_FILL_LAYER + +#include +#include + +namespace mbgl { + +class FillLayer : public StyleLayer { +public: + RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override; + + FillPaintProperties properties; +}; + +} + +#endif diff --git a/src/mbgl/layer/line_layer.cpp b/src/mbgl/layer/line_layer.cpp new file mode 100644 index 000000000..340f8fe7f --- /dev/null +++ b/src/mbgl/layer/line_layer.cpp @@ -0,0 +1,22 @@ +#include + +namespace mbgl { + +RenderPass LineLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + applyTransitionedStyleProperty(PropertyKey::LineOpacity, properties.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineColor, properties.color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineTranslate, properties.translate, z, now, zoomHistory); + applyStyleProperty(PropertyKey::LineTranslateAnchor, properties.translateAnchor, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineWidth, properties.width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineGapWidth, properties.gap_width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineBlur, properties.blur, z, now, zoomHistory); + applyStyleProperty(PropertyKey::LineDashArray, properties.dash_array, z, now, zoomHistory); + applyStyleProperty(PropertyKey::LineImage, properties.image, z, now, zoomHistory); + + // for scaling dasharrays + applyStyleProperty(PropertyKey::LineWidth, properties.dash_line_width, std::floor(z), now, zoomHistory); + + return properties.isVisible() ? RenderPass::Translucent : RenderPass::None; +} + +} diff --git a/src/mbgl/layer/line_layer.hpp b/src/mbgl/layer/line_layer.hpp new file mode 100644 index 000000000..9f59768c1 --- /dev/null +++ b/src/mbgl/layer/line_layer.hpp @@ -0,0 +1,18 @@ +#ifndef MBGL_LINE_LAYER +#define MBGL_LINE_LAYER + +#include +#include + +namespace mbgl { + +class LineLayer : public StyleLayer { +public: + RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override; + + LinePaintProperties properties; +}; + +} + +#endif diff --git a/src/mbgl/layer/raster_layer.cpp b/src/mbgl/layer/raster_layer.cpp new file mode 100644 index 000000000..2831483b8 --- /dev/null +++ b/src/mbgl/layer/raster_layer.cpp @@ -0,0 +1,16 @@ +#include + +namespace mbgl { + +RenderPass RasterLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + applyTransitionedStyleProperty(PropertyKey::RasterOpacity, properties.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterHueRotate, properties.hue_rotate, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterBrightnessLow, properties.brightness[0], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterBrightnessHigh, properties.brightness[1], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterSaturation, properties.saturation, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterContrast, properties.contrast, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterFade, properties.fade, z, now, zoomHistory); + return properties.isVisible() ? RenderPass::Translucent : RenderPass::None; +} + +} diff --git a/src/mbgl/layer/raster_layer.hpp b/src/mbgl/layer/raster_layer.hpp new file mode 100644 index 000000000..fc57a9171 --- /dev/null +++ b/src/mbgl/layer/raster_layer.hpp @@ -0,0 +1,18 @@ +#ifndef MBGL_RASTER_LAYER +#define MBGL_RASTER_LAYER + +#include +#include + +namespace mbgl { + +class RasterLayer : public StyleLayer { +public: + RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override; + + RasterPaintProperties properties; +}; + +} + +#endif diff --git a/src/mbgl/layer/symbol_layer.cpp b/src/mbgl/layer/symbol_layer.cpp new file mode 100644 index 000000000..bdfa577ce --- /dev/null +++ b/src/mbgl/layer/symbol_layer.cpp @@ -0,0 +1,39 @@ +#include +#include +#include + +namespace mbgl { + +RenderPass SymbolLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + applyTransitionedStyleProperty(PropertyKey::IconOpacity, properties.icon.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconColor, properties.icon.color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconHaloColor, properties.icon.halo_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconHaloWidth, properties.icon.halo_width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconHaloBlur, properties.icon.halo_blur, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconTranslate, properties.icon.translate, z, now, zoomHistory); + applyStyleProperty(PropertyKey::IconTranslateAnchor, properties.icon.translate_anchor, z, now, zoomHistory); + + applyTransitionedStyleProperty(PropertyKey::TextOpacity, properties.text.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextColor, properties.text.color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextHaloColor, properties.text.halo_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextHaloWidth, properties.text.halo_width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextHaloBlur, properties.text.halo_blur, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextTranslate, properties.text.translate, z, now, zoomHistory); + applyStyleProperty(PropertyKey::TextTranslateAnchor, properties.text.translate_anchor, z, now, zoomHistory); + + // text-size and icon-size are layout properties but they also need to be evaluated as paint properties: + auto it = bucket->layout.properties.find(PropertyKey::IconSize); + if (it != bucket->layout.properties.end()) { + const PropertyEvaluator evaluator(z, zoomHistory); + properties.icon.size = mapbox::util::apply_visitor(evaluator, it->second); + } + it = bucket->layout.properties.find(PropertyKey::TextSize); + if (it != bucket->layout.properties.end()) { + const PropertyEvaluator evaluator(z, zoomHistory); + properties.text.size = mapbox::util::apply_visitor(evaluator, it->second); + } + + return properties.isVisible() ? RenderPass::Translucent : RenderPass::None; +} + +} diff --git a/src/mbgl/layer/symbol_layer.hpp b/src/mbgl/layer/symbol_layer.hpp new file mode 100644 index 000000000..ee25b00be --- /dev/null +++ b/src/mbgl/layer/symbol_layer.hpp @@ -0,0 +1,18 @@ +#ifndef MBGL_SYMBOL_LAYER +#define MBGL_SYMBOL_LAYER + +#include +#include + +namespace mbgl { + +class SymbolLayer : public StyleLayer { +public: + RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override; + + SymbolPaintProperties properties; +}; + +} + +#endif diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index acf832009..c4a38c923 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -63,29 +64,6 @@ void TileWorker::redoPlacement(float angle, float pitch, bool collisionDebug) { } } -template -struct PropertyEvaluator { - typedef T result_type; - explicit PropertyEvaluator(float z_) : z(z_) {} - - template ::value, int>::type = 0> - T operator()(const P &value) const { - return value; - } - - T operator()(const Function &value) const { - return mapbox::util::apply_visitor(FunctionEvaluator(z), value); - } - - template ::value, int>::type = 0> - T operator()(const P &) const { - return T(); - } - -private: - const float z; -}; - template void applyLayoutProperty(PropertyKey key, const ClassProperties &classProperties, T &target, const float z) { auto it = classProperties.properties.find(key); diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp index a9433eecb..6187907a6 100644 --- a/src/mbgl/renderer/circle_bucket.cpp +++ b/src/mbgl/renderer/circle_bucket.cpp @@ -2,6 +2,7 @@ #include #include +#include using namespace mbgl; @@ -19,10 +20,10 @@ void CircleBucket::upload() { } void CircleBucket::render(Painter& painter, - const StyleLayer& layer_desc, + const StyleLayer& layer, const TileID& id, const mat4& matrix) { - painter.renderCircle(*this, layer_desc, id, matrix); + painter.renderCircle(*this, dynamic_cast(layer), id, matrix); } bool CircleBucket::hasData() const { diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp index 38582c012..5b60be3c7 100644 --- a/src/mbgl/renderer/fill_bucket.cpp +++ b/src/mbgl/renderer/fill_bucket.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -197,10 +198,10 @@ void FillBucket::upload() { } void FillBucket::render(Painter& painter, - const StyleLayer& layer_desc, + const StyleLayer& layer, const TileID& id, const mat4& matrix) { - painter.renderFill(*this, layer_desc, id, matrix); + painter.renderFill(*this, dynamic_cast(layer), id, matrix); } bool FillBucket::hasData() const { diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp index d2d7650d7..a7c3f0067 100644 --- a/src/mbgl/renderer/line_bucket.cpp +++ b/src/mbgl/renderer/line_bucket.cpp @@ -1,5 +1,5 @@ #include - +#include #include #include #include @@ -388,10 +388,10 @@ void LineBucket::upload() { } void LineBucket::render(Painter& painter, - const StyleLayer& layer_desc, + const StyleLayer& layer, const TileID& id, const mat4& matrix) { - painter.renderLine(*this, layer_desc, id, matrix); + painter.renderLine(*this, dynamic_cast(layer), id, matrix); } bool LineBucket::hasData() const { diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index d5dfed442..a7ffd8269 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include #include #include @@ -286,7 +288,7 @@ void Painter::renderPass(RenderPass pass_, } } else { MBGL_DEBUG_GROUP("background"); - renderBackground(item.layer); + renderBackground(dynamic_cast(item.layer)); } } @@ -303,20 +305,18 @@ std::vector Painter::determineRenderOrder(const Style& style) { if (layer.bucket->visibility == VisibilityType::None) continue; if (layer.type == StyleLayerType::Background) { // This layer defines a background color/image. - if (layer.properties.is()) { - auto& props = layer.properties.get(); - if (props.image.from.empty()) { - // This is a solid background. We can use glClear(). - background = props.color; - background[0] *= props.opacity; - background[1] *= props.opacity; - background[2] *= props.opacity; - background[3] *= props.opacity; - } else { - // This is a textured background. We need to render it with a quad. - background = {{ 0, 0, 0, 0 }}; - order.emplace_back(layer); - } + auto& props = dynamic_cast(layer).properties; + if (props.image.from.empty()) { + // This is a solid background. We can use glClear(). + background = props.color; + background[0] *= props.opacity; + background[1] *= props.opacity; + background[2] *= props.opacity; + background[3] *= props.opacity; + } else { + // This is a textured background. We need to render it with a quad. + background = {{ 0, 0, 0, 0 }}; + order.emplace_back(layer); } continue; } @@ -378,10 +378,10 @@ std::vector Painter::determineRenderOrder(const Style& style) { return order; } -void Painter::renderBackground(const StyleLayer &layer_desc) { +void Painter::renderBackground(const BackgroundLayer& layer) { // Note: This function is only called for textured background. Otherwise, the background color // is created with glClear. - const BackgroundPaintProperties& properties = layer_desc.getProperties(); + const BackgroundPaintProperties& properties = layer.properties; if (!properties.image.to.empty()) { if ((properties.opacity >= 1.0f) != (pass == RenderPass::Opaque)) diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index dbe575985..b7402d69b 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -37,10 +37,16 @@ struct FrameData; class DebugBucket; class FillBucket; +class FillLayer; class LineBucket; +class LineLayer; class CircleBucket; +class CircleLayer; class SymbolBucket; +class SymbolLayer; class RasterBucket; +class RasterLayer; +class BackgroundLayer; struct RasterProperties; @@ -96,13 +102,13 @@ public: // Renders the red debug frame around a tile, visualizing its perimeter. void renderDebugFrame(const mat4 &matrix); - void renderDebugText(DebugBucket& bucket, const mat4 &matrix); - void renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix); - void renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix); - void renderCircle(CircleBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix); - void renderSymbol(SymbolBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix); - void renderRaster(RasterBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix); - void renderBackground(const StyleLayer &layer_desc); + void renderDebugText(DebugBucket&, const mat4&); + void renderFill(FillBucket&, const FillLayer&, const TileID&, const mat4&); + void renderLine(LineBucket&, const LineLayer&, const TileID&, const mat4&); + void renderCircle(CircleBucket&, const CircleLayer&, const TileID&, const mat4&); + void renderSymbol(SymbolBucket&, const SymbolLayer&, const TileID&, const mat4&); + void renderRaster(RasterBucket&, const RasterLayer&, const TileID&, const mat4&); + void renderBackground(const BackgroundLayer&); float saturationFactor(float saturation); float contrastFactor(float contrast); diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp index a7aa6ac45..cb0fe0baa 100644 --- a/src/mbgl/renderer/painter_circle.cpp +++ b/src/mbgl/renderer/painter_circle.cpp @@ -1,9 +1,7 @@ #include #include -#include -#include -#include +#include #include #include @@ -14,7 +12,7 @@ using namespace mbgl; void Painter::renderCircle(CircleBucket& bucket, - const StyleLayer& layer_desc, + const CircleLayer& layer, const TileID& id, const mat4& matrix) { // Abort early. @@ -22,7 +20,7 @@ void Painter::renderCircle(CircleBucket& bucket, config.stencilTest = false; - const CirclePaintProperties& properties = layer_desc.getProperties(); + const CirclePaintProperties& properties = layer.properties; mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor); Color color = properties.color; diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 33fc14a0d..b4247d6d9 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -1,8 +1,6 @@ #include #include -#include -#include -#include +#include #include #include #include @@ -13,8 +11,8 @@ using namespace mbgl; -void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix) { - const FillPaintProperties& properties = layer_desc.getProperties(); +void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileID& id, const mat4& matrix) { + const FillPaintProperties& properties = layer.properties; mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor); Color fill_color = properties.fill_color; diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index fdbe690f7..945022280 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -1,8 +1,6 @@ #include #include -#include -#include -#include +#include #include #include #include @@ -15,7 +13,7 @@ using namespace mbgl; -void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix) { +void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileID& id, const mat4& matrix) { // Abort early. if (pass == RenderPass::Opaque) return; @@ -23,7 +21,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const config.depthTest = true; config.depthMask = GL_FALSE; - const auto& properties = layer_desc.getProperties(); + const auto& properties = layer.properties; const auto& layout = bucket.layout; // the distance over which the line edge fades out. diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp index f05256318..80730113a 100644 --- a/src/mbgl/renderer/painter_raster.cpp +++ b/src/mbgl/renderer/painter_raster.cpp @@ -1,15 +1,15 @@ #include #include #include -#include +#include #include using namespace mbgl; -void Painter::renderRaster(RasterBucket& bucket, const StyleLayer &layer_desc, const TileID&, const mat4 &matrix) { +void Painter::renderRaster(RasterBucket& bucket, const RasterLayer& layer, const TileID&, const mat4& matrix) { if (pass != RenderPass::Translucent) return; - const RasterPaintProperties& properties = layer_desc.getProperties(); + const RasterPaintProperties& properties = layer.properties; if (bucket.hasData()) { useProgram(rasterShader->program); diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index f1ebef398..1ad8c64e8 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -1,7 +1,6 @@ #include #include -#include -#include +#include #include #include #include @@ -126,13 +125,13 @@ void Painter::renderSDF(SymbolBucket &bucket, } } -void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, const TileID &id, const mat4 &matrix) { +void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const TileID& id, const mat4& matrix) { // Abort early. if (pass == RenderPass::Opaque) { return; } - const auto& properties = layer_desc.getProperties(); + const auto& properties = layer.properties; const auto& layout = bucket.layout; config.depthMask = GL_FALSE; diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp index 9f28dfd32..d9146f0e8 100644 --- a/src/mbgl/renderer/raster_bucket.cpp +++ b/src/mbgl/renderer/raster_bucket.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -17,10 +18,10 @@ void RasterBucket::upload() { } void RasterBucket::render(Painter& painter, - const StyleLayer& layer_desc, + const StyleLayer& layer, const TileID& id, const mat4& matrix) { - painter.renderRaster(*this, layer_desc, id, matrix); + painter.renderRaster(*this, dynamic_cast(layer), id, matrix); } bool RasterBucket::setImage(std::unique_ptr image) { diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index a56a926b7..d769060c6 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -75,10 +76,10 @@ void SymbolBucket::upload() { } void SymbolBucket::render(Painter& painter, - const StyleLayer& layer_desc, + const StyleLayer& layer, const TileID& id, const mat4& matrix) { - painter.renderSymbol(*this, layer_desc, id, matrix); + painter.renderSymbol(*this, dynamic_cast(layer), id, matrix); } bool SymbolBucket::hasData() const { return hasTextData() || hasIconData() || !symbolInstances.empty(); } diff --git a/src/mbgl/style/property_evaluator.hpp b/src/mbgl/style/property_evaluator.hpp new file mode 100644 index 000000000..7856c90f4 --- /dev/null +++ b/src/mbgl/style/property_evaluator.hpp @@ -0,0 +1,45 @@ +#ifndef MBGL_PROPERTY_EVALUATOR +#define MBGL_PROPERTY_EVALUATOR + +#include +#include +#include + +namespace mbgl { + +struct ZoomHistory; + +template +class PropertyEvaluator { +public: + typedef T result_type; + + PropertyEvaluator(float z_) : z(z_), zoomHistory() {} + PropertyEvaluator(float z_, const ZoomHistory& zoomHistory_) : z(z_), zoomHistory(zoomHistory_) {} + + template ::value, int>::type = 0> + T operator()(const P &value) const { + return value; + } + + T operator()(const Function& value) const { + return mapbox::util::apply_visitor(FunctionEvaluator(z), value); + } + + T operator()(const PiecewiseConstantFunction& value) const { + return value.evaluate(z, zoomHistory); + } + + template ::value, int>::type = 0> + T operator()(const P &) const { + return T(); + } + +private: + const float z; + ZoomHistory zoomHistory; +}; + +} + +#endif diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index 17c6fa938..e6b3ee5bd 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -1,35 +1,38 @@ #include -#include #include -#include +#include +#include +#include +#include +#include +#include namespace mbgl { -StyleLayer::StyleLayer(const std::string &id_, std::map &&styles_) - : id(id_), styles(std::move(styles_)) {} +std::unique_ptr StyleLayer::create(StyleLayerType type) { + switch (type) { + case StyleLayerType::Fill: + return std::make_unique(); + case StyleLayerType::Line: + return std::make_unique(); + case StyleLayerType::Circle: + return std::make_unique(); + case StyleLayerType::Symbol: + return std::make_unique(); + case StyleLayerType::Raster: + return std::make_unique(); + case StyleLayerType::Background: + return std::make_unique(); + default: + return nullptr; + } +} bool StyleLayer::isBackground() const { return type == StyleLayerType::Background; } -bool StyleLayer::isVisible() const { - switch (type) { - case StyleLayerType::Fill: - return getProperties().isVisible(); - case StyleLayerType::Line: - return getProperties().isVisible(); - case StyleLayerType::Circle: - return getProperties().isVisible(); - case StyleLayerType::Symbol: - return getProperties().isVisible(); - case StyleLayerType::Raster: - return getProperties().isVisible(); - default: - return false; - } -} - bool StyleLayer::hasRenderPass(RenderPass pass) const { return bool(passes & pass); } @@ -119,208 +122,14 @@ void StyleLayer::applyClassProperties(const ClassID class_id, } } -template -struct PropertyEvaluator { - typedef T result_type; - PropertyEvaluator(float z_, const ZoomHistory &zoomHistory_) : z(z_), zoomHistory(zoomHistory_) {} - - template ::value, int>::type = 0> - T operator()(const P &value) const { - return value; - } - - T operator()(const Function &value) const { - return mapbox::util::apply_visitor(FunctionEvaluator(z), value); - } - - T operator()(const PiecewiseConstantFunction &value) const { - return value.evaluate(z, zoomHistory); - } - - template ::value, int>::type = 0> - T operator()(const P &) const { - return T(); - } - -private: - const float z; - const ZoomHistory &zoomHistory; -}; - -template -void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - auto it = appliedStyle.find(key); - if (it != appliedStyle.end()) { - AppliedClassPropertyValues &applied = it->second; - // Iterate through all properties that we need to apply in order. - const PropertyEvaluator evaluator(z, zoomHistory); - for (auto& property : applied.propertyValues) { - if (now >= property.begin) { - // We overwrite the current property with the new value. - target = mapbox::util::apply_visitor(evaluator, property.value); - } else { - // Do not apply this property because its transition hasn't begun yet. - } - } - } -} - -template -void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - auto it = appliedStyle.find(key); - if (it != appliedStyle.end()) { - AppliedClassPropertyValues &applied = it->second; - // Iterate through all properties that we need to apply in order. - const PropertyEvaluator evaluator(z, zoomHistory); - for (auto& property : applied.propertyValues) { - if (now >= property.end) { - // We overwrite the current property with the new value. - target = mapbox::util::apply_visitor(evaluator, property.value); - } else if (now >= property.begin) { - // We overwrite the current property partially with the new value. - float progress = std::chrono::duration(now - property.begin) / (property.end - property.begin); - target = util::interpolate(target, mapbox::util::apply_visitor(evaluator, property.value), progress); - hasPendingTransitions = true; - } else { - // Do not apply this property because its transition hasn't begun yet. - } - } - } -} - -template <> -void StyleLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - properties.set(); - FillPaintProperties& fill = properties.get(); - applyStyleProperty(PropertyKey::FillAntialias, fill.antialias, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::FillOpacity, fill.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::FillColor, fill.fill_color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::FillOutlineColor, fill.stroke_color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::FillTranslate, fill.translate, z, now, zoomHistory); - applyStyleProperty(PropertyKey::FillTranslateAnchor, fill.translateAnchor, z, now, zoomHistory); - applyStyleProperty(PropertyKey::FillImage, fill.image, z, now, zoomHistory); -} - -template <> -void StyleLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - properties.set(); - LinePaintProperties& line = properties.get(); - applyTransitionedStyleProperty(PropertyKey::LineOpacity, line.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::LineColor, line.color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::LineTranslate, line.translate, z, now, zoomHistory); - applyStyleProperty(PropertyKey::LineTranslateAnchor, line.translateAnchor, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::LineWidth, line.width, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::LineGapWidth, line.gap_width, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::LineBlur, line.blur, z, now, zoomHistory); - applyStyleProperty(PropertyKey::LineDashArray, line.dash_array, z, now, zoomHistory); - applyStyleProperty(PropertyKey::LineImage, line.image, z, now, zoomHistory); - - // for scaling dasharrays - applyStyleProperty(PropertyKey::LineWidth, line.dash_line_width, std::floor(z), now, zoomHistory); -} - -template <> -void StyleLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - properties.set(); - CirclePaintProperties& circle = properties.get(); - applyTransitionedStyleProperty(PropertyKey::CircleRadius, circle.radius, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::CircleColor, circle.color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::CircleOpacity, circle.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::CircleTranslate, circle.translate, z, now, zoomHistory); - applyStyleProperty(PropertyKey::CircleTranslateAnchor, circle.translateAnchor, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::CircleBlur, circle.blur, z, now, zoomHistory); -} - -template <> -void StyleLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - properties.set(); - SymbolPaintProperties& symbol = properties.get(); - applyTransitionedStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::IconColor, symbol.icon.color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::IconHaloColor, symbol.icon.halo_color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::IconHaloWidth, symbol.icon.halo_width, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::IconHaloBlur, symbol.icon.halo_blur, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::IconTranslate, symbol.icon.translate, z, now, zoomHistory); - applyStyleProperty(PropertyKey::IconTranslateAnchor, symbol.icon.translate_anchor, z, now, zoomHistory); - - applyTransitionedStyleProperty(PropertyKey::TextOpacity, symbol.text.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::TextColor, symbol.text.color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::TextHaloColor, symbol.text.halo_color, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::TextHaloWidth, symbol.text.halo_width, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::TextHaloBlur, symbol.text.halo_blur, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::TextTranslate, symbol.text.translate, z, now, zoomHistory); - applyStyleProperty(PropertyKey::TextTranslateAnchor, symbol.text.translate_anchor, z, now, zoomHistory); - - // text-size and icon-size are layout properties but they also need to be evaluated as paint properties: - auto it = bucket->layout.properties.find(PropertyKey::IconSize); - if (it != bucket->layout.properties.end()) { - const PropertyEvaluator evaluator(z, zoomHistory); - symbol.icon.size = mapbox::util::apply_visitor(evaluator, it->second); - } - it = bucket->layout.properties.find(PropertyKey::TextSize); - if (it != bucket->layout.properties.end()) { - const PropertyEvaluator evaluator(z, zoomHistory); - symbol.text.size = mapbox::util::apply_visitor(evaluator, it->second); - } -} - -template <> -void StyleLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - properties.set(); - RasterPaintProperties& raster = properties.get(); - applyTransitionedStyleProperty(PropertyKey::RasterOpacity, raster.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::RasterHueRotate, raster.hue_rotate, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::RasterBrightnessLow, raster.brightness[0], z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::RasterBrightnessHigh, raster.brightness[1], z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::RasterSaturation, raster.saturation, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::RasterContrast, raster.contrast, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::RasterFade, raster.fade, z, now, zoomHistory); -} - -template <> -void StyleLayer::applyStyleProperties(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { - properties.set(); - BackgroundPaintProperties& background = properties.get(); - applyTransitionedStyleProperty(PropertyKey::BackgroundOpacity, background.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::BackgroundColor, background.color, z, now, zoomHistory); - applyStyleProperty(PropertyKey::BackgroundImage, background.image, z, now, zoomHistory); -} - void StyleLayer::updateProperties(float z, const TimePoint& now, ZoomHistory &zoomHistory) { cleanupAppliedStyleProperties(now); // Clear the pending transitions flag upon each update. hasPendingTransitions = false; - switch (type) { - case StyleLayerType::Fill: applyStyleProperties(z, now, zoomHistory); break; - case StyleLayerType::Line: applyStyleProperties(z, now, zoomHistory); break; - case StyleLayerType::Circle: applyStyleProperties(z, now, zoomHistory); break; - case StyleLayerType::Symbol: applyStyleProperties(z, now, zoomHistory); break; - case StyleLayerType::Raster: applyStyleProperties(z, now, zoomHistory); break; - case StyleLayerType::Background: applyStyleProperties(z, now, zoomHistory); break; - default: properties.set(); break; - } - // Update the render passes when this layer is visible. - passes = RenderPass::None; - if (isVisible()) { - if (properties.is()) { - const FillPaintProperties &fillProperties = properties.get(); - const float alpha = fillProperties.fill_color[3] * fillProperties.opacity; - - if (fillProperties.antialias) { - passes |= RenderPass::Translucent; - } - if (!fillProperties.image.from.empty() || alpha < 1.0f) { - passes |= RenderPass::Translucent; - } else { - passes |= RenderPass::Opaque; - } - } else { - passes |= RenderPass::Translucent; - } - } + passes = applyStyleProperties(z, now, zoomHistory); } bool StyleLayer::hasTransitions() const { diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp index fdba82764..d44b2ce7c 100644 --- a/src/mbgl/style/style_layer.hpp +++ b/src/mbgl/style/style_layer.hpp @@ -3,15 +3,16 @@ #include #include -#include #include #include +#include #include #include #include #include +#include #include #include @@ -24,16 +25,13 @@ class StyleBucket; class StyleLayer : public util::noncopyable { public: - StyleLayer(const std::string &id, std::map &&styles); + static std::unique_ptr create(StyleLayerType); - template const T& getProperties() const { - return properties.get(); - } + virtual ~StyleLayer() = default; // Determines whether this layer is the background layer. bool isBackground() const; -public: // Checks whether this layer needs to be rendered in the given render pass. bool hasRenderPass(RenderPass) const; @@ -47,6 +45,62 @@ public: bool hasTransitions() const; +public: + // The name of this layer. + std::string id; + + StyleLayerType type = StyleLayerType::Unknown; + + // Bucket information, telling the renderer how to generate the geometries + // for this layer (feature property filters, tessellation instructions, ...). + util::ptr bucket; + + // Contains all style classes that can be applied to this layer. + std::map styles; + +protected: + // TODO: extract + template + void applyStyleProperty(PropertyKey key, T& target, const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + auto it = appliedStyle.find(key); + if (it != appliedStyle.end()) { + AppliedClassPropertyValues &applied = it->second; + // Iterate through all properties that we need to apply in order. + const PropertyEvaluator evaluator(z, zoomHistory); + for (auto& property : applied.propertyValues) { + if (now >= property.begin) { + // We overwrite the current property with the new value. + target = mapbox::util::apply_visitor(evaluator, property.value); + } else { + // Do not apply this property because its transition hasn't begun yet. + } + } + } + } + + template + void applyTransitionedStyleProperty(PropertyKey key, T& target, const float z, const TimePoint& now, const ZoomHistory& zoomHistory) { + auto it = appliedStyle.find(key); + if (it != appliedStyle.end()) { + AppliedClassPropertyValues &applied = it->second; + // Iterate through all properties that we need to apply in order. + const PropertyEvaluator evaluator(z, zoomHistory); + for (auto& property : applied.propertyValues) { + if (now >= property.end) { + // We overwrite the current property with the new value. + target = mapbox::util::apply_visitor(evaluator, property.value); + } else if (now >= property.begin) { + // We overwrite the current property partially with the new value. + float progress = std::chrono::duration(now - property.begin) / (property.end - property.begin); + target = util::interpolate(target, mapbox::util::apply_visitor(evaluator, property.value), progress); + hasPendingTransitions = true; + } else { + // Do not apply this property because its transition hasn't begun yet. + } + } + } + } + private: // Applies all properties from a class, if they haven't been applied already. void applyClassProperties(ClassID class_id, std::set &already_applied, @@ -54,30 +108,11 @@ private: // Sets the properties of this object by evaluating all pending transitions and // aplied classes in order. - template void applyStyleProperties(float z, const TimePoint& now, const ZoomHistory &zoomHistory); - template void applyStyleProperty(PropertyKey key, T &, float z, const TimePoint& now, const ZoomHistory &zoomHistory); - template void applyTransitionedStyleProperty(PropertyKey key, T &, float z, const TimePoint& now, const ZoomHistory &zoomHistory); + virtual RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) = 0; // Removes all expired style transitions. void cleanupAppliedStyleProperties(const TimePoint& now); - // Checks whether the layer is currently visible at all. - bool isVisible() const; - -public: - // The name of this layer. - const std::string id; - - StyleLayerType type = StyleLayerType::Unknown; - - // Bucket information, telling the renderer how to generate the geometries - // for this layer (feature property filters, tessellation instructions, ...). - util::ptr bucket; - - // Contains all style classes that can be applied to this layer. - const std::map styles; - -private: // For every property, stores a list of applied property values, with // optional transition times. std::map appliedStyle; @@ -86,12 +121,6 @@ private: // evaluated StyleProperties object and is updated accordingly. RenderPass passes = RenderPass::None; -public: - // Stores the evaluated, and cascaded styling information, specific to this - // layer's type. - StyleProperties properties; - -private: // Stores whether there are pending transitions to be done on each update. bool hasPendingTransitions = false; }; diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index fac530660..538015ead 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -632,6 +632,8 @@ template<> StyleParser::Result>> St #pragma mark - Parse Layers void StyleParser::parseLayers(JSVal value) { + std::vector ids; + if (!value.IsArray()) { Log::Warning(Event::ParseStyle, "layers must be an array"); return; @@ -662,53 +664,151 @@ void StyleParser::parseLayers(JSVal value) { continue; } - // Parse paints already, as they can't be inherited anyway. - std::map paints; - parsePaints(layerValue, paints); - - util::ptr layer = std::make_shared(layerID, std::move(paints)); - - layers.emplace_back(layer); - layersMap.emplace(layerID, std::pair> { layerValue, layer }); + layersMap.emplace(layerID, std::pair> { layerValue, nullptr }); + ids.push_back(layerID); } - for (auto& pair : layersMap) { - parseLayer(pair.second); + for (const auto& id : ids) { + auto it = layersMap.find(id); + + parseLayer(it->first, + it->second.first, + it->second.second); + + if (it->second.second) { + layers.emplace_back(it->second.second); + } } } -void StyleParser::parseLayer(std::pair> &pair) { - JSVal value = pair.first; - util::ptr &layer = pair.second; - - if (value.HasMember("type")) { - JSVal type = value["type"]; - if (!type.IsString()) { - Log::Warning(Event::ParseStyle, "layer type of '%s' must be a string", layer->id.c_str()); - } else { - layer->type = StyleLayerTypeClass(std::string { type.GetString(), type.GetStringLength() }); - } - } - - if (layer->bucket) { +void StyleParser::parseLayer(const std::string& id, JSVal value, util::ptr& layer) { + if (layer) { // Skip parsing this again. We already have a valid layer definition. return; } // Make sure we have not previously attempted to parse this layer. - if (std::find(stack.begin(), stack.end(), layer.get()) != stack.end()) { - Log::Warning(Event::ParseStyle, "layer reference of '%s' is circular", layer->id.c_str()); + if (std::find(stack.begin(), stack.end(), id) != stack.end()) { + Log::Warning(Event::ParseStyle, "layer reference of '%s' is circular", id.c_str()); return; } if (value.HasMember("ref")) { - // This layer is referencing another layer. Inherit the bucket from that layer, if we - // already parsed it. - parseReference(value["ref"], layer); + // This layer is referencing another layer. Recursively parse that layer. + JSVal refVal = value["ref"]; + if (!refVal.IsString()) { + Log::Warning(Event::ParseStyle, "layer ref of '%s' must be a string", id.c_str()); + return; + } + + const std::string ref { refVal.GetString(), refVal.GetStringLength() }; + auto it = layersMap.find(ref); + if (it == layersMap.end()) { + Log::Warning(Event::ParseStyle, "layer '%s' references unknown layer %s", id.c_str(), ref.c_str()); + return; + } + + // Recursively parse the referenced layer. + stack.push_front(id); + parseLayer(it->first, + it->second.first, + it->second.second); + stack.pop_front(); + + util::ptr reference = it->second.second; + if (!reference) { + return; + } + + layer = StyleLayer::create(reference->type); + layer->id = id; + layer->type = reference->type; + layer->bucket = reference->bucket; + } else { // Otherwise, parse the source/source-layer/filter/render keys to form the bucket. - parseBucket(value, layer); + if (!value.HasMember("type")) { + Log::Warning(Event::ParseStyle, "layer '%s' is missing a type", id.c_str()); + return; + } + + JSVal typeVal = value["type"]; + if (!typeVal.IsString()) { + Log::Warning(Event::ParseStyle, "layer '%s' has an invalid type", id.c_str()); + return; + } + + std::string type { typeVal.GetString(), typeVal.GetStringLength() }; + StyleLayerType typeClass = StyleLayerTypeClass(type); + layer = StyleLayer::create(typeClass); + + if (!layer) { + Log::Warning(Event::ParseStyle, "unknown type '%s' for layer '%s'", type.c_str(), id.c_str()); + return; + } + + layer->id = id; + layer->type = typeClass; + + util::ptr bucket = std::make_shared(layer->type); + + // We name the buckets according to the layer that defined it. + bucket->name = layer->id; + + if (value.HasMember("source")) { + JSVal value_source = value["source"]; + if (value_source.IsString()) { + bucket->source = { value_source.GetString(), value_source.GetStringLength() }; + auto source_it = sourcesMap.find(bucket->source); + if (source_it == sourcesMap.end()) { + Log::Warning(Event::ParseStyle, "can't find source '%s' required for layer '%s'", bucket->source.c_str(), layer->id.c_str()); + } + } else { + Log::Warning(Event::ParseStyle, "source of layer '%s' must be a string", layer->id.c_str()); + } + } + + if (value.HasMember("source-layer")) { + JSVal value_source_layer = value["source-layer"]; + if (value_source_layer.IsString()) { + bucket->source_layer = { value_source_layer.GetString(), value_source_layer.GetStringLength() }; + } else { + Log::Warning(Event::ParseStyle, "source-layer of layer '%s' must be a string", layer->id.c_str()); + } + } + + if (value.HasMember("filter")) { + bucket->filter = parseFilterExpression(value["filter"]); + } + + if (value.HasMember("layout")) { + parseLayout(value["layout"], bucket); + } + + if (value.HasMember("minzoom")) { + JSVal min_zoom = value["minzoom"]; + if (min_zoom.IsNumber()) { + bucket->min_zoom = min_zoom.GetDouble(); + } else { + Log::Warning(Event::ParseStyle, "minzoom of layer %s must be numeric", layer->id.c_str()); + } + } + + if (value.HasMember("maxzoom")) { + JSVal max_zoom = value["maxzoom"]; + if (max_zoom.IsNumber()) { + bucket->max_zoom = max_zoom.GetDouble(); + } else { + Log::Warning(Event::ParseStyle, "maxzoom of layer %s must be numeric", layer->id.c_str()); + } + } + + layer->bucket = bucket; } + + std::map paints; + parsePaints(value, paints); + layer->styles = std::move(paints); } #pragma mark - Parse Styles @@ -860,88 +960,6 @@ void StyleParser::parseLayout(JSVal value, util::ptr &bucket) { } -void StyleParser::parseReference(JSVal value, util::ptr &layer) { - if (!value.IsString()) { - Log::Warning(Event::ParseStyle, "layer ref of '%s' must be a string", layer->id.c_str()); - return; - } - const std::string ref { value.GetString(), value.GetStringLength() }; - auto it = layersMap.find(ref); - if (it == layersMap.end()) { - Log::Warning(Event::ParseStyle, "layer '%s' references unknown layer %s", layer->id.c_str(), ref.c_str()); - // We cannot parse this layer further. - return; - } - - // Recursively parse the referenced layer. - stack.push_front(layer.get()); - parseLayer(it->second); - stack.pop_front(); - - util::ptr reference = it->second.second; - layer->type = reference->type; - layer->bucket = reference->bucket; -} - -#pragma mark - Parse Bucket - -void StyleParser::parseBucket(JSVal value, util::ptr &layer) { - util::ptr bucket = std::make_shared(layer->type); - - // We name the buckets according to the layer that defined it. - bucket->name = layer->id; - - if (value.HasMember("source")) { - JSVal value_source = value["source"]; - if (value_source.IsString()) { - bucket->source = { value_source.GetString(), value_source.GetStringLength() }; - auto source_it = sourcesMap.find(bucket->source); - if (source_it == sourcesMap.end()) { - Log::Warning(Event::ParseStyle, "can't find source '%s' required for layer '%s'", bucket->source.c_str(), layer->id.c_str()); - } - } else { - Log::Warning(Event::ParseStyle, "source of layer '%s' must be a string", layer->id.c_str()); - } - } - - if (value.HasMember("source-layer")) { - JSVal value_source_layer = value["source-layer"]; - if (value_source_layer.IsString()) { - bucket->source_layer = { value_source_layer.GetString(), value_source_layer.GetStringLength() }; - } else { - Log::Warning(Event::ParseStyle, "source-layer of layer '%s' must be a string", layer->id.c_str()); - } - } - - if (value.HasMember("filter")) { - bucket->filter = parseFilterExpression(value["filter"]); - } - - if (value.HasMember("layout")) { - parseLayout(value["layout"], bucket); - } - - if (value.HasMember("minzoom")) { - JSVal min_zoom = value["minzoom"]; - if (min_zoom.IsNumber()) { - bucket->min_zoom = min_zoom.GetDouble(); - } else { - Log::Warning(Event::ParseStyle, "minzoom of layer %s must be numeric", layer->id.c_str()); - } - } - - if (value.HasMember("maxzoom")) { - JSVal max_zoom = value["maxzoom"]; - if (max_zoom.IsNumber()) { - bucket->max_zoom = max_zoom.GetDouble(); - } else { - Log::Warning(Event::ParseStyle, "maxzoom of layer %s must be numeric", layer->id.c_str()); - } - } - - layer->bucket = bucket; -} - void StyleParser::parseSprite(JSVal value) { if (value.IsString()) { sprite = { value.GetString(), value.GetStringLength() }; diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp index 22dc4f627..2f6063e1f 100644 --- a/src/mbgl/style/style_parser.hpp +++ b/src/mbgl/style/style_parser.hpp @@ -54,11 +54,9 @@ public: private: void parseSources(JSVal value); void parseLayers(JSVal value); - void parseLayer(std::pair> &pair); + void parseLayer(const std::string& id, JSVal value, util::ptr&); void parsePaints(JSVal value, std::map &paints); void parsePaint(JSVal, ClassProperties &properties); - void parseReference(JSVal value, util::ptr &layer); - void parseBucket(JSVal value, util::ptr &layer); void parseLayout(JSVal value, util::ptr &bucket); void parseSprite(JSVal value); void parseGlyphURL(JSVal value); @@ -106,8 +104,8 @@ private: std::unordered_map sourcesMap; std::unordered_map>> layersMap; - // Store a stack of layers we're parsing right now. This is to prevent reference cycles. - std::forward_list stack; + // Store a stack of layer IDs we're parsing right now. This is to prevent reference cycles. + std::forward_list stack; // Base URL of the sprite image. std::string sprite; diff --git a/test/api/annotations.cpp b/test/api/annotations.cpp index 907f0446b..415b2ddb6 100644 --- a/test/api/annotations.cpp +++ b/test/api/annotations.cpp @@ -48,14 +48,11 @@ TEST(Annotations, LineAnnotation) { AnnotationSegments segments = {{ {{ { 0, 0 }, { 45, 45 } }} }}; - LinePaintProperties lineProperties; - lineProperties.color = {{ 255, 0, 0, 1 }}; - lineProperties.width = 5; + LinePaintProperties properties; + properties.color = {{ 255, 0, 0, 1 }}; + properties.width = 5; - StyleProperties styleProperties; - styleProperties.set(lineProperties); - - map.addShapeAnnotation(ShapeAnnotation(segments, styleProperties)); + map.addShapeAnnotation(ShapeAnnotation(segments, properties)); util::write_file("test/output/line_annotation.png", renderPNG(map)); } @@ -70,13 +67,10 @@ TEST(Annotations, FillAnnotation) { AnnotationSegments segments = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; - FillPaintProperties fillProperties; - fillProperties.fill_color = {{ 255, 0, 0, 1 }}; + FillPaintProperties properties; + properties.fill_color = {{ 255, 0, 0, 1 }}; - StyleProperties styleProperties; - styleProperties.set(fillProperties); - - map.addShapeAnnotation(ShapeAnnotation(segments, styleProperties)); + map.addShapeAnnotation(ShapeAnnotation(segments, properties)); util::write_file("test/output/fill_annotation.png", renderPNG(map)); } @@ -109,13 +103,10 @@ TEST(Annotations, NonImmediateAdd) { AnnotationSegments segments = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; - FillPaintProperties fillProperties; - fillProperties.fill_color = {{ 255, 0, 0, 1 }}; + FillPaintProperties properties; + properties.fill_color = {{ 255, 0, 0, 1 }}; - StyleProperties styleProperties; - styleProperties.set(fillProperties); - - map.addShapeAnnotation(ShapeAnnotation(segments, styleProperties)); + map.addShapeAnnotation(ShapeAnnotation(segments, properties)); util::write_file("test/output/non_immediate_add.png", renderPNG(map)); } @@ -143,16 +134,13 @@ TEST(Annotations, RemoveShape) { AnnotationSegments segments = {{ {{ { 0, 0 }, { 45, 45 } }} }}; - LinePaintProperties lineProperties; - lineProperties.color = {{ 255, 0, 0, 1 }}; - lineProperties.width = 5; - - StyleProperties styleProperties; - styleProperties.set(lineProperties); + LinePaintProperties properties; + properties.color = {{ 255, 0, 0, 1 }}; + properties.width = 5; Map map(view, fileSource, MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"), ""); - uint32_t shape = map.addShapeAnnotation(ShapeAnnotation(segments, styleProperties)); + uint32_t shape = map.addShapeAnnotation(ShapeAnnotation(segments, properties)); renderPNG(map); diff --git a/test/fixtures/style_parser/text-size.style.json b/test/fixtures/style_parser/text-size.style.json index 46dd33e3c..8c0076197 100644 --- a/test/fixtures/style_parser/text-size.style.json +++ b/test/fixtures/style_parser/text-size.style.json @@ -9,7 +9,7 @@ }, "layers": [{ "id": "country_label", - "type": "text", + "type": "symbol", "source": "mapbox", "source-layer": "country_label", "filter": ["==", "$type", "Point"],