merge text and icon buckets/styles
(we're not yet placing together!)
This commit is contained in:
100
bin/style.js
100
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
82
include/mbgl/renderer/symbol_bucket.hpp
Normal file
82
include/mbgl/renderer/symbol_bucket.hpp
Normal file
@@ -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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
// 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;
|
||||
|
||||
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;
|
||||
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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
EvenOdd,
|
||||
NonZero,
|
||||
Default = NonZero
|
||||
};
|
||||
|
||||
enum class CapType : uint8_t {
|
||||
Round,
|
||||
Butt,
|
||||
Square,
|
||||
Default = Butt
|
||||
};
|
||||
|
||||
enum class JoinType : uint8_t {
|
||||
Miter,
|
||||
Bevel,
|
||||
Round,
|
||||
Default = Miter
|
||||
};
|
||||
|
||||
enum class TextPathType : uint8_t {
|
||||
Horizontal,
|
||||
Curve,
|
||||
Default = Horizontal
|
||||
};
|
||||
|
||||
enum class PlacementType : bool {
|
||||
Point,
|
||||
Line,
|
||||
Default = Point
|
||||
};
|
||||
|
||||
enum class TextTransformType : uint8_t {
|
||||
None,
|
||||
Uppercase,
|
||||
Lowercase,
|
||||
Default = None
|
||||
};
|
||||
|
||||
enum class TranslateAnchorType : uint8_t {
|
||||
Map,
|
||||
Viewport,
|
||||
Default = Map
|
||||
};
|
||||
|
||||
enum class RotateAnchorType : uint8_t {
|
||||
Map,
|
||||
Viewport,
|
||||
Default = Viewport
|
||||
};
|
||||
|
||||
enum class RotationAlignmentType : bool {
|
||||
Map,
|
||||
Viewport,
|
||||
Default = Viewport
|
||||
};
|
||||
|
||||
enum class TextJustifyType : uint8_t {
|
||||
Center,
|
||||
Left,
|
||||
Right,
|
||||
Default = Center
|
||||
};
|
||||
|
||||
enum class TextHorizontalAlignType : uint8_t {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
Default = Center
|
||||
};
|
||||
|
||||
enum class TextVerticalAlignType : uint8_t {
|
||||
Top,
|
||||
Center,
|
||||
Bottom,
|
||||
Default = Center
|
||||
};
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class SourceType : uint8_t {
|
||||
Vector,
|
||||
Raster,
|
||||
GeoJSON,
|
||||
Video,
|
||||
Default = Vector
|
||||
Video
|
||||
};
|
||||
|
||||
inline WindingType parseWindingType(const std::string &type) {
|
||||
if (type == "even-odd") return WindingType::EvenOdd;
|
||||
if (type == "non-zero") return WindingType::NonZero;
|
||||
return WindingType::Default;
|
||||
}
|
||||
MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, {
|
||||
{ SourceType::Vector, "vector" },
|
||||
{ SourceType::Raster, "raster" },
|
||||
{ SourceType::GeoJSON, "geojson" },
|
||||
{ SourceType::Video, "video" },
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 WindingType : bool {
|
||||
EvenOdd,
|
||||
NonZero,
|
||||
};
|
||||
|
||||
inline TranslateAnchorType parseTranslateAnchorType(const std::string &anchor) {
|
||||
if (anchor == "map") return TranslateAnchorType::Map;
|
||||
if (anchor == "viewport") return TranslateAnchorType::Viewport;
|
||||
return TranslateAnchorType::Default;
|
||||
}
|
||||
MBGL_DEFINE_ENUM_CLASS(WindingTypeClass, WindingType, {
|
||||
{ WindingType::EvenOdd, "even-odd" },
|
||||
{ WindingType::NonZero, "non-zero" },
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
enum class CapType : uint8_t {
|
||||
Round,
|
||||
Butt,
|
||||
Square,
|
||||
};
|
||||
|
||||
inline float parseVerticalAlignmentType(const std::string &alignment) {
|
||||
if (alignment == "bottom") return 1.0f;
|
||||
if (alignment == "top") return 0.0f;
|
||||
return 0.5f;
|
||||
}
|
||||
MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, {
|
||||
{ CapType::Round, "round" },
|
||||
{ CapType::Butt, "butt" },
|
||||
{ CapType::Square, "square" },
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class JoinType : uint8_t {
|
||||
Miter,
|
||||
Bevel,
|
||||
Round
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, {
|
||||
{ JoinType::Miter, "miter" },
|
||||
{ JoinType::Bevel, "bevel" },
|
||||
{ JoinType::Round, "round" },
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class TranslateAnchorType : bool {
|
||||
Map,
|
||||
Viewport
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, {
|
||||
{ TranslateAnchorType::Map, "map" },
|
||||
{ TranslateAnchorType::Viewport, "viewport" },
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class RotateAnchorType : bool {
|
||||
Map,
|
||||
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,
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(RotationAlignmentTypeClass, RotationAlignmentType, {
|
||||
{ RotationAlignmentType::Map, "map" },
|
||||
{ RotationAlignmentType::Viewport, "viewport" },
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class TextJustifyType : uint8_t {
|
||||
Center,
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, {
|
||||
{ TextJustifyType::Center, "center" },
|
||||
{ TextJustifyType::Left, "left" },
|
||||
{ TextJustifyType::Right, "right" },
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class TextHorizontalAlignType : uint8_t {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(TextHorizontalAlignTypeClass, TextHorizontalAlignType, {
|
||||
{ TextHorizontalAlignType::Left, "left" },
|
||||
{ TextHorizontalAlignType::Center, "center" },
|
||||
{ TextHorizontalAlignType::Right, "right" },
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class TextVerticalAlignType : uint8_t {
|
||||
Top,
|
||||
Center,
|
||||
Bottom,
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(TextVerticalAlignTypeClass, TextVerticalAlignType, {
|
||||
{ TextVerticalAlignType::Top, "top" },
|
||||
{ TextVerticalAlignType::Center, "center" },
|
||||
{ TextVerticalAlignType::Bottom, "bottom" },
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class TextTransformType : uint8_t {
|
||||
None,
|
||||
Uppercase,
|
||||
Lowercase,
|
||||
};
|
||||
|
||||
MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, {
|
||||
{ TextTransformType::None, "none" },
|
||||
{ TextTransformType::Uppercase, "uppercase" },
|
||||
{ TextTransformType::Lowercase, "lowercase" },
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
202
src/renderer/painter_symbol.cpp
Normal file
202
src/renderer/painter_symbol.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
271
src/renderer/symbol_bucket.cpp
Normal file
271
src/renderer/symbol_bucket.cpp
Normal file
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>();
|
||||
case StyleLayerType::Symbol: {
|
||||
StyleBucketSymbol &render = bucket.render.get<StyleBucketSymbol>();
|
||||
|
||||
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;
|
||||
parseRenderProperty<PlacementTypeClass>(value, render.placement, "symbol-placement");
|
||||
parseRenderProperty(value, render.min_distance, "symbol-min-distance");
|
||||
|
||||
case StyleLayerType::Text: {
|
||||
StyleBucketText &render = bucket.render.get<StyleBucketText>();
|
||||
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(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
|
||||
|
||||
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.line_height, "text-line-height")) {
|
||||
render.line_height *= 24; // em
|
||||
if (parseRenderProperty(value, render.text.line_height, "text-line-height")) {
|
||||
render.text.line_height *= 24; // em
|
||||
}
|
||||
if (parseRenderProperty(value, render.letter_spacing, "text-letter-spacing")) {
|
||||
render.letter_spacing *= 24; // em
|
||||
if (parseRenderProperty(value, render.text.letter_spacing, "text-letter-spacing")) {
|
||||
render.text.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);
|
||||
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.
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user