diff --git a/.travis.yml b/.travis.yml index 9dde1b9bb..5d46212f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,11 @@ compiler: - gcc - clang +env: + matrix: + - BUILDTYPE=Release + - BUILDTYPE=Debug + cache: - apt - directories: @@ -18,14 +23,20 @@ before_install: install: - ./setup-libraries.sh +- rm -rf mapnik-packaging/out/packages + before_script: -- if [ ${CXX} = "g++" ]; then export CXX="g++-4.8" ; fi +- if [[ ${CXX} == "g++" ]]; then export CXX="g++-4.8" ; fi script: -- make llmr -- make linux -- make run-tests +- make llmr BUILDTYPE=${BUILDTYPE} +- make clean +- make linux BUILDTYPE=${BUILDTYPE} +- make clean +- make run-tests BUILDTYPE=${BUILDTYPE} +# TODO - port to linux +#- make run-headless-test BUILDTYPE=${BUILDTYPE} notifications: - hipchat: WB52YkcbCGMbNcStsGeaoRO7cyBSK4wX2ZHo2Y4b@GL diff --git a/Makefile b/Makefile index f1baf3e40..b10cdbb7b 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ all: llmr # Builds the regular library llmr: config.gypi llmr.gyp node deps/run_gyp llmr.gyp --depth=. -Goutput_dir=.. --generator-output=./build/llmr -f make - make -C build/llmr V=$(V) llmr-x86 + $(MAKE) -C build/llmr BUILDTYPE=$(BUILDTYPE) V=$(V) llmr-x86 node: @if [ ! `which node` ]; then echo 'error: depends on node.js. please make sure node is on your PATH'; exit 1; fi; @@ -20,7 +20,7 @@ build/test/Makefile: src common config.gypi test/test.gyp deps/run_gyp test/test.gyp --depth=. -Goutput_dir=.. --generator-output=./build/test -f make test: build/test/Makefile - make -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) test + $(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) test # Runs all test cases run-tests: test @@ -29,13 +29,13 @@ run-tests: test done test/%: - make -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) $* + $(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) $* build/$(BUILDTYPE)/test_$* # Only runs headless test case run-headless-test: build/test/Makefile - make -C build/test BUILDTYPE=Debug V=$(V) headless - build/Debug/test_headless + $(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) headless + build/$(BUILDTYPE)/test_headless ##### Makefile builds ########################################################## @@ -44,7 +44,7 @@ run-headless-test: build/test/Makefile # Builds the linux app with make. This is also used by Travis CI linux: config.gypi linux/llmr-app.gyp node deps/run_gyp linux/llmr-app.gyp --depth=. -Goutput_dir=.. --generator-output=./build/linux -f make - make -C build/linux V=$(V) linuxapp + $(MAKE) -C build/linux BUILDTYPE=$(BUILDTYPE) V=$(V) linuxapp # Executes the Linux binary run-linux: linux @@ -55,7 +55,7 @@ run-linux: linux # Builds the OS X app with make. osx: config.gypi macosx/llmr-app.gyp node deps/run_gyp macosx/llmr-app.gyp --depth=. -Goutput_dir=.. --generator-output=./build/macosx -f make - make -C build/macosx V=$(V) osxapp + $(MAKE) -C build/macosx BUILDTYPE=$(BUILDTYPE) V=$(V) osxapp # Executes the OS X binary run-osx: osx diff --git a/bin/style.js b/bin/style.js index 1a6aca8b7..90f9e3bdd 100644 --- a/bin/style.js +++ b/bin/style.js @@ -716,14 +716,6 @@ module.exports = { "type": "text", "enabled": 4 }, - "place_label_city_point": { - "source": "outdoors", - "layer": "place_label", - "field": "type", - "value": "city", - "type": "point", - "size": 4 - }, "place_label_city": { "source": "outdoors", "layer": "place_label", @@ -731,7 +723,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 +735,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 +747,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,19 +763,49 @@ module.exports = { ], "text_field": "name", "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", - "fontSize": 14, + "font": "Open Sans Semibold, Arial Unicode MS Regular", + "fontSize": 18, "feature_type": "point", "type": "text" }, - "road_label": { + "road_label_1": { "source": "outdoors", "layer": "road_label", + "field": "class", + "value": ["motorway","main"], "text_field": "name", "path": "curve", "padding": 2, "font": "Open Sans Regular, Arial Unicode MS Regular", - "fontSize": 13, + "fontSize": 18, + "feature_type": "line", + "type": "text", + "maxAngleDelta": 0.5 + }, + "road_label_2": { + "source": "outdoors", + "layer": "road_label", + "field": "class", + "value": ["street","street_limited"], + "text_field": "name", + "path": "curve", + "padding": 2, + "font": "Open Sans Regular, Arial Unicode MS Regular", + "fontSize": 16, + "feature_type": "line", + "type": "text", + "maxAngleDelta": 0.5 + }, + "road_label_3": { + "source": "outdoors", + "layer": "road_label", + "field": "class", + "value": ["service","driveway","path"], + "text_field": "name", + "path": "curve", + "padding": 2, + "font": "Open Sans Regular, Arial Unicode MS Regular", + "fontSize": 14, "feature_type": "line", "type": "text", "maxAngleDelta": 0.5 @@ -814,7 +836,25 @@ module.exports = { "layer": "poi_label", "icon": "maki", "field": "scalerank", - "value": [1, 2, 3], + "value": [1, 2], + "size": 12, + "type": "point" + }, + "poi_3": { + "source": "outdoors", + "layer": "poi_label", + "icon": "maki", + "field": "scalerank", + "value": 3, + "size": 12, + "type": "point" + }, + "poi_4": { + "source": "outdoors", + "layer": "poi_label", + "icon": "maki", + "field": "scalerank", + "value": 4, "size": 12, "type": "point" }, @@ -827,7 +867,7 @@ module.exports = { "size": 24, "type": "point" }, - "poi_label": { + "poi_label_1-2": { "source": "outdoors", "layer": "poi_label", "field": "scalerank", @@ -839,10 +879,35 @@ module.exports = { "path": "horizontal", "padding": 2, "font": "Open Sans Regular, Arial Unicode MS Regular", - "fontSize": 12, + "fontSize": 11, "feature_type": "point", - "type": "text", - "alwaysVisible": true + "type": "text" + }, + "poi_label_3": { + "source": "outdoors", + "layer": "poi_label", + "field": "scalerank", + "value": 3, + "text_field": "name", + "path": "horizontal", + "padding": 2, + "font": "Open Sans Regular, Arial Unicode MS Regular", + "fontSize": 10, + "feature_type": "point", + "type": "text" + }, + "poi_label_4": { + "source": "outdoors", + "layer": "poi_label", + "field": "scalerank", + "value": 4, + "text_field": "name", + "path": "horizontal", + "padding": 2, + "font": "Open Sans Regular, Arial Unicode MS Regular", + "fontSize": 10, + "feature_type": "point", + "type": "text" } }, "structure": [ @@ -938,6 +1003,30 @@ 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" + }, + { + "name": "building", + "bucket": "building" + }, + { + "name": "building_wall", + "bucket": "building" + }, { "name": "hillshade_full_highlight", "bucket": "hillshade_full_highlight" @@ -954,18 +1043,6 @@ 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" @@ -1006,18 +1083,6 @@ module.exports = { "name": "aeroway_taxiway", "bucket": "aeroway_taxiway" }, - { - "name": "building_shadow", - "bucket": "building" - }, - { - "name": "building", - "bucket": "building" - }, - { - "name": "building_wall", - "bucket": "building" - }, { "name": "tunnel_motorway_link_casing", "bucket": "tunnel_motorway_link" @@ -1294,10 +1359,6 @@ module.exports = { "name": "state_label", "bucket": "state_label" }, - { - "name": "place_label_city_point", - "bucket": "place_label_city_point" - }, { "name": "place_label_city", "bucket": "place_label_city" @@ -1315,12 +1376,16 @@ module.exports = { "bucket": "place_label_other" }, { - "name": "poi_label", - "bucket": "poi_label" + "name": "road_label_1", + "bucket": "road_label_1" }, { - "name": "road_label", - "bucket": "road_label" + "name": "road_label_2", + "bucket": "road_label_2" + }, + { + "name": "road_label_3", + "bucket": "road_label_3" }, { "name": "contour_label", @@ -1338,6 +1403,26 @@ module.exports = { "name": "poi", "bucket": "poi" }, + { + "name": "poi_label_1-2", + "bucket": "poi_label_1-2" + }, + { + "name": "poi_3", + "bucket": "poi_3" + }, + { + "name": "poi_label_3", + "bucket": "poi_label_3" + }, + { + "name": "poi_4", + "bucket": "poi_4" + }, + { + "name": "poi_label_4", + "bucket": "poi_label_4" + }, { "name": "poi_aerodrome", "bucket": "poi_aerodrome" @@ -1571,12 +1656,27 @@ module.exports = { {"z": 8, "val": 1}, {"z": 12, "val": 2} ], - "road_label_size": [ + "road_label_1_size": [ "stops", - {"z": 0, "val": 12}, + {"z": 13, "val": 11}, {"z": 14, "val": 12}, {"z": 15, "val": 13}, - {"z": 22, "val": 13} + {"z": 16, "val": 14}, + {"z": 17, "val": 16}, + {"z": 18, "val": 18} + ], + "road_label_2_size": [ + "stops", + {"z": 13, "val": 11}, + {"z": 14, "val": 12}, + {"z": 16, "val": 14}, + {"z": 18, "val": 16} + ], + "road_label_3_size": [ + "stops", + {"z": 15, "val": 10}, + {"z": 16, "val": 12}, + {"z": 18, "val": 14} ], "fence_width": [ "stops", @@ -1599,6 +1699,11 @@ module.exports = { {"z": 19, "val": 12}, {"z": 20, "val": 24}, {"z": 21, "val": 48} + ], + "country_label_size": [ + "stops", + {"z": 1, "val": 14}, + {"z": 12, "val": 24} ] }, "classes": [ @@ -1753,7 +1858,7 @@ module.exports = { "color": "#103", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", @@ -1766,7 +1871,7 @@ module.exports = { "color": "#206", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", @@ -1779,7 +1884,7 @@ module.exports = { "color": "#fffff3", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", @@ -1792,7 +1897,7 @@ module.exports = { "color": "#ffd", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", @@ -2146,11 +2251,8 @@ module.exports = { "country_label": { "color": "country_text", "stroke": "rgba(255,255,255,0.5)", - "size": [ - "stops", - {"z": 6, "val": 14}, - {"z": 12, "val": 24} - ] + "strokeWidth": 0.4, + "size": "country_label_size" }, "country_label_line": { "color": "country_text", @@ -2164,7 +2266,6 @@ module.exports = { "marine_label_point_1": { "color": "#a9c4c7", "size": ["stops", - {"z": 0, "val": 20}, {"z": 3, "val": 20}, {"z": 4, "val": 25}, {"z": 5, "val": 30}, @@ -2175,7 +2276,6 @@ module.exports = { "marine_label_point_2": { "color": "#a9c4c7", "size": ["stops", - {"z": 0, "val": 13}, {"z": 3, "val": 13}, {"z": 4, "val": 14}, {"z": 5, "val": 20}, @@ -2187,7 +2287,6 @@ module.exports = { "marine_label_point_other": { "color": "#a9c4c7", "size": ["stops", - {"z": 0, "val": 12}, {"z": 3, "val": 12}, {"z": 4, "val": 13}, {"z": 5, "val": 15}, @@ -2209,9 +2308,6 @@ module.exports = { {"z": 10, "val": 0} ] }, - "place_label_city_point": { - "color": "#4a4032" - }, "place_label_city": { "color": "#444", "strokeWidth": 0.4, @@ -2223,20 +2319,12 @@ module.exports = { {"z": 7, "val": 14}, {"z": 14.99, "val": 20}, {"z": 15, "val": 0} - ], - "translate": [ - 0, - [ - "stops", - {"z": 4, "val": 10}, - {"z": 6, "val": 30}, - {"z": 7, "val": 0} - ] ] }, "place_label_town": { "color": "#716656", - "strokeWidth": 0.5, + "strokeWidth": 0.3, + "strokeBlur": 2, "stroke": "text_stroke", "size": [ "stops", @@ -2248,7 +2336,8 @@ module.exports = { }, "place_label_village": { "color": "#635644", - "strokeWidth": 0.5, + "strokeWidth": 0.3, + "strokeBlur": 2, "stroke": "text_stroke", "size": [ "stops", @@ -2264,18 +2353,32 @@ module.exports = { "stroke": "text_stroke", "size": [ "stops", - {"z": 0, "val": 10}, - {"z": 14, "val": 11}, - {"z": 15, "val": 12}, - {"z": 16, "val": 14} + {"z": 13, "val": 11}, + {"z": 14, "val": 12}, + {"z": 16, "val": 14}, + {"z": 18, "val": 18} ] }, - "road_label": { + "road_label_1": { "color": "#585042", "stroke": "land", "strokeWidth": 0.6, "strokeBlur": 2, - "size": "road_label_size" + "size": "road_label_1_size" + }, + "road_label_2": { + "color": "#585042", + "stroke": "land", + "strokeWidth": 0.6, + "strokeBlur": 2, + "size": "road_label_2_size" + }, + "road_label_3": { + "color": "#585042", + "stroke": "land", + "strokeWidth": 0.6, + "strokeBlur": 2, + "size": "road_label_3_size" }, "water_label": { "color": "water_dark", @@ -2290,12 +2393,54 @@ module.exports = { "poi": { "antialias": false }, - "poi_label": { + "poi_3": { + "antialias": false, + "opacity": [ + "stops", + {"z": 16.5, "val": 0}, + {"z": 16.75, "val": 1} + ] + }, + "poi_4": { + "antialias": false, + "opacity": [ + "stops", + {"z": 18.5, "val": 0}, + {"z": 18.75, "val": 1} + ] + }, + "poi_label_1-2": { + "color": "#444", + "size": 11, + "stroke": "land", + "strokeWidth": 0.3, + "strokeBlur": 1, + "translate": [0, 14] + }, + "poi_label_3": { "color": "#444", "size": 10, "stroke": "land", - "strokeWidth": 0.6, - "strokeBlur": 2, + "strokeWidth": 0.3, + "strokeBlur": 1, + "translate": [0, 14], + "opacity": [ + "stops", + {"z": 16.5, "val": 0}, + {"z": 16.75, "val": 1} + ] + }, + "poi_label_4": { + "color": "#444", + "size": 10, + "opacity": [ + "stops", + {"z": 18.5, "val": 0}, + {"z": 18.75, "val": 1} + ], + "stroke": "land", + "strokeWidth": 0.3, + "strokeBlur": 1, "translate": [0, 14] }, "poi_aerodrome": { @@ -2314,7 +2459,7 @@ module.exports = { "color": "land_night" }, "admin_maritime_cover": { - "color": "#0a1347", + "color": "water_night", "width": 5 }, "admin_maritime": { @@ -2465,11 +2610,11 @@ module.exports = { "color": "#103", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", - {"z": 0, "val": 0.3}, + {"z": 16, "val": 0.3}, {"z": 17, "val": 0.2}, {"z": 18, "val": 0.1} ] @@ -2478,11 +2623,11 @@ module.exports = { "color": "#206", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", - {"z": 0, "val": 0.3}, + {"z": 16, "val": 0.3}, {"z": 17, "val": 0.2}, {"z": 18, "val": 0.1} ] @@ -2491,7 +2636,7 @@ module.exports = { "color": "#fdfdad", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", @@ -2505,7 +2650,7 @@ module.exports = { "color": "#ffe1b7", "antialias": false, "prerender": true, - "prerender-size": 512, + "prerender-size": 1024, "prerender-blur": 1, "opacity": [ "stops", @@ -2854,12 +2999,9 @@ module.exports = { }, "country_label": { "color": "text_night", - "stroke": "text_stroke_night", - "size": [ - "stops", - {"z": 6, "val": 14}, - {"z": 12, "val": 24} - ] + "stroke": "text2_stroke_night", + "strokeWidth": 0.4, + "size": "country_label_size" }, "country_label_line": { "color": "text_night", @@ -2873,7 +3015,6 @@ module.exports = { "marine_label_point_1": { "color": "water_dark_night", "size": ["stops", - {"z": 0, "val": 20}, {"z": 3, "val": 20}, {"z": 4, "val": 25}, {"z": 5, "val": 30}, @@ -2884,7 +3025,6 @@ module.exports = { "marine_label_point_2": { "color": "water_dark_night", "size": ["stops", - {"z": 0, "val": 13}, {"z": 3, "val": 13}, {"z": 4, "val": 14}, {"z": 5, "val": 20}, @@ -2896,7 +3036,6 @@ module.exports = { "marine_label_point_other": { "color": "#a9c4c7", "size": ["stops", - {"z": 0, "val": 12}, {"z": 3, "val": 12}, {"z": 4, "val": 13}, {"z": 5, "val": 15}, @@ -2918,13 +3057,10 @@ module.exports = { {"z": 10, "val": 0} ] }, - "place_label_city_point": { - "color": "#ddd" - }, "place_label_city": { "color": "#fff", "strokeWidth": 0.4, - "stroke": "text_stroke_night", + "stroke": "text2_stroke_night", "size": [ "stops", {"z": 3.99, "val": 0}, @@ -2932,21 +3068,13 @@ module.exports = { {"z": 7, "val": 14}, {"z": 14.99, "val": 20}, {"z": 15, "val": 0} - ], - "translate": [ - 0, - [ - "stops", - {"z": 4, "val": 10}, - {"z": 6, "val": 30}, - {"z": 7, "val": 0} - ] ] }, "place_label_town": { "color": "text_night", - "strokeWidth": 0.5, - "stroke": "text_stroke_night", + "strokeWidth": 0.3, + "strokeBlur": 2, + "stroke": "text2_stroke_night", "size": [ "stops", {"z": 9, "val": 10}, @@ -2957,8 +3085,9 @@ module.exports = { }, "place_label_village": { "color": "text_night", - "strokeWidth": 0.5, - "stroke": "text_stroke_night", + "strokeWidth": 0.3, + "strokeBlur": 2, + "stroke": "text2_stroke_night", "size": [ "stops", {"z": 9, "val": 8}, @@ -2970,43 +3099,100 @@ module.exports = { }, "place_label_other": { "color": "text_night", - "stroke": "text_stroke_night", - "strokeWidth": 0.5, - "strokeBlur": 3, + "stroke": "text2_stroke_night", + "strokeWidth": 0.3, + "strokeBlur": 2, "size": [ "stops", - {"z": 0, "val": 10}, - {"z": 14, "val": 11}, - {"z": 15, "val": 12}, - {"z": 16, "val": 14} + {"z": 13, "val": 11}, + {"z": 14, "val": 12}, + {"z": 16, "val": 14}, + {"z": 18, "val": 18} ] }, - "road_label": { + "road_label_1": { "color": "text_night", "stroke": "text2_stroke_night", "strokeWidth": 0.5, "strokeBlur": 3, - "size": "road_label_size" + "size": "road_label_1_size" + }, + "road_label_2": { + "color": "text_night", + "stroke": "text2_stroke_night", + "strokeWidth": 0.5, + "strokeBlur": 3, + "size": "road_label_2_size" + }, + "road_label_3": { + "color": "text_night", + "stroke": "text2_stroke_night", + "strokeWidth": 0.5, + "strokeBlur": 3, + "size": "road_label_3_size" }, "water_label": { "color": "water_dark_night", - "stroke": "text_stroke_night" + "strokeWidth": 0.8, + "stroke": "text2_stroke_night" }, "waterway_label": { - "color": "land_night", + "color": "water_dark_night", "strokeWidth": 0.8, - "stroke": "water_night" + "stroke": "text2_stroke_night" }, "poi": { "color": "white", "antialias": false }, - "poi_label": { + "poi_3": { + "antialias": false, + "opacity": [ + "stops", + {"z": 16.5, "val": 0}, + {"z": 16.75, "val": 1} + ] + }, + "poi_4": { + "antialias": false, + "opacity": [ + "stops", + {"z": 18.5, "val": 0}, + {"z": 18.75, "val": 1} + ] + }, + "poi_label_1-2": { + "color": "#fff", + "size": 11, + "stroke": "text2_stroke_night", + "strokeWidth": 0.3, + "strokeBlur": 1, + "translate": [0, 14] + }, + "poi_label_3": { "color": "#fff", "size": 10, "stroke": "text2_stroke_night", "strokeWidth": 0.3, - "strokeBlur": 2, + "strokeBlur": 1, + "translate": [0, 14], + "opacity": [ + "stops", + {"z": 16.5, "val": 0}, + {"z": 16.75, "val": 1} + ] + }, + "poi_label_4": { + "color": "#fff", + "size": 10, + "opacity": [ + "stops", + {"z": 18.5, "val": 0}, + {"z": 18.75, "val": 1} + ], + "stroke": "text2_stroke_night", + "strokeWidth": 0.3, + "strokeBlur": 1, "translate": [0, 14] }, "poi_aerodrome": { 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..5785c29b3 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include namespace llmr { @@ -23,6 +26,7 @@ private: bool obsolete() const; void parseGlyphs(); void parseStyleLayers(const std::vector& layers); + void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &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/platform/gl.hpp b/include/llmr/platform/gl.hpp index f0f913a5e..da30d746e 100644 --- a/include/llmr/platform/gl.hpp +++ b/include/llmr/platform/gl.hpp @@ -39,7 +39,7 @@ namespace llmr { namespace gl { // Debug group markers, useful for debuggin on iOS -#if GL_EXT_debug_marker +#if defined(__APPLE__) && defined(DEBUG) && defined(GL_EXT_debug_marker) // static int indent = 0; inline void start_group(const std::string &str) { glPushGroupMarkerEXT(0, str.c_str()); 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/collision.hpp b/include/llmr/text/collision.hpp index ef4899c26..c9dafdd38 100644 --- a/include/llmr/text/collision.hpp +++ b/include/llmr/text/collision.hpp @@ -11,7 +11,7 @@ public: Collision(); ~Collision(); - PlacementProperty place(const PlacedGlyphs &boxes, + PlacementProperty place(const GlyphBoxes &boxes, const CollisionAnchor &anchor, float minPlacementScale, float maxPlacementScale, float padding, bool horizontal, bool alwaysVisible); diff --git a/include/llmr/text/glyph_store.hpp b/include/llmr/text/glyph_store.hpp index 90fa6d908..eb5d6038f 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::u32string &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/ios/img/Icon-40.png b/ios/img/Icon-40.png new file mode 100644 index 000000000..eca13393e Binary files /dev/null and b/ios/img/Icon-40.png differ diff --git a/ios/img/Icon-40@2x.png b/ios/img/Icon-40@2x.png new file mode 100644 index 000000000..070d03753 Binary files /dev/null and b/ios/img/Icon-40@2x.png differ diff --git a/ios/img/Icon-60.png b/ios/img/Icon-60.png index d062c3275..ff4c6ab4b 100644 Binary files a/ios/img/Icon-60.png and b/ios/img/Icon-60.png differ diff --git a/ios/img/Icon-60@2x.png b/ios/img/Icon-60@2x.png index 84550f36e..b7f25955f 100644 Binary files a/ios/img/Icon-60@2x.png and b/ios/img/Icon-60@2x.png differ diff --git a/ios/img/Icon-72.png b/ios/img/Icon-72.png index 9218aca97..0c876f664 100644 Binary files a/ios/img/Icon-72.png and b/ios/img/Icon-72.png differ diff --git a/ios/img/Icon-72@2x.png b/ios/img/Icon-72@2x.png index b4fb12ba7..6da408204 100644 Binary files a/ios/img/Icon-72@2x.png and b/ios/img/Icon-72@2x.png differ diff --git a/ios/img/Icon-76.png b/ios/img/Icon-76.png index debb8c453..895b4a176 100644 Binary files a/ios/img/Icon-76.png and b/ios/img/Icon-76.png differ diff --git a/ios/img/Icon-76@2x.png b/ios/img/Icon-76@2x.png index 1dce0cbd5..7bc520897 100644 Binary files a/ios/img/Icon-76@2x.png and b/ios/img/Icon-76@2x.png differ diff --git a/ios/img/Icon-Small-50.png b/ios/img/Icon-Small-50.png index a72e343a3..6d17da4b0 100644 Binary files a/ios/img/Icon-Small-50.png and b/ios/img/Icon-Small-50.png differ diff --git a/ios/img/Icon-Small-50@2x.png b/ios/img/Icon-Small-50@2x.png index 0535d00f0..ac4ec1928 100644 Binary files a/ios/img/Icon-Small-50@2x.png and b/ios/img/Icon-Small-50@2x.png differ diff --git a/ios/img/Icon-Small.png b/ios/img/Icon-Small.png index 46d4a5de6..aecbbc8a1 100644 Binary files a/ios/img/Icon-Small.png and b/ios/img/Icon-Small.png differ diff --git a/ios/img/Icon-Small@2x.png b/ios/img/Icon-Small@2x.png index 99058cebd..7773852e7 100644 Binary files a/ios/img/Icon-Small@2x.png and b/ios/img/Icon-Small@2x.png differ diff --git a/ios/img/Icon-Spotlight-40.png b/ios/img/Icon-Spotlight-40.png index 14b1ae112..eca13393e 100644 Binary files a/ios/img/Icon-Spotlight-40.png and b/ios/img/Icon-Spotlight-40.png differ diff --git a/ios/img/Icon-Spotlight-40@2x.png b/ios/img/Icon-Spotlight-40@2x.png index 4a45d8eff..070d03753 100644 Binary files a/ios/img/Icon-Spotlight-40@2x.png and b/ios/img/Icon-Spotlight-40@2x.png differ diff --git a/ios/img/Icon.png b/ios/img/Icon.png index bb426e668..9ca8194ee 100644 Binary files a/ios/img/Icon.png and b/ios/img/Icon.png differ diff --git a/ios/img/Icon@2x.png b/ios/img/Icon@2x.png index 3069b485f..7c2e8ba03 100644 Binary files a/ios/img/Icon@2x.png and b/ios/img/Icon@2x.png differ diff --git a/ios/img/iTunesArtwork.png b/ios/img/iTunesArtwork.png new file mode 100644 index 000000000..b10824b04 Binary files /dev/null and b/ios/img/iTunesArtwork.png differ diff --git a/ios/img/iTunesArtwork@2x.png b/ios/img/iTunesArtwork@2x.png new file mode 100644 index 000000000..fdee900aa Binary files /dev/null and b/ios/img/iTunesArtwork@2x.png differ diff --git a/macosx/Icon.icns b/macosx/Icon.icns index ab5ae136f..c4535a2e5 100644 Binary files a/macosx/Icon.icns and b/macosx/Icon.icns differ diff --git a/setup-libraries.sh b/setup-libraries.sh index fca19fd9c..b92cd3f05 100755 --- a/setup-libraries.sh +++ b/setup-libraries.sh @@ -16,6 +16,7 @@ ensure_dep cmake ensure_dep automake ensure_dep autoconf ensure_dep pkg-config +ensure_dep node if [ ${UNAME} = 'Darwin' ]; then ensure_dep makedepend ensure_dep glibtool @@ -27,10 +28,12 @@ fi if [[ $MISSING_DEPS != "" ]]; then if [ ${UNAME} = 'Darwin' ]; then echo "Missing build deps: ${MISSING_DEPS}" - echo 'Please run "brew install autoconf automake libtool makedepend cmake pkg-config" and then re-run ./setup-libraries.sh' + echo 'Please run "brew install autoconf automake libtool makedepend cmake pkg-config node"' + 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" and then re-run ./setup-libraries.sh' + 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 'and then re-run ./setup-libraries.sh' fi exit 1 fi @@ -74,8 +77,6 @@ source MacOSX.sh 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 - ./scripts/make_universal.sh cd ../../ @@ -86,15 +87,13 @@ cd ../../ elif [ ${UNAME} = 'Linux' ]; then source Linux.sh - if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64/lib/libglfw3.a ] ; then ./scripts/build_glfw.sh ; fi + if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi 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`/../../include/ `pwd`/../../linux/ `pwd`/../../common/ ; fi -rm -rf out/packages - cd ../../ ./configure \ --pkg-config-root=`pwd`/mapnik-packaging/osx/out/build-cpp11-libstdcpp-gcc-x86_64/lib/pkgconfig \ 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/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/map/tile_parser.cpp b/src/map/tile_parser.cpp index 70085b309..ff5d61a5e 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -10,13 +10,13 @@ #include #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), @@ -25,7 +25,6 @@ TileParser::TileParser(const std::string& data, VectorTileData& tile, const Styl glyphStore(glyphStore), spriteAtlas(spriteAtlas), placement(tile.id.z) { - parseGlyphs(); parseStyleLayers(style.layers); } @@ -33,17 +32,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::u32string &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}); } } @@ -203,7 +198,9 @@ 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); + std::map shaping; + GlyphPositions face; // Shape and place all labels. { @@ -223,11 +220,19 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye const std::u32string string = ucs4conv.convert(toString(it_prop->second)); - // TODO: Shape label - // TODO: Place label - } + // Shape labels. + const Shaping shaped = fontStack.getShaping(string); + shaping.emplace(toString(it_prop->second), shaped); + // Place labels. + addGlyph(tile.id.to_uint64(), bucket_desc.geometry.font, string, fontStack, glyphAtlas, face); + } } + // 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 310baf374..5823607ac 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()) { @@ -111,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()); @@ -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/collision.cpp b/src/text/collision.cpp index d1488cb29..0da50f280 100644 --- a/src/text/collision.cpp +++ b/src/text/collision.cpp @@ -53,7 +53,7 @@ Collision::Collision() : cTree(new Tree()), hTree(new Tree()) { CollisionAnchor{m, m}, 1, {{M_PI * 2, 0}}, false, 2); } -GlyphBox getMergedGlyphs(const PlacedGlyphs &placed_glyphs, bool horizontal, +GlyphBox getMergedGlyphs(const GlyphBoxes &boxes, bool horizontal, const CollisionAnchor &anchor) { GlyphBox mergedGlyphs; const float inf = std::numeric_limits::infinity(); @@ -62,28 +62,28 @@ GlyphBox getMergedGlyphs(const PlacedGlyphs &placed_glyphs, bool horizontal, mergedGlyphs.anchor = anchor; CollisionRect &box = mergedGlyphs.box; - for (const PlacedGlyph &placed_glyph : placed_glyphs) { - const CollisionRect &gbox = placed_glyph.glyphBox.box; + for (const GlyphBox &glyph : boxes) { + const CollisionRect &gbox = glyph.box; box.tl.x = util::min(box.tl.x, gbox.tl.x); box.tl.y = util::min(box.tl.y, gbox.tl.y); box.br.x = util::max(box.br.x, gbox.br.x); box.br.y = util::max(box.br.y, gbox.br.y); mergedGlyphs.minScale = - util::max(mergedGlyphs.minScale, placed_glyph.glyphBox.minScale); + util::max(mergedGlyphs.minScale, glyph.minScale); } return mergedGlyphs; } -PlacementProperty Collision::place(const PlacedGlyphs &placed_glyphs, +PlacementProperty Collision::place(const GlyphBoxes &boxes, const CollisionAnchor &anchor, float minPlacementScale, float maxPlacementScale, float padding, bool horizontal, bool alwaysVisible) { float minScale = std::numeric_limits::infinity(); - for (const PlacedGlyph &placed_glyph : placed_glyphs) { - minScale = util::min(minScale, placed_glyph.glyphBox.minScale); + for (const GlyphBox &glyphBox : boxes) { + minScale = util::min(minScale, glyphBox.minScale); } minPlacementScale = util::max(minPlacementScale, minScale); @@ -92,11 +92,9 @@ PlacementProperty Collision::place(const PlacedGlyphs &placed_glyphs, // for horizontal labels. GlyphBoxes glyphs; if (horizontal) { - glyphs.push_back(getMergedGlyphs(placed_glyphs, horizontal, anchor)); + glyphs.push_back(getMergedGlyphs(boxes, horizontal, anchor)); } else { - for (const PlacedGlyph &placed_glyph : placed_glyphs) { - glyphs.push_back(placed_glyph.glyphBox); - } + glyphs = boxes; } // Calculate bboxes for all the glyphs diff --git a/src/text/glyph.cpp b/src/text/glyph.cpp index 039e3bc36..882a8c493 100644 --- a/src/text/glyph.cpp +++ b/src/text/glyph.cpp @@ -7,95 +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 - return { 0, 0 }; + 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 459c2d971..e0404c08d 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -10,10 +11,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,15 +23,37 @@ 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::u32string &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()) { // 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(), ' ', '+'); + 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. @@ -70,11 +94,10 @@ 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(); } else if (glyph_pbf.tag == 3) { // width @@ -92,7 +115,7 @@ void GlyphPBF::parse(FontStack &stack) { } } - stack.insert(id, glyph.metrics, glyph.bitmap); + stack.insert(glyph.id, glyph); } else { fontstack_pbf.skip(); } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index 237fd05d7..f57436bcb 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; @@ -145,8 +136,9 @@ void getSegmentGlyphs(std::back_insert_iterator glyphs, } } -PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping, - const IndexedFaces &faces, float fontScale, +void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes, + Anchor &anchor, float advance, 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. @@ -162,12 +154,10 @@ PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping, // origin.x -= advance; // } - PlacedGlyphs glyphs; - 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. @@ -235,29 +225,32 @@ PlacedGlyphs getGlyphs(Anchor &anchor, float advance, const Shaping &shaping, fontScale * util::max(tl.y, tr.y, bl.y, br.y)}; } + GlyphBox glyphBox = GlyphBox{ + box, + // Prevent label from extending past the end of the line + util::max(instance.minScale, anchor.scale), + instance.maxScale, + instance.anchor, + horizontal}; + // Remember the glyph for later insertion. glyphs.emplace_back(PlacedGlyph{ tl, tr, bl, br, glyph.rect, static_cast( - std::fmod((anchor.angle + rotate + instance.offset + 2 * M_PI), - (2 * M_PI))), - GlyphBox{box, instance.minScale, instance.maxScale, - instance.anchor, horizontal}}); + std::fmod((anchor.angle + rotate + instance.offset + 2 * M_PI), (2 * M_PI))), + glyphBox}); + + if (instance.offset == 0.0f) { + boxes.emplace_back(glyphBox); + } } } - - // Prevent label from extending past the end of the line - for (PlacedGlyph &g : glyphs) { - g.glyphBox.minScale = util::max(g.glyphBox.minScale, anchor.scale); - } - - return glyphs; } 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 +261,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); @@ -289,27 +282,28 @@ void Placement::addFeature(TextBucket& bucket, } for (Anchor anchor : anchors) { - PlacedGlyphs glyphs = - getGlyphs(anchor, advance, shaping, faces, fontScale, horizontal, + PlacedGlyphs glyphs; + GlyphBoxes boxes; + + getGlyphs(glyphs, boxes, anchor, advance, shaping, face, fontScale, horizontal, line, maxAngleDelta, rotate); PlacementProperty place = - collision.place(glyphs, anchor, anchor.scale, maxPlacementScale, + collision.place(boxes, anchor, anchor.scale, maxPlacementScale, padding, horizontal, info.alwaysVisible); if (place) { - bucket.addGlyphs(glyphs, place.zoom, place.rotationRange, - zoom - zOffset); + bucket.addGlyphs(glyphs, place.zoom, place.rotationRange, zoom - zOffset); } } } -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; diff --git a/test/headless.cpp b/test/headless.cpp index c515b36c9..af34f4e19 100644 --- a/test/headless.cpp +++ b/test/headless.cpp @@ -11,6 +11,15 @@ #include +namespace llmr { +namespace platform { + +void notify_map_change() { + // no-op +} + +}} + class View : public llmr::View { public: void make_active() {