From 2b9fbb0731c94be0217d3e34d89e06945fce387f Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 7 May 2014 10:37:25 -0700 Subject: [PATCH] squashed stylequest merge * uses OSM Bright style * adds dot shader * adds layer translation * adds dashed line support * adds style array parsing * improves background layer parsing * improves style constant parsing * fixes sprite JSON pixel ratio parsing --- bin/style.js | 2305 ++++++++++++++++++++---- include/llmr/renderer/painter.hpp | 3 + include/llmr/renderer/point_bucket.hpp | 2 + include/llmr/shader/dot_shader.hpp | 33 + include/llmr/shader/line_shader.hpp | 2 +- include/llmr/style/properties.hpp | 16 + include/llmr/style/style_parser.hpp | 8 +- src/map/tile_parser.cpp | 6 +- src/map/vector_tile.cpp | 12 +- src/platform/platform.cpp | 2 +- src/renderer/painter.cpp | 115 +- src/renderer/point_bucket.cpp | 6 + src/shader/dot.fragment.glsl | 9 + src/shader/dot.vertex.glsl | 9 + src/shader/dot_shader.cpp | 57 + src/shader/line.fragment.glsl | 6 +- src/shader/line.vertex.glsl | 6 +- src/shader/line_shader.cpp | 10 +- src/shader/shaders_gl.cpp | 8 +- src/shader/shaders_gles2.cpp | 8 +- src/style/sprite.cpp | 2 +- src/style/style.cpp | 14 +- src/style/style_parser.cpp | 137 +- 23 files changed, 2355 insertions(+), 421 deletions(-) create mode 100644 include/llmr/shader/dot_shader.hpp create mode 100644 src/shader/dot.fragment.glsl create mode 100644 src/shader/dot.vertex.glsl create mode 100644 src/shader/dot_shader.cpp diff --git a/bin/style.js b/bin/style.js index b9d404a9e..c89ff81e8 100644 --- a/bin/style.js +++ b/bin/style.js @@ -2,53 +2,103 @@ module.exports = { "buckets": { - "satellite": { - "source": "satellite", - "type": "raster" + "admin_maritime": { + "source": "mapbox streets", + "layer": "admin", + "field": "maritime", + "value": "1", + "join": "round", + "type": "line" + }, + "admin_level_2": { + "source": "mapbox streets", + "layer": "admin", + "field": "admin_level", + "value": 2, + "join": "round", + "cap": "round", + "type": "line" + }, + "admin_level_3": { + "source": "mapbox streets", + "layer": "admin", + "field": "admin_level", + "value": [ + 3, + 4, + 5 + ], + "join": "round", + "type": "line" }, "water": { "source": "mapbox streets", "layer": "water", "type": "fill" }, - "road_large": { + "waterway_other": { "source": "mapbox streets", - "layer": "road", "field": "class", "value": ["motorway", "main"], - "type": "line", "cap": "round", "join": "round" + "layer": "waterway", + "field": "type", + "value": [ + "ditch", + "drain" + ], + "cap": "round", + "type": "line" }, - "road_regular": { + "waterway_river": { "source": "mapbox streets", - "layer": "road", "field": "class", "value": "street", - "type": "line", "cap": "round", "join": "round" + "layer": "waterway", + "field": "type", + "value": "river", + "cap": "round", + "type": "line" }, - "road_limited": { + "waterway_stream_canal": { "source": "mapbox streets", - "layer": "road", "field": "class", "value": "street_limited", - "type": "line", "cap": "round", "join": "round" + "layer": "waterway", + "field": "type", + "value": [ + "stream", + "canal" + ], + "cap": "round", + "type": "line" }, - "park": { + "landuse_park": { "source": "mapbox streets", - "layer": "landuse", "field": "class", "value": "park", + "layer": "landuse", + "field": "class", + "value": "park", "type": "fill" }, - "wood": { + "landuse_cemetary": { "source": "mapbox streets", - "layer": "landuse", "field": "class", "value": "wood", + "layer": "landuse", + "field": "class", + "value": "cemetary", "type": "fill" }, - "school": { + "landuse_hospital": { "source": "mapbox streets", - "layer": "landuse", "field": "class", "value": "school", + "layer": "landuse", + "field": "class", + "value": "hospital", "type": "fill" }, - "cemetery": { + "landuse_school": { "source": "mapbox streets", - "layer": "landuse", "field": "class", "value": "cemetery", + "layer": "landuse", + "field": "class", + "value": "school", "type": "fill" }, - "industrial": { + "landuse_wood": { "source": "mapbox streets", - "layer": "landuse", "field": "class", "value": "industrial", + "layer": "landuse", + "field": "class", + "value": "wood", "type": "fill" }, "building": { @@ -56,337 +106,1956 @@ module.exports = { "layer": "building", "type": "fill" }, - "alcohol_poi": { + "aeroway_fill": { "source": "mapbox streets", - "layer": "poi_label", - "field": "type", - "value": ["Alcohol"], - "type": "point" + "layer": "aeroway", + "type": "fill", + "enabled": 12 }, - "cafe_poi": { + "aeroway_runway": { "source": "mapbox streets", - "layer": "poi_label", + "layer": "aeroway", "field": "type", - "value": ["Cafe"], - "type": "point" + "value": "runway", + "type": "line", + "enabled": 12 }, - "embassy_poi": { + "aeroway_taxiway": { "source": "mapbox streets", - "layer": "poi_label", + "layer": "aeroway", "field": "type", - "value": ["Embassy"], - "type": "point" + "value": "taxiway", + "type": "line", + "enabled": 12 }, - "park_poi": { + "motorway": { "source": "mapbox streets", - "layer": "poi_label", - "field": "type", - "value": ["Park"], - "type": "point" + "layer": "road", + "field": "class", + "value": "motorway", + "join": "round", + "cap": "round", + "type": "line" }, - "restaurant_poi": { + "motorway_link": { "source": "mapbox streets", - "layer": "poi_label", - "field": "type", - "value": ["Restaurant"], - "type": "point" + "layer": "road", + "field": "class", + "value": "motorway_link", + "join": "round", + "cap": "round", + "type": "line" + }, + "main": { + "source": "mapbox streets", + "layer": "road", + "field": "class", + "value": "main", + "join": "round", + "cap": "round", + "type": "line" + }, + "street": { + "source": "mapbox streets", + "layer": "road", + "field": "class", + "value": [ + "street", + "street_limited" + ], + "join": "round", + "cap": "round", + "type": "line", + "enabled": 12 + }, + "service": { + "source": "mapbox streets", + "layer": "road", + "field": "class", + "value": "service", + "join": "round", + "cap": "round", + "type": "line", + "enabled": 15 + }, + "path": { + "source": "mapbox streets", + "layer": "road", + "field": "class", + "value": "path", + "type": "line", + "enabled": 15 + }, + "major_rail": { + "source": "mapbox streets", + "layer": "road", + "field": "class", + "value": "major_rail", + "type": "line" + }, + "tunnel_motorway": { + "source": "mapbox streets", + "layer": "tunnel", + "field": "class", + "value": "motorway", + "join": "round", + "cap": "round", + "type": "line" + }, + "tunnel_motorway_link": { + "source": "mapbox streets", + "layer": "tunnel", + "field": "class", + "value": "motorway_link", + "join": "round", + "cap": "round", + "type": "line" + }, + "tunnel_main": { + "source": "mapbox streets", + "layer": "tunnel", + "field": "class", + "value": "main", + "join": "round", + "cap": "round", + "type": "line" + }, + "tunnel_street": { + "source": "mapbox streets", + "layer": "tunnel", + "field": "class", + "value": [ + "street", + "street_limited" + ], + "join": "round", + "type": "line" + }, + "tunnel_service": { + "source": "mapbox streets", + "layer": "tunnel", + "field": "class", + "value": "service", + "join": "round", + "cap": "round", + "type": "line" + }, + "tunnel_path": { + "source": "mapbox streets", + "layer": "tunnel", + "field": "class", + "value": "path", + "type": "line", + "enabled": 15 + }, + "tunnel_major_rail": { + "source": "mapbox streets", + "layer": "tunnel", + "field": "class", + "value": "major_rail", + "type": "line" + }, + "bridge_motorway": { + "source": "mapbox streets", + "layer": "bridge", + "field": "class", + "value": "motorway", + "join": "round", + "type": "line" + }, + "bridge_motorway_link": { + "source": "mapbox streets", + "layer": "bridge", + "field": "class", + "value": "motorway_link", + "join": "round", + "type": "line" + }, + "bridge_main": { + "source": "mapbox streets", + "layer": "bridge", + "field": "class", + "value": "main", + "join": "round", + "type": "line" + }, + "bridge_street": { + "source": "mapbox streets", + "layer": "bridge", + "field": "class", + "value": [ + "street", + "street_limited" + ], + "join": "round", + "type": "line", + "enabled": 12 + }, + "bridge_service": { + "source": "mapbox streets", + "layer": "bridge", + "field": "class", + "value": "service", + "join": "round", + "type": "line", + "enabled": 15 + }, + "bridge_major_rail": { + "source": "mapbox streets", + "layer": "bridge", + "field": "class", + "value": "major_rail", + "type": "line" + }, + "bridge_path": { + "source": "mapbox streets", + "layer": "bridge", + "field": "class", + "value": "path", + "type": "line", + "enabled": 15 }, "country_label": { "source": "mapbox streets", - "type": "text", "layer": "country_label", - "feature_type": "point", - "padding": 10, "text_field": "name", "path": "horizontal", - "font": "Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS", + "fontSize": 13, + "feature_type": "point", + "type": "text", + "enabled": 3 + }, + "country_label_line": { + "source": "mapbox streets", + "layer": "country_label_line", + "type": "line", + "enabled": 3 + }, + "marin_label_1": { + "source": "mapbox streets", + "layer": "marin_label", + "field": "labelrank", + "value": 1, + "feature_type": "line", + "type": "text", + "text_field": "name", + "path": "curve", + "fontSize": 22 + }, + "marin_label_2": { + "source": "mapbox streets", + "layer": "marin_label", + "field": "labelrank", + "value": 2, + "feature_type": "line", + "type": "text", + "text_field": "name", + "path": "curve", "fontSize": 16 }, - "place_label": { + "marin_label_3": { "source": "mapbox streets", + "layer": "marin_label", + "field": "labelrank", + "value": 3, + "feature_type": "line", "type": "text", + "text_field": "name", + "path": "curve", + "fontSize": 14 + }, + "place_label_city_point": { + "source": "mapbox streets", "layer": "place_label", - "feature_type": "point", + "field": "type", + "value": "city", + "type": "point" + }, + "place_label_city": { + "source": "mapbox streets", + "layer": "place_label", + "field": "type", + "value": "city", "text_field": "name", "path": "horizontal", - "font": "Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS", - "fontSize": 18, - "alwaysVisible": true + "fontSize": 24, + "feature_type": "point", + "type": "text" + }, + "place_label_town": { + "source": "mapbox streets", + "layer": "place_label", + "field": "type", + "value": "town", + "text_field": "name", + "path": "horizontal", + "fontSize": 24, + "feature_type": "point", + "type": "text" + }, + "place_label_village": { + "source": "mapbox streets", + "layer": "place_label", + "field": "type", + "value": "village", + "text_field": "name", + "path": "horizontal", + "fontSize": 22, + "feature_type": "point", + "type": "text" + }, + "place_label_other": { + "source": "mapbox streets", + "layer": "place_label", + "field": "type", + "value": [ + "hamlet", + "suburb", + "neighbourhood" + ], + "text_field": "name", + "path": "horizontal", + "fontSize": 14, + "feature_type": "point", + "type": "text" + }, + "poi_label": { + "source": "mapbox streets", + "layer": "poi_label", + "text_field": "name", + "path": "horizontal", + "padding": 2, + "fontSize": 12, + "feature_type": "point", + "type": "text" }, "road_label": { "source": "mapbox streets", - "type": "text", "layer": "road_label", - "feature_type": "line", "text_field": "name", "path": "curve", - "font": "Open Sans, Jomolhari, Siyam Rupali, Alef, Arial Unicode MS", + "padding": 2, + "fontSize": 13, + "feature_type": "line", + "type": "text" + }, + "water_label": { + "source": "mapbox streets", + "layer": "water_label", + "text_field": "name", + "path": "horizontal", "fontSize": 12, - "textMinDistance": 250, - "maxAngleDelta": 1.04, // radians + "feature_type": "point", + "type": "text" }, + "poi_airport": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "airport", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_rail": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "rail", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_fire_station": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "fire-station", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_bus": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "bus", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_restaurant": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "restaurant", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_park": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "park", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_playground": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "playground", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_hospital": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "hospital", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_cafe": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "cafe", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + }, + "poi_beer": { + "source": "mapbox streets", + "layer": "poi_label", + "field": "maki", + "value": "beer", + "size": { + "x": 12, + "y": 12 + }, + "type": "point" + } }, - "sprite": "img/maki-sprite", "constants": { - "park": "#c8df9f", - "text": "#000000", + "land": "#f8f4f0", + "water": "#a0c8f0", + "park": "#d8e8c8", + "cemetary": "#e0e4dd", + "hospital": "#fde", + "school": "#f0e8f8", + "wood": "#6a4", + "building": "#f2eae2", + "building_shadow": "#dfdbd7", + "aeroway": "#f0ede9", + "motorway": "#fc8", + "motorway_casing": "#e9ac77", + "motorway_tunnel": "#ffdaa6", + "main": "#fea", + "main_tunnel": "#fff4c6", + "street": "#fff", + "street_limited": "#f3f3f3", + "street_casing": "#cfcdca", + "path": "#cba", + "rail": "#bbb", + "text": "#334", + "marine_text": "#8dbeed", + "maki": "#666", + "point_translate": [ + 0, -30 + ] }, - "structure": [ - { "name": "satellite", "bucket": "satellite" }, - { "name": "park", "bucket": "park" }, - { "name": "wood", "bucket": "wood" }, - { "name": "water", "bucket": "water" }, - { "name": "building", "bucket": "building" }, - { "name": "road_limited", "bucket": "road_limited" }, - { "name": "road_regular", "bucket": "road_regular" }, - { "name": "road_large", "bucket": "road_large" }, - { "name": "alcohol_poi", "bucket": "alcohol_poi" }, - { "name": "cafe_poi", "bucket": "cafe_poi" }, - { "name": "embassy_poi", "bucket": "embassy_poi" }, - { "name": "park_poi", "bucket": "park_poi" }, - { "name": "restaurant_poi", "bucket": "restaurant_poi" }, - { "name": "country_label", "bucket": "country_label" }, - { "name": "place_label", "bucket": "place_label" }, - { "name": "road_label", "bucket": "road_label" }, - ], - "classes": [ - { - "name": "default", - "layers": { - "background": { - "type": "background", - "color": "#FFFFFF" - }, - "park": { - "type": "fill", - "color": "park", - "antialias": true, - "image": "park" - }, - "wood": { - "type": "fill", - "color": "#33AA66", - "antialias": true, - "opacity": 0.1 - }, - "water": { - "type": "fill", - "color": "#bae0e9", - "stroke": "#73b6e6", - "antialias": true, - "image": "water_etsy" - }, - "building": { - "type": "fill", - "color": "#000000", - "antialias": true, - "opacity": [ "linear", 13, 0, 0.1, 0, 0.1 ] - }, - "road_limited": { - "type": "line", - "color": "#BBBBBB", - "width": [ - "stops", - { z: 0, val: 1 }, - { z: 30, val: 1 } - ] - }, - "road_regular": { - "type": "line", - "color": "#999999", - "width": [ - "stops", - { z: 0, val: 0.5 }, - { z: 13, val: 0.5 }, - { z: 16, val: 2 }, - { z: 20, val: 16 }, - { z: 30, val: 16 } - ], - }, - "road_large": { - "type": "line", - "color": "#666666", - "width": [ - "stops", - { z: 0, val: 0.5 }, - { z: 11, val: 0.5 }, - { z: 13, val: 1 }, - { z: 16, val: 4 }, - { z: 20, val: 32 }, - { z: 30, val: 32 } - ], - }, - "alcohol_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "alcohol-shop", - "enabled": [ "min", 17 ] - }, - "cafe_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "cafe", - "enabled": [ "min", 17 ] - }, - "embassy_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "embassy", - "enabled": [ "min", 17 ] - }, - "park_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "park", - "enabled": [ "min", 17 ] - }, - "restaurant_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "restaurant", - "enabled": [ "min", 17 ] - }, - "country_label": { - "type": "text", - "stroke": [ 1, 1, 1, 0.7 ], - "color": "text", - "size": 16 - }, - "place_label": { - "type": "text", - "stroke": [1,1,1,0.7], - "color": "text", - "size": 18 - }, - "road_label": { - "type": "text", - "color": "text", - "stroke": [1,1,1,0.7], - "size": ["exponential", 14, 8, 1, 8, 12] - }, - } - }, - { - "name": "satellite", - "layers": { - "background": { - "type": "background", - "color": "#333333", - "opacity": 1.0 - }, - "park": { - "type": "fill", - "opacity": 0, - }, - "wood": { - "type": "fill", - "opacity": 0, - }, - "water": { - "type": "fill", - "opacity": 0, - }, - "building": { - "type": "fill", - "opacity": 0, - }, - "road_limited": { - "type": "line", - "color": "#BBBBBB", - "width": [ - "stops", - { z: 0, val: 1 }, - { z: 30, val: 1 } - ] - }, - "road_regular": { - "type": "line", - "color": "#999999", - "width": [ - "stops", - { z: 0, val: 0.5 }, - { z: 13, val: 0.5 }, - { z: 16, val: 2 }, - { z: 20, val: 16 }, - { z: 30, val: 16 } - ], - }, - "road_large": { - "type": "line", - "color": "#666666", - "width": [ - "stops", - { z: 0, val: 0.5 }, - { z: 11, val: 0.5 }, - { z: 13, val: 1 }, - { z: 16, val: 4 }, - { z: 20, val: 32 }, - { z: 30, val: 32 } - ], - }, - "alcohol_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "alcohol-shop", - "enabled": [ "min", 17 ] - }, - "cafe_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "cafe", - "enabled": [ "min", 17 ] - }, - "embassy_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "embassy", - "enabled": [ "min", 17 ] - }, - "park_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "park", - "enabled": [ "min", 17 ] - }, - "restaurant_poi": { - "type": "point", - "color": "#cccccc", - "size": 18, - "image": "restaurant", - "enabled": [ "min", 17 ] - }, - "country_label": { - "type": "text", - "stroke": [ 1, 1, 1, 0.7 ], - "color": "text", - "size": 16 - }, - "place_label": { - "type": "text", - "stroke": [1,1,1,0.7], - "color": "text", - "size": 18 - }, - "road_label": { - "type": "text", - "color": "text", - "stroke": [1,1,1,0.7], - "size": ["exponential", 14, 8, 1, 8, 12] - }, - "satellite": { - "type": "raster", - "opacity": 0.25 - }, + "structure": [{ + "name": "background", + "bucket": "background" + }, { + "name": "waterway_other", + "bucket": "waterway_other" + }, { + "name": "waterway_river", + "bucket": "waterway_river" + }, { + "name": "waterway_stream_canal", + "bucket": "waterway_stream_canal" + }, { + "name": "landuse_park", + "bucket": "landuse_park" + }, { + "name": "landuse_cemetary", + "bucket": "landuse_cemetary" + }, { + "name": "landuse_hospital", + "bucket": "landuse_hospital" + }, { + "name": "landuse_school", + "bucket": "landuse_school" + }, { + "name": "landuse_wood", + "bucket": "landuse_wood" + }, { + "name": "water", + "bucket": "water" + }, { + "name": "water_offset", + "bucket": "water" + }, { + "name": "aeroway_fill", + "bucket": "aeroway_fill" + }, { + "name": "aeroway_runway", + "bucket": "aeroway_runway" + }, { + "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" + }, { + "name": "tunnel_motorway_casing", + "bucket": "tunnel_motorway" + }, { + "name": "tunnel_motorway_link", + "bucket": "tunnel_motorway_link" + }, { + "name": "tunnel_motorway", + "bucket": "tunnel_motorway" + }, { + "name": "tunnel_path", + "bucket": "tunnel_path" + }, { + "name": "tunnel_major_rail", + "bucket": "tunnel_major_rail" + }, { + "name": "tunnel_major_rail_hatching", + "bucket": "tunnel_major_rail" + }, { + "name": "tunnel_service_casing", + "bucket": "tunnel_service" + }, { + "name": "tunnel_service", + "bucket": "tunnel_service" + }, { + "name": "tunnel_main_casing", + "bucket": "tunnel_main" + }, { + "name": "tunnel_street_casing", + "bucket": "tunnel_street" + }, { + "name": "tunnel_street", + "bucket": "tunnel_street" + }, { + "name": "tunnel_main", + "bucket": "tunnel_main" + }, { + "name": "road_motorway_link_casing", + "bucket": "motorway_link" + }, { + "name": "road_service_casing", + "bucket": "service" + }, { + "name": "road_main_casing", + "bucket": "main" + }, { + "name": "road_street_casing", + "bucket": "street" + }, { + "name": "road_motorway_link", + "bucket": "motorway_link" + }, { + "name": "road_service", + "bucket": "service" + }, { + "name": "road_street", + "bucket": "street" + }, { + "name": "road_main", + "bucket": "main" + }, { + "name": "road_motorway_casing", + "bucket": "motorway" + }, { + "name": "road_motorway", + "bucket": "motorway" + }, { + "name": "bridge_service_casing", + "bucket": "bridge_service" + }, { + "name": "bridge_service", + "bucket": "bridge_service" + }, { + "name": "bridge_main_casing", + "bucket": "bridge_main" + }, { + "name": "bridge_main", + "bucket": "bridge_main" + }, { + "name": "bridge_street_casing", + "bucket": "bridge_street" + }, { + "name": "bridge_street", + "bucket": "bridge_street" + }, { + "name": "bridge_motorway_link_casing", + "bucket": "bridge_motorway_link" + }, { + "name": "bridge_motorway_link", + "bucket": "bridge_motorway_link" + }, { + "name": "bridge_motorway_casing", + "bucket": "bridge_motorway" + }, { + "name": "bridge_motorway", + "bucket": "bridge_motorway" + }, { + "name": "road_path", + "bucket": "path" + }, { + "name": "road_major_rail", + "bucket": "major_rail" + }, { + "name": "road_major_rail_hatching", + "bucket": "major_rail" + }, { + "name": "bridge_path", + "bucket": "bridge_path" + }, { + "name": "bridge_major_rail", + "bucket": "bridge_major_rail" + }, { + "name": "bridge_major_rail_hatching", + "bucket": "bridge_major_rail" + }, { + "name": "admin_level_3", + "bucket": "admin_level_3" + }, { + "name": "admin_level_2", + "bucket": "admin_level_2" + }, { + "name": "admin_maritime", + "bucket": "admin_maritime" + }, { + "name": "country_label_line", + "bucket": "country_label_line" + }, { + "name": "country_label", + "bucket": "country_label" + }, { + "name": "marin_label_1", + "bucket": "marin_label_1" + }, { + "name": "marin_label_2", + "bucket": "marin_label_2" + }, { + "name": "marin_label_3", + "bucket": "marin_label_3" + }, { + "name": "place_label_city_point", + "bucket": "place_label_city_point" + }, { + "name": "place_label_city", + "bucket": "place_label_city" + }, { + "name": "place_label_town", + "bucket": "place_label_town" + }, { + "name": "place_label_village", + "bucket": "place_label_village" + }, { + "name": "place_label_other", + "bucket": "place_label_other" + }, { + "name": "road_label", + "bucket": "road_label" + }, { + "name": "poi_label", + "bucket": "poi_label" + }, { + "name": "water_label", + "bucket": "water_label" + }, { + "name": "poi_airport", + "bucket": "poi_airport" + }, { + "name": "poi_rail", + "bucket": "poi_rail" + }, { + "name": "poi_bus", + "bucket": "poi_bus" + }, { + "name": "poi_fire_station", + "bucket": "poi_fire_station" + }, { + "name": "poi_restaurant", + "bucket": "poi_restaurant" + }, { + "name": "poi_park", + "bucket": "poi_park" + }, { + "name": "poi_hospital", + "bucket": "poi_hospital" + }, { + "name": "poi_playground", + "bucket": "poi_playground" + }, { + "name": "poi_cafe", + "bucket": "poi_cafe" + }, { + "name": "poi_beer", + "bucket": "poi_beer" + }], + "classes": [{ + "name": "default", + "layers": { + "background": { + "color": "land", + }, + "admin_maritime": { + "color": "#cfe0fa", + "width": 4.5, + }, + "admin_level_2": { + "color": "#446", + "width": [ + "stops", { + "z": 0, + "val": 1.5 + }, { + "z": 6, + "val": 1.5 + }, { + "z": 8, + "val": 3 + }, { + "z": 22, + "val": 3 + } + ], + }, + "admin_level_3": { + "color": "#446", + "dasharray": [ + 30, + 5 + ], + "width": [ + "stops", { + "z": 0, + "val": 0.5 + }, { + "z": 6, + "val": 0.5 + }, { + "z": 8, + "val": 1 + }, { + "z": 12, + "val": 1.5 + }, { + "z": 22, + "val": 1.5 + } + ], + }, + "waterway_other": { + "color": "water", + "width": 0.5, + }, + "waterway_river": { + "color": "water", + "width": [ + "stops", { + "z": 0, + "val": 1 + }, { + "z": 12, + "val": 1 + }, { + "z": 14, + "val": 2 + }, { + "z": 16, + "val": 3 + }, { + "z": 22, + "val": 3 + } + ], + }, + "waterway_stream_canal": { + "color": "water", + "width": [ + "stops", { + "z": 0, + "val": 1 + }, { + "z": 14, + "val": 1 + }, { + "z": 16, + "val": 2 + }, { + "z": 18, + "val": 3 + }, { + "z": 22, + "val": 3 + } + ], + }, + "landuse_park": { + "color": "park", + }, + "landuse_cemetary": { + "color": "cemetary", + }, + "landuse_hospital": { + "color": "hospital", + }, + "landuse_school": { + "color": "school", + }, + "landuse_wood": { + "color": "wood", + "opacity": 0.1, + }, + "water": { + "color": "water", + }, + "water_offset": { + "color": "#f0f0ff", + "image": "wave", + "opacity": 0.4, + "translate": [ + 0, + 2.5 + ], + }, + "aeroway_fill": { + "color": "aeroway", + "opacity": 0.7, + }, + "aeroway_runway": { + "color": "aeroway", + "width": 5, + }, + "aeroway_taxiway": { + "color": "aeroway", + "width": 1.5, + }, + "building": { + "color": "building", + }, + "building_wall": { + "color": "building", + "stroke": "building_shadow", + "opacity": [ + "stops", { + "z": 0, + "val": 0 + }, { + "z": 17, + "val": 0 + }, { + "z": 18, + "val": 1 + }, { + "z": 22, + "val": 1 + } + ], + }, + "building_shadow": { + "color": "building_shadow", + "translate": [ + 2, + 2 + ], + "opacity": [ + "stops", { + "z": 0, + "val": 0 + }, { + "z": 17, + "val": 0 + }, { + "z": 18, + "val": 1 + }, { + "z": 22, + "val": 1 + } + ], + }, + "road_motorway_casing": { + "color": "motorway_casing", + "width": [ + "stops", { + "z": 6, + "val": 0.4 + }, { + "z": 7, + "val": 0.6 + }, { + "z": 8, + "val": 1.5 + }, { + "z": 10, + "val": 3 + }, { + "z": 13, + "val": 3.5 + }, { + "z": 14, + "val": 5 + }, { + "z": 15, + "val": 7 + }, { + "z": 16, + "val": 9 + }, { + "z": 22, + "val": 9 + } + ], + }, + "road_motorway": { + "color": "motorway", + "width": [ + "stops", { + "z": 7, + "val": 0 + }, { + "z": 8, + "val": 0.5 + }, { + "z": 10, + "val": 1 + }, { + "z": 13, + "val": 2 + }, { + "z": 14, + "val": 3.5 + }, { + "z": 15, + "val": 5 + }, { + "z": 16, + "val": 7 + }, { + "z": 22, + "val": 7 + } + ], + "opacity": [ + "stops", { + "z": 7, + "val": 0 + }, { + "z": 8, + "val": 1 + }, { + "z": 22, + "val": 1 + } + ], + }, + "road_main_casing": { + "color": "motorway_casing", + "width": [ + "stops", { + "z": 6, + "val": 0.2 + }, { + "z": 16, + "val": 8 + }, { + "z": 22, + "val": 8 + } + ], + }, + "road_main": { + "color": "main", + "width": [ + "stops", { + "z": 8, + "val": 0.5 + }, { + "z": 10, + "val": 1 + }, { + "z": 13, + "val": 1.5 + }, { + "z": 14, + "val": 2.5 + }, { + "z": 15, + "val": 3.5 + }, { + "z": 16, + "val": 6 + }, { + "z": 22, + "val": 6 + } + ], + }, + "road_motorway_link_casing": { + "color": "motorway_casing", + "width": [ + "stops", { + "z": 13, + "val": 1 + }, { + "z": 14, + "val": 3 + }, { + "z": 15, + "val": 5 + }, { + "z": 16, + "val": 6.5 + }, { + "z": 22, + "val": 6.5 + } + ], + }, + "road_motorway_link": { + "color": "motorway", + "width": [ + "stops", { + "z": 13, + "val": 1.5 + }, { + "z": 14, + "val": 1.5 + }, { + "z": 15, + "val": 3 + }, { + "z": 16, + "val": 4.5 + }, { + "z": 22, + "val": 4.5 + } + ], + }, + "road_street_casing": { + "color": "street_casing", + "width": [ + "stops", { + "z": 0, + "val": 1 + }, { + "z": 12, + "val": 1 + }, { + "z": 14, + "val": 1 + }, { + "z": 15, + "val": 4 + }, { + "z": 16, + "val": 6.5 + }, { + "z": 22, + "val": 6.5 + } + ], + }, + "road_street": { + "color": "street", + "width": [ + "stops", { + "z": 14.5, + "val": 0 + }, { + "z": 15, + "val": 2.5 + }, { + "z": 16, + "val": 4 + }, { + "z": 22, + "val": 4 + } + ], + }, + "road_service_casing": { + "color": "street_casing", + "width": [ + "stops", { + "z": 0, + "val": 1 + }, { + "z": 15, + "val": 1 + }, { + "z": 16, + "val": 4 + }, { + "z": 22, + "val": 4 + } + ], + }, + "road_service": { + "color": "street", + "width": 2, + }, + "road_path": { + "color": "path", + "dasharray": [ + 2, + 1 + ], + "width": [ + "stops", { + "z": 15, + "val": 1 + }, { + "z": 16, + "val": 1.2 + }, { + "z": 17, + "val": 1.5 + }, { + "z": 22, + "val": 1.5 + } + ], + }, + "road_major_rail": { + "color": "rail", + "width": [ + "stops", { + "z": 0, + "val": 0.4 + }, { + "z": 16, + "val": 0.75 + }, { + "z": 22, + "val": 0.75 + } + ], + }, + "road_major_rail_hatching": { + "color": "rail", + "dasharray": [ + 2, + 31 + ], + "width": 4, + }, + "bridge_motorway_casing": { + "color": "motorway_casing", + "width": [ + "stops", { + "z": 6, + "val": 0.4 + }, { + "z": 7, + "val": 0.6 + }, { + "z": 8, + "val": 1.5 + }, { + "z": 10, + "val": 3 + }, { + "z": 13, + "val": 3.5 + }, { + "z": 14, + "val": 5 + }, { + "z": 15, + "val": 7 + }, { + "z": 16, + "val": 9 + }, { + "z": 22, + "val": 9 + } + ], + }, + "bridge_motorway": { + "color": "motorway", + "width": [ + "stops", { + "z": 7, + "val": 0 + }, { + "z": 8, + "val": 0.5 + }, { + "z": 10, + "val": 1 + }, { + "z": 13, + "val": 2 + }, { + "z": 14, + "val": 3.5 + }, { + "z": 15, + "val": 5 + }, { + "z": 16, + "val": 7 + }, { + "z": 22, + "val": 7 + } + ], + "opacity": [ + "stops", { + "z": 7, + "val": 0 + }, { + "z": 8, + "val": 1 + }, { + "z": 22, + "val": 1 + } + ], + }, + "bridge_main_casing": { + "color": "motorway_casing", + "width": [ + "stops", { + "z": 6, + "val": 0.2 + }, { + "z": 16, + "val": 8 + }, { + "z": 22, + "val": 8 + } + ], + }, + "bridge_main": { + "color": "main", + "width": [ + "stops", { + "z": 8, + "val": 0.5 + }, { + "z": 10, + "val": 1 + }, { + "z": 13, + "val": 1.5 + }, { + "z": 14, + "val": 2.5 + }, { + "z": 15, + "val": 3.5 + }, { + "z": 16, + "val": 6 + }, { + "z": 22, + "val": 6 + } + ], + }, + "bridge_motorway_link_casing": { + "color": "motorway_casing", + "width": [ + "stops", { + "z": 13, + "val": 1 + }, { + "z": 14, + "val": 3 + }, { + "z": 15, + "val": 5 + }, { + "z": 16, + "val": 6.5 + }, { + "z": 22, + "val": 6.5 + } + ], + }, + "bridge_motorway_link": { + "color": "motorway", + "width": [ + "stops", { + "z": 13, + "val": 1.5 + }, { + "z": 14, + "val": 1.5 + }, { + "z": 15, + "val": 3 + }, { + "z": 16, + "val": 4.5 + }, { + "z": 22, + "val": 4.5 + } + ], + }, + "bridge_street_casing": { + "color": "street_casing", + "width": [ + "stops", { + "z": 12, + "val": 0.5 + }, { + "z": 14, + "val": 1 + }, { + "z": 15, + "val": 4 + }, { + "z": 16, + "val": 6.5 + }, { + "z": 22, + "val": 6.5 + } + ], + }, + "bridge_street": { + "color": "street", + "width": [ + "stops", { + "z": 14, + "val": 0 + }, { + "z": 15, + "val": 2.5 + }, { + "z": 16, + "val": 4 + }, { + "z": 22, + "val": 4 + } + ], + "opacity": [ + "stops", { + "z": 14, + "val": 0 + }, { + "z": 15, + "val": 1 + }, { + "z": 22, + "val": 1 + } + ], + }, + "bridge_service_casing": { + "color": "street_casing", + "width": [ + "stops", { + "z": 15, + "val": 1 + }, { + "z": 16, + "val": 4 + }, { + "z": 22, + "val": 4 + } + ], + }, + "bridge_service": { + "color": "street", + "width": 2, + }, + "bridge_path": { + "color": "path", + "dasharray": [ + 2, + 1 + ], + "width": [ + "stops", { + "z": 15, + "val": 1 + }, { + "z": 16, + "val": 1.2 + }, { + "z": 17, + "val": 1.5 + }, { + "z": 22, + "val": 1.5 + } + ], + }, + "bridge_major_rail": { + "color": "rail", + "width": [ + "stops", { + "z": 0, + "val": 0.4 + }, { + "z": 16, + "val": 0.75 + }, { + "z": 22, + "val": 0.75 + } + ], + }, + "bridge_major_rail_hatching": { + "color": "rail", + "dasharray": [ + 2, + 31 + ], + "width": 4, + }, + "tunnel_motorway_casing": { + "color": "motorway_casing", + "dasharray": [ + 7, + 2 + ], + "width": [ + "stops", { + "z": 6, + "val": 0.4 + }, { + "z": 7, + "val": 0.6 + }, { + "z": 8, + "val": 1.5 + }, { + "z": 10, + "val": 3 + }, { + "z": 13, + "val": 3.5 + }, { + "z": 14, + "val": 5 + }, { + "z": 15, + "val": 7 + }, { + "z": 16, + "val": 9 + }, { + "z": 22, + "val": 9 + } + ], + }, + "tunnel_motorway": { + "color": "motorway_tunnel", + "width": [ + "stops", { + "z": 7, + "val": 0 + }, { + "z": 8, + "val": 0.5 + }, { + "z": 10, + "val": 1 + }, { + "z": 13, + "val": 2 + }, { + "z": 14, + "val": 3.5 + }, { + "z": 15, + "val": 5 + }, { + "z": 16, + "val": 7 + }, { + "z": 22, + "val": 7 + } + ], + "opacity": [ + "stops", { + "z": 7, + "val": 0 + }, { + "z": 8, + "val": 1 + }, { + "z": 22, + "val": 1 + } + ], + }, + "tunnel_main_casing": { + "color": "motorway_casing", + "dasharray": [ + 7, + 2 + ], + "width": [ + "stops", { + "z": 6, + "val": 0.2 + }, { + "z": 16, + "val": 8 + }, { + "z": 22, + "val": 8 + } + ], + }, + "tunnel_main": { + "color": "main_tunnel", + "width": [ + "stops", { + "z": 8, + "val": 0.5 + }, { + "z": 10, + "val": 1 + }, { + "z": 13, + "val": 1.5 + }, { + "z": 14, + "val": 2.5 + }, { + "z": 15, + "val": 3.5 + }, { + "z": 16, + "val": 6 + }, { + "z": 22, + "val": 6 + } + ], + }, + "tunnel_motorway_link_casing": { + "color": "motorway_casing", + "width": [ + "stops", { + "z": 13, + "val": 1 + }, { + "z": 14, + "val": 3 + }, { + "z": 15, + "val": 5 + }, { + "z": 16, + "val": 6.5 + }, { + "z": 22, + "val": 6.5 + } + ], + }, + "tunnel_motorway_link": { + "color": "motorway", + "width": [ + "stops", { + "z": 14, + "val": 1.5 + }, { + "z": 15, + "val": 3 + }, { + "z": 16, + "val": 4.5 + }, { + "z": 22, + "val": 4.5 + } + ], + }, + "tunnel_street_casing": { + "color": "street_casing", + "dasharray": [ + 7, + 2 + ], + "width": [ + "stops", { + "z": 12, + "val": 0.5 + }, { + "z": 14, + "val": 1 + }, { + "z": 15, + "val": 4 + }, { + "z": 16, + "val": 6.5 + }, { + "z": 22, + "val": 6.5 + } + ], + }, + "tunnel_street": { + "color": "street", + "width": [ + "stops", { + "z": 14, + "val": 0 + }, { + "z": 15, + "val": 2.5 + }, { + "z": 16, + "val": 4 + }, { + "z": 22, + "val": 4 + } + ], + "opacity": [ + "stops", { + "z": 14, + "val": 0 + }, { + "z": 15, + "val": 1 + }, { + "z": 22, + "val": 1 + } + ], + }, + "tunnel_service_casing": { + "color": "street_casing", + "dasharray": [ + 7, + 2 + ], + "width": [ + "stops", { + "z": 15, + "val": 1 + }, { + "z": 16, + "val": 4 + }, { + "z": 22, + "val": 4 + } + ], + }, + "tunnel_service": { + "color": "street", + "width": 2, + }, + "tunnel_major_rail": { + "color": "rail", + "width": [ + "stops", { + "z": 0, + "val": 0.4 + }, { + "z": 16, + "val": 0.75 + }, { + "z": 22, + "val": 0.75 + } + ], + }, + "tunnel_major_rail_hatching": { + "color": "rail", + "dasharray": [ + 2, + 31 + ], + "width": 4, + }, + "country_label": { + "color": "text", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + }, + "country_label_line": { + "color": "text", + "width": 0.5, + "opacity": 0.5, + }, + "marin_label_1": { + "color": "marine_text", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + }, + "marin_label_2": { + "color": "marine_text", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + }, + "marin_label_3": { + "color": "marine_text", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + }, + "place_label_city_point": { + "color": "#333", + "radius": 2, + }, + "place_label_city": { + "color": "#333", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + "size": [ + "stops", { + "z": 0, + "val": 10 + }, { + "z": 10, + "val": 18 + }, { + "z": 12, + "val": 24 + } + ], + "translate": [ + 0, + 30 + ], + }, + "place_label_town": { + "color": "#333", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + "size": [ + "stops", { + "z": 0, + "val": 14 + }, { + "z": 12, + "val": 16 + }, { + "z": 14, + "val": 20 + }, { + "z": 16, + "val": 24 + } + ], + }, + "place_label_village": { + "color": "#333", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + "size": [ + "stops", { + "z": 0, + "val": 12 + }, { + "z": 12, + "val": 14 + }, { + "z": 14, + "val": 28 + }, { + "z": 16, + "val": 22 + } + ], + }, + "place_label_other": { + "color": "#633", + "stroke": [ + 1, + 1, + 1, + 0.8 + ], + "size": [ + "stops", { + "z": 0, + "val": 10 + }, { + "z": 14, + "val": 11 + }, { + "z": 15, + "val": 12 + }, { + "z": 16, + "val": 14 + } + ], + }, + "poi_label": { + "color": "#666", + "stroke": [ + 1, + 1, + 1, + 0.5 + ], + }, + "road_label": { + "color": "#765", + "stroke": [ + 1, + 1, + 1, + 0.5 + ], + "size": [ + "stops", { + "z": 0, + "val": 12 + }, { + "z": 14, + "val": 12 + }, { + "z": 15, + "val": 13 + } + ], + }, + "water_label": { + "color": "marine_text", + "stroke": [ + 1, + 1, + 1, + 0.75 + ], + }, + "poi_airport": { + "color": "maki", + "image": "airport-12", + "translate": "point_translate", + }, + "poi_restaurant": { + "color": "maki", + "image": "restaurant-12", + "translate": "point_translate", + }, + "poi_bus": { + "color": "maki", + "image": "bus-12", + "translate": "point_translate", + }, + "poi_rail": { + "color": "maki", + "image": "rail-12", + "translate": "point_translate", + }, + "poi_fire_station": { + "color": "maki", + "image": "fire-station-12", + "translate": "point_translate", + }, + "poi_park": { + "color": "maki", + "image": "park-12", + "translate": "point_translate", + }, + "poi_hospital": { + "color": "maki", + "image": "hospital-12", + "translate": "point_translate", + }, + "poi_playground": { + "color": "maki", + "image": "playground-12", + "translate": "point_translate", + }, + "poi_cafe": { + "color": "maki", + "image": "cafe-12", + "translate": "point_translate", + }, + "poi_beer": { + "color": "maki", + "image": "beer-12", + "translate": "point_translate", } } - ] + }], + "sprite": "/img/maki-sprite" }; diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index c611f56d4..03d894597 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -62,6 +63,7 @@ private: void setupShaders(); void renderLayers(const std::shared_ptr& tile, const std::vector& layers); void renderLayer(const std::shared_ptr& tile_data, const LayerDescription& layer_desc); + void translateLayer(std::array translation, bool reverse = false); void renderDebug(const std::shared_ptr& tile); void useProgram(uint32_t program); @@ -97,6 +99,7 @@ private: std::unique_ptr pointShader; std::unique_ptr rasterShader; std::unique_ptr textShader; + std::unique_ptr dotShader; // Set up the stencil quad we're using to generate the stencil mask. VertexBuffer tileStencilBuffer = { diff --git a/include/llmr/renderer/point_bucket.hpp b/include/llmr/renderer/point_bucket.hpp index e615f7ffe..6bbaaac8a 100644 --- a/include/llmr/renderer/point_bucket.hpp +++ b/include/llmr/renderer/point_bucket.hpp @@ -19,6 +19,7 @@ class Style; class PointVertexBuffer; class BucketDescription; class PointShader; +class DotShader; struct pbf; class PointBucket : public Bucket { @@ -33,6 +34,7 @@ public: bool hasPoints() const; void drawPoints(PointShader& shader); + void drawPoints(DotShader& shader); public: const BucketGeometryDescription geometry; diff --git a/include/llmr/shader/dot_shader.hpp b/include/llmr/shader/dot_shader.hpp new file mode 100644 index 000000000..5e817c09c --- /dev/null +++ b/include/llmr/shader/dot_shader.hpp @@ -0,0 +1,33 @@ +#ifndef LLMR_SHADER_SHADER_DOT +#define LLMR_SHADER_SHADER_DOT + +#include + +namespace llmr { + + class DotShader : public Shader { + public: + DotShader(); + + void bind(char *offset); + + void setColor(const std::array& color); + void setSize(float size); + void setBlur(float blur); + + private: + int32_t a_pos = -1; + + std::array color = {{}}; + int32_t u_color = -1; + + float size = 0; + int32_t u_size = -1; + + float blur = 0; + int32_t u_blur = -1; +}; + +} + +#endif diff --git a/include/llmr/shader/line_shader.hpp b/include/llmr/shader/line_shader.hpp index bbf8d1ea5..234c70a64 100644 --- a/include/llmr/shader/line_shader.hpp +++ b/include/llmr/shader/line_shader.hpp @@ -21,7 +21,7 @@ public: private: int32_t a_pos = -1; int32_t a_extrude = -1; - // int32_t a_linesofar = -1; + int32_t a_linesofar = -1; std::array exmatrix = {{}}; int32_t u_exmatrix = -1; diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 8baa6cfef..e68239025 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -56,38 +56,49 @@ struct FunctionProperty { struct PointClass { FunctionProperty enabled = true; + std::array translate = {{ 0, 0 }}; FunctionProperty size; Color color = {{ 0, 0, 0, 1 }}; FunctionProperty opacity = 1; std::string image; + FunctionProperty radius = 0; + FunctionProperty blur = 0; }; struct PointProperties { bool enabled = true; + std::array translate = {{ 0, 0 }}; float size = 0; Color color = {{ 0, 0, 0, 1 }}; float opacity = 1.0; std::string image; + float radius = 0; + float blur = 0; }; struct LineClass { FunctionProperty enabled = true; + std::array translate = {{ 0, 0 }}; FunctionProperty width; FunctionProperty offset; Color color = {{ 0, 0, 0, 1 }}; + std::array dash_array = {{ 1, -1 }}; FunctionProperty opacity = 1; }; struct LineProperties { bool enabled = true; + std::array translate = {{ 0, 0 }}; float width = 0; float offset = 0; Color color = {{ 0, 0, 0, 1 }}; + std::array dash_array = {{ 1, -1 }}; float opacity = 1.0; }; struct FillClass { FunctionProperty enabled = true; + std::array translate = {{ 0, 0 }}; Winding winding = Winding::NonZero; FunctionProperty antialias = true; Color fill_color = {{ 0, 0, 0, 1 }}; @@ -98,6 +109,7 @@ struct FillClass { struct FillProperties { bool enabled = true; + std::array translate = {{ 0, 0 }}; Winding winding = Winding::NonZero; bool antialias = true; Color fill_color = {{ 0, 0, 0, 1 }}; @@ -108,6 +120,7 @@ struct FillProperties { struct TextClass { FunctionProperty enabled = true; + std::array translate = {{ 0, 0 }}; Color color = {{ 0, 0, 0, 1 }}; Color halo = {{ 1, 1, 1, 0.75 }}; FunctionProperty haloRadius = 0.25f; @@ -118,6 +131,7 @@ struct TextClass { struct TextProperties { bool enabled = true; + std::array translate = {{ 0, 0 }}; Color color = {{ 0, 0, 0, 1 }}; Color halo = {{ 1, 1, 1, 0.75 }}; float haloRadius = 0.25f; @@ -138,11 +152,13 @@ struct BackgroundProperties { struct RasterClass { FunctionProperty enabled = true; + std::array translate = {{ 0, 0 }}; FunctionProperty opacity = 1; }; struct RasterProperties { bool enabled = true; + std::array translate = {{ 0, 0 }}; float opacity = 1.0; }; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index a096a81a8..25a7fd3b0 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -13,13 +13,13 @@ public: void parseBuckets(JSVal value, std::map& buckets); void parseLayers(JSVal value, std::vector& layers); void parseConstants(JSVal value); - void parseClasses(JSVal value, std::map& classes); + void parseClasses(JSVal value, std::map& classes, std::map& buckets, std::vector& layers); private: LayerDescription parseLayer(JSVal value); BucketDescription parseBucket(JSVal value); - std::pair parseClassDescription(JSVal value); - void parseClass(const std::string& name, JSVal value, ClassDescription& class_desc); + std::pair parseClassDescription(JSVal value, std::map& buckets, std::vector& layers); + void parseClass(const std::string& name, JSVal value, ClassDescription& class_desc, std::map& buckets, std::vector& layers); FillClass parseFillClass(JSVal value); LineClass parseLineClass(JSVal value); PointClass parsePointClass(JSVal value); @@ -29,6 +29,8 @@ private: bool parseBoolean(JSVal value); std::string parseString(JSVal value); + const JSVal& replaceConstant(const JSVal& value); + std::vector parseArray(JSVal value, uint16_t expected_count); Color parseColor(JSVal value); Value parseValue(JSVal value); FunctionProperty::fn parseFunctionType(JSVal type); diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 48fc24718..26af27f67 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -61,7 +61,11 @@ void TileParser::parseStyleLayers(const std::vector& layers) { auto bucket_it = tile.buckets.find(layer_desc.bucket_name); if (bucket_it == tile.buckets.end()) { auto bucket_it = style.buckets.find(layer_desc.bucket_name); - if (bucket_it != style.buckets.end()) { + if (layer_desc.bucket_name == "background") { + // background is a special, fake bucket + continue; + } + else if (bucket_it != style.buckets.end()) { // Only create the new bucket if we have an actual specification // for it. std::unique_ptr bucket = createBucket(bucket_it->second); diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index ab6a2ec3e..bcc8c2d9b 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -28,24 +28,18 @@ VectorTileFeature::VectorTileFeature(pbf feature, const VectorTileLayer& layer) uint32_t tag_key = tags.varint(); if (layer.keys.size() <= tag_key) { - // TODO: Throw correct exception - fprintf(stderr, "feature referenced out of range key\n"); - break; + throw std::runtime_error("feature referenced out of range key"); } if (tags) { uint32_t tag_val = tags.varint(); if (layer.values.size() <= tag_val) { - // TODO: Throw correct exception - fprintf(stderr, "feature referenced out of range value\n"); - break; + throw std::runtime_error("feature referenced out of range value"); } properties.emplace(layer.keys[tag_key], layer.values[tag_val]); } else { - // TODO: Throw correct exception - fprintf(stderr, "uneven number of feature tag ids\n"); - break; + throw std::runtime_error("uneven number of feature tag ids"); } } } else if (feature.tag == 3) { // type diff --git a/src/platform/platform.cpp b/src/platform/platform.cpp index 6f3610546..461a77053 100644 --- a/src/platform/platform.cpp +++ b/src/platform/platform.cpp @@ -1,3 +1,3 @@ #include -const char *llmr::kSpriteURL = "http://mapbox-kkaefer.s3.amazonaws.com/static/sprite"; +const char *llmr::kSpriteURL = "http://mapbox-kkaefer.s3.amazonaws.com/static/osm-bright-gl/sprite"; diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 4eadd3c9d..0915e790f 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -48,6 +48,7 @@ void Painter::setup() { assert(patternShader); assert(rasterShader); assert(textShader); + assert(dotShader); // Blending @@ -76,6 +77,7 @@ void Painter::setupShaders() { pointShader = std::make_unique(); rasterShader = std::make_unique(); textShader = std::make_unique(); + dotShader = std::make_unique(); } void Painter::resize() { @@ -255,6 +257,20 @@ void Painter::renderLayer(const std::shared_ptr& tile_data, const Laye } } +void Painter::translateLayer(std::array translation, bool reverse) { + if (translation[0] || translation[1]) { + if (reverse) { + translation[0] *= -1; + translation[1] *= -1; + } + matrix::translate(matrix, + matrix, + translation[0] / map.getState().getPixelRatio(), + translation[1] / map.getState().getPixelRatio(), + 0); + } +} + void Painter::renderRaster(const std::string& layer_name, const std::shared_ptr& tile_data) { if (pass == Opaque) return; @@ -308,6 +324,8 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons stroke_color = fill_color; } + translateLayer(properties.translate); + gl::group group(layer_name + " (fill)"); // Because we're drawing top-to-bottom, and we update the stencil mask // below, we have to draw the outline first (!) @@ -410,6 +428,8 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons glDepthRange(strata + strata_epsilon, 1.0f); bucket.drawVertices(*outlineShader); } + + translateLayer(properties.translate, true); } void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& /*id*/) { @@ -438,6 +458,10 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons color[2] *= properties.opacity; color[3] *= properties.opacity; + float dash_length = properties.dash_array[0]; + float dash_gap = properties.dash_array[1]; + + translateLayer(properties.translate); gl::group group(layer_name + " (line)"); glDepthRange(strata, 1.0f); @@ -486,16 +510,14 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons useProgram(lineShader->program); lineShader->setMatrix(matrix); lineShader->setExtrudeMatrix(extrudeMatrix); - - // TODO: Move this to transform? - const float tilePixelRatio = map.getState().getScale() / (1 << map.getState().getIntegerZoom()) / 8; - - lineShader->setDashArray({{ 1, -1 }}); + lineShader->setDashArray({{ dash_length, dash_gap }}); lineShader->setLineWidth({{ outset, inset }}); - lineShader->setRatio(tilePixelRatio); + lineShader->setRatio(map.getState().getPixelRatio()); lineShader->setColor(color); bucket.drawLines(*lineShader); } + + translateLayer(properties.translate, true); } void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, const Tile::ID& /*id&*/) { @@ -510,8 +532,7 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co const PointProperties& properties = point_properties_it->second; if (!properties.enabled) return; - auto &sprite = map.getStyle().sprite; - if (!sprite || !sprite->isLoaded()) return; + translateLayer(properties.translate); gl::group group(layer_name + " (point)"); @@ -521,32 +542,58 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co color[2] *= properties.opacity; color[3] *= properties.opacity; - std::string sized_image = properties.image; - sized_image.append("-"); - sized_image.append(std::to_string(static_cast(std::round(properties.size)))); + auto &sprite = map.getStyle().sprite; + ImagePosition imagePos; - ImagePosition imagePos = sprite->getPosition(sized_image, false); - - // fprintf(stderr, "%f/%f => %f/%f\n", imagePos.tl.x, imagePos.tl.y, imagePos.br.x, imagePos.br.y); - - useProgram(pointShader->program); - pointShader->setMatrix(matrix); - pointShader->setImage(0); - pointShader->setColor(color); - const float pointSize = properties.size * 1.4142135623730951 * map.getState().getPixelRatio(); -#if defined(GL_ES_VERSION_2_0) - pointShader->setSize(pointSize); -#else - glPointSize(pointSize); - glEnable(GL_POINT_SPRITE); -#endif - pointShader->setPointTopLeft({{ imagePos.tl.x, imagePos.tl.y }}); - pointShader->setPointBottomRight({{ imagePos.br.x, imagePos.br.y }}); - if (sprite->raster->isLoaded()) { - sprite->raster->bind(map.getState().isChanging()); + if (properties.image.length() && sprite && sprite->isLoaded()) { + std::string sized_image = properties.image; + if (properties.size) { + sized_image.append("-"); + sized_image.append(std::to_string(static_cast(std::round(properties.size)))); + } + imagePos = sprite->getPosition(sized_image, false); } - glDepthRange(strata, 1.0f); - bucket.drawPoints(*pointShader); + + if (!imagePos.size) { + useProgram(dotShader->program); + dotShader->setMatrix(matrix); + dotShader->setColor(color); + + const float pointSize = (properties.radius ? properties.radius * 2 : 8) * map.getState().getPixelRatio(); +#if defined(GL_ES_VERSION_2_0) + dotShader->setSize(pointSize); +#else + glPointSize(pointSize); + glEnable(GL_POINT_SPRITE); +#endif + dotShader->setBlur((properties.blur ? properties.blur : 1.5) / pointSize); + + glDepthRange(strata, 1.0f); + bucket.drawPoints(*dotShader); + } else { + useProgram(pointShader->program); + pointShader->setMatrix(matrix); + pointShader->setColor(color); + + pointShader->setImage(0); + pointShader->setPointTopLeft({{ imagePos.tl.x, imagePos.tl.y }}); + pointShader->setPointBottomRight({{ imagePos.br.x, imagePos.br.y }}); + + sprite->raster->bind(map.getState().isChanging()); + + const float pointSize = (properties.size ? properties.size : (imagePos.size.x / map.getState().getPixelRatio())) * 1.4142135623730951 * map.getState().getPixelRatio(); +#if defined(GL_ES_VERSION_2_0) + pointShader->setSize(pointSize); +#else + glPointSize(pointSize); + glEnable(GL_POINT_SPRITE); +#endif + + glDepthRange(strata, 1.0f); + bucket.drawPoints(*pointShader); + } + + translateLayer(properties.translate, true); } void Painter::renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& /*id*/) { @@ -561,6 +608,8 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons const TextProperties& properties = text_properties_it->second; if (!properties.enabled) return; + translateLayer(properties.translate); + gl::group group(layer_name + " (text)"); mat4 exMatrix; @@ -654,6 +703,8 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons textShader->setBuffer((256.0f - 64.0f) / 256.0f); glDepthRange(strata + strata_epsilon, 1.0f); bucket.drawGlyphs(*textShader); + + translateLayer(properties.translate, true); } void Painter::renderDebug(const TileData::Ptr& tile_data) { diff --git a/src/renderer/point_bucket.cpp b/src/renderer/point_bucket.cpp index 53e9566d0..d662595c2 100644 --- a/src/renderer/point_bucket.cpp +++ b/src/renderer/point_bucket.cpp @@ -50,3 +50,9 @@ void PointBucket::drawPoints(PointShader& shader) { array.bind(shader, vertexBuffer, vertex_index); glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start)); } + +void PointBucket::drawPoints(DotShader& shader) { + char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); + array.bind(shader, vertexBuffer, vertex_index); + glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start)); +} diff --git a/src/shader/dot.fragment.glsl b/src/shader/dot.fragment.glsl new file mode 100644 index 000000000..3f1d5a234 --- /dev/null +++ b/src/shader/dot.fragment.glsl @@ -0,0 +1,9 @@ +uniform vec4 u_color; +uniform float u_blur; + +void main() { + float dist = length(gl_PointCoord - 0.5); + float t = smoothstep(0.5, 0.5 - u_blur, dist); + + gl_FragColor = u_color * t; +} diff --git a/src/shader/dot.vertex.glsl b/src/shader/dot.vertex.glsl new file mode 100644 index 000000000..a0d64c33b --- /dev/null +++ b/src/shader/dot.vertex.glsl @@ -0,0 +1,9 @@ +attribute vec2 a_pos; + +uniform mat4 u_matrix; +uniform float u_size; + +void main(void) { + gl_Position = u_matrix * vec4(a_pos, 0, 1); + gl_PointSize = u_size; +} diff --git a/src/shader/dot_shader.cpp b/src/shader/dot_shader.cpp new file mode 100644 index 000000000..df2a6924f --- /dev/null +++ b/src/shader/dot_shader.cpp @@ -0,0 +1,57 @@ +#include +#include +#include + +#include + +using namespace llmr; + +DotShader::DotShader() +: Shader( + shaders[DOT_SHADER].vertex, + shaders[DOT_SHADER].fragment + ) { + if (!valid) { + fprintf(stderr, "invalid dot shader\n"); + return; + } + + a_pos = glGetAttribLocation(program, "a_pos"); + + u_matrix = glGetUniformLocation(program, "u_matrix"); + u_color = glGetUniformLocation(program, "u_color"); + u_size = glGetUniformLocation(program, "u_size"); + u_blur = glGetUniformLocation(program, "u_blur"); + + // fprintf(stderr, "PointShader:\n"); + // fprintf(stderr, " - u_matrix: %d\n", u_matrix); + // fprintf(stderr, " - u_color: %d\n", u_color); + // fprintf(stderr, " - u_size: %d\n", u_size); + // fprintf(stderr, " - u_blur: %d\n", u_blur); +} + +void DotShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); +} + +void DotShader::setColor(const std::array& new_color) { + if (color != new_color) { + glUniform4fv(u_color, 1, new_color.data()); + color = new_color; + } +} + +void DotShader::setSize(float new_size) { + if (size != new_size) { + glUniform1f(u_size, new_size); + size = new_size; + } +} + +void DotShader::setBlur(float new_blur) { + if (blur != new_blur) { + glUniform1f(u_blur, new_blur); + blur = new_blur; + } +} diff --git a/src/shader/line.fragment.glsl b/src/shader/line.fragment.glsl index de08ac76b..ca8fed9bb 100644 --- a/src/shader/line.fragment.glsl +++ b/src/shader/line.fragment.glsl @@ -4,7 +4,7 @@ uniform vec4 u_color; uniform vec2 u_dasharray; varying vec2 v_normal; -// varying float v_linesofar; +varying float v_linesofar; void main() { // Calculate the distance of the pixel from the line in pixels. @@ -17,8 +17,8 @@ void main() { // Calculate the antialiasing fade factor based on distance to the dash. // Only affects alpha when line is dashed - // float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y); - // alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0)); + float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y); + alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0)); gl_FragColor = u_color * alpha; } \ No newline at end of file diff --git a/src/shader/line.vertex.glsl b/src/shader/line.vertex.glsl index 17c927810..14be3c4eb 100644 --- a/src/shader/line.vertex.glsl +++ b/src/shader/line.vertex.glsl @@ -8,7 +8,7 @@ attribute vec2 a_pos; attribute vec2 a_extrude; -// attribute float a_linesofar; +attribute float a_linesofar; // posmatrix is for the vertex position, exmatrix is for rotating and projecting // the extrusion vector. @@ -21,7 +21,7 @@ uniform vec2 u_linewidth; uniform vec4 u_color; varying vec2 v_normal; -// varying float v_linesofar; +varying float v_linesofar; void main() { // We store the texture normals in the most insignificant bit @@ -41,5 +41,5 @@ void main() { // because we're extruding the line in pixel space, regardless of the current // tile's zoom level. gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0) + u_exmatrix * dist; - // v_linesofar = a_linesofar * u_ratio; + v_linesofar = a_linesofar * u_ratio; } \ No newline at end of file diff --git a/src/shader/line_shader.cpp b/src/shader/line_shader.cpp index 67536be6c..031e1002e 100644 --- a/src/shader/line_shader.cpp +++ b/src/shader/line_shader.cpp @@ -18,7 +18,7 @@ LineShader::LineShader() a_pos = glGetAttribLocation(program, "a_pos"); a_extrude = glGetAttribLocation(program, "a_extrude"); - // a_linesofar = glGetAttribLocation(program, "a_linesofar"); + a_linesofar = glGetAttribLocation(program, "a_linesofar"); u_matrix = glGetUniformLocation(program, "u_matrix"); u_exmatrix = glGetUniformLocation(program, "u_exmatrix"); @@ -38,13 +38,13 @@ LineShader::LineShader() void LineShader::bind(char *offset) { glEnableVertexAttribArray(a_pos); - glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset); - - // glEnableVertexAttribArray(a_linesofar); - // glVertexAttribPointer(a_linesofar, 1, GL_SHORT, false, 8, offset + 6); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset + 0); glEnableVertexAttribArray(a_extrude); glVertexAttribPointer(a_extrude, 2, GL_BYTE, false, 8, offset + 4); + + glEnableVertexAttribArray(a_linesofar); + glVertexAttribPointer(a_linesofar, 1, GL_SHORT, false, 8, offset + 6); } void LineShader::setExtrudeMatrix(const std::array& new_exmatrix) { diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index 5bc95082d..32f8af081 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -7,8 +7,12 @@ using namespace llmr; const shader_source llmr::shaders[SHADER_COUNT] = { { - "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n}\n\n", - "#version 120\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nvarying vec2 v_normal;\nvoid main ()\n{\n float tmpvar_1;\n tmpvar_1 = (sqrt(dot (v_normal, v_normal)) * u_linewidth.x);\n gl_FragColor = (u_color * clamp (min (\n (tmpvar_1 - (u_linewidth.y - 1.0))\n , \n (u_linewidth.x - tmpvar_1)\n ), 0.0, 1.0));\n}\n\n", + "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", + "#version 120\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", + }, + { + "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", + "#version 120\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform vec2 u_dasharray;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n float tmpvar_1;\n tmpvar_1 = (sqrt(dot (v_normal, v_normal)) * u_linewidth.x);\n float tmpvar_2;\n tmpvar_2 = (float(mod (v_linesofar, (u_dasharray.x + u_dasharray.y))));\n gl_FragColor = (u_color * (clamp (\n min ((tmpvar_1 - (u_linewidth.y - 1.0)), (u_linewidth.x - tmpvar_1))\n , 0.0, 1.0) * max (\n float((-(u_dasharray.y) >= 0.0))\n , \n clamp (min (tmpvar_2, (u_dasharray.x - tmpvar_2)), 0.0, 1.0)\n )));\n}\n\n", }, { "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform vec2 u_world;\nuniform float u_size;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = floor((a_pos / 2.0));\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = ((tmpvar_2.xy + 1.0) * u_world);\n gl_PointSize = u_size;\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index e30b650bd..cd247a9e5 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -7,8 +7,12 @@ using namespace llmr; const shader_source llmr::shaders[SHADER_COUNT] = { { - "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n}\n\n", - "precision highp float;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nvarying vec2 v_normal;\nvoid main ()\n{\n float tmpvar_1;\n tmpvar_1 = (sqrt(dot (v_normal, v_normal)) * u_linewidth.x);\n gl_FragColor = (u_color * clamp (min (\n (tmpvar_1 - (u_linewidth.y - 1.0))\n , \n (u_linewidth.x - tmpvar_1)\n ), 0.0, 1.0));\n}\n\n", + "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", + "precision highp float;\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n mediump vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n mediump float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", + }, + { + "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", + "precision highp float;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform vec2 u_dasharray;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n float tmpvar_1;\n tmpvar_1 = (sqrt(dot (v_normal, v_normal)) * u_linewidth.x);\n float tmpvar_2;\n tmpvar_2 = (float(mod (v_linesofar, (u_dasharray.x + u_dasharray.y))));\n gl_FragColor = (u_color * (clamp (\n min ((tmpvar_1 - (u_linewidth.y - 1.0)), (u_linewidth.x - tmpvar_1))\n , 0.0, 1.0) * max (\n float((-(u_dasharray.y) >= 0.0))\n , \n clamp (min (tmpvar_2, (u_dasharray.x - tmpvar_2)), 0.0, 1.0)\n )));\n}\n\n", }, { "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform vec2 u_world;\nuniform float u_size;\nvarying highp vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = floor((a_pos / 2.0));\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = ((tmpvar_2.xy + 1.0) * u_world);\n gl_PointSize = u_size;\n}\n\n", diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index 408ed11f0..cf8f3ffed 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -96,7 +96,7 @@ void Sprite::parseJSON(std::shared_ptr &sprite) { if (value.HasMember("y")) y = value["y"].GetInt(); if (value.HasMember("width")) width = value["width"].GetInt(); if (value.HasMember("height")) height = value["height"].GetInt(); - if (value.HasMember("pixelRatio")) pixelRatio = value["height"].GetInt(); + if (value.HasMember("pixelRatio")) pixelRatio = value["pixelRatio"].GetInt(); sprite->pos.insert({ name, { x, y, width, height, pixelRatio } }); } diff --git a/src/style/style.cpp b/src/style/style.cpp index ad85c7f1a..9c766419b 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -38,6 +38,8 @@ void Style::cascade(float z) { // values so as to not override with default values. llmr::FillProperties& fill = computed.fills[layer_name]; fill.enabled = layer.enabled.evaluate(z); + fill.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; fill.winding = layer.winding; fill.antialias = layer.antialias.evaluate(z); fill.fill_color = layer.fill_color; @@ -55,9 +57,13 @@ void Style::cascade(float z) { // values so as to not override with default values. llmr::LineProperties& stroke = computed.lines[layer_name]; stroke.enabled = layer.enabled.evaluate(z); + stroke.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; stroke.width = layer.width.evaluate(z); stroke.offset = layer.offset.evaluate(z); stroke.color = layer.color; + stroke.dash_array = {{ layer.dash_array[0].evaluate(z), + layer.dash_array[1].evaluate(z) }}; stroke.opacity = layer.opacity.evaluate(z); } @@ -70,10 +76,14 @@ void Style::cascade(float z) { // values so as to not override with default values. llmr::PointProperties& point = computed.points[layer_name]; point.enabled = layer.enabled.evaluate(z); + point.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; point.color = layer.color; point.size = layer.size.evaluate(z); point.opacity = layer.opacity.evaluate(z); point.image = layer.image; + point.radius = layer.radius.evaluate(z); + point.blur = layer.blur.evaluate(z); } // Cascade text classes @@ -85,6 +95,8 @@ void Style::cascade(float z) { // values so as to not override with default values. llmr::TextProperties& text = computed.texts[layer_name]; text.enabled = layer.enabled.evaluate(z); + text.translate = {{ layer.translate[0].evaluate(z), + layer.translate[1].evaluate(z) }}; text.color = layer.color; text.size = layer.size.evaluate(z); text.halo = layer.halo; @@ -146,7 +158,7 @@ void Style::loadJSON(const uint8_t *const data, size_t bytes) { } if (document.HasMember("classes")) { - parser.parseClasses(document["classes"], classes); + parser.parseClasses(document["classes"], classes, buckets, layers); } } else { throw Style::exception("stylesheet root must be an object"); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 9064b3ac6..081dedce1 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -3,6 +3,8 @@ using namespace llmr; +using JSVal = const rapidjson::Value&; + void StyleParser::parseBuckets(JSVal value, std::map& buckets) { if (value.IsObject()) { rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); @@ -192,17 +194,17 @@ void StyleParser::parseConstants(JSVal value) { } } -void StyleParser::parseClasses(JSVal value, std::map& classes) { +void StyleParser::parseClasses(JSVal value, std::map& classes, std::map& buckets, std::vector& layers) { if (value.IsArray()) { for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - classes.insert(std::forward>(parseClassDescription(value[i]))); + classes.insert(std::forward>(parseClassDescription(value[i], buckets, layers))); } } else { throw Style::exception("classes must be an array"); } } -std::pair StyleParser::parseClassDescription(JSVal value) { +std::pair StyleParser::parseClassDescription(JSVal value, std::map& buckets, std::vector& style_layers) { ClassDescription klass; std::string klass_name; @@ -227,7 +229,7 @@ std::pair StyleParser::parseClassDescription(JSVa const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; - parseClass(name, itr->value, klass); + parseClass(name, itr->value, klass, buckets, style_layers); } } else { throw Style::exception("class layer styles must be an object"); @@ -240,32 +242,31 @@ std::pair StyleParser::parseClassDescription(JSVa return { klass_name, std::forward(klass) }; } -void StyleParser::parseClass(const std::string& name, JSVal value, ClassDescription& class_desc) { +void StyleParser::parseClass(const std::string& name, JSVal value, ClassDescription& class_desc, std::map& buckets, std::vector& layers) { if (value.IsObject()) { - if (value.HasMember("type")) { - JSVal type = value["type"]; - if (type.IsString()) { - std::string type_name = { type.GetString(), type.GetStringLength() }; - if (type_name == "fill") { - class_desc.fill.insert({ name, std::forward(parseFillClass(value)) }); - } else if (type_name == "line") { - class_desc.line.insert({ name, std::forward(parseLineClass(value)) }); - } else if (type_name == "point") { - class_desc.point.insert({ name, std::forward(parsePointClass(value)) }); - } else if (type_name == "text") { - class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); - } else if (type_name == "raster") { - class_desc.raster.insert({ name, std::forward(parseRasterClass(value)) }); - } else if (type_name == "background") { + for (const auto& layer : layers) { + if (name == layer.name) { + if (layer.bucket_name == "background") { + // background buckets are fake class_desc.background = parseBackgroundClass(value); } else { - throw Style::exception("unknown class type name"); + auto bucket_it = buckets.find(layer.bucket_name); + BucketType type = bucket_it->second.type; + if (type == BucketType::Fill) { + class_desc.fill.insert({ name, std::forward(parseFillClass(value)) }); + } else if (type == BucketType::Line) { + class_desc.line.insert({ name, std::forward(parseLineClass(value)) }); + } else if (type == BucketType::Point) { + class_desc.point.insert({ name, std::forward(parsePointClass(value)) }); + } else if (type == BucketType::Text) { + class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); + } else if (type == BucketType::Raster) { + class_desc.raster.insert({ name, std::forward(parseRasterClass(value)) }); + } else { + throw Style::exception("unknown class type name"); + } } - } else { - throw Style::exception("style class type must be a string"); } - } else { - throw Style::exception("style class must specify a type"); } } else { throw Style::exception("style class must be an object"); @@ -288,14 +289,46 @@ std::string StyleParser::parseString(JSVal value) { return { value.GetString(), value.GetStringLength() }; } +const JSVal& StyleParser::replaceConstant(const JSVal& value) { + if (value.IsString()) { + const std::string string_value { value.GetString(), value.GetStringLength() }; + auto it = constants.find(string_value); + if (it != constants.end()) { + return *it->second; + } + } + + return value; +} + +std::vector StyleParser::parseArray(JSVal value, uint16_t expected_count) { + JSVal rvalue = replaceConstant(value); + if (!rvalue.IsArray()) { + throw Style::exception("array value must be an array"); + } + + if (rvalue.IsArray() && rvalue.Size() != expected_count) { + throw Style::exception("array value has unexpected number of elements"); + } + + std::vector values; + values.reserve(expected_count); + for (uint16_t i = 0; i < expected_count; i++) { + values.push_back(parseFunction(rvalue[(rapidjson::SizeType)i])); + } + + return values; +} + Color StyleParser::parseColor(JSVal value) { - if (value.IsArray()) { + JSVal rvalue = replaceConstant(value); + if (rvalue.IsArray()) { // [ r, g, b, a] array - if (value.Size() != 4) { + if (rvalue.Size() != 4) { throw Style::exception("color array must have four elements"); } - JSVal r = value[(rapidjson::SizeType)0], g = value[1], b = value[2], a = value[3]; + JSVal r = rvalue[(rapidjson::SizeType)0], g = rvalue[1], b = rvalue[2], a = rvalue[3]; if (!r.IsNumber() || !g.IsNumber() || !b.IsNumber() || !a.IsNumber()) { throw Style::exception("color values must be numbers"); } @@ -305,20 +338,13 @@ Color StyleParser::parseColor(JSVal value) { static_cast(b.GetDouble()), static_cast(a.GetDouble())}}; - } else if (!value.IsString()) { + } else if (!rvalue.IsString()) { throw Style::exception("color value must be a string"); } - const std::string str{value.GetString(), value.GetStringLength()}; - - auto it = constants.find(str); - if (it != constants.end()) { - return parseColor(*it->second); - } else { - CSSColorParser::Color css_color = CSSColorParser::parse(str); - return {{(float)css_color.r / 255, (float)css_color.g / 255, - (float)css_color.b / 255, css_color.a}}; - } + CSSColorParser::Color css_color = CSSColorParser::parse({ rvalue.GetString(), rvalue.GetStringLength() }); + return {{(float)css_color.r / 255, (float)css_color.g / 255, + (float)css_color.b / 255, css_color.a}}; } FunctionProperty::fn StyleParser::parseFunctionType(JSVal type) { @@ -396,6 +422,11 @@ FillClass StyleParser::parseFillClass(JSVal value) { klass.enabled = parseFunction(value["enabled"]); } + if (value.HasMember("translate")) { + std::vector values = parseArray(value["translate"], 2); + klass.translate = std::array {{ values[0], values[1] }}; + } + if (value.HasMember("color")) { klass.fill_color = parseColor(value["color"]); } @@ -428,6 +459,11 @@ LineClass StyleParser::parseLineClass(JSVal value) { klass.enabled = parseFunction(value["enabled"]); } + if (value.HasMember("translate")) { + std::vector values = parseArray(value["translate"], 2); + klass.translate = std::array {{ values[0], values[1] }}; + } + if (value.HasMember("color")) { klass.color = parseColor(value["color"]); } @@ -440,6 +476,11 @@ LineClass StyleParser::parseLineClass(JSVal value) { klass.opacity = parseFunction(value["opacity"]); } + if (value.HasMember("dasharray")) { + std::vector values = parseArray(value["dasharray"], 2); + klass.dash_array = std::array {{ values[0], values[1] }}; + } + return klass; } @@ -450,6 +491,11 @@ PointClass StyleParser::parsePointClass(JSVal value) { klass.enabled = parseFunction(value["enabled"]); } + if (value.HasMember("translate")) { + std::vector values = parseArray(value["translate"], 2); + klass.translate = std::array {{ values[0], values[1] }}; + } + if (value.HasMember("color")) { klass.color = parseColor(value["color"]); } @@ -466,6 +512,14 @@ PointClass StyleParser::parsePointClass(JSVal value) { klass.size = parseFunction(value["size"]); } + if (value.HasMember("radius")) { + klass.radius = parseFunction(value["radius"]); + } + + if (value.HasMember("blur")) { + klass.blur = parseFunction(value["blur"]); + } + return klass; } @@ -477,6 +531,11 @@ TextClass StyleParser::parseTextClass(JSVal value) { klass.enabled = parseFunction(value["enabled"]); } + if (value.HasMember("translate")) { + std::vector values = parseArray(value["translate"], 2); + klass.translate = std::array {{ values[0], values[1] }}; + } + if (value.HasMember("color")) { klass.color = parseColor(value["color"]); }