From 0580874afae80fc6a11249355e8e5855a7264e5f Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 27 May 2014 17:59:38 -0700 Subject: [PATCH 001/172] bump MVK for attribution & app backgrounding --- ios/MVKMapKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/MVKMapKit b/ios/MVKMapKit index 9c3aa2d91..5821b22b4 160000 --- a/ios/MVKMapKit +++ b/ios/MVKMapKit @@ -1 +1 @@ -Subproject commit 9c3aa2d919f2a76d5fef2500a3ee624b57a11383 +Subproject commit 5821b22b47c475562dc474cb75a28ac7320a1c95 From eb377aced7fc6df31cddd78d0bd74085b64880c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 15:50:54 +0200 Subject: [PATCH 002/172] add font names --- bin/style.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bin/style.js b/bin/style.js index bc548ac29..1a6aca8b7 100644 --- a/bin/style.js +++ b/bin/style.js @@ -267,6 +267,7 @@ module.exports = { "value": 10, "path": "curve", "text_field": "ele", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 10, "feature_type": "line", "type": "text" @@ -648,6 +649,7 @@ module.exports = { "layer": "country_label", "text_field": "name", "path": "horizontal", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 24, "feature_type": "point", "type": "text" @@ -664,6 +666,7 @@ module.exports = { "type": "text", "text_field": "name", "path": "curve", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 16 }, "marine_label_point_1": { @@ -675,6 +678,7 @@ module.exports = { "path": "horizontal", "field": "labelrank", "value": 1, + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 30 }, "marine_label_point_2": { @@ -686,6 +690,7 @@ module.exports = { "path": "horizontal", "field": "labelrank", "value": 2, + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 24 }, "marine_label_point_other": { @@ -697,6 +702,7 @@ module.exports = { "path": "horizontal", "field": "labelrank", "value": [3,4,5,6], + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 18 }, "state_label": { @@ -704,6 +710,7 @@ module.exports = { "layer": "state_label", "text_field": "name", "path": "horizontal", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 16, "feature_type": "point", "type": "text", @@ -724,6 +731,7 @@ module.exports = { "value": "city", "text_field": "name", "path": "horizontal", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 20, "feature_type": "point", "type": "text" @@ -735,6 +743,7 @@ module.exports = { "value": "town", "text_field": "name", "path": "horizontal", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 24, "feature_type": "point", "type": "text" @@ -746,6 +755,7 @@ module.exports = { "value": "village", "text_field": "name", "path": "horizontal", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 22, "feature_type": "point", "type": "text" @@ -761,6 +771,7 @@ module.exports = { ], "text_field": "name", "path": "horizontal", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 14, "feature_type": "point", "type": "text" @@ -771,6 +782,7 @@ module.exports = { "text_field": "name", "path": "curve", "padding": 2, + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 13, "feature_type": "line", "type": "text", @@ -781,6 +793,7 @@ module.exports = { "layer": "water_label", "text_field": "name", "path": "horizontal", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 12, "feature_type": "point", "type": "text" @@ -790,6 +803,7 @@ module.exports = { "layer": "waterway_label", "text_field": "name", "path": "curve", + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 12, "textMinDistance": 15, "feature_type": "line", @@ -824,6 +838,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, + "font": "Open Sans Regular, Arial Unicode MS Regular", "fontSize": 12, "feature_type": "point", "type": "text", From cca9d81ee75bc045e8fa790822b7a1ec83b3dbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 15:51:09 +0200 Subject: [PATCH 003/172] add debug warnings --- include/llmr/util/constants.hpp | 5 +++++ src/map/tile_parser.cpp | 7 ++++++- src/renderer/text_bucket.cpp | 7 +++++++ src/util/constants.cpp | 5 +++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/llmr/util/constants.hpp b/include/llmr/util/constants.hpp index 70befcb37..f315e5171 100644 --- a/include/llmr/util/constants.hpp +++ b/include/llmr/util/constants.hpp @@ -19,6 +19,11 @@ extern const bool styleParseWarnings; extern const bool spriteWarnings; extern const bool renderWarnings; extern const bool renderTree; +extern const bool labelTextMissingWarning; +extern const bool missingFontStackWarning; +extern const bool missingFontFaceWarning; +extern const bool glyphWarning; +extern const bool shapingWarning; } diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 49444428a..434372944 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -163,9 +163,11 @@ std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& laye } std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { - // Determine the correct text stack. if (!layer.shaping.size()) { + if (debug::missingFontStackWarning) { + fprintf(stderr, "[WARNING] missing font stack '%s'\n", bucket_desc.geometry.font.c_str()); + } return nullptr; } @@ -179,6 +181,9 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye auto it = const_faces.find(face); if (it == const_faces.end()) { // This layer references an unknown face. + if (debug::missingFontFaceWarning) { + fprintf(stderr, "[WARNING] missing font face '%s'\n", face.c_str()); + } return nullptr; } faces.push_back(&it->second); diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index 0fd351343..310baf374 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -103,12 +104,18 @@ void TextBucket::addFeature(const VectorTileFeature &feature, auto it_prop = feature.properties.find(geom_desc.field); if (it_prop == feature.properties.end()) { // feature does not have the correct property + if (debug::labelTextMissingWarning) { + fprintf(stderr, "[WARNING] feature doesn't have property '%s' required for labelling\n", geom_desc.field.c_str()); + } return; } const Value &value = it_prop->second; auto it_shaping = shapings.find(value); if (it_shaping == shapings.end()) { + if (debug::shapingWarning) { + fprintf(stderr, "[WARNING] missing shaping for '%s'\n", toString(value).c_str()); + } // we lack shaping information for this label return; } diff --git a/src/util/constants.cpp b/src/util/constants.cpp index 2a4ecd374..f67464926 100644 --- a/src/util/constants.cpp +++ b/src/util/constants.cpp @@ -7,3 +7,8 @@ const bool llmr::debug::styleParseWarnings = false; const bool llmr::debug::spriteWarnings = false; const bool llmr::debug::renderWarnings = false; const bool llmr::debug::renderTree = false; +const bool llmr::debug::labelTextMissingWarning = true; +const bool llmr::debug::missingFontStackWarning = true; +const bool llmr::debug::missingFontFaceWarning = true; +const bool llmr::debug::glyphWarning = true; +const bool llmr::debug::shapingWarning = true; From 1749aa3de2744c830becf05608e008a78b92c49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 15:51:29 +0200 Subject: [PATCH 004/172] switch to glyph/shaping-less endpoint --- src/map/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/map.cpp b/src/map/map.cpp index 835edac0b..e72c7e30b 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -163,7 +163,7 @@ void Map::setup() { sources.emplace("outdoors", std::unique_ptr(new Source(*this, painter, - "http://api-maps-gl.tilestream.net/v3/mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5/%d/%d/%d.gl.pbf", + "http://api-maps-gl.tilestream.net/v3/mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5/%d/%d/%d.vector.pbf", Source::Type::vector, {{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }}, 512, From ed7b86a1349c0d943e95910d439ac52fd157b28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 20:51:13 +0200 Subject: [PATCH 005/172] add glyph store and load glyph pbfs --- include/llmr/map/map.hpp | 3 + include/llmr/map/tile_parser.hpp | 4 +- include/llmr/platform/platform.hpp | 4 +- include/llmr/text/glyph.hpp | 5 ++ include/llmr/text/glyph_store.hpp | 66 +++++++++++++++++++ src/map/tile_parser.cpp | 67 +++++++++++-------- src/map/vector_tile_data.cpp | 2 +- src/platform/request.cpp | 34 ++++++---- src/text/glyph.cpp | 101 +++++++++++++++++++++++++++++ src/text/glyph_store.cpp | 92 ++++++++++++++++++++++++++ 10 files changed, 334 insertions(+), 44 deletions(-) create mode 100644 include/llmr/text/glyph_store.hpp create mode 100644 src/text/glyph.cpp create mode 100644 src/text/glyph_store.cpp diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index ab1738f96..49050540c 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,7 @@ public: inline const TransformState &getState() const { return state; } inline const Style &getStyle() const { return style; } inline GlyphAtlas &getGlyphAtlas() { return glyphAtlas; } + inline GlyphStore &getGlyphStore() { return glyphStore; } inline SpriteAtlas &getSpriteAtlas() { return spriteAtlas; } inline uv_loop_t *getLoop() { return loop; } inline time getAnimationTime() const { return animationTime; } @@ -152,6 +154,7 @@ private: Texturepool texturepool; Style style; GlyphAtlas glyphAtlas; + GlyphStore glyphStore; SpriteAtlas spriteAtlas; Painter painter; diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 86545e4f7..644cc45b1 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -9,6 +9,7 @@ namespace llmr { class Style; class GlyphAtlas; +class GlyphStore; class SpriteAtlas; class LayerDescription; @@ -16,7 +17,7 @@ class Bucket; class TileParser { public: - TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, SpriteAtlas &spriteAtlas); + TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, GlyphStore &glyphStore, SpriteAtlas &spriteAtlas); private: bool obsolete() const; @@ -35,6 +36,7 @@ private: VectorTileData& tile; const Style& style; GlyphAtlas& glyphAtlas; + GlyphStore &glyphStore; SpriteAtlas &spriteAtlas; Faces faces; Placement placement; diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index 972e7db6b..d516378c2 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -25,9 +25,11 @@ struct Response { // Makes an HTTP request of a URL, preferrably on a background thread, and calls a function with the // results in the original thread (which runs the libuv loop). +// If the loop pointer is NULL, the callback function will be called on an arbitrary thread. // Returns a cancellable request. std::shared_ptr request_http(const std::string &url, - std::function callback, uv_loop_t *loop); + std::function callback, + uv_loop_t *loop = nullptr); // Cancels an HTTP request. void cancel_request_http(const std::shared_ptr &req); diff --git a/include/llmr/text/glyph.hpp b/include/llmr/text/glyph.hpp index 91531e24f..e6138e712 100644 --- a/include/llmr/text/glyph.hpp +++ b/include/llmr/text/glyph.hpp @@ -9,6 +9,11 @@ namespace llmr { +typedef std::pair GlyphRange; + +// Note: this only works for the BMP +GlyphRange getGlyphRange(uint32_t glyph); + struct GlyphMetrics { operator bool() const { return width == 0 && height == 0 && advance == 0; diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp new file mode 100644 index 000000000..1cd2fd539 --- /dev/null +++ b/include/llmr/text/glyph_store.hpp @@ -0,0 +1,66 @@ +#ifndef LLMR_TEXT_GLYPH_STORE +#define LLMR_TEXT_GLYPH_STORE + +#include +#include + + +#include +#include +#include +#include +#include +#include + +namespace llmr { + + +class SDFGlyph { +public: + SDFGlyph(); + SDFGlyph(pbf data); + + // A signed distance field of the glyph with a border of 3 pixels. + std::string bitmap; + + // Glyph metrics + GlyphMetrics metrics; +}; + + +class GlyphSet { +public: + GlyphSet(const std::string &fontStack, GlyphRange glyphRange); + + void parse(); + + std::shared_future getFuture(); + +private: + std::map glyphs; + + std::string data; + std::promise promise; + std::shared_future future; + std::mutex mtx; +}; + +// Manages Glyphrange PBF loading. +class GlyphStore { +public: + // Block until all specified GlyphRanges of the specified font stack are loaded. + void waitForGlyphRanges(const std::string &fontStack, const std::set &glyphRanges); + +private: + // Loads an individual glyph range from the font stack and adds it to rangeSets + std::shared_future loadGlyphRange(const std::string &fontStack, std::map> &rangeSets, GlyphRange range); + +private: + std::unordered_map>> stacks; + std::mutex mtx; +}; + + +} + +#endif diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 434372944..c610ca139 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -9,17 +9,21 @@ #include #include #include +#include #include +#include + using namespace llmr; -TileParser::TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, SpriteAtlas &spriteAtlas) +TileParser::TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, GlyphStore &glyphStore, SpriteAtlas &spriteAtlas) : vector_data(pbf((const uint8_t *)data.data(), data.size())), tile(tile), style(style), glyphAtlas(glyphAtlas), + glyphStore(glyphStore), spriteAtlas(spriteAtlas), placement(tile.id.z) { parseGlyphs(); @@ -162,35 +166,42 @@ std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& laye return obsolete() ? nullptr : std::move(bucket); } +typedef std::pair GlyphRange; + std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { - // Determine the correct text stack. - if (!layer.shaping.size()) { - if (debug::missingFontStackWarning) { - fprintf(stderr, "[WARNING] missing font stack '%s'\n", bucket_desc.geometry.font.c_str()); - } - return nullptr; - } - - // TODO: currently hardcoded to use the first font stack. - const std::map& shaping = layer.shaping.begin()->second; - - const Faces& const_faces = faces; - - IndexedFaces faces; - for (const std::string& face : layer.faces) { - auto it = const_faces.find(face); - if (it == const_faces.end()) { - // This layer references an unknown face. - if (debug::missingFontFaceWarning) { - fprintf(stderr, "[WARNING] missing font face '%s'\n", face.c_str()); - } - return nullptr; - } - faces.push_back(&it->second); - } - std::unique_ptr bucket = std::make_unique( tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); - addBucketFeatures(bucket, layer, bucket_desc, faces, shaping); + + + std::set ranges; + std::wstring_convert, char32_t> ucs4conv; + + FilteredVectorTileLayer filtered_layer(layer, bucket_desc); + for (const pbf& feature_pbf : filtered_layer) { + if (obsolete()) return nullptr; + VectorTileFeature feature { feature_pbf, layer }; + + auto it_prop = feature.properties.find(bucket_desc.geometry.field); + if (it_prop == feature.properties.end()) { + // feature does not have the correct property + if (debug::labelTextMissingWarning) { + fprintf(stderr, "[WARNING] feature doesn't have property '%s' required for labelling\n", bucket_desc.geometry.field.c_str()); + } + continue; + } + + const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); + + // Loop through all characters of this text and collect unique codepoints. + for (uint32_t chr : string) { + ranges.insert(getGlyphRange(chr)); + } + } + + glyphStore.waitForGlyphRanges(bucket_desc.geometry.font, ranges); + + // TODO: Now that we have all the glyph ranges, actually perform the shaping and add features to + // the bucket, and add the required glyphs from the glyphStore to the glyphAtlas. + return std::move(bucket); } diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp index 337e2fcc3..3c972aa31 100644 --- a/src/map/vector_tile_data.cpp +++ b/src/map/vector_tile_data.cpp @@ -22,7 +22,7 @@ void VectorTileData::parse() { // Parsing creates state that is encapsulated in TileParser. While parsing, // the TileParser object writes results into this objects. All other state // is going to be discarded afterwards. - TileParser parser(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getSpriteAtlas()); + TileParser parser(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getGlyphStore(), map.getSpriteAtlas()); } catch (const std::exception& ex) { fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what()); cancel(); diff --git a/src/platform/request.cpp b/src/platform/request.cpp index aadf83dea..f689517ab 100644 --- a/src/platform/request.cpp +++ b/src/platform/request.cpp @@ -12,25 +12,33 @@ Request::Request(const std::string &url, res(std::make_unique(callback)), cancelled(false), loop(loop) { - // Add a check handle without a callback to keep the default loop running. - // We don't have a real handler attached to the default loop right from the - // beginning, because we're using asynchronous messaging to perform the actual - // request in the request thread. Only after the request is complete, we - // create an actual work request that is attached to the default loop. - async = new uv_async_t(); - async->data = new std::unique_ptr(); - uv_async_init(loop, async, complete); + if (loop) { + // Add a check handle without a callback to keep the default loop running. + // We don't have a real handler attached to the default loop right from the + // beginning, because we're using asynchronous messaging to perform the actual + // request in the request thread. Only after the request is complete, we + // create an actual work request that is attached to the default loop. + async = new uv_async_t(); + async->data = new std::unique_ptr(); + uv_async_init(loop, async, complete); + } } Request::~Request() { } void Request::complete() { - // We're scheduling the response callback to be invoked in the event loop. - // Since the Request object will be deleted before the callback is invoked, - // we move over the Response object to be owned by the async handle. - ((std::unique_ptr *)async->data)->swap(res); - uv_async_send(async); + if (loop) { + // We're scheduling the response callback to be invoked in the event loop. + // Since the Request object will be deleted before the callback is invoked, + // we move over the Response object to be owned by the async handle. + ((std::unique_ptr *)async->data)->swap(res); + uv_async_send(async); + } else { + // We're calling the response callback immediately. We're currently on an + // arbitrary thread, but that's okay. + res->callback(res.get()); + } } void Request::complete(uv_async_t *async) { diff --git a/src/text/glyph.cpp b/src/text/glyph.cpp new file mode 100644 index 000000000..039e3bc36 --- /dev/null +++ b/src/text/glyph.cpp @@ -0,0 +1,101 @@ +#include + +namespace llmr { + +// Note: this only works for the BMP +// Note: we could use a binary lookup table to get averaged constant time lookups, however, +// most of our lookups are going to be within the first 3 ranges listed here, so this is +// likely faster. +GlyphRange getGlyphRange(uint32_t glyph) { + if (glyph <= 127) return { 0, 127 }; // Basic Latin + if (glyph <= 255) return { 128, 255 }; // Latin-1 Supplement + if (glyph >= 8192 && glyph <= 8303) return { 8192, 8303 }; // General Punctuation + if (glyph <= 383) return { 256, 383 }; // Latin Extended-A + if (glyph <= 591) return { 384, 591 }; // Latin Extended-B + if (glyph <= 687) return { 592, 687 }; // IPA Extensions + if (glyph <= 767) return { 688, 767 }; // Spacing Modifier Letters + if (glyph <= 879) return { 768, 879 }; // Combining Diacritical Marks + if (glyph <= 1023) return { 880, 1023 }; // Greek + if (glyph <= 1279) return { 1024, 1279 }; // Cyrillic + if (glyph <= 1423) return { 1280, 1423 }; // Armenian + if (glyph <= 1535) return { 1424, 1535 }; // Hebrew + if (glyph <= 1791) return { 1536, 1791 }; // Arabic + if (glyph <= 1871) return { 1792, 1871 }; // Syriac + if (glyph <= 1983) return { 1872, 1983 }; // Thaana + if (glyph <= 2431) return { 1984, 2431 }; // Devanagari + if (glyph <= 2559) return { 2432, 2559 }; // Bengali + if (glyph <= 2687) return { 2560, 2687 }; // Gurmukhi + if (glyph <= 2815) return { 2688, 2815 }; // Gujarati + if (glyph <= 2943) return { 2816, 2943 }; // Oriya + if (glyph <= 3071) return { 2944, 3071 }; // Tamil + if (glyph <= 3199) return { 3072, 3199 }; // Telugu + if (glyph <= 3327) return { 3200, 3327 }; // Kannada + if (glyph <= 3455) return { 3328, 3455 }; // Malayalam + if (glyph <= 3583) return { 3456, 3583 }; // Sinhala + if (glyph <= 3711) return { 3584, 3711 }; // Thai + if (glyph <= 3839) return { 3712, 3839 }; // Lao + if (glyph <= 4095) return { 3840, 4095 }; // Tibetan + if (glyph <= 4255) return { 4096, 4255 }; // Myanmar + if (glyph <= 4351) return { 4256, 4351 }; // Georgian + if (glyph <= 4607) return { 4352, 4607 }; // Hangul Jamo + if (glyph <= 4991) return { 4608, 4991 }; // Ethiopic + if (glyph <= 5119) return { 4992, 5119 }; // Cherokee + if (glyph <= 5759) return { 5120, 5759 }; // Unified Canadian Aboriginal Syllabics + if (glyph <= 5791) return { 5760, 5791 }; // Ogham + if (glyph <= 5887) return { 5792, 5887 }; // Runic + if (glyph <= 6143) return { 5888, 6143 }; // Khmer + if (glyph <= 6319) return { 6144, 6319 }; // Mongolian + if (glyph <= 7935) return { 6320, 7935 }; // Latin Extended Additional + if (glyph <= 8191) return { 7936, 8191 }; // Greek Extended + if (glyph <= 8351) return { 8304, 8351 }; // Superscripts and Subscripts + if (glyph <= 8399) return { 8352, 8399 }; // Currency Symbols + if (glyph <= 8447) return { 8400, 8447 }; // Combining Marks for Symbols + if (glyph <= 8527) return { 8448, 8527 }; // Letterlike Symbols + if (glyph <= 8591) return { 8528, 8591 }; // Number Forms + if (glyph <= 8703) return { 8592, 8703 }; // Arrows + if (glyph <= 8959) return { 8704, 8959 }; // Mathematical Operators + if (glyph <= 9215) return { 8960, 9215 }; // Miscellaneous Technical + if (glyph <= 9279) return { 9216, 9279 }; // Control Pictures + if (glyph <= 9311) return { 9280, 9311 }; // Optical Character Recognition + if (glyph <= 9471) return { 9312, 9471 }; // Enclosed Alphanumerics + if (glyph <= 9599) return { 9472, 9599 }; // Box Drawing + if (glyph <= 9631) return { 9600, 9631 }; // Block Elements + if (glyph <= 9727) return { 9632, 9727 }; // Geometric Shapes + if (glyph <= 9983) return { 9728, 9983 }; // Miscellaneous Symbols + if (glyph <= 10175) return { 9984, 10175 }; // Dingbats + if (glyph <= 10495) return { 10176, 10495 }; // Braille Patterns + if (glyph <= 12031) return { 10496, 12031 }; // CJK Radicals Supplement + if (glyph <= 12255) return { 12032, 12255 }; // Kangxi Radicals + if (glyph <= 12287) return { 12256, 12287 }; // Ideographic Description Characters + if (glyph <= 12351) return { 12288, 12351 }; // CJK Symbols and Punctuation + if (glyph <= 12447) return { 12352, 12447 }; // Hiragana + if (glyph <= 12543) return { 12448, 12543 }; // Katakana + if (glyph <= 12591) return { 12544, 12591 }; // Bopomofo + if (glyph <= 12687) return { 12592, 12687 }; // Hangul Compatibility Jamo + if (glyph <= 12703) return { 12688, 12703 }; // Kanbun + if (glyph <= 12735) return { 12704, 12735 }; // Bopomofo Extended + if (glyph <= 13055) return { 12736, 13055 }; // Enclosed CJK Letters and Months + if (glyph <= 13311) return { 13056, 13311 }; // CJK Compatibility + if (glyph <= 19893) return { 13312, 19893 }; // CJK Unified Ideographs Extension A + if (glyph <= 40959) return { 19894, 40959 }; // CJK Unified Ideographs + if (glyph <= 42127) return { 40960, 42127 }; // Yi Syllables + if (glyph <= 42191) return { 42128, 42191 }; // Yi Radicals + if (glyph <= 55203) return { 42192, 55203 }; // Hangul Syllables + if (glyph <= 56191) return { 55204, 56191 }; // High Surrogates + if (glyph <= 56319) return { 56192, 56319 }; // High Private Use Surrogates + if (glyph <= 57343) return { 56320, 57343 }; // Low Surrogates + if (glyph <= 63743) return { 57344, 63743 }; // Private Use + if (glyph <= 64255) return { 63744, 64255 }; // CJK Compatibility Ideographs + if (glyph <= 64335) return { 64256, 64335 }; // Alphabetic Presentation Forms + if (glyph <= 65023) return { 64336, 65023 }; // Arabic Presentation Forms-A + if (glyph <= 65071) return { 65024, 65071 }; // Combining Half Marks + if (glyph <= 65103) return { 65072, 65103 }; // CJK Compatibility Forms + if (glyph <= 65135) return { 65104, 65135 }; // Small Form Variants + if (glyph <= 65278) return { 65136, 65278 }; // Arabic Presentation Forms-B + if (glyph <= 65279) return { 65279, 65279 }; // Specials + if (glyph <= 65519) return { 65280, 65519 }; // Halfwidth and Fullwidth Forms + if (glyph <= 65533) return { 65520, 65533 }; // Specials + return { 0, 0 }; +} + +} diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp new file mode 100644 index 000000000..fae9d1326 --- /dev/null +++ b/src/text/glyph_store.cpp @@ -0,0 +1,92 @@ +#include + +#include +#include +#include +#include + +namespace llmr { + + +GlyphSet::GlyphSet(const std::string &fontStack, GlyphRange glyphRange) + : future(promise.get_future().share()) +{ + // Load the glyph set URL + std::string url = util::sprintf<255>("http://mapbox.s3.amazonaws.com/gl-glyphs/%s/%d-%d.pbf", fontStack.c_str(), glyphRange.first, glyphRange.second); + + // TODO: Find more reliable URL normalization function + std::replace(url.begin(), url.end(), ' ', '+'); + + platform::request_http(url, [&](platform::Response *res) { + if (res->code != 200) { + // Something went wrong with loading the glyph pbf. Pass on the error to the future listeners. + const std::string msg = util::sprintf<255>("[ERROR] failed to load glyphs (%d): %s\n", res->code, res->error_message.c_str()); + promise.set_exception(std::make_exception_ptr(std::runtime_error(msg))); + } else { + // Transfer the data to the GlyphSet and signal its availability. + // Once it is available, the caller will need to call parse() to actually + // parse the data we received. We are not doing this here since this callback is being + // called from another (unknown) thread. + data.swap(res->body); + promise.set_value(*this); + } + }); +} + +std::shared_future GlyphSet::getFuture() { + return future; +} + +void GlyphSet::parse() { + std::lock_guard lock(mtx); + + if (!data.size()) { + // If there is no data, this means we either haven't received any data, or + // we have already parsed the data. + return; + } + + // TODO: parse the glyphs + + + data.clear(); +} + + +void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set &glyphRanges) { + // We are implementing a blocking wait with futures: Every GlyphSet has a future that we are + // waiting for until it is loaded. + + std::vector> futures; + futures.reserve(glyphRanges.size()); + { + std::lock_guard lock(mtx); + auto &rangeSets = stacks[fontStack]; + + // Attempt to load the glyph range. If the GlyphSet already exists, we are getting back + // the same shared_future. + for (GlyphRange range : glyphRanges) { + futures.emplace_back(loadGlyphRange(fontStack, rangeSets, range)); + } + } + + // Now that we potentially created all GlyphSets, we are waiting for the results, one by one. + // When we get a result (or the GlyphSet is aready loaded), we are attempting to parse the + // GlyphSet. + for (std::shared_future &future : futures) { + future.get().parse(); + } +} + +std::shared_future GlyphStore::loadGlyphRange(const std::string &name, std::map> &rangeSets, const GlyphRange range) { + auto range_it = rangeSets.find(range); + if (range_it == rangeSets.end()) { + // We don't have this glyph set yet for this font stack. + range_it = rangeSets.emplace(range, std::make_unique(name, range)).first; + } + + return range_it->second->getFuture(); +} + + +} From d2b44cd61cd47a335ed1f3e6735390ea50d9d81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 21:17:28 +0200 Subject: [PATCH 006/172] add glyphs proto --- proto/glyphs.proto | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 proto/glyphs.proto diff --git a/proto/glyphs.proto b/proto/glyphs.proto new file mode 100644 index 000000000..606050f7a --- /dev/null +++ b/proto/glyphs.proto @@ -0,0 +1,33 @@ +// Protocol Version 1 + +package llmr.glyphs; + +option optimize_for = LITE_RUNTIME; + +// Stores a glyph with metrics and optional SDF bitmap information. +message glyph { + required uint32 id = 1; + + // A signed distance field of the glyph with a border of 3 pixels. + optional bytes bitmap = 2; + + // Glyph metrics. + required uint32 width = 3; + required uint32 height = 4; + required sint32 left = 5; + required sint32 top = 6; + required uint32 advance = 7; +} + +// Stores fontstack information and a list of faces. +message fontstack { + required string name = 1; + required string range = 2; + repeated glyph glyphs = 3; +} + +message glyphs { + repeated fontstack stacks = 1; + + extensions 16 to 8191; +} From 906b4839c614535b5202631222e7b5e1c35e47da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 21:55:14 +0200 Subject: [PATCH 007/172] parse glyph pbf --- include/llmr/text/glyph_store.hpp | 32 +++++++------ src/text/glyph_store.cpp | 75 ++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index 1cd2fd539..c2d467e78 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -17,9 +17,6 @@ namespace llmr { class SDFGlyph { public: - SDFGlyph(); - SDFGlyph(pbf data); - // A signed distance field of the glyph with a border of 3 pixels. std::string bitmap; @@ -27,21 +24,27 @@ public: GlyphMetrics metrics; }; - -class GlyphSet { +class FontStack { public: - GlyphSet(const std::string &fontStack, GlyphRange glyphRange); - - void parse(); - - std::shared_future getFuture(); + void insert(uint32_t id, const SDFGlyph &glyph); private: std::map glyphs; + std::mutex mtx; +}; +class GlyphPBF { +public: + GlyphPBF(const std::string &fontStack, GlyphRange glyphRange); + + void parse(FontStack &stack); + + std::shared_future getFuture(); + +private: std::string data; - std::promise promise; - std::shared_future future; + std::promise promise; + std::shared_future future; std::mutex mtx; }; @@ -53,10 +56,11 @@ public: private: // Loads an individual glyph range from the font stack and adds it to rangeSets - std::shared_future loadGlyphRange(const std::string &fontStack, std::map> &rangeSets, GlyphRange range); + std::shared_future loadGlyphRange(const std::string &fontStack, std::map> &rangeSets, GlyphRange range); private: - std::unordered_map>> stacks; + std::unordered_map>> ranges; + std::unordered_map> stacks; std::mutex mtx; }; diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index fae9d1326..65fe38bc4 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -2,13 +2,20 @@ #include #include +#include #include #include namespace llmr { -GlyphSet::GlyphSet(const std::string &fontStack, GlyphRange glyphRange) +void FontStack::insert(uint32_t id, const SDFGlyph &glyph) { + std::lock_guard lock(mtx); + glyphs.emplace(id, glyph); +} + + +GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) : future(promise.get_future().share()) { // Load the glyph set URL @@ -33,11 +40,11 @@ GlyphSet::GlyphSet(const std::string &fontStack, GlyphRange glyphRange) }); } -std::shared_future GlyphSet::getFuture() { +std::shared_future GlyphPBF::getFuture() { return future; } -void GlyphSet::parse() { +void GlyphPBF::parse(FontStack &stack) { std::lock_guard lock(mtx); if (!data.size()) { @@ -46,8 +53,48 @@ void GlyphSet::parse() { return; } - // TODO: parse the glyphs + // Parse the glyph PBF + pbf glyphs_pbf(reinterpret_cast(data.data()), data.size()); + while (glyphs_pbf.next()) { + if (glyphs_pbf.tag == 1) { // stacks + pbf fontstack_pbf = glyphs_pbf.message(); + while (fontstack_pbf.next()) { + if (fontstack_pbf.tag == 3) { // glyphs + pbf glyph_pbf = fontstack_pbf.message(); + + SDFGlyph glyph; + uint32_t id = 0; + + while (glyph_pbf.next()) { + if (glyph_pbf.tag == 1) { // id + id = glyph_pbf.varint(); + } else if (glyph_pbf.tag == 2) { // bitmap + glyph.bitmap = glyph_pbf.string(); + } else if (glyph_pbf.tag == 3) { // width + glyph.metrics.width = glyph_pbf.varint(); + } else if (glyph_pbf.tag == 4) { // height + glyph.metrics.height = glyph_pbf.varint(); + } else if (glyph_pbf.tag == 5) { // left + glyph.metrics.left = glyph_pbf.svarint(); + } else if (glyph_pbf.tag == 6) { // top + glyph.metrics.top = glyph_pbf.svarint(); + } else if (glyph_pbf.tag == 7) { // advance + glyph.metrics.advance = glyph_pbf.varint(); + } else { + glyph_pbf.skip(); + } + } + + stack.insert(id, glyph); + } else { + fontstack_pbf.skip(); + } + } + } else { + glyphs_pbf.skip(); + } + } data.clear(); } @@ -57,11 +104,19 @@ void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set // We are implementing a blocking wait with futures: Every GlyphSet has a future that we are // waiting for until it is loaded. - std::vector> futures; + FontStack *stack = nullptr; + + std::vector> futures; futures.reserve(glyphRanges.size()); { std::lock_guard lock(mtx); - auto &rangeSets = stacks[fontStack]; + auto &rangeSets = ranges[fontStack]; + + auto stack_it = stacks.find(fontStack); + if (stack_it == stacks.end()) { + stack_it = stacks.emplace(fontStack, std::make_unique()).first; + } + stack = stack_it->second.get(); // Attempt to load the glyph range. If the GlyphSet already exists, we are getting back // the same shared_future. @@ -73,16 +128,16 @@ void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set // Now that we potentially created all GlyphSets, we are waiting for the results, one by one. // When we get a result (or the GlyphSet is aready loaded), we are attempting to parse the // GlyphSet. - for (std::shared_future &future : futures) { - future.get().parse(); + for (std::shared_future &future : futures) { + future.get().parse(*stack); } } -std::shared_future GlyphStore::loadGlyphRange(const std::string &name, std::map> &rangeSets, const GlyphRange range) { +std::shared_future GlyphStore::loadGlyphRange(const std::string &name, std::map> &rangeSets, const GlyphRange range) { auto range_it = rangeSets.find(range); if (range_it == rangeSets.end()) { // We don't have this glyph set yet for this font stack. - range_it = rangeSets.emplace(range, std::make_unique(name, range)).first; + range_it = rangeSets.emplace(range, std::make_unique(name, range)).first; } return range_it->second->getFuture(); From 193b2aacb78872084564e0f3398fb9cb0ed7983b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 22:00:00 +0200 Subject: [PATCH 008/172] add second labelling pass --- src/map/tile_parser.cpp | 66 ++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index c610ca139..f44d464f1 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -173,35 +173,61 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); - std::set ranges; std::wstring_convert, char32_t> ucs4conv; - FilteredVectorTileLayer filtered_layer(layer, bucket_desc); - for (const pbf& feature_pbf : filtered_layer) { - if (obsolete()) return nullptr; - VectorTileFeature feature { feature_pbf, layer }; - auto it_prop = feature.properties.find(bucket_desc.geometry.field); - if (it_prop == feature.properties.end()) { - // feature does not have the correct property - if (debug::labelTextMissingWarning) { - fprintf(stderr, "[WARNING] feature doesn't have property '%s' required for labelling\n", bucket_desc.geometry.field.c_str()); + // Determine and load glyph ranges + { + std::set ranges; + + FilteredVectorTileLayer filtered_layer(layer, bucket_desc); + for (const pbf& feature_pbf : filtered_layer) { + if (obsolete()) return nullptr; + VectorTileFeature feature { feature_pbf, layer }; + + auto it_prop = feature.properties.find(bucket_desc.geometry.field); + if (it_prop == feature.properties.end()) { + // feature does not have the correct property + if (debug::labelTextMissingWarning) { + fprintf(stderr, "[WARNING] feature doesn't have property '%s' required for labelling\n", bucket_desc.geometry.field.c_str()); + } + continue; + } + + const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); + + // Loop through all characters of this text and collect unique codepoints. + for (uint32_t chr : string) { + ranges.insert(getGlyphRange(chr)); } - continue; } - const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); - - // Loop through all characters of this text and collect unique codepoints. - for (uint32_t chr : string) { - ranges.insert(getGlyphRange(chr)); - } + glyphStore.waitForGlyphRanges(bucket_desc.geometry.font, ranges); } - glyphStore.waitForGlyphRanges(bucket_desc.geometry.font, ranges); + // Shape and place all labels. + { + FilteredVectorTileLayer filtered_layer(layer, bucket_desc); + for (const pbf& feature_pbf : filtered_layer) { + if (obsolete()) return nullptr; + VectorTileFeature feature { feature_pbf, layer }; - // TODO: Now that we have all the glyph ranges, actually perform the shaping and add features to - // the bucket, and add the required glyphs from the glyphStore to the glyphAtlas. + auto it_prop = feature.properties.find(bucket_desc.geometry.field); + if (it_prop == feature.properties.end()) { + // feature does not have the correct property + if (debug::labelTextMissingWarning) { + fprintf(stderr, "[WARNING] feature doesn't have property '%s' required for labelling\n", bucket_desc.geometry.field.c_str()); + } + continue; + } + + const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); + + // TODO: Shape label + // TODO: Place label + } + + } return std::move(bucket); } From 6f68cd3676fd61e74e4d10675d960a1b9fed58d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 22:12:31 +0200 Subject: [PATCH 009/172] return font stack --- include/llmr/text/glyph_store.hpp | 13 ++++++++++--- src/map/tile_parser.cpp | 2 ++ src/text/glyph_store.cpp | 28 +++++++++++++++++++++------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index c2d467e78..90fa6d908 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -26,11 +26,14 @@ public: class FontStack { public: - void insert(uint32_t id, const SDFGlyph &glyph); + void insert(uint32_t id, const GlyphMetrics &glyphMetrics, const std::string &bitmap); + + const std::map &getMetrics() const; private: - std::map glyphs; - std::mutex mtx; + std::map bitmaps; + std::map metrics; + mutable std::mutex mtx; }; class GlyphPBF { @@ -54,10 +57,14 @@ public: // Block until all specified GlyphRanges of the specified font stack are loaded. void waitForGlyphRanges(const std::string &fontStack, const std::set &glyphRanges); + FontStack &getFontStack(const std::string &fontStack); + private: // Loads an individual glyph range from the font stack and adds it to rangeSets std::shared_future loadGlyphRange(const std::string &fontStack, std::map> &rangeSets, GlyphRange range); + FontStack &createFontStack(const std::string &fontStack); + private: std::unordered_map>> ranges; std::unordered_map> stacks; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index f44d464f1..744f6fe21 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -205,6 +205,8 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye glyphStore.waitForGlyphRanges(bucket_desc.geometry.font, ranges); } + const FontStack &fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); + // Shape and place all labels. { FilteredVectorTileLayer filtered_layer(layer, bucket_desc); diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 65fe38bc4..a355b28f2 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -9,11 +9,16 @@ namespace llmr { -void FontStack::insert(uint32_t id, const SDFGlyph &glyph) { +void FontStack::insert(uint32_t id, const GlyphMetrics &glyphMetrics, const std::string &bitmap) { std::lock_guard lock(mtx); - glyphs.emplace(id, glyph); + metrics.emplace(id, glyphMetrics); + bitmaps.emplace(id, bitmap); } +const std::map &FontStack::getMetrics() const { + std::lock_guard lock(mtx); + return metrics; +} GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) : future(promise.get_future().share()) @@ -112,11 +117,7 @@ void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set std::lock_guard lock(mtx); auto &rangeSets = ranges[fontStack]; - auto stack_it = stacks.find(fontStack); - if (stack_it == stacks.end()) { - stack_it = stacks.emplace(fontStack, std::make_unique()).first; - } - stack = stack_it->second.get(); + stack = &createFontStack(fontStack); // Attempt to load the glyph range. If the GlyphSet already exists, we are getting back // the same shared_future. @@ -143,5 +144,18 @@ std::shared_future GlyphStore::loadGlyphRange(const std::string &nam return range_it->second->getFuture(); } +FontStack &GlyphStore::createFontStack(const std::string &fontStack) { + auto stack_it = stacks.find(fontStack); + if (stack_it == stacks.end()) { + stack_it = stacks.emplace(fontStack, std::make_unique()).first; + } + return *stack_it->second.get(); +} + +FontStack &GlyphStore::getFontStack(const std::string &fontStack) { + std::lock_guard lock(mtx); + return createFontStack(fontStack); +} + } From 83b3b0bb6a2cc557deebf1cd59486c3fe0e1e063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 28 May 2014 22:18:18 +0200 Subject: [PATCH 010/172] create a copy --- src/map/tile_parser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 744f6fe21..f097913cc 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -205,7 +205,8 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye glyphStore.waitForGlyphRanges(bucket_desc.geometry.font, ranges); } - const FontStack &fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); + // Create a copy! + const FontStack fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); // Shape and place all labels. { From a66db39a06023f5848af3725bc7c007790eeae1d Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Wed, 28 May 2014 18:45:47 -0400 Subject: [PATCH 011/172] Monkey patching to get linux compile working. --- src/map/tile_parser.cpp | 11 +++-------- src/text/glyph_store.cpp | 4 ++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index f097913cc..673600ecc 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -13,8 +13,6 @@ #include -#include - using namespace llmr; @@ -173,9 +171,6 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); - std::wstring_convert, char32_t> ucs4conv; - - // Determine and load glyph ranges { std::set ranges; @@ -194,7 +189,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye continue; } - const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); + const std::string string = toString(it_prop->second); // Loop through all characters of this text and collect unique codepoints. for (uint32_t chr : string) { @@ -206,7 +201,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye } // Create a copy! - const FontStack fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); + const FontStack &fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); // Shape and place all labels. { @@ -224,7 +219,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye continue; } - const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); + const std::string string = toString(it_prop->second); // TODO: Shape label // TODO: Place label diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index a355b28f2..bafd6ce82 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -27,7 +27,7 @@ GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) std::string url = util::sprintf<255>("http://mapbox.s3.amazonaws.com/gl-glyphs/%s/%d-%d.pbf", fontStack.c_str(), glyphRange.first, glyphRange.second); // TODO: Find more reliable URL normalization function - std::replace(url.begin(), url.end(), ' ', '+'); + // std::replace(url.begin(), url.end(), ' ', '+'); platform::request_http(url, [&](platform::Response *res) { if (res->code != 200) { @@ -91,7 +91,7 @@ void GlyphPBF::parse(FontStack &stack) { } } - stack.insert(id, glyph); + stack.insert(id, glyph.metrics, glyph.bitmap); } else { fontstack_pbf.skip(); } From 944167296a8921c6184cfbcba05f473bfa60c82e Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Wed, 28 May 2014 18:53:54 -0400 Subject: [PATCH 012/172] replace comes from regex --- src/text/glyph_store.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index bafd6ce82..e2ebb97bd 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace llmr { @@ -27,7 +28,7 @@ GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) std::string url = util::sprintf<255>("http://mapbox.s3.amazonaws.com/gl-glyphs/%s/%d-%d.pbf", fontStack.c_str(), glyphRange.first, glyphRange.second); // TODO: Find more reliable URL normalization function - // std::replace(url.begin(), url.end(), ' ', '+'); + std::replace(url.begin(), url.end(), ' ', '+'); platform::request_http(url, [&](platform::Response *res) { if (res->code != 200) { From 56c55d0b0288a3ab57a95d2b3851a2a39c734e71 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 02:36:47 +0000 Subject: [PATCH 013/172] add include needed for std::replace on linux --- src/text/glyph_store.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index a355b28f2..95b295a79 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace llmr { From c85a0c3da2f296e8c78aa58a01e2bf83259a421d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 19:44:11 -0700 Subject: [PATCH 014/172] comment unfinished FontStack code --- src/map/tile_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index f097913cc..7d8323960 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -206,7 +206,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye } // Create a copy! - const FontStack fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); + //const FontStack fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); // Shape and place all labels. { From 5c46bef7176b6d8c784516eff6cc1915cf9b28a1 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 19:57:01 -0700 Subject: [PATCH 015/172] fallback to boost::locale on linux --- include/llmr/util/utf.hpp | 44 +++++++++++++++++++++++++++++++++++++++ src/map/tile_parser.cpp | 11 ++++------ 2 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 include/llmr/util/utf.hpp diff --git a/include/llmr/util/utf.hpp b/include/llmr/util/utf.hpp new file mode 100644 index 000000000..fb9ab2048 --- /dev/null +++ b/include/llmr/util/utf.hpp @@ -0,0 +1,44 @@ +#ifndef LLMR_UTIL_UTF +#define LLMR_UTIL_UTF + +#include + +// g++/libstdc++ is missing c++11 codecvt support +#ifdef __linux__ +#include +#else +#include +#endif + +namespace llmr { + +namespace util { + +#ifdef __linux__ + +class utf8_to_utf32 { + public: + explicit utf8_to_utf32() + : utf32conv_() {} + std::u32string convert(std::string const& utf8) { + return boost::locale::conv::utf_to_utf(utf8) + } +}; +#else + +class utf8_to_utf32 { + public: + explicit utf8_to_utf32() + : utf32conv_() {} + std::u32string convert(std::string const& utf8) { + return utf32conv_.from_bytes(utf8); + } + private: + std::wstring_convert, char32_t> utf32conv_; +}; + +#endif + +}} + +#endif diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 7d8323960..70085b309 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -12,8 +12,7 @@ #include #include - -#include +#include using namespace llmr; @@ -172,9 +171,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye std::unique_ptr bucket = std::make_unique( tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); - - std::wstring_convert, char32_t> ucs4conv; - + util::utf8_to_utf32 ucs4conv; // Determine and load glyph ranges { @@ -194,7 +191,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye continue; } - const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); + const std::u32string string = ucs4conv.convert(toString(it_prop->second)); // Loop through all characters of this text and collect unique codepoints. for (uint32_t chr : string) { @@ -224,7 +221,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye continue; } - const std::u32string string = ucs4conv.from_bytes(toString(it_prop->second)); + const std::u32string string = ucs4conv.convert(toString(it_prop->second)); // TODO: Shape label // TODO: Place label From 97683460c18fe714a6a0f29f81b66739de893f91 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 19:57:26 -0700 Subject: [PATCH 016/172] fix compile of glyph_store.cpp --- src/text/glyph_store.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 95b295a79..459c2d971 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -92,7 +92,7 @@ void GlyphPBF::parse(FontStack &stack) { } } - stack.insert(id, glyph); + stack.insert(id, glyph.metrics, glyph.bitmap); } else { fontstack_pbf.skip(); } From 25803b4b98192675cb15cb73738d1c554253dd1f Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Wed, 28 May 2014 22:57:32 -0400 Subject: [PATCH 017/172] Guesses. --- src/map/tile_parser.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 673600ecc..32344edcc 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -10,12 +10,11 @@ #include #include #include - +#include #include using namespace llmr; - TileParser::TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, GlyphStore &glyphStore, SpriteAtlas &spriteAtlas) : vector_data(pbf((const uint8_t *)data.data(), data.size())), tile(tile), @@ -219,10 +218,29 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye continue; } + uint32_t i = 0; + uint32_t x = 0; const std::string string = toString(it_prop->second); - + std::map shaping; + std::map metrics = fontStack.getMetrics(); + // fprintf(stderr, "%s\n", string.c_str()); + // Loop through all characters of this label and shape. + for (uint32_t chr : string) { + // Can we reuse GlyphPlacement here? First arg is a faces index ... + GlyphPlacement shaped = GlyphPlacement(0, chr, x, 0); + // No idea how to properly put together a shaping std::map ... + shaping.emplace(i, shaped); + i++; + x += metrics[chr].advance; + } // TODO: Shape label // TODO: Place label + // Can faces here be a std::map of fontstacks? + // It looks like nearly the same interface through the rest + // of the stack. + std::unique_ptr bucket = std::make_unique( + tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); + addBucketFeatures(bucket, layer, bucket_desc, faces, shaping); } } From 6b0465448d324888e7c484ae66a40aca1f71d5d6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 20:04:40 -0700 Subject: [PATCH 018/172] fix utf.hpp linux compile --- include/llmr/util/utf.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/llmr/util/utf.hpp b/include/llmr/util/utf.hpp index fb9ab2048..f23f616f8 100644 --- a/include/llmr/util/utf.hpp +++ b/include/llmr/util/utf.hpp @@ -18,12 +18,12 @@ namespace util { class utf8_to_utf32 { public: - explicit utf8_to_utf32() - : utf32conv_() {} + explicit utf8_to_utf32() {} std::u32string convert(std::string const& utf8) { return boost::locale::conv::utf_to_utf(utf8) } }; + #else class utf8_to_utf32 { From 36796490de07279d8f36fdf0e944309aa79f2ba3 Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Wed, 28 May 2014 23:12:26 -0400 Subject: [PATCH 019/172] More educated guess. --- src/map/tile_parser.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 32344edcc..553c8c79a 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -201,6 +201,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye // Create a copy! const FontStack &fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); + std::map shaping; // Shape and place all labels. { @@ -221,29 +222,30 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye uint32_t i = 0; uint32_t x = 0; const std::string string = toString(it_prop->second); - std::map shaping; + Shaping shapedGlyphs; std::map metrics = fontStack.getMetrics(); // fprintf(stderr, "%s\n", string.c_str()); + // TODO: Shape label // Loop through all characters of this label and shape. for (uint32_t chr : string) { - // Can we reuse GlyphPlacement here? First arg is a faces index ... - GlyphPlacement shaped = GlyphPlacement(0, chr, x, 0); - // No idea how to properly put together a shaping std::map ... - shaping.emplace(i, shaped); + // Can we reuse GlyphPlacement here? First arg is a faces index. + GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); + // No idea how to properly put together a shapedGlyphs vector. + shapedGylphs.push(glyph); i++; x += metrics[chr].advance; } - // TODO: Shape label // TODO: Place label - // Can faces here be a std::map of fontstacks? - // It looks like nearly the same interface through the rest - // of the stack. - std::unique_ptr bucket = std::make_unique( - tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); - addBucketFeatures(bucket, layer, bucket_desc, faces, shaping); + shaping.emplace(string, shaped); } - } + // Can faces here be a std::map of fontstacks? + // It looks like nearly the same interface through the rest + // of the stack. + std::unique_ptr bucket = std::make_unique( + tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); + addBucketFeatures(bucket, layer, bucket_desc, faces, shaping); + return std::move(bucket); } From da0d436572fbf75bb5c0ba19e4cf4e2299696202 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 20:28:37 -0700 Subject: [PATCH 020/172] missing semicolon --- include/llmr/util/utf.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/llmr/util/utf.hpp b/include/llmr/util/utf.hpp index f23f616f8..8aa85a90a 100644 --- a/include/llmr/util/utf.hpp +++ b/include/llmr/util/utf.hpp @@ -20,7 +20,7 @@ class utf8_to_utf32 { public: explicit utf8_to_utf32() {} std::u32string convert(std::string const& utf8) { - return boost::locale::conv::utf_to_utf(utf8) + return boost::locale::conv::utf_to_utf(utf8); } }; From d702152068affd0792fb6e4588559efafbcedcdf Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 20:34:34 -0700 Subject: [PATCH 021/172] temporarily remove directory caching --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9dde1b9bb..3a3a66e52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,6 @@ compiler: cache: - apt -- directories: - - mapnik-packaging before_install: - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test From cbd881c020549bcb8b6dcf633ff500e45e90c54b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 20:34:48 -0700 Subject: [PATCH 022/172] Revert "temporarily remove directory caching" This reverts commit d702152068affd0792fb6e4588559efafbcedcdf. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3a3a66e52..9dde1b9bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ compiler: cache: - apt +- directories: + - mapnik-packaging before_install: - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test From 6e5ff8c1226965a31a22d5097d4a7de48f6dd6e1 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 28 May 2014 21:00:34 -0700 Subject: [PATCH 023/172] also find boost headers in include --- setup-libraries.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup-libraries.sh b/setup-libraries.sh index d43461111..fca19fd9c 100755 --- a/setup-libraries.sh +++ b/setup-libraries.sh @@ -71,7 +71,7 @@ source MacOSX.sh if [ ! -f out/build-cpp11-libcpp-x86_64/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi if [ ! -f out/build-cpp11-libcpp-x86_64/lib/libssl.a ] ; then ./scripts/build_openssl.sh ; fi if [ ! -f out/build-cpp11-libcpp-x86_64/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi - if [ ! -d out/build-cpp11-libcpp-x86_64/include/boost ] ; then ./scripts/build_boost.sh `pwd`/../../src/ `pwd`/../../linux/ `pwd`/../../common/ ; fi + if [ ! -d out/build-cpp11-libcpp-x86_64/include/boost ] ; then ./scripts/build_boost.sh `pwd`/../../src/ `pwd`/../../include/ `pwd`/../../linux/ `pwd`/../../common/ ; fi echo ' ...done' rm -rf out/packages @@ -91,7 +91,7 @@ source Linux.sh if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64/lib/libssl.a ] ; then ./scripts/build_openssl.sh ; fi if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi - if [ ! -d out/build-cpp11-libstdcpp-gcc-x86_64/include/boost ] ; then ./scripts/build_boost.sh `pwd`/../../src/ `pwd`/../../linux/ `pwd`/../../common/ ; fi + if [ ! -d out/build-cpp11-libstdcpp-gcc-x86_64/include/boost ] ; then ./scripts/build_boost.sh `pwd`/../../src/ `pwd`/../../include/ `pwd`/../../linux/ `pwd`/../../common/ ; fi rm -rf out/packages From d82acee8c7ec8b5850131ded412bc6337b0371bd Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 29 May 2014 05:05:48 -0400 Subject: [PATCH 024/172] Stash. --- include/llmr/geometry/glyph_atlas.hpp | 3 +- include/llmr/map/tile_parser.hpp | 3 ++ include/llmr/renderer/text_bucket.hpp | 3 +- include/llmr/text/glyph_store.hpp | 9 +++-- include/llmr/text/placement.hpp | 4 +-- src/geometry/glyph_atlas.cpp | 2 +- src/map/tile_parser.cpp | 48 +++++++++------------------ src/renderer/text_bucket.cpp | 7 ++-- src/text/glyph_store.cpp | 32 +++++++++++++++--- src/text/placement.cpp | 33 +++++++----------- 10 files changed, 76 insertions(+), 68 deletions(-) diff --git a/include/llmr/geometry/glyph_atlas.hpp b/include/llmr/geometry/glyph_atlas.hpp index 312572f5e..5bcd573f5 100644 --- a/include/llmr/geometry/glyph_atlas.hpp +++ b/include/llmr/geometry/glyph_atlas.hpp @@ -2,6 +2,7 @@ #define LLMR_GEOMETRY_GLYPH_ATLAS #include +#include #include #include @@ -30,7 +31,7 @@ public: Rect addGlyph(uint64_t tile_id, const std::string& face_name, - const VectorTileGlyph& glyph); + const SDFGlyph& glyph); void removeGlyphs(uint64_t tile_id); void bind(); diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 644cc45b1..b4bccb67a 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace llmr { @@ -23,6 +25,7 @@ private: bool obsolete() const; void parseGlyphs(); void parseStyleLayers(const std::vector& layers); + void addGlyph(uint64_t tileid, const std::string stackname, const std::string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face); std::unique_ptr createBucket(const BucketDescription& bucket_desc); std::unique_ptr createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); std::unique_ptr createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); diff --git a/include/llmr/renderer/text_bucket.hpp b/include/llmr/renderer/text_bucket.hpp index 2b73aa74d..ad282bdd0 100644 --- a/include/llmr/renderer/text_bucket.hpp +++ b/include/llmr/renderer/text_bucket.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ public: PlacementRange placementRange, float zoom); void addFeature(const VectorTileFeature &feature, - const IndexedFaces &faces, + const GlyphPositions &face, const std::map &shapings); void drawGlyphs(TextShader &shader); diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index 90fa6d908..ea7c96dc4 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -4,7 +4,6 @@ #include #include - #include #include #include @@ -17,6 +16,8 @@ namespace llmr { class SDFGlyph { public: + uint32_t id = 0; + // A signed distance field of the glyph with a border of 3 pixels. std::string bitmap; @@ -26,13 +27,15 @@ public: class FontStack { public: - void insert(uint32_t id, const GlyphMetrics &glyphMetrics, const std::string &bitmap); - + void insert(uint32_t id, const SDFGlyph &glyph); const std::map &getMetrics() const; + const std::map &getSDFs() const; + const Shaping getShaping(const std::string &string) const; private: std::map bitmaps; std::map metrics; + std::map sdfs; mutable std::mutex mtx; }; diff --git a/include/llmr/text/placement.hpp b/include/llmr/text/placement.hpp index 8ec7df5e4..87c47345e 100644 --- a/include/llmr/text/placement.hpp +++ b/include/llmr/text/placement.hpp @@ -18,9 +18,9 @@ public: void addFeature(TextBucket &bucket, const std::vector &line, const BucketGeometryDescription &info, - const IndexedFaces &faces, + const GlyphPositions &face, const Shaping &shaping); - float measureText(const IndexedFaces &faces, + float measureText(const GlyphPositions &face, const Shaping &shaping); private: diff --git a/src/geometry/glyph_atlas.cpp b/src/geometry/glyph_atlas.cpp index 200d281f7..f4defac69 100644 --- a/src/geometry/glyph_atlas.cpp +++ b/src/geometry/glyph_atlas.cpp @@ -22,7 +22,7 @@ GlyphAtlas::~GlyphAtlas() { } Rect GlyphAtlas::addGlyph(uint64_t tile_id, const std::string& face_name, - const VectorTileGlyph& glyph) { + const SDFGlyph& glyph) { std::lock_guard lock(mtx); // Use constant value for now. diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 553c8c79a..2cd10049a 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -23,7 +23,6 @@ TileParser::TileParser(const std::string& data, VectorTileData& tile, const Styl glyphStore(glyphStore), spriteAtlas(spriteAtlas), placement(tile.id.z) { - parseGlyphs(); parseStyleLayers(style.layers); } @@ -31,17 +30,13 @@ bool TileParser::obsolete() const { return tile.state == TileData::State::obsolete; } -void TileParser::parseGlyphs() { - for (const std::pair pair : vector_data.faces) { - const std::string &name = pair.first; - const VectorTileFace &face = pair.second; - - GlyphPositions &glyphs = faces[name]; - for (const VectorTileGlyph &glyph : face.glyphs) { - const Rect rect = - glyphAtlas.addGlyph(tile.id.to_uint64(), name, glyph); - glyphs.emplace(glyph.id, Glyph{rect, glyph.metrics}); - } +void TileParser::addGlyph(uint64_t tileid, const std::string stackname, const std::string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face) { + std::map sdfs = fontStack.getSDFs(); + // Loop through all characters and add glyph to atlas, positions. + for (uint32_t chr : string) { + const SDFGlyph sdf = sdfs[chr]; + const Rect rect = glyphAtlas.addGlyph(tileid, stackname, sdf); + face.emplace(chr, Glyph{rect, sdf.metrics}); } } @@ -202,6 +197,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye // Create a copy! const FontStack &fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); std::map shaping; + GlyphPositions face; // Shape and place all labels. { @@ -219,33 +215,21 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye continue; } - uint32_t i = 0; - uint32_t x = 0; const std::string string = toString(it_prop->second); - Shaping shapedGlyphs; - std::map metrics = fontStack.getMetrics(); - // fprintf(stderr, "%s\n", string.c_str()); - // TODO: Shape label - // Loop through all characters of this label and shape. - for (uint32_t chr : string) { - // Can we reuse GlyphPlacement here? First arg is a faces index. - GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); - // No idea how to properly put together a shapedGlyphs vector. - shapedGylphs.push(glyph); - i++; - x += metrics[chr].advance; - } - // TODO: Place label + + // Shape labels. + const Shaping shaped = fontStack.getShaping(string); shaping.emplace(string, shaped); + + // Place labels. + addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, string, fontStack, glyphAtlas, face); } } - // Can faces here be a std::map of fontstacks? // It looks like nearly the same interface through the rest // of the stack. - std::unique_ptr bucket = std::make_unique( - tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); - addBucketFeatures(bucket, layer, bucket_desc, faces, shaping); + addBucketFeatures(bucket, layer, bucket_desc, face, shaping); return std::move(bucket); } + diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index 310baf374..7e9633f4b 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -99,7 +100,7 @@ void TextBucket::addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, }; void TextBucket::addFeature(const VectorTileFeature &feature, - const IndexedFaces &faces, + const GlyphPositions &face, const std::map &shapings) { auto it_prop = feature.properties.find(geom_desc.field); if (it_prop == feature.properties.end()) { @@ -134,14 +135,14 @@ void TextBucket::addFeature(const VectorTileFeature &feature, while ((cmd = geometry.next(x, y)) != Geometry::end) { if (cmd == Geometry::move_to) { if (!line.empty()) { - placement.addFeature(*this, line, geom_desc, faces, shaping); + placement.addFeature(*this, line, geom_desc, face, shaping); line.clear(); } } line.emplace_back(x, y); } if (line.size()) { - placement.addFeature(*this, line, geom_desc, faces, shaping); + placement.addFeature(*this, line, geom_desc, face, shaping); } } diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index e2ebb97bd..88642907a 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -10,10 +10,11 @@ namespace llmr { -void FontStack::insert(uint32_t id, const GlyphMetrics &glyphMetrics, const std::string &bitmap) { +void FontStack::insert(uint32_t id, const SDFGlyph &glyph) { std::lock_guard lock(mtx); - metrics.emplace(id, glyphMetrics); - bitmaps.emplace(id, bitmap); + metrics.emplace(id, glyph.metrics); + bitmaps.emplace(id, glyph.bitmap); + sdfs.emplace(id, glyph); } const std::map &FontStack::getMetrics() const { @@ -21,6 +22,26 @@ const std::map &FontStack::getMetrics() const { return metrics; } +const std::map &FontStack::getSDFs() const { + std::lock_guard lock(mtx); + return sdfs; +} + +const Shaping FontStack::getShaping(const std::string &string) const { + std::lock_guard lock(mtx); + uint32_t i = 0; + uint32_t x = 0; + Shaping shaped; + // Loop through all characters of this label and shape. + for (uint32_t chr : string) { + GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); + shaped.push_back(glyph); + i++; + x += metrics.find(chr)->second.advance; + } + return shaped; +} + GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) : future(promise.get_future().share()) { @@ -30,6 +51,8 @@ GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) // TODO: Find more reliable URL normalization function std::replace(url.begin(), url.end(), ' ', '+'); + fprintf(stderr, url.c_str()); + platform::request_http(url, [&](platform::Response *res) { if (res->code != 200) { // Something went wrong with loading the glyph pbf. Pass on the error to the future listeners. @@ -75,6 +98,7 @@ void GlyphPBF::parse(FontStack &stack) { while (glyph_pbf.next()) { if (glyph_pbf.tag == 1) { // id id = glyph_pbf.varint(); + glyph.id = glyph_pbf.varint(); } else if (glyph_pbf.tag == 2) { // bitmap glyph.bitmap = glyph_pbf.string(); } else if (glyph_pbf.tag == 3) { // width @@ -92,7 +116,7 @@ void GlyphPBF::parse(FontStack &stack) { } } - stack.insert(id, glyph.metrics, glyph.bitmap); + stack.insert(id, glyph); } else { fontstack_pbf.skip(); } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index 237fd05d7..310f457cd 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -35,21 +35,12 @@ bool byScale(const Anchor &a, const Anchor &b) { return a.scale < b.scale; } static const Glyph null_glyph; inline const Glyph &getGlyph(const GlyphPlacement &placed, - const IndexedFaces &faces) { - if (placed.face < faces.size()) { - const GlyphPositions &face = *faces[placed.face]; - if (&face) { - auto it = face.find(placed.glyph); - if (it != face.end()) { - return it->second; - } else { - fprintf(stderr, "glyph %d does not exist\n", placed.glyph); - } - } else { - fprintf(stderr, "face pointer is null\n"); - } + const GlyphPositions &face) { + auto it = face.find(placed.glyph); + if (it != face.end()) { + return it->second; } else { - fprintf(stderr, "face does not exist\n"); + fprintf(stderr, "glyph %d does not exist\n", placed.glyph); } return null_glyph; @@ -146,7 +137,7 @@ void getSegmentGlyphs(std::back_insert_iterator glyphs, } PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping, - const IndexedFaces &faces, float fontScale, + const GlyphPositions &face, float fontScale, bool horizontal, const std::vector &line, float maxAngleDelta, float rotate) { // The total text advance is the width of this label. @@ -167,7 +158,7 @@ PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping, const uint32_t buffer = 3; for (const GlyphPlacement &placed : shaping) { - const Glyph &glyph = getGlyph(placed, faces); + const Glyph &glyph = getGlyph(placed, face); if (!glyph) { // This glyph is empty and doesn't have any pixels that we'd need to // show. @@ -257,7 +248,7 @@ PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping, void Placement::addFeature(TextBucket& bucket, const std::vector &line, const BucketGeometryDescription &info, - const IndexedFaces &faces, + const GlyphPositions &face, const Shaping &shaping) { const bool horizontal = info.path == TextPathType::Horizontal; @@ -268,7 +259,7 @@ void Placement::addFeature(TextBucket& bucket, const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.size); - const float advance = measureText(faces, shaping); + const float advance = measureText(face, shaping); Anchors anchors; // fprintf(stderr, "adding feature with advance %f\n", advance); @@ -290,7 +281,7 @@ void Placement::addFeature(TextBucket& bucket, for (Anchor anchor : anchors) { PlacedGlyphs glyphs = - getGlyphs(anchor, advance, shaping, faces, fontScale, horizontal, + getGlyphs(anchor, advance, shaping, face, fontScale, horizontal, line, maxAngleDelta, rotate); PlacementProperty place = collision.place(glyphs, anchor, anchor.scale, maxPlacementScale, @@ -302,14 +293,14 @@ void Placement::addFeature(TextBucket& bucket, } } -float Placement::measureText(const IndexedFaces &faces, +float Placement::measureText(const GlyphPositions &face, const Shaping &shaping) { float advance = 0; // TODO: advance is not calculated correctly. we should instead use the // bounding box of the glyph placement. for (const GlyphPlacement &shape : shaping) { - advance += getGlyph(shape, faces).metrics.advance; + advance += getGlyph(shape, face).metrics.advance; } return advance; From d5349f9cd31f60914dcacb3a8f540a1eb47c5790 Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 29 May 2014 05:19:15 -0400 Subject: [PATCH 025/172] Don't call varint() more than once. --- src/text/glyph_store.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 88642907a..3e6c2bc74 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -93,11 +93,9 @@ void GlyphPBF::parse(FontStack &stack) { pbf glyph_pbf = fontstack_pbf.message(); SDFGlyph glyph; - uint32_t id = 0; while (glyph_pbf.next()) { if (glyph_pbf.tag == 1) { // id - id = glyph_pbf.varint(); glyph.id = glyph_pbf.varint(); } else if (glyph_pbf.tag == 2) { // bitmap glyph.bitmap = glyph_pbf.string(); @@ -116,7 +114,7 @@ void GlyphPBF::parse(FontStack &stack) { } } - stack.insert(id, glyph); + stack.insert(glyph.id, glyph); } else { fontstack_pbf.skip(); } From f48999dc13fec3fa024f9faa13b4d697a417fa41 Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 29 May 2014 05:37:30 -0400 Subject: [PATCH 026/172] Treat out of range glyphs as belonging to 0-127 for now. --- src/text/glyph.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/text/glyph.cpp b/src/text/glyph.cpp index 039e3bc36..99e0169ca 100644 --- a/src/text/glyph.cpp +++ b/src/text/glyph.cpp @@ -95,7 +95,10 @@ GlyphRange getGlyphRange(uint32_t glyph) { if (glyph <= 65279) return { 65279, 65279 }; // Specials if (glyph <= 65519) return { 65280, 65519 }; // Halfwidth and Fullwidth Forms if (glyph <= 65533) return { 65520, 65533 }; // Specials - return { 0, 0 }; + // fprintf(stderr, "Glyph out of range %u\n", glyph); + // If glyph is out of range request basic latin for now... + // TODO: null range or way to prevent any range from being used at all? + return { 0, 127 }; } } From 8ba1acaa8361ec717ea6726131df25016645aa9f Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 29 May 2014 06:09:54 -0400 Subject: [PATCH 027/172] Add second fontstack for testing. --- bin/style.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/style.js b/bin/style.js index 1a6aca8b7..e1f3cae08 100644 --- a/bin/style.js +++ b/bin/style.js @@ -731,7 +731,7 @@ module.exports = { "value": "city", "text_field": "name", "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 20, "feature_type": "point", "type": "text" @@ -743,7 +743,7 @@ module.exports = { "value": "town", "text_field": "name", "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 24, "feature_type": "point", "type": "text" @@ -755,7 +755,7 @@ module.exports = { "value": "village", "text_field": "name", "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 22, "feature_type": "point", "type": "text" @@ -771,7 +771,7 @@ module.exports = { ], "text_field": "name", "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 14, "feature_type": "point", "type": "text" From 99396478ff0579a50feb3cc4bb30dbfe4455b204 Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 29 May 2014 11:41:35 -0400 Subject: [PATCH 028/172] Use 256 sized rangeglyphs. Switch to mapbox API VTs. --- src/map/map.cpp | 2 +- src/text/glyph.cpp | 97 +++------------------------------------- src/text/glyph_store.cpp | 2 +- 3 files changed, 7 insertions(+), 94 deletions(-) diff --git a/src/map/map.cpp b/src/map/map.cpp index e72c7e30b..7ac6dbe0e 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -163,7 +163,7 @@ void Map::setup() { sources.emplace("outdoors", std::unique_ptr(new Source(*this, painter, - "http://api-maps-gl.tilestream.net/v3/mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5/%d/%d/%d.vector.pbf", + "http://a.tiles.mapbox.com/v3/mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5/%d/%d/%d.vector.pbf", Source::Type::vector, {{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }}, 512, diff --git a/src/text/glyph.cpp b/src/text/glyph.cpp index 99e0169ca..882a8c493 100644 --- a/src/text/glyph.cpp +++ b/src/text/glyph.cpp @@ -7,98 +7,11 @@ namespace llmr { // most of our lookups are going to be within the first 3 ranges listed here, so this is // likely faster. GlyphRange getGlyphRange(uint32_t glyph) { - if (glyph <= 127) return { 0, 127 }; // Basic Latin - if (glyph <= 255) return { 128, 255 }; // Latin-1 Supplement - if (glyph >= 8192 && glyph <= 8303) return { 8192, 8303 }; // General Punctuation - if (glyph <= 383) return { 256, 383 }; // Latin Extended-A - if (glyph <= 591) return { 384, 591 }; // Latin Extended-B - if (glyph <= 687) return { 592, 687 }; // IPA Extensions - if (glyph <= 767) return { 688, 767 }; // Spacing Modifier Letters - if (glyph <= 879) return { 768, 879 }; // Combining Diacritical Marks - if (glyph <= 1023) return { 880, 1023 }; // Greek - if (glyph <= 1279) return { 1024, 1279 }; // Cyrillic - if (glyph <= 1423) return { 1280, 1423 }; // Armenian - if (glyph <= 1535) return { 1424, 1535 }; // Hebrew - if (glyph <= 1791) return { 1536, 1791 }; // Arabic - if (glyph <= 1871) return { 1792, 1871 }; // Syriac - if (glyph <= 1983) return { 1872, 1983 }; // Thaana - if (glyph <= 2431) return { 1984, 2431 }; // Devanagari - if (glyph <= 2559) return { 2432, 2559 }; // Bengali - if (glyph <= 2687) return { 2560, 2687 }; // Gurmukhi - if (glyph <= 2815) return { 2688, 2815 }; // Gujarati - if (glyph <= 2943) return { 2816, 2943 }; // Oriya - if (glyph <= 3071) return { 2944, 3071 }; // Tamil - if (glyph <= 3199) return { 3072, 3199 }; // Telugu - if (glyph <= 3327) return { 3200, 3327 }; // Kannada - if (glyph <= 3455) return { 3328, 3455 }; // Malayalam - if (glyph <= 3583) return { 3456, 3583 }; // Sinhala - if (glyph <= 3711) return { 3584, 3711 }; // Thai - if (glyph <= 3839) return { 3712, 3839 }; // Lao - if (glyph <= 4095) return { 3840, 4095 }; // Tibetan - if (glyph <= 4255) return { 4096, 4255 }; // Myanmar - if (glyph <= 4351) return { 4256, 4351 }; // Georgian - if (glyph <= 4607) return { 4352, 4607 }; // Hangul Jamo - if (glyph <= 4991) return { 4608, 4991 }; // Ethiopic - if (glyph <= 5119) return { 4992, 5119 }; // Cherokee - if (glyph <= 5759) return { 5120, 5759 }; // Unified Canadian Aboriginal Syllabics - if (glyph <= 5791) return { 5760, 5791 }; // Ogham - if (glyph <= 5887) return { 5792, 5887 }; // Runic - if (glyph <= 6143) return { 5888, 6143 }; // Khmer - if (glyph <= 6319) return { 6144, 6319 }; // Mongolian - if (glyph <= 7935) return { 6320, 7935 }; // Latin Extended Additional - if (glyph <= 8191) return { 7936, 8191 }; // Greek Extended - if (glyph <= 8351) return { 8304, 8351 }; // Superscripts and Subscripts - if (glyph <= 8399) return { 8352, 8399 }; // Currency Symbols - if (glyph <= 8447) return { 8400, 8447 }; // Combining Marks for Symbols - if (glyph <= 8527) return { 8448, 8527 }; // Letterlike Symbols - if (glyph <= 8591) return { 8528, 8591 }; // Number Forms - if (glyph <= 8703) return { 8592, 8703 }; // Arrows - if (glyph <= 8959) return { 8704, 8959 }; // Mathematical Operators - if (glyph <= 9215) return { 8960, 9215 }; // Miscellaneous Technical - if (glyph <= 9279) return { 9216, 9279 }; // Control Pictures - if (glyph <= 9311) return { 9280, 9311 }; // Optical Character Recognition - if (glyph <= 9471) return { 9312, 9471 }; // Enclosed Alphanumerics - if (glyph <= 9599) return { 9472, 9599 }; // Box Drawing - if (glyph <= 9631) return { 9600, 9631 }; // Block Elements - if (glyph <= 9727) return { 9632, 9727 }; // Geometric Shapes - if (glyph <= 9983) return { 9728, 9983 }; // Miscellaneous Symbols - if (glyph <= 10175) return { 9984, 10175 }; // Dingbats - if (glyph <= 10495) return { 10176, 10495 }; // Braille Patterns - if (glyph <= 12031) return { 10496, 12031 }; // CJK Radicals Supplement - if (glyph <= 12255) return { 12032, 12255 }; // Kangxi Radicals - if (glyph <= 12287) return { 12256, 12287 }; // Ideographic Description Characters - if (glyph <= 12351) return { 12288, 12351 }; // CJK Symbols and Punctuation - if (glyph <= 12447) return { 12352, 12447 }; // Hiragana - if (glyph <= 12543) return { 12448, 12543 }; // Katakana - if (glyph <= 12591) return { 12544, 12591 }; // Bopomofo - if (glyph <= 12687) return { 12592, 12687 }; // Hangul Compatibility Jamo - if (glyph <= 12703) return { 12688, 12703 }; // Kanbun - if (glyph <= 12735) return { 12704, 12735 }; // Bopomofo Extended - if (glyph <= 13055) return { 12736, 13055 }; // Enclosed CJK Letters and Months - if (glyph <= 13311) return { 13056, 13311 }; // CJK Compatibility - if (glyph <= 19893) return { 13312, 19893 }; // CJK Unified Ideographs Extension A - if (glyph <= 40959) return { 19894, 40959 }; // CJK Unified Ideographs - if (glyph <= 42127) return { 40960, 42127 }; // Yi Syllables - if (glyph <= 42191) return { 42128, 42191 }; // Yi Radicals - if (glyph <= 55203) return { 42192, 55203 }; // Hangul Syllables - if (glyph <= 56191) return { 55204, 56191 }; // High Surrogates - if (glyph <= 56319) return { 56192, 56319 }; // High Private Use Surrogates - if (glyph <= 57343) return { 56320, 57343 }; // Low Surrogates - if (glyph <= 63743) return { 57344, 63743 }; // Private Use - if (glyph <= 64255) return { 63744, 64255 }; // CJK Compatibility Ideographs - if (glyph <= 64335) return { 64256, 64335 }; // Alphabetic Presentation Forms - if (glyph <= 65023) return { 64336, 65023 }; // Arabic Presentation Forms-A - if (glyph <= 65071) return { 65024, 65071 }; // Combining Half Marks - if (glyph <= 65103) return { 65072, 65103 }; // CJK Compatibility Forms - if (glyph <= 65135) return { 65104, 65135 }; // Small Form Variants - if (glyph <= 65278) return { 65136, 65278 }; // Arabic Presentation Forms-B - if (glyph <= 65279) return { 65279, 65279 }; // Specials - if (glyph <= 65519) return { 65280, 65519 }; // Halfwidth and Fullwidth Forms - if (glyph <= 65533) return { 65520, 65533 }; // Specials - // fprintf(stderr, "Glyph out of range %u\n", glyph); - // If glyph is out of range request basic latin for now... - // TODO: null range or way to prevent any range from being used at all? - return { 0, 127 }; + unsigned start = (glyph/256) * 256; + unsigned end = (start + 255); + if (start > 65280) start = 65280; + if (end > 65533) end = 65533; + return { start, end }; } } diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index dc77d18c0..e0404c08d 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -47,7 +47,7 @@ GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) : future(promise.get_future().share()) { // Load the glyph set URL - std::string url = util::sprintf<255>("http://mapbox.s3.amazonaws.com/gl-glyphs/%s/%d-%d.pbf", fontStack.c_str(), glyphRange.first, glyphRange.second); + std::string url = util::sprintf<255>("http://mapbox.s3.amazonaws.com/gl-glyphs-256/%s/%d-%d.pbf", fontStack.c_str(), glyphRange.first, glyphRange.second); // TODO: Find more reliable URL normalization function std::replace(url.begin(), url.end(), ' ', '+'); From 67a3e4651f5f3bb52d2178eb00f931be105036fb Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Thu, 29 May 2014 12:08:37 -0400 Subject: [PATCH 029/172] include locale, ref #270 --- include/llmr/util/utf.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/llmr/util/utf.hpp b/include/llmr/util/utf.hpp index 8aa85a90a..92da93f01 100644 --- a/include/llmr/util/utf.hpp +++ b/include/llmr/util/utf.hpp @@ -8,6 +8,7 @@ #include #else #include +#include #endif namespace llmr { From 72a71c6f70a14a166ccf29a09d2cb1c0d643e73f Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 29 May 2014 12:13:56 -0400 Subject: [PATCH 030/172] Lookup shaping value by string key. Refs #272. --- src/renderer/text_bucket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index 7e9633f4b..5823607ac 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -112,7 +112,7 @@ void TextBucket::addFeature(const VectorTileFeature &feature, } const Value &value = it_prop->second; - auto it_shaping = shapings.find(value); + auto it_shaping = shapings.find(toString(value)); if (it_shaping == shapings.end()) { if (debug::shapingWarning) { fprintf(stderr, "[WARNING] missing shaping for '%s'\n", toString(value).c_str()); From 16c43d30bd42aad8d8596c787f175a128b230fc4 Mon Sep 17 00:00:00 2001 From: Nicki Dlugash Date: Thu, 29 May 2014 13:05:48 -0400 Subject: [PATCH 031/172] moved contour lines above hillshade --- bin/style.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/bin/style.js b/bin/style.js index 35f40beac..a3c312f54 100644 --- a/bin/style.js +++ b/bin/style.js @@ -984,18 +984,6 @@ module.exports = { "name": "waterway_stream", "bucket": "waterway_stream" }, - { - "name": "contour_line_loud", - "bucket": "contour_line_10" - }, - { - "name": "contour_line_loud", - "bucket": "contour_line_5" - }, - { - "name": "contour_line_regular", - "bucket": "contour_line_other" - }, { "name": "building_shadow", "bucket": "building" @@ -1024,6 +1012,18 @@ module.exports = { "name": "hillshade_full_shadow", "bucket": "hillshade_full_shadow" }, + { + "name": "contour_line_loud", + "bucket": "contour_line_10" + }, + { + "name": "contour_line_loud", + "bucket": "contour_line_5" + }, + { + "name": "contour_line_regular", + "bucket": "contour_line_other" + }, { "name": "barrier_line_gate", "bucket": "barrier_line_gate" From 7e0d4399380fd88192b5bde7b8e28a53d4be590d Mon Sep 17 00:00:00 2001 From: Eden Halperin Date: Thu, 29 May 2014 11:16:59 -0700 Subject: [PATCH 032/172] fix country labels --- bin/style.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/style.js b/bin/style.js index 553883728..82705ae24 100644 --- a/bin/style.js +++ b/bin/style.js @@ -649,7 +649,7 @@ module.exports = { "layer": "country_label", "text_field": "name", "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 24, "feature_type": "point", "type": "text" @@ -2251,7 +2251,7 @@ module.exports = { "country_label": { "color": "country_text", "stroke": "rgba(255,255,255,0.5)", - "strokeWidth": 0.4, + "strokeWidth": 0.5, "size": "country_label_size" }, "country_label_line": { @@ -3000,7 +3000,7 @@ module.exports = { "country_label": { "color": "text_night", "stroke": "text2_stroke_night", - "strokeWidth": 0.4, + "strokeWidth": 0.5, "size": "country_label_size" }, "country_label_line": { From f5f187fb911ac3564b7415e1136c48d538a35e71 Mon Sep 17 00:00:00 2001 From: Eden Halperin Date: Thu, 29 May 2014 11:45:34 -0700 Subject: [PATCH 033/172] use updated fontstack --- bin/style.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/style.js b/bin/style.js index 82705ae24..38faa8483 100644 --- a/bin/style.js +++ b/bin/style.js @@ -649,7 +649,7 @@ module.exports = { "layer": "country_label", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Bold, Arial Unicode MS Bold", "fontSize": 24, "feature_type": "point", "type": "text" @@ -666,7 +666,7 @@ module.exports = { "type": "text", "text_field": "name", "path": "curve", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Italic, Arial Unicode MS Regular", "fontSize": 16 }, "marine_label_point_1": { @@ -678,7 +678,7 @@ module.exports = { "path": "horizontal", "field": "labelrank", "value": 1, - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Italic, Arial Unicode MS Regular", "fontSize": 30 }, "marine_label_point_2": { @@ -690,7 +690,7 @@ module.exports = { "path": "horizontal", "field": "labelrank", "value": 2, - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Italic, Arial Unicode MS Regular", "fontSize": 24 }, "marine_label_point_other": { @@ -702,7 +702,7 @@ module.exports = { "path": "horizontal", "field": "labelrank", "value": [3,4,5,6], - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Italic, Arial Unicode MS Regular", "fontSize": 18 }, "state_label": { @@ -815,7 +815,7 @@ module.exports = { "layer": "water_label", "text_field": "name", "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", "fontSize": 12, "feature_type": "point", "type": "text" @@ -825,7 +825,7 @@ module.exports = { "layer": "waterway_label", "text_field": "name", "path": "curve", - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", "fontSize": 12, "textMinDistance": 15, "feature_type": "line", From f83f4a6d63be8674c7f2ec35f9471025040147a0 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 12:16:01 -0700 Subject: [PATCH 034/172] include / fix compile issues with g++-4.9 --- include/llmr/map/tile.hpp | 1 + include/llmr/renderer/bucket.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 0f43f9df2..9681c3637 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace llmr { diff --git a/include/llmr/renderer/bucket.hpp b/include/llmr/renderer/bucket.hpp index f8447be89..43bd96e3f 100644 --- a/include/llmr/renderer/bucket.hpp +++ b/include/llmr/renderer/bucket.hpp @@ -2,6 +2,7 @@ #define LLMR_RENDERER_BUCKET #include +#include #include #include #include From 189436919d9e2793e85b098c0aa43a506f3a4d7e Mon Sep 17 00:00:00 2001 From: Nicki Dlugash Date: Thu, 29 May 2014 15:31:48 -0400 Subject: [PATCH 035/172] updated font for poi labels, and made arial unicode bold fallback for open sans semibold --- bin/style.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/style.js b/bin/style.js index 38faa8483..c831fd414 100644 --- a/bin/style.js +++ b/bin/style.js @@ -723,7 +723,7 @@ module.exports = { "value": "city", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 20, "feature_type": "point", "type": "text" @@ -735,7 +735,7 @@ module.exports = { "value": "town", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 24, "feature_type": "point", "type": "text" @@ -747,7 +747,7 @@ module.exports = { "value": "village", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 22, "feature_type": "point", "type": "text" @@ -763,7 +763,7 @@ module.exports = { ], "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, "feature_type": "point", "type": "text" @@ -878,7 +878,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 11, "feature_type": "point", "type": "text" @@ -891,7 +891,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", "type": "text" @@ -904,7 +904,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Regular, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", "type": "text" From 42c233b8b45c25dc41a989c68bd71a3ced3ac2b5 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 12:32:54 -0700 Subject: [PATCH 036/172] fix -Wformat-security warning with dodgy fprintf --- common.gypi | 14 +++++++++++--- src/text/glyph_store.cpp | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index b1ad46015..a3e4e5e2f 100644 --- a/common.gypi +++ b/common.gypi @@ -5,6 +5,11 @@ 'CLANG_CXX_LIBRARY': 'libc++', 'CLANG_CXX_LANGUAGE_STANDARD':'c++11', 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', + 'GCC_ENABLE_CPP_RTTI':'YES', + 'OTHER_CPLUSPLUSFLAGS': [ '-Wall', '-Wextra' ], + 'GCC_WARN_PEDANTIC': 'YES', + 'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE' }, 'cflags_cc': ['-std=c++11'], 'configurations': { @@ -14,7 +19,11 @@ 'xcode_settings': { 'GCC_OPTIMIZATION_LEVEL': '0', 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES', - 'OTHER_CPLUSPLUSFLAGS': [ '-Wall', '-Wextra', '-pedantic' ] + 'DEAD_CODE_STRIPPING': 'NO', + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'NO', + 'RUN_CLANG_STATIC_ANALYZER':'YES', + 'CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY': 'YES', + 'CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER': 'YES' } }, 'Release': { @@ -24,8 +33,7 @@ 'GCC_OPTIMIZATION_LEVEL': '3', 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO', 'DEAD_CODE_STRIPPING': 'YES', - 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', - 'OTHER_CPLUSPLUSFLAGS': [ '-Wall', '-Wextra', '-pedantic' ] + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES' } } } diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index e0404c08d..3f741236f 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -52,7 +52,7 @@ GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) // TODO: Find more reliable URL normalization function std::replace(url.begin(), url.end(), ' ', '+'); - fprintf(stderr, url.c_str()); + fprintf(stderr, "%s\n", url.c_str()); platform::request_http(url, [&](platform::Response *res) { if (res->code != 200) { From 829f9d11977d95102fe2141f70fa75ed6faf3ccb Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 12:36:22 -0700 Subject: [PATCH 037/172] [build] another missing include --- src/util/threadpool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/threadpool.cpp b/src/util/threadpool.cpp index 3b69302b1..29ab11f1c 100644 --- a/src/util/threadpool.cpp +++ b/src/util/threadpool.cpp @@ -1,6 +1,7 @@ #include #include #include +#include using namespace llmr::util; From aa85c54b2de903cacaf592efdac596ea3fce9fc3 Mon Sep 17 00:00:00 2001 From: Nicki Dlugash Date: Thu, 29 May 2014 15:42:04 -0400 Subject: [PATCH 038/172] dont have font stack yet with arial unicode bold as fallback to Open Sans Semibold, so changed them back --- bin/style.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/style.js b/bin/style.js index c831fd414..aa7d5b38f 100644 --- a/bin/style.js +++ b/bin/style.js @@ -649,7 +649,7 @@ module.exports = { "layer": "country_label", "text_field": "name", "path": "horizontal", - "font": "Open Sans Bold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 24, "feature_type": "point", "type": "text" @@ -723,7 +723,7 @@ module.exports = { "value": "city", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 20, "feature_type": "point", "type": "text" @@ -735,7 +735,7 @@ module.exports = { "value": "town", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 24, "feature_type": "point", "type": "text" @@ -747,7 +747,7 @@ module.exports = { "value": "village", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 22, "feature_type": "point", "type": "text" @@ -763,7 +763,7 @@ module.exports = { ], "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 18, "feature_type": "point", "type": "text" @@ -878,7 +878,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 11, "feature_type": "point", "type": "text" @@ -891,7 +891,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 10, "feature_type": "point", "type": "text" @@ -904,7 +904,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Semibold, Arial Unicode MS Regular", "fontSize": 10, "feature_type": "point", "type": "text" From 7b7e8007e3801de4593fa72f96fa2ac0c8ca43b6 Mon Sep 17 00:00:00 2001 From: Nicki Dlugash Date: Thu, 29 May 2014 15:44:38 -0400 Subject: [PATCH 039/172] temporarily changed country label font back to original --- bin/style.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/style.js b/bin/style.js index aa7d5b38f..8c7b11aaf 100644 --- a/bin/style.js +++ b/bin/style.js @@ -649,7 +649,7 @@ module.exports = { "layer": "country_label", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", + "font": "Open Sans Bold, Arial Unicode MS Bold", "fontSize": 24, "feature_type": "point", "type": "text" From 3003085763d0b590d6f2c8536abed0e086839212 Mon Sep 17 00:00:00 2001 From: Nicki Dlugash Date: Thu, 29 May 2014 15:50:04 -0400 Subject: [PATCH 040/172] new font stack deployed. Made Arial Unicode Bold fallback for Open Sans Semibold --- bin/style.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/style.js b/bin/style.js index 8c7b11aaf..c831fd414 100644 --- a/bin/style.js +++ b/bin/style.js @@ -723,7 +723,7 @@ module.exports = { "value": "city", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 20, "feature_type": "point", "type": "text" @@ -735,7 +735,7 @@ module.exports = { "value": "town", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 24, "feature_type": "point", "type": "text" @@ -747,7 +747,7 @@ module.exports = { "value": "village", "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 22, "feature_type": "point", "type": "text" @@ -763,7 +763,7 @@ module.exports = { ], "text_field": "name", "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, "feature_type": "point", "type": "text" @@ -878,7 +878,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 11, "feature_type": "point", "type": "text" @@ -891,7 +891,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", "type": "text" @@ -904,7 +904,7 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, - "font": "Open Sans Semibold, Arial Unicode MS Regular", + "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", "type": "text" From da33bef634b9555fb93c5e02faffd29c516f7ec7 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 13:09:10 -0700 Subject: [PATCH 041/172] initialize variables --- src/style/properties.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/style/properties.cpp b/src/style/properties.cpp index 0e4841830..b39f20c51 100644 --- a/src/style/properties.cpp +++ b/src/style/properties.cpp @@ -29,9 +29,11 @@ float functions::stops(float z, const std::vector& stops) { if (stops.size() % 2 != 0) return 0; bool smaller = false; - float smaller_z, smaller_val; + float smaller_z = 0.0; + float smaller_val = 0.0; bool larger = false; - float larger_z, larger_val; + float larger_z = 0.0; + float larger_val = 0.0; for (uint32_t i = 0; i < stops.size(); i += 2) { float stop_z = stops[i]; From 23655f0bb1484408072a6ce60c8a787b4b51d460 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 13:09:24 -0700 Subject: [PATCH 042/172] use std::pow --- src/map/transform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map/transform.cpp b/src/map/transform.cpp index 996117bfa..d567a586c 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -60,8 +60,8 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) { // Un-rotate when rotated and panning far enough to show off-world in corners. double w = final.scale * util::tileSize / 2; - double m = std::sqrt(pow((current.width / 2), 2) + pow((current.height / 2), 2)); - double x = std::abs(sqrt(pow(final.x, 2) + pow(final.y, 2))); + double m = std::sqrt(std::pow((current.width / 2), 2) + pow((current.height / 2), 2)); + double x = std::abs(sqrt(std::pow(final.x, 2) + std::pow(final.y, 2))); if (current.angle && w - x < m) _setAngle(0, 500_milliseconds, true); if (duration == 0) { From 5c7461f19e293491a1a0ae7c3d528364207c8007 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 13:10:51 -0700 Subject: [PATCH 043/172] use std::abs --- src/clipper/clipper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp index 95975450e..56ad58416 100755 --- a/src/clipper/clipper.cpp +++ b/src/clipper/clipper.cpp @@ -2152,13 +2152,13 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, else if (e1->PolyTyp != e2->PolyTyp) { //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... - if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 && + if ((e1->WindDelta == 0) && std::abs(e2->WindCnt) == 1 && (m_ClipType != ctUnion || e2->WindCnt2 == 0)) { AddOutPt(e1, Pt); if (e1Contributing) e1->OutIdx = Unassigned; } - else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) && + else if ((e2->WindDelta == 0) && (std::abs(e1->WindCnt) == 1) && (m_ClipType != ctUnion || e1->WindCnt2 == 0)) { AddOutPt(e2, Pt); From 30a34d73f87f28a63b4451e823b6d10ee3fc5d9e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 13:23:00 -0700 Subject: [PATCH 044/172] fix static analyzer warning: Result of 'calloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t' --- include/llmr/geometry/sprite_atlas.hpp | 2 +- src/geometry/sprite_atlas.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/llmr/geometry/sprite_atlas.hpp b/include/llmr/geometry/sprite_atlas.hpp index 220edc701..13b85e548 100644 --- a/include/llmr/geometry/sprite_atlas.hpp +++ b/include/llmr/geometry/sprite_atlas.hpp @@ -62,7 +62,7 @@ private: BinPack bin; std::map> images; std::set uninitialized; - char *data = nullptr; + uint32_t *data = nullptr; std::atomic dirty; uint32_t texture = 0; uint32_t filter = 0; diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 35f6f4588..4404695f9 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -30,7 +30,7 @@ bool SpriteAtlas::resize(const float newRatio) { pixelRatio = newRatio; if (data) { - char *old_data = data; + uint32_t *old_data = data; data = nullptr; allocate(); @@ -185,7 +185,7 @@ void SpriteAtlas::allocate() { if (!data) { dimension w = static_cast(width * pixelRatio); dimension h = static_cast(height * pixelRatio); - data = (char *)calloc(w * h, sizeof(uint32_t)); + data = (uint32_t *)calloc(w * h, sizeof(uint32_t)); } } From 88f89d0150fb01a8f98b87ef2958940450fae14f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 13:09:10 -0700 Subject: [PATCH 045/172] initialize variables --- src/style/properties.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/style/properties.cpp b/src/style/properties.cpp index 0e4841830..b39f20c51 100644 --- a/src/style/properties.cpp +++ b/src/style/properties.cpp @@ -29,9 +29,11 @@ float functions::stops(float z, const std::vector& stops) { if (stops.size() % 2 != 0) return 0; bool smaller = false; - float smaller_z, smaller_val; + float smaller_z = 0.0; + float smaller_val = 0.0; bool larger = false; - float larger_z, larger_val; + float larger_z = 0.0; + float larger_val = 0.0; for (uint32_t i = 0; i < stops.size(); i += 2) { float stop_z = stops[i]; From b4d5b1ca657c92dc03a8b265b35637137ff1a50b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 13:09:24 -0700 Subject: [PATCH 046/172] use std::pow --- src/map/transform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map/transform.cpp b/src/map/transform.cpp index 996117bfa..d567a586c 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -60,8 +60,8 @@ void Transform::_moveBy(const double dx, const double dy, const time duration) { // Un-rotate when rotated and panning far enough to show off-world in corners. double w = final.scale * util::tileSize / 2; - double m = std::sqrt(pow((current.width / 2), 2) + pow((current.height / 2), 2)); - double x = std::abs(sqrt(pow(final.x, 2) + pow(final.y, 2))); + double m = std::sqrt(std::pow((current.width / 2), 2) + pow((current.height / 2), 2)); + double x = std::abs(sqrt(std::pow(final.x, 2) + std::pow(final.y, 2))); if (current.angle && w - x < m) _setAngle(0, 500_milliseconds, true); if (duration == 0) { From 07767951ee8cf17620fd1a7eb86e1bba600c3ba0 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 13:10:51 -0700 Subject: [PATCH 047/172] use std::abs --- src/clipper/clipper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp index 95975450e..56ad58416 100755 --- a/src/clipper/clipper.cpp +++ b/src/clipper/clipper.cpp @@ -2152,13 +2152,13 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, else if (e1->PolyTyp != e2->PolyTyp) { //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... - if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 && + if ((e1->WindDelta == 0) && std::abs(e2->WindCnt) == 1 && (m_ClipType != ctUnion || e2->WindCnt2 == 0)) { AddOutPt(e1, Pt); if (e1Contributing) e1->OutIdx = Unassigned; } - else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) && + else if ((e2->WindDelta == 0) && (std::abs(e1->WindCnt) == 1) && (m_ClipType != ctUnion || e1->WindCnt2 == 0)) { AddOutPt(e2, Pt); From 841cee77505d7065bcc77269f9ed9913ced63fc0 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Thu, 29 May 2014 23:41:49 +0300 Subject: [PATCH 048/172] change default cubic bezier for easings --- src/util/transition.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/transition.cpp b/src/util/transition.cpp index 37177a935..7f4b544fe 100644 --- a/src/util/transition.cpp +++ b/src/util/transition.cpp @@ -4,7 +4,7 @@ namespace llmr { namespace util { -UnitBezier ease(0.25, 0.1, 0.25, 1); +UnitBezier ease(0, 0, 0.25, 1); transition::~transition() {} From c9a1d9efd47d70eaf0e4d2de00fccf4eb9b5a5cf Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 14:17:22 -0700 Subject: [PATCH 049/172] remove unused member variable --- include/llmr/renderer/prerendered_texture.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/llmr/renderer/prerendered_texture.hpp b/include/llmr/renderer/prerendered_texture.hpp index e35cc0321..4b163ac70 100644 --- a/include/llmr/renderer/prerendered_texture.hpp +++ b/include/llmr/renderer/prerendered_texture.hpp @@ -26,7 +26,6 @@ private: GLint previous_fbo = 0; GLuint fbo = 0; GLuint texture = 0; - bool mipmapped = false; }; } From a83e749e0977ae057e9ae4e0e82cd2d3cf5b9bba Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 14:17:58 -0700 Subject: [PATCH 050/172] [travis] try building with thread and address sanitizer in Debug --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5d46212f1..99dad26fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ install: before_script: - if [[ ${CXX} == "g++" ]]; then export CXX="g++-4.8" ; fi +- if [[ $BUILDTYPE} == "Debug" ]]; then export CXXFLAGS="-fsanitize=address -fsanitize=thread";export LDFLAGS="-fsanitize=address -fsanitize=thread" script: - make llmr BUILDTYPE=${BUILDTYPE} From a501f8788f9be0ec97f4c54170e2e3af792dd1f6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 14:51:05 -0700 Subject: [PATCH 051/172] [travis] fix syntax --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 99dad26fd..789083764 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ install: before_script: - if [[ ${CXX} == "g++" ]]; then export CXX="g++-4.8" ; fi -- if [[ $BUILDTYPE} == "Debug" ]]; then export CXXFLAGS="-fsanitize=address -fsanitize=thread";export LDFLAGS="-fsanitize=address -fsanitize=thread" +- if [[ $BUILDTYPE} == "Debug" ]]; then export CXXFLAGS="-fsanitize=address -fsanitize=thread";export LDFLAGS="-fsanitize=address -fsanitize=thread" ; fi script: - make llmr BUILDTYPE=${BUILDTYPE} From 2cb699cd189a0b885f633e74ee3f8a0534265c27 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 29 May 2014 14:56:42 -0700 Subject: [PATCH 052/172] rename app build products --- ios/llmr-app.gyp | 2 +- linux/llmr-app.gyp | 2 +- macosx/llmr-app.gyp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/llmr-app.gyp b/ios/llmr-app.gyp index e42e914fc..5d7e1f8e3 100644 --- a/ios/llmr-app.gyp +++ b/ios/llmr-app.gyp @@ -6,7 +6,7 @@ 'targets': [ { "target_name": "iosapp", - "product_name": "llmr", + "product_name": "Mapbox GL", "type": "executable", "sources": [ "./main.m", diff --git a/linux/llmr-app.gyp b/linux/llmr-app.gyp index d979f00b4..10ceab1e9 100644 --- a/linux/llmr-app.gyp +++ b/linux/llmr-app.gyp @@ -6,7 +6,7 @@ 'targets': [ { 'target_name': 'linuxapp', - 'product_name': 'llmr', + 'product_name': 'Mapbox GL', 'type': 'executable', 'sources': [ './main.cpp', diff --git a/macosx/llmr-app.gyp b/macosx/llmr-app.gyp index 560b22300..83bcd0f03 100644 --- a/macosx/llmr-app.gyp +++ b/macosx/llmr-app.gyp @@ -6,7 +6,7 @@ 'targets': [ { 'target_name': 'osxapp', - 'product_name': 'llmr', + 'product_name': 'Mapbox GL', 'type': 'executable', 'sources': [ './main.mm', From 5e429f706ced8a6b2d842fb5eff4ba844d7b8da6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 15:07:14 -0700 Subject: [PATCH 053/172] [build] debug: stop defaulting to static analyzer, use -O1, and add hardening flags --- common.gypi | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index a3e4e5e2f..8e6919a10 100644 --- a/common.gypi +++ b/common.gypi @@ -17,13 +17,11 @@ 'cflags': [ '-g', '-O0' ], 'defines': [ 'DEBUG' ], 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '0', + 'GCC_OPTIMIZATION_LEVEL': '1', 'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES', 'DEAD_CODE_STRIPPING': 'NO', 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'NO', - 'RUN_CLANG_STATIC_ANALYZER':'YES', - 'CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY': 'YES', - 'CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER': 'YES' + 'OTHER_CPLUSPLUSFLAGS': [ '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common'] } }, 'Release': { From 8413860a58ef2adcf4ceab27ee3107415b58cb62 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 15:34:05 -0700 Subject: [PATCH 054/172] add zlib to linux deps --- README.md | 2 +- setup-libraries.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c94627b47..a8d3c31c9 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Target devices: iPhone 4 and above (4S, 5, 5c, 5s) and iPad 2 and above (3, 4, m Ensure you have git and other build essentials: sudo apt-get update - sudo apt-get install git cmake make pkg-config curl automake libtool xutils-dev + sudo apt-get install git build-essential zlib1g-dev automake libtool xutils-dev make cmake pkg-config nodejs-legacy Install a `-std=c++11` capable compiler diff --git a/setup-libraries.sh b/setup-libraries.sh index b92cd3f05..710562bf1 100755 --- a/setup-libraries.sh +++ b/setup-libraries.sh @@ -32,7 +32,7 @@ if [[ $MISSING_DEPS != "" ]]; then echo 'and then re-run ./setup-libraries.sh' elif [ ${UNAME} = 'Linux' ]; then echo "Missing build deps: ${MISSING_DEPS}" - echo 'Please run "sudo apt-get install automake libtool xutils-dev cmake pkg-config libxi-dev libglu1-mesa-dev x11proto-randr-dev x11proto-xext-dev libxrandr-dev x11proto-xf86vidmode-dev libxxf86vm-dev libxcursor-dev nodejs-legacy"' + echo 'Please run "sudo apt-get install git build-essential zlib1g-dev automake libtool xutils-dev make cmake pkg-config nodejs-legacy libxi-dev libglu1-mesa-dev x11proto-randr-dev x11proto-xext-dev libxrandr-dev x11proto-xf86vidmode-dev libxxf86vm-dev libxcursor-dev"' echo 'and then re-run ./setup-libraries.sh' fi exit 1 From 8cce7dce2d6dd44411f639324d1f36f6f87a76aa Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 29 May 2014 16:01:57 -0700 Subject: [PATCH 055/172] simpler Linux build product name --- linux/llmr-app.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/llmr-app.gyp b/linux/llmr-app.gyp index 10ceab1e9..75fd0dfe3 100644 --- a/linux/llmr-app.gyp +++ b/linux/llmr-app.gyp @@ -6,7 +6,7 @@ 'targets': [ { 'target_name': 'linuxapp', - 'product_name': 'Mapbox GL', + 'product_name': 'mapbox-gl', 'type': 'executable', 'sources': [ './main.cpp', From b79f6f736f019969e496c8c22fe9b3b505e07f5a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 16:04:10 -0700 Subject: [PATCH 056/172] [travis] we can only sanitize either addresses or threads, choose one --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 789083764..00b80fe5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ install: before_script: - if [[ ${CXX} == "g++" ]]; then export CXX="g++-4.8" ; fi -- if [[ $BUILDTYPE} == "Debug" ]]; then export CXXFLAGS="-fsanitize=address -fsanitize=thread";export LDFLAGS="-fsanitize=address -fsanitize=thread" ; fi +- if [[ ${BUILDTYPE} == "Debug" ]]; then export CXXFLAGS="-fsanitize=address";export LDFLAGS="-fsanitize=address" ; fi script: - make llmr BUILDTYPE=${BUILDTYPE} From deaa1f2824dda2e304225d803b02ec56b6b19f5a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 16:40:07 -0700 Subject: [PATCH 057/172] [travis][build] run clang's address sanitizer + fixup cxxflags on linux --- .travis.yml | 3 ++- common.gypi | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 00b80fe5e..8662afde1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,8 @@ install: before_script: - if [[ ${CXX} == "g++" ]]; then export CXX="g++-4.8" ; fi -- if [[ ${BUILDTYPE} == "Debug" ]]; then export CXXFLAGS="-fsanitize=address";export LDFLAGS="-fsanitize=address" ; fi +- if [[ ${BUILDTYPE} == "Debug" ]] && [[ ${CXX} == "g++" ]]; then export CXXFLAGS="-fsanitize=address";export LDFLAGS="-fsanitize=address" ; fi +- if [[ ${BUILDTYPE} == "Debug" ]] && [[ ${CXX} == "clang++" ]]; then export CXXFLAGS="-fsanitize=thread -fPIC";export LDFLAGS="-fsanitize=thread -pie" ; fi script: - make llmr BUILDTYPE=${BUILDTYPE} diff --git a/common.gypi b/common.gypi index 8e6919a10..ba2347090 100644 --- a/common.gypi +++ b/common.gypi @@ -11,10 +11,10 @@ 'GCC_WARN_PEDANTIC': 'YES', 'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE' }, - 'cflags_cc': ['-std=c++11'], + 'cflags_cc': ['-std=c++11', '-Wall', '-Wextra'], 'configurations': { 'Debug': { - 'cflags': [ '-g', '-O0' ], + 'cflags_cc': [ '-g', '-O1', '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ], 'defines': [ 'DEBUG' ], 'xcode_settings': { 'GCC_OPTIMIZATION_LEVEL': '1', @@ -25,7 +25,7 @@ } }, 'Release': { - 'cflags': [ '-O3' ], + 'cflags_cc': [ '-O3' ], 'defines': [ 'NDEBUG' ], 'xcode_settings': { 'GCC_OPTIMIZATION_LEVEL': '3', From 7c589b9da49631667c4847ffe29fca37970a327a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 16:54:36 -0700 Subject: [PATCH 058/172] sanitizer needs CFLAGS set for libtess --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 00b80fe5e..a464bf203 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,8 @@ install: before_script: - if [[ ${CXX} == "g++" ]]; then export CXX="g++-4.8" ; fi -- if [[ ${BUILDTYPE} == "Debug" ]]; then export CXXFLAGS="-fsanitize=address";export LDFLAGS="-fsanitize=address" ; fi +- if [[ ${BUILDTYPE} == "Debug" ]] && [[ ${CXX} == "g++" ]]; then export CXXFLAGS="-fsanitize=address";export CFLAGS="${CXXFLAGS}";export LDFLAGS="-fsanitize=address" ; fi +- if [[ ${BUILDTYPE} == "Debug" ]] && [[ ${CXX} == "clang++" ]]; then export CXXFLAGS="-fsanitize=thread -fPIC";export CFLAGS="${CXXFLAGS}";export LDFLAGS="-fsanitize=thread -pie" ; fi script: - make llmr BUILDTYPE=${BUILDTYPE} From d4f45473589aa6a699fe1fb2788f849cbdfe29f8 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 17:10:50 -0700 Subject: [PATCH 059/172] [test] fix signed/unsigned comparisons --- test/rotation_range.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/rotation_range.cpp b/test/rotation_range.cpp index cb7ee0742..e0089464a 100644 --- a/test/rotation_range.cpp +++ b/test/rotation_range.cpp @@ -48,7 +48,7 @@ TEST(RotationRange, rotatingFixedCollisions) { CollisionRect{CollisionPoint{-1, 0}, CollisionPoint{0, 1}}, CollisionRect{CollisionPoint{1.4142, -10}, CollisionPoint{10, 10}}); - EXPECT_EQ(1, collisions.size()); + EXPECT_EQ(static_cast(1), collisions.size()); EXPECT_EQ(135, std::round(deg(collisions.front()[0]))); EXPECT_EQ(135, std::round(deg(collisions.front()[1]))); } @@ -61,7 +61,7 @@ TEST(RotationRange, cornerBoxCollisions) { std::back_inserter(list), CollisionPoint{1, 1}, CollisionCorners{{CollisionPoint{0, 0}, CollisionPoint{0, 10}, CollisionPoint{10, 10}, CollisionPoint{10, 0}}}); - EXPECT_EQ(1, list.size()); + EXPECT_EQ(static_cast(1), list.size()); EXPECT_EQ((CollisionRange{{M_PI / 4.0, M_PI * 7.0 / 4.0}}), list[0]); } @@ -72,7 +72,7 @@ TEST(RotationRange, cornerBoxCollisions) { std::back_inserter(list), CollisionPoint{200, 200}, CollisionCorners{{CollisionPoint{1, 1}, CollisionPoint{1, 10}, CollisionPoint{10, 10}, CollisionPoint{10, 1}}}); - EXPECT_EQ(0, list.size()); + EXPECT_EQ(static_cast(0), list.size()); } } @@ -83,7 +83,7 @@ TEST(RotationRange, circleEdgeCollisions) { circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, CollisionPoint{-10, 0}, CollisionPoint{10, 0}); std::sort(list.begin(), list.end()); - EXPECT_EQ(2, list.size()); + EXPECT_EQ(static_cast(2), list.size()); EXPECT_EQ(static_cast(M_PI / 2), list[0]); EXPECT_EQ(static_cast(M_PI * 3.0 / 2.0), list[1]); } @@ -93,7 +93,7 @@ TEST(RotationRange, circleEdgeCollisions) { CollisionAngles list; circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, CollisionPoint{0, 0}, CollisionPoint{10, 0}); - EXPECT_EQ(1, list.size()); + EXPECT_EQ(static_cast(1), list.size()); EXPECT_EQ(static_cast(M_PI / 2), list[0]); } @@ -102,7 +102,7 @@ TEST(RotationRange, circleEdgeCollisions) { CollisionAngles list; circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, CollisionPoint{3, 1}, CollisionPoint{30, 1}); - EXPECT_EQ(0, list.size()); + EXPECT_EQ(static_cast(0), list.size()); } { @@ -110,7 +110,7 @@ TEST(RotationRange, circleEdgeCollisions) { CollisionAngles list; circleEdgeCollisions(std::back_inserter(list), CollisionPoint{0, 1}, 1, CollisionPoint{-10, 1}, CollisionPoint{10, 1}); - EXPECT_EQ(0, list.size()); + EXPECT_EQ(static_cast(0), list.size()); } } @@ -121,7 +121,7 @@ TEST(RotationRange, rotatingRotatingCollisions) { CollisionRect{{-1, 0}, {1, 0}}, CollisionRect{{-1, 0}, {1, 0}}, CollisionAnchor{1, 1}); - EXPECT_EQ(2, c.size()); + EXPECT_EQ(static_cast(2), c.size()); EXPECT_EQ(135, std::round(deg(c[0][0]))); EXPECT_EQ(135, std::round(deg(c[0][1]))); EXPECT_EQ(315, std::round(deg(c[1][0]))); @@ -134,6 +134,6 @@ TEST(RotationRange, rotatingRotatingCollisions) { CollisionRect{{-1, 0}, {1, 0}}, CollisionRect{{-1, 0}, {1, 0}}, CollisionAnchor{2, 2}); - EXPECT_EQ(0, c.size()); + EXPECT_EQ(static_cast(0), c.size()); } } From 0b9c45721f4feedee49475454eb2a3f0c193d069 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 17:11:11 -0700 Subject: [PATCH 060/172] [travis] turn off a few clang++ warnings --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a464bf203..72d834a32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ before_script: - if [[ ${CXX} == "g++" ]]; then export CXX="g++-4.8" ; fi - if [[ ${BUILDTYPE} == "Debug" ]] && [[ ${CXX} == "g++" ]]; then export CXXFLAGS="-fsanitize=address";export CFLAGS="${CXXFLAGS}";export LDFLAGS="-fsanitize=address" ; fi - if [[ ${BUILDTYPE} == "Debug" ]] && [[ ${CXX} == "clang++" ]]; then export CXXFLAGS="-fsanitize=thread -fPIC";export CFLAGS="${CXXFLAGS}";export LDFLAGS="-fsanitize=thread -pie" ; fi - +- if [[ ${CXX} == "clang++" ]]; then export CXXFLAGS="-Wno-unused-local-typedefs -Wno-unknown-pragmas $CXXFLAGS"; fi script: - make llmr BUILDTYPE=${BUILDTYPE} - make clean From f5394a76383507565fb4f798d3fe4afdd0fa5c15 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 18:07:19 -0700 Subject: [PATCH 061/172] release mode: silent debug output + ifdef any potentially expensive calls --- src/geometry/glyph_atlas.cpp | 2 ++ src/geometry/sprite_atlas.cpp | 3 ++- src/map/map.cpp | 10 ++++++++-- src/map/tile_data.cpp | 2 ++ src/map/vector_tile_data.cpp | 2 ++ src/renderer/fill_bucket.cpp | 6 ++++++ src/renderer/painter.cpp | 9 +++++---- src/renderer/painter_text.cpp | 8 +++++--- src/shader/gaussian_shader.cpp | 2 ++ src/shader/raster_shader.cpp | 2 ++ src/shader/shader.cpp | 12 ++++++++++-- src/style/sprite.cpp | 2 ++ src/text/glyph_store.cpp | 2 ++ src/util/constants.cpp | 13 +++++++++++++ 14 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/geometry/glyph_atlas.cpp b/src/geometry/glyph_atlas.cpp index f4defac69..afb904407 100644 --- a/src/geometry/glyph_atlas.cpp +++ b/src/geometry/glyph_atlas.cpp @@ -137,6 +137,8 @@ void GlyphAtlas::bind() { glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); dirty = false; +#if defined(DEBUG) // platform::show_debug_image("Glyph Atlas", data, width, height); +#endif } }; diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 35f6f4588..882c6c17d 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -270,8 +270,9 @@ void SpriteAtlas::bind(bool linear) { data // const GLvoid * data ); +#if defined(DEBUG) // platform::show_color_debug_image("Sprite Atlas", data, width, height, width * pixelRatio, height * pixelRatio); - +#endif dirty = false; } }; diff --git a/src/map/map.cpp b/src/map/map.cpp index 7ac6dbe0e..60a7aa78d 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -479,8 +479,9 @@ void Map::prepare() { } void Map::render() { +#if defined(DEBUG) std::vector debug; - +#endif painter.clear(); painter.resetFramebuffer(); @@ -493,6 +494,7 @@ void Map::render() { painter.drawClippingMasks(sources); +#if defined(DEBUG) // Generate debug information size_t source_id = 0; for (const auto &pair : sources) { @@ -501,7 +503,7 @@ void Map::render() { debug.emplace_back(util::sprintf<100>("source %d: %d\n", source_id, count)); source_id++; } - +#endif // Actually render the layers if (debug::renderTree) { std::cout << "{" << std::endl; indent++; } renderLayers(style.layers); @@ -520,7 +522,9 @@ void Map::render() { painter.renderMatte(); +#if defined(DEBUG) painter.renderDebugText(debug); +#endif // Schedule another rerender when we definitely need a next frame. if (transform.needsTransition()) { @@ -573,12 +577,14 @@ void Map::renderLayers(const std::vector& layers) { template typename Styles::const_iterator find_style(const Styles &styles, const LayerDescription &layer_desc) { auto it = styles.find(layer_desc.name); +#if defined(DEBUG) if (it == styles.end()) { if (debug::renderWarnings) { fprintf(stderr, "[WARNING] can't find class named '%s' in style\n", layer_desc.name.c_str()); } } +#endif return it; } diff --git a/src/map/tile_data.cpp b/src/map/tile_data.cpp index 9ad752526..2c8a47deb 100644 --- a/src/map/tile_data.cpp +++ b/src/map/tile_data.cpp @@ -42,7 +42,9 @@ void TileData::request() { // Schedule tile parsing in another thread tile->reparse(); } else { +#if defined(DEBUG) fprintf(stderr, "[%s] tile loading failed: %d, %s\n", tile->url.c_str(), res->code, res->error_message.c_str()); +#endif } }, map.getLoop()); } diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp index 3c972aa31..4a1e91f41 100644 --- a/src/map/vector_tile_data.cpp +++ b/src/map/vector_tile_data.cpp @@ -24,7 +24,9 @@ void VectorTileData::parse() { // is going to be discarded afterwards. TileParser parser(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getGlyphStore(), map.getSpriteAtlas()); } catch (const std::exception& ex) { +#if defined(DEBUG) fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what()); +#endif cancel(); return; } diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index 2a4e1c78a..702156659 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -182,18 +182,24 @@ void FillBucket::tessellate() { if (a != TESS_UNDEF && b != TESS_UNDEF && c != TESS_UNDEF) { triangleElementsBuffer.add(triangleIndex + a, triangleIndex + b, triangleIndex + c); } else { +#if defined(DEBUG) // TODO: We're missing a vertex that was not part of the line. fprintf(stderr, "undefined element buffer\n"); +#endif } } else { +#if defined(DEBUG) fprintf(stderr, "undefined element buffer\n"); +#endif } } triangleGroup.vertex_length += total_vertex_count; triangleGroup.elements_length += triangle_count; } else { +#if defined(DEBUG) fprintf(stderr, "tessellation failed\n"); +#endif } // We're adding the total vertex count *after* we added additional vertices diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 82808f4d1..b755301eb 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -1,13 +1,13 @@ #include - #include - #include #include -#include #include #include #include +#if defined(DEBUG) +#include +#endif #include #include @@ -29,8 +29,9 @@ bool Painter::needsAnimation() const { } void Painter::setup() { +#if defined(DEBUG) util::timer timer("painter setup"); - +#endif setupShaders(); assert(iconShader); diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index 0c3c0a01b..bd1709a96 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -1,6 +1,7 @@ #include #include #include +#include using namespace llmr; @@ -66,8 +67,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons history[0].z = history[1].z; } - size_t frameLen = history.size(); - assert("there should never be less than three frames in the history" && frameLen >= 3); + 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; @@ -81,7 +81,9 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons timeDiff = lastFrame.timestamp - history[1].timestamp; float fadedist = zoomDiff / (timeDiff / duration); - if (isnan(fadedist)) fprintf(stderr, "fadedist should never be NaN\n"); +#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 diff --git a/src/shader/gaussian_shader.cpp b/src/shader/gaussian_shader.cpp index 450ce331a..03509de41 100644 --- a/src/shader/gaussian_shader.cpp +++ b/src/shader/gaussian_shader.cpp @@ -12,7 +12,9 @@ GaussianShader::GaussianShader() shaders[GAUSSIAN_SHADER].fragment ) { if (!valid) { +#if defined(DEBUG) fprintf(stderr, "invalid raster shader\n"); +#endif return; } diff --git a/src/shader/raster_shader.cpp b/src/shader/raster_shader.cpp index eaf45ea2b..f083d3e26 100644 --- a/src/shader/raster_shader.cpp +++ b/src/shader/raster_shader.cpp @@ -12,7 +12,9 @@ RasterShader::RasterShader() shaders[RASTER_SHADER].fragment ) { if (!valid) { +#if defined(DEBUG) fprintf(stderr, "invalid raster shader\n"); +#endif return; } diff --git a/src/shader/shader.cpp b/src/shader/shader.cpp index 97e494f65..70b59e7aa 100644 --- a/src/shader/shader.cpp +++ b/src/shader/shader.cpp @@ -1,7 +1,8 @@ #include #include +#if defined(DEBUG) #include - +#endif #include #include #include @@ -11,18 +12,23 @@ using namespace llmr; Shader::Shader(const GLchar *vertSource, const GLchar *fragSource) : valid(false), program(0) { +#if defined(DEBUG) util::timer timer("shader compilation"); - +#endif GLuint vertShader; if (!compileShader(&vertShader, GL_VERTEX_SHADER, vertSource)) { +#if defined(DEBUG) fprintf(stderr, "Vertex shader failed to compile: %s\n", vertSource); +#endif return; } GLuint fragShader; if (!compileShader(&fragShader, GL_FRAGMENT_SHADER, fragSource)) { +#if defined(DEBUG) fprintf(stderr, "Fragment shader failed to compile: %s\n", fragSource); +#endif return; } @@ -80,7 +86,9 @@ Shader::Shader(const GLchar *vertSource, const GLchar *fragSource) glGetProgramiv(program, GL_VALIDATE_STATUS, &status); if (status == 0) { +#if defined(DEBUG) fprintf(stderr, "Program failed to validate\n"); +#endif glDeleteShader(vertShader); vertShader = 0; glDeleteShader(fragShader); diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index bb24c5fec..a0070b288 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -54,7 +54,9 @@ void Sprite::complete(std::shared_ptr &sprite) { if (sprite->raster && sprite->pos.size()) { sprite->loaded = true; sprite->map.update(); +#if defined(DEBUG) fprintf(stderr, "sprite loaded\n"); +#endif } } diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 3f741236f..4a4517b70 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -52,7 +52,9 @@ GlyphPBF::GlyphPBF(const std::string &fontStack, GlyphRange glyphRange) // TODO: Find more reliable URL normalization function std::replace(url.begin(), url.end(), ' ', '+'); +#if defined(DEBUG) fprintf(stderr, "%s\n", url.c_str()); +#endif platform::request_http(url, [&](platform::Response *res) { if (res->code != 200) { diff --git a/src/util/constants.cpp b/src/util/constants.cpp index f67464926..c939bbde4 100644 --- a/src/util/constants.cpp +++ b/src/util/constants.cpp @@ -2,6 +2,7 @@ const float llmr::util::tileSize = 512.0f; +#if defined(DEBUG) const bool llmr::debug::tileParseWarnings = false; const bool llmr::debug::styleParseWarnings = false; const bool llmr::debug::spriteWarnings = false; @@ -12,3 +13,15 @@ const bool llmr::debug::missingFontStackWarning = true; const bool llmr::debug::missingFontFaceWarning = true; const bool llmr::debug::glyphWarning = true; const bool llmr::debug::shapingWarning = true; +#else +const bool llmr::debug::tileParseWarnings = false; +const bool llmr::debug::styleParseWarnings = false; +const bool llmr::debug::spriteWarnings = false; +const bool llmr::debug::renderWarnings = false; +const bool llmr::debug::renderTree = false; +const bool llmr::debug::labelTextMissingWarning = false; +const bool llmr::debug::missingFontStackWarning = false; +const bool llmr::debug::missingFontFaceWarning = false; +const bool llmr::debug::glyphWarning = true; +const bool llmr::debug::shapingWarning = true; +#endif \ No newline at end of file From 2be6fefdf80521d31bf79bddcc66acb3f5f5a1f2 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 29 May 2014 18:13:41 -0700 Subject: [PATCH 062/172] make shapingWarning and glyphWarning off for release builds --- src/util/constants.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/constants.cpp b/src/util/constants.cpp index c939bbde4..46852e5e7 100644 --- a/src/util/constants.cpp +++ b/src/util/constants.cpp @@ -22,6 +22,6 @@ const bool llmr::debug::renderTree = false; const bool llmr::debug::labelTextMissingWarning = false; const bool llmr::debug::missingFontStackWarning = false; const bool llmr::debug::missingFontFaceWarning = false; -const bool llmr::debug::glyphWarning = true; -const bool llmr::debug::shapingWarning = true; +const bool llmr::debug::glyphWarning = false; +const bool llmr::debug::shapingWarning = false; #endif \ No newline at end of file From 6e53a0328b5de4609f9bc187d6f076ee9f65ecaa Mon Sep 17 00:00:00 2001 From: Young Hahn Date: Thu, 29 May 2014 22:54:46 -0400 Subject: [PATCH 063/172] Remove VectorTileGlyph, VectorTileFace, IndexedFaces, Faces and glyph related parts of vector_tile.proto. Refs #274. --- include/llmr/geometry/glyph_atlas.hpp | 2 - include/llmr/map/tile_parser.hpp | 1 - include/llmr/map/vector_tile.hpp | 30 ------- include/llmr/text/glyph.hpp | 2 - proto/vector_tile.proto | 44 ---------- src/map/vector_tile.cpp | 119 -------------------------- 6 files changed, 198 deletions(-) diff --git a/include/llmr/geometry/glyph_atlas.hpp b/include/llmr/geometry/glyph_atlas.hpp index 5bcd573f5..0aada6a73 100644 --- a/include/llmr/geometry/glyph_atlas.hpp +++ b/include/llmr/geometry/glyph_atlas.hpp @@ -12,8 +12,6 @@ namespace llmr { -class VectorTileGlyph; - class GlyphAtlas { public: diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 5785c29b3..84bb65e12 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -42,7 +42,6 @@ private: GlyphAtlas& glyphAtlas; GlyphStore &glyphStore; SpriteAtlas &spriteAtlas; - Faces faces; Placement placement; }; diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp index f57c5d350..1e809556e 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -83,38 +83,9 @@ public: uint32_t extent = 4096; std::vector keys; std::vector values; - std::vector faces; std::map> shaping; }; -class VectorTileGlyph { -public: - VectorTileGlyph(); - VectorTileGlyph(pbf data); - - uint32_t id = 0; - - // A signed distance field of the glyph with a border of 3 pixels. - std::string bitmap; - - // Glyph metrics - GlyphMetrics metrics; -}; - -std::ostream& operator<<(std::ostream&, const VectorTileGlyph& glyph); - -class VectorTileFace { -public: - VectorTileFace(pbf data); - - std::string name; - std::string family; - std::string style; - std::vector glyphs; -}; - -std::ostream& operator<<(std::ostream&, const VectorTileFace& face); - class VectorTile { public: VectorTile(); @@ -122,7 +93,6 @@ public: VectorTile& operator=(VectorTile&& other); std::map layers; - std::map faces; }; diff --git a/include/llmr/text/glyph.hpp b/include/llmr/text/glyph.hpp index e6138e712..8f9024a90 100644 --- a/include/llmr/text/glyph.hpp +++ b/include/llmr/text/glyph.hpp @@ -43,8 +43,6 @@ struct Glyph { }; typedef std::map GlyphPositions; -typedef std::map Faces; -typedef std::vector IndexedFaces; class GlyphPlacement { public: diff --git a/proto/vector_tile.proto b/proto/vector_tile.proto index e982c1a01..ea482adb2 100644 --- a/proto/vector_tile.proto +++ b/proto/vector_tile.proto @@ -75,43 +75,6 @@ message feature { optional uint32 vertex_count = 6; } -// Stores a glyph with metrics and optional SDF bitmap information. -message glyph { - required uint32 id = 1; - - // A signed distance field of the glyph with a border of 3 pixels. - optional bytes bitmap = 2; - - // Glyph metrics. - required uint32 width = 3; - required uint32 height = 4; - required sint32 left = 5; - required sint32 top = 6; - required uint32 advance = 7; -} - -// Stores font face information and a list of glyphs. -message face { - required string family = 1; - required string style = 2; - repeated glyph glyphs = 5; -} - -// Stores the shaping information for the label with a given text -message label { - // The original value ID this shaping information is for. - required uint32 text = 1; - - // References the index of the font stack in the layer's fontstack array. - required uint32 stack = 2; - - // Parallel arrays of face ID, glyph ID and position. - repeated uint32 faces = 3 [packed = true]; - repeated uint32 glyphs = 4 [packed = true]; - repeated uint32 x = 5 [packed = true]; - repeated uint32 y = 6 [packed = true]; -} - message layer { // Any compliant implementation must first read the version // number encoded in this message and choose the correct @@ -136,18 +99,11 @@ message layer { // Total vertex count in this layer. optional uint32 vertex_count = 6; - // Shaping information for labels contained in this tile. - repeated string faces = 7; - repeated label labels = 8; - repeated string stacks = 9; - extensions 16 to max; } message tile { repeated layer layers = 3; - repeated face faces = 4; - extensions 16 to 8191; } diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index 248e94712..f0f5a85cd 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -70,9 +70,6 @@ VectorTile::VectorTile(pbf tile) { if (tile.tag == 3) { // layer VectorTileLayer layer(tile.message()); layers.emplace(layer.name, std::forward(layer)); - } else if (tile.tag == 4) { // face - VectorTileFace face(tile.message()); - faces.emplace(face.name, std::forward(face)); } else { tile.skip(); } @@ -86,100 +83,8 @@ VectorTile& VectorTile::operator=(VectorTile && other) { return *this; } -VectorTileFace::VectorTileFace(pbf face) { - while (face.next()) { - if (face.tag == 1) { // family - family = face.string(); - } else if (face.tag == 2) { // style - style = face.string(); - } else if (face.tag == 5) { // glyphs - glyphs.emplace_back(face.message()); - } else { - face.skip(); - } - } - name = family + " " + style; -} - - -std::ostream& llmr::operator<<(std::ostream& os, const VectorTileFace& face) { - os << "Face: " << face.name << std::endl; - for (const VectorTileGlyph& glyph : face.glyphs) { - os << " - " << glyph; - } - return os; -} - - -// -1 overflows to maximum value -VectorTileGlyph::VectorTileGlyph() {} - -VectorTileGlyph::VectorTileGlyph(pbf glyph) { - while (glyph.next()) { - if (glyph.tag == 1) { // id - id = glyph.varint(); - } else if (glyph.tag == 2) { // bitmap - bitmap = glyph.string(); - } else if (glyph.tag == 3) { // width - metrics.width = glyph.varint(); - } else if (glyph.tag == 4) { // height - metrics.height = glyph.varint(); - } else if (glyph.tag == 5) { // left - metrics.left = glyph.svarint(); - } else if (glyph.tag == 6) { // top - metrics.top = glyph.svarint(); - } else if (glyph.tag == 7) { // advance - metrics.advance = glyph.varint(); - } else { - glyph.skip(); - } - } -} - -std::ostream& llmr::operator<<(std::ostream& os, const VectorTileGlyph& glyph) { - os << "Glyph " << glyph.id << ": " << glyph.metrics.width << "x" << glyph.metrics.height << - " (" << glyph.metrics.left << "/" << glyph.metrics.top << ") +" << glyph.metrics.advance << std::endl; - return os; -} - -class VectorTileLabel { -public: - VectorTileLabel(pbf data); - - uint32_t text = 0; - uint32_t stack = 0; - std::vector placements; -}; - -VectorTileLabel::VectorTileLabel(pbf label) { - pbf faces, glyphs, x, y; - - while (label.next()) { - if (label.tag == 1) { // text - text = label.varint(); - } else if (label.tag == 2) { // stack - stack = label.varint(); - } else if (label.tag == 3) { // faces - faces = label.message(); - } else if (label.tag == 4) { // glyphs - glyphs = label.message(); - } else if (label.tag == 5) { // x - x = label.message(); - } else if (label.tag == 6) { // y - y = label.message(); - } else { - label.skip(); - } - } - - while (faces && glyphs && x && y) { - placements.emplace_back(faces.varint(), glyphs.varint(), x.varint(), y.varint()); - } -} - VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { std::vector stacks; - std::vector labels; while (layer.next()) { if (layer.tag == 1) { // name @@ -190,34 +95,10 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { values.emplace_back(std::move(parseValue(layer.message()))); } else if (layer.tag == 5) { // extent extent = layer.varint(); - } else if (layer.tag == 7) { // faces - faces.emplace_back(layer.string()); - } else if (layer.tag == 8) { // labels - labels.emplace_back(layer.message()); - } else if (layer.tag == 9) { // stacks - stacks.emplace_back(layer.string()); } else { layer.skip(); } } - - // Build index of [stack][text] => shaping information - for (VectorTileLabel& label : labels) { - if (values.size() <= label.text || stacks.size() <= label.stack) { - // The indices are out of range. Skip this label. - continue; - } - - const Value& text = values[label.text]; - const std::string& stack = stacks[label.stack]; - - shaping[stack][text].swap(label.placements); - } -} - -std::ostream& llmr::operator<<(std::ostream& os, const GlyphPlacement& placement) { - os << "Glyph " << placement.face << "/" << placement.glyph << ": " << placement.x << "/" << placement.y << std::endl; - return os; } FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const BucketDescription& bucket_desc) From 3442403e6707be66ff133bd4690eb380dcc65dce Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Fri, 30 May 2014 00:07:22 -0400 Subject: [PATCH 064/172] parse maxWidth, lineHeight and alignment, pass to FontStack::getShaping --- bin/style.js | 2 ++ include/llmr/style/bucket_description.hpp | 9 +++++++++ include/llmr/text/glyph_store.hpp | 9 ++++++++- include/llmr/text/placement.hpp | 2 -- src/map/tile_parser.cpp | 6 +++++- src/style/style_parser.cpp | 18 +++++++++++++++++ src/text/glyph_store.cpp | 14 ++++++++++++- src/text/placement.cpp | 24 ++++------------------- 8 files changed, 59 insertions(+), 25 deletions(-) diff --git a/bin/style.js b/bin/style.js index c831fd414..931bde011 100644 --- a/bin/style.js +++ b/bin/style.js @@ -765,6 +765,8 @@ module.exports = { "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, + "text-max-width": 2, + "text-line-height": 1.4, "feature_type": "point", "type": "text" }, diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 3cdc8ea4d..004932aa4 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -68,6 +68,12 @@ inline TextPathType textPathType(const std::string& path) { else return TextPathType::Horizontal; }; +inline float alignmentType(const std::string& alignment) { + if (alignment == "right") return 1.0f; + else if (alignment == "left") return 0.0f; + else return 0.5; +}; + class BucketGeometryDescription { public: CapType cap = CapType::None; @@ -79,6 +85,9 @@ public: float miter_limit = 2.0f; float round_limit = 1.0f; TextPathType path = TextPathType::Horizontal; + float alignment = 0.5; + float line_height = 1.2 * 24; + float max_width = 15.0f * 24; float padding = 2.0f; float textMinDistance = 250.0f; float rotate = 0.0f; // what is this? diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index eb5d6038f..74472194b 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -30,7 +30,14 @@ public: void insert(uint32_t id, const SDFGlyph &glyph); const std::map &getMetrics() const; const std::map &getSDFs() const; - const Shaping getShaping(const std::u32string &string) const; + const Shaping getShaping(const std::u32string &string, + const float &maxWidth, + const float &lineHeight, + const float &alignment) const; + Shaping lineWrap(Shaping shaped, + const float &lineHeight, + const float &maxWidth, + const float &alignment) const; private: std::map bitmaps; diff --git a/include/llmr/text/placement.hpp b/include/llmr/text/placement.hpp index 87c47345e..fb3ddaa66 100644 --- a/include/llmr/text/placement.hpp +++ b/include/llmr/text/placement.hpp @@ -20,8 +20,6 @@ public: const BucketGeometryDescription &info, const GlyphPositions &face, const Shaping &shaping); - float measureText(const GlyphPositions &face, - const Shaping &shaping); private: const int8_t zoom; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index ff5d61a5e..431300318 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -15,6 +15,8 @@ #include #include +#include + using namespace llmr; TileParser::TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, GlyphStore &glyphStore, SpriteAtlas &spriteAtlas) @@ -202,6 +204,8 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye std::map shaping; GlyphPositions face; + // std::cerr << bucket_desc; + // Shape and place all labels. { FilteredVectorTileLayer filtered_layer(layer, bucket_desc); @@ -221,7 +225,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye const std::u32string string = ucs4conv.convert(toString(it_prop->second)); // Shape labels. - const Shaping shaped = fontStack.getShaping(string); + const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, bucket_desc.geometry.line_height, bucket_desc.geometry.alignment); shaping.emplace(toString(it_prop->second), shaped); // Place labels. diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 6276d657d..ba189f76f 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -102,6 +102,24 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } else { throw Style::exception("curve must be a string"); } + } else if (name == "alignment") { + if (value.IsString()) { + bucket.geometry.alignment = alignmentType({ value.GetString(), value.GetStringLength() }); + } else { + throw Style::exception("alignment must be a string"); + } + } else if (name == "lineHeight") { + if (value.IsNumber()) { + bucket.geometry.line_height = value.GetDouble() * 24; + } else { + throw Style::exception("line height must be a number"); + } + } else if (name == "maxWidth") { + if (value.IsNumber()) { + bucket.geometry.max_width = value.GetDouble() * 24; + } else { + throw Style::exception("max width must be a number"); + } } else if (name == "miterLimit") { if (value.IsNumber()) { bucket.geometry.miter_limit = value.GetDouble(); diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 3f741236f..a148ac928 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace llmr { @@ -28,7 +29,7 @@ const std::map &FontStack::getSDFs() const { return sdfs; } -const Shaping FontStack::getShaping(const std::u32string &string) const { +const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, const float &lineHeight, const float &alignment) const { std::lock_guard lock(mtx); uint32_t i = 0; uint32_t x = 0; @@ -40,6 +41,17 @@ const Shaping FontStack::getShaping(const std::u32string &string) const { i++; x += metrics.find(chr)->second.advance; } + + shaped = lineWrap(shaped, lineHeight, maxWidth, alignment); + + return shaped; +} + +Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, const float &alignment) const { + std::cerr << "\nlineHeight: " << lineHeight << + "\nmaxWidth: " << maxWidth << + "\nalignment: " << alignment << + "\n"; return shaped; } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index f57436bcb..ed71f881e 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -137,15 +137,12 @@ void getSegmentGlyphs(std::back_insert_iterator glyphs, } void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes, - Anchor &anchor, float advance, const Shaping &shaping, + Anchor &anchor, vec2 origin, const Shaping &shaping, const GlyphPositions &face, float fontScale, bool horizontal, const std::vector &line, float maxAngleDelta, float rotate) { // The total text advance is the width of this label. - // TODO: figure out correct ascender height. - vec2 origin{-advance / 2, -17}; - // TODO: allow setting an alignment // var alignment = 'center'; // if (alignment == 'center') { @@ -261,10 +258,10 @@ void Placement::addFeature(TextBucket& bucket, const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.size); - const float advance = measureText(face, shaping); Anchors anchors; - // fprintf(stderr, "adding feature with advance %f\n", advance); + // TODO: figure out correct ascender height. + vec2 origin{0, -17}; if (line.size() == 1) { // Point labels @@ -285,7 +282,7 @@ void Placement::addFeature(TextBucket& bucket, PlacedGlyphs glyphs; GlyphBoxes boxes; - getGlyphs(glyphs, boxes, anchor, advance, shaping, face, fontScale, horizontal, + getGlyphs(glyphs, boxes, anchor, origin, shaping, face, fontScale, horizontal, line, maxAngleDelta, rotate); PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale, @@ -295,16 +292,3 @@ void Placement::addFeature(TextBucket& bucket, } } } - -float Placement::measureText(const GlyphPositions &face, - const Shaping &shaping) { - float advance = 0; - - // TODO: advance is not calculated correctly. we should instead use the - // bounding box of the glyph placement. - for (const GlyphPlacement &shape : shaping) { - advance += getGlyph(shape, face).metrics.advance; - } - - return advance; -} From 63729a500944a47c034713a531b7add337df6688 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 01:02:33 -0400 Subject: [PATCH 065/172] fix `make run-linux` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b10cdbb7b..5865996bc 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ linux: config.gypi linux/llmr-app.gyp node # Executes the Linux binary run-linux: linux - build/$(BUILDTYPE)/llmr + build/$(BUILDTYPE)/mapbox-gl From 9057c4980dc12515cd8d6f33d9253e61592272fe Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 01:32:15 -0400 Subject: [PATCH 066/172] line wrapping --- bin/style.js | 4 +-- include/llmr/text/glyph.hpp | 4 +-- src/text/glyph_store.cpp | 51 ++++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/bin/style.js b/bin/style.js index 931bde011..38ffd7c32 100644 --- a/bin/style.js +++ b/bin/style.js @@ -765,8 +765,8 @@ module.exports = { "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, - "text-max-width": 2, - "text-line-height": 1.4, + "maxWidth": 2, + "lineHeight": 1.4, "feature_type": "point", "type": "text" }, diff --git a/include/llmr/text/glyph.hpp b/include/llmr/text/glyph.hpp index e6138e712..c13088c41 100644 --- a/include/llmr/text/glyph.hpp +++ b/include/llmr/text/glyph.hpp @@ -53,8 +53,8 @@ public: uint32_t face = 0; uint32_t glyph = 0; - uint32_t x = 0; - uint32_t y = 0; + int32_t x = 0; + int32_t y = 0; }; typedef std::vector Shaping; diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index a148ac928..6293aee23 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -47,11 +47,54 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m return shaped; } +void alignHorizontally(Shaping &shaping, const std::map &metrics, + const uint32_t &start, const uint32_t &end, const float &alignment) { + + uint32_t lastAdvance = metrics.find(shaping[end].glyph)->second.advance; + int32_t lineIndent = (shaping[end].x + lastAdvance) * alignment; + + for (uint32_t j = start; j <= end; j++) { + shaping[j].x -= lineIndent; + } + } + Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, const float &alignment) const { - std::cerr << "\nlineHeight: " << lineHeight << - "\nmaxWidth: " << maxWidth << - "\nalignment: " << alignment << - "\n"; + uint32_t lastSafeBreak = 0; + uint32_t lengthBeforeCurrentLine = 0; + uint32_t lineStartIndex = 0; + uint32_t line = 0; + + for (uint32_t i = 0; i < shaped.size(); i++) { + GlyphPlacement &shape = shaped[i]; + + shape.x -= lengthBeforeCurrentLine; + shape.y += lineHeight * line; + + if (shape.x > maxWidth && lastSafeBreak != 0) { + + uint32_t lineLength = shaped[lastSafeBreak + 1].x; + + for (uint32_t k = lastSafeBreak + 1; k <= i; k++) { + shaped[k].y += lineHeight; + shaped[k].x -= lineLength; + } + + if (alignment) { + alignHorizontally(shaped, metrics, lineStartIndex, lastSafeBreak - 1, alignment); + } + + lineStartIndex = lastSafeBreak + 1; + lastSafeBreak = 0; + lengthBeforeCurrentLine += lineLength; + line++; + } + if (shape.glyph == 32) { + lastSafeBreak = i; + } + } + + alignHorizontally(shaped, metrics, lineStartIndex, shaped.size() - 1, alignment); + return shaped; } From 41c310c76238d3a2823c79592b553a6ff3205c47 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 03:11:57 -0400 Subject: [PATCH 067/172] add verticalAlign for text Default is center. Other options are "top" and "bottom" --- include/llmr/style/bucket_description.hpp | 7 ++++++ include/llmr/text/glyph_store.hpp | 6 +++-- src/map/tile_parser.cpp | 4 +++- src/style/style_parser.cpp | 6 +++++ src/text/glyph_store.cpp | 29 ++++++++++++++++------- src/text/placement.cpp | 2 +- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 004932aa4..b708ef686 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -74,6 +74,12 @@ inline float alignmentType(const std::string& alignment) { else return 0.5; }; +inline float verticalAlignmentType(const std::string& alignment) { + if (alignment == "bottom") return 1.0f; + else if (alignment == "top") return 0.0f; + else return 0.5; +}; + class BucketGeometryDescription { public: CapType cap = CapType::None; @@ -86,6 +92,7 @@ public: float round_limit = 1.0f; TextPathType path = TextPathType::Horizontal; float alignment = 0.5; + float vertical_alignment = 0.5; float line_height = 1.2 * 24; float max_width = 15.0f * 24; float padding = 2.0f; diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index 74472194b..f8b14683d 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -33,11 +33,13 @@ public: const Shaping getShaping(const std::u32string &string, const float &maxWidth, const float &lineHeight, - const float &alignment) const; + const float &alignment, + const float &verticalAlignment) const; Shaping lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, - const float &alignment) const; + const float &alignment, + const float &verticalAlignment) const; private: std::map bitmaps; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 431300318..f2b3ac05c 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -225,7 +225,9 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye const std::u32string string = ucs4conv.convert(toString(it_prop->second)); // Shape labels. - const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, bucket_desc.geometry.line_height, bucket_desc.geometry.alignment); + const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, + bucket_desc.geometry.line_height, bucket_desc.geometry.alignment, + bucket_desc.geometry.vertical_alignment); shaping.emplace(toString(it_prop->second), shaped); // Place labels. diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index ba189f76f..535e63916 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -108,6 +108,12 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } else { throw Style::exception("alignment must be a string"); } + } else if (name == "verticalAlignment") { + if (value.IsString()) { + bucket.geometry.vertical_alignment = verticalAlignmentType({ value.GetString(), value.GetStringLength() }); + } else { + throw Style::exception("alignment must be a string"); + } } else if (name == "lineHeight") { if (value.IsNumber()) { bucket.geometry.line_height = value.GetDouble() * 24; diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 6293aee23..ac647eb84 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -29,7 +29,8 @@ const std::map &FontStack::getSDFs() const { return sdfs; } -const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, const float &lineHeight, const float &alignment) const { +const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, + const float &lineHeight, const float &alignment, const float &verticalAlignment) const { std::lock_guard lock(mtx); uint32_t i = 0; uint32_t x = 0; @@ -42,23 +43,32 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m x += metrics.find(chr)->second.advance; } - shaped = lineWrap(shaped, lineHeight, maxWidth, alignment); + shaped = lineWrap(shaped, lineHeight, maxWidth, alignment, verticalAlignment); return shaped; } +void alignVertically(Shaping &shaping, const uint32_t &lines, const float &lineHeight, const float &verticalAlign) { + const float dy = -(lineHeight * (lines - 1) + 24) * verticalAlign - 5; + for (GlyphPlacement &shape : shaping) { + shape.y += dy; + } +} + void alignHorizontally(Shaping &shaping, const std::map &metrics, const uint32_t &start, const uint32_t &end, const float &alignment) { - uint32_t lastAdvance = metrics.find(shaping[end].glyph)->second.advance; - int32_t lineIndent = (shaping[end].x + lastAdvance) * alignment; + uint32_t lastAdvance = metrics.find(shaping[end].glyph)->second.advance; + int32_t lineIndent = (shaping[end].x + lastAdvance) * alignment; - for (uint32_t j = start; j <= end; j++) { - shaping[j].x -= lineIndent; - } - } + for (uint32_t j = start; j <= end; j++) { + shaping[j].x -= lineIndent; + } +} + +Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, + const float &alignment, const float &verticalAlignment) const { -Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, const float &alignment) const { uint32_t lastSafeBreak = 0; uint32_t lengthBeforeCurrentLine = 0; uint32_t lineStartIndex = 0; @@ -94,6 +104,7 @@ Shaping FontStack::lineWrap(Shaping shaped, const float &lineHeight, const float } alignHorizontally(shaped, metrics, lineStartIndex, shaped.size() - 1, alignment); + alignVertically(shaped, line + 1, lineHeight, verticalAlignment); return shaped; } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index ed71f881e..edefa6075 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -261,7 +261,7 @@ void Placement::addFeature(TextBucket& bucket, Anchors anchors; // TODO: figure out correct ascender height. - vec2 origin{0, -17}; + vec2 origin{0, 0}; if (line.size() == 1) { // Point labels From 2bf23a7d77cd3040826eee1a87e136e3d1badd84 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Fri, 30 May 2014 00:40:49 -0700 Subject: [PATCH 068/172] bump MVK for latest pinch enhancements --- ios/MVKMapKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/MVKMapKit b/ios/MVKMapKit index 9c3aa2d91..7c7bb2310 160000 --- a/ios/MVKMapKit +++ b/ios/MVKMapKit @@ -1 +1 @@ -Subproject commit 9c3aa2d919f2a76d5fef2500a3ee624b57a11383 +Subproject commit 7c7bb2310216a8d18108db40b09db08732df1f88 From 7c653895c6f6f7dc07241031277610efb439a243 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 03:50:25 -0400 Subject: [PATCH 069/172] translate as a text bucket property When used, text is translated before being checked for collisions. --- bin/style.js | 18 ++++++++++-------- include/llmr/style/bucket_description.hpp | 2 ++ src/style/style_parser.cpp | 9 ++++++++- src/text/placement.cpp | 5 +---- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/bin/style.js b/bin/style.js index 38ffd7c32..3d24d6e79 100644 --- a/bin/style.js +++ b/bin/style.js @@ -765,8 +765,7 @@ module.exports = { "path": "horizontal", "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 18, - "maxWidth": 2, - "lineHeight": 1.4, + "maxWidth": 6, "feature_type": "point", "type": "text" }, @@ -880,6 +879,9 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, + "maxWidth": 8, + "verticalAlignment": "top", + "translate": [0, -1], "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 11, "feature_type": "point", @@ -893,6 +895,9 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, + "maxWidth": 8, + "verticalAlignment": "top", + "translate": [0, -1], "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", @@ -906,6 +911,9 @@ module.exports = { "text_field": "name", "path": "horizontal", "padding": 2, + "maxWidth": 8, + "verticalAlignment": "top", + "translate": [0, -1], "font": "Open Sans Semibold, Arial Unicode MS Bold", "fontSize": 10, "feature_type": "point", @@ -2417,7 +2425,6 @@ module.exports = { "stroke": "land", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_label_3": { "color": "#444", @@ -2425,7 +2432,6 @@ module.exports = { "stroke": "land", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14], "opacity": [ "stops", {"z": 16.5, "val": 0}, @@ -2443,7 +2449,6 @@ module.exports = { "stroke": "land", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_aerodrome": { "opacity": ["stops", @@ -3169,7 +3174,6 @@ module.exports = { "stroke": "text2_stroke_night", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_label_3": { "color": "#fff", @@ -3177,7 +3181,6 @@ module.exports = { "stroke": "text2_stroke_night", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14], "opacity": [ "stops", {"z": 16.5, "val": 0}, @@ -3195,7 +3198,6 @@ module.exports = { "stroke": "text2_stroke_night", "strokeWidth": 0.3, "strokeBlur": 1, - "translate": [0, 14] }, "poi_aerodrome": { "opacity": ["stops", diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index b708ef686..e306b799f 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -6,6 +6,7 @@ #include #include "value.hpp" +#include "../util/vec.hpp" namespace llmr { @@ -95,6 +96,7 @@ public: float vertical_alignment = 0.5; float line_height = 1.2 * 24; float max_width = 15.0f * 24; + vec2 translate {0, 0}; float padding = 2.0f; float textMinDistance = 250.0f; float rotate = 0.0f; // what is this? diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 535e63916..1a1d8ee1e 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -108,11 +108,18 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } else { throw Style::exception("alignment must be a string"); } + } else if (name == "translate") { + if (value.IsArray()) { + bucket.geometry.translate.x = value[(rapidjson::SizeType)0].GetDouble() * 24; + bucket.geometry.translate.y = value[(rapidjson::SizeType)1].GetDouble() * -24; + } else { + throw Style::exception("translate must be a string"); + } } else if (name == "verticalAlignment") { if (value.IsString()) { bucket.geometry.vertical_alignment = verticalAlignmentType({ value.GetString(), value.GetStringLength() }); } else { - throw Style::exception("alignment must be a string"); + throw Style::exception("verticalAlignment must be a string"); } } else if (name == "lineHeight") { if (value.IsNumber()) { diff --git a/src/text/placement.cpp b/src/text/placement.cpp index edefa6075..b15e32496 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -260,9 +260,6 @@ void Placement::addFeature(TextBucket& bucket, Anchors anchors; - // TODO: figure out correct ascender height. - vec2 origin{0, 0}; - if (line.size() == 1) { // Point labels anchors = Anchors{{Anchor{ @@ -282,7 +279,7 @@ void Placement::addFeature(TextBucket& bucket, PlacedGlyphs glyphs; GlyphBoxes boxes; - getGlyphs(glyphs, boxes, anchor, origin, shaping, face, fontScale, horizontal, + getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal, line, maxAngleDelta, rotate); PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale, From cc9521c5e27b7c972fa30450f3cacf0de42c2acb Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Fri, 30 May 2014 00:57:50 -0700 Subject: [PATCH 070/172] update iOS bundle ID --- ios/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Info.plist b/ios/Info.plist index d78b5428e..9c96d492a 100644 --- a/ios/Info.plist +++ b/ios/Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.mapbox.llmr.native + com.mapbox.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName From 9ac55e0d74df48344888b41e4f3e3f3a41d08ebf Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 May 2014 04:02:23 -0400 Subject: [PATCH 071/172] add text letterSpacing --- include/llmr/style/bucket_description.hpp | 1 + include/llmr/text/glyph_store.hpp | 3 ++- src/map/tile_parser.cpp | 2 +- src/style/style_parser.cpp | 6 ++++++ src/text/glyph_store.cpp | 6 ++++-- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index e306b799f..3b6fc4313 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -96,6 +96,7 @@ public: float vertical_alignment = 0.5; float line_height = 1.2 * 24; float max_width = 15.0f * 24; + float letter_spacing = 0; vec2 translate {0, 0}; float padding = 2.0f; float textMinDistance = 250.0f; diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index f8b14683d..49427a276 100644 --- a/include/llmr/text/glyph_store.hpp +++ b/include/llmr/text/glyph_store.hpp @@ -34,7 +34,8 @@ public: const float &maxWidth, const float &lineHeight, const float &alignment, - const float &verticalAlignment) const; + const float &verticalAlignment, + const float &letterSpacing) const; Shaping lineWrap(Shaping shaped, const float &lineHeight, const float &maxWidth, diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index f2b3ac05c..2d47542d9 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -227,7 +227,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye // Shape labels. const Shaping shaped = fontStack.getShaping(string, bucket_desc.geometry.max_width, bucket_desc.geometry.line_height, bucket_desc.geometry.alignment, - bucket_desc.geometry.vertical_alignment); + bucket_desc.geometry.vertical_alignment, bucket_desc.geometry.letter_spacing); shaping.emplace(toString(it_prop->second), shaped); // Place labels. diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 1a1d8ee1e..61f3c444c 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -133,6 +133,12 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } else { throw Style::exception("max width must be a number"); } + } else if (name == "letterSpacing") { + if (value.IsNumber()) { + bucket.geometry.letter_spacing = value.GetDouble() * 24; + } else { + throw Style::exception("letter spacing must be a number"); + } } else if (name == "miterLimit") { if (value.IsNumber()) { bucket.geometry.miter_limit = value.GetDouble(); diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index ac647eb84..4d7ff57ec 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -30,7 +30,9 @@ const std::map &FontStack::getSDFs() const { } const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth, - const float &lineHeight, const float &alignment, const float &verticalAlignment) const { + const float &lineHeight, const float &alignment, const float &verticalAlignment, + const float &letterSpacing) const { + std::lock_guard lock(mtx); uint32_t i = 0; uint32_t x = 0; @@ -40,7 +42,7 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float &m GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); shaped.push_back(glyph); i++; - x += metrics.find(chr)->second.advance; + x += metrics.find(chr)->second.advance + letterSpacing; } shaped = lineWrap(shaped, lineHeight, maxWidth, alignment, verticalAlignment); From ec973af82e467d7816bae5daf83359dbe85233dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 13:02:40 +0200 Subject: [PATCH 072/172] skip characters that don't have metrics --- src/text/glyph_store.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 4a4517b70..cbcf012dd 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -38,7 +38,11 @@ const Shaping FontStack::getShaping(const std::u32string &string) const { GlyphPlacement glyph = GlyphPlacement(0, chr, x, 0); shaped.push_back(glyph); i++; - x += metrics.find(chr)->second.advance; + + auto metrics_it = metrics.find(chr); + if (metrics_it != metrics.end()) { + x += metrics_it->second.advance; + } } return shaped; } From 942da9cecc4b97eea68a1ad98f5d119a67be45bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 13:23:48 +0200 Subject: [PATCH 073/172] don't convert twice --- src/map/tile_parser.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index ff5d61a5e..f23a5e673 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -218,11 +218,12 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye continue; } - const std::u32string string = ucs4conv.convert(toString(it_prop->second)); + const std::string source_string = toString(it_prop->second); + const std::u32string string = ucs4conv.convert(source_string); // Shape labels. const Shaping shaped = fontStack.getShaping(string); - shaping.emplace(toString(it_prop->second), shaped); + shaping.emplace(source_string, shaped); // Place labels. addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, string, fontStack, glyphAtlas, face); From 461a19dfa22b5301080d891baac5cad6e554adad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 13:36:53 +0200 Subject: [PATCH 074/172] fallback to default properties instead of not rendering when we don't have a style refs #272 --- include/llmr/style/properties.hpp | 12 ++++++++++++ src/map/map.cpp | 6 +++++- src/renderer/painter_fill.cpp | 5 +++-- src/renderer/painter_icon.cpp | 5 +++-- src/renderer/painter_line.cpp | 5 +++-- src/renderer/painter_raster.cpp | 5 +++-- src/renderer/painter_text.cpp | 5 +++-- 7 files changed, 32 insertions(+), 11 deletions(-) diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index b8ffcfad6..d0bc3b2d4 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -128,6 +128,7 @@ struct IconClass : public GenericClass { }; struct IconProperties : public GenericProperties { + inline IconProperties() : GenericProperties() {} float size = 0; Color color = {{ 1, 1, 1, 1 }}; std::string image; @@ -147,6 +148,7 @@ struct LineClass : public GenericClass { }; struct LineProperties : public GenericProperties { + inline LineProperties() : GenericProperties() {} float width = 0; float offset = 0; Color color = {{ 0, 0, 0, 1 }}; @@ -164,6 +166,7 @@ struct FillClass : public GenericClass { }; struct FillProperties : public GenericProperties { + inline FillProperties() : GenericProperties() {} Winding winding = Winding::NonZero; bool antialias = true; Color fill_color = {{ 0, 0, 0, 1 }}; @@ -187,6 +190,7 @@ struct TextClass : public GenericClass { }; struct TextProperties : public GenericProperties { + inline TextProperties() : GenericProperties() {} Color color = {{ 0, 0, 0, 1 }}; Color halo = {{ 1, 1, 1, 0.75 }}; float halo_radius = 0.25f; @@ -202,6 +206,7 @@ struct BackgroundClass : public GenericClass { }; struct BackgroundProperties : public GenericProperties { + inline BackgroundProperties() : GenericProperties() {} Color color = {{ 1, 1, 1, 1 }}; }; @@ -209,6 +214,7 @@ struct RasterClass : public GenericClass { }; struct RasterProperties : public GenericProperties { + inline RasterProperties() : GenericProperties() {} }; struct CompositeClass : public GenericClass { @@ -219,6 +225,12 @@ struct CompositeProperties : public GenericProperties { }; +const IconProperties defaultIconProperties; +const LineProperties defaultLineProperties; +const FillProperties defaultFillProperties; +const TextProperties defaultTextProperties; +const BackgroundProperties defaultBackgroundProperties; +const RasterProperties defaultRasterProperties; const CompositeProperties defaultCompositeProperties; } diff --git a/src/map/map.cpp b/src/map/map.cpp index 60a7aa78d..71ce0e938 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -591,7 +591,11 @@ typename Styles::const_iterator find_style(const Styles &styles, const LayerDesc template bool is_invisible(const Styles &styles, const LayerDescription &layer_desc) { auto it = find_style(styles, layer_desc); - if (it == styles.end()) { return true; } + if (it == styles.end()) { + // We don't have a style, so we fall back to the default style which is + // always visible. + return false; + } return !it->second.isVisible(); } diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index cd7b0780d..d0ba2a8de 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -146,9 +146,10 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons const std::unordered_map &fill_properties = map.getStyle().computed.fills; const std::unordered_map::const_iterator fill_properties_it = fill_properties.find(layer_name); - if (fill_properties_it == fill_properties.end()) return; - const FillProperties& properties = fill_properties_it->second; + const FillProperties &properties = fill_properties_it != fill_properties.end() + ? fill_properties_it->second + : defaultFillProperties; if (!properties.enabled) return; diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 382312c12..51bb88fb2 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -13,9 +13,10 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons const std::unordered_map &icon_properties = map.getStyle().computed.icons; const std::unordered_map::const_iterator icon_properties_it = icon_properties.find(layer_name); - if (icon_properties_it == icon_properties.end()) return; - const IconProperties& properties = icon_properties_it->second; + const IconProperties &properties = icon_properties_it != icon_properties.end() + ? icon_properties_it->second + : defaultIconProperties; if (!properties.enabled) return; Color color = properties.color; diff --git a/src/renderer/painter_line.cpp b/src/renderer/painter_line.cpp index 2788a8bb1..71692c74c 100644 --- a/src/renderer/painter_line.cpp +++ b/src/renderer/painter_line.cpp @@ -11,9 +11,10 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons const std::unordered_map &line_properties = map.getStyle().computed.lines; const std::unordered_map::const_iterator line_properties_it = line_properties.find(layer_name); - if (line_properties_it == line_properties.end()) return; - const LineProperties& properties = line_properties_it->second; + const LineProperties &properties = line_properties_it != line_properties.end() + ? line_properties_it->second + : defaultLineProperties; if (!properties.enabled) return; float width = properties.width; diff --git a/src/renderer/painter_raster.cpp b/src/renderer/painter_raster.cpp index de0d35261..f1943bb49 100644 --- a/src/renderer/painter_raster.cpp +++ b/src/renderer/painter_raster.cpp @@ -9,9 +9,10 @@ void Painter::renderRaster(RasterBucket& bucket, const std::string& layer_name, const std::unordered_map &raster_properties = map.getStyle().computed.rasters; const std::unordered_map::const_iterator raster_properties_it = raster_properties.find(layer_name); - if (raster_properties_it == raster_properties.end()) return; - const RasterProperties& properties = raster_properties_it->second; + const RasterProperties &properties = raster_properties_it != raster_properties.end() + ? raster_properties_it->second + : defaultRasterProperties; if (!properties.enabled) return; depthMask(false); diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index bd1709a96..148fe7d53 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -12,9 +12,10 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons const std::unordered_map &text_properties = map.getStyle().computed.texts; const std::unordered_map::const_iterator text_properties_it = text_properties.find(layer_name); - if (text_properties_it == text_properties.end()) return; - const TextProperties& properties = text_properties_it->second; + const TextProperties &properties = text_properties_it != text_properties.end() + ? text_properties_it->second + : defaultTextProperties; if (!properties.enabled) return; mat4 exMatrix; From 31d9dbefeaad90eaece85c013d355c624018db7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 14:01:53 +0200 Subject: [PATCH 075/172] pass shaping directly instead of looking it up --- include/llmr/renderer/text_bucket.hpp | 4 ++-- src/map/tile_parser.cpp | 10 +++------- src/renderer/text_bucket.cpp | 28 +++------------------------ 3 files changed, 8 insertions(+), 34 deletions(-) diff --git a/include/llmr/renderer/text_bucket.hpp b/include/llmr/renderer/text_bucket.hpp index ad282bdd0..36c50ae7f 100644 --- a/include/llmr/renderer/text_bucket.hpp +++ b/include/llmr/renderer/text_bucket.hpp @@ -36,9 +36,9 @@ public: void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, PlacementRange placementRange, float zoom); - void addFeature(const VectorTileFeature &feature, + void addFeature(const pbf &geometry, const GlyphPositions &face, - const std::map &shapings); + const Shaping &shaping); void drawGlyphs(TextShader &shader); diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index f23a5e673..e0e28e345 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -199,7 +199,6 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye // Create a copy! const FontStack &fontStack = glyphStore.getFontStack(bucket_desc.geometry.font); - std::map shaping; GlyphPositions face; // Shape and place all labels. @@ -222,18 +221,15 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye const std::u32string string = ucs4conv.convert(source_string); // Shape labels. - const Shaping shaped = fontStack.getShaping(string); - shaping.emplace(source_string, shaped); + const Shaping shaping = fontStack.getShaping(string); // Place labels. addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, string, fontStack, glyphAtlas, face); + + bucket->addFeature(feature.geometry, face, shaping); } } - // It looks like nearly the same interface through the rest - // of the stack. - addBucketFeatures(bucket, layer, bucket_desc, face, shaping); - return std::move(bucket); } diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index 5823607ac..da6de3817 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -99,37 +99,15 @@ void TextBucket::addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, } }; -void TextBucket::addFeature(const VectorTileFeature &feature, +void TextBucket::addFeature(const pbf &geom_pbf, const GlyphPositions &face, - const std::map &shapings) { - auto it_prop = feature.properties.find(geom_desc.field); - if (it_prop == feature.properties.end()) { - // feature does not have the correct property - if (debug::labelTextMissingWarning) { - fprintf(stderr, "[WARNING] feature doesn't have property '%s' required for labelling\n", geom_desc.field.c_str()); - } - return; - } - const Value &value = it_prop->second; - - auto it_shaping = shapings.find(toString(value)); - if (it_shaping == shapings.end()) { - if (debug::shapingWarning) { - fprintf(stderr, "[WARNING] missing shaping for '%s'\n", toString(value).c_str()); - } - // we lack shaping information for this label - return; - } - const Shaping &shaping = it_shaping->second; - - // std::cerr << "we have shaping for " << value << std::endl; - + const Shaping &shaping) { // Decode all lines. std::vector line; Geometry::command cmd; Coordinate coord; - pbf geom = feature.geometry; + pbf geom(geom_pbf); Geometry geometry(geom); int32_t x, y; while ((cmd = geometry.next(x, y)) != Geometry::end) { From 3a8b88dbbde2b1361b19dc5e4cc1c3edb592eea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 14:26:26 +0200 Subject: [PATCH 076/172] fix nearest neighbor image scaling refs #226 --- src/geometry/sprite_atlas.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 47f7832bc..1a077506a 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -35,15 +35,22 @@ bool SpriteAtlas::resize(const float newRatio) { data = nullptr; allocate(); - dimension w = static_cast(width * newRatio); - dimension h = static_cast(height * newRatio); - float s = std::pow(oldRatio / newRatio, 2); + const int old_w = width * oldRatio; + const int old_h = height * oldRatio; + const int new_w = width * newRatio; + const int new_h = height * newRatio; // Basic image scaling. TODO: Replace this with better image scaling. uint32_t *img_new = reinterpret_cast(data); - uint32_t *img_old = reinterpret_cast(old_data); - for (size_t i = 0, length = w * h; i < length; i++) { - img_new[i] = img_old[static_cast(s * i)]; + const uint32_t *img_old = reinterpret_cast(old_data); + + for (int y = 0; y < new_h; y++) { + const int old_yoffset = ((y * old_h) / new_h) * old_w; + const int new_yoffset = y * new_w; + for (int x = 0; x < new_w; x++) { + const int old_x = (x * old_w) / new_w; + img_new[new_yoffset + x] = img_old[old_yoffset + old_x]; + } } free(old_data); From 3e7f801de11ef6a73578f58cbd89b61a6448924b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 14:28:42 +0200 Subject: [PATCH 077/172] mark all sprites as uninitialized on pixelRatio changes fixes #226 --- src/geometry/sprite_atlas.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 1a077506a..bb514502b 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -55,6 +55,11 @@ bool SpriteAtlas::resize(const float newRatio) { free(old_data); dirty = true; + + // Mark all sprite images as in need of update + for (const auto &pair : images) { + uninitialized.emplace(pair.first); + } } return dirty; From 78fda8bb62a85fe0a536d2f38832a6123739e4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 30 May 2014 17:00:47 +0200 Subject: [PATCH 078/172] make sure we retain shared state when destructing the map object refs #261 --- include/llmr/map/map.hpp | 21 +++--- include/llmr/map/tile_data.hpp | 2 + include/llmr/map/tile_parser.hpp | 22 ++++-- include/llmr/map/vector_tile_data.hpp | 4 + include/llmr/renderer/raster_bucket.hpp | 2 +- include/llmr/util/raster.hpp | 4 +- src/map/map.cpp | 59 ++++++++------- src/map/tile_data.cpp | 15 +++- src/map/tile_parser.cpp | 97 +++++++++++++++---------- src/map/vector_tile_data.cpp | 15 +++- src/renderer/painter_clipping.cpp | 12 +-- src/renderer/painter_fill.cpp | 6 +- src/renderer/painter_icon.cpp | 4 +- src/renderer/painter_line.cpp | 2 +- src/renderer/painter_raster.cpp | 2 +- src/renderer/painter_text.cpp | 9 ++- src/renderer/raster_bucket.cpp | 2 +- src/util/raster.cpp | 6 +- 18 files changed, 174 insertions(+), 110 deletions(-) diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 49050540c..5f46c0e7e 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -97,13 +97,13 @@ public: public: inline const TransformState &getState() const { return state; } - inline const Style &getStyle() const { return style; } - inline GlyphAtlas &getGlyphAtlas() { return glyphAtlas; } - inline GlyphStore &getGlyphStore() { return glyphStore; } - inline SpriteAtlas &getSpriteAtlas() { return spriteAtlas; } + inline std::shared_ptr getStyle() const { return style; } + inline std::shared_ptr getGlyphAtlas() { return glyphAtlas; } + inline std::shared_ptr getGlyphStore() { return glyphStore; } + inline std::shared_ptr getSpriteAtlas() { return spriteAtlas; } + inline std::shared_ptr getTexturepool() { return texturepool; } inline uv_loop_t *getLoop() { return loop; } inline time getAnimationTime() const { return animationTime; } - inline Texturepool &getTexturepool() { return texturepool; } inline const Sources &getSources() { return sources; } private: @@ -151,11 +151,12 @@ private: Transform transform; TransformState state; - Texturepool texturepool; - Style style; - GlyphAtlas glyphAtlas; - GlyphStore glyphStore; - SpriteAtlas spriteAtlas; + std::shared_ptr