summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2015-08-24 10:47:30 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2015-08-24 10:47:30 -0700
commit0451aca37e866c3380072b114e2d49353888e4b5 (patch)
tree899dcf40ef2ea0f51e25640556548d63cad60a21
parente42e3ea3a00fd7d74ff73b955ebcb8d202362088 (diff)
parente97662972fef0e56132a03f2c2510c0da8537aad (diff)
downloadqtlocation-mapboxgl-0451aca37e866c3380072b114e2d49353888e4b5.tar.gz
Merge branch 'v8'
-rw-r--r--include/mbgl/storage/resource.hpp4
-rw-r--r--include/mbgl/style/style_properties.hpp15
-rw-r--r--include/mbgl/style/types.hpp2
-rw-r--r--ios/benchmark/MBXBenchViewController.mm2
-rw-r--r--ios/benchmark/fo/MBXBenchViewController.mm2
-rw-r--r--platform/default/default_styles.cpp10
-rw-r--r--platform/default/sqlite_cache.cpp2
-rwxr-xr-xscripts/ios/package.sh2
-rw-r--r--src/mbgl/geometry/circle_buffer.cpp13
-rw-r--r--src/mbgl/geometry/circle_buffer.hpp27
-rw-r--r--src/mbgl/map/sprite.cpp5
-rw-r--r--src/mbgl/map/tile_worker.cpp46
-rw-r--r--src/mbgl/map/tile_worker.hpp3
-rw-r--r--src/mbgl/renderer/circle_bucket.cpp92
-rw-r--r--src/mbgl/renderer/circle_bucket.hpp46
-rw-r--r--src/mbgl/renderer/painter.cpp3
-rw-r--r--src/mbgl/renderer/painter.hpp4
-rw-r--r--src/mbgl/renderer/painter_circle.cpp49
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp9
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp9
-rw-r--r--src/mbgl/shader/circle.fragment.glsl10
-rw-r--r--src/mbgl/shader/circle.vertex.glsl23
-rw-r--r--src/mbgl/shader/circle_shader.cpp21
-rw-r--r--src/mbgl/shader/circle_shader.hpp27
-rw-r--r--src/mbgl/storage/default_file_source.cpp5
-rw-r--r--src/mbgl/style/property_fallback.cpp11
-rw-r--r--src/mbgl/style/property_key.hpp13
-rw-r--r--src/mbgl/style/style_layer.cpp29
-rw-r--r--src/mbgl/style/style_layout.hpp4
-rw-r--r--src/mbgl/style/style_parser.cpp142
-rw-r--r--src/mbgl/style/style_parser.hpp5
-rw-r--r--src/mbgl/style/style_properties.cpp1
m---------src/mbgl/util/geojsonvt0
-rw-r--r--src/mbgl/util/mapbox.cpp91
-rw-r--r--src/mbgl/util/mapbox.hpp1
m---------styles0
-rw-r--r--test/fixtures/api/water.json2
-rw-r--r--test/fixtures/headless/pois.json2
-rw-r--r--test/fixtures/resources/style.json6
-rw-r--r--test/fixtures/style_parser/circle-blur.info.json7
-rw-r--r--test/fixtures/style_parser/circle-blur.style.json18
-rw-r--r--test/fixtures/style_parser/circle-color.info.json7
-rw-r--r--test/fixtures/style_parser/circle-color.style.json18
-rw-r--r--test/fixtures/style_parser/circle-opacity.info.json7
-rw-r--r--test/fixtures/style_parser/circle-opacity.style.json18
-rw-r--r--test/fixtures/style_parser/circle-radius.info.json7
-rw-r--r--test/fixtures/style_parser/circle-radius.style.json18
-rw-r--r--test/fixtures/style_parser/colors.style.json2
-rw-r--r--test/fixtures/style_parser/function-numeric.style.json2
-rw-r--r--test/fixtures/style_parser/function-string-bool-enum.style.json4
-rw-r--r--test/fixtures/style_parser/function-type.style.json2
-rw-r--r--test/fixtures/style_parser/line-opacity.style.json2
-rw-r--r--test/fixtures/style_parser/line-translate.style.json2
-rw-r--r--test/fixtures/style_parser/line-width.style.json2
-rw-r--r--test/fixtures/style_parser/stop-zoom-value.style.json2
-rw-r--r--test/fixtures/style_parser/stops-array.style.json2
-rw-r--r--test/fixtures/style_parser/text-size.style.json2
-rw-r--r--test/miscellaneous/mapbox.cpp17
m---------test/suite0
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