diff options
59 files changed, 697 insertions, 180 deletions
diff --git a/include/mbgl/storage/resource.hpp b/include/mbgl/storage/resource.hpp index 2fcb3b1b78..0c2a27e9d1 100644 --- a/include/mbgl/storage/resource.hpp +++ b/include/mbgl/storage/resource.hpp @@ -13,8 +13,8 @@ struct Resource { Source, Tile, Glyphs, - JSON, - Image + SpriteImage, + SpriteJSON }; const Kind kind; diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp index 9ab528586f..23354b1a24 100644 --- a/include/mbgl/style/style_properties.hpp +++ b/include/mbgl/style/style_properties.hpp @@ -45,6 +45,20 @@ struct LineProperties { } }; +struct CircleProperties { + inline CircleProperties() {} + float radius = 5.0f; + Color color = {{ 0, 0, 0, 1 }}; + float opacity = 1.0f; + std::array<float, 2> translate = {{ 0, 0 }}; + TranslateAnchorType translateAnchor = TranslateAnchorType::Map; + float blur = 0; + + inline bool isVisible() const { + return radius > 0 && color[3] > 0 && opacity > 0; + } +}; + struct SymbolProperties { inline SymbolProperties() {} @@ -100,6 +114,7 @@ struct BackgroundProperties { typedef mapbox::util::variant< FillProperties, LineProperties, + CircleProperties, SymbolProperties, RasterProperties, BackgroundProperties, diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp index e46ece6f4a..adc13b386c 100644 --- a/include/mbgl/style/types.hpp +++ b/include/mbgl/style/types.hpp @@ -27,6 +27,7 @@ enum class StyleLayerType : uint8_t { Unknown, Fill, Line, + Circle, Symbol, Raster, Background @@ -36,6 +37,7 @@ MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, { { StyleLayerType::Unknown, "unknown" }, { StyleLayerType::Fill, "fill" }, { StyleLayerType::Line, "line" }, + { StyleLayerType::Circle, "circle" }, { StyleLayerType::Symbol, "symbol" }, { StyleLayerType::Raster, "raster" }, { StyleLayerType::Background, "background" }, diff --git a/ios/benchmark/MBXBenchViewController.mm b/ios/benchmark/MBXBenchViewController.mm index 86b4ec9cbe..0305ab853b 100644 --- a/ios/benchmark/MBXBenchViewController.mm +++ b/ios/benchmark/MBXBenchViewController.mm @@ -32,7 +32,7 @@ { [super viewDidLoad]; - NSURL* url = [[NSURL alloc] initWithString:@"asset://styles/mapbox-streets-v7.json"]; + NSURL* url = [[NSURL alloc] initWithString:@"asset://styles/streets-v8.json"]; self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds styleURL:url]; self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.mapView.delegate = self; diff --git a/ios/benchmark/fo/MBXBenchViewController.mm b/ios/benchmark/fo/MBXBenchViewController.mm index f1079d9e08..b4eb4ec3fa 100644 --- a/ios/benchmark/fo/MBXBenchViewController.mm +++ b/ios/benchmark/fo/MBXBenchViewController.mm @@ -21,7 +21,7 @@ { [super viewDidLoad]; - NSURL* url = [[NSURL alloc] initWithString:@"asset://styles/mapbox-streets-v7.json"]; + NSURL* url = [[NSURL alloc] initWithString:@"asset://styles/streets-v8.json"]; self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds accessToken:nil styleURL:url]; self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.mapView.delegate = self; diff --git a/platform/default/default_styles.cpp b/platform/default/default_styles.cpp index e25d96e4c9..9ee5414974 100644 --- a/platform/default/default_styles.cpp +++ b/platform/default/default_styles.cpp @@ -4,11 +4,11 @@ namespace mbgl { namespace util { const std::vector<std::pair<std::string, std::string>> defaultStyles = { - { "asset://styles/mapbox-streets-v7.json", "Mapbox Streets" }, - { "asset://styles/emerald-v7.json", "Emerald" }, - { "asset://styles/light-v7.json", "Light" }, - { "asset://styles/dark-v7.json", "Dark" }, - { "asset://styles/satellite-v7.json", "Satellite" } + { "asset://styles/streets-v8.json", "Mapbox Streets" }, + { "asset://styles/emerald-v8.json", "Emerald" }, + { "asset://styles/light-v8.json", "Light" }, + { "asset://styles/dark-v8.json", "Dark" }, + { "asset://styles/satellite-v8.json", "Satellite" } }; } // end namespace util diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp index 775c2a68a1..9d5d0541e8 100644 --- a/platform/default/sqlite_cache.cpp +++ b/platform/default/sqlite_cache.cpp @@ -217,7 +217,7 @@ void SQLiteCache::Impl::put(const Resource& resource, std::shared_ptr<const Resp putStmt->bind(6 /* expires */, response->expires); std::string data; - if (resource.kind != Resource::Image) { + if (resource.kind != Resource::SpriteImage) { // Do not compress images, since they are typically compressed already. data = util::compress(response->data); } diff --git a/scripts/ios/package.sh b/scripts/ios/package.sh index 56bd325ebf..26e0cc37f4 100755 --- a/scripts/ios/package.sh +++ b/scripts/ios/package.sh @@ -102,7 +102,7 @@ cp -pv LICENSE.md "${OUTPUT}/static" mkdir -p "${OUTPUT}/static/${NAME}.bundle" cp -pv platform/ios/resources/* "${OUTPUT}/static/${NAME}.bundle" mkdir -p "${OUTPUT}/static/${NAME}.bundle/styles" -cp -pv styles/styles/{dark,emerald,light,mapbox-streets,satellite}-v7.json "${OUTPUT}/static/${NAME}.bundle/styles" +cp -pv styles/styles/{dark,emerald,light,streets,satellite}-v8.json "${OUTPUT}/static/${NAME}.bundle/styles" step "Creating API Docs..." if [ -z `which appledoc` ]; then diff --git a/src/mbgl/geometry/circle_buffer.cpp b/src/mbgl/geometry/circle_buffer.cpp new file mode 100644 index 0000000000..f4b0cddec3 --- /dev/null +++ b/src/mbgl/geometry/circle_buffer.cpp @@ -0,0 +1,13 @@ +#include <mbgl/geometry/circle_buffer.hpp> + +#include <mbgl/platform/gl.hpp> + +#include <climits> + +using namespace mbgl; + +void CircleVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey) { + vertex_type *vertices = static_cast<vertex_type *>(addElement()); + vertices[0] = (x * 2) + ((ex + 1) / 2); + vertices[1] = (y * 2) + ((ey + 1) / 2); +} diff --git a/src/mbgl/geometry/circle_buffer.hpp b/src/mbgl/geometry/circle_buffer.hpp new file mode 100644 index 0000000000..cab9122e5b --- /dev/null +++ b/src/mbgl/geometry/circle_buffer.hpp @@ -0,0 +1,27 @@ +#ifndef MBGL_GEOMETRY_CIRCLE_BUFFER +#define MBGL_GEOMETRY_CIRCLE_BUFFER + +#include <mbgl/geometry/buffer.hpp> + +namespace mbgl { + +class CircleVertexBuffer : public Buffer< + 4 // 2 bytes per short * 4 of them. +> { +public: + typedef int16_t vertex_type; + + /* + * Add a vertex to this buffer + * + * @param {number} x vertex position + * @param {number} y vertex position + * @param {number} ex extrude normal + * @param {number} ey extrude normal + */ + void add(vertex_type x, vertex_type y, float ex, float ey); +}; + +} + +#endif // MBGL_GEOMETRY_CIRCLE_BUFFER diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp index 84fbce6069..d5628b05b2 100644 --- a/src/mbgl/map/sprite.cpp +++ b/src/mbgl/map/sprite.cpp @@ -9,6 +9,7 @@ #include <mbgl/util/raster.hpp> #include <mbgl/util/thread.hpp> #include <mbgl/util/uv_detail.hpp> +#include <mbgl/util/mapbox.hpp> #include <rapidjson/document.h> @@ -49,7 +50,7 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) loader = std::make_unique<Loader>(); FileSource* fs = util::ThreadContext::getFileSource(); - loader->jsonRequest = fs->request({ Resource::Kind::JSON, jsonURL }, util::RunLoop::getLoop(), + loader->jsonRequest = fs->request({ Resource::Kind::SpriteJSON, jsonURL }, util::RunLoop::getLoop(), [this, jsonURL](const Response& res) { loader->jsonRequest = nullptr; if (res.status == Response::Successful) { @@ -65,7 +66,7 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) }); loader->spriteRequest = - fs->request({ Resource::Kind::Image, spriteURL }, util::RunLoop::getLoop(), + fs->request({ Resource::Kind::SpriteImage, spriteURL }, util::RunLoop::getLoop(), [this, spriteURL](const Response& res) { loader->spriteRequest = nullptr; if (res.status == Response::Successful) { diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index dd56f33f51..a555ca7ab0 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -5,6 +5,7 @@ #include <mbgl/geometry/glyph_atlas.hpp> #include <mbgl/renderer/fill_bucket.hpp> #include <mbgl/renderer/line_bucket.hpp> +#include <mbgl/renderer/circle_bucket.hpp> #include <mbgl/renderer/symbol_bucket.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/util/constants.hpp> @@ -47,8 +48,8 @@ Bucket* TileWorker::getBucket(const StyleLayer& layer) const { TileParseResult TileWorker::parse(const GeometryTile& geometryTile) { partialParse = false; - for (const auto& layer : layers) { - parseLayer(*layer, geometryTile); + for (auto i = layers.rbegin(); i != layers.rend(); i++) { + parseLayer(**i, geometryTile); } return partialParse ? TileData::State::partial : TileData::State::parsed; @@ -57,8 +58,8 @@ TileParseResult TileWorker::parse(const GeometryTile& geometryTile) { void TileWorker::redoPlacement(float angle, bool collisionDebug) { collision->reset(angle, 0); collision->setDebug(collisionDebug); - for (const auto& layer_desc : layers) { - auto bucket = getBucket(*layer_desc); + for (auto i = layers.rbegin(); i != layers.rend(); i++) { + auto bucket = getBucket(**i); if (bucket) { bucket->placeFeatures(); } @@ -139,15 +140,22 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr std::unique_ptr<Bucket> bucket; - if (styleBucket.type == StyleLayerType::Fill) { + switch (styleBucket.type) { + case StyleLayerType::Fill: bucket = createFillBucket(*geometryLayer, styleBucket); - } else if (styleBucket.type == StyleLayerType::Line) { + break; + case StyleLayerType::Line: bucket = createLineBucket(*geometryLayer, styleBucket); - } else if (styleBucket.type == StyleLayerType::Symbol) { + break; + case StyleLayerType::Circle: + bucket = createCircleBucket(*geometryLayer, styleBucket); + break; + case StyleLayerType::Symbol: bucket = createSymbolBucket(*geometryLayer, styleBucket); - } else if (styleBucket.type == StyleLayerType::Raster) { + break; + case StyleLayerType::Raster: return; - } else { + default: Log::Warning(Event::ParseTile, "unknown bucket render type for layer '%s' (source layer '%s')", styleBucket.name.c_str(), styleBucket.source_layer.c_str()); } @@ -203,6 +211,17 @@ std::unique_ptr<Bucket> TileWorker::createLineBucket(const GeometryTileLayer& la return bucket->hasData() ? std::move(bucket) : nullptr; } +std::unique_ptr<Bucket> TileWorker::createCircleBucket(const GeometryTileLayer& layer, + const StyleBucket& bucket_desc) { + auto bucket = std::make_unique<CircleBucket>(circleVertexBuffer, + triangleElementsBuffer); + + // Circle does not have layout properties to apply. + + addBucketGeometries(bucket, layer, bucket_desc.filter); + return bucket->hasData() ? std::move(bucket) : nullptr; +} + std::unique_ptr<Bucket> TileWorker::createSymbolBucket(const GeometryTileLayer& layer, const StyleBucket& bucket_desc) { auto bucket = std::make_unique<SymbolBucket>(*collision, id.overscaling); @@ -215,14 +234,13 @@ std::unique_ptr<Bucket> TileWorker::createSymbolBucket(const GeometryTileLayer& layout.icon.rotation_alignment = RotationAlignmentType::Map; layout.text.rotation_alignment = RotationAlignmentType::Map; }; - applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, layout.min_distance, z); + applyLayoutProperty(PropertyKey::SymbolSpacing, bucket_desc.layout, layout.spacing, z); applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, layout.avoid_edges, z); applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, layout.icon.allow_overlap, z); applyLayoutProperty(PropertyKey::IconIgnorePlacement, bucket_desc.layout, layout.icon.ignore_placement, z); applyLayoutProperty(PropertyKey::IconOptional, bucket_desc.layout, layout.icon.optional, z); applyLayoutProperty(PropertyKey::IconRotationAlignment, bucket_desc.layout, layout.icon.rotation_alignment, z); - applyLayoutProperty(PropertyKey::IconMaxSize, bucket_desc.layout, layout.icon.max_size, z); applyLayoutProperty(PropertyKey::IconImage, bucket_desc.layout, layout.icon.image, z); applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, layout.icon.padding, z); applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, layout.icon.rotate, z); @@ -232,7 +250,6 @@ std::unique_ptr<Bucket> TileWorker::createSymbolBucket(const GeometryTileLayer& applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, layout.text.rotation_alignment, z); applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, layout.text.field, z); applyLayoutProperty(PropertyKey::TextFont, bucket_desc.layout, layout.text.font, z); - applyLayoutProperty(PropertyKey::TextMaxSize, bucket_desc.layout, layout.text.max_size, z); applyLayoutProperty(PropertyKey::TextMaxWidth, bucket_desc.layout, layout.text.max_width, z); applyLayoutProperty(PropertyKey::TextLineHeight, bucket_desc.layout, layout.text.line_height, z); applyLayoutProperty(PropertyKey::TextLetterSpacing, bucket_desc.layout, layout.text.letter_spacing, z); @@ -248,6 +265,11 @@ std::unique_ptr<Bucket> TileWorker::createSymbolBucket(const GeometryTileLayer& applyLayoutProperty(PropertyKey::TextOffset, bucket_desc.layout, layout.text.offset, z); applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, layout.text.allow_overlap, z); + applyLayoutProperty(PropertyKey::IconSize, bucket_desc.layout, layout.icon.size, z + 1); + applyLayoutProperty(PropertyKey::IconSize, bucket_desc.layout, layout.icon.max_size, 18); + applyLayoutProperty(PropertyKey::TextSize, bucket_desc.layout, layout.text.size, z + 1); + applyLayoutProperty(PropertyKey::TextSize, bucket_desc.layout, layout.text.max_size, 18); + if (bucket->needsDependencies(layer, bucket_desc.filter, *style.glyphStore, *style.sprite)) { partialParse = true; } diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp index da5c766506..15a5487dc9 100644 --- a/src/mbgl/map/tile_worker.hpp +++ b/src/mbgl/map/tile_worker.hpp @@ -6,6 +6,7 @@ #include <mbgl/geometry/elements_buffer.hpp> #include <mbgl/geometry/fill_buffer.hpp> #include <mbgl/geometry/line_buffer.hpp> +#include <mbgl/geometry/circle_buffer.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/ptr.hpp> #include <mbgl/style/filter_expression.hpp> @@ -52,6 +53,7 @@ private: std::unique_ptr<Bucket> createFillBucket(const GeometryTileLayer&, const StyleBucket&); std::unique_ptr<Bucket> createLineBucket(const GeometryTileLayer&, const StyleBucket&); + std::unique_ptr<Bucket> createCircleBucket(const GeometryTileLayer&, const StyleBucket&); std::unique_ptr<Bucket> createSymbolBucket(const GeometryTileLayer&, const StyleBucket&); template <class Bucket> @@ -68,6 +70,7 @@ private: FillVertexBuffer fillVertexBuffer; LineVertexBuffer lineVertexBuffer; + CircleVertexBuffer circleVertexBuffer; TriangleElementsBuffer triangleElementsBuffer; LineElementsBuffer lineElementsBuffer; diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp new file mode 100644 index 0000000000..fde04df29a --- /dev/null +++ b/src/mbgl/renderer/circle_bucket.cpp @@ -0,0 +1,92 @@ +#include <mbgl/renderer/circle_bucket.hpp> +#include <mbgl/renderer/painter.hpp> + +#include <mbgl/shader/circle_shader.hpp> + +using namespace mbgl; + +CircleBucket::CircleBucket(CircleVertexBuffer& vertexBuffer, + TriangleElementsBuffer& elementsBuffer) + : vertexBuffer_(vertexBuffer) + , elementsBuffer_(elementsBuffer) + , vertexStart_(vertexBuffer_.index()) + , elementsStart_(elementsBuffer_.index()) { +} + +CircleBucket::~CircleBucket() { + // Do not remove. header file only contains forward definitions to unique pointers. +} + +void CircleBucket::upload() { + vertexBuffer_.upload(); + elementsBuffer_.upload(); + uploaded = true; +} + +void CircleBucket::render(Painter& painter, + const StyleLayer& layer_desc, + const TileID& id, + const mat4& matrix) { + painter.renderCircle(*this, layer_desc, id, matrix); +} + +bool CircleBucket::hasData() const { + return !triangleGroups_.empty(); +} + +void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) { + for (auto& circle : geometryCollection) { + for(auto & geometry : circle) { + auto x = geometry.x; + auto y = geometry.y; + + // this geometry will be of the Point type, and we'll derive + // two triangles from it. + // + // ┌─────────┐ + // │ 4 3 │ + // │ │ + // │ 1 2 │ + // └─────────┘ + // + vertexBuffer_.add(x, y, -1, -1); // 1 + vertexBuffer_.add(x, y, 1, -1); // 2 + vertexBuffer_.add(x, y, 1, 1); // 3 + vertexBuffer_.add(x, y, -1, 1); // 4 + + if (!triangleGroups_.size() || (triangleGroups_.back()->vertex_length + 4 > 65535)) { + // Move to a new group because the old one can't hold the geometry. + triangleGroups_.emplace_back(std::make_unique<TriangleGroup>()); + } + + TriangleGroup& group = *triangleGroups_.back(); + auto index = group.vertex_length; + + // 1, 2, 3 + // 1, 4, 3 + elementsBuffer_.add(index, index + 1, index + 2); + elementsBuffer_.add(index, index + 3, index + 2); + + group.vertex_length += 4; + group.elements_length += 2; + } + } +} + +void CircleBucket::drawCircles(CircleShader& shader) { + char* vertexIndex = BUFFER_OFFSET(vertexStart_ * vertexBuffer_.itemSize); + char* elementsIndex = BUFFER_OFFSET(elementsStart_ * elementsBuffer_.itemSize); + + for (auto& group : triangleGroups_) { + assert(group); + + if (!group->elements_length) continue; + + group->array[0].bind(shader, vertexBuffer_, elementsBuffer_, vertexIndex); + + MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elementsIndex)); + + vertexIndex += group->vertex_length * vertexBuffer_.itemSize; + elementsIndex += group->elements_length * elementsBuffer_.itemSize; + } +} diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp new file mode 100644 index 0000000000..727b9fa376 --- /dev/null +++ b/src/mbgl/renderer/circle_bucket.hpp @@ -0,0 +1,46 @@ +#ifndef MBGL_RENDERER_CIRCLE_BUCKET +#define MBGL_RENDERER_CIRCLE_BUCKET + +#include <mbgl/renderer/bucket.hpp> + +#include <mbgl/map/geometry_tile.hpp> + +#include <mbgl/geometry/elements_buffer.hpp> +#include <mbgl/geometry/circle_buffer.hpp> + +#include <mbgl/style/style_bucket.hpp> +#include <mbgl/style/style_layout.hpp> + +namespace mbgl { + +class CircleVertexBuffer; +class CircleShader; + +class CircleBucket : public Bucket { + using TriangleGroup = ElementGroup<3>; + +public: + CircleBucket(CircleVertexBuffer &vertexBuffer, TriangleElementsBuffer &elementsBuffer); + ~CircleBucket() override; + + void upload() override; + void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override; + + bool hasData() const; + void addGeometry(const GeometryCollection&); + + void drawCircles(CircleShader& shader); + +private: + CircleVertexBuffer& vertexBuffer_; + TriangleElementsBuffer& elementsBuffer_; + + const size_t vertexStart_; + const size_t elementsStart_; + + std::vector<std::unique_ptr<TriangleGroup>> triangleGroups_; +}; + +} // namespace mbgl + +#endif // MBGL_RENDERER_CIRCLE_BUCKET diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 8c6cfd20bc..b55b71dcb1 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -27,6 +27,7 @@ #include <mbgl/shader/sdf_shader.hpp> #include <mbgl/shader/dot_shader.hpp> #include <mbgl/shader/box_shader.hpp> +#include <mbgl/shader/circle_shader.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/mat3.hpp> @@ -66,6 +67,7 @@ void Painter::setup() { assert(sdfGlyphShader); assert(sdfIconShader); assert(dotShader); + assert(circleShader); // Blending @@ -100,6 +102,7 @@ void Painter::setupShaders() { if (!sdfIconShader) sdfIconShader = std::make_unique<SDFIconShader>(); if (!dotShader) dotShader = std::make_unique<DotShader>(); if (!collisionBoxShader) collisionBoxShader = std::make_unique<CollisionBoxShader>(); + if (!circleShader) circleShader = std::make_unique<CircleShader>(); } void Painter::resize() { diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 06810927b7..78cf308b7b 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -38,6 +38,7 @@ struct FrameData; class DebugBucket; class FillBucket; class LineBucket; +class CircleBucket; class SymbolBucket; class RasterBucket; @@ -50,6 +51,7 @@ class LineShader; class LinejoinShader; class LineSDFShader; class LinepatternShader; +class CircleShader; class PatternShader; class IconShader; class RasterShader; @@ -100,6 +102,7 @@ public: 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); @@ -222,6 +225,7 @@ public: std::unique_ptr<SDFIconShader> sdfIconShader; std::unique_ptr<DotShader> dotShader; std::unique_ptr<CollisionBoxShader> collisionBoxShader; + std::unique_ptr<CircleShader> circleShader; StaticVertexBuffer backgroundBuffer = { { -1, -1 }, { 1, -1 }, diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp new file mode 100644 index 0000000000..0c0ac15069 --- /dev/null +++ b/src/mbgl/renderer/painter_circle.cpp @@ -0,0 +1,49 @@ +#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_layout.hpp> + +#include <mbgl/map/sprite.hpp> +#include <mbgl/map/tile_id.hpp> +#include <mbgl/map/map_data.hpp> + +#include <mbgl/shader/circle_shader.hpp> + +using namespace mbgl; + +void Painter::renderCircle(CircleBucket& bucket, + const StyleLayer& layer_desc, + const TileID& id, + const mat4& matrix) { + // Abort early. + if (pass == RenderPass::Opaque) return; + + config.stencilTest = false; + + const CircleProperties& properties = layer_desc.getProperties<CircleProperties>(); + mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor); + + Color color = properties.color; + color[0] *= properties.opacity; + color[1] *= properties.opacity; + color[2] *= properties.opacity; + color[3] *= properties.opacity; + + // Antialiasing factor: this is a minimum blur distance that serves as + // a faux-antialiasing for the circle. since blur is a ratio of the circle's + // size and the intent is to keep the blur at roughly 1px, the two + // are inversely related. + float antialiasing = 1 / data.pixelRatio / properties.radius; + + useProgram(circleShader->program); + + circleShader->u_matrix = vtxMatrix; + circleShader->u_exmatrix = projMatrix; + circleShader->u_color = color; + circleShader->u_blur = std::max(properties.blur, antialiasing); + circleShader->u_size = properties.radius; + + bucket.drawCircles(*circleShader); +} diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index af0781d2e4..5c2db77096 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -49,7 +49,7 @@ void Painter::renderSDF(SymbolBucket &bucket, sdfShader.u_texsize = texsize; // adjust min/max zooms for variable font sies - float zoomAdjust = std::log(fontSize / bucketProperties.max_size) / std::log(2); + float zoomAdjust = std::log(fontSize / bucketProperties.size) / std::log(2); sdfShader.u_zoom = (state.getNormalizedZoom() - zoomAdjust) * 10; // current zoom level @@ -69,7 +69,7 @@ void Painter::renderSDF(SymbolBucket &bucket, // We're drawing in the translucent pass which is bottom-to-top, so we need // to draw the halo first. - if (styleProperties.halo_color[3] > 0.0f) { + if (styleProperties.halo_color[3] > 0.0f && styleProperties.halo_width > 0.0f) { sdfShader.u_gamma = styleProperties.halo_blur * blurOffset / fontScale / sdfPx + gamma; if (styleProperties.opacity < 1.0f) { @@ -157,8 +157,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c ? state.getAngle() : 0; - // If layerStyle.size > bucket.info.fontSize then labels may collide - const float fontSize = properties.icon.size != 0 ? properties.icon.size : layout.icon.max_size; + const float fontSize = properties.icon.size; const float fontScale = fontSize / 1.0f; spriteAtlas->bind(state.isChanging() || layout.placement == PlacementType::Line || angleOffset != 0 || fontScale != 1 || sdf); @@ -191,7 +190,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, const StyleLayer &layer_desc, c iconShader->u_texsize = {{ float(spriteAtlas->getWidth()) / 4.0f, float(spriteAtlas->getHeight()) / 4.0f }}; // adjust min/max zooms for variable font sies - float zoomAdjust = std::log(fontSize / layout.icon.max_size) / std::log(2); + float zoomAdjust = std::log(fontSize / layout.icon.size) / std::log(2); iconShader->u_zoom = (state.getNormalizedZoom() - zoomAdjust) * 10; // current zoom level iconShader->u_fadedist = 0 * 10; diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 1ee90293d2..e8ad132c51 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -274,10 +274,11 @@ void SymbolBucket::addFeature(const std::vector<std::vector<Coordinate>> &lines, const float minScale = 0.5f; const float glyphSize = 24.0f; - const float fontScale = layout.text.max_size / glyphSize; + const float fontScale = layout.text.size / glyphSize; const float textBoxScale = collision.tilePixelRatio * fontScale; - const float iconBoxScale = collision.tilePixelRatio * layout.icon.max_size; - const float symbolSpacing = collision.tilePixelRatio * layout.min_distance; + const float textMaxBoxScale = collision.tilePixelRatio * layout.text.max_size / glyphSize; + const float iconBoxScale = collision.tilePixelRatio * layout.icon.size; + const float symbolSpacing = collision.tilePixelRatio * layout.spacing; const bool avoidEdges = layout.avoid_edges && layout.placement != PlacementType::Line; const float textPadding = layout.text.padding * collision.tilePixelRatio; const float iconPadding = layout.icon.padding * collision.tilePixelRatio; @@ -302,7 +303,7 @@ void SymbolBucket::addFeature(const std::vector<std::vector<Coordinate>> &lines, // Calculate the anchor points around which you want to place labels Anchors anchors = isLine ? - getAnchors(line, symbolSpacing, textMaxAngle, shapedText.left, shapedText.right, shapedIcon.left, shapedIcon.right, glyphSize, textBoxScale, overscaling) : + getAnchors(line, symbolSpacing, textMaxAngle, shapedText.left, shapedText.right, shapedIcon.left, shapedIcon.right, glyphSize, textMaxBoxScale, overscaling) : Anchors({ Anchor(float(line[0].x), float(line[0].y), 0, minScale) }); // For each potential label, create the placement features used to check for collisions, and the quads use for rendering. diff --git a/src/mbgl/shader/circle.fragment.glsl b/src/mbgl/shader/circle.fragment.glsl new file mode 100644 index 0000000000..7267bf81e3 --- /dev/null +++ b/src/mbgl/shader/circle.fragment.glsl @@ -0,0 +1,10 @@ +uniform vec4 u_color; +uniform float u_blur; +uniform float u_size; + +varying vec2 v_extrude; + +void main() { + float t = smoothstep(1.0 - u_blur, 1.0, length(v_extrude)); + gl_FragColor = u_color * (1.0 - t); +} diff --git a/src/mbgl/shader/circle.vertex.glsl b/src/mbgl/shader/circle.vertex.glsl new file mode 100644 index 0000000000..eeeb30abc5 --- /dev/null +++ b/src/mbgl/shader/circle.vertex.glsl @@ -0,0 +1,23 @@ +// set by gl_util +uniform float u_size; + +attribute vec2 a_pos; + +uniform mat4 u_matrix; +uniform mat4 u_exmatrix; + +varying vec2 v_extrude; + +void main(void) { + // unencode the extrusion vector that we snuck into the a_pos vector + v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0); + + vec4 extrude = u_exmatrix * vec4(v_extrude * u_size, 0, 0); + // multiply a_pos by 0.5, since we had it * 2 in order to sneak + // in extrusion data + gl_Position = u_matrix * vec4(a_pos * 0.5, 0, 1); + + // gl_Position is divided by gl_Position.w after this shader runs. + // Multiply the extrude by it so that it isn't affected by it. + gl_Position += extrude * gl_Position.w; +} diff --git a/src/mbgl/shader/circle_shader.cpp b/src/mbgl/shader/circle_shader.cpp new file mode 100644 index 0000000000..074f92d68b --- /dev/null +++ b/src/mbgl/shader/circle_shader.cpp @@ -0,0 +1,21 @@ +#include <mbgl/shader/circle_shader.hpp> +#include <mbgl/shader/shaders.hpp> +#include <mbgl/platform/gl.hpp> + +#include <cstdio> + +using namespace mbgl; + +CircleShader::CircleShader() + : Shader( + "circle", + shaders[CIRCLE_SHADER].vertex, + shaders[CIRCLE_SHADER].fragment + ) { + a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); +} + +void CircleShader::bind(char *offset) { + MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos)); + MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 4, offset)); +} diff --git a/src/mbgl/shader/circle_shader.hpp b/src/mbgl/shader/circle_shader.hpp new file mode 100644 index 0000000000..545a0baad5 --- /dev/null +++ b/src/mbgl/shader/circle_shader.hpp @@ -0,0 +1,27 @@ +#ifndef MBGL_SHADER_CIRCLE_SHADER +#define MBGL_SHADER_CIRCLE_SHADER + +#include <mbgl/shader/shader.hpp> +#include <mbgl/shader/uniform.hpp> + +namespace mbgl { + +class CircleShader : public Shader { +public: + CircleShader(); + + void bind(char *offset); + + UniformMatrix<4> u_matrix = {"u_matrix", *this}; + UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this}; + Uniform<std::array<float, 4>> u_color = {"u_color", *this}; + Uniform<float> u_size = {"u_size", *this}; + Uniform<float> u_blur = {"u_blur", *this}; + +private: + int32_t a_pos = -1; +}; + +} + +#endif // MBGL_SHADER_CIRCLE_SHADER diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index 12db28c981..c33728db15 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -55,6 +55,11 @@ Request* DefaultFileSource::request(const Resource& resource, url = util::mapbox::normalizeGlyphsURL(resource.url, accessToken); break; + case Resource::Kind::SpriteImage: + case Resource::Kind::SpriteJSON: + url = util::mapbox::normalizeSpriteURL(resource.url, accessToken); + break; + default: url = resource.url; } diff --git a/src/mbgl/style/property_fallback.cpp b/src/mbgl/style/property_fallback.cpp index 655a75df9b..0c4a01ef4f 100644 --- a/src/mbgl/style/property_fallback.cpp +++ b/src/mbgl/style/property_fallback.cpp @@ -21,6 +21,13 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::LineGapWidth, defaultStyleProperties<LineProperties>().gap_width }, { PropertyKey::LineBlur, defaultStyleProperties<LineProperties>().blur }, + { PropertyKey::CircleRadius, defaultStyleProperties<CircleProperties>().radius }, + { PropertyKey::CircleColor, defaultStyleProperties<CircleProperties>().color }, + { PropertyKey::CircleOpacity, defaultStyleProperties<CircleProperties>().opacity }, + { PropertyKey::CircleTranslate, defaultStyleProperties<CircleProperties>().translate }, + { PropertyKey::CircleTranslateAnchor, defaultStyleProperties<CircleProperties>().translateAnchor }, + { PropertyKey::CircleBlur, defaultStyleProperties<CircleProperties>().blur }, + { PropertyKey::IconOpacity, defaultStyleProperties<SymbolProperties>().icon.opacity }, { PropertyKey::IconSize, defaultStyleProperties<SymbolProperties>().icon.size }, { PropertyKey::IconColor, defaultStyleProperties<SymbolProperties>().icon.color }, @@ -56,14 +63,13 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::LineRoundLimit, defaultStyleLayout<StyleLayoutLine>().round_limit }, { PropertyKey::SymbolPlacement, defaultStyleLayout<StyleLayoutSymbol>().placement }, - { PropertyKey::SymbolMinDistance, defaultStyleLayout<StyleLayoutSymbol>().min_distance }, + { PropertyKey::SymbolSpacing, defaultStyleLayout<StyleLayoutSymbol>().spacing }, { PropertyKey::SymbolAvoidEdges, defaultStyleLayout<StyleLayoutSymbol>().avoid_edges }, { PropertyKey::IconAllowOverlap, defaultStyleLayout<StyleLayoutSymbol>().icon.allow_overlap }, { PropertyKey::IconIgnorePlacement, defaultStyleLayout<StyleLayoutSymbol>().icon.ignore_placement }, { PropertyKey::IconOptional, defaultStyleLayout<StyleLayoutSymbol>().icon.optional }, { PropertyKey::IconRotationAlignment, defaultStyleLayout<StyleLayoutSymbol>().icon.rotation_alignment }, - { PropertyKey::IconMaxSize, defaultStyleLayout<StyleLayoutSymbol>().icon.max_size }, { PropertyKey::IconImage, defaultStyleLayout<StyleLayoutSymbol>().icon.image }, { PropertyKey::IconRotate, defaultStyleLayout<StyleLayoutSymbol>().icon.rotate }, { PropertyKey::IconPadding, defaultStyleLayout<StyleLayoutSymbol>().icon.padding }, @@ -73,7 +79,6 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::TextRotationAlignment, defaultStyleLayout<StyleLayoutSymbol>().text.rotation_alignment }, { PropertyKey::TextField, defaultStyleLayout<StyleLayoutSymbol>().text.field }, { PropertyKey::TextFont, defaultStyleLayout<StyleLayoutSymbol>().text.font }, - { PropertyKey::TextMaxSize, defaultStyleLayout<StyleLayoutSymbol>().text.max_size }, { PropertyKey::TextMaxWidth, defaultStyleLayout<StyleLayoutSymbol>().text.max_width }, { PropertyKey::TextLineHeight, defaultStyleLayout<StyleLayoutSymbol>().text.line_height }, { PropertyKey::TextLetterSpacing, defaultStyleLayout<StyleLayoutSymbol>().text.letter_spacing }, diff --git a/src/mbgl/style/property_key.hpp b/src/mbgl/style/property_key.hpp index dfe82e4bb0..4349035f58 100644 --- a/src/mbgl/style/property_key.hpp +++ b/src/mbgl/style/property_key.hpp @@ -27,8 +27,15 @@ enum class PropertyKey { LineMiterLimit, LineRoundLimit, + CircleRadius, + CircleColor, + CircleOpacity, + CircleTranslate, + CircleTranslateAnchor, + CircleBlur, + SymbolPlacement, - SymbolMinDistance, + SymbolSpacing, SymbolAvoidEdges, IconOpacity, @@ -44,7 +51,6 @@ enum class PropertyKey { IconIgnorePlacement, IconOptional, IconRotationAlignment, - IconMaxSize, IconImage, IconOffset, IconPadding, @@ -52,7 +58,6 @@ enum class PropertyKey { IconKeepUpright, TextOpacity, - TextSize, TextColor, TextHaloColor, TextHaloWidth, @@ -63,7 +68,7 @@ enum class PropertyKey { TextRotationAlignment, TextField, TextFont, - TextMaxSize, + TextSize, TextMaxWidth, TextLineHeight, TextLetterSpacing, diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index dfd693dffa..57a446b26a 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -19,6 +19,8 @@ bool StyleLayer::isVisible() const { return getProperties<FillProperties>().isVisible(); case StyleLayerType::Line: return getProperties<LineProperties>().isVisible(); + case StyleLayerType::Circle: + return getProperties<CircleProperties>().isVisible(); case StyleLayerType::Symbol: return getProperties<SymbolProperties>().isVisible(); case StyleLayerType::Raster: @@ -209,11 +211,22 @@ void StyleLayer::applyStyleProperties<LineProperties>(const float z, const TimeP } template <> +void StyleLayer::applyStyleProperties<CircleProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { + properties.set<CircleProperties>(); + CircleProperties& circle = properties.get<CircleProperties>(); + 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<SymbolProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) { properties.set<SymbolProperties>(); SymbolProperties &symbol = properties.get<SymbolProperties>(); applyTransitionedStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::IconSize, symbol.icon.size, 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); @@ -222,13 +235,24 @@ void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const Tim applyStyleProperty(PropertyKey::IconTranslateAnchor, symbol.icon.translate_anchor, z, now, zoomHistory); applyTransitionedStyleProperty(PropertyKey::TextOpacity, symbol.text.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::TextSize, symbol.text.size, 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 <> @@ -259,6 +283,7 @@ void StyleLayer::updateProperties(float z, const TimePoint& now, ZoomHistory &zo switch (type) { case StyleLayerType::Fill: applyStyleProperties<FillProperties>(z, now, zoomHistory); break; case StyleLayerType::Line: applyStyleProperties<LineProperties>(z, now, zoomHistory); break; + case StyleLayerType::Circle: applyStyleProperties<CircleProperties>(z, now, zoomHistory); break; case StyleLayerType::Symbol: applyStyleProperties<SymbolProperties>(z, now, zoomHistory); break; case StyleLayerType::Raster: applyStyleProperties<RasterProperties>(z, now, zoomHistory); break; case StyleLayerType::Background: applyStyleProperties<BackgroundProperties>(z, now, zoomHistory); break; diff --git a/src/mbgl/style/style_layout.hpp b/src/mbgl/style/style_layout.hpp index 90bc71fd6e..6db8ce1930 100644 --- a/src/mbgl/style/style_layout.hpp +++ b/src/mbgl/style/style_layout.hpp @@ -42,7 +42,7 @@ public: StyleLayoutSymbol& operator=(const StyleLayoutSymbol &) = delete; PlacementType placement = PlacementType::Point; - float min_distance = 250.0f; + float spacing = 250.0f; bool avoid_edges = false; struct { @@ -50,6 +50,7 @@ public: bool ignore_placement = false; bool optional = false; RotationAlignmentType rotation_alignment = RotationAlignmentType::Viewport; + float size = 1.0f; float max_size = 1.0f; std::string image; float rotate = 0.0f; @@ -62,6 +63,7 @@ public: RotationAlignmentType rotation_alignment = RotationAlignmentType::Viewport; std::string field; std::string font = "Open Sans Regular, Arial Unicode MS Regular"; + float size = 16.0f; float max_size = 16.0f; float max_width = 15.0f /* em */; float line_height = 1.2f /* em */; diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 4767bdafa3..6dc92a8d3d 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -27,8 +27,11 @@ StyleParser::StyleParser(MapData& data_) } void StyleParser::parse(JSVal document) { - if (document.HasMember("constants")) { - parseConstants(document["constants"]); + if (document.HasMember("version")) { + version = document["version"].GetInt(); + if (version != 8) { + Log::Warning(Event::ParseStyle, "current renderer implementation only supports style spec version 8; using an outdated style will cause rendering errors"); + } } if (document.HasMember("sources")) { @@ -89,37 +92,11 @@ void StyleParser::parse(JSVal document) { } } -void StyleParser::parseConstants(JSVal value) { - if (value.IsObject()) { - rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); - for (; itr != value.MemberEnd(); ++itr) { - std::string name { itr->name.GetString(), itr->name.GetStringLength() }; - // Discard constants that don't start with an @ sign. - if (name.length() && name[0] == '@') { - constants.emplace(std::move(name), &itr->value); - } - } - } else { - Log::Warning(Event::ParseStyle, "constants must be an object"); - } -} - -JSVal StyleParser::replaceConstant(JSVal value) { - if (value.IsString()) { - auto it = constants.find({ value.GetString(), value.GetStringLength() }); - if (it != constants.end()) { - return *it->second; - } - } - - return value; -} - #pragma mark - Parse Render Properties template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, bool &target, const char *name) { if (value.HasMember(name)) { - JSVal property = replaceConstant(value[name]); + JSVal property = value[name]; if (property.IsBool()) { target = property.GetBool(); return StyleParserSuccess; @@ -133,7 +110,7 @@ template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, boo template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, std::string &target, const char *name) { if (value.HasMember(name)) { - JSVal property = replaceConstant(value[name]); + JSVal property = value[name]; if (property.IsString()) { target = { property.GetString(), property.GetStringLength() }; return StyleParserSuccess; @@ -146,7 +123,7 @@ template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, std template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, float &target, const char *name) { if (value.HasMember(name)) { - JSVal property = replaceConstant(value[name]); + JSVal property = value[name]; if (property.IsNumber()) { target = property.GetDouble(); return StyleParserSuccess; @@ -159,7 +136,7 @@ template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, flo template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, uint16_t &target, const char *name) { if (value.HasMember(name)) { - JSVal property = replaceConstant(value[name]); + JSVal property = value[name]; if (property.IsUint()) { unsigned int int_value = property.GetUint(); if (int_value > std::numeric_limits<uint16_t>::max()) { @@ -178,7 +155,7 @@ template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, uin template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, int32_t &target, const char *name) { if (value.HasMember(name)) { - JSVal property = replaceConstant(value[name]); + JSVal property = value[name]; if (property.IsInt()) { target = property.GetInt(); return StyleParserSuccess; @@ -191,7 +168,7 @@ template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, int template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, vec2<float> &target, const char *name) { if (value.HasMember(name)) { - JSVal property = replaceConstant(value[name]); + JSVal property = value[name]; if (property.IsArray()) { if (property.Size() >= 2) { target.x = property[(rapidjson::SizeType)0].GetDouble(); @@ -210,7 +187,7 @@ template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, vec template<typename Parser, typename T> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, T &target, const char *name) { if (value.HasMember(name)) { - JSVal property = replaceConstant(value[name]); + JSVal property = value[name]; if (property.IsString()) { target = Parser({ property.GetString(), property.GetStringLength() }); return StyleParserSuccess; @@ -270,7 +247,7 @@ StyleParser::Result<std::vector<float>> StyleParser::parseFloatArray(JSVal value std::vector<float> vec; for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - JSVal part = replaceConstant(value[i]); + JSVal part = value[i]; if (!part.IsNumber()) { Log::Warning(Event::ParseStyle, "dasharray value must be an array of numbers"); return Result<std::vector<float>> { StyleParserFailure, std::vector<float>() }; @@ -297,9 +274,8 @@ StyleParser::Result<std::array<float, 2>> StyleParser::parseProperty(JSVal value template <> StyleParser::Result<float> StyleParser::parseProperty(JSVal value, const char* property_name) { - JSVal rvalue = replaceConstant(value); - if (rvalue.IsNumber()) { - return Result<float> { StyleParserSuccess, rvalue.GetDouble() }; + if (value.IsNumber()) { + return Result<float> { StyleParserSuccess, value.GetDouble() }; } else { Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", property_name); return Result<float> { StyleParserFailure, 0.0f }; @@ -308,23 +284,20 @@ StyleParser::Result<float> StyleParser::parseProperty(JSVal value, const char* p template <> StyleParser::Result<Color> StyleParser::parseProperty(JSVal value, const char*) { - JSVal rvalue = replaceConstant(value); - return Result<Color> { StyleParserSuccess, parseColor(rvalue) }; + return Result<Color> { StyleParserSuccess, parseColor(value) }; } template <> StyleParser::Result<Faded<std::vector<float>>> StyleParser::parseProperty(JSVal value, const char*) { Faded<std::vector<float>> parsed; - JSVal rvalue = replaceConstant(value); - parsed.to = std::get<1>(parseFloatArray(rvalue)); + parsed.to = std::get<1>(parseFloatArray(value)); return Result<Faded<std::vector<float>>> { StyleParserSuccess, parsed }; } template <> StyleParser::Result<Faded<std::string>> StyleParser::parseProperty(JSVal value, const char *property_name) { - JSVal rvalue = replaceConstant(value); Faded<std::string> parsed; - if (rvalue.IsString()) { + if (value.IsString()) { parsed.to = { value.GetString(), value.GetStringLength() }; return Result<Faded<std::string>> { StyleParserSuccess, parsed }; } else { @@ -357,7 +330,7 @@ StyleParser::Result<std::vector<std::pair<float, T>>> StyleParser::parseStops(JS return Result<std::vector<std::pair<float, T>>> { StyleParserFailure, {}}; } - stops.emplace_back(z.GetDouble(), std::get<1>(parseProperty<T>(replaceConstant(stop[rapidjson::SizeType(1)]), property_name))); + stops.emplace_back(z.GetDouble(), std::get<1>(parseProperty<T>(stop[rapidjson::SizeType(1)], property_name))); } else { Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); return Result<std::vector<std::pair<float, T>>> { StyleParserFailure, {}}; @@ -448,7 +421,7 @@ StyleParser::Status StyleParser::parseOptionalProperty(const char *property_name if (!value.HasMember(property_name)) { return StyleParserFailure; } else { - return setProperty<T>(replaceConstant(value[property_name]), property_name, key, klass); + return setProperty<T>(value[property_name], property_name, key, klass); } } @@ -458,32 +431,38 @@ StyleParser::Status StyleParser::parseOptionalProperty(const char *property_name return StyleParserFailure; } else { if (value.HasMember(transition_name)) { - return setProperty<T>(replaceConstant(value[property_name]), property_name, key, klass, value[transition_name]); + return setProperty<T>(value[property_name], property_name, key, klass, value[transition_name]); } else { JSVal val = JSVal(rapidjson::kObjectType); - return setProperty<T>(replaceConstant(value[property_name]), property_name, key, klass, val); + return setProperty<T>(value[property_name], property_name, key, klass, val); } } } -std::string normalizeFontStack(const std::string &name) { - namespace algo = boost::algorithm; - std::vector<std::string> parts; - algo::split(parts, name, algo::is_any_of(","), algo::token_compress_on); - std::for_each(parts.begin(), parts.end(), [](std::string& str) { algo::trim(str); }); - return algo::join(parts, ", "); -} - template<> StyleParser::Result<std::string> StyleParser::parseProperty(JSVal value, const char *property_name) { - if (!value.IsString()) { + if (std::string { "text-font" } == property_name) { + if (!value.IsArray()) { + Log::Warning(Event::ParseStyle, "value of '%s' must be an array of strings", property_name); + return Result<std::string> { StyleParserFailure, std::string() }; + } else { + std::string result = ""; + for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { + JSVal stop = value[i]; + if (stop.IsString()) { + result += stop.GetString(); + if (i < value.Size()-1) { + result += ","; + } + } else { + Log::Warning(Event::ParseStyle, "text-font members must be strings"); + return Result<std::string> { StyleParserFailure, {} }; + } + } + return Result<std::string> { StyleParserSuccess, result }; + } + } else if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name); return Result<std::string> { StyleParserFailure, std::string() }; - } - - if (std::string { "text-font" } == property_name) { - return Result<std::string> { - StyleParserSuccess, normalizeFontStack({ value.GetString(), value.GetStringLength() }) - }; } else { return Result<std::string> { StyleParserSuccess, { value.GetString(), value.GetStringLength() } }; } @@ -767,7 +746,7 @@ void StyleParser::parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair) { if (value.HasMember("ref")) { // This layer is referencing another layer. Inherit the bucket from that layer, if we // already parsed it. - parseReference(replaceConstant(value["ref"]), layer); + parseReference(value["ref"], layer); } else { // Otherwise, parse the source/source-layer/filter/render keys to form the bucket. parseBucket(value, layer); @@ -782,10 +761,10 @@ void StyleParser::parsePaints(JSVal value, std::map<ClassID, ClassProperties> &p const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; if (name == "paint") { - parsePaint(replaceConstant(itr->value), paints[ClassID::Default]); + parsePaint(itr->value, paints[ClassID::Default]); } else if (name.compare(0, 6, "paint.") == 0 && name.length() > 6) { const ClassID class_id = ClassDictionary::Get().lookup(name.substr(6)); - parsePaint(replaceConstant(itr->value), paints[class_id]); + parsePaint(itr->value, paints[class_id]); } } } @@ -803,7 +782,7 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<Function<std::array<float, 2>>>("fill-translate", Key::FillTranslate, klass, value); parseOptionalProperty<PropertyTransition>("fill-translate-transition", Key::FillTranslate, klass, value); parseOptionalProperty<Function<TranslateAnchorType>>("fill-translate-anchor", Key::FillTranslateAnchor, klass, value); - parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("fill-image", Key::FillImage, klass, value, "fill-image-transition"); + parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("fill-pattern", Key::FillImage, klass, value, "fill-pattern-transition"); parseOptionalProperty<Function<float>>("line-opacity", Key::LineOpacity, klass, value); parseOptionalProperty<PropertyTransition>("line-opacity-transition", Key::LineOpacity, klass, value); @@ -819,7 +798,14 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<Function<float>>("line-blur", Key::LineBlur, klass, value); parseOptionalProperty<PropertyTransition>("line-blur-transition", Key::LineBlur, klass, value); parseOptionalProperty<PiecewiseConstantFunction<Faded<std::vector<float>>>>("line-dasharray", Key::LineDashArray, klass, value, "line-dasharray-transition"); - parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("line-image", Key::LineImage, klass, value, "line-image-transition"); + parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("line-pattern", Key::LineImage, klass, value, "line-pattern-transition"); + + parseOptionalProperty<Function<float>>("circle-radius", Key::CircleRadius, klass, value); + parseOptionalProperty<Function<Color>>("circle-color", Key::CircleColor, klass, value); + parseOptionalProperty<Function<float>>("circle-opacity", Key::CircleOpacity, klass, value); + parseOptionalProperty<Function<std::array<float,2>>>("circle-translate", Key::CircleTranslate, klass, value); + parseOptionalProperty<Function<TranslateAnchorType>>("circle-translate-anchor", Key::CircleTranslateAnchor, klass, value); + parseOptionalProperty<Function<float>>("circle-blur", Key::CircleBlur, klass, value); parseOptionalProperty<Function<float>>("icon-opacity", Key::IconOpacity, klass, value); parseOptionalProperty<PropertyTransition>("icon-opacity-transition", Key::IconOpacity, klass, value); @@ -869,7 +855,7 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<Function<float>>("background-opacity", Key::BackgroundOpacity, klass, value); parseOptionalProperty<Function<Color>>("background-color", Key::BackgroundColor, klass, value); - parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("background-image", Key::BackgroundImage, klass, value, "background-image-transition"); + parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("background-pattern", Key::BackgroundImage, klass, value, "background-pattern-transition"); } void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) { @@ -883,13 +869,13 @@ void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) { parseOptionalProperty<Function<float>>("line-round-limit", Key::LineRoundLimit, bucket->layout, value); parseOptionalProperty<Function<PlacementType>>("symbol-placement", Key::SymbolPlacement, bucket->layout, value); - parseOptionalProperty<Function<float>>("symbol-min-distance", Key::SymbolMinDistance, bucket->layout, value); + parseOptionalProperty<Function<float>>("symbol-spacing", Key::SymbolSpacing, bucket->layout, value); parseOptionalProperty<Function<bool>>("symbol-avoid-edges", Key::SymbolAvoidEdges, bucket->layout, value); parseOptionalProperty<Function<bool>>("icon-allow-overlap", Key::IconAllowOverlap, bucket->layout, value); parseOptionalProperty<Function<bool>>("icon-ignore-placement", Key::IconIgnorePlacement, bucket->layout, value); parseOptionalProperty<Function<bool>>("icon-optional", Key::IconOptional, bucket->layout, value); parseOptionalProperty<Function<RotationAlignmentType>>("icon-rotation-alignment", Key::IconRotationAlignment, bucket->layout, value); - parseOptionalProperty<Function<float>>("icon-max-size", Key::IconMaxSize, bucket->layout, value); + parseOptionalProperty<Function<float>>("icon-size", Key::IconSize, bucket->layout, value); parseOptionalProperty<Function<std::string>>("icon-image", Key::IconImage, bucket->layout, value); parseOptionalProperty<Function<float>>("icon-rotate", Key::IconRotate, bucket->layout, value); parseOptionalProperty<Function<float>>("icon-padding", Key::IconPadding, bucket->layout, value); @@ -898,7 +884,7 @@ void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) { parseOptionalProperty<Function<RotationAlignmentType>>("text-rotation-alignment", Key::TextRotationAlignment, bucket->layout, value); parseOptionalProperty<Function<std::string>>("text-field", Key::TextField, bucket->layout, value); parseOptionalProperty<Function<std::string>>("text-font", Key::TextFont, bucket->layout, value); - parseOptionalProperty<Function<float>>("text-max-size", Key::TextMaxSize, bucket->layout, value); + parseOptionalProperty<Function<float>>("text-size", Key::TextSize, bucket->layout, value); parseOptionalProperty<Function<float>>("text-max-width", Key::TextMaxWidth, bucket->layout, value); parseOptionalProperty<Function<float>>("text-line-height", Key::TextLineHeight, bucket->layout, value); parseOptionalProperty<Function<float>>("text-letter-spacing", Key::TextLetterSpacing, bucket->layout, value); @@ -948,7 +934,7 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) { bucket->name = layer->id; if (value.HasMember("source")) { - JSVal value_source = replaceConstant(value["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); @@ -961,7 +947,7 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) { } if (value.HasMember("source-layer")) { - JSVal value_source_layer = replaceConstant(value["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 { @@ -970,13 +956,11 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) { } if (value.HasMember("filter")) { - JSVal value_filter = replaceConstant(value["filter"]); - bucket->filter = parseFilterExpression(value_filter); + bucket->filter = parseFilterExpression(value["filter"]); } if (value.HasMember("layout")) { - JSVal value_render = replaceConstant(value["layout"]); - parseLayout(value_render, bucket); + parseLayout(value["layout"], bucket); } if (value.HasMember("minzoom")) { diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp index 5f0c509ebf..22dc4f6275 100644 --- a/src/mbgl/style/style_parser.hpp +++ b/src/mbgl/style/style_parser.hpp @@ -52,9 +52,6 @@ public: } private: - void parseConstants(JSVal value); - JSVal replaceConstant(JSVal value); - void parseSources(JSVal value); void parseLayers(JSVal value); void parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair); @@ -101,7 +98,7 @@ private: FilterExpression parseFilter(JSVal); private: - std::unordered_map<std::string, const rapidjson::Value *> constants; + std::uint8_t version; std::vector<std::unique_ptr<Source>> sources; std::vector<util::ptr<StyleLayer>> layers; diff --git a/src/mbgl/style/style_properties.cpp b/src/mbgl/style/style_properties.cpp index 3c5b525c1d..aa4c7e29c7 100644 --- a/src/mbgl/style/style_properties.cpp +++ b/src/mbgl/style/style_properties.cpp @@ -5,6 +5,7 @@ namespace mbgl { template<> const FillProperties &defaultStyleProperties() { static const FillProperties p; return p; } template<> const LineProperties &defaultStyleProperties() { static const LineProperties p; return p; } +template<> const CircleProperties &defaultStyleProperties() { static const CircleProperties p; return p; } template<> const SymbolProperties &defaultStyleProperties() { static const SymbolProperties p; return p; } template<> const RasterProperties &defaultStyleProperties() { static const RasterProperties p; return p; } template<> const BackgroundProperties &defaultStyleProperties() { static const BackgroundProperties p; return p; } diff --git a/src/mbgl/util/geojsonvt b/src/mbgl/util/geojsonvt -Subproject 995ffc72c556da4b4880a6036fbcf7159fc5ecc +Subproject ed99a6290fa42107a982e7f3675aae49d29026b diff --git a/src/mbgl/util/mapbox.cpp b/src/mbgl/util/mapbox.cpp index 54e6868095..dee0e0f8f4 100644 --- a/src/mbgl/util/mapbox.cpp +++ b/src/mbgl/util/mapbox.cpp @@ -1,74 +1,101 @@ #include <mbgl/util/mapbox.hpp> #include <stdexcept> +#include <vector> namespace mbgl { namespace util { namespace mapbox { -const std::string mapbox = "mapbox://"; +const std::string protocol = "mapbox://"; +const std::string baseURL = "https://api.mapbox.com/"; -std::string normalizeURL(const std::string& url, const std::string& pathPrefix, const std::string& accessToken) { - if (accessToken.empty()) - throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources"); +bool isMapboxURL(const std::string& url) { + return url.compare(0, protocol.length(), protocol) == 0; +} - return std::string("https://api.tiles.mapbox.com") - + pathPrefix - + url.substr(mapbox.length()) - + "?access_token=" - + accessToken; +std::vector<std::string> getMapboxURLPathname(const std::string& url) { + std::vector<std::string> pathname; + std::size_t startIndex = protocol.length(); + while (startIndex < url.length()) { + std::size_t endIndex = url.find("/", startIndex); + if (endIndex == std::string::npos) endIndex = url.length(); + pathname.push_back(url.substr(startIndex, endIndex - startIndex)); + startIndex = endIndex + 1; + } + return pathname; } std::string normalizeSourceURL(const std::string& url, const std::string& accessToken) { - if (url.compare(0, mapbox.length(), mapbox) != 0) + if (!isMapboxURL(url)) { return url; + } - std::string result = normalizeURL(url + ".json", "/v4/", accessToken); - - // TileJSON requests need a secure flag appended to their URLs so - // that the server knows to send SSL-ified resource references. - result += "&secure"; + if (accessToken.empty()) { + throw std::runtime_error("You must provide a Mapbox API access token for Mapbox tile sources"); + } - return result; + return baseURL + "v4/" + url.substr(protocol.length()) + ".json?access_token=" + accessToken + "&secure"; } std::string normalizeStyleURL(const std::string& url, const std::string& accessToken) { - if (url.compare(0, mapbox.length(), mapbox) != 0) + if (!isMapboxURL(url)) { return url; + } - const std::string user = url.substr(mapbox.length(), url.find('.') - mapbox.length()); - - return normalizeURL(url, "/styles/v1/" + user + "/", accessToken); + std::vector<std::string> pathname = getMapboxURLPathname(url); + std::string user = pathname[1]; + std::string id = pathname[2]; + bool isDraft = pathname.size() > 3; + return baseURL + "styles/v1/" + user + "/" + id + (isDraft ? "/draft" : "") + "?access_token=" + accessToken; } -std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken) { - if (url.compare(0, mapbox.length(), mapbox) != 0) { +std::string normalizeSpriteURL(const std::string& url, const std::string& accessToken) { + if (!isMapboxURL(url)) { return url; } - const std::string fontstack = "mapbox://fontstack/"; + std::vector<std::string> pathname = getMapboxURLPathname(url); + std::string user = pathname[1]; + bool isDraft = pathname.size() > 3; + + std::string id, extension; + if (isDraft) { + size_t index = pathname[3].find_first_of("@."); + id = pathname[2]; + extension = pathname[3].substr(index); + } else { + size_t index = pathname[2].find_first_of("@."); + id = pathname[2].substr(0, index); + extension = pathname[2].substr(index); + } + + return baseURL + "styles/v1/" + user + "/" + id + "/" + (isDraft ? "draft/" : "") + "sprite" + extension + "?access_token=" + accessToken; +} - if (url.compare(0, fontstack.length(), fontstack) == 0) { - return normalizeURL(url, "/v4/", accessToken); +std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken) { + if (!isMapboxURL(url)) { + return url; } - return normalizeURL(url, "/", accessToken); + std::vector<std::string> pathname = getMapboxURLPathname(url); + std::string user = pathname[1]; + return baseURL + "fonts/v1/" + user + "/{fontstack}/{range}.pbf?access_token=" + accessToken; } std::string normalizeTileURL(const std::string& url, const std::string& sourceURL, SourceType sourceType) { - if (sourceURL.empty() || sourceURL.compare(0, mapbox.length(), mapbox) != 0 || - sourceType != SourceType::Raster) { + if (sourceURL.empty() || !isMapboxURL(sourceURL) || sourceType != SourceType::Raster) { return url; } - + std::string::size_type queryIdx = url.rfind("?"); // Trim off the right end but never touch anything before the extension dot. std::string urlSansParams((queryIdx == std::string::npos) ? url : url.substr(0, queryIdx)); - + while (!urlSansParams.empty() && isdigit(urlSansParams.back())) { urlSansParams.pop_back(); } - + std::string::size_type basenameIdx = url.rfind("/", queryIdx); std::string::size_type extensionIdx = url.rfind(".", queryIdx); if (basenameIdx == std::string::npos || extensionIdx == std::string::npos || @@ -76,7 +103,7 @@ std::string normalizeTileURL(const std::string& url, const std::string& sourceUR // No file extension: probably not a file name we can tack a ratio onto. return url; } - + std::string normalizedURL(url); normalizedURL.insert(extensionIdx, "{ratio}"); return normalizedURL; diff --git a/src/mbgl/util/mapbox.hpp b/src/mbgl/util/mapbox.hpp index 86ea349b8c..9c24dda0e6 100644 --- a/src/mbgl/util/mapbox.hpp +++ b/src/mbgl/util/mapbox.hpp @@ -10,6 +10,7 @@ namespace mapbox { std::string normalizeSourceURL(const std::string& url, const std::string& accessToken); std::string normalizeStyleURL(const std::string& url, const std::string& accessToken); +std::string normalizeSpriteURL(const std::string& url, const std::string& accessToken); std::string normalizeGlyphsURL(const std::string& url, const std::string& accessToken); std::string normalizeTileURL(const std::string& url, const std::string& sourceURL, SourceType sourceType); diff --git a/styles b/styles -Subproject 44bdcec816407ba16765a556135915652e5e5b2 +Subproject 19dde3cb1c36fe5f42dafc78c806fd7aca98126 diff --git a/test/fixtures/api/water.json b/test/fixtures/api/water.json index 2bcce11992..c969b345ae 100644 --- a/test/fixtures/api/water.json +++ b/test/fixtures/api/water.json @@ -1,5 +1,5 @@ { - "version": 7, + "version": 8, "name": "Water", "sources": { "mapbox": { diff --git a/test/fixtures/headless/pois.json b/test/fixtures/headless/pois.json index 7a4488608a..a7fcfdb9dc 100644 --- a/test/fixtures/headless/pois.json +++ b/test/fixtures/headless/pois.json @@ -1,5 +1,5 @@ { - "version": 7, + "version": 8, "name": "POIs", "sources": { "mapbox": { diff --git a/test/fixtures/resources/style.json b/test/fixtures/resources/style.json index fb67afc662..fc5f9c973b 100644 --- a/test/fixtures/resources/style.json +++ b/test/fixtures/resources/style.json @@ -1,5 +1,5 @@ { - "version": 1, + "version": 8, "name": "Test", "sources": { "vectorsource": { @@ -20,7 +20,7 @@ "source": "vectorsource", "source-layer": "road_label", "layout": { - "text-font": "Open Sans Regular, Arial Unicode MS Regular", + "text-font": ["Open Sans Regular", "Arial Unicode MS Regular"], "text-field": "{name_en}" } }, { @@ -29,7 +29,7 @@ "source": "vectorsource", "source-layer": "poi_label", "layout": { - "text-font": "Open Sans Regular, Arial Unicode MS Regular", + "text-font": ["Open Sans Regular", "Arial Unicode MS Regular"], "icon-image": "{maki}_icon" } }] diff --git a/test/fixtures/style_parser/circle-blur.info.json b/test/fixtures/style_parser/circle-blur.info.json new file mode 100644 index 0000000000..397e4cd4d1 --- /dev/null +++ b/test/fixtures/style_parser/circle-blur.info.json @@ -0,0 +1,7 @@ +{ + "default": { + "log": [ + [1, "WARNING", "ParseStyle", "value of 'circle-blur' must be a number, or a number function"] + ] + } +} diff --git a/test/fixtures/style_parser/circle-blur.style.json b/test/fixtures/style_parser/circle-blur.style.json new file mode 100644 index 0000000000..8140ad5e47 --- /dev/null +++ b/test/fixtures/style_parser/circle-blur.style.json @@ -0,0 +1,18 @@ +{ + "version": 8, + "sources": { + "mapbox": { + "type": "vector", + "url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5", + "maxzoom": 14 + } + }, + "layers": [{ + "id": "circle_blur_example", + "type": "circle", + "source": "mapbox", + "paint": { + "circle-blur": null + } + }] +} diff --git a/test/fixtures/style_parser/circle-color.info.json b/test/fixtures/style_parser/circle-color.info.json new file mode 100644 index 0000000000..b1708c2f05 --- /dev/null +++ b/test/fixtures/style_parser/circle-color.info.json @@ -0,0 +1,7 @@ +{ + "default": { + "log": [ + [1, "WARNING", "ParseStyle", "color value must be a string"] + ] + } +} diff --git a/test/fixtures/style_parser/circle-color.style.json b/test/fixtures/style_parser/circle-color.style.json new file mode 100644 index 0000000000..44c32f99ce --- /dev/null +++ b/test/fixtures/style_parser/circle-color.style.json @@ -0,0 +1,18 @@ +{ + "version": 8, + "sources": { + "mapbox": { + "type": "vector", + "url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5", + "maxzoom": 14 + } + }, + "layers": [{ + "id": "circle_color_example", + "type": "circle", + "source": "mapbox", + "paint": { + "circle-color": null + } + }] +} diff --git a/test/fixtures/style_parser/circle-opacity.info.json b/test/fixtures/style_parser/circle-opacity.info.json new file mode 100644 index 0000000000..3e8662bdbe --- /dev/null +++ b/test/fixtures/style_parser/circle-opacity.info.json @@ -0,0 +1,7 @@ +{ + "default": { + "log": [ + [1, "WARNING", "ParseStyle", "value of 'circle-opacity' must be a number, or a number function"] + ] + } +} diff --git a/test/fixtures/style_parser/circle-opacity.style.json b/test/fixtures/style_parser/circle-opacity.style.json new file mode 100644 index 0000000000..601e81a51b --- /dev/null +++ b/test/fixtures/style_parser/circle-opacity.style.json @@ -0,0 +1,18 @@ +{ + "version": 8, + "sources": { + "mapbox": { + "type": "vector", + "url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5", + "maxzoom": 14 + } + }, + "layers": [{ + "id": "circle_opacity_example", + "type": "circle", + "source": "mapbox", + "paint": { + "circle-opacity": null + } + }] +} diff --git a/test/fixtures/style_parser/circle-radius.info.json b/test/fixtures/style_parser/circle-radius.info.json new file mode 100644 index 0000000000..7e87aa4fdb --- /dev/null +++ b/test/fixtures/style_parser/circle-radius.info.json @@ -0,0 +1,7 @@ +{ + "default": { + "log": [ + [1, "WARNING", "ParseStyle", "value of 'circle-radius' must be a number, or a number function"] + ] + } +} diff --git a/test/fixtures/style_parser/circle-radius.style.json b/test/fixtures/style_parser/circle-radius.style.json new file mode 100644 index 0000000000..a7fb28b2d3 --- /dev/null +++ b/test/fixtures/style_parser/circle-radius.style.json @@ -0,0 +1,18 @@ +{ + "version": 8, + "sources": { + "mapbox": { + "type": "vector", + "url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5", + "maxzoom": 14 + } + }, + "layers": [{ + "id": "circle_radius_example", + "type": "circle", + "source": "mapbox", + "paint": { + "circle-radius": null + } + }] +} diff --git a/test/fixtures/style_parser/colors.style.json b/test/fixtures/style_parser/colors.style.json index 24aa2e5d1c..8996548885 100644 --- a/test/fixtures/style_parser/colors.style.json +++ b/test/fixtures/style_parser/colors.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "constants": { "@land": "r44,239,225)", "@snow": "f4f8foNGbjf#", diff --git a/test/fixtures/style_parser/function-numeric.style.json b/test/fixtures/style_parser/function-numeric.style.json index 2db5624ac9..f3fca7e1d0 100644 --- a/test/fixtures/style_parser/function-numeric.style.json +++ b/test/fixtures/style_parser/function-numeric.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/fixtures/style_parser/function-string-bool-enum.style.json b/test/fixtures/style_parser/function-string-bool-enum.style.json index c38f195259..0447990911 100644 --- a/test/fixtures/style_parser/function-string-bool-enum.style.json +++ b/test/fixtures/style_parser/function-string-bool-enum.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", @@ -31,7 +31,7 @@ "source-layer": "waterway", "layout": { "text-font": { - "stops": [[0, "Open Sans Regular"]] + "stops": [[0, ["Open Sans Regular"]]] }, "text-keep-upright": { "stops": [[0, false], [10, true]] diff --git a/test/fixtures/style_parser/function-type.style.json b/test/fixtures/style_parser/function-type.style.json index c992e71f04..cde8dfc76b 100644 --- a/test/fixtures/style_parser/function-type.style.json +++ b/test/fixtures/style_parser/function-type.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/fixtures/style_parser/line-opacity.style.json b/test/fixtures/style_parser/line-opacity.style.json index 8f5221b8ad..712b2b6f50 100644 --- a/test/fixtures/style_parser/line-opacity.style.json +++ b/test/fixtures/style_parser/line-opacity.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/fixtures/style_parser/line-translate.style.json b/test/fixtures/style_parser/line-translate.style.json index 3c079f3520..a32b2d8ee4 100644 --- a/test/fixtures/style_parser/line-translate.style.json +++ b/test/fixtures/style_parser/line-translate.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/fixtures/style_parser/line-width.style.json b/test/fixtures/style_parser/line-width.style.json index 18653074db..e5fe6fa8e1 100644 --- a/test/fixtures/style_parser/line-width.style.json +++ b/test/fixtures/style_parser/line-width.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/fixtures/style_parser/stop-zoom-value.style.json b/test/fixtures/style_parser/stop-zoom-value.style.json index 5f907cd8e9..520db9a904 100644 --- a/test/fixtures/style_parser/stop-zoom-value.style.json +++ b/test/fixtures/style_parser/stop-zoom-value.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/fixtures/style_parser/stops-array.style.json b/test/fixtures/style_parser/stops-array.style.json index 107c1c064c..daa48214d9 100644 --- a/test/fixtures/style_parser/stops-array.style.json +++ b/test/fixtures/style_parser/stops-array.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/fixtures/style_parser/text-size.style.json b/test/fixtures/style_parser/text-size.style.json index 175ce456ad..46dd33e3c4 100644 --- a/test/fixtures/style_parser/text-size.style.json +++ b/test/fixtures/style_parser/text-size.style.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 8, "sources": { "mapbox": { "type": "vector", diff --git a/test/miscellaneous/mapbox.cpp b/test/miscellaneous/mapbox.cpp index f93749760b..f1febd729b 100644 --- a/test/miscellaneous/mapbox.cpp +++ b/test/miscellaneous/mapbox.cpp @@ -8,22 +8,29 @@ using namespace mbgl; TEST(Mapbox, SourceURL) { - EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "key"), "https://api.tiles.mapbox.com/v4/user.map.json?access_token=key&secure"); - EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "token"), "https://api.tiles.mapbox.com/v4/user.map.json?access_token=token&secure"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "key"), "https://api.mapbox.com/v4/user.map.json?access_token=key&secure"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", "token"), "https://api.mapbox.com/v4/user.map.json?access_token=token&secure"); EXPECT_THROW(mbgl::util::mapbox::normalizeSourceURL("mapbox://user.map", ""), std::runtime_error); } TEST(Mapbox, GlyphsURL) { - EXPECT_EQ(mbgl::util::mapbox::normalizeGlyphsURL("mapbox://fontstack/{fontstack}/{range}.pbf", "key"), "https://api.tiles.mapbox.com/v4/fontstack/{fontstack}/{range}.pbf?access_token=key"); - EXPECT_EQ(mbgl::util::mapbox::normalizeGlyphsURL("mapbox://fonts/v1/user/{fontstack}/{range}.pbf", "key"), "https://api.tiles.mapbox.com/fonts/v1/user/{fontstack}/{range}.pbf?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeGlyphsURL("mapbox://fonts/boxmap/{fontstack}/{range}.pbf", "key"), "https://api.mapbox.com/fonts/v1/boxmap/{fontstack}/{range}.pbf?access_token=key"); EXPECT_EQ(mbgl::util::mapbox::normalizeGlyphsURL("http://path", "key"), "http://path"); } TEST(Mapbox, StyleURL) { - EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("mapbox://user.style", "key"), "https://api.tiles.mapbox.com/styles/v1/user/user.style?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("mapbox://styles/user/style", "key"), "https://api.mapbox.com/styles/v1/user/style?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("mapbox://styles/user/style/draft", "key"), "https://api.mapbox.com/styles/v1/user/style/draft?access_token=key"); EXPECT_EQ(mbgl::util::mapbox::normalizeStyleURL("http://path", "key"), "http://path"); } +TEST(Mapbox, SpriteURL) { + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("map/box/sprites@2x.json", "key"), "map/box/sprites@2x.json"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("mapbox://sprites/mapbox/streets-v8.json", "key"), "https://api.mapbox.com/styles/v1/mapbox/streets-v8/sprite.json?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("mapbox://sprites/mapbox/streets-v8@2x.png", "key"), "https://api.mapbox.com/styles/v1/mapbox/streets-v8/sprite@2x.png?access_token=key"); + EXPECT_EQ(mbgl::util::mapbox::normalizeSpriteURL("mapbox://sprites/mapbox/streets-v8/draft@2x.png", "key"), "https://api.mapbox.com/styles/v1/mapbox/streets-v8/draft/sprite@2x.png?access_token=key"); +} + TEST(Mapbox, TileURL) { try { EXPECT_EQ(mbgl::util::mapbox::normalizeTileURL("http://path.png/tile.png", "mapbox://user.map", SourceType::Raster), "http://path.png/tile{ratio}.png"); diff --git a/test/suite b/test/suite -Subproject b6b8a25e76231c2ceed341e024b4dce462c45a2 +Subproject b6828212d3fe5a06e1e91df1dc9a212cb565609 |