[core] Introduce StyleLayer subclasses

This commit is contained in:
John Firebaugh
2015-10-19 15:24:22 -07:00
parent df89de5cc5
commit 3afc8b4a29
40 changed files with 652 additions and 539 deletions

View File

@@ -340,7 +340,7 @@ mbgl::AnnotationSegment annotation_segment_from_latlng_jlist(JNIEnv *env, jobjec
return segment;
}
std::pair<mbgl::AnnotationSegment, mbgl::StyleProperties> annotation_std_pair_from_polygon_jobject(JNIEnv *env, jobject polygon) {
std::pair<mbgl::AnnotationSegment, mbgl::ShapeAnnotation::Properties> 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<mbgl::AnnotationSegment, mbgl::StyleProperties> 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<float>(rS) / 255.0f, static_cast<float>(gS) / 255.0f, static_cast<float>(bS) / 255.0f, static_cast<float>(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<float>(r) / 255.0f, static_cast<float>(g) / 255.0f, static_cast<float>(b) / 255.0f, static_cast<float>(a) / 255.0f }};
@@ -964,7 +964,7 @@ jlong JNICALL nativeAddPolygon(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
std::vector<mbgl::ShapeAnnotation> shapes;
std::pair<mbgl::AnnotationSegment, mbgl::StyleProperties> segment = annotation_std_pair_from_polygon_jobject(env, polygon);
std::pair<mbgl::AnnotationSegment, mbgl::ShapeAnnotation::Properties> 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<jobject>(env->GetObjectArrayElement(jarray, i));
std::pair<mbgl::AnnotationSegment, mbgl::StyleProperties> segment = annotation_std_pair_from_polygon_jobject(env, polygon);
std::pair<mbgl::AnnotationSegment, mbgl::ShapeAnnotation::Properties> segment = annotation_std_pair_from_polygon_jobject(env, polygon);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
return nullptr;

View File

@@ -6,6 +6,8 @@
#include <mbgl/util/geo.hpp>
#include <mapbox/variant.hpp>
namespace mbgl {
using AnnotationSegment = std::vector<LatLng>;
@@ -13,12 +15,14 @@ using AnnotationSegments = std::vector<AnnotationSegment>;
class ShapeAnnotation {
public:
inline ShapeAnnotation(const AnnotationSegments& segments_, const StyleProperties& styleProperties_)
using Properties = mapbox::util::variant<FillPaintProperties, LinePaintProperties>;
inline ShapeAnnotation(const AnnotationSegments& segments_, const Properties& styleProperties_)
: segments(segments_), styleProperties(styleProperties_) {
}
const AnnotationSegments segments;
const StyleProperties styleProperties;
const Properties styleProperties;
};
}

View File

@@ -1,14 +1,10 @@
#ifndef MBGL_STYLE_STYLE_PROPERTIES
#define MBGL_STYLE_STYLE_PROPERTIES
#include <mapbox/variant.hpp>
#include <mbgl/style/types.hpp>
#include <array>
#include <string>
#include <type_traits>
#include <memory>
#include <vector>
namespace mbgl {
@@ -169,22 +165,16 @@ public:
float opacity = 1.0f;
Color color = {{ 0, 0, 0, 1 }};
Faded<std::string> 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

View File

@@ -223,11 +223,8 @@ void GLFWView::addRandomPointAnnotations(int count) {
void GLFWView::addRandomShapeAnnotations(int count) {
std::vector<mbgl::ShapeAnnotation> shapes;
mbgl::FillPaintProperties fillProperties;
fillProperties.opacity = .1;
mbgl::StyleProperties properties;
properties.set<mbgl::FillPaintProperties>(fillProperties);
mbgl::FillPaintProperties properties;
properties.opacity = .1;
for (int i = 0; i < count; i++) {
mbgl::AnnotationSegment triangle;

View File

@@ -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]])
{

View File

@@ -2,7 +2,7 @@
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/layer/symbol_layer.hpp>
#include <boost/function_output_iterator.hpp>
@@ -112,20 +112,19 @@ void AnnotationManager::updateStyle(Style& style) {
source->enabled = true;
style.addSource(std::move(source));
std::map<ClassID, ClassProperties> pointPaints;
pointPaints.emplace(ClassID::Default, ClassProperties());
std::unique_ptr<StyleLayer> pointLayer = std::make_unique<StyleLayer>(PointLayerID, std::move(pointPaints));
pointLayer->type = StyleLayerType::Symbol;
std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>();
layer->id = PointLayerID;
layer->type = StyleLayerType::Symbol;
layer->styles.emplace(ClassID::Default, ClassProperties());
util::ptr<StyleBucket> pointBucket = std::make_shared<StyleBucket>(pointLayer->type);
pointBucket->name = pointLayer->id;
pointBucket->source = SourceID;
pointBucket->source_layer = PointLayerID;
pointBucket->layout.set(PropertyKey::IconImage, ConstantFunction<std::string>("{sprite}"));
pointBucket->layout.set(PropertyKey::IconAllowOverlap, ConstantFunction<bool>(true));
layer->bucket = std::make_shared<StyleBucket>(layer->type);
layer->bucket->name = layer->id;
layer->bucket->source = SourceID;
layer->bucket->source_layer = PointLayerID;
layer->bucket->layout.set(PropertyKey::IconImage, ConstantFunction<std::string>("{sprite}"));
layer->bucket->layout.set(PropertyKey::IconAllowOverlap, ConstantFunction<bool>(true));
pointLayer->bucket = pointBucket;
style.addLayer(std::move(pointLayer));
style.addLayer(std::move(layer));
}
for (const auto& shape : shapeAnnotations) {

View File

@@ -6,7 +6,8 @@
#include <mbgl/util/string.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/layer/line_layer.hpp>
#include <mbgl/layer/fill_layer.hpp>
namespace mbgl {
@@ -55,35 +56,47 @@ void ShapeAnnotationImpl::updateStyle(Style& style) {
if (style.getLayer(layerID))
return;
ClassProperties paintProperties;
if (shape.styleProperties.is<LinePaintProperties>()) {
const LinePaintProperties& lineProperties = shape.styleProperties.get<LinePaintProperties>();
paintProperties.set(PropertyKey::LineOpacity, ConstantFunction<float>(lineProperties.opacity));
paintProperties.set(PropertyKey::LineWidth, ConstantFunction<float>(lineProperties.width));
paintProperties.set(PropertyKey::LineColor, ConstantFunction<Color>(lineProperties.color));
const LinePaintProperties& properties = shape.styleProperties.get<LinePaintProperties>();
std::unique_ptr<LineLayer> layer = std::make_unique<LineLayer>();
layer->id = layerID;
layer->type = StyleLayerType::Line;
ClassProperties paintProperties;
paintProperties.set(PropertyKey::LineOpacity, ConstantFunction<float>(properties.opacity));
paintProperties.set(PropertyKey::LineWidth, ConstantFunction<float>(properties.width));
paintProperties.set(PropertyKey::LineColor, ConstantFunction<Color>(properties.color));
layer->styles.emplace(ClassID::Default, std::move(paintProperties));
layer->bucket = std::make_shared<StyleBucket>(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>(JoinType::Round));
style.addLayer(std::move(layer), AnnotationManager::PointLayerID);
} else if (shape.styleProperties.is<FillPaintProperties>()) {
const FillPaintProperties& fillProperties = shape.styleProperties.get<FillPaintProperties>();
paintProperties.set(PropertyKey::FillOpacity, ConstantFunction<float>(fillProperties.opacity));
paintProperties.set(PropertyKey::FillColor, ConstantFunction<Color>(fillProperties.fill_color));
paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction<Color>(fillProperties.stroke_color));
const FillPaintProperties& properties = shape.styleProperties.get<FillPaintProperties>();
std::unique_ptr<FillLayer> layer = std::make_unique<FillLayer>();
layer->id = layerID;
layer->type = StyleLayerType::Fill;
ClassProperties paintProperties;
paintProperties.set(PropertyKey::FillOpacity, ConstantFunction<float>(properties.opacity));
paintProperties.set(PropertyKey::FillColor, ConstantFunction<Color>(properties.fill_color));
paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction<Color>(properties.stroke_color));
layer->styles.emplace(ClassID::Default, std::move(paintProperties));
layer->bucket = std::make_shared<StyleBucket>(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<ClassID, ClassProperties> shapePaints;
shapePaints.emplace(ClassID::Default, std::move(paintProperties));
std::unique_ptr<StyleLayer> shapeLayer = std::make_unique<StyleLayer>(layerID, std::move(shapePaints));
shapeLayer->type = (shape.styleProperties.is<LinePaintProperties>() ? StyleLayerType::Line : StyleLayerType::Fill);
util::ptr<StyleBucket> shapeBucket = std::make_shared<StyleBucket>(shapeLayer->type);
shapeBucket->name = shapeLayer->id;
shapeBucket->source = AnnotationManager::SourceID;
shapeBucket->source_layer = shapeLayer->id;
if (shape.styleProperties.is<LinePaintProperties>()) {
shapeBucket->layout.set(PropertyKey::LineJoin, ConstantFunction<JoinType>(JoinType::Round));
}
shapeLayer->bucket = shapeBucket;
style.addLayer(std::move(shapeLayer), AnnotationManager::PointLayerID);
}
void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile) {

View File

@@ -6,6 +6,7 @@
#include <mbgl/util/geo.hpp>
#include <mbgl/util/geojsonvt/geojsonvt.hpp>
#include <memory>
#include <string>
#include <map>

View File

@@ -0,0 +1,12 @@
#include <mbgl/layer/background_layer.hpp>
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;
}
}

View File

@@ -0,0 +1,18 @@
#ifndef MBGL_BACKGROUND_LAYER
#define MBGL_BACKGROUND_LAYER
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
namespace mbgl {
class BackgroundLayer : public StyleLayer {
public:
RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override;
BackgroundPaintProperties properties;
};
}
#endif

View File

@@ -0,0 +1,15 @@
#include <mbgl/layer/circle_layer.hpp>
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;
}
}

View File

@@ -0,0 +1,18 @@
#ifndef MBGL_CIRCLE_LAYER
#define MBGL_CIRCLE_LAYER
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
namespace mbgl {
class CircleLayer : public StyleLayer {
public:
RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override;
CirclePaintProperties properties;
};
}
#endif

View File

@@ -0,0 +1,29 @@
#include <mbgl/layer/fill_layer.hpp>
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;
}
}

View File

@@ -0,0 +1,18 @@
#ifndef MBGL_FILL_LAYER
#define MBGL_FILL_LAYER
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
namespace mbgl {
class FillLayer : public StyleLayer {
public:
RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override;
FillPaintProperties properties;
};
}
#endif

View File

@@ -0,0 +1,22 @@
#include <mbgl/layer/line_layer.hpp>
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;
}
}

View File

@@ -0,0 +1,18 @@
#ifndef MBGL_LINE_LAYER
#define MBGL_LINE_LAYER
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
namespace mbgl {
class LineLayer : public StyleLayer {
public:
RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override;
LinePaintProperties properties;
};
}
#endif

View File

@@ -0,0 +1,16 @@
#include <mbgl/layer/raster_layer.hpp>
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;
}
}

View File

@@ -0,0 +1,18 @@
#ifndef MBGL_RASTER_LAYER
#define MBGL_RASTER_LAYER
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
namespace mbgl {
class RasterLayer : public StyleLayer {
public:
RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override;
RasterPaintProperties properties;
};
}
#endif

View File

@@ -0,0 +1,39 @@
#include <mbgl/layer/symbol_layer.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/style/property_evaluator.hpp>
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<float> 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<float> evaluator(z, zoomHistory);
properties.text.size = mapbox::util::apply_visitor(evaluator, it->second);
}
return properties.isVisible() ? RenderPass::Translucent : RenderPass::None;
}
}

View File

@@ -0,0 +1,18 @@
#ifndef MBGL_SYMBOL_LAYER
#define MBGL_SYMBOL_LAYER
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
namespace mbgl {
class SymbolLayer : public StyleLayer {
public:
RenderPass applyStyleProperties(float z, const TimePoint& now, const ZoomHistory&) override;
SymbolPaintProperties properties;
};
}
#endif

View File

@@ -2,6 +2,7 @@
#include <mbgl/map/tile_worker.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/property_evaluator.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/line_bucket.hpp>
@@ -63,29 +64,6 @@ void TileWorker::redoPlacement(float angle, float pitch, bool collisionDebug) {
}
}
template <typename T>
struct PropertyEvaluator {
typedef T result_type;
explicit PropertyEvaluator(float z_) : z(z_) {}
template <typename P, typename std::enable_if<std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &value) const {
return value;
}
T operator()(const Function<T> &value) const {
return mapbox::util::apply_visitor(FunctionEvaluator<T>(z), value);
}
template <typename P, typename std::enable_if<!std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &) const {
return T();
}
private:
const float z;
};
template <typename T>
void applyLayoutProperty(PropertyKey key, const ClassProperties &classProperties, T &target, const float z) {
auto it = classProperties.properties.find(key);

View File

@@ -2,6 +2,7 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/shader/circle_shader.hpp>
#include <mbgl/layer/circle_layer.hpp>
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<const CircleLayer&>(layer), id, matrix);
}
bool CircleBucket::hasData() const {

View File

@@ -1,5 +1,6 @@
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/geometry/fill_buffer.hpp>
#include <mbgl/layer/fill_layer.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/style/style.hpp>
@@ -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<const FillLayer&>(layer), id, matrix);
}
bool FillBucket::hasData() const {

View File

@@ -1,5 +1,5 @@
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/layer/line_layer.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/style/style.hpp>
@@ -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<const LineLayer&>(layer), id, matrix);
}
bool LineBucket::hasData() const {

View File

@@ -12,6 +12,8 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/layer/background_layer.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
@@ -286,7 +288,7 @@ void Painter::renderPass(RenderPass pass_,
}
} else {
MBGL_DEBUG_GROUP("background");
renderBackground(item.layer);
renderBackground(dynamic_cast<const BackgroundLayer&>(item.layer));
}
}
@@ -303,20 +305,18 @@ std::vector<RenderItem> 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<BackgroundPaintProperties>()) {
auto& props = layer.properties.get<BackgroundPaintProperties>();
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<const BackgroundLayer&>(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<RenderItem> 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<BackgroundPaintProperties>();
const BackgroundPaintProperties& properties = layer.properties;
if (!properties.image.to.empty()) {
if ((properties.opacity >= 1.0f) != (pass == RenderPass::Opaque))

View File

@@ -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);

View File

@@ -1,9 +1,7 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
#include <mbgl/layer/circle_layer.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/map/tile_id.hpp>
@@ -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<CirclePaintProperties>();
const CirclePaintProperties& properties = layer.properties;
mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);
Color color = properties.color;

View File

@@ -1,8 +1,6 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
#include <mbgl/layer/fill_layer.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
@@ -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<FillPaintProperties>();
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;

View File

@@ -1,8 +1,6 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
#include <mbgl/layer/line_layer.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/map/map_data.hpp>
@@ -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<LinePaintProperties>();
const auto& properties = layer.properties;
const auto& layout = bucket.layout;
// the distance over which the line edge fades out.

View File

@@ -1,15 +1,15 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/platform/gl.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/layer/raster_layer.hpp>
#include <mbgl/shader/raster_shader.hpp>
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<RasterPaintProperties>();
const RasterPaintProperties& properties = layer.properties;
if (bucket.hasData()) {
useProgram(rasterShader->program);

View File

@@ -1,7 +1,6 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
#include <mbgl/layer/symbol_layer.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
#include <mbgl/shader/sdf_shader.hpp>
@@ -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<SymbolPaintProperties>();
const auto& properties = layer.properties;
const auto& layout = bucket.layout;
config.depthMask = GL_FALSE;

View File

@@ -1,4 +1,5 @@
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/layer/raster_layer.hpp>
#include <mbgl/shader/raster_shader.hpp>
#include <mbgl/renderer/painter.hpp>
@@ -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<const RasterLayer&>(layer), id, matrix);
}
bool RasterBucket::setImage(std::unique_ptr<util::Image> image) {

View File

@@ -1,4 +1,5 @@
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/layer/symbol_layer.hpp>
#include <mbgl/map/geometry_tile.hpp>
#include <mbgl/style/style_properties.hpp>
#include <mbgl/annotation/sprite_image.hpp>
@@ -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<const SymbolLayer&>(layer), id, matrix);
}
bool SymbolBucket::hasData() const { return hasTextData() || hasIconData() || !symbolInstances.empty(); }

View File

@@ -0,0 +1,45 @@
#ifndef MBGL_PROPERTY_EVALUATOR
#define MBGL_PROPERTY_EVALUATOR
#include <mbgl/style/zoom_history.hpp>
#include <mbgl/style/function_properties.hpp>
#include <mbgl/style/piecewisefunction_properties.hpp>
namespace mbgl {
struct ZoomHistory;
template <typename T>
class PropertyEvaluator {
public:
typedef T result_type;
PropertyEvaluator(float z_) : z(z_), zoomHistory() {}
PropertyEvaluator(float z_, const ZoomHistory& zoomHistory_) : z(z_), zoomHistory(zoomHistory_) {}
template <typename P, typename std::enable_if<std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &value) const {
return value;
}
T operator()(const Function<T>& value) const {
return mapbox::util::apply_visitor(FunctionEvaluator<T>(z), value);
}
T operator()(const PiecewiseConstantFunction<T>& value) const {
return value.evaluate(z, zoomHistory);
}
template <typename P, typename std::enable_if<!std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &) const {
return T();
}
private:
const float z;
ZoomHistory zoomHistory;
};
}
#endif

View File

@@ -1,35 +1,38 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/style/property_fallback.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/layer/fill_layer.hpp>
#include <mbgl/layer/line_layer.hpp>
#include <mbgl/layer/circle_layer.hpp>
#include <mbgl/layer/symbol_layer.hpp>
#include <mbgl/layer/raster_layer.hpp>
#include <mbgl/layer/background_layer.hpp>
namespace mbgl {
StyleLayer::StyleLayer(const std::string &id_, std::map<ClassID, ClassProperties> &&styles_)
: id(id_), styles(std::move(styles_)) {}
std::unique_ptr<StyleLayer> StyleLayer::create(StyleLayerType type) {
switch (type) {
case StyleLayerType::Fill:
return std::make_unique<FillLayer>();
case StyleLayerType::Line:
return std::make_unique<LineLayer>();
case StyleLayerType::Circle:
return std::make_unique<CircleLayer>();
case StyleLayerType::Symbol:
return std::make_unique<SymbolLayer>();
case StyleLayerType::Raster:
return std::make_unique<RasterLayer>();
case StyleLayerType::Background:
return std::make_unique<BackgroundLayer>();
default:
return nullptr;
}
}
bool StyleLayer::isBackground() const {
return type == StyleLayerType::Background;
}
bool StyleLayer::isVisible() const {
switch (type) {
case StyleLayerType::Fill:
return getProperties<FillPaintProperties>().isVisible();
case StyleLayerType::Line:
return getProperties<LinePaintProperties>().isVisible();
case StyleLayerType::Circle:
return getProperties<CirclePaintProperties>().isVisible();
case StyleLayerType::Symbol:
return getProperties<SymbolPaintProperties>().isVisible();
case StyleLayerType::Raster:
return getProperties<RasterPaintProperties>().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 <typename T>
struct PropertyEvaluator {
typedef T result_type;
PropertyEvaluator(float z_, const ZoomHistory &zoomHistory_) : z(z_), zoomHistory(zoomHistory_) {}
template <typename P, typename std::enable_if<std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &value) const {
return value;
}
T operator()(const Function<T> &value) const {
return mapbox::util::apply_visitor(FunctionEvaluator<T>(z), value);
}
T operator()(const PiecewiseConstantFunction<T> &value) const {
return value.evaluate(z, zoomHistory);
}
template <typename P, typename std::enable_if<!std::is_convertible<P, T>::value, int>::type = 0>
T operator()(const P &) const {
return T();
}
private:
const float z;
const ZoomHistory &zoomHistory;
};
template <typename T>
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<T> 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 <typename T>
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<T> 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<float>(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<FillPaintProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<FillPaintProperties>();
FillPaintProperties& fill = properties.get<FillPaintProperties>();
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<LinePaintProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<LinePaintProperties>();
LinePaintProperties& line = properties.get<LinePaintProperties>();
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<CirclePaintProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<CirclePaintProperties>();
CirclePaintProperties& circle = properties.get<CirclePaintProperties>();
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<SymbolPaintProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<SymbolPaintProperties>();
SymbolPaintProperties& symbol = properties.get<SymbolPaintProperties>();
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<float> 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<float> evaluator(z, zoomHistory);
symbol.text.size = mapbox::util::apply_visitor(evaluator, it->second);
}
}
template <>
void StyleLayer::applyStyleProperties<RasterPaintProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<RasterPaintProperties>();
RasterPaintProperties& raster = properties.get<RasterPaintProperties>();
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<BackgroundPaintProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<BackgroundPaintProperties>();
BackgroundPaintProperties& background = properties.get<BackgroundPaintProperties>();
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<FillPaintProperties>(z, now, zoomHistory); break;
case StyleLayerType::Line: applyStyleProperties<LinePaintProperties>(z, now, zoomHistory); break;
case StyleLayerType::Circle: applyStyleProperties<CirclePaintProperties>(z, now, zoomHistory); break;
case StyleLayerType::Symbol: applyStyleProperties<SymbolPaintProperties>(z, now, zoomHistory); break;
case StyleLayerType::Raster: applyStyleProperties<RasterPaintProperties>(z, now, zoomHistory); break;
case StyleLayerType::Background: applyStyleProperties<BackgroundPaintProperties>(z, now, zoomHistory); break;
default: properties.set<std::false_type>(); break;
}
// Update the render passes when this layer is visible.
passes = RenderPass::None;
if (isVisible()) {
if (properties.is<FillPaintProperties>()) {
const FillPaintProperties &fillProperties = properties.get<FillPaintProperties>();
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 {

View File

@@ -3,15 +3,16 @@
#include <mbgl/style/class_dictionary.hpp>
#include <mbgl/style/class_properties.hpp>
#include <mbgl/style/style_properties.hpp>
#include <mbgl/style/applied_class_properties.hpp>
#include <mbgl/style/zoom_history.hpp>
#include <mbgl/style/property_evaluator.hpp>
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/interpolate.hpp>
#include <vector>
#include <string>
@@ -24,16 +25,13 @@ class StyleBucket;
class StyleLayer : public util::noncopyable {
public:
StyleLayer(const std::string &id, std::map<ClassID, ClassProperties> &&styles);
static std::unique_ptr<StyleLayer> create(StyleLayerType);
template <typename T> const T& getProperties() const {
return properties.get<T>();
}
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<StyleBucket> bucket;
// Contains all style classes that can be applied to this layer.
std::map<ClassID, ClassProperties> styles;
protected:
// TODO: extract
template <typename T>
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<T> 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 <typename T>
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<T> 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<float>(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<PropertyKey> &already_applied,
@@ -54,30 +108,11 @@ private:
// Sets the properties of this object by evaluating all pending transitions and
// aplied classes in order.
template <typename T> void applyStyleProperties(float z, const TimePoint& now, const ZoomHistory &zoomHistory);
template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, const TimePoint& now, const ZoomHistory &zoomHistory);
template <typename T> 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<const StyleBucket> bucket;
// Contains all style classes that can be applied to this layer.
const std::map<ClassID, ClassProperties> styles;
private:
// For every property, stores a list of applied property values, with
// optional transition times.
std::map<PropertyKey, AppliedClassPropertyValues> 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;
};

View File

@@ -632,6 +632,8 @@ template<> StyleParser::Result<PiecewiseConstantFunction<Faded<std::string>>> St
#pragma mark - Parse Layers
void StyleParser::parseLayers(JSVal value) {
std::vector<std::string> 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<ClassID, ClassProperties> paints;
parsePaints(layerValue, paints);
util::ptr<StyleLayer> layer = std::make_shared<StyleLayer>(layerID, std::move(paints));
layers.emplace_back(layer);
layersMap.emplace(layerID, std::pair<JSVal, util::ptr<StyleLayer>> { layerValue, layer });
layersMap.emplace(layerID, std::pair<JSVal, util::ptr<StyleLayer>> { 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<JSVal, util::ptr<StyleLayer>> &pair) {
JSVal value = pair.first;
util::ptr<StyleLayer> &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<StyleLayer>& 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<StyleLayer> 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<StyleBucket> bucket = std::make_shared<StyleBucket>(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<ClassID, ClassProperties> paints;
parsePaints(value, paints);
layer->styles = std::move(paints);
}
#pragma mark - Parse Styles
@@ -860,88 +960,6 @@ void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) {
}
void StyleParser::parseReference(JSVal value, util::ptr<StyleLayer> &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<StyleLayer> reference = it->second.second;
layer->type = reference->type;
layer->bucket = reference->bucket;
}
#pragma mark - Parse Bucket
void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) {
util::ptr<StyleBucket> bucket = std::make_shared<StyleBucket>(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() };

View File

@@ -54,11 +54,9 @@ public:
private:
void parseSources(JSVal value);
void parseLayers(JSVal value);
void parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair);
void parseLayer(const std::string& id, JSVal value, util::ptr<StyleLayer>&);
void parsePaints(JSVal value, std::map<ClassID, ClassProperties> &paints);
void parsePaint(JSVal, ClassProperties &properties);
void parseReference(JSVal value, util::ptr<StyleLayer> &layer);
void parseBucket(JSVal value, util::ptr<StyleLayer> &layer);
void parseLayout(JSVal value, util::ptr<StyleBucket> &bucket);
void parseSprite(JSVal value);
void parseGlyphURL(JSVal value);
@@ -106,8 +104,8 @@ private:
std::unordered_map<std::string, const Source*> sourcesMap;
std::unordered_map<std::string, std::pair<JSVal, util::ptr<StyleLayer>>> layersMap;
// Store a stack of layers we're parsing right now. This is to prevent reference cycles.
std::forward_list<StyleLayer *> stack;
// Store a stack of layer IDs we're parsing right now. This is to prevent reference cycles.
std::forward_list<std::string> stack;
// Base URL of the sprite image.
std::string sprite;

View File

@@ -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<LinePaintProperties>(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<FillPaintProperties>(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<FillPaintProperties>(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<LinePaintProperties>(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);

View File

@@ -9,7 +9,7 @@
},
"layers": [{
"id": "country_label",
"type": "text",
"type": "symbol",
"source": "mapbox",
"source-layer": "country_label",
"filter": ["==", "$type", "Point"],