summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/style.js100
-rw-r--r--include/mbgl/map/tile_parser.hpp11
-rw-r--r--include/mbgl/renderer/icon_bucket.hpp53
-rw-r--r--include/mbgl/renderer/painter.hpp8
-rw-r--r--include/mbgl/renderer/symbol_bucket.hpp82
-rw-r--r--include/mbgl/renderer/text_bucket.hpp61
-rw-r--r--include/mbgl/style/property_key.hpp2
-rw-r--r--include/mbgl/style/style_bucket.hpp56
-rw-r--r--include/mbgl/style/style_parser.hpp4
-rw-r--r--include/mbgl/style/style_properties.hpp32
-rw-r--r--include/mbgl/style/types.hpp219
-rw-r--r--include/mbgl/text/placement.hpp8
-rw-r--r--src/map/map.cpp8
-rw-r--r--src/map/tile_parser.cpp119
-rw-r--r--src/renderer/icon_bucket.cpp79
-rw-r--r--src/renderer/line_bucket.cpp2
-rw-r--r--src/renderer/painter_icon.cpp45
-rw-r--r--src/renderer/painter_symbol.cpp202
-rw-r--r--src/renderer/painter_text.cpp156
-rw-r--r--src/renderer/symbol_bucket.cpp271
-rw-r--r--src/renderer/text_bucket.cpp146
-rw-r--r--src/style/property_fallback.cpp1
-rw-r--r--src/style/style_bucket.cpp3
-rw-r--r--src/style/style_layer.cpp42
-rw-r--r--src/style/style_parser.cpp138
-rw-r--r--src/style/style_properties.cpp2
-rw-r--r--src/text/placement.cpp16
27 files changed, 879 insertions, 987 deletions
diff --git a/bin/style.js b/bin/style.js
index dc2e05709a..cca10b346f 100644
--- a/bin/style.js
+++ b/bin/style.js
@@ -1543,10 +1543,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "country_label",
"filter": { "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 24,
"text-max-width": 5
@@ -1568,10 +1568,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "LineString", "labelrank": 1 },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 30,
"text-max-angle": 0.5,
@@ -1596,10 +1596,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "LineString", "labelrank": 2 },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 24,
"text-max-angle": 0.5
@@ -1623,10 +1623,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "LineString", "labelrank": 3 },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 18,
"text-max-angle": 0.5
@@ -1650,10 +1650,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "LineString", "labelrank": [4, 5, 6] },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 16,
"text-max-angle": 0.5
@@ -1677,10 +1677,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "Point", "labelrank": 1 },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 30,
"text-max-width": 8,
@@ -1706,10 +1706,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "Point", "labelrank": 2 },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 24,
"text-max-width": 8,
@@ -1735,10 +1735,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "Point", "labelrank": 3 },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 18,
"text-max-width": 8,
@@ -1764,10 +1764,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "marine_label",
"filter": { "$type": "Point", "labelrank": [4, 5, 6] },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 16,
"text-max-width": 8,
@@ -1793,10 +1793,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "state_label",
"filter": { "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Regular, Arial Unicode MS Regular",
"text-max-size": 16,
"text-max-width": 8
@@ -1822,10 +1822,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "place_label",
"filter": { "type": "city", "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 20,
"text-max-width": 8
@@ -1851,10 +1851,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "place_label",
"filter": { "type": "town", "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 24,
"text-max-width": 8
@@ -1880,10 +1880,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "place_label",
"filter": { "type": "village", "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 22,
"text-max-width": 8
@@ -1909,10 +1909,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "place_label",
"filter": { "type": ["hamlet", "suburb", "neighbourhood"], "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 18,
"text-max-width": 6
@@ -1937,10 +1937,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "road_label",
"filter": { "class": ["motorway", "main"], "$type": "LineString" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-padding": 2,
"text-font": "Open Sans Regular, Arial Unicode MS Regular",
"text-max-size": 18,
@@ -1963,10 +1963,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "road_label",
"filter": { "class": ["street", "street_limited"], "$type": "LineString" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-padding": 2,
"text-font": "Open Sans Regular, Arial Unicode MS Regular",
"text-max-size": 16,
@@ -1989,10 +1989,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "road_label",
"filter": { "class": ["service", "driveway", "path"], "$type": "LineString" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-padding": 2,
"text-font": "Open Sans Regular, Arial Unicode MS Regular",
"text-max-size": 14,
@@ -2015,9 +2015,9 @@ module.exports = {
"source": "mapbox",
"source-layer": "contour",
"filter": { "index": [5, 10], "$type": "LineString" },
- "type": "text",
+ "type": "symbol",
"render": {
- "text-path": "curve",
+ "symbol-placement": "line",
"text-field": "{ele} m",
"text-font": "Open Sans Regular, Arial Unicode MS Regular",
"text-max-size": 10,
@@ -2040,10 +2040,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "water_label",
"filter": { "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 12,
"text-max-width": 8
@@ -2061,10 +2061,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "waterway_label",
"filter": { "$type": "LineString" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "curve",
+ "symbol-placement": "line",
"text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
"text-max-size": 12,
"text-max-angle": 0.5
@@ -2083,7 +2083,7 @@ module.exports = {
"source": "mapbox",
"source-layer": "poi_label",
"filter": { "scalerank": [1, 2] },
- "type": "icon",
+ "type": "symbol",
"render": {
"icon-image": "{maki}-12",
"icon-size": 12
@@ -2094,10 +2094,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "poi_label",
"filter": { "scalerank": [1, 2], "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-padding": 2,
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 12,
@@ -2121,7 +2121,7 @@ module.exports = {
"source": "mapbox",
"source-layer": "poi_label",
"filter": { "scalerank": 3 },
- "type": "icon",
+ "type": "symbol",
"render": {
"icon-image": "{maki}-12",
"icon-size": 12
@@ -2141,10 +2141,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "poi_label",
"filter": { "scalerank": 3, "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-padding": 2,
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 11,
@@ -2174,7 +2174,7 @@ module.exports = {
"source": "mapbox",
"source-layer": "poi_label",
"filter": { "scalerank": 4 },
- "type": "icon",
+ "type": "symbol",
"render": {
"icon-image": "{maki}-12",
"icon-size": 12
@@ -2194,10 +2194,10 @@ module.exports = {
"source": "mapbox",
"source-layer": "poi_label",
"filter": { "scalerank": 4, "$type": "Point" },
- "type": "text",
+ "type": "symbol",
"render": {
"text-field": "{name_en}",
- "text-path": "horizontal",
+ "symbol-placement": "point",
"text-padding": 2,
"text-font": "Open Sans Semibold, Arial Unicode MS Bold",
"text-max-size": 10,
@@ -2227,7 +2227,7 @@ module.exports = {
"source": "mapbox",
"source-layer": "poi_label",
"filter": { "maki": "airport" },
- "type": "icon",
+ "type": "symbol",
"render": {
"icon-image": "{maki}-12",
"icon-size": 12
diff --git a/include/mbgl/map/tile_parser.hpp b/include/mbgl/map/tile_parser.hpp
index 1550350ed7..84505c1e05 100644
--- a/include/mbgl/map/tile_parser.hpp
+++ b/include/mbgl/map/tile_parser.hpp
@@ -21,9 +21,8 @@ class SpriteAtlas;
class Style;
class StyleBucket;
class StyleBucketFill;
-class StyleBucketIcon;
class StyleBucketLine;
-class StyleBucketText;
+class StyleBucketSymbol;
class StyleLayerGroup;
class VectorTileData;
@@ -40,18 +39,14 @@ public:
private:
bool obsolete() const;
- void parseGlyphs();
void parseStyleLayers(std::shared_ptr<StyleLayerGroup> group);
- void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face);
std::unique_ptr<Bucket> createBucket(std::shared_ptr<StyleBucket> bucket_desc);
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill);
std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line);
- std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon);
- std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text);
+ std::unique_ptr<Bucket> createSymbolBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketSymbol &symbol);
- template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter);
- template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args);
+ template <class Bucket> void addBucketGeometries(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter);
private:
const VectorTile vector_data;
diff --git a/include/mbgl/renderer/icon_bucket.hpp b/include/mbgl/renderer/icon_bucket.hpp
deleted file mode 100644
index e3b311332d..0000000000
--- a/include/mbgl/renderer/icon_bucket.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef MBGL_RENDERER_ICONBUCKET
-#define MBGL_RENDERER_ICONBUCKET
-
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/geometry/icon_buffer.hpp>
-#include <mbgl/style/style_bucket.hpp>
-
-#include <vector>
-#include <memory>
-
-#ifndef BUFFER_OFFSET
-#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
-#endif
-
-namespace mbgl {
-
-class Style;
-class IconVertexBuffer;
-class BucketDescription;
-class IconShader;
-class DotShader;
-class SpriteAtlas;
-class VectorTileFeature;
-
-class IconBucket : public Bucket {
-public:
- IconBucket(IconVertexBuffer& vertexBuffer,
- const StyleBucketIcon& properties);
-
- virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
- virtual bool hasData() const;
-
- void addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas);
-
- void drawIcons(IconShader& shader);
- void drawIcons(DotShader& shader);
-
-public:
- const StyleBucketIcon &properties;
-
-private:
-
- IconVertexBuffer& vertexBuffer;
- VertexArrayObject array;
-
- const size_t vertex_start;
- size_t vertex_end = 0;
-};
-
-}
-
-#endif
diff --git a/include/mbgl/renderer/painter.hpp b/include/mbgl/renderer/painter.hpp
index dedb4dc120..b4023de167 100644
--- a/include/mbgl/renderer/painter.hpp
+++ b/include/mbgl/renderer/painter.hpp
@@ -38,8 +38,7 @@ class StyleSource;
class FillBucket;
class LineBucket;
-class IconBucket;
-class TextBucket;
+class SymbolBucket;
class RasterBucket;
struct FillProperties;
@@ -83,8 +82,7 @@ public:
void renderFill(FillBucket& bucket, const FillProperties& properties, const Tile::ID& id, const mat4 &mat);
void renderFill(FillBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
void renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
- void renderIcon(IconBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
- void renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ void renderSymbol(SymbolBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
void renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
void preparePrerender(PrerenderedTexture &texture);
@@ -119,7 +117,7 @@ public:
bool needsAnimation() const;
private:
void setupShaders();
- const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Default);
+ const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Map);
void prepareTile(const Tile& tile);
diff --git a/include/mbgl/renderer/symbol_bucket.hpp b/include/mbgl/renderer/symbol_bucket.hpp
new file mode 100644
index 0000000000..a073856d2b
--- /dev/null
+++ b/include/mbgl/renderer/symbol_bucket.hpp
@@ -0,0 +1,82 @@
+#ifndef MBGL_RENDERER_SYMBOLBUCKET
+#define MBGL_RENDERER_SYMBOLBUCKET
+
+#include "bucket.hpp"
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/text/types.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <memory>
+#include <map>
+#include <vector>
+
+namespace mbgl {
+
+class Style;
+class TextVertexBuffer;
+class IconVertexBuffer;
+class TriangleElementsBuffer;
+class TextShader;
+class IconShader;
+class DotShader;
+class Placement;
+class SpriteAtlas;
+class GlyphAtlas;
+class GlyphStore;
+class FontStack;
+
+class SymbolBucket : public Bucket {
+ typedef ElementGroup triangle_group_type;
+
+public:
+ SymbolBucket(
+ TextVertexBuffer &textVertexBuffer,
+ IconVertexBuffer& iconVertexBuffer,
+ TriangleElementsBuffer &triangleElementsBuffer,
+ const StyleBucketSymbol &properties, Placement &placement);
+
+ virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id);
+ virtual bool hasData() const;
+ virtual bool hasTextData() const;
+ virtual bool hasIconData() const;
+
+ void addFeatures(const VectorTileLayer &layer, const FilterExpression &filter,
+ const Tile::ID &id, SpriteAtlas &spriteAtlas, GlyphAtlas &glyphAtlas,
+ GlyphStore &glyphStore);
+
+ void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, PlacementRange placementRange,
+ float zoom);
+
+
+ void drawGlyphs(TextShader &shader);
+ void drawIcons(IconShader& shader);
+ void drawIcons(DotShader& shader);
+
+private:
+ void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string,
+ const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face);
+ void addFeature(const pbf &geom_pbf, const GlyphPositions &face, const Shaping &shaping);
+
+public:
+ const StyleBucketSymbol &properties;
+
+private:
+ TextVertexBuffer& textVertexBuffer;
+ IconVertexBuffer& iconVertexBuffer;
+ TriangleElementsBuffer& triangleElementsBuffer;
+ Placement &placement;
+
+ const size_t text_vertex_start;
+ const size_t icon_vertex_start;
+ const size_t triangle_elements_start;
+ size_t icon_vertex_end = 0;
+ VertexArrayObject array;
+
+ std::vector<triangle_group_type> triangleGroups;
+};
+}
+
+#endif
diff --git a/include/mbgl/renderer/text_bucket.hpp b/include/mbgl/renderer/text_bucket.hpp
deleted file mode 100644
index cb4b8f2cda..0000000000
--- a/include/mbgl/renderer/text_bucket.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef MBGL_RENDERER_TEXTBUCKET
-#define MBGL_RENDERER_TEXTBUCKET
-
-#include "bucket.hpp"
-#include <mbgl/geometry/vao.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/text/types.hpp>
-#include <mbgl/text/glyph.hpp>
-#include <mbgl/style/style_bucket.hpp>
-
-#include <memory>
-#include <map>
-#include <vector>
-
-namespace mbgl {
-
-class Style;
-class TextVertexBuffer;
-class TriangleElementsBuffer;
-class TextShader;
-class Placement;
-struct pbf;
-
-class TextBucket : public Bucket {
- typedef ElementGroup triangle_group_type;
-
-public:
- TextBucket(
- TextVertexBuffer &vertexBuffer,
- TriangleElementsBuffer &triangleElementsBuffer,
- const StyleBucketText &properties, Placement &placement);
-
- virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id);
- virtual bool hasData() const;
-
- void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom,
- PlacementRange placementRange, float zoom);
-
- void addFeature(const pbf &geometry,
- const GlyphPositions &face,
- const Shaping &shaping);
-
- void drawGlyphs(TextShader &shader);
-
-public:
- const StyleBucketText &properties;
-
-private:
- TextVertexBuffer& vertexBuffer;
- TriangleElementsBuffer& triangleElementsBuffer;
- Placement &placement;
-
- const size_t vertex_start;
- const size_t triangle_elements_start;
-
- std::vector<triangle_group_type> triangleGroups;
-};
-}
-
-#endif
diff --git a/include/mbgl/style/property_key.hpp b/include/mbgl/style/property_key.hpp
index d5553ebf0d..68dc709597 100644
--- a/include/mbgl/style/property_key.hpp
+++ b/include/mbgl/style/property_key.hpp
@@ -35,6 +35,7 @@ enum class PropertyKey {
IconHaloColor,
IconHaloWidth,
IconHaloBlur,
+ IconTranslate, // for transitions only
IconTranslateX,
IconTranslateY,
IconTranslateAnchor,
@@ -45,6 +46,7 @@ enum class PropertyKey {
TextHaloColor,
TextHaloWidth,
TextHaloBlur,
+ TextTranslate, // for transitions only
TextTranslateX,
TextTranslateY,
TextTranslateAnchor,
diff --git a/include/mbgl/style/style_bucket.hpp b/include/mbgl/style/style_bucket.hpp
index 6948a96158..af76650e56 100644
--- a/include/mbgl/style/style_bucket.hpp
+++ b/include/mbgl/style/style_bucket.hpp
@@ -18,52 +18,27 @@ class Source;
class StyleBucketFill {
public:
- WindingType winding = WindingType::Default;
+ WindingType winding = WindingType::NonZero;
};
class StyleBucketLine {
public:
- CapType cap = CapType::Default;
- JoinType join = JoinType::Default;
+ CapType cap = CapType::Butt;
+ JoinType join = JoinType::Miter;
float miter_limit = 2.0f;
float round_limit = 1.0f;
};
-class StyleBucketIcon {
+class StyleBucketSymbol {
public:
- uint16_t size = 16;
- vec2<float> translate {0, 0};
- TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
- std::string icon;
- float spacing = 0.0f;
- float padding = 2.0f;
-};
-
-class StyleBucketText {
-public:
- std::string field;
- TextPathType path = TextPathType::Default;
- TextTransformType transform = TextTransformType::Default;
- std::string font;
- float max_size = 16.0f;
- float max_width = 15.0f * 24;
- float line_height = 1.2f * 24;
- float letter_spacing = 0.0f;
- float alignment = 0.5f;
- float vertical_alignment = 0.5;
- vec2<float> translate {0, 0};
- TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
- float max_angle_delta = 45.0f;
- float min_distance = 250.0f;
- float rotate = 0.0f; // what is this?
- float padding = 2.0f;
- float slant = 0.0f;
- bool always_visible = false;
-};
-
-class StyleBucketSymbol : util::noncopyable {
-public:
- PlacementType placement = PlacementType::Default;
+ // Make movable only.
+ inline StyleBucketSymbol() = default;
+ inline StyleBucketSymbol(StyleBucketSymbol &&) = default;
+ inline StyleBucketSymbol& operator=(StyleBucketSymbol &&) = default;
+ inline StyleBucketSymbol(const StyleBucketSymbol &) = delete;
+ inline StyleBucketSymbol& operator=(const StyleBucketSymbol &) = delete;
+
+ PlacementType placement = PlacementType::Point;
float min_distance = 250.0f;
struct {
@@ -76,6 +51,7 @@ public:
float padding = 2.0f;
bool keep_upright = false;
vec2<float> offset = {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
} icon;
struct {
@@ -96,6 +72,7 @@ public:
bool keep_upright = true;
TextTransformType transform = TextTransformType::None;
vec2<float> offset = {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
bool allow_overlap = false;
bool ignore_placement = false;
bool optional = false;
@@ -106,9 +83,8 @@ class StyleBucketRaster {
public:
};
-typedef util::variant<StyleBucketFill, StyleBucketLine, StyleBucketIcon,
- StyleBucketText, StyleBucketRaster,
- std::false_type> StyleBucketRender;
+typedef util::variant<StyleBucketFill, StyleBucketLine, StyleBucketSymbol,
+ StyleBucketRaster, std::false_type> StyleBucketRender;
class StyleBucket {
diff --git a/include/mbgl/style/style_parser.hpp b/include/mbgl/style/style_parser.hpp
index 431e3af8db..8b8dc74f21 100644
--- a/include/mbgl/style/style_parser.hpp
+++ b/include/mbgl/style/style_parser.hpp
@@ -62,8 +62,8 @@ private:
// Parses optional properties into a render bucket.
template<typename T>
bool parseRenderProperty(JSVal value, T &target, const char *name);
- template <typename T, typename Parser>
- bool parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser);
+ template <typename Parser, typename T>
+ bool parseRenderProperty(JSVal value, T &target, const char *name);
// Parses optional properties into style class properties.
template <typename T>
diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp
index 9575347be3..35ea97781b 100644
--- a/include/mbgl/style/style_properties.hpp
+++ b/include/mbgl/style/style_properties.hpp
@@ -19,7 +19,7 @@ struct FillProperties {
Color fill_color = {{ 0, 0, 0, 1 }};
Color stroke_color = {{ 0, 0, 0, -1 }};
std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
std::string image;
inline bool isVisible() const {
@@ -32,7 +32,7 @@ struct LineProperties {
float opacity = 1.0f;
Color color = {{ 0, 0, 0, 1 }};
std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
float width = 1;
float offset = 0;
float blur = 0;
@@ -44,31 +44,6 @@ struct LineProperties {
}
};
-struct IconProperties {
- inline IconProperties() {}
- float opacity = 1.0f;
- float rotate = 0.0f;
- RotateAnchorType rotate_anchor = RotateAnchorType::Default;
-
- inline bool isVisible() const {
- return opacity > 0;
- }
-};
-
-struct TextProperties {
- inline TextProperties() {}
- float opacity = 1.0f;
- float size = 12.0f;
- Color color = {{ 0, 0, 0, 1 }};
- Color halo_color = {{ 1, 1, 1, 0.75 }};
- float halo_width = 0.25f;
- float halo_blur = 1.0f;
-
- inline bool isVisible() const {
- return opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0;
- }
-};
-
struct SymbolProperties {
inline SymbolProperties() {}
@@ -133,8 +108,7 @@ struct BackgroundProperties {
typedef util::variant<
FillProperties,
LineProperties,
- IconProperties,
- TextProperties,
+ SymbolProperties,
CompositeProperties,
RasterProperties,
BackgroundProperties,
diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp
index 70090a7e36..55b7685fd3 100644
--- a/include/mbgl/style/types.hpp
+++ b/include/mbgl/style/types.hpp
@@ -11,12 +11,13 @@ namespace mbgl {
// Stores a premultiplied color, with all four channels ranging from 0..1
typedef std::array<float, 4> Color;
+// -------------------------------------------------------------------------------------------------
+
enum class StyleLayerType : uint8_t {
Unknown,
Fill,
Line,
- Icon,
- Text,
+ Symbol,
Raster,
Composite,
Background
@@ -26,170 +27,172 @@ MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, {
{ StyleLayerType::Unknown, "unknown" },
{ StyleLayerType::Fill, "fill" },
{ StyleLayerType::Line, "line" },
- { StyleLayerType::Icon, "icon" },
- { StyleLayerType::Text, "text" },
+ { StyleLayerType::Symbol, "symbol" },
{ StyleLayerType::Raster, "raster" },
{ StyleLayerType::Composite, "composite" },
{ StyleLayerType::Background, "background" },
{ StyleLayerType(-1), "unknown" },
});
+// -------------------------------------------------------------------------------------------------
-enum class WindingType : uint8_t {
+enum class SourceType : uint8_t {
+ Vector,
+ Raster,
+ GeoJSON,
+ Video
+};
+
+MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, {
+ { SourceType::Vector, "vector" },
+ { SourceType::Raster, "raster" },
+ { SourceType::GeoJSON, "geojson" },
+ { SourceType::Video, "video" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class WindingType : bool {
EvenOdd,
NonZero,
- Default = NonZero
};
+MBGL_DEFINE_ENUM_CLASS(WindingTypeClass, WindingType, {
+ { WindingType::EvenOdd, "even-odd" },
+ { WindingType::NonZero, "non-zero" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class CapType : uint8_t {
Round,
Butt,
Square,
- Default = Butt
};
+MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, {
+ { CapType::Round, "round" },
+ { CapType::Butt, "butt" },
+ { CapType::Square, "square" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class JoinType : uint8_t {
Miter,
Bevel,
- Round,
- Default = Miter
+ Round
};
-enum class TextPathType : uint8_t {
- Horizontal,
- Curve,
- Default = Horizontal
-};
+MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, {
+ { JoinType::Miter, "miter" },
+ { JoinType::Bevel, "bevel" },
+ { JoinType::Round, "round" },
+});
-enum class PlacementType : bool {
- Point,
- Line,
- Default = Point
-};
+// -------------------------------------------------------------------------------------------------
-enum class TextTransformType : uint8_t {
- None,
- Uppercase,
- Lowercase,
- Default = None
+enum class TranslateAnchorType : bool {
+ Map,
+ Viewport
};
-enum class TranslateAnchorType : uint8_t {
+MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, {
+ { TranslateAnchorType::Map, "map" },
+ { TranslateAnchorType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class RotateAnchorType : bool {
Map,
Viewport,
- Default = Map
};
-enum class RotateAnchorType : uint8_t {
- Map,
- Viewport,
- Default = Viewport
+MBGL_DEFINE_ENUM_CLASS(RotateAnchorTypeClass, RotateAnchorType, {
+ { RotateAnchorType::Map, "map" },
+ { RotateAnchorType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class PlacementType : bool {
+ Point,
+ Line,
};
+MBGL_DEFINE_ENUM_CLASS(PlacementTypeClass, PlacementType, {
+ { PlacementType::Point, "point" },
+ { PlacementType::Line, "line" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class RotationAlignmentType : bool {
Map,
Viewport,
- Default = Viewport
};
+MBGL_DEFINE_ENUM_CLASS(RotationAlignmentTypeClass, RotationAlignmentType, {
+ { RotationAlignmentType::Map, "map" },
+ { RotationAlignmentType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class TextJustifyType : uint8_t {
Center,
Left,
- Right,
- Default = Center
+ Right
};
+MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, {
+ { TextJustifyType::Center, "center" },
+ { TextJustifyType::Left, "left" },
+ { TextJustifyType::Right, "right" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class TextHorizontalAlignType : uint8_t {
Left,
Center,
Right,
- Default = Center
};
+MBGL_DEFINE_ENUM_CLASS(TextHorizontalAlignTypeClass, TextHorizontalAlignType, {
+ { TextHorizontalAlignType::Left, "left" },
+ { TextHorizontalAlignType::Center, "center" },
+ { TextHorizontalAlignType::Right, "right" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class TextVerticalAlignType : uint8_t {
Top,
Center,
Bottom,
- Default = Center
-};
-
-enum class SourceType : uint8_t {
- Vector,
- Raster,
- GeoJSON,
- Video,
- Default = Vector
};
-inline WindingType parseWindingType(const std::string &type) {
- if (type == "even-odd") return WindingType::EvenOdd;
- if (type == "non-zero") return WindingType::NonZero;
- return WindingType::Default;
-}
-
-inline CapType parseCapType(const std::string &cap) {
- if (cap == "round") return CapType::Round;
- if (cap == "butt") return CapType::Butt;
- if (cap == "square") return CapType::Square;
- return CapType::Default;
-}
-
-inline JoinType parseJoinType(const std::string &join) {
- if (join == "miter") return JoinType::Miter;
- if (join == "bevel") return JoinType::Bevel;
- if (join == "round") return JoinType::Round;
- return JoinType::Default;
-}
-
-inline TextPathType parseTextPathType(const std::string &path) {
- if (path == "horizontal") return TextPathType::Horizontal;
- if (path == "curve") return TextPathType::Curve;
- return TextPathType::Default;
-}
+MBGL_DEFINE_ENUM_CLASS(TextVerticalAlignTypeClass, TextVerticalAlignType, {
+ { TextVerticalAlignType::Top, "top" },
+ { TextVerticalAlignType::Center, "center" },
+ { TextVerticalAlignType::Bottom, "bottom" },
+});
-inline PlacementType parsePlacementType(const std::string &path) {
- if (path == "point") return PlacementType::Point;
- if (path == "line") return PlacementType::Line;
- return PlacementType::Default;
-}
+// -------------------------------------------------------------------------------------------------
-inline TextTransformType parseTextTransformType(const std::string& transform) {
- if (transform == "uppercase") return TextTransformType::Uppercase;
- if (transform == "lowercase") return TextTransformType::Lowercase;
- return TextTransformType::Default;
+enum class TextTransformType : uint8_t {
+ None,
+ Uppercase,
+ Lowercase,
};
-inline TranslateAnchorType parseTranslateAnchorType(const std::string &anchor) {
- if (anchor == "map") return TranslateAnchorType::Map;
- if (anchor == "viewport") return TranslateAnchorType::Viewport;
- return TranslateAnchorType::Default;
-}
-
-inline RotateAnchorType parseRotateAnchorType(const std::string &anchor) {
- if (anchor == "map") return RotateAnchorType::Map;
- if (anchor == "viewport") return RotateAnchorType::Viewport;
- return RotateAnchorType::Default;
-}
-
-inline float parseAlignmentType(const std::string &alignment) {
- if (alignment == "right") return 1.0f;
- if (alignment == "left") return 0.0f;
- return 0.5f;
-}
-
-inline float parseVerticalAlignmentType(const std::string &alignment) {
- if (alignment == "bottom") return 1.0f;
- if (alignment == "top") return 0.0f;
- return 0.5f;
-}
-
-inline SourceType parseSourceType(const std::string &source) {
- if (source == "vector") return SourceType::Vector;
- if (source == "raster") return SourceType::Raster;
- if (source == "geojson") return SourceType::GeoJSON;
- if (source == "video") return SourceType::Video;
- return SourceType::Default;
-}
+MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, {
+ { TextTransformType::None, "none" },
+ { TextTransformType::Uppercase, "uppercase" },
+ { TextTransformType::Lowercase, "lowercase" },
+});
}
diff --git a/include/mbgl/text/placement.hpp b/include/mbgl/text/placement.hpp
index aa03712e30..7700f32f0a 100644
--- a/include/mbgl/text/placement.hpp
+++ b/include/mbgl/text/placement.hpp
@@ -9,15 +9,15 @@
namespace mbgl {
-class TextBucket;
-class StyleBucketText;
+class SymbolBucket;
+class StyleBucketSymbol;
class Placement {
public:
Placement(int8_t zoom, float placementDepth);
- void addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
- const StyleBucketText &info,
+ void addFeature(SymbolBucket &bucket, const std::vector<Coordinate> &line,
+ const StyleBucketSymbol &info,
const GlyphPositions &face,
const Shaping &shaping);
diff --git a/src/map/map.cpp b/src/map/map.cpp
index 9252a57cce..ca43662e09 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -683,13 +683,9 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
if (pass == Opaque) return;
if (!layer_desc->getProperties<LineProperties>().isVisible()) return;
break;
- case StyleLayerType::Icon:
+ case StyleLayerType::Symbol:
if (pass == Opaque) return;
- if (!layer_desc->getProperties<IconProperties>().isVisible()) return;
- break;
- case StyleLayerType::Text:
- if (pass == Opaque) return;
- if (!layer_desc->getProperties<TextProperties>().isVisible()) return;
+ if (!layer_desc->getProperties<SymbolProperties>().isVisible()) return;
break;
case StyleLayerType::Raster:
if (pass == Translucent) return;
diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp
index 807e827972..6be9bcb32c 100644
--- a/src/map/tile_parser.cpp
+++ b/src/map/tile_parser.cpp
@@ -6,8 +6,7 @@
#include <mbgl/style/style_layer_group.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/renderer/icon_bucket.hpp>
-#include <mbgl/renderer/text_bucket.hpp>
+#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/util/raster.hpp>
#include <mbgl/util/constants.hpp>
@@ -51,21 +50,6 @@ void TileParser::parse() {
bool TileParser::obsolete() const { return tile.state == TileData::State::obsolete; }
-void TileParser::addGlyph(uint64_t tileid, const std::string stackname,
- const std::u32string &string, const FontStack &fontStack,
- GlyphAtlas &glyphAtlas, GlyphPositions &face) {
- const std::map<uint32_t, SDFGlyph> &sdfs = fontStack.getSDFs();
- // Loop through all characters and add glyph to atlas, positions.
- for (uint32_t chr : string) {
- auto sdf_it = sdfs.find(chr);
- if (sdf_it != sdfs.end()) {
- const SDFGlyph& sdf = sdf_it->second;
- const Rect<uint16_t> rect = glyphAtlas.addGlyph(tileid, stackname, sdf);
- face.emplace(chr, Glyph{rect, sdf.metrics});
- }
- }
-}
-
void TileParser::parseStyleLayers(std::shared_ptr<StyleLayerGroup> group) {
if (!group) {
return;
@@ -119,10 +103,8 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu
return createFillBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketFill>());
} else if (bucket_desc->render.is<StyleBucketLine>()) {
return createLineBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketLine>());
- } else if (bucket_desc->render.is<StyleBucketIcon>()) {
- return createIconBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketIcon>());
- } else if (bucket_desc->render.is<StyleBucketText>()) {
- return createTextBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketText>());
+ } else if (bucket_desc->render.is<StyleBucketSymbol>()) {
+ return createSymbolBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketSymbol>());
} else if (bucket_desc->render.is<StyleBucketRaster>()) {
return nullptr;
} else {
@@ -140,7 +122,7 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu
}
template <class Bucket>
-void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) {
+void TileParser::addBucketGeometries(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) {
FilteredVectorTileLayer filtered_layer(layer, filter);
for (pbf feature : filtered_layer) {
if (obsolete())
@@ -157,103 +139,20 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer,
}
}
-template <class Bucket, typename... Args>
-void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args) {
- FilteredVectorTileLayer filtered_layer(layer, filter);
- for (const pbf &feature_pbf : filtered_layer) {
- if (obsolete()) {
- return;
- }
- bucket->addFeature({feature_pbf, layer}, std::forward<Args>(args)...);
- }
-}
-
-
std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill) {
std::unique_ptr<FillBucket> bucket = std::make_unique<FillBucket>(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, fill);
- addBucketFeatures(bucket, layer, filter);
+ addBucketGeometries(bucket, layer, filter);
return obsolete() ? nullptr : std::move(bucket);
}
std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line) {
std::unique_ptr<LineBucket> bucket = std::make_unique<LineBucket>(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, line);
- addBucketFeatures(bucket, layer, filter);
+ addBucketGeometries(bucket, layer, filter);
return obsolete() ? nullptr : std::move(bucket);
}
-std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon) {
- std::unique_ptr<IconBucket> bucket = std::make_unique<IconBucket>(tile.iconVertexBuffer, icon);
- addBucketFeatures(bucket, layer, filter, *spriteAtlas);
+std::unique_ptr<Bucket> TileParser::createSymbolBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketSymbol &symbol) {
+ std::unique_ptr<SymbolBucket> bucket = std::make_unique<SymbolBucket>(tile.textVertexBuffer, tile.iconVertexBuffer, tile.triangleElementsBuffer, symbol, placement);
+ bucket->addFeatures(layer, filter, tile.id, *spriteAtlas, *glyphAtlas, *glyphStore);
return obsolete() ? nullptr : std::move(bucket);
}
-
-std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text) {
-
- // Make sure that we always have a valid glyph store. If this is not set, the stylesheet
- // doesn't specify a glyph URL.
- if (!glyphStore) {
- return nullptr;
- }
-
- const StyleBucketText &properties = text;
-
- std::unique_ptr<TextBucket> bucket = std::make_unique<TextBucket>(
- tile.textVertexBuffer, tile.triangleElementsBuffer, properties, placement);
-
- util::utf8_to_utf32 ucs4conv;
-
- std::vector<std::pair<std::u32string, pbf>> labels;
-
- // Determine and load glyph ranges
- {
- std::set<GlyphRange> ranges;
-
- FilteredVectorTileLayer filtered_layer(layer, filter);
- for (const pbf &feature_pbf : filtered_layer) {
- if (obsolete())
- return nullptr;
- VectorTileFeature feature{feature_pbf, layer};
-
- std::string u8string = util::replaceTokens(properties.field, feature.properties);
-
- auto& convert = std::use_facet<std::ctype<char>>(std::locale());
- if (properties.transform == TextTransformType::Uppercase) {
- convert.toupper(&u8string[0], &u8string[0] + u8string.size());
- } else if (properties.transform == TextTransformType::Lowercase) {
- convert.tolower(&u8string[0], &u8string[0] + u8string.size());
- }
-
- std::u32string string = ucs4conv.convert(u8string);
-
- // Loop through all characters of this text and collect unique codepoints.
- for (char32_t chr : string) {
- ranges.insert(getGlyphRange(chr));
- }
-
- labels.emplace_back(string, feature.geometry);
- }
-
- glyphStore->waitForGlyphRanges(properties.font, ranges);
- }
-
- // Create a copy!
- const FontStack &fontStack = glyphStore->getFontStack(properties.font);
- GlyphPositions face;
-
- // Shape and place all labels.
- for (const std::pair<std::u32string, pbf> &label : labels) {
-
- // Shape labels.
- const Shaping shaping = fontStack.getShaping(label.first, properties.max_width,
- properties.line_height, properties.alignment,
- properties.vertical_alignment, properties.letter_spacing);
-
- // Place labels.
- addGlyph(tile.id.to_uint64(), properties.font, label.first, fontStack, *glyphAtlas,
- face);
-
- bucket->addFeature(label.second, face, shaping);
- }
-
- return std::move(bucket);
-}
diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp
deleted file mode 100644
index af988fee80..0000000000
--- a/src/renderer/icon_bucket.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <mbgl/renderer/icon_bucket.hpp>
-#include <mbgl/geometry/icon_buffer.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/geometry/geometry.hpp>
-#include <mbgl/geometry/sprite_atlas.hpp>
-
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/map/sprite.hpp>
-#include <mbgl/map/vector_tile.hpp>
-
-#include <mbgl/platform/gl.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/token.hpp>
-
-#include <cassert>
-
-struct geometry_too_long_exception : std::exception {};
-
-using namespace mbgl;
-
-IconBucket::IconBucket(IconVertexBuffer& vertexBuffer,
- const StyleBucketIcon& properties)
- : properties(properties),
- vertexBuffer(vertexBuffer),
- vertex_start(vertexBuffer.index()) {
-}
-
-void IconBucket::addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas) {
- std::string field;
-
- if (properties.icon.size()) {
- field = util::replaceTokens(properties.icon, feature.properties);
- }
-
- if (!field.size()) {
- field = "<circle>";
- }
-
- const Rect<uint16_t> rect = sprite_atlas.getIcon(properties.size, field);
- const uint16_t tx = rect.x + rect.w / 2;
- const uint16_t ty = rect.y + rect.h / 2;
-
- Geometry::command cmd;
- pbf geom = feature.geometry;
- Geometry geometry(geom);
- int32_t x, y;
- while ((cmd = geometry.next(x, y)) != Geometry::end) {
- if (cmd == Geometry::move_to) {
- vertexBuffer.add(x, y, tx, ty);
- } else {
- if (debug::tileParseWarnings) {
- fprintf(stderr, "[WARNING] other command than move_to in icon geometry\n");
- }
- }
- }
-
- vertex_end = vertexBuffer.index();
-}
-
-void IconBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
- painter.renderIcon(*this, layer_desc, id);
-}
-
-bool IconBucket::hasData() const {
- return vertex_end > 0;
-}
-
-void IconBucket::drawIcons(IconShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- array.bind(shader, vertexBuffer, vertex_index);
- glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start));
-}
-
-void IconBucket::drawIcons(DotShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- array.bind(shader, vertexBuffer, vertex_index);
- glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start));
-}
diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp
index 74cfba3c6d..2e04820e42 100644
--- a/src/renderer/line_bucket.cpp
+++ b/src/renderer/line_bucket.cpp
@@ -80,7 +80,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
CapType beginCap = properties.cap;
CapType endCap = closed ? CapType::Butt : properties.cap;
- JoinType currentJoin = JoinType::Default;
+ JoinType currentJoin = JoinType::Miter;
Coordinate currentVertex = Coordinate::null(),
prevVertex = Coordinate::null(),
diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp
deleted file mode 100644
index 158030df19..0000000000
--- a/src/renderer/painter_icon.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/icon_bucket.hpp>
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/sprite.hpp>
-#include <mbgl/style/style_layer.hpp>
-#include <mbgl/geometry/sprite_atlas.hpp>
-#include <mbgl/util/math.hpp>
-
-using namespace mbgl;
-
-void Painter::renderIcon(IconBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
- // Abort early.
- if (!bucket.hasData()) return;
- if (pass == Opaque) return;
-
- const IconProperties &properties = layer_desc->getProperties<IconProperties>();
-
-// TODO: when translating icon, are we doing this in the bucket already?
-// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
-
- SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
-
- useProgram(iconShader->program);
- iconShader->setMatrix(matrix);
-// TODO: update
- iconShader->setColor({{ 1, 1, 1, 1 }});
- iconShader->setImage(0);
- iconShader->setRatio(map.getState().getPixelRatio());
- iconShader->setDimension({{
- spriteAtlas.getTextureWidth(),
- spriteAtlas.getTextureHeight(),
- }});
-
- spriteAtlas.bind(map.getState().isChanging());
-
- const float iconSize = bucket.properties.size * map.getState().getPixelRatio();
- iconShader->setSize(iconSize);
-#ifndef GL_ES_VERSION_2_0
- glPointSize(iconSize);
- glEnable(GL_POINT_SPRITE);
-#endif
-
- glDepthRange(strata, 1.0f);
- bucket.drawIcons(*iconShader);
-}
diff --git a/src/renderer/painter_symbol.cpp b/src/renderer/painter_symbol.cpp
new file mode 100644
index 0000000000..8201e4b7f1
--- /dev/null
+++ b/src/renderer/painter_symbol.cpp
@@ -0,0 +1,202 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/style/style_layer.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/geometry/sprite_atlas.hpp>
+#include <mbgl/map/map.hpp>
+#include <mbgl/util/math.hpp>
+#include <cmath>
+
+namespace mbgl {
+
+void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr<StyleLayer> layer_desc,
+ const Tile::ID &id) {
+ // Abort early.
+ if (pass == Opaque) {
+ return;
+ }
+
+ if (bucket.hasTextData()) {
+ const SymbolProperties &properties = layer_desc->getProperties<SymbolProperties>();
+
+ mat4 exMatrix;
+ matrix::copy(exMatrix, projMatrix);
+ if (bucket.properties.placement == PlacementType::Line) {
+ matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle());
+ }
+
+ // If layerStyle.size > bucket.info.fontSize then labels may collide
+ float fontSize = std::fmin(properties.text.size, bucket.properties.text.max_size);
+ matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f);
+
+ // TODO: figure out whether we actually need to account for this while painting; we might
+ // already have
+ // done this during label placement.
+ // const mat4 &vtxMatrix = translatedMatrix(properties.translate, id,
+ // properties.translateAnchor);
+
+ useProgram(textShader->program);
+ textShader->setMatrix(matrix);
+ textShader->setExtrudeMatrix(exMatrix);
+
+ GlyphAtlas &glyphAtlas = *map.getGlyphAtlas();
+ glyphAtlas.bind();
+ textShader->setTextureSize(
+ {{static_cast<float>(glyphAtlas.width), static_cast<float>(glyphAtlas.height)}});
+
+ // Convert the -pi..pi to an int8 range.
+ float angle = std::round((map.getState().getAngle()) / M_PI * 128);
+
+ // adjust min/max zooms for variable font sies
+ float zoomAdjust = log(fontSize / bucket.properties.text.max_size) / log(2);
+
+ textShader->setAngle((int32_t)(angle + 256) % 256);
+ textShader->setFlip(bucket.properties.placement == PlacementType::Line ? 1 : 0);
+ textShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) *
+ 10); // current zoom level
+
+ // Label fading
+ const timestamp duration = 300_milliseconds;
+ const timestamp currentTime = util::now();
+
+ std::deque<FrameSnapshot> &history = frameHistory.history;
+
+ // Remove frames until only one is outside the duration, or until there are only three
+ while (history.size() > 3 && history[1].t + duration < currentTime) {
+ history.pop_front();
+ }
+
+ if (history[1].t + duration < currentTime) {
+ history[0].z = history[1].z;
+ }
+
+ assert("there should never be less than three frames in the history" &&
+ (history.size() >= 3));
+
+ // Find the range of zoom levels we want to fade between
+ float startingZ = history.front().z;
+ const FrameSnapshot lastFrame = history.back();
+ float endingZ = lastFrame.z;
+ float lowZ = std::fmin(startingZ, endingZ);
+ float highZ = std::fmax(startingZ, endingZ);
+
+ // Calculate the speed of zooming, and how far it would zoom in terms of zoom levels in one
+ // duration
+ float zoomDiff = endingZ - history[1].z, timeDiff = lastFrame.t - history[1].t;
+ float fadedist = zoomDiff / (timeDiff / duration);
+
+#if defined(DEBUG)
+ if (std::isnan(fadedist))
+ fprintf(stderr, "fadedist should never be NaN\n");
+#endif
+
+ // At end of a zoom when the zoom stops changing continue pretending to zoom at that speed
+ // bump is how much farther it would have been if it had continued zooming at the same rate
+ float bump = (currentTime - lastFrame.t) / duration * fadedist;
+
+ textShader->setFadeDist(fadedist * 10);
+ textShader->setMinFadeZoom(std::floor(lowZ * 10));
+ textShader->setMaxFadeZoom(std::floor(highZ * 10));
+ textShader->setFadeZoom((map.getState().getNormalizedZoom() + bump) * 10);
+
+ // This defines the gamma around the SDF cutoff value.
+ const float sdfGamma = 0.75f / 10.0f;
+
+ // Our signed distance fields are scaled so that 1 pixel is scaled to 32 pixels.
+ // Our cutoff between positive and negative values is hard coded to 64 (== 2 pixels).
+ // This means that our 6/8 of the value range lies outside the glyph outline.
+ const float sdfOffset = (256.0f - 64.0f) / 32.0f;
+
+ // Currently, all of our fonts are rendered with a font size of 24px.
+ const float sdfFontSize = 24.0f;
+
+ // The default gamma value has to be adjust for the current pixelratio so that we're not
+ // drawing
+ // blurry font on retina screens.
+ const float gamma = sdfGamma * sdfFontSize / fontSize / map.getState().getPixelRatio();
+
+ // We're drawing in the translucent pass which is bottom-to-top, so we need
+ // to draw the halo first.
+ if (properties.text.halo_color[3] > 0.0f) {
+ const float haloWidth = util::clamp(
+ (sdfOffset - properties.text.halo_width / (fontSize / sdfFontSize)) / 8.0f, 0.0f,
+ 1.0f);
+
+ if (properties.text.halo_blur != 0.0f) {
+ // We are converting the halo_blur value to current screen pixels.
+ // Then we're dividing it by two because the gamma value is added/subtracted into
+ // both
+ // directions in the shader, but the halo_blur describes the entire width of the
+ // blur.
+ // Note that this does *not* have to be adjusted for retina screens, because we want
+ // the
+ // same blur width when we explicitly specify one.
+ textShader->setGamma((properties.text.halo_blur / (fontSize / sdfFontSize)) / 8.0f /
+ 2.0f);
+ } else {
+ textShader->setGamma(sdfGamma);
+ }
+
+ if (properties.text.opacity < 1.0f) {
+ Color color = properties.text.halo_color;
+ color[0] *= properties.text.opacity;
+ color[1] *= properties.text.opacity;
+ color[2] *= properties.text.opacity;
+ color[3] *= properties.text.opacity;
+ textShader->setColor(color);
+ } else {
+ textShader->setColor(properties.text.halo_color);
+ }
+ textShader->setBuffer(haloWidth);
+ glDepthRange(strata, 1.0f);
+ bucket.drawGlyphs(*textShader);
+ }
+
+ if (properties.text.color[3] > 0.0f) {
+ // Then, we draw the text over the halo
+ textShader->setGamma(gamma);
+ if (properties.text.opacity < 1.0f) {
+ Color color = properties.text.color;
+ color[0] *= properties.text.opacity;
+ color[1] *= properties.text.opacity;
+ color[2] *= properties.text.opacity;
+ color[3] *= properties.text.opacity;
+ textShader->setColor(color);
+ } else {
+ textShader->setColor(properties.text.color);
+ }
+ textShader->setBuffer((256.0f - 64.0f) / 256.0f);
+ glDepthRange(strata + strata_epsilon, 1.0f);
+ bucket.drawGlyphs(*textShader);
+ }
+ }
+
+ if (bucket.hasIconData()) {
+ SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
+
+ useProgram(iconShader->program);
+ iconShader->setMatrix(matrix);
+
+ // TODO: update
+ iconShader->setColor({{1, 1, 1, 1}});
+ iconShader->setImage(0);
+ iconShader->setRatio(map.getState().getPixelRatio());
+ iconShader->setDimension({{
+ spriteAtlas.getTextureWidth(), spriteAtlas.getTextureHeight(),
+ }});
+
+ spriteAtlas.bind(map.getState().isChanging());
+
+ // TODO: remove hardcoded icon size.
+ const float iconSize = 12 * map.getState().getPixelRatio();
+ iconShader->setSize(iconSize);
+#ifndef GL_ES_VERSION_2_0
+ glPointSize(iconSize);
+ glEnable(GL_POINT_SPRITE);
+#endif
+
+ glDepthRange(strata, 1.0f);
+ bucket.drawIcons(*iconShader);
+ }
+}
+}
diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp
deleted file mode 100644
index d5ad3db51f..0000000000
--- a/src/renderer/painter_text.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/text_bucket.hpp>
-#include <mbgl/style/style_layer.hpp>
-#include <mbgl/geometry/glyph_atlas.hpp>
-#include <mbgl/map/map.hpp>
-#include <mbgl/util/math.hpp>
-#include <cmath>
-
-using namespace mbgl;
-
-void Painter::renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
- // Abort early.
- if (pass == Opaque) return;
- if (!bucket.hasData()) return;
-
- const TextProperties &properties = layer_desc->getProperties<TextProperties>();
-
- mat4 exMatrix;
- matrix::copy(exMatrix, projMatrix);
- if (bucket.properties.path == TextPathType::Curve) {
- matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle());
- }
-
- // If layerStyle.size > bucket.info.fontSize then labels may collide
- float fontSize = std::fmin(properties.size, bucket.properties.max_size);
- matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f);
-
-// TODO: figure out whether we actually need to account for this while painting; we might already have
-// done this during label placement.
-// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
-
- useProgram(textShader->program);
- textShader->setMatrix(matrix);
- textShader->setExtrudeMatrix(exMatrix);
-
- GlyphAtlas &glyphAtlas = *map.getGlyphAtlas();
- glyphAtlas.bind();
- textShader->setTextureSize({{static_cast<float>(glyphAtlas.width),
- static_cast<float>(glyphAtlas.height)}});
-
- // Convert the -pi..pi to an int8 range.
- float angle = std::round((map.getState().getAngle()) / M_PI * 128);
-
- // adjust min/max zooms for variable font sies
- float zoomAdjust = log(fontSize / bucket.properties.max_size) / log(2);
-
- textShader->setAngle((int32_t)(angle + 256) % 256);
- textShader->setFlip(bucket.properties.path == TextPathType::Curve ? 1 : 0);
- textShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) * 10); // current zoom level
-
- // Label fading
- const timestamp duration = 300_milliseconds;
- const timestamp currentTime = util::now();
-
- std::deque<FrameSnapshot> &history = frameHistory.history;
-
- // Remove frames until only one is outside the duration, or until there are only three
- while (history.size() > 3 && history[1].t + duration < currentTime) {
- history.pop_front();
- }
-
- if (history[1].t + duration < currentTime) {
- history[0].z = history[1].z;
- }
-
- assert("there should never be less than three frames in the history" && (history.size() >= 3));
-
- // Find the range of zoom levels we want to fade between
- float startingZ = history.front().z;
- const FrameSnapshot lastFrame = history.back();
- float endingZ = lastFrame.z;
- float lowZ = std::fmin(startingZ, endingZ);
- float highZ = std::fmax(startingZ, endingZ);
-
- // Calculate the speed of zooming, and how far it would zoom in terms of zoom levels in one duration
- float zoomDiff = endingZ - history[1].z,
- timeDiff = lastFrame.t - history[1].t;
- float fadedist = zoomDiff / (timeDiff / duration);
-
-#if defined(DEBUG)
- if (std::isnan(fadedist)) fprintf(stderr, "fadedist should never be NaN\n");
-#endif
-
- // At end of a zoom when the zoom stops changing continue pretending to zoom at that speed
- // bump is how much farther it would have been if it had continued zooming at the same rate
- float bump = (currentTime - lastFrame.t) / duration * fadedist;
-
- textShader->setFadeDist(fadedist * 10);
- textShader->setMinFadeZoom(std::floor(lowZ * 10));
- textShader->setMaxFadeZoom(std::floor(highZ * 10));
- textShader->setFadeZoom((map.getState().getNormalizedZoom() + bump) * 10);
-
- // This defines the gamma around the SDF cutoff value.
- const float sdfGamma = 0.75f / 10.0f;
-
- // Our signed distance fields are scaled so that 1 pixel is scaled to 32 pixels.
- // Our cutoff between positive and negative values is hard coded to 64 (== 2 pixels).
- // This means that our 6/8 of the value range lies outside the glyph outline.
- const float sdfOffset = (256.0f - 64.0f) / 32.0f;
-
- // Currently, all of our fonts are rendered with a font size of 24px.
- const float sdfFontSize = 24.0f;
-
- // The default gamma value has to be adjust for the current pixelratio so that we're not drawing
- // blurry font on retina screens.
- const float gamma = sdfGamma * sdfFontSize / fontSize / map.getState().getPixelRatio();
-
- // We're drawing in the translucent pass which is bottom-to-top, so we need
- // to draw the halo first.
- if (properties.halo_color[3] > 0.0f) {
- const float haloWidth = util::clamp((sdfOffset - properties.halo_width / (fontSize / sdfFontSize)) / 8.0f, 0.0f, 1.0f);
-
- if (properties.halo_blur != 0.0f) {
- // We are converting the halo_blur value to current screen pixels.
- // Then we're dividing it by two because the gamma value is added/subtracted into both
- // directions in the shader, but the halo_blur describes the entire width of the blur.
- // Note that this does *not* have to be adjusted for retina screens, because we want the
- // same blur width when we explicitly specify one.
- textShader->setGamma((properties.halo_blur / (fontSize / sdfFontSize)) / 8.0f / 2.0f);
- } else {
- textShader->setGamma(sdfGamma);
- }
-
- if (properties.opacity < 1.0f) {
- Color color = properties.halo_color;
- color[0] *= properties.opacity;
- color[1] *= properties.opacity;
- color[2] *= properties.opacity;
- color[3] *= properties.opacity;
- textShader->setColor(color);
- } else {
- textShader->setColor(properties.halo_color);
- }
- textShader->setBuffer(haloWidth);
- glDepthRange(strata, 1.0f);
- bucket.drawGlyphs(*textShader);
- }
-
- if (properties.color[3] > 0.0f) {
- // Then, we draw the text over the halo
- textShader->setGamma(gamma);
- if (properties.opacity < 1.0f) {
- Color color = properties.color;
- color[0] *= properties.opacity;
- color[1] *= properties.opacity;
- color[2] *= properties.opacity;
- color[3] *= properties.opacity;
- textShader->setColor(color);
- } else {
- textShader->setColor(properties.color);
- }
- textShader->setBuffer((256.0f - 64.0f) / 256.0f);
- glDepthRange(strata + strata_epsilon, 1.0f);
- bucket.drawGlyphs(*textShader);
- }
-}
diff --git a/src/renderer/symbol_bucket.cpp b/src/renderer/symbol_bucket.cpp
new file mode 100644
index 0000000000..60fd6e240a
--- /dev/null
+++ b/src/renderer/symbol_bucket.cpp
@@ -0,0 +1,271 @@
+#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/geometry/text_buffer.hpp>
+#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/geometry/sprite_atlas.hpp>
+#include <mbgl/geometry/geometry.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/text/placement.hpp>
+#include <mbgl/platform/log.hpp>
+
+#include <mbgl/util/utf.hpp>
+#include <mbgl/util/token.hpp>
+#include <mbgl/util/math.hpp>
+
+
+namespace mbgl {
+
+SymbolBucket::SymbolBucket(TextVertexBuffer &textVertexBuffer, IconVertexBuffer &iconVertexBuffer,
+ TriangleElementsBuffer &triangleElementsBuffer,
+ const StyleBucketSymbol &properties, Placement &placement)
+ : properties(properties),
+ textVertexBuffer(textVertexBuffer),
+ iconVertexBuffer(iconVertexBuffer),
+ triangleElementsBuffer(triangleElementsBuffer),
+ placement(placement),
+ text_vertex_start(textVertexBuffer.index()),
+ icon_vertex_start(iconVertexBuffer.index()),
+ triangle_elements_start(triangleElementsBuffer.index()) {}
+
+void SymbolBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc,
+ const Tile::ID &id) {
+ painter.renderSymbol(*this, layer_desc, id);
+}
+
+bool SymbolBucket::hasData() const {
+ return hasTextData() || hasIconData();
+}
+
+
+bool SymbolBucket::hasTextData() const {
+ return !triangleGroups.empty();
+}
+
+bool SymbolBucket::hasIconData() const {
+ return icon_vertex_end > 0;
+}
+
+void SymbolBucket::addGlyph(uint64_t tileid, const std::string stackname,
+ const std::u32string &string, const FontStack &fontStack,
+ GlyphAtlas &glyphAtlas, GlyphPositions &face) {
+ const std::map<uint32_t, SDFGlyph> &sdfs = fontStack.getSDFs();
+ // Loop through all characters and add glyph to atlas, positions.
+ for (uint32_t chr : string) {
+ auto sdf_it = sdfs.find(chr);
+ if (sdf_it != sdfs.end()) {
+ const SDFGlyph& sdf = sdf_it->second;
+ const Rect<uint16_t> rect = glyphAtlas.addGlyph(tileid, stackname, sdf);
+ face.emplace(chr, Glyph{rect, sdf.metrics});
+ }
+ }
+}
+
+void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpression &filter,
+ const Tile::ID &id, SpriteAtlas &spriteAtlas, GlyphAtlas &glyphAtlas,
+ GlyphStore &glyphStore) {
+ const bool text = properties.text.field.size();
+ const bool icon = properties.icon.image.size();
+
+ util::utf8_to_utf32 ucs4conv;
+
+ std::vector<std::pair<std::u32string, pbf>> labels;
+
+ // Determine and load glyph ranges
+ {
+ std::set<GlyphRange> ranges;
+
+ FilteredVectorTileLayer filtered_layer(layer, filter);
+ for (const pbf &feature_pbf : filtered_layer) {
+ VectorTileFeature feature {feature_pbf, layer};
+
+ if (text) {
+ std::string u8string = util::replaceTokens(properties.text.field, feature.properties);
+
+ auto& convert = std::use_facet<std::ctype<char>>(std::locale());
+ if (properties.text.transform == TextTransformType::Uppercase) {
+ convert.toupper(&u8string[0], &u8string[0] + u8string.size());
+ } else if (properties.text.transform == TextTransformType::Lowercase) {
+ convert.tolower(&u8string[0], &u8string[0] + u8string.size());
+ }
+
+ std::u32string string = ucs4conv.convert(u8string);
+
+ if (string.size()) {
+ // Loop through all characters of this text and collect unique codepoints.
+ for (char32_t chr : string) {
+ ranges.insert(getGlyphRange(chr));
+ }
+
+ labels.emplace_back(string, feature.geometry);
+ }
+ }
+
+ // TODO: refactor for simultaneous placement
+ // TODO: refactor to use quads instead of GL_POINTS
+ if (icon) {
+ std::string field = util::replaceTokens(properties.icon.image, feature.properties);
+
+ // TODO: remove hardcoded size 12.
+ const Rect<uint16_t> rect = spriteAtlas.getIcon(12, field);
+ const uint16_t tx = rect.x + rect.w / 2;
+ const uint16_t ty = rect.y + rect.h / 2;
+
+ Geometry::command cmd;
+ pbf geom = feature.geometry;
+ Geometry geometry(geom);
+ int32_t x, y;
+ while ((cmd = geometry.next(x, y)) != Geometry::end) {
+ if (cmd == Geometry::move_to) {
+ iconVertexBuffer.add(x, y, tx, ty);
+ } else {
+ Log::Warning(Event::ParseTile, "other command than move_to in icon geometry");
+ }
+ }
+
+ icon_vertex_end = iconVertexBuffer.index();
+ }
+ }
+
+ glyphStore.waitForGlyphRanges(properties.text.font, ranges);
+ }
+
+
+ float horizontalAlign = 0.5;
+ if (properties.text.horizontal_align == TextHorizontalAlignType::Right) horizontalAlign = 1;
+ else if (properties.text.horizontal_align == TextHorizontalAlignType::Left) horizontalAlign = 0;
+
+ float verticalAlign = 0.5;
+ if (properties.text.vertical_align == TextVerticalAlignType::Bottom) verticalAlign = 1;
+ else if (properties.text.vertical_align == TextVerticalAlignType::Top) verticalAlign = 0;
+
+
+
+ // Create a copy!
+ const FontStack &fontStack = glyphStore.getFontStack(properties.text.font);
+ GlyphPositions face;
+
+
+ // Shape and place all labels.
+ for (const std::pair<std::u32string, pbf> &label : labels) {
+
+ // Shape labels.
+ const Shaping shaping = fontStack.getShaping(label.first, properties.text.max_width,
+ properties.text.line_height, horizontalAlign,
+ verticalAlign, properties.text.letter_spacing);
+
+ addGlyph(id.to_uint64(), properties.text.font, label.first, fontStack, glyphAtlas, face);
+
+ // Place labels.
+ addFeature(label.second, face, shaping);
+ }
+}
+
+void SymbolBucket::addFeature(const pbf &geom_pbf, const GlyphPositions &face,
+ const Shaping &shaping) {
+ // Decode all lines.
+ std::vector<Coordinate> line;
+ Geometry::command cmd;
+
+ Coordinate coord;
+ pbf geom(geom_pbf);
+ Geometry geometry(geom);
+ int32_t x, y;
+ while ((cmd = geometry.next(x, y)) != Geometry::end) {
+ if (cmd == Geometry::move_to) {
+ if (!line.empty()) {
+ placement.addFeature(*this, line, properties, face, shaping);
+ line.clear();
+ }
+ }
+ line.emplace_back(x, y);
+ }
+ if (line.size()) {
+ placement.addFeature(*this, line, properties, face, shaping);
+ }
+}
+
+void SymbolBucket::addGlyphs(const PlacedGlyphs &glyphs, float placementZoom,
+ PlacementRange placementRange, float zoom) {
+ placementZoom += zoom;
+
+ for (const PlacedGlyph &glyph : glyphs) {
+ const auto &tl = glyph.tl;
+ const auto &tr = glyph.tr;
+ const auto &bl = glyph.bl;
+ const auto &br = glyph.br;
+ const auto &tex = glyph.tex;
+ const auto &angle = glyph.angle;
+
+ float minZoom = util::max(static_cast<float>(zoom + log(glyph.glyphBox.minScale) / log(2)),
+ placementZoom);
+ float maxZoom =
+ util::min(static_cast<float>(zoom + log(glyph.glyphBox.maxScale) / log(2)), 25.0f);
+ const auto &glyphAnchor = glyph.glyphBox.anchor;
+
+ if (maxZoom <= minZoom)
+ continue;
+
+ // Lower min zoom so that while fading out the label
+ // it can be shown outside of collision-free zoom levels
+ if (minZoom == placementZoom) {
+ minZoom = 0;
+ }
+
+ const int glyph_vertex_length = 4;
+
+ if (!triangleGroups.size() ||
+ (triangleGroups.back().vertex_length + glyph_vertex_length > 65535)) {
+ // Move to a new group because the old one can't hold the geometry.
+ triangleGroups.emplace_back();
+ }
+
+ // We're generating triangle fans, so we always start with the first
+ // coordinate in this polygon.
+ triangle_group_type &triangleGroup = triangleGroups.back();
+ uint32_t triangleIndex = triangleGroup.vertex_length;
+
+ // coordinates (2 triangles)
+ textVertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tl.x, tl.y, tex.x, tex.y, angle, minZoom,
+ placementRange, maxZoom, placementZoom);
+ textVertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tr.x, tr.y, tex.x + tex.w, tex.y, angle,
+ minZoom, placementRange, maxZoom, placementZoom);
+ textVertexBuffer.add(glyphAnchor.x, glyphAnchor.y, bl.x, bl.y, tex.x, tex.y + tex.h, angle,
+ minZoom, placementRange, maxZoom, placementZoom);
+ textVertexBuffer.add(glyphAnchor.x, glyphAnchor.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h,
+ angle, minZoom, placementRange, maxZoom, placementZoom);
+
+ // add the two triangles, referencing the four coordinates we just inserted.
+ triangleElementsBuffer.add(triangleIndex + 0, triangleIndex + 1, triangleIndex + 2);
+ triangleElementsBuffer.add(triangleIndex + 1, triangleIndex + 2, triangleIndex + 3);
+
+ triangleGroup.vertex_length += glyph_vertex_length;
+ triangleGroup.elements_length += 2;
+ }
+}
+
+void SymbolBucket::drawGlyphs(TextShader &shader) {
+ char *vertex_index = BUFFER_OFFSET(text_vertex_start * textVertexBuffer.itemSize);
+ char *elements_index =
+ BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
+ for (triangle_group_type &group : triangleGroups) {
+ group.array.bind(shader, textVertexBuffer, triangleElementsBuffer, vertex_index);
+ glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
+ vertex_index += group.vertex_length * textVertexBuffer.itemSize;
+ elements_index += group.elements_length * triangleElementsBuffer.itemSize;
+ }
+}
+
+void SymbolBucket::drawIcons(IconShader& shader) {
+ char *vertex_index = BUFFER_OFFSET(icon_vertex_start * iconVertexBuffer.itemSize);
+ array.bind(shader, iconVertexBuffer, vertex_index);
+ glDrawArrays(GL_POINTS, 0, (GLsizei)(icon_vertex_end - icon_vertex_start));
+}
+
+void SymbolBucket::drawIcons(DotShader& shader) {
+ char *vertex_index = BUFFER_OFFSET(icon_vertex_start * iconVertexBuffer.itemSize);
+ array.bind(shader, iconVertexBuffer, vertex_index);
+ glDrawArrays(GL_POINTS, 0, (GLsizei)(icon_vertex_end - icon_vertex_start));
+}
+
+}
diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp
deleted file mode 100644
index 45c7bf971f..0000000000
--- a/src/renderer/text_bucket.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-#include <mbgl/renderer/text_bucket.hpp>
-#include <mbgl/geometry/text_buffer.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/geometry/geometry.hpp>
-
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/text/placement.hpp>
-#include <mbgl/text/glyph_store.hpp>
-#include <mbgl/util/constants.hpp>
-
-#include <mbgl/util/math.hpp>
-#include <mbgl/platform/gl.hpp>
-
-#include <iostream>
-
-#include <cassert>
-
-using namespace mbgl;
-
-TextBucket::TextBucket(
- TextVertexBuffer &vertexBuffer,
- TriangleElementsBuffer &triangleElementsBuffer,
- const StyleBucketText &properties, Placement &placement)
- : properties(properties),
- vertexBuffer(vertexBuffer),
- triangleElementsBuffer(triangleElementsBuffer),
- placement(placement),
- vertex_start(vertexBuffer.index()),
- triangle_elements_start(triangleElementsBuffer.index()) {}
-
-void TextBucket::addGlyphs(const PlacedGlyphs &glyphs, float placementZoom,
- PlacementRange placementRange, float zoom) {
- placementZoom += zoom;
-
- for (const PlacedGlyph &glyph : glyphs) {
- const auto &tl = glyph.tl;
- const auto &tr = glyph.tr;
- const auto &bl = glyph.bl;
- const auto &br = glyph.br;
- const auto &tex = glyph.tex;
- const auto &angle = glyph.angle;
-
- float minZoom = util::max(
- static_cast<float>(zoom + log(glyph.glyphBox.minScale) / log(2)),
- placementZoom);
- float maxZoom = util::min(
- static_cast<float>(zoom + log(glyph.glyphBox.maxScale) / log(2)),
- 25.0f);
- const auto &glyphAnchor = glyph.glyphBox.anchor;
-
- if (maxZoom <= minZoom)
- continue;
-
- // Lower min zoom so that while fading out the label
- // it can be shown outside of collision-free zoom levels
- if (minZoom == placementZoom) {
- minZoom = 0;
- }
-
- const int glyph_vertex_length = 4;
-
- if (!triangleGroups.size() ||
- (triangleGroups.back().vertex_length + glyph_vertex_length >
- 65535)) {
- // Move to a new group because the old one can't hold the geometry.
- triangleGroups.emplace_back();
- }
-
- // We're generating triangle fans, so we always start with the first
- // coordinate in this polygon.
- triangle_group_type &triangleGroup = triangleGroups.back();
- uint32_t triangleIndex = triangleGroup.vertex_length;
-
- // coordinates (2 triangles)
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tl.x, tl.y, tex.x,
- tex.y, angle, minZoom, placementRange, maxZoom,
- placementZoom);
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tr.x, tr.y,
- tex.x + tex.w, tex.y, angle, minZoom, placementRange,
- maxZoom, placementZoom);
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, bl.x, bl.y, tex.x,
- tex.y + tex.h, angle, minZoom, placementRange,
- maxZoom, placementZoom);
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, br.x, br.y,
- tex.x + tex.w, tex.y + tex.h, angle, minZoom,
- placementRange, maxZoom, placementZoom);
-
- // add the two triangles, referencing the four coordinates we just
- // inserted.
- triangleElementsBuffer.add(triangleIndex + 0, triangleIndex + 1,
- triangleIndex + 2);
- triangleElementsBuffer.add(triangleIndex + 1, triangleIndex + 2,
- triangleIndex + 3);
-
- triangleGroup.vertex_length += glyph_vertex_length;
- triangleGroup.elements_length += 2;
- }
-};
-
-void TextBucket::addFeature(const pbf &geom_pbf,
- const GlyphPositions &face,
- const Shaping &shaping) {
- // Decode all lines.
- std::vector<Coordinate> line;
- Geometry::command cmd;
-
- Coordinate coord;
- pbf geom(geom_pbf);
- Geometry geometry(geom);
- int32_t x, y;
- while ((cmd = geometry.next(x, y)) != Geometry::end) {
- if (cmd == Geometry::move_to) {
- if (!line.empty()) {
- placement.addFeature(*this, line, properties, face, shaping);
- line.clear();
- }
- }
- line.emplace_back(x, y);
- }
- if (line.size()) {
- placement.addFeature(*this, line, properties, face, shaping);
- }
-}
-
-void TextBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc,
- const Tile::ID &id) {
- painter.renderText(*this, layer_desc, id);
-}
-
-bool TextBucket::hasData() const {
- return !triangleGroups.empty();
-}
-
-void TextBucket::drawGlyphs(TextShader &shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- char *elements_index =
- BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
- for (triangle_group_type &group : triangleGroups) {
- group.array.bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
- glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
- vertex_index += group.vertex_length * vertexBuffer.itemSize;
- elements_index += group.elements_length * triangleElementsBuffer.itemSize;
- }
-}
diff --git a/src/style/property_fallback.cpp b/src/style/property_fallback.cpp
index fb291034e9..4401c8105a 100644
--- a/src/style/property_fallback.cpp
+++ b/src/style/property_fallback.cpp
@@ -33,6 +33,7 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::IconTranslateX, defaultStyleProperties<SymbolProperties>().icon.translate[0] },
{ PropertyKey::IconTranslateY, defaultStyleProperties<SymbolProperties>().icon.translate[1] },
{ PropertyKey::IconTranslateAnchor, defaultStyleProperties<SymbolProperties>().icon.translate_anchor },
+
{ PropertyKey::TextOpacity, defaultStyleProperties<SymbolProperties>().text.opacity },
{ PropertyKey::TextSize, defaultStyleProperties<SymbolProperties>().text.size },
{ PropertyKey::TextColor, defaultStyleProperties<SymbolProperties>().text.color },
diff --git a/src/style/style_bucket.cpp b/src/style/style_bucket.cpp
index afd4bc09f7..9a40c2386b 100644
--- a/src/style/style_bucket.cpp
+++ b/src/style/style_bucket.cpp
@@ -6,8 +6,7 @@ StyleBucket::StyleBucket(StyleLayerType type) {
switch (type) {
case StyleLayerType::Fill: render = StyleBucketFill{}; break;
case StyleLayerType::Line: render = StyleBucketLine{}; break;
- case StyleLayerType::Icon: render = StyleBucketIcon{}; break;
- case StyleLayerType::Text: render = StyleBucketText{}; break;
+ case StyleLayerType::Symbol: render = StyleBucketSymbol{}; break;
case StyleLayerType::Raster: render = StyleBucketRaster{}; break;
default: break;
}
diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp
index df94ef9524..3d5ffd6a43 100644
--- a/src/style/style_layer.cpp
+++ b/src/style/style_layer.cpp
@@ -191,23 +191,30 @@ void StyleLayer::applyStyleProperties<LineProperties>(const float z, const times
}
template <>
-void StyleLayer::applyStyleProperties<IconProperties>(const float z, const timestamp now) {
- properties.set<IconProperties>();
- IconProperties &icon = properties.get<IconProperties>();
- applyStyleProperty(PropertyKey::IconOpacity, icon.opacity, z, now);
- applyStyleProperty(PropertyKey::IconRotate, icon.rotate, z, now);
-}
+void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const timestamp now) {
+ properties.set<SymbolProperties>();
+ SymbolProperties &symbol = properties.get<SymbolProperties>();
+ applyStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now);
+ applyStyleProperty(PropertyKey::IconRotate, symbol.icon.rotate, z, now);
+ applyStyleProperty(PropertyKey::IconSize, symbol.icon.size, z, now);
+ applyStyleProperty(PropertyKey::IconColor, symbol.icon.color, z, now);
+ applyStyleProperty(PropertyKey::IconHaloColor, symbol.icon.halo_color, z, now);
+ applyStyleProperty(PropertyKey::IconHaloWidth, symbol.icon.halo_width, z, now);
+ applyStyleProperty(PropertyKey::IconHaloBlur, symbol.icon.halo_blur, z, now);
+ applyStyleProperty(PropertyKey::IconTranslateX, symbol.icon.translate[0], z, now);
+ applyStyleProperty(PropertyKey::IconTranslateY, symbol.icon.translate[1], z, now);
+ applyStyleProperty(PropertyKey::IconTranslateAnchor, symbol.icon.translate_anchor, z, now);
+
+ applyStyleProperty(PropertyKey::TextOpacity, symbol.text.opacity, z, now);
+ applyStyleProperty(PropertyKey::TextSize, symbol.text.size, z, now);
+ applyStyleProperty(PropertyKey::TextColor, symbol.text.color, z, now);
+ applyStyleProperty(PropertyKey::TextHaloColor, symbol.text.halo_color, z, now);
+ applyStyleProperty(PropertyKey::TextHaloWidth, symbol.text.halo_width, z, now);
+ applyStyleProperty(PropertyKey::TextHaloBlur, symbol.text.halo_blur, z, now);
+ applyStyleProperty(PropertyKey::TextTranslateX, symbol.text.translate[0], z, now);
+ applyStyleProperty(PropertyKey::TextTranslateY, symbol.text.translate[1], z, now);
+ applyStyleProperty(PropertyKey::TextTranslateAnchor, symbol.text.translate_anchor, z, now);
-template <>
-void StyleLayer::applyStyleProperties<TextProperties>(const float z, const timestamp now) {
- properties.set<TextProperties>();
- TextProperties &text = properties.get<TextProperties>();
- applyStyleProperty(PropertyKey::TextOpacity, text.opacity, z, now);
- applyStyleProperty(PropertyKey::TextSize, text.size, z, now);
- applyStyleProperty(PropertyKey::TextColor, text.color, z, now);
- applyStyleProperty(PropertyKey::TextHaloColor, text.halo_color, z, now);
- applyStyleProperty(PropertyKey::TextHaloWidth, text.halo_width, z, now);
- applyStyleProperty(PropertyKey::TextHaloBlur, text.halo_blur, z, now);
}
template <>
@@ -247,8 +254,7 @@ void StyleLayer::updateProperties(float z, const timestamp now) {
switch (type) {
case StyleLayerType::Fill: applyStyleProperties<FillProperties>(z, now); break;
case StyleLayerType::Line: applyStyleProperties<LineProperties>(z, now); break;
- case StyleLayerType::Icon: applyStyleProperties<IconProperties>(z, now); break;
- case StyleLayerType::Text: applyStyleProperties<TextProperties>(z, now); break;
+ case StyleLayerType::Symbol: applyStyleProperties<SymbolProperties>(z, now); break;
case StyleLayerType::Raster: applyStyleProperties<RasterProperties>(z, now); break;
case StyleLayerType::Composite: applyStyleProperties<CompositeProperties>(z, now); break;
case StyleLayerType::Background: applyStyleProperties<BackgroundProperties>(z, now); break;
diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp
index 0bed3381cd..3377185d32 100644
--- a/src/style/style_parser.cpp
+++ b/src/style/style_parser.cpp
@@ -63,6 +63,20 @@ JSVal StyleParser::replaceConstant(JSVal value) {
#pragma mark - Parse Render Properties
+template<> bool StyleParser::parseRenderProperty(JSVal value, bool &target, const char *name) {
+ if (value.HasMember(name)) {
+ JSVal property = replaceConstant(value[name]);
+ if (property.IsBool()) {
+ target = property.GetBool();
+ return true;
+ } else {
+ fprintf(stderr, "[WARNING] '%s' must be a boolean\n", name);
+ }
+ }
+ return false;
+}
+
+
template<> bool StyleParser::parseRenderProperty(JSVal value, std::string &target, const char *name) {
if (value.HasMember(name)) {
JSVal property = replaceConstant(value[name]);
@@ -139,12 +153,12 @@ template<> bool StyleParser::parseRenderProperty(JSVal value, vec2<float> &targe
return false;
}
-template<typename T, typename Parser>
-bool StyleParser::parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser) {
+template<typename Parser, typename T>
+bool StyleParser::parseRenderProperty(JSVal value, T &target, const char *name) {
if (value.HasMember(name)) {
JSVal property = replaceConstant(value[name]);
if (property.IsString()) {
- target = parser({ property.GetString(), property.GetStringLength() });
+ target = Parser({ property.GetString(), property.GetStringLength() });
return true;
} else {
fprintf(stderr, "[WARNING] %s must have one of the enum values\n", name);
@@ -167,7 +181,7 @@ void StyleParser::parseSources(JSVal value) {
int32_t min_zoom = 0;
int32_t max_zoom = 22;
- parseRenderProperty(itr->value, type, "type", parseSourceType);
+ parseRenderProperty<SourceTypeClass>(itr->value, type, "type");
parseRenderProperty(itr->value, url, "url");
if (type == SourceType::Raster) {
parseRenderProperty(itr->value, tile_size, "tileSize");
@@ -348,19 +362,19 @@ template<> std::tuple<bool, std::string> StyleParser::parseProperty(JSVal value,
template<> std::tuple<bool, TranslateAnchorType> StyleParser::parseProperty(JSVal value, const char *property_name) {
if (!value.IsString()) {
fprintf(stderr, "[WARNING] value of '%s' must be a string\n", property_name);
- return std::tuple<bool, TranslateAnchorType> { false, TranslateAnchorType::Default };
+ return std::tuple<bool, TranslateAnchorType> { false, TranslateAnchorType::Map };
}
- return std::tuple<bool, TranslateAnchorType> { true, parseTranslateAnchorType({ value.GetString(), value.GetStringLength() }) };
+ return std::tuple<bool, TranslateAnchorType> { true, TranslateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, RotateAnchorType> StyleParser::parseProperty<RotateAnchorType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
fprintf(stderr, "[WARNING] value of '%s' must be a string\n", property_name);
- return std::tuple<bool, RotateAnchorType> { false, RotateAnchorType::Default };
+ return std::tuple<bool, RotateAnchorType> { false, RotateAnchorType::Map };
}
- return std::tuple<bool, RotateAnchorType> { true, parseRotateAnchorType({ value.GetString(), value.GetStringLength() }) };
+ return std::tuple<bool, RotateAnchorType> { true, RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, PropertyTransition> StyleParser::parseProperty(JSVal value, const char *property_name) {
@@ -592,6 +606,18 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<Function<float>>("icon-opacity", Key::IconOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-icon-opacity", Key::IconOpacity, klass, value);
parseOptionalProperty<Function<float>>("icon-rotate", Key::IconRotate, klass, value);
+ parseOptionalProperty<Function<float>>("icon-size", Key::IconSize, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-size", Key::IconSize, klass, value);
+ parseOptionalProperty<Function<Color>>("icon-color", Key::IconColor, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-color", Key::IconColor, klass, value);
+ parseOptionalProperty<Function<Color>>("icon-halo-color", Key::IconHaloColor, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-halo-color", Key::IconHaloColor, klass, value);
+ parseOptionalProperty<Function<float>>("icon-halo-width", Key::IconHaloWidth, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-halo-width", Key::IconHaloWidth, klass, value);
+ parseOptionalProperty<Function<float>>("icon-halo-blur", Key::IconHaloBlur, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-halo-blur", Key::IconHaloBlur, klass, value);
+ parseOptionalProperty<Function<float>>("icon-translate", { Key::IconTranslateX, Key::IconTranslateY }, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-translate", Key::IconTranslate, klass, value);
parseOptionalProperty<Function<float>>("text-opacity", Key::TextOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-text-opacity", Key::TextOpacity, klass, value);
@@ -605,6 +631,8 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<PropertyTransition>("transition-text-halo-width", Key::TextHaloWidth, klass, value);
parseOptionalProperty<Function<float>>("text-halo-blur", Key::TextHaloBlur, klass, value);
parseOptionalProperty<PropertyTransition>("transition-text-halo-blur", Key::TextHaloBlur, klass, value);
+ parseOptionalProperty<Function<float>>("text-translate", { Key::TextTranslateX, Key::TextTranslateY }, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-text-translate", Key::TextTranslate, klass, value);
parseOptionalProperty<Function<float>>("composite-opacity", Key::CompositeOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-composite-opacity", Key::CompositeOpacity, klass, value);
@@ -833,61 +861,63 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
case StyleLayerType::Fill: {
StyleBucketFill &render = bucket.render.get<StyleBucketFill>();
- parseRenderProperty(value, render.winding, "fill-winding", parseWindingType);
+ parseRenderProperty<WindingTypeClass>(value, render.winding, "fill-winding");
} break;
case StyleLayerType::Line: {
StyleBucketLine &render = bucket.render.get<StyleBucketLine>();
- parseRenderProperty(value, render.cap, "line-cap", parseCapType);
- parseRenderProperty(value, render.join, "line-join", parseJoinType);
+ parseRenderProperty<CapTypeClass>(value, render.cap, "line-cap");
+ parseRenderProperty<JoinTypeClass>(value, render.join, "line-join");
parseRenderProperty(value, render.miter_limit, "line-miter-limit");
parseRenderProperty(value, render.round_limit, "line-round-limit");
} break;
- case StyleLayerType::Icon: {
- StyleBucketIcon &render = bucket.render.get<StyleBucketIcon>();
-
- parseRenderProperty(value, render.size, "icon-size");
- parseRenderProperty(value, render.icon, "icon-image");
- parseRenderProperty(value, render.spacing, "icon-spacing");
- parseRenderProperty(value, render.padding, "icon-padding");
- if (parseRenderProperty(value, render.translate, "icon-translate")) {
- render.translate.x *= 24;
- render.translate.y *= -24;
- }
- parseRenderProperty(value, render.translate_anchor, "icon-translate-anchor", parseTranslateAnchorType);
- } break;
-
- case StyleLayerType::Text: {
- StyleBucketText &render = bucket.render.get<StyleBucketText>();
-
- parseRenderProperty(value, render.field, "text-field");
- parseRenderProperty(value, render.path, "text-path", parseTextPathType);
- parseRenderProperty(value, render.transform, "text-transform", parseTextTransformType);
- parseRenderProperty(value, render.font, "text-font");
- parseRenderProperty(value, render.max_size, "text-max-size");
- if (parseRenderProperty(value, render.max_width, "text-max-width")) {
- render.max_width *= 24; // em
- }
- if (parseRenderProperty(value, render.line_height, "text-line-height")) {
- render.line_height *= 24; // em
- }
- if (parseRenderProperty(value, render.letter_spacing, "text-letter-spacing")) {
- render.letter_spacing *= 24; // em
- }
- parseRenderProperty(value, render.alignment, "text-alignment", parseAlignmentType);
- parseRenderProperty(value, render.vertical_alignment, "text-vertical-alignment", parseVerticalAlignmentType);
- parseRenderProperty(value, render.max_angle_delta, "text-max-angle");
- parseRenderProperty(value, render.min_distance, "text-min-distance");
- parseRenderProperty(value, render.rotate, "text-rotate");
- parseRenderProperty(value, render.slant, "text-slant");
- parseRenderProperty(value, render.padding, "text-padding");
- if (parseRenderProperty(value, render.translate, "text-translate")) {
- render.translate.x *= 24;
- render.translate.y *= -24;
- }
- parseRenderProperty(value, render.translate_anchor, "text-translate-anchor", parseTranslateAnchorType);
+ case StyleLayerType::Symbol: {
+ StyleBucketSymbol &render = bucket.render.get<StyleBucketSymbol>();
+
+ parseRenderProperty<PlacementTypeClass>(value, render.placement, "symbol-placement");
+ parseRenderProperty(value, render.min_distance, "symbol-min-distance");
+
+ parseRenderProperty(value, render.icon.allow_overlap, "icon-allow-overlap");
+ parseRenderProperty(value, render.icon.ignore_placement, "icon-ignore-placement");
+ parseRenderProperty(value, render.icon.optional, "icon-optional");
+ parseRenderProperty<RotationAlignmentTypeClass>(value, render.icon.rotation_alignment, "icon-rotation-alignment");
+ parseRenderProperty(value, render.icon.max_size, "icon-max-size");
+ parseRenderProperty(value, render.icon.image, "icon-image");
+ parseRenderProperty(value, render.icon.padding, "icon-padding");
+ parseRenderProperty(value, render.icon.keep_upright, "icon-keep-upright");
+ parseRenderProperty(value, render.icon.offset, "icon-offset");
+ parseRenderProperty<TranslateAnchorTypeClass>(value, render.icon.translate_anchor, "icon-translate-anchor");
+
+
+ parseRenderProperty<RotationAlignmentTypeClass>(value, render.text.rotation_alignment, "text-rotation-alignment");
+ parseRenderProperty(value, render.text.field, "text-field");
+ parseRenderProperty(value, render.text.font, "text-font");
+ parseRenderProperty(value, render.text.max_size, "text-max-size");
+ if (parseRenderProperty(value, render.text.max_width, "text-max-width")) {
+ render.text.max_width *= 24; // em
+ }
+ if (parseRenderProperty(value, render.text.line_height, "text-line-height")) {
+ render.text.line_height *= 24; // em
+ }
+ if (parseRenderProperty(value, render.text.letter_spacing, "text-letter-spacing")) {
+ render.text.letter_spacing *= 24; // em
+ }
+ parseRenderProperty<TextJustifyTypeClass>(value, render.text.justify, "text-justify");
+ parseRenderProperty<TextHorizontalAlignTypeClass>(value, render.text.horizontal_align, "text-horizontal-align");
+ parseRenderProperty<TextVerticalAlignTypeClass>(value, render.text.vertical_align, "text-vertical-align");
+ parseRenderProperty(value, render.text.max_angle_delta, "text-max-angle");
+ parseRenderProperty(value, render.text.rotate, "text-rotate");
+ parseRenderProperty(value, render.text.slant, "text-slant");
+ parseRenderProperty(value, render.text.padding, "text-padding");
+ parseRenderProperty(value, render.text.keep_upright, "text-keep-upright");
+ parseRenderProperty<TextTransformTypeClass>(value, render.text.transform, "text-transform");
+ parseRenderProperty(value, render.text.offset, "text-offset");
+ parseRenderProperty<TranslateAnchorTypeClass>(value, render.text.translate_anchor, "text-translate-anchor");
+ parseRenderProperty(value, render.text.allow_overlap, "text-allow-overlap");
+ parseRenderProperty(value, render.text.ignore_placement, "text-ignore-placement");
+ parseRenderProperty(value, render.text.optional, "text-optional");
} break;
default:
// There are no render properties for these layer types.
diff --git a/src/style/style_properties.cpp b/src/style/style_properties.cpp
index 3908d35ffa..1b05528d2f 100644
--- a/src/style/style_properties.cpp
+++ b/src/style/style_properties.cpp
@@ -4,8 +4,6 @@ namespace mbgl {
template<> const FillProperties &defaultStyleProperties() { static const FillProperties p; return p; }
template<> const LineProperties &defaultStyleProperties() { static const LineProperties p; return p; }
-template<> const IconProperties &defaultStyleProperties() { static const IconProperties p; return p; }
-template<> const TextProperties &defaultStyleProperties() { static const TextProperties p; return p; }
template<> const SymbolProperties &defaultStyleProperties() { static const SymbolProperties p; return p; }
template<> const CompositeProperties &defaultStyleProperties() { static const CompositeProperties p; return p; }
template<> const RasterProperties &defaultStyleProperties() { static const RasterProperties p; return p; }
diff --git a/src/text/placement.cpp b/src/text/placement.cpp
index b15266137b..82c45b4e0c 100644
--- a/src/text/placement.cpp
+++ b/src/text/placement.cpp
@@ -1,7 +1,7 @@
#include <mbgl/text/placement.hpp>
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/geometry/interpolate.hpp>
-#include <mbgl/renderer/text_bucket.hpp>
+#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/constants.hpp>
@@ -245,11 +245,11 @@ void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes,
}
}
-void Placement::addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
- const StyleBucketText &info, const GlyphPositions &face,
+void Placement::addFeature(SymbolBucket &bucket, const std::vector<Coordinate> &line,
+ const StyleBucketSymbol &info, const GlyphPositions &face,
const Shaping &shaping) {
- const bool horizontal = info.path == TextPathType::Horizontal;
- const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.max_size);
+ const bool horizontal = info.text.rotation_alignment == RotationAlignmentType::Viewport;
+ const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.text.max_size);
Anchors anchors;
@@ -272,10 +272,10 @@ void Placement::addFeature(TextBucket &bucket, const std::vector<Coordinate> &li
PlacedGlyphs glyphs;
GlyphBoxes boxes;
- getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal, line,
- info.max_angle_delta * (M_PI/180), info.rotate);
+ getGlyphs(glyphs, boxes, anchor, info.text.offset, shaping, face, fontScale, horizontal, line,
+ info.text.max_angle_delta * (M_PI/180), info.text.rotate);
PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale,
- info.padding, horizontal, info.always_visible);
+ info.text.padding, horizontal, info.text.ignore_placement);
if (place) {
bucket.addGlyphs(glyphs, place.zoom, place.rotationRange, zoom - zOffset);
}