diff --git a/bin/style.js b/bin/style.js index e80d76759..7ca40b612 100644 --- a/bin/style.js +++ b/bin/style.js @@ -1,3614 +1,168 @@ "use strict"; module.exports = { - "buckets": { - "admin_maritime": { - "source": "outdoors", - "layer": "admin", - "field": "maritime", - "value": 1, - "join": "round", - "cap": "round", - "type": "line" - }, - "admin_l2": { - "source": "outdoors", - "layer": "admin", - "filter": [ - "and", - {"field": "admin_level", "value": 2}, - {"field": "maritime", "operator": "not", "value": 1} - ], - "join": "round", - "cap": "round", - "type": "line" - }, - "admin_l3": { - "source": "outdoors", - "layer": "admin", - "filter": [ - "and", - {"field": "admin_level", "value": [3,4,5]}, - {"field": "maritime", "operator": "not", "value": 1} - ], - "join": "round", - "type": "line" - }, - "landcover_wood": { - "source": "outdoors", - "layer": "landcover", - "field": "class", - "value": "wood", - "type": "fill" - }, - "landcover_scrub": { - "source": "outdoors", - "layer": "landcover", - "field": "class", - "value": "scrub", - "type": "fill" - }, - "landcover_grass": { - "source": "outdoors", - "layer": "landcover", - "field": "class", - "value": "grass", - "type": "fill" - }, - "landcover_crop": { - "source": "outdoors", - "layer": "landcover", - "field": "class", - "value": "crop", - "type": "fill" - }, - "landcover_snow": { - "source": "outdoors", - "layer": "landcover", - "field": "class", - "value": "snow", - "type": "fill" - }, - "water": { - "source": "outdoors", - "layer": "water", - "type": "fill" - }, - "waterway_other": { - "source": "outdoors", - "layer": "waterway", - "field": "type", - "value": [ - "ditch", - "drain" - ], - "cap": "round", - "type": "line" - }, - "waterway_river_canal": { - "source": "outdoors", - "layer": "waterway", - "field": "type", - "value": [ - "river", - "canal" - ], - "cap": "round", - "type": "line" - }, - "waterway_stream": { - "source": "outdoors", - "layer": "waterway", - "field": "type", - "value": "stream", - "cap": "round", - "type": "line" - }, - "landuse_park": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "park", - "type": "fill" - }, - "landuse_pitch": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "pitch", - "type": "fill" - }, - "landuse_cemetery": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "cemetery", - "type": "fill" - }, - "landuse_hospital": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "hospital", - "type": "fill" - }, - "landuse_industrial": { - "source": "outdoors", - "layer": "landuse", - "type": "fill", - "field": "class", - "value": "industrial" - }, - "landuse_school": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "school", - "type": "fill" - }, - "landuse_wood": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "wood", - "type": "fill" - }, - "landuse_scrub": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "scrub", - "type": "fill" - }, - "landuse_grass": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "grass", - "type": "fill" - }, - "landuse_crop": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "crop", - "type": "fill" - }, - "landuse_sand": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "sand", - "type": "fill" - }, - "landuse_rock": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "rock", - "type": "fill" - }, - "landuse_snow": { - "source": "outdoors", - "layer": "landuse", - "field": "class", - "value": "snow", - "type": "fill" - }, - "overlay_wetland": { - "source": "outdoors", - "layer": "landuse_overlay", - "field": "class", - "value": ["wetland", "wetland_noveg"], - "type": "fill" - }, - "overlay_breakwater_pier": { - "source": "outdoors", - "layer": "landuse_overlay", - "field": "class", - "value": [ - "breakwater", - "pier" - ], - "type": "fill" - }, - "hillshade_full_shadow": { - "source": "outdoors", - "layer": "hillshade", - "field": "class", - "value": "full_shadow", - "type": "fill" - }, - "hillshade_medium_shadow": { - "source": "outdoors", - "layer": "hillshade", - "field": "class", - "value": "medium_shadow", - "type": "fill" - }, - "hillshade_medium_highlight": { - "source": "outdoors", - "layer": "hillshade", - "field": "class", - "value": "medium_highlight", - "type": "fill" - }, - "hillshade_full_highlight": { - "source": "outdoors", - "layer": "hillshade", - "field": "class", - "value": "full_highlight", - "type": "fill" - }, - "contour_line_5": { - "source": "outdoors", - "layer": "contour", - "field": "index", - "join": "round", - "value": 5, - "type": "line" - }, - "contour_line_10": { - "source": "outdoors", - "layer": "contour", - "field": "index", - "join": "round", - "value": 10, - "type": "line" - }, - "contour_line_other": { - "source": "outdoors", - "layer": "contour", - "join": "round", - "type": "line" - }, - "contour_label": { - "source": "outdoors", - "layer": "contour", - "filter": [ - "and", - { "field": "index", "value": [ 5, 10 ] }, - { "field": "ele", "operator": "not", "value": 0 } - ], - "path": "curve", - "text_field": "{{ele}} m", - "font": "Open Sans Regular, Arial Unicode MS Regular", - "fontSize": 10, - "feature_type": "line", - "type": "text", - "maxAngleDelta": 0.5 - }, - "building": { - "source": "outdoors", - "layer": "building", - "type": "fill" - }, - "barrier_line_gate": { - "source": "outdoors", - "layer": "barrier_line", - "field": "class", - "value": "gate", - "type": "line" - }, - "barrier_line_fence": { - "source": "outdoors", - "layer": "barrier_line", - "field": "class", - "value": "fence", - "type": "line" - }, - "barrier_line_hedge": { - "source": "outdoors", - "layer": "barrier_line", - "field": "class", - "value": "hedge", - "type": "line" - }, - "barrier_line_land": { - "source": "outdoors", - "layer": "barrier_line", - "field": "class", - "value": "land", - "type": "line" - }, - "barrier_line_land_fill": { - "source": "outdoors", - "layer": "barrier_line", - "field": "class", - "value": "land", - "type": "fill" - }, - "barrier_line_cliff": { - "source": "outdoors", - "layer": "barrier_line", - "field": "class", - "value": "cliff", - "type": "line" - }, - "aeroway_fill": { - "source": "outdoors", - "layer": "aeroway", - "type": "fill", - "enabled": 12 - }, - "aeroway_runway": { - "source": "outdoors", - "layer": "aeroway", - "field": "type", - "value": "runway", - "type": "line", - "enabled": 12 - }, - "aeroway_taxiway": { - "source": "outdoors", - "layer": "aeroway", - "field": "type", - "value": "taxiway", - "type": "line", - "enabled": 12 - }, - "motorway": { - "source": "outdoors", - "layer": "road", - "field": "class", - "value": "motorway", - "join": "round", - "cap": "round", - "type": "line" - }, - "motorway_link": { - "source": "outdoors", - "layer": "road", - "field": "class", - "value": "motorway_link", - "join": "round", - "cap": "round", - "type": "line" - }, - "main": { - "source": "outdoors", - "layer": "road", - "field": "class", - "value": "main", - "join": "round", - "cap": "round", - "type": "line" - }, - "street": { - "source": "outdoors", - "layer": "road", - "field": "class", - "value": [ - "street", - "street_limited" - ], - "join": "round", - "cap": "round", - "type": "line", - "enabled": 12 - }, - "service": { - "source": "outdoors", - "layer": "road", - "field": "class", - "value": "service", - "join": "round", - "cap": "round", - "type": "line", - "enabled": 15 - }, - "path": { - "source": "outdoors", - "layer": "road", - "field": "class", - "value": "path", - "type": "line" - }, - "path_footway": { - "source": "outdoors", - "layer": "road", - "field": "type", - "value": "footway", - "type": "line" - }, - "path_path": { - "source": "outdoors", - "layer": "road", - "field": "type", - "value": "path", - "type": "line" - }, - "path_cycleway": { - "source": "outdoors", - "layer": "road", - "field": "type", - "value": "cycleway", - "type": "line" - }, - "path_mtb": { - "source": "outdoors", - "layer": "road", - "field": "type", - "value": "mtb", - "type": "line" - }, - "path_steps": { - "source": "outdoors", - "layer": "road", - "field": "type", - "value": "steps", - "type": "line" - }, - "path_piste": { - "source": "outdoors", - "layer": "road", - "field": "type", - "value": "piste", - "type": "line" - }, - "major_rail": { - "source": "outdoors", - "layer": "road", - "field": "class", - "value": "major_rail", - "type": "line" - }, - "tunnel_motorway": { - "source": "outdoors", - "layer": "tunnel", - "field": "class", - "value": "motorway", - "type": "line" - }, - "tunnel_motorway_link": { - "source": "outdoors", - "layer": "tunnel", - "field": "class", - "value": "motorway_link", - "type": "line" - }, - "tunnel_main": { - "source": "outdoors", - "layer": "tunnel", - "field": "class", - "value": "main", - "type": "line" - }, - "tunnel_street": { - "source": "outdoors", - "layer": "tunnel", - "field": "class", - "value": [ - "street", - "street_limited" - ], - "type": "line", - "enabled": 12 - }, - "tunnel_service": { - "source": "outdoors", - "layer": "tunnel", - "field": "class", - "value": "service", - "type": "line", - "enabled": 15 - }, - "tunnel_path": { - "source": "outdoors", - "layer": "tunnel", - "field": "class", - "value": "path", - "type": "line" - }, - "tunnel_path_footway": { - "source": "outdoors", - "layer": "tunnel", - "field": "type", - "value": "footway", - "type": "line" - }, - "tunnel_path_path": { - "source": "outdoors", - "layer": "tunnel", - "field": "type", - "value": "path", - "type": "line" - }, - "tunnel_path_cycleway": { - "source": "outdoors", - "layer": "tunnel", - "field": "type", - "value": "cycleway", - "type": "line" - }, - "tunnel_path_mtb": { - "source": "outdoors", - "layer": "tunnel", - "field": "type", - "value": "mtb", - "type": "line" - }, - "tunnel_path_steps": { - "source": "outdoors", - "layer": "tunnel", - "field": "type", - "value": "steps", - "type": "line" - }, - "tunnel_path_piste": { - "source": "outdoors", - "layer": "tunnel", - "field": "type", - "value": "piste", - "type": "line" - }, - "tunnel_major_rail": { - "source": "outdoors", - "layer": "tunnel", - "field": "class", - "value": "major_rail", - "type": "line" - }, - "bridge_motorway": { - "source": "outdoors", - "layer": "bridge", - "field": "class", - "value": "motorway", - "type": "line" - }, - "bridge_motorway_link": { - "source": "outdoors", - "layer": "bridge", - "field": "class", - "value": "motorway_link", - "type": "line" - }, - "bridge_main": { - "source": "outdoors", - "layer": "bridge", - "field": "class", - "value": "main", - "type": "line" - }, - "bridge_street": { - "source": "outdoors", - "layer": "bridge", - "field": "class", - "value": [ - "street", - "street_limited" - ], - "type": "line", - "enabled": 12 - }, - "bridge_service": { - "source": "outdoors", - "layer": "bridge", - "field": "class", - "value": "service", - "type": "line", - "enabled": 15 - }, - "bridge_path": { - "source": "outdoors", - "layer": "bridge", - "type": "line" - }, - "bridge_path_footway": { - "source": "outdoors", - "layer": "bridge", - "field": "type", - "value": "footway", - "type": "line" - }, - "bridge_path_path": { - "source": "outdoors", - "layer": "bridge", - "field": "type", - "value": "path", - "type": "line" - }, - "bridge_path_cycleway": { - "source": "outdoors", - "layer": "bridge", - "field": "type", - "value": "cycleway", - "type": "line" - }, - "bridge_path_mtb": { - "source": "outdoors", - "layer": "bridge", - "field": "type", - "value": "mtb", - "type": "line" - }, - "bridge_path_steps": { - "source": "outdoors", - "layer": "bridge", - "field": "type", - "value": "steps", - "type": "line" - }, - "bridge_path_piste": { - "source": "outdoors", - "layer": "bridge", - "field": "type", - "value": "piste", - "type": "line" - }, - "bridge_major_rail": { - "source": "outdoors", - "layer": "bridge", - "field": "class", - "value": "major_rail", - "type": "line" - }, - "bridge_aerialway": { - "source": "outdoors", - "layer": "bridge", - "field": "class", - "value": "aerialway", - "type": "line" - }, - "country_label": { - "source": "outdoors", - "layer": "country_label", - "text_field": "{{name_en}}", - "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 24, - "feature_type": "point", - "type": "text", - "maxWidth": 5 - }, - "country_label_line": { - "source": "outdoors", - "layer": "country_label_line", - "type": "line" - }, - "marine_label_line_1": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "line", - "type": "text", - "field": "labelrank", - "value": 1, - "text_field": "{{name_en}}", - "path": "curve", - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 30, - "letterSpacing": 0.4, - "maxAngleDelta": 0.5 - }, - "marine_label_line_2": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "line", - "field": "labelrank", - "value": 2, - "type": "text", - "text_field": "{{name_en}}", - "path": "curve", - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 24, - "letterSpacing": 0.2, - "maxAngleDelta": 0.5 - }, - "marine_label_line_3": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "line", - "type": "text", - "field": "labelrank", - "value": 3, - "text_field": "{{name_en}}", - "path": "curve", - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 18, - "letterSpacing": 0.1, - "maxAngleDelta": 0.5 - }, - "marine_label_line_other": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "line", - "type": "text", - "field": "labelrank", - "value": [4, 5, 6], - "text_field": "{{name_en}}", - "path": "curve", - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 16, - "letterSpacing": 0.1, - "maxAngleDelta": 0.5 - }, - "marine_label_point_1": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "point", - "type": "text", - "text_field": "{{name_en}}", - "path": "horizontal", - "field": "labelrank", - "value": 1, - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 30, - "maxWidth": 8, - "letterSpacing": 0.4, - "lineHeight": 2 - }, - "marine_label_point_2": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "point", - "type": "text", - "text_field": "{{name_en}}", - "path": "horizontal", - "field": "labelrank", - "value": 2, - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 24, - "maxWidth": 8, - "letterSpacing": 0.2, - "lineHeight": 1.5 - }, - "marine_label_point_3": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "point", - "type": "text", - "text_field": "{{name_en}}", - "path": "horizontal", - "field": "labelrank", - "value": 3, - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 18, - "maxWidth": 8, - "letterSpacing": 0.1, - "lineHeight": 1.3 - }, - "marine_label_point_other": { - "source": "outdoors", - "layer": "marine_label", - "feature_type": "point", - "type": "text", - "text_field": "{{name_en}}", - "path": "horizontal", - "field": "labelrank", - "value": [4,5,6], - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 16, - "maxWidth": 8, - "letterSpacing": 0.1, - "lineHeight": 1.2 - }, - "state_label": { - "source": "outdoors", - "layer": "state_label", - "text_field": "{{name_en}}", - "path": "horizontal", - "font": "Open Sans Regular, Arial Unicode MS Regular", - "fontSize": 16, - "feature_type": "point", - "type": "text", - "enabled": 4, - "maxWidth": 8 - }, - "place_label_city": { - "source": "outdoors", - "layer": "place_label", - "field": "type", - "value": "city", - "text_field": "{{name_en}}", - "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 20, - "feature_type": "point", - "type": "text", - "maxWidth": 8 - }, - "place_label_town": { - "source": "outdoors", - "layer": "place_label", - "field": "type", - "value": "town", - "text_field": "{{name_en}}", - "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 24, - "feature_type": "point", - "type": "text", - "maxWidth": 8 - }, - "place_label_village": { - "source": "outdoors", - "layer": "place_label", - "field": "type", - "value": "village", - "text_field": "{{name_en}}", - "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 22, - "feature_type": "point", - "type": "text", - "maxWidth": 8 - }, - "place_label_other": { - "source": "outdoors", - "layer": "place_label", - "field": "type", - "value": [ - "hamlet", - "suburb", - "neighbourhood" - ], - "text_field": "{{name_en}}", - "path": "horizontal", - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 18, - "maxWidth": 6, - "feature_type": "point", - "type": "text" - }, - "road_label_1": { - "source": "outdoors", - "layer": "road_label", - "field": "class", - "value": ["motorway","main"], - "text_field": "{{name_en}}", - "path": "curve", - "padding": 2, - "font": "Open Sans Regular, Arial Unicode MS Regular", - "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_en}}", - "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_en}}", - "path": "curve", - "padding": 2, - "font": "Open Sans Regular, Arial Unicode MS Regular", - "fontSize": 14, - "feature_type": "line", - "type": "text", - "maxAngleDelta": 0.5 - }, - "water_label": { - "source": "outdoors", - "layer": "water_label", - "text_field": "{{name_en}}", - "path": "horizontal", - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 12, - "feature_type": "point", - "type": "text", - "maxWidth": 8 - }, - "waterway_label": { - "source": "outdoors", - "layer": "waterway_label", - "text_field": "{{name_en}}", - "path": "curve", - "font": "Open Sans Semibold Italic, Arial Unicode MS Bold", - "fontSize": 12, - "feature_type": "line", - "type": "text", - "maxAngleDelta": 0.5 - }, - "poi": { - "source": "outdoors", - "layer": "poi_label", - "icon": "{{maki}}", - "field": "scalerank", - "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_4": { - "source": "outdoors", - "layer": "poi_label", - "icon": "{{maki}}", - "filter": [ - "and", - { "field": "scalerank", "value": 4 }, - { "field": "localrank", "operator": "<=", "value": 4 } - ], - "size": 12, - "type": "point" - }, - "poi_4_16": { - "source": "outdoors", - "layer": "poi_label", - "icon": "{{maki}}", - "filter": [ - "and", - { "field": "scalerank", "value": 4 }, - { "field": "localrank", "operator": "<=", "value": 16 }, - { "field": "localrank", "operator": ">", "value": 4 } - ], - "size": 12, - "type": "point" - }, - "poi_4_all": { - "source": "outdoors", - "layer": "poi_label", - "icon": "{{maki}}", - "field": "scalerank", - "value": 4, - "size": 12, - "type": "point" - }, - "poi_aerodrome": { - "source": "outdoors", - "layer": "poi_label", - "icon": "{{maki}}", - "field": "maki", - "value": "airport", - "size": 24, - "type": "point" - }, - "poi_label_1-2": { - "source": "outdoors", - "layer": "poi_label", - "field": "scalerank", - "value": [ - 1, - 2 - ], - "text_field": "{{name_en}}", - "path": "horizontal", - "padding": 2, - "maxWidth": 10, - "verticalAlignment": "top", - "translate": [0, -1], - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 12, - "feature_type": "point", - "type": "text" - }, - "poi_label_3": { - "source": "outdoors", - "layer": "poi_label", - "field": "scalerank", - "value": 3, - "text_field": "{{name_en}}", - "path": "horizontal", - "padding": 2, - "maxWidth": 8, - "verticalAlignment": "top", - "translate": [0, -1], - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 11, - "feature_type": "point", - "type": "text" - }, - "poi_label_4_4": { - "source": "outdoors", - "layer": "poi_label", - "filter": [ - "and", - { "field": "scalerank", "value": 4 }, - { "field": "localrank", "operator": "<=", "value": 4 } - ], - "text_field": "{{name_en}}", - "path": "horizontal", - "padding": 2, - "maxWidth": 8, - "verticalAlignment": "top", - "translate": [0, -1], - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 10, - "feature_type": "point", - "type": "text" - }, - "poi_label_4_16": { - "source": "outdoors", - "layer": "poi_label", - "filter": [ - "and", - { "field": "scalerank", "value": 4 }, - { "field": "localrank", "operator": "<=", "value": 16 } - ], - "text_field": "{{name_en}}", - "path": "horizontal", - "padding": 2, - "maxWidth": 8, - "verticalAlignment": "top", - "translate": [0, -1], - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 10, - "feature_type": "point", - "type": "text" - }, - "poi_label_4_all": { - "source": "outdoors", - "layer": "poi_label", - "field": "scalerank", - "value": 4, - "text_field": "{{name_en}}", - "path": "horizontal", - "padding": 2, - "maxWidth": 8, - "verticalAlignment": "top", - "translate": [0, -1], - "font": "Open Sans Semibold, Arial Unicode MS Bold", - "fontSize": 10, - "feature_type": "point", - "type": "text" - } + "version": 3, + "constants": { + "@land": "#eee", + "@water": "#999", + "@park": "#bda", + "@road": "#fefefe", + "@border": "#6d90ab", + "@building": "#ddd", + "@building_outline": "#ccc", + "@text": "#000000", + "@road_blur": 1, + "@stroke_width": 0.25 + }, + "sources": { + "mapbox.mapbox-streets-v5": { + "type": "vector", + "url": "mapbox://mapbox.mapbox-streets-v5", + "glyphs": "http://mapbox.s3.amazonaws.com/gl-glyphs-256/{fontstack}/{range}.pbf", + "maxZoom": 14 + } + }, + "layers": [{ + "id": "background", + "style": { + "fill-color": "@land", + "transition-fill-color": { + "duration": 500, + "delay": 0 + } + } + }, { + "id": "park", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "landuse", + "filter": { "class": "park" }, + "render": { + "type": "fill" }, - "structure": [ - { - "name": "background", - "bucket": "background" - }, - { - "name": "landcover_snow", - "bucket": "landcover_snow" - }, - { - "name": "landcover_crop", - "bucket": "landcover_crop" - }, - { - "name": "landcover_grass", - "bucket": "landcover_grass" - }, - { - "name": "landcover_scrub", - "bucket": "landcover_scrub" - }, - { - "name": "landcover_wood", - "bucket": "landcover_wood" - }, - { - "name": "landuse_wood", - "bucket": "landuse_wood" - }, - { - "name": "landuse_school", - "bucket": "landuse_school" - }, - { - "name": "landuse_sand", - "bucket": "landuse_sand" - }, - { - "name": "landuse_pitch", - "bucket": "landuse_pitch" - }, - { - "name": "landuse_park", - "bucket": "landuse_park" - }, - { - "name": "landuse_industrial", - "bucket": "landuse_industrial" - }, - { - "name": "landuse_scrub", - "bucket": "landuse_scrub" - }, - { - "name": "landuse_grass", - "bucket": "landuse_grass" - }, - { - "name": "landuse_crop", - "bucket": "landuse_crop" - }, - { - "name": "landuse_rock", - "bucket": "landuse_rock" - }, - { - "name": "landuse_snow", - "bucket": "landuse_snow" - }, - { - "name": "landuse_hospital", - "bucket": "landuse_hospital" - }, - { - "name": "landuse_cemetery", - "bucket": "landuse_cemetery" - }, - { - "name": "overlay_wetland", - "bucket": "overlay_wetland" - }, - { - "name": "overlay_breakwater_pier", - "bucket": "overlay_breakwater_pier" - }, - { - "name": "waterway_river_canal", - "bucket": "waterway_river_canal" - }, - { - "name": "waterway_stream", - "bucket": "waterway_stream" - }, - { - "name": "building_shadow", - "bucket": "building" - }, - { - "name": "building", - "bucket": "building" - }, - { - "name": "building_wall", - "bucket": "building" - }, - { - "name": "hillshade_full_highlight", - "bucket": "hillshade_full_highlight" - }, - { - "name": "hillshade_medium_highlight", - "bucket": "hillshade_medium_highlight" - }, - { - "name": "hillshade_medium_shadow", - "bucket": "hillshade_medium_shadow" - }, - { - "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" - }, - { - "name": "barrier_line_fence", - "bucket": "barrier_line_fence" - }, - { - "name": "barrier_line_hedge", - "bucket": "barrier_line_hedge" - }, - { - "name": "barrier_line_land", - "bucket": "barrier_line_land" - }, - { - "name": "barrier_line_land_fill", - "bucket": "barrier_line_land_fill" - }, - { - "name": "barrier_line_cliff", - "bucket": "barrier_line_cliff" - }, - { - "name": "water", - "bucket": "water" - }, - { - "name": "aeroway_fill", - "bucket": "aeroway_fill" - }, - { - "name": "aeroway_runway", - "bucket": "aeroway_runway" - }, - { - "name": "aeroway_taxiway", - "bucket": "aeroway_taxiway" - }, - { - "name": "tunnel_motorway_link_casing", - "bucket": "tunnel_motorway_link" - }, - { - "name": "tunnel_service_casing", - "bucket": "tunnel_service" - }, - { - "name": "tunnel_main_casing", - "bucket": "tunnel_main" - }, - { - "name": "tunnel_street_casing", - "bucket": "tunnel_street" - }, - { - "name": "tunnel_motorway_link", - "bucket": "tunnel_motorway_link" - }, - { - "name": "tunnel_service", - "bucket": "tunnel_service" - }, - { - "name": "tunnel_street", - "bucket": "tunnel_street" - }, - { - "name": "tunnel_main", - "bucket": "tunnel_main" - }, - { - "name": "tunnel_motorway_casing", - "bucket": "tunnel_motorway" - }, - { - "name": "tunnel_motorway", - "bucket": "tunnel_motorway" - }, - { - "name": "road_path_case", - "bucket": "tunnel_path" - }, - { - "name": "road_path_footway", - "bucket": "tunnel_path_footway" - }, - { - "name": "road_path_path", - "bucket": "tunnel_path_path" - }, - { - "name": "road_path_cycleway", - "bucket": "tunnel_path_cycleway" - }, - { - "name": "road_path_mtb", - "bucket": "tunnel_path_mtb" - }, - { - "name": "road_path_piste", - "bucket": "tunnel_path_piste" - }, - { - "name": "road_path_steps", - "bucket": "tunnel_path_steps" - }, - { - "name": "road_major_rail", - "bucket": "tunnel_major_rail" - }, - { - "name": "road_major_rail_hatching", - "bucket": "tunnel_major_rail" - }, - { - "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_casing", - "bucket": "motorway" - }, - { - "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", - "bucket": "motorway" - }, - { - "name": "road_path_case", - "bucket": "path" - }, - { - "name": "road_path_footway", - "bucket": "path_footway" - }, - { - "name": "road_path_path", - "bucket": "path_path" - }, - { - "name": "road_path_cycleway", - "bucket": "path_cycleway" - }, - { - "name": "road_path_mtb", - "bucket": "path_mtb" - }, - { - "name": "road_path_piste", - "bucket": "path_piste" - }, - { - "name": "road_path_steps", - "bucket": "path_steps" - }, - { - "name": "road_major_rail", - "bucket": "major_rail" - }, - { - "name": "road_major_rail_hatching", - "bucket": "major_rail" - }, - { - "name": "bridge_motorway_link_casing", - "bucket": "bridge_motorway_link" - }, - { - "name": "bridge_service_casing", - "bucket": "bridge_service" - }, - { - "name": "bridge_main_casing", - "bucket": "bridge_main" - }, - { - "name": "bridge_street_casing", - "bucket": "bridge_street" - }, - { - "name": "bridge_motorway_link", - "bucket": "bridge_motorway_link" - }, - { - "name": "bridge_service", - "bucket": "bridge_service" - }, - { - "name": "bridge_street", - "bucket": "bridge_street" - }, - { - "name": "bridge_main", - "bucket": "bridge_main" - }, - { - "name": "bridge_motorway_casing", - "bucket": "bridge_motorway" - }, - { - "name": "bridge_motorway", - "bucket": "bridge_motorway" - }, - { - "name": "road_path_footway", - "bucket": "bridge_path_footway" - }, - { - "name": "road_path_path", - "bucket": "bridge_path_path" - }, - { - "name": "road_path_cycleway", - "bucket": "bridge_path_cycleway" - }, - { - "name": "road_path_mtb", - "bucket": "bridge_path_mtb" - }, - { - "name": "road_path_piste", - "bucket": "bridge_path_piste" - }, - { - "name": "road_path_steps", - "bucket": "bridge_path_steps" - }, - { - "name": "bridge_aerialway_casing", - "bucket": "bridge_aerialway" - }, - { - "name": "bridge_aerialway", - "bucket": "bridge_aerialway" - }, - { - "name": "road_major_rail", - "bucket": "bridge_major_rail" - }, - { - "name": "road_major_rail_hatching", - "bucket": "bridge_major_rail" - }, - { - "name": "admin_l3", - "bucket": "admin_l3" - }, - { - "name": "admin_l2", - "bucket": "admin_l2" - }, - { - "name": "admin_maritime_cover", - "bucket": "admin_maritime" - }, - { - "name": "admin_maritime", - "bucket": "admin_maritime" - }, - { - "name": "country_label_line", - "bucket": "country_label_line" - }, - { - "name": "country_label", - "bucket": "country_label" - }, - { - "name": "marine_label_line_1", - "bucket": "marine_label_line_1" - }, - { - "name": "marine_label_line_2", - "bucket": "marine_label_line_2" - }, - { - "name": "marine_label_line_3", - "bucket": "marine_label_line_3" - }, - { - "name": "marine_label_line_other", - "bucket": "marine_label_line_other" - }, - { - "name": "marine_label_point_1", - "bucket": "marine_label_point_1" - }, - { - "name": "marine_label_point_2", - "bucket": "marine_label_point_2" - }, - { - "name": "marine_label_point_3", - "bucket": "marine_label_point_3" - }, - { - "name": "marine_label_point_other", - "bucket": "marine_label_point_other" - }, - { - "name": "state_label", - "bucket": "state_label" - }, - { - "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": "water_label", - "bucket": "water_label" - }, - { - "name": "poi_aerodrome", - "bucket": "poi_aerodrome" - }, - { - "name": "poi", - "bucket": "poi" - }, - { - "name": "poi_label_1-2", - "bucket": "poi_label_1-2" - }, - { - "name": "road_label_1", - "bucket": "road_label_1" - }, - { - "name": "poi_3", - "bucket": "poi_3" - }, - { - "name": "poi_label_3", - "bucket": "poi_label_3" - }, - { - "name": "road_label_2", - "bucket": "road_label_2" - }, - { - "name": "road_label_3", - "bucket": "road_label_3" - }, - { - "name": "contour_label", - "bucket": "contour_label" - }, - { - "name": "waterway_label", - "bucket": "waterway_label" - }, - { - "name": "poi_4_4", - "bucket": "poi_4_4" - }, - { - "name": "poi_label_4_4", - "bucket": "poi_label_4_4" - }, - { - "name": "poi_4_16", - "bucket": "poi_4_16" - }, - { - "name": "poi_label_4_16", - "bucket": "poi_label_4_16" - }, - { - "name": "poi_4_all", - "bucket": "poi_4_all" - }, - { - "name": "poi_label_4_all", - "bucket": "poi_label_4_all" - } - ], - "constants": { - "land": "rgb(244,239,225)", - "water": "#cdd", - "water_dark": "#185869", - "crop": "#eeeed4", - "grass": "#e6e6cc", - "scrub": "#dfe5c8", - "wood": "#cee2bd", - "snow": "#f4f8ff", - "rock": "#ddd", - "sand": "#ffd", - "cemetery": "#edf4ed", - "pitch": "#fff", - "park": "#d4e4bc", - "piste": "blue", - "school": "#e8dfe0", - "hospital": "#f8eee0", - "builtup": "#f6faff", - "case": "#fff", - "motorway": "#cda0a0", - "main": "#ddc0b9", - "street": "#fff", - "text": "#666", - "text_stroke": "rgba(255,255,255,0.8)", - "country_text": "#222", - "marine_text": "#a0bdc0", - "water_text": "#185869", - - "land_night": "#017293", - "water_night": "#103", - "water_dark_night": "#003366", - "crop_night": "#178d96", - "grass_night": "#23948a", - "scrub_night": "#31a186", - "wood_night": "#45b581", - "park_night": "#51bd8b", - "snow_night": "#5ad9fe", - "rock_night": "#999", - "sand_night": "#437162", - "cemetery_night": "#218c96", - "pitch_night": "rgba(255,255,255,0.2)", - "school_night": "#01536a", - "hospital_night": "#015e7a", - "builtup_night": "#014b60", - - "admin_night": "#ffb680", - "text_night": "#fff", - "text_water_night": "#2a5b8a", - "text_stroke_night": "#103", - "text2_stroke_night": "rgba(1,69,89,0.8)", - - "case_night": "#015e7a", - "street_case_night": "#015b76", - "motorway_night": "#bbdde7", - "main_night": "#64b2c9", - "street_night": "#0186ac", - "contour_night": "#ffff80", - - "river_canal_width": [ - "stops", - {"z": 11, "val": 0.5}, - {"z": 12, "val": 1}, - {"z": 14, "val": 2}, - {"z": 16, "val": 3} - ], - "stream_width": [ - "stops", - {"z": 13, "val": 0.25}, - {"z": 14, "val": 0.5}, - {"z": 16, "val": 1.5}, - {"z": 18, "val": 2} - ], - "motorway_width": [ - "stops", - {"z": 5, "val": 0}, - {"z": 6, "val": 0.5}, - {"z": 8, "val": 0.8}, - {"z": 10, "val": 1}, - {"z": 11, "val": 1.2}, - {"z": 12, "val": 2}, - {"z": 13, "val": 3}, - {"z": 14, "val": 4}, - {"z": 15, "val": 6}, - {"z": 16, "val": 9}, - {"z": 17, "val": 12}, - {"z": 18, "val": 14} - ], - "motorway_casing_width": [ - "stops", - {"z": 7.5, "val": 0.6}, - {"z": 8, "val": 0.8}, - {"z": 10, "val": 2.8}, - {"z": 11, "val": 3}, - {"z": 12, "val": 4}, - {"z": 13, "val": 5}, - {"z": 14, "val": 6.5}, - {"z": 15, "val": 9}, - {"z": 16, "val": 12}, - {"z": 17, "val": 15}, - {"z": 18, "val": 17} - ], - "motorway_link_width": [ - "stops", - {"z": 12, "val": 1.2}, - {"z": 14, "val": 2}, - {"z": 16, "val": 3}, - {"z": 18, "val": 4} - ], - "motorway_link_casing_width": [ - "stops", - {"z": 12, "val": 2.8}, - {"z": 14, "val": 3.5}, - {"z": 16, "val": 5}, - {"z": 18, "val": 6} - ], - "main_width": [ - "stops", - {"z": 5, "val": 1}, - {"z": 12, "val": 1}, - {"z": 13, "val": 1.5}, - {"z": 14, "val": 2}, - {"z": 15, "val": 3}, - {"z": 16, "val": 6}, - {"z": 17, "val": 10}, - {"z": 18, "val": 12} - ], - "main_casing_width": [ - "stops", - {"z": 9, "val": 2.9}, - {"z": 12, "val": 2.9}, - {"z": 13, "val": 3.5}, - {"z": 14, "val": 4}, - {"z": 15, "val": 5.5}, - {"z": 16, "val": 9}, - {"z": 17, "val": 12}, - {"z": 18, "val": 14} - ], - "street_width": [ - "stops", - {"z": 14.5, "val": 0}, - {"z": 15, "val": 1.5}, - {"z": 16, "val": 3}, - {"z": 17, "val": 8} - ], - "street_casing_width": [ - "stops", - {"z": 13, "val": 0.4}, - {"z": 14, "val": 1}, - {"z": 15, "val": 2.5}, - {"z": 16, "val": 4}, - {"z": 17, "val": 10} - ], - "street_casing_opacity": [ - "stops", - {"z": 14, "val": 0}, - {"z": 14.5, "val": 1} - ], - "service_casing_width": [ - "stops", - {"z": 14, "val": 0.5}, - {"z": 15, "val": 3}, - {"z": 16, "val": 3.5}, - {"z": 17, "val": 4}, - {"z": 18, "val": 5}, - {"z": 19, "val": 6} - ], - "runway_width": [ - "stops", - {"z": 10, "val": 1}, - {"z": 11, "val": 2}, - {"z": 12, "val": 3}, - {"z": 13, "val": 5}, - {"z": 14, "val": 7}, - {"z": 15, "val": 11}, - {"z": 16, "val": 15}, - {"z": 17, "val": 19}, - {"z": 18, "val": 23} - ], - "taxiway_width": [ - "stops", - {"z": 10, "val": 0.2}, - {"z": 12, "val": 0.2}, - {"z": 13, "val": 1}, - {"z": 14, "val": 1.5}, - {"z": 15, "val": 2}, - {"z": 16, "val": 3}, - {"z": 17, "val": 4}, - {"z": 18,"val": 5} - ], - "aerialway_width": [ - "stops", - {"z": 13.5, "val": 0.8}, - {"z": 14, "val": 1.4}, - {"z": 15, "val": 1.6}, - {"z": 16, "val": 2}, - {"z": 17, "val": 2.4}, - {"z": 18, "val": 3} - ], - "aerialway_casing_width": [ - "stops", - {"z": 13.5, "val": 2}, - {"z": 14, "val": 2.5}, - {"z": 15, "val": 3}, - {"z": 16, "val": 3.5}, - {"z": 17, "val": 4}, - {"z": 22, "val": 5} - ], - "path_width": [ - "stops", - {"z": 14, "val": 1.2}, - {"z": 15, "val": 1.5}, - {"z": 16, "val": 1.8} - ], - "admin_l2_width": [ - "stops", - {"z": 2, "val": 0.5}, - {"z": 3, "val": 0.7}, - {"z": 4, "val": 0.7}, - {"z": 5, "val": 0.8}, - {"z": 6, "val": 1}, - {"z": 8, "val": 2}, - {"z": 10, "val": 3} - ], - "admin_l3_width": [ - "stops", - {"z": 6, "val": 0.6}, - {"z": 8, "val": 1}, - {"z": 12, "val": 2} - ], - "road_label_1_size": [ - "stops", - {"z": 13, "val": 11}, - {"z": 14, "val": 12}, - {"z": 15, "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", - {"z": 17, "val": 0.6}, - {"z": 19, "val": 1} - ], - "hedge_width": [ - "stops", - {"z": 16, "val": 0.6}, - {"z": 17, "val": 1.2}, - {"z": 19, "val": 1.6} - ], - "barrier_line_land_width": [ - "stops", - {"z": 14, "val": 0.4}, - {"z": 15, "val": 0.75}, - {"z": 16, "val": 1.5}, - {"z": 17, "val": 3}, - {"z": 18, "val": 6}, - {"z": 19, "val": 12}, - {"z": 20, "val": 24}, - {"z": 21, "val": 48} - ], - "country_label_size": [ - "stops", - {"z": 1, "val": 14}, - {"z": 12, "val": 24} - ], - "poi_label_1-2_size": [ - "stops", - {"z": 15, "val": 10}, - {"z": 16, "val": 11}, - {"z": 17, "val": 12} - ], - "poi_label_3_size": [ - "stops", - {"z": 16, "val": 10}, - {"z": 17, "val": 11} - ], - "hillshade_prerender": [ - "stops", - {"z": 11, "val": 0}, - {"z": 12, "val": 1} - ], - "hillshade_prerender_size": [ - "stops", - {"z": 11, "val": 1056}, - {"z": 12, "val": 512}, - {"z": 13, "val": 256} - ] + "style": { + "fill-color": "@park" + } + }, { + "id": "water", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "water", + "render": { + "type": "fill" }, - "classes": [ - { - "name": "default", - "layers": { - "background": { - "color": "land" - }, - "admin_maritime_cover": { - "color": "water", - "width": 5 - }, - "admin_maritime": { - "color": "#c0d6d6", - "width": [ - "stops", - {"z": 6, "val": 1}, - {"z": 8, "val": 2}, - {"z": 12, "val": 3} - ] - }, - "admin_l2": { - "color": "#88a", - "width": "admin_l2_width" - }, - "admin_l3": { - "color": "#88a", - "dasharray": [ - 60, - 20 - ], - "opacity": [ - "stops", - {"z": 4, "val": 0}, - {"z": 6, "val": 1} - ], - "width": "admin_l3_width" - }, - "waterway_river_canal": { - "color": "#87abaf", - "width": "river_canal_width" - }, - "waterway_stream": { - "color": "#87abaf", - "width": "stream_width" - }, - "barrier_line_gate": { - "width": 2.5, - "color": "#aab" - }, - "barrier_line_fence": { - "color": "#aeada3", - "width": "fence_width" - }, - "barrier_line_hedge": { - "color": "#8de99b", - "width": "hedge_width" - }, - "barrier_line_land": { - "color": "land", - "width": "barrier_line_land_width" - }, - "barrier_line_land_fill": { - "color": "land" - }, - "barrier_line_cliff": { - "color": "#987", - "width": 4 - }, - "landcover_wood": { - "color": "wood", - "opacity": [ - "stops", - {"z": 13, "val": 1}, - {"z": 14, "val": 0.8}, - {"z": 17, "val": 0.2} - ] - }, - "landcover_scrub": { - "color": "scrub", - "opacity": [ - "stops", - {"z": 13, "val": 1}, - {"z": 14, "val": 0.8}, - {"z": 17, "val": 0.2} - ] - }, - "landcover_grass": { - "color": "grass", - "opacity": [ - "stops", - {"z": 13, "val": 1}, - {"z": 14, "val": 0.8}, - {"z": 17, "val": 0.2} - ] - }, - "landcover_crop": { - "color": "crop" - }, - "landcover_snow": { - "color": "snow" - }, - "landuse_wood": { - "color": "wood" - }, - "landuse_scrub": { - "color": "scrub" - }, - "landuse_grass": { - "color": "grass" - }, - "landuse_crop": { - "color": "crop" - }, - "landuse_snow": { - "color": "snow" - }, - "landuse_rock": { - "color": "rock" - }, - "landuse_sand": { - "color": "sand" - }, - "landuse_park": { - "color": "park" - }, - "landuse_cemetery": { - "color": "cemetery" - }, - "landuse_hospital": { - "color": "hospital" - }, - "landuse_school": { - "color": "school" - }, - "landuse_pitch": { - "color": "rgba(255,255,255,0.5)", - "stroke": "pitch" - }, - "landuse_industrial": { - "color": "rgba(246,250,255,0.5)" - }, - "overlay_wetland": { - "color": "rgba(210,225,225,0.2)", - "image": "wetland_noveg_64" - }, - "overlay_breakwater_pier": { - "color": "land" - }, - "hillshade_full_shadow": { - "color": "#103", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 15, "val": 0.08}, - {"z": 16, "val": 0.075}, - {"z": 17, "val": 0.05}, - {"z": 18, "val": 0.05}, - {"z": 19, "val": 0.025} - ] - }, - "hillshade_medium_shadow": { - "color": "#206", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 15, "val": 0.08}, - {"z": 16, "val": 0.075}, - {"z": 17, "val": 0.05}, - {"z": 18, "val": 0.05}, - {"z": 19, "val": 0.025} - ] - }, - "hillshade_full_highlight": { - "color": "#fffff3", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 15, "val": 0.3}, - {"z": 16, "val": 0.3}, - {"z": 17, "val": 0.2}, - {"z": 18, "val": 0.2}, - {"z": 19, "val": 0.1} - ] - }, - "hillshade_medium_highlight": { - "color": "#ffd", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 15, "val": 0.3}, - {"z": 16, "val": 0.3}, - {"z": 17, "val": 0.2}, - {"z": 18, "val": 0.2}, - {"z": 19, "val": 0.1} - ] - }, - "contour_line_loud": { - "color": "#008", - "width": 0.9, - "opacity": [ - "stops", - {"z": 12, "val": 0.05}, - {"z": 13, "val": 0.11} - ] - }, - "contour_line_regular": { - "color": "#008", - "width": 0.5, - "opacity": [ - "stops", - {"z": 12, "val": 0.05}, - {"z": 13, "val": 0.11} - ] - }, - "contour_label": { - "color": "text", - "stroke": "land", - "strokeWidth": 0.3, - "strokeBlur": 3, - "size": 10 - }, - "water": { - "color": "water", - "stroke": "#a2bdc0" - }, - "aeroway_fill": { - "color": "#ddd" - }, - "aeroway_runway": { - "color": "#ddd", - "width": "runway_width" - }, - "aeroway_taxiway": { - "color": "#ddd", - "width": "taxiway_width" - }, - "building": { - "color": "#ebe7db" - }, - "building_wall": { - "color": "#ebe7db", - "stroke": "#d5d1c6", - "opacity": [ - "stops", - {"z": 16.5, "val": 0}, - {"z": 17, "val": 0.7} - ] - }, - "building_shadow": { - "color": "#d5d1c6", - "stroke": "#d5d1c6", - "translate": [ - 1, - 1 - ], - "opacity": [ - "stops", - {"z": 16.5, "val": 0}, - {"z": 17, "val": 1} - ] - }, - "tunnel_motorway_casing": { - "color": "case", - "dasharray": [ - 6, - 6 - ], - "width": "motorway_casing_width", - "opacity": [ - "stops", - {"z": 9.5, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "tunnel_motorway": { - "color": "#e6cec7", - "width": "motorway_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "tunnel_main_casing": { - "color": "case", - "dasharray": [ - 6, - 6 - ], - "width": "main_casing_width", - "opacity": ["stops", - {"z": 9, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "tunnel_main": { - "color": "#e6cec7", - "width": "main_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "tunnel_motorway_link_casing": { - "color": "case", - "dasharray": [ - 6, - 6 - ], - "width": "motorway_link_casing_width" - }, - "tunnel_motorway_link": { - "color": "#e6cec7", - "width": "motorway_link_width" - }, - "tunnel_street_casing": { - "color": "#d9d5c6", - "width": "street_casing_width", - "opacity": "street_casing_opacity" - }, - "tunnel_street": { - "color": "#d9d5c6", - "width": "street_width" - }, - "tunnel_service_casing": { - "color": "#000", - "opacity": 0.04, - "dasharray": [ - 6, - 6 - ], - "width": "service_casing_width" - }, - "tunnel_service": { - "color": "#e6cec7", - "width": 2 - }, - "road_motorway_casing": { - "color": "case", - "width": "motorway_casing_width", - "opacity": [ - "stops", - {"z": 9.5, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "road_motorway": { - "color": "motorway", - "width": "motorway_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "road_main_casing": { - "color": "case", - "width": "main_casing_width", - "opacity": ["stops", - {"z": 9, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "road_main": { - "color": "main", - "width": "main_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "road_motorway_link_casing": { - "color": "case", - "width": "motorway_link_casing_width" - }, - "road_motorway_link": { - "color": "motorway", - "width": "motorway_link_width" - }, - "road_street_casing": { - "color": "#d9d5c6", - "width": "street_casing_width", - "opacity": "street_casing_opacity" - }, - "road_street": { - "color": "street", - "width": "street_width" - }, - "road_service_casing": { - "color": "#000", - "opacity": 0.04, - "width": "service_casing_width" - }, - "road_service": { - "color": "street", - "width": 2 - }, - "road_path_case": { - "color": "#ffd", - "opacity": 0.4, - "width": [ - "stops", - {"z": 15, "val": 3}, - {"z": 16, "val": 4} - ] - }, - "road_path_footway": { - "color": "#bba", - "dasharray": [ - 10, - 4 - ], - "width": "path_width" - }, - "road_path_path": { - "color": "#987", - "dasharray": [ - 10, - 4 - ], - "opacity": 0.8, - "width": [ - "stops", - {"z": 14, "val": 0.8}, - {"z": 15, "val": 0.9}, - {"z": 16, "val": 1.2} - ] - }, - "road_path_cycleway": { - "color": "#488", - "dasharray": [ - 10, - 4 - ], - "width": "path_width" - }, - "road_path_mtb": { - "color": "#488", - "dasharray": [ - 12, - 4 - ], - "width": "path_width" - }, - "road_path_piste": { - "color": "#87b", - "dasharray": [ - 8, - 4 - ], - "width": "path_width" - }, - "road_path_steps": { - "color": "#bba", - "dasharray": [ - 10, - 4 - ], - "width": 4 - }, - "road_major_rail": { - "color": "#c8c4c0", - "width": 0.8 - }, - "road_major_rail_hatching": { - "color": "#c8c4c0", - "dasharray": [ - 2, - 31 - ], - "width": 5 - }, - "bridge_motorway_casing": { - "color": "case", - "width": "motorway_casing_width", - "opacity": [ - "stops", - {"z": 9.5, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "bridge_motorway": { - "color": "motorway", - "width": "motorway_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "bridge_main_casing": { - "color": "case", - "width": "main_casing_width", - "opacity": ["stops", - {"z": 9, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "bridge_main": { - "color": "main", - "width": "main_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "bridge_motorway_link_casing": { - "color": "case", - "width": "motorway_link_casing_width" - }, - "bridge_motorway_link": { - "color": "motorway", - "width": "motorway_link_width" - }, - "bridge_street_casing": { - "color": "#d9d5c6", - "width": "street_casing_width", - "opacity": "street_casing_opacity" - }, - "bridge_street": { - "color": "street", - "width": "street_width" - }, - "bridge_service_casing": { - "color": "#000", - "opacity": 0.04, - "width": "service_casing_width" - }, - "bridge_service": { - "color": "street", - "width": 2 - }, - "bridge_aerialway_casing": { - "color": "white", - "opacity": 0.5, - "width": "aerialway_casing_width" - }, - "bridge_aerialway": { - "color": "#876", - "opacity": 0.5, - "width": "aerialway_width" - }, - "country_label": { - "color": "country_text", - "stroke": "rgba(255,255,255,0.5)", - "strokeWidth": 0.5, - "size": "country_label_size" - }, - "country_label_line": { - "color": "country_text", - "width": 0.5, - "opacity": 0.5 - }, - "marine_label_line_1": { - "color": "marine_text", - "size": ["stops", - {"z": 3, "val": 20}, - {"z": 4, "val": 25}, - {"z": 5, "val": 30}, - {"z": 22, "val": 30} - ], - "stroke": "water" - }, - "marine_label_line_2": { - "color": "marine_text", - "size": ["stops", - {"z": 3, "val": 13}, - {"z": 4, "val": 14}, - {"z": 5, "val": 20}, - {"z": 6, "val": 24}, - {"z": 22, "val": 24} - ], - "stroke": "water" - }, - "marine_label_line_3": { - "color": "marine_text", - "size": ["stops", - {"z": 3, "val": 12}, - {"z": 4, "val": 13}, - {"z": 5, "val": 15}, - {"z": 6, "val": 18}, - {"z": 22, "val": 18} - ], - "stroke": "water" - }, - "marine_label_line_other": { - "color": "marine_text", - "size": ["stops", - {"z": 4, "val": 12}, - {"z": 5, "val": 14}, - {"z": 6, "val": 16}, - {"z": 22, "val": 16} - ], - "stroke": "water" - }, - "marine_label_point_1": { - "color": "marine_text", - "size": ["stops", - {"z": 3, "val": 20}, - {"z": 4, "val": 25}, - {"z": 5, "val": 30}, - {"z": 22, "val": 30} - ], - "stroke": "water" - }, - "marine_label_point_2": { - "color": "marine_text", - "size": ["stops", - {"z": 3, "val": 13}, - {"z": 4, "val": 14}, - {"z": 5, "val": 20}, - {"z": 6, "val": 24}, - {"z": 22, "val": 24} - ], - "stroke": "water" - }, - "marine_label_point_3": { - "color": "marine_text", - "size": ["stops", - {"z": 3, "val": 12}, - {"z": 4, "val": 13}, - {"z": 5, "val": 15}, - {"z": 6, "val": 18}, - {"z": 22, "val": 18} - ], - "stroke": "water" - }, - "marine_label_point_other": { - "color": "marine_text", - "size": ["stops", - {"z": 4, "val": 12}, - {"z": 5, "val": 14}, - {"z": 6, "val": 16}, - {"z": 22, "val": 16} - ], - "stroke": "water" - }, - "state_label": { - "color": "#333", - "strokeWidth": 0.4, - "strokeBlur": 1, - "stroke": "rgba(244,239,225,0.8)", - "size": [ - "stops", - {"z": 3.99, "val": 0}, - {"z": 4, "val": 10}, - {"z": 9.99, "val": 16}, - {"z": 10, "val": 0} - ] - }, - "place_label_city": { - "color": "#444", - "strokeWidth": 0.4, - "stroke": "text_stroke", - "size": [ - "stops", - {"z": 3.99, "val": 0}, - {"z": 4, "val": 10}, - {"z": 7, "val": 14}, - {"z": 14.99, "val": 20}, - {"z": 15, "val": 0} - ] - }, - "place_label_town": { - "color": "#716656", - "strokeWidth": 0.3, - "strokeBlur": 2, - "stroke": "text_stroke", - "size": [ - "stops", - {"z": 9, "val": 10}, - {"z": 12, "val": 13}, - {"z": 14, "val": 17}, - {"z": 16, "val": 22} - ] - }, - "place_label_village": { - "color": "#635644", - "strokeWidth": 0.3, - "strokeBlur": 2, - "stroke": "text_stroke", - "size": [ - "stops", - {"z": 9, "val": 8}, - {"z": 12, "val": 10}, - {"z": 14, "val": 14}, - {"z": 16, "val": 16}, - {"z": 17, "val": 20} - ] - }, - "place_label_other": { - "color": "#7d6c55", - "stroke": "text_stroke", - "size": [ - "stops", - {"z": 13, "val": 11}, - {"z": 14, "val": 12}, - {"z": 16, "val": 14}, - {"z": 18, "val": 18} - ] - }, - "road_label_1": { - "color": "#585042", - "stroke": "land", - "strokeWidth": 0.6, - "strokeBlur": 2, - "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", - "stroke": "rgba(255,255,255,0.75)" - }, - "waterway_label": { - "color": "water_dark", - "strokeWidth": 0.4, - "strokeBlur": 2, - "stroke": "text_stroke" - }, - "poi": { - "antialias": false - }, - "poi_3": { - "antialias": false, - "opacity": [ - "stops", - {"z": 17.5, "val": 0}, - {"z": 17.75, "val": 1} - ] - }, - "poi_4_4": { - "antialias": false, - "opacity": [ - "stops", - {"z": 18, "val": 0}, - {"z": 18.25, "val": 1} - ] - }, - "poi_4_16": { - "antialias": false, - "opacity": [ - "stops", - {"z": 18.5, "val": 0}, - {"z": 18.75, "val": 1} - ] - }, - "poi_4_all": { - "antialias": false, - "opacity": [ - "stops", - {"z": 18.75, "val": 0}, - {"z": 19, "val": 1} - ] - }, - "poi_label_1-2": { - "color": "#444", - "size": "poi_label_1-2_size", - "stroke": "land", - "strokeWidth": 0.3, - "strokeBlur": 1 - }, - "poi_label_3": { - "color": "#444", - "size": "poi_label_3_size", - "stroke": "land", - "strokeWidth": 0.3, - "strokeBlur": 1, - "opacity": [ - "stops", - {"z": 17.5, "val": 0}, - {"z": 17.75, "val": 1} - ] - }, - "poi_label_4_4": { - "color": "#444", - "size": 10, - "opacity": [ - "stops", - {"z": 18, "val": 0}, - {"z": 17.25, "val": 1} - ], - "stroke": "land", - "strokeWidth": 0.3, - "strokeBlur": 1 - }, - "poi_label_4_16": { - "color": "#444", - "size": 10, - "opacity": [ - "stops", - {"z": 18.25, "val": 0}, - {"z": 18.75, "val": 1} - ], - "stroke": "land", - "strokeWidth": 0.3, - "strokeBlur": 1 - }, - "poi_label_4_all": { - "color": "#444", - "size": 10, - "opacity": [ - "stops", - {"z": 18.75, "val": 0}, - {"z": 19, "val": 1} - ], - "stroke": "land", - "strokeWidth": 0.3, - "strokeBlur": 1 - }, - "poi_aerodrome": { - "opacity": ["stops", - {"z": 13, "val": 0}, - {"z": 13.25, "val": 1} - ], - "antialias": false - } - } - }, - { - "name": "night", - "layers": { - "background": { - "color": "land_night" - }, - "admin_maritime_cover": { - "color": "water_night", - "width": 5 - }, - "admin_maritime": { - "color": "#0a1347", - "width": [ - "stops", - {"z": 6, "val": 1}, - {"z": 8, "val": 2}, - {"z": 12, "val": 3} - ] - }, - "admin_l2": { - "color": "admin_night", - "width": "admin_l2_width" - }, - "admin_l3": { - "color": "admin_night", - "dasharray": [ - 60, - 20 - ], - "opacity": [ - "stops", - {"z": 4, "val": 0}, - {"z": 6, "val": 1} - ], - "width": "admin_l3_width" - }, - "waterway_river_canal": { - "color": "rgb(10,20,71)", - "width": "river_canal_width" - }, - "waterway_stream": { - "color": "rgb(10,20,71)", - "width": "stream_width" - }, - "barrier_line_gate": { - "width": 2.5, - "color": "#59596f" - }, - "barrier_line_fence": { - "color": "#014b61", - "width": "fence_width" - }, - "barrier_line_hedge": { - "color": "#2e7a57", - "width": "hedge_width" - }, - "barrier_line_land": { - "color": "land_night", - "width": "barrier_line_land_width" - }, - "barrier_line_land_fill": { - "color": "land_night" - }, - "barrier_line_cliff": { - "color": "#63574b", - "width": 4 - }, - "landcover_wood": { - "color": "wood_night", - "opacity": [ - "stops", - {"z": 13, "val": 1}, - {"z": 14, "val": 0.8}, - {"z": 17, "val": 0.2} - ] - }, - "landcover_scrub": { - "color": "scrub_night", - "opacity": [ - "stops", - {"z": 13, "val": 1}, - {"z": 14, "val": 0.8}, - {"z": 17, "val": 0.2} - ] - }, - "landcover_grass": { - "color": "grass_night", - "opacity": [ - "stops", - {"z": 13, "val": 1}, - {"z": 14, "val": 0.8}, - {"z": 17, "val": 0.2} - ] - }, - "landcover_crop": { - "color": "crop_night" - }, - "landcover_snow": { - "color": "snow_night" - }, - "landuse_wood": { - "color": "wood_night", - "opacity": 0.8 - }, - "landuse_scrub": { - "color": "scrub_night", - "opacity": 0.8 - }, - "landuse_grass": { - "color": "grass_night", - "opacity": 0.8 - }, - "landuse_crop": { - "color": "crop_night", - "opacity": 0.8 - }, - "landuse_snow": { - "color": "snow_night", - "opacity": 0.8 - }, - "landuse_rock": { - "color": "rock_night", - "opacity": 0.8 - }, - "landuse_sand": { - "color": "sand_night", - "opacity": 0.8 - }, - "landuse_park": { - "color": "park_night" - }, - "landuse_cemetery": { - "color": "cemetery_night" - }, - "landuse_hospital": { - "color": "hospital_night" - }, - "landuse_school": { - "color": "school_night" - }, - "landuse_pitch": { - "color": "pitch_night", - "stroke": "pitch" - }, - "landuse_industrial": { - "color": "builtup_night" - }, - "overlay_wetland": { - "color": "rgba(210,225,225,0.2)", - "image": "wetland_noveg_64" - }, - "overlay_breakwater_pier": { - "color": "land_night" - }, - "hillshade_full_shadow": { - "color": "#103", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 16, "val": 0.3}, - {"z": 17, "val": 0.2}, - {"z": 18, "val": 0.1}, - {"z": 19, "val": 0.05} - ] - }, - "hillshade_medium_shadow": { - "color": "#206", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 16, "val": 0.3}, - {"z": 17, "val": 0.2}, - {"z": 18, "val": 0.1}, - {"z": 19, "val": 0.05} - ] - }, - "hillshade_full_highlight": { - "color": "#fdfdad", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 14, "val": 0.4}, - {"z": 15, "val": 0.3}, - {"z": 17, "val": 0.2}, - {"z": 18, "val": 0.1}, - {"z": 19, "val": 0.05} - ] - }, - "hillshade_medium_highlight": { - "color": "#ffe1b7", - "antialias": false, - "prerender": "hillshade_prerender", - "prerender-size": "hillshade_prerender_size", - "prerender-blur": 1, - "opacity": [ - "stops", - {"z": 15, "val": 0.3}, - {"z": 17, "val": 0.2}, - {"z": 18, "val": 0.15}, - {"z": 19, "val": 0.05} - ] - }, - "contour_line_loud": { - "color": "contour_night", - "width": 0.9, - "opacity": [ - "stops", - {"z": 12, "val": 0.1}, - {"z": 13, "val": 0.2} - ] - }, - "contour_line_regular": { - "color": "contour_night", - "width": 0.5, - "opacity": [ - "stops", - {"z": 12, "val": 0.1}, - {"z": 13, "val": 0.4} - ] - }, - "contour_label": { - "color": "contour_night", - "stroke": "land_night", - "strokeWidth": 0.3, - "strokeBlur": 3, - "size": 10 - }, - "water": { - "color": "water_night", - "stroke": "water_dark_night" - }, - "aeroway_fill": { - "color": "#367" - }, - "aeroway_runway": { - "color": "#367", - "width": "runway_width" - }, - "aeroway_taxiway": { - "color": "#367", - "width": "taxiway_width" - }, - "building": { - "color": "#027797" - }, - "building_wall": { - "color": "#027797", - "stroke": "#026688", - "opacity": [ - "stops", - {"z": 16.5, "val": 0}, - {"z": 17, "val": 0.7} - ] - }, - "building_shadow": { - "color": "#026688", - "stroke": "#026688", - "translate": [ - 1, - 1 - ], - "opacity": [ - "stops", - {"z": 16.5, "val": 0}, - {"z": 17, "val": 1} - ] - }, - "tunnel_motorway_casing": { - "color": "case_night", - "dasharray": [ - 6, - 6 - ], - "width": "motorway_casing_width", - "opacity": [ - "stops", - {"z": 9.5, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "tunnel_motorway": { - "color": "#78b0c1", - "width": "motorway_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "tunnel_main_casing": { - "color": "case_night", - "dasharray": [ - 6, - 6 - ], - "width": "main_casing_width", - "opacity": ["stops", - {"z": 9, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "tunnel_main": { - "color": "#78b0c1", - "width": "main_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "tunnel_motorway_link_casing": { - "color": "case_night", - "dasharray": [ - 6, - 6 - ], - "width": "motorway_link_casing_width" - }, - "tunnel_motorway_link": { - "color": "#78b0c1", - "width": "motorway_link_width" - }, - "tunnel_street_casing": { - "color": "street_case_night", - "width": "street_casing_width", - "opacity": "street_casing_opacity" - }, - "tunnel_street": { - "color": "street_night", - "width": "street_width" - }, - "tunnel_service_casing": { - "color": "#000", - "opacity": 0.04, - "dasharray": [ - 6, - 6 - ], - "width": "service_casing_width" - }, - "tunnel_service": { - "color": "#017ca0", - "width": 2 - }, - "road_motorway_casing": { - "color": "case_night", - "width": "motorway_casing_width", - "opacity": [ - "stops", - {"z": 9.5, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "road_motorway": { - "color": "motorway_night", - "width": "motorway_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "road_main_casing": { - "color": "case_night", - "width": "main_casing_width", - "opacity": ["stops", - {"z": 9, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "road_main": { - "color": "main_night", - "width": "main_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "road_motorway_link_casing": { - "color": "case_night", - "width": "motorway_link_casing_width" - }, - "road_motorway_link": { - "color": "motorway_night", - "width": "motorway_link_width" - }, - "road_street_casing": { - "color": "street_case_night", - "width": "street_casing_width", - "opacity": "street_casing_opacity" - }, - "road_street": { - "color": "street_night", - "width": "street_width" - }, - "road_service_casing": { - "color": "#000", - "opacity": 0.04, - "width": "service_casing_width" - }, - "road_service": { - "color": "street_night", - "width": 2 - }, - "road_path_case": { - "color": "land_night", - "opacity": 0.2 - }, - "road_path_footway": { - "color": "#fff", - "dasharray": [ - 10, - 4 - ], - "width": "path_width" - }, - "road_path_path": { - "color": "#fff", - "dasharray": [ - 10, - 4 - ], - "opacity": 0.8, - "width": [ - "stops", - {"z": 14, "val": 0.8}, - {"z": 15, "val": 0.9}, - {"z": 16, "val": 1.2} - ] - }, - "road_path_cycleway": { - "color": "#94e6ff", - "dasharray": [ - 10, - 4 - ], - "width": "path_width" - }, - "road_path_mtb": { - "color": "#94e6ff", - "dasharray": [ - 12, - 4 - ], - "width": "path_width" - }, - "road_path_piste": { - "color": "#715dae", - "dasharray": [ - 8, - 4 - ], - "width": "path_width" - }, - "road_path_steps": { - "color": "#016684", - "dasharray": [ - 10, - 4 - ], - "opacity": 0.3, - "width": 6 - }, - "road_major_rail": { - "color": "#c8c4c0", - "width": 0.8 - }, - "road_major_rail_hatching": { - "color": "#c8c4c0", - "dasharray": [ - 2, - 31 - ], - "width": 5 - }, - "bridge_motorway_casing": { - "color": "case_night", - "width": "motorway_casing_width", - "opacity": [ - "stops", - {"z": 9.5, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "bridge_motorway": { - "color": "motorway_night", - "width": "motorway_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "bridge_main_casing": { - "color": "case_night", - "width": "main_casing_width", - "opacity": ["stops", - {"z": 9, "val": 0}, - {"z": 10, "val": 1} - ] - }, - "bridge_main": { - "color": "main_night", - "width": "main_width", - "opacity": [ - "stops", - {"z": 6.5, "val": 0}, - {"z": 7, "val": 1} - ] - }, - "bridge_motorway_link_casing": { - "color": "case_night", - "width": "motorway_link_casing_width" - }, - "bridge_motorway_link": { - "color": "motorway_night", - "width": "motorway_link_width" - }, - "bridge_street_casing": { - "color": "street_case_night", - "width": "street_casing_width", - "opacity": "street_casing_opacity" - }, - "bridge_street": { - "color": "street_night", - "width": "street_width" - }, - "bridge_service_casing": { - "color": "#000", - "opacity": 0.04, - "width": "service_casing_width" - }, - "bridge_service": { - "color": "street_night", - "width": 2 - }, - "bridge_aerialway_casing": { - "color": "white", - "opacity": 0.5, - "width": "aerialway_casing_width" - }, - "bridge_aerialway": { - "color": "#876", - "opacity": 0.5, - "width": "aerialway_width" - }, - "country_label": { - "color": "text_night", - "stroke": "text2_stroke_night", - "strokeWidth": 0.4, - "strokeBlur": 2, - "size": "country_label_size" - }, - "country_label_line": { - "color": "text_night", - "width": 0.5, - "opacity": 0.5 - }, - "marine_label_line_1": { - "color": "water_dark_night", - "size": ["stops", - {"z": 3, "val": 20}, - {"z": 4, "val": 25}, - {"z": 5, "val": 30}, - {"z": 22, "val": 30} - ], - "stroke": "water_night" - }, - "marine_label_line_2": { - "color": "water_dark_night", - "size": ["stops", - {"z": 3, "val": 13}, - {"z": 4, "val": 14}, - {"z": 5, "val": 20}, - {"z": 6, "val": 24}, - {"z": 22, "val": 24} - ], - "stroke": "water_night" - }, - "marine_label_line_3": { - "color": "water_dark_night", - "size": ["stops", - {"z": 3, "val": 12}, - {"z": 4, "val": 13}, - {"z": 5, "val": 15}, - {"z": 6, "val": 18}, - {"z": 22, "val": 18} - ], - "stroke": "water_night" - }, - "marine_label_line_other": { - "color": "water_dark_night", - "size": ["stops", - {"z": 4, "val": 12}, - {"z": 5, "val": 14}, - {"z": 6, "val": 16}, - {"z": 22, "val": 16} - ], - "stroke": "water_night" - }, - "marine_label_point_1": { - "color": "water_dark_night", - "size": ["stops", - {"z": 3, "val": 20}, - {"z": 4, "val": 25}, - {"z": 5, "val": 30}, - {"z": 22, "val": 30} - ], - "stroke": "water_night" - }, - "marine_label_point_2": { - "color": "water_dark_night", - "size": ["stops", - {"z": 3, "val": 13}, - {"z": 4, "val": 14}, - {"z": 5, "val": 20}, - {"z": 6, "val": 24}, - {"z": 22, "val": 24} - ], - "stroke": "water_night" - }, - "marine_label_point_3": { - "color": "water_dark_night", - "size": ["stops", - {"z": 3, "val": 12}, - {"z": 4, "val": 13}, - {"z": 5, "val": 15}, - {"z": 6, "val": 18}, - {"z": 22, "val": 18} - ], - "stroke": "water_night" - }, - "marine_label_point_other": { - "color": "water_dark_night", - "size": ["stops", - {"z": 4, "val": 12}, - {"z": 5, "val": 14}, - {"z": 6, "val": 16}, - {"z": 22, "val": 16} - ], - "stroke": "water_night" - }, - "state_label": { - "color": "#fff", - "strokeWidth": 0.4, - "strokeBlur": 1, - "stroke": "land_night", - "size": [ - "stops", - {"z": 3.99, "val": 0}, - {"z": 4, "val": 10}, - {"z": 9.99, "val": 16}, - {"z": 10, "val": 0} - ] - }, - "place_label_city": { - "color": "#fff", - "strokeWidth": 0.4, - "stroke": "text2_stroke_night", - "size": [ - "stops", - {"z": 3.99, "val": 0}, - {"z": 4, "val": 10}, - {"z": 7, "val": 14}, - {"z": 14.99, "val": 20}, - {"z": 15, "val": 0} - ] - }, - "place_label_town": { - "color": "text_night", - "strokeWidth": 0.3, - "strokeBlur": 2, - "stroke": "text2_stroke_night", - "size": [ - "stops", - {"z": 9, "val": 10}, - {"z": 12, "val": 13}, - {"z": 14, "val": 17}, - {"z": 16, "val": 22} - ] - }, - "place_label_village": { - "color": "text_night", - "strokeWidth": 0.3, - "strokeBlur": 2, - "stroke": "text2_stroke_night", - "size": [ - "stops", - {"z": 9, "val": 8}, - {"z": 12, "val": 10}, - {"z": 14, "val": 14}, - {"z": 16, "val": 16}, - {"z": 17, "val": 20} - ] - }, - "place_label_other": { - "color": "text_night", - "stroke": "text2_stroke_night", - "strokeWidth": 0.3, - "strokeBlur": 2, - "size": [ - "stops", - {"z": 13, "val": 11}, - {"z": 14, "val": 12}, - {"z": 16, "val": 14}, - {"z": 18, "val": 18} - ] - }, - "road_label_1": { - "color": "text_night", - "stroke": "text2_stroke_night", - "strokeWidth": 0.5, - "strokeBlur": 3, - "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": "text_water_night", - "stroke": "water_night" - }, - "waterway_label": { - "color": "text_water_night", - "stroke": "water_night" - }, - "poi": { - "color": "white", - "antialias": false - }, - "poi_3": { - "antialias": false, - "opacity": [ - "stops", - {"z": 17.5, "val": 0}, - {"z": 17.75, "val": 1} - ] - }, - "poi_4_4": { - "antialias": false, - "opacity": [ - "stops", - {"z": 18, "val": 0}, - {"z": 17.25, "val": 1} - ] - }, - "poi_4_16": { - "antialias": false, - "opacity": [ - "stops", - {"z": 18.5, "val": 0}, - {"z": 18.75, "val": 1} - ] - }, - "poi_4_all": { - "antialias": false, - "opacity": [ - "stops", - {"z": 18.75, "val": 0}, - {"z": 19, "val": 1} - ] - }, - "poi_label_1-2": { - "color": "#fff", - "size": "poi_label_1-2_size", - "stroke": "text2_stroke_night", - "strokeWidth": 0.3, - "strokeBlur": 1 - }, - "poi_label_3": { - "color": "#fff", - "size": "poi_label_3_size", - "stroke": "text2_stroke_night", - "strokeWidth": 0.3, - "strokeBlur": 1, - "opacity": [ - "stops", - {"z": 17.5, "val": 0}, - {"z": 17.75, "val": 1} - ] - }, - "poi_label_4_4": { - "color": "#fff", - "size": 10, - "opacity": [ - "stops", - {"z": 18, "val": 0}, - {"z": 18.25, "val": 1} - ], - "stroke": "text2_stroke_night", - "strokeWidth": 0.3, - "strokeBlur": 1 - }, - "poi_label_4_16": { - "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 - }, - "poi_label_4_all": { - "color": "#fff", - "size": 10, - "opacity": [ - "stops", - {"z": 18.75, "val": 0}, - {"z": 19, "val": 1} - ], - "stroke": "text2_stroke_night", - "strokeWidth": 0.3, - "strokeBlur": 1 - }, - "poi_aerodrome": { - "opacity": ["stops", - {"z": 13, "val": 0}, - {"z": 13.25, "val": 1} - ], - "antialias": false - } - } + "style": { + "fill-color": "blue" + } + }, { + "id": "roads", + "layers": [{ + "id": "road", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "road", + "render": { + "type": "line", + "line-cap": "round", + "line-join": "bevel" + }, + "style": { + "line-color": "@road", + "line-blur": "@road_blur", + "line-width": { + "fn": "exponential", + "z": 10, + "val": -1, + "slope": 0.2, + "min": 1 } - ], - "sprite": "/img/maki-sprite" + } + }] + }, { + "id": "building", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "building", + "render": { + "type": "fill" + }, + "style": { + "fill-color": "@building", + "transition-fill-opacity": { + "duration": 500, + "delay": 500 + }, + "fill-opacity": { + "fn": "linear", + "z": 14, + "val": 0, + "slope": 1, + "min": 0, + "max": 1 + } + } + }, { + "id": "borders", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "admin", + "render": { + "type": "line" + }, + "style": { + "line-color": "rgba(0, 0, 0, 0.3)", + "line-width": 1 + } + }, { + "id": "poi", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "poi_label", + "render": { + "type": "icon", + "icon-size": 12 + }, + "style": { + "icon-rotate-anchor": "viewport" + } + }, { + "id": "country_label", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "country_label", + "filter": { "$type": "point" }, + "render": { + "type": "text", + "text-field": "{{name}}", + "text-font": "Open Sans Regular, Arial Unicode MS Regular", + "text-max-size": 16, + "text-path": "horizontal", + "text-padding": 10 + }, + "style": { + "text-halo-color": "rgba(255, 255, 255, 0.7)", + "text-halo-width": "@stroke_width", + "text-color": "@text" + } + }, { + "id": "road_label", + "source": "mapbox.mapbox-streets-v5", + "source-layer": "road_label", + "filter": { "$type": "line" }, + "render": { + "type": "text", + "text-field": "{{name}}", + "text-font": "Open Sans Regular, Arial Unicode MS Regular", + "text-max-size": 12, + "text-path": "curve", + "text-min-distance": 250, + "text-max-angle": 1.04 + }, + "style": { + "text-color": "@text", + "text-halo-color": "rgba(255, 255, 255, 0.7)", + "text-halo-width": "@stroke_width", + "text-size": { + "fn": "exponential", + "z": 14, + "val": 8, + "slope": 1, + "min": 8, + "max": 12 + } + } + }] }; diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index b4e6c7246..bcfa5f1bc 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -78,15 +78,8 @@ void GLFWView::key(GLFWwindow *window, int key, int /*scancode*/, int action, in break; case GLFW_KEY_R: if (!mods) { - std::set newAppliedClasses; - if (view->map->getAppliedClasses().count("night")) { - newAppliedClasses.insert("default"); - } else { - newAppliedClasses.insert("default"); - newAppliedClasses.insert(newAppliedClasses.end(), "night"); - } view->map->setDefaultTransitionDuration(300); - view->map->setAppliedClasses(newAppliedClasses); + view->map->toggleClass("night"); } break; case GLFW_KEY_N: diff --git a/include/llmr/geometry/buffer.hpp b/include/llmr/geometry/buffer.hpp index 27807c809..607f902bf 100644 --- a/include/llmr/geometry/buffer.hpp +++ b/include/llmr/geometry/buffer.hpp @@ -32,6 +32,10 @@ public: return pos / itemSize; } + inline bool empty() const { + return pos == 0; + } + // Transfers this buffer to the GPU and binds the buffer to the GL context. void bind(bool force = false) { if (buffer == 0) { diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index e20803b99..ee5debe4d 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -21,8 +21,6 @@ namespace llmr { class Source; -typedef std::map> Sources; - class Map : private util::noncopyable { public: explicit Map(View &view); @@ -53,8 +51,9 @@ public: void resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width, uint16_t fb_height); // Styling - void setAppliedClasses(std::set appliedClasses); - std::set getAppliedClasses() const; + void toggleClass(const std::string &name); +// void setAppliedClasses(const std::vector &appliedClasses); +// const std::vector &getAppliedClasses() const; void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0); void setStyleJSON(std::string newStyleJSON); std::string getStyleJSON() const; @@ -108,7 +107,7 @@ public: inline std::shared_ptr getTexturepool() { return texturepool; } inline std::shared_ptr getLoop() { return loop; } inline time getAnimationTime() const { return animationTime; } - inline const Sources &getSources() { return sources; } + inline time getTime() const { return animationTime; } private: // uv async callbacks @@ -133,8 +132,8 @@ private: // Unconditionally performs a render with the current map state. void render(); - void renderLayers(const std::vector& layers); - void renderLayer(const LayerDescription& layer_desc, RenderPass pass); + void renderLayers(std::shared_ptr layers); + void renderLayer(std::shared_ptr layer_desc, RenderPass pass); private: // If cleared, the next time the render thread attempts to render the map, it will *actually* @@ -162,8 +161,6 @@ private: Painter painter; - Sources sources; - std::string styleJSON = ""; bool debug = false; diff --git a/include/llmr/map/raster_tile_data.hpp b/include/llmr/map/raster_tile_data.hpp index fd72cca9b..f84b540d4 100644 --- a/include/llmr/map/raster_tile_data.hpp +++ b/include/llmr/map/raster_tile_data.hpp @@ -16,8 +16,8 @@ public: ~RasterTileData(); virtual void parse(); - virtual void render(Painter &painter, const LayerDescription& layer_desc); - virtual bool hasData(const LayerDescription& layer_desc) const; + virtual void render(Painter &painter, std::shared_ptr layer_desc); + virtual bool hasData(std::shared_ptr layer_desc) const; protected: RasterBucket bucket; diff --git a/include/llmr/map/source.hpp b/include/llmr/map/source.hpp index 7ce6aa632..c27250858 100644 --- a/include/llmr/map/source.hpp +++ b/include/llmr/map/source.hpp @@ -16,60 +16,49 @@ namespace llmr { -class Map; class TransformState; -class Painter; class Texturepool; class Source : public std::enable_shared_from_this, private util::noncopyable { public: - enum class Type { - vector, - raster - }; + Source(SourceType type = SourceType::Vector, const std::string &url = "", const std::string &glyphs = "", + uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22); -public: - Source(Map &map, Painter &painter, - const char *url = "", Type type = Type::vector, std::vector zooms = {0}, - uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 14, - bool enabled = true); - - - bool update(); - void updateMatrices(const TransformState &transform); - void drawClippingMasks(); + bool update(Map &map); + void updateMatrices(const mat4 &projMatrix, const TransformState &transform); + void drawClippingMasks(Painter &painter); size_t getTileCount() const; - void render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc); - void finishRender(); + void render(Painter &painter, std::shared_ptr layer_desc); + void finishRender(Painter &painter); std::forward_list getIDs() const; void updateClipIDs(const std::map &mapping); + static std::string normalizeSourceURL(const std::string &url); + public: - bool enabled; + const SourceType type; + const std::string url; + const std::string glyphs; + const uint32_t tile_size; + const int32_t min_zoom; + const int32_t max_zoom; private: bool findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list& retain); bool findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::forward_list& retain); - std::forward_list covering_tiles(int32_t zoom, const box& points); + std::forward_list covering_tiles(const TransformState &state, int32_t clamped_zoom, const box& points); - bool updateTiles(); + bool updateTiles(Map &map); - TileData::State addTile(const Tile::ID& id); + TileData::State addTile(Map &map, const Tile::ID& id); TileData::State hasTile(const Tile::ID& id); - double getZoom() const; + double getZoom(const TransformState &state) const; private: - Map& map; - Painter& painter; - - const Type type; - const std::vector zooms; - const std::string url; - const uint32_t tile_size; - const int32_t min_zoom; - const int32_t max_zoom; + // Stores the time when this source was most recently updated. + time updated = 0; std::map> tiles; std::map> tile_data; diff --git a/include/llmr/map/tile_data.hpp b/include/llmr/map/tile_data.hpp index 0717f6c92..09f36d59b 100644 --- a/include/llmr/map/tile_data.hpp +++ b/include/llmr/map/tile_data.hpp @@ -16,7 +16,7 @@ namespace llmr { class Map; class Painter; -class LayerDescription; +class StyleLayer; class TileData : public std::enable_shared_from_this, private util::noncopyable { @@ -49,8 +49,8 @@ public: virtual void beforeParse(); virtual void parse() = 0; virtual void afterParse(); - virtual void render(Painter &painter, const LayerDescription& layer_desc) = 0; - virtual bool hasData(const LayerDescription& layer_desc) const = 0; + virtual void render(Painter &painter, std::shared_ptr layer_desc) = 0; + virtual bool hasData(std::shared_ptr layer_desc) const = 0; public: diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index edeb3b000..9e763a13a 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace llmr { @@ -14,8 +15,13 @@ class GlyphAtlas; class GlyphStore; class SpriteAtlas; class VectorTileData; +class StyleLayer; +typedef std::vector> StyleLayerGroup; +class StyleBucket; +class StyleBucketFill; +class StyleBucketLine; +class StyleBucketIcon; -class LayerDescription; class Bucket; class TileParser { @@ -32,15 +38,17 @@ public: private: bool obsolete() const; void parseGlyphs(); - void parseStyleLayers(const std::vector& layers); + void parseStyleLayers(std::shared_ptr 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); - std::unique_ptr createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); - std::unique_ptr createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); - template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc); - template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args&& ...args); + std::unique_ptr createBucket(std::shared_ptr bucket_desc); + + std::unique_ptr createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill); + std::unique_ptr createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line); + std::unique_ptr createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon); + std::unique_ptr createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text); + + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter); + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args); private: const VectorTile vector_data; diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp index 904cc9a2e..b2f3d416e 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -67,14 +67,14 @@ public: }; public: - FilteredVectorTileLayer(const VectorTileLayer& layer, const BucketDescription& bucket_desc); + FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression); iterator begin() const; iterator end() const; private: const VectorTileLayer& layer; - const BucketDescription& bucket_desc; + const PropertyFilterExpression& filterExpression; }; std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement); diff --git a/include/llmr/map/vector_tile_data.hpp b/include/llmr/map/vector_tile_data.hpp index 717ed79a3..d6f5391c2 100644 --- a/include/llmr/map/vector_tile_data.hpp +++ b/include/llmr/map/vector_tile_data.hpp @@ -29,8 +29,8 @@ public: virtual void beforeParse(); virtual void parse(); virtual void afterParse(); - virtual void render(Painter &painter, const LayerDescription& layer_desc); - virtual bool hasData(const LayerDescription& layer_desc) const; + virtual void render(Painter &painter, std::shared_ptr layer_desc); + virtual bool hasData(std::shared_ptr layer_desc) const; protected: // Holds the actual geometries in this tile. diff --git a/include/llmr/renderer/bucket.hpp b/include/llmr/renderer/bucket.hpp index 43bd96e3f..c135b8ee1 100644 --- a/include/llmr/renderer/bucket.hpp +++ b/include/llmr/renderer/bucket.hpp @@ -10,10 +10,11 @@ namespace llmr { class Painter; +class StyleLayer; class Bucket : private util::noncopyable { public: - virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id) = 0; + virtual void render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id) = 0; virtual bool hasData() const = 0; virtual ~Bucket() {} diff --git a/include/llmr/renderer/debug_bucket.hpp b/include/llmr/renderer/debug_bucket.hpp index 0b9df57fa..b0b4f7cd0 100644 --- a/include/llmr/renderer/debug_bucket.hpp +++ b/include/llmr/renderer/debug_bucket.hpp @@ -21,7 +21,7 @@ class DebugBucket : public Bucket { public: DebugBucket(DebugFontBuffer& fontBuffer); - virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); + virtual void render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id); virtual bool hasData() const; void drawLines(PlainShader& shader); diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp index 95d53ce75..95de06464 100644 --- a/include/llmr/renderer/fill_bucket.hpp +++ b/include/llmr/renderer/fill_bucket.hpp @@ -41,10 +41,10 @@ public: FillBucket(FillVertexBuffer& vertexBuffer, TriangleElementsBuffer& triangleElementsBuffer, LineElementsBuffer& lineElementsBuffer, - const BucketFillDescription& properties); + const StyleBucketFill& properties); ~FillBucket(); - virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); + virtual void render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id); virtual bool hasData() const; void addGeometry(pbf& data); @@ -55,7 +55,7 @@ public: void drawVertices(OutlineShader& shader); public: - const BucketFillDescription &properties; + const StyleBucketFill &properties; private: TESSalloc *allocator; diff --git a/include/llmr/renderer/icon_bucket.hpp b/include/llmr/renderer/icon_bucket.hpp index 5d653a15f..e6fe161f1 100644 --- a/include/llmr/renderer/icon_bucket.hpp +++ b/include/llmr/renderer/icon_bucket.hpp @@ -26,9 +26,9 @@ class VectorTileFeature; class IconBucket : public Bucket { public: IconBucket(IconVertexBuffer& vertexBuffer, - const BucketIconDescription& properties); + const StyleBucketIcon& properties); - virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); + virtual void render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id); virtual bool hasData() const; void addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas); @@ -37,7 +37,7 @@ public: void drawIcons(DotShader& shader); public: - const BucketIconDescription &properties; + const StyleBucketIcon &properties; private: diff --git a/include/llmr/renderer/line_bucket.hpp b/include/llmr/renderer/line_bucket.hpp index d7253ace9..f33982a52 100644 --- a/include/llmr/renderer/line_bucket.hpp +++ b/include/llmr/renderer/line_bucket.hpp @@ -25,9 +25,9 @@ public: LineBucket(LineVertexBuffer& vertexBuffer, TriangleElementsBuffer& triangleElementsBuffer, PointElementsBuffer& pointElementsBuffer, - const BucketLineDescription& properties); + const StyleBucketLine& properties); - virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); + virtual void render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id); virtual bool hasData() const; void addGeometry(pbf& data); @@ -39,7 +39,7 @@ public: void drawPoints(LinejoinShader& shader); public: - const BucketLineDescription &properties; + const StyleBucketLine &properties; private: diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 104f4c9bd..1adca7045 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -24,6 +24,7 @@ #include #include +#include namespace llmr { @@ -42,8 +43,6 @@ class RasterBucket; class LayerDescription; class RasterTileData; -typedef std::map> Sources; - class Painter : private util::noncopyable { public: Painter(Map &map); @@ -64,7 +63,7 @@ public: void changeMatrix(); // Renders a particular layer from a tile. - void renderTileLayer(const Tile& tile, const LayerDescription &layer_desc); + void renderTileLayer(const Tile& tile, std::shared_ptr layer_desc); // Renders debug information for a tile. void renderTileDebug(const Tile& tile); @@ -79,15 +78,15 @@ public: void renderDebugText(DebugBucket& bucket); void renderDebugText(const std::vector &strings); void renderFill(FillBucket& bucket, const FillProperties& properties, const Tile::ID& id, const mat4 &mat); - void renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id); - void renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id); - void renderIcon(IconBucket& bucket, const std::string& layer_name, const Tile::ID& id); - void renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id); - void renderRaster(RasterBucket& bucket, const std::string& layer_name, const Tile::ID& id); + void renderFill(FillBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id); + void renderLine(LineBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id); + void renderIcon(IconBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id); + void renderText(TextBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id); + void renderRaster(RasterBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id); void preparePrerender(PrerenderedTexture &texture); void finishPrerender(PrerenderedTexture &texture); - void renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties); +// void renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties); void resize(); @@ -101,7 +100,7 @@ public: // Configures the painter strata that is used for early z-culling of fragments. void setStrata(float strata); - void drawClippingMasks(const Sources &sources); + void drawClippingMasks(const std::set> &sources); void drawClippingMask(const mat4& matrix, const ClipID& clip); void clearFramebuffers(); @@ -115,7 +114,7 @@ public: bool needsAnimation() const; private: void setupShaders(); - const mat4 &translatedMatrix(const std::array &translation, const Tile::ID &id, TranslateAnchor anchor = TranslateAnchor::Map); + const mat4 &translatedMatrix(const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor = parseTranslateAnchorType()); void prepareTile(const Tile& tile); diff --git a/include/llmr/renderer/raster_bucket.hpp b/include/llmr/renderer/raster_bucket.hpp index 675d15f82..bbd5dee27 100644 --- a/include/llmr/renderer/raster_bucket.hpp +++ b/include/llmr/renderer/raster_bucket.hpp @@ -15,7 +15,7 @@ class RasterBucket : public Bucket { public: RasterBucket(const std::shared_ptr &texturepool); - virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); + virtual void render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id); virtual bool hasData() const; bool setImage(const std::string &data); diff --git a/include/llmr/renderer/text_bucket.hpp b/include/llmr/renderer/text_bucket.hpp index 566ed459e..abc95b165 100644 --- a/include/llmr/renderer/text_bucket.hpp +++ b/include/llmr/renderer/text_bucket.hpp @@ -28,9 +28,9 @@ public: TextBucket( TextVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, - const BucketTextDescription &properties, Placement &placement); + const StyleBucketText &properties, Placement &placement); - virtual void render(Painter &painter, const std::string &layer_name, const Tile::ID &id); + virtual void render(Painter &painter, std::shared_ptr layer_desc, const Tile::ID &id); virtual bool hasData() const; void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, @@ -43,7 +43,7 @@ public: void drawGlyphs(TextShader &shader); public: - const BucketTextDescription &properties; + const StyleBucketText &properties; private: TextVertexBuffer& vertexBuffer; diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index a2386e436..9b1bb5c77 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -8,125 +8,11 @@ #include #include #include +#include namespace llmr { -enum class BucketType { - None = 0, - Fill = 1, - Line = 2, - Icon = 3, - Text = 4, - Raster = 5 -}; - -enum class CapType { - None = 0, - Round = 1, - Butt = 2, - Square = 3 -}; - -enum class JoinType { - None = 0, - Miter = 1, - Bevel = 2, - Round = 3 -}; - -enum class TextPathType { - Horizontal = 0, - Curve = 1 -}; - - -inline BucketType bucketType(const std::string& type) { - if (type == "fill") return BucketType::Fill; - else if (type == "line") return BucketType::Line; - else if (type == "point") return BucketType::Icon; - else if (type == "text") return BucketType::Text; - else if (type == "raster") return BucketType::Raster; - else return BucketType::None; -} - -inline CapType capType(const std::string& cap) { - if (cap == "round") return CapType::Round; - else if (cap == "butt") return CapType::Butt; - else if (cap == "square") return CapType::Square; - else return CapType::None; -} - - -inline JoinType joinType(const std::string& join) { - if (join == "miter") return JoinType::Miter; - else if (join == "bevel") return JoinType::Bevel; - else if (join == "round") return JoinType::Round; - else return JoinType::None; -} - -inline TextPathType textPathType(const std::string& path) { - if (path == "horizontal") return TextPathType::Horizontal; - else if (path == "curve") return TextPathType::Curve; - else return TextPathType::Horizontal; -}; - -inline float alignmentType(const std::string& alignment) { - if (alignment == "right") return 1.0f; - else if (alignment == "left") return 0.0f; - else return 0.5; -}; - -inline float verticalAlignmentType(const std::string& alignment) { - if (alignment == "bottom") return 1.0f; - else if (alignment == "top") return 0.0f; - else return 0.5; -}; - -class BucketFillDescription { -public: -}; - -class BucketLineDescription { -public: - CapType cap = CapType::None; - JoinType join = JoinType::None; - float miter_limit = 2.0f; - float round_limit = 1.0f; -}; - -class BucketIconDescription { -public: - uint16_t size = 16; - vec2 translate {0, 0}; - std::string icon; -}; - -class BucketTextDescription { -public: - std::string field; - TextPathType path = TextPathType::Horizontal; - std::string font; - float max_size = 16.0f; - float max_width = 15.0f * 24; - float line_height = 1.2f * 24; - float letter_spacing = 0.0f; - float alignment = 0.5f; - float vertical_alignment = 0.5; - vec2 translate {0, 0}; - float max_angle_delta = M_PI; - float min_distance = 250.0f; - float rotate = 0.0f; // what is this? - float padding = 2.0f; - bool always_visible = false; -}; - -class BucketRasterDescription { -public: -}; - -typedef util::variant BucketRenderDescription; - +// Deprecated class BucketDescription { public: BucketType feature_type = BucketType::None; @@ -139,7 +25,7 @@ public: PropertyFilterExpression filter = std::true_type(); // Specifies how the geometry for this bucket should be created - BucketRenderDescription render; + StyleBucketRender render; }; std::ostream& operator<<(std::ostream&, const BucketDescription& bucket); diff --git a/include/llmr/style/layer_description.hpp b/include/llmr/style/layer_description.hpp index 97cb7d6f2..75013db72 100644 --- a/include/llmr/style/layer_description.hpp +++ b/include/llmr/style/layer_description.hpp @@ -5,17 +5,17 @@ #include namespace llmr { - -class LayerDescription { -public: - std::string name; - std::string bucket_name; - std::vector child_layer; - - size_t size() const; -}; - -std::ostream& operator<<(std::ostream&, const LayerDescription& layer); +// +//class LayerDescription { +//public: +// std::string name; +// std::string bucket_name; +// std::vector child_layer; +// +// size_t size() const; +//}; +// +//std::ostream& operator<<(std::ostream&, const LayerDescription& layer); } diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index c31942f94..cc85122a2 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -13,16 +13,14 @@ #include #include +#include + namespace llmr { // Stores a premultiplied color, with all four channels ranging from 0..1 typedef std::array Color; -struct PropertyTransition { - inline PropertyTransition(uint16_t duration, uint16_t delay = 0) - : duration(duration), delay(delay) {} - inline PropertyTransition(const PropertyTransition &transition) - : duration(transition.duration), delay(transition.delay) {} +struct ClassPropertyTransition { uint16_t duration = 0; uint16_t delay = 0; }; @@ -43,32 +41,12 @@ enum class TransitionablePropertyKey { HaloBlur = 13, }; -enum class Winding { - EvenOdd = 1, - NonZero = 2 -}; - -// enum LineCap { -// Round = 1 -// }; - -// enum LineJoin { -// Butt = 1, -// Bevel = 2 -// }; - enum class Property { Null = 1, Constant = 2, Stops = 3, Linear = 4 }; - -enum class TranslateAnchor : uint8_t { - Map = 1, - Viewport = 2 -}; - namespace functions { float null(float z, const std::vector&); @@ -104,88 +82,73 @@ struct FunctionProperty { template inline T evaluate(float z) const { return function(z, values); } }; - -enum class RenderType { - Fill, - Line, - Icon, - Text, - Raster, - Composite, - Background -}; - enum class ClassPropertyKey { - Enabled, - TranslateX, - TranslateY, - TranslateTransition, - TranslateAnchor, - Opacity, - OpacityTransition, - Prerender, - PrerenderBuffer, - PrerenderSize, - PrerenderBlur, - - FillWinding, + FillEnabled, FillAntialias, + FillOpacity, FillColor, - FillColorTransition, - FillStrokeColor, - FillStrokeColorTransition, + FillOutlineColor, + FillTranslate, // for transitions only + FillTranslateX, + FillTranslateY, + FillTranslateAnchor, FillImage, - LineWidth, - LineWidthTransition, - LineOffset, - LineOffsetTransition, + LineEnabled, + LineOpacity, LineColor, - LineColorTransition, + LineTranslate, // for transitions only + LineTranslateX, + LineTranslateY, + LineTranslateAnchor, + LineWidth, + LineOffset, + LineBlur, + LineDashArray, // for transitions only LineDashLand, LineDashGap, - LineDashTransition, + LineImage, - IconSize, - IconColor, - IconColorTransition, - IconImage, - IconRadius, - IconRadiusTransition, - IconBlur, - IconBlurTransition, + IconEnabled, + IconOpacity, + IconRotate, + IconRotateAnchor, - TextColor, - TextColorTransition, - TextHaloColor, - TextHaloColorTransition, - TextHaloRadius, - TextHaloRadiusTransition, - TextHaloBlur, - TextHaloBlurTransition, + TextEnabled, + TextOpacity, TextSize, - TextRotate, - TextAlwaysVisible, + TextColor, + TextHaloColor, + TextHaloWidth, + TextHaloBlur, - BackgroundColor, - BackgroundColorTransition, + CompositeEnabled, + CompositeOpacity, + + RasterSpin, + RasterBrightnessLow, + RasterBrightnessHigh, + RasterSaturation, + RasterContrast, + RasterFade, + + BackgroundColor }; typedef util::variant< FunctionProperty, - PropertyTransition, - TranslateAnchor, + TranslateAnchorType, + RotateAnchorType, Color, - Winding, std::string, bool > ClassPropertyValue; class ClassProperties { public: - inline ClassProperties(RenderType type) : type(type) {} + inline ClassProperties() {} inline ClassProperties(ClassProperties &&properties) - : type(properties.type), properties(std::move(properties.properties)) {} + : properties(std::move(properties.properties)) {} template inline const T *get(ClassPropertyKey key) const { @@ -196,16 +159,27 @@ public: return nullptr; } } - - template - inline void emplace(Args&& ...args) { - properties.emplace(::std::forward(args)...); + inline const ClassPropertyTransition *getTransition(ClassPropertyKey key) const { + const auto it = transitions.find(key); + if (it != transitions.end()) { + return ::std::addressof(it->second); + } else { + return nullptr; + } } - const RenderType type; + template + inline void set(Args&& ...args) { + properties.emplace(::std::forward(args)...); + } + template + inline void setTransition(Args&& ...args) { + transitions.emplace(::std::forward(args)...); + } -private: +public: std::map properties; + std::map transitions; }; struct PrerenderProperties { @@ -213,99 +187,164 @@ struct PrerenderProperties { uint16_t size = 256; uint16_t blur = 0; }; +// +//struct GenericProperties { +// bool enabled = true; +// std::array translate = {{ 0, 0 }}; +// TranslateAnchorType translateAnchor = parseTranslateAnchorType(); +// float opacity = 1.0; +// +// // These are unresolved properties because the value here is per tile, so it might differ. +// boost::optional prerender; +// boost::optional prerenderBuffer; +// boost::optional prerenderSize; +// boost::optional prerenderBlur; +// +// inline bool getPrerender(int8_t z) const { +// return prerender && prerender.get().evaluate(z); +// } +// +// // Obtains prerender properties by integer zoom level. +// inline PrerenderProperties getPrerenderProperties(int8_t z) const { +// PrerenderProperties props; +// if (prerenderBuffer) props.buffer = prerenderBuffer.get().evaluate(z); +// if (prerenderSize) props.size = prerenderSize.get().evaluate(z); +// if (prerenderBlur) props.blur = prerenderBlur.get().evaluate(z); +// return props; +// } +// +// virtual bool isVisible() const { +// if (!enabled) { return false; } +// if (opacity <= 0) { return false; } +// return true; +// } +//}; -struct GenericProperties { +struct FillProperties { + FillProperties() {} bool enabled = true; - std::array translate = {{ 0, 0 }}; - TranslateAnchor translateAnchor = TranslateAnchor::Map; - float opacity = 1.0; - - // These are unresolved properties because the value here is per tile, so it might differ. - boost::optional prerender; - boost::optional prerenderBuffer; - boost::optional prerenderSize; - boost::optional prerenderBlur; - - inline bool getPrerender(int8_t z) const { - return prerender && prerender.get().evaluate(z); - } - - // Obtains prerender properties by integer zoom level. - inline PrerenderProperties getPrerenderProperties(int8_t z) const { - PrerenderProperties props; - if (prerenderBuffer) props.buffer = prerenderBuffer.get().evaluate(z); - if (prerenderSize) props.size = prerenderSize.get().evaluate(z); - if (prerenderBlur) props.blur = prerenderBlur.get().evaluate(z); - return props; - } - - virtual bool isVisible() const { - if (!enabled) { return false; } - if (opacity <= 0) { return false; } - return true; - } -}; - -struct IconProperties : public GenericProperties { - inline IconProperties() : GenericProperties() {} - float size = 0; - Color color = {{ 1, 1, 1, 1 }}; - std::string image; - float radius = 0; - float blur = 0; -}; - -struct LineProperties : public GenericProperties { - inline LineProperties() : GenericProperties() {} - float width = 0; - float offset = 0; - Color color = {{ 0, 0, 0, 1 }}; - std::array dash_array = {{ 1, -1 }}; -}; - -struct FillProperties : public GenericProperties { - inline FillProperties() : GenericProperties() {} - Winding winding = Winding::NonZero; bool antialias = true; + float opacity = 1.0f; Color fill_color = {{ 0, 0, 0, 1 }}; Color stroke_color = {{ 0, 0, 0, 1 }}; - float blur = 0.0f; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translateAnchor = parseTranslateAnchorType(); std::string image; + + inline bool isVisible() const { + return enabled && opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0); + } }; -struct TextProperties : public GenericProperties { - inline TextProperties() : GenericProperties() {} +struct LineProperties { + inline LineProperties() {} + bool enabled = true; + float opacity = 1.0f; Color color = {{ 0, 0, 0, 1 }}; - Color halo = {{ 1, 1, 1, 0.75 }}; - float halo_radius = 0.25f; - float halo_blur = 1.0f; - float size = 12.0f; - float rotate = 0.0f; - bool always_visible = false; + std::array translate = {{ 0, 0 }}; + TranslateAnchorType translateAnchor = parseTranslateAnchorType(); + float width = 0; + float offset = 0; + float blur = 0; + std::array dash_array = {{ 1, -1 }}; + std::string image; + + inline bool isVisible() const { + return enabled && opacity > 0 && color[3] > 0 && width > 0; + } }; -struct BackgroundProperties : public GenericProperties { - inline BackgroundProperties() : GenericProperties() {} +struct IconProperties { + inline IconProperties() {} + bool enabled = true; + float opacity = 1.0f; + float rotate = 0.0f; + RotateAnchorType rotate_anchor = parseRotateAnchorType(); + + inline bool isVisible() const { + return enabled && opacity > 0; + } +}; + +struct TextProperties { + inline TextProperties() {} + bool enabled = true; + float opacity = 1.0f; + float size = 12.0f; + Color color = {{ 0, 0, 0, 1 }}; + Color halo_color = {{ 1, 1, 1, 0.75 }}; + float halo_width = 0.25f; + float halo_blur = 1.0f; + + inline bool isVisible() const { + return enabled && opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0; + } +}; + +struct CompositeProperties { + inline CompositeProperties() {} + bool enabled = true; + float opacity = 1.0f; + + inline bool isVisible() const { + return enabled && opacity > 0; + } +}; + +struct RasterProperties { + inline RasterProperties() {} + bool enabled = true; + float opacity = 1.0f; + float spin = 0.0f; + std::array brightness = {{ 0, 1 }}; + float saturation = 0.0f; + float contrast = 0.0f; + float fade = 0.0f; + + inline bool isVisible() const { + return enabled && opacity > 0; + } +}; + +struct BackgroundProperties { + inline BackgroundProperties() {} Color color = {{ 1, 1, 1, 1 }}; }; -struct RasterProperties : public GenericProperties { - inline RasterProperties() : GenericProperties() {} +typedef util::variant< + FillProperties, + LineProperties, + IconProperties, + TextProperties, + CompositeProperties, + RasterProperties, + BackgroundProperties, + std::false_type +> StyleProperties; + +template +const T &defaultStyleProperties(); + + + + +//class StyleSource { +//public: +// typedef std::shared_ptr Ptr; +// +// enum { Vector, Raster } type = Vector; +// std::string url; +// float tileSize = 512.0f; +//}; + +class RasterizeProperties { +public: + boost::optional enabled; + boost::optional buffer; + boost::optional size; + boost::optional blur; }; -struct CompositeProperties : public GenericProperties { - inline CompositeProperties() : GenericProperties() {} -}; - - -const IconProperties defaultIconProperties; -const LineProperties defaultLineProperties; -const FillProperties defaultFillProperties; -const TextProperties defaultTextProperties; -const BackgroundProperties defaultBackgroundProperties; -const RasterProperties defaultRasterProperties; -const CompositeProperties defaultCompositeProperties; - } diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 5dc19a11a..d4b5a7961 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -21,6 +21,33 @@ namespace llmr { class Sprite; +class StyleLayer; +typedef std::vector> StyleLayerGroup; + +class StyleLayer { +public: + typedef std::shared_ptr Ptr; + +public: + template const T &getProperties() { + if (style.is()) { + return style.get(); + } else { + return defaultStyleProperties(); + } + } + +public: + std::string id; + StyleBucket::Ptr bucket; + std::unordered_map styles; + StyleProperties style; + std::unique_ptr rasterize; + std::shared_ptr layers; +}; + + + class Style { public: struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} }; @@ -41,69 +68,90 @@ public: void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0); + void updateSources(); + const std::set> getActiveSources() const; + + void toggleClass(const std::string &name); + public: std::shared_ptr sprite; + std::shared_ptr layers; + std::shared_ptr background; + std::vector appliedClasses; - // This is static information parsed from the stylesheet. - std::map buckets; - std::vector layers; - std::map classes; - - // Currently applied settings. - std::set appliedClasses; - struct { - BackgroundProperties background; - std::unordered_map fills; - std::unordered_map lines; - std::unordered_map icons; - std::unordered_map texts; - std::unordered_map rasters; - std::unordered_map composites; - std::unordered_map> effective_classes; - } computed; private: - bool transitionInProgress(const std::string &layer_name, TransitionablePropertyKey key, time start); - bool transitionExists(const std::string &layer_name, TransitionablePropertyKey key) const; - bool inNeedOfTransition(const std::string &layer_name, TransitionablePropertyKey key) const; - uint64_t transitionDuration(const std::string &layer_name, TransitionablePropertyKey key) const; - uint64_t transitionDelay(const std::string &layer_name, TransitionablePropertyKey key) const; + void updateSources(const std::shared_ptr &layers); + void cascade(const std::shared_ptr &layers, float z); - void cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); - void cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); - void cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); - void cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); - void cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); - void cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); - void cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); - void cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +private: + std::set> activeSources; + + // This is static information parsed from the stylesheet. + +// // This is unused!!! +// std::map buckets; +// +// +// std::vector layers; +// +// // These are unused!!! +// std::map classes; +// +// // Currently applied settings. +// struct { +// BackgroundProperties background; +// std::unordered_map fills; +// std::unordered_map lines; +// std::unordered_map icons; +// std::unordered_map texts; +// std::unordered_map rasters; +// std::unordered_map composites; +// std::unordered_map> effective_classes; +// } computed; + +private: +// bool transitionInProgress(const std::string &layer_name, TransitionablePropertyKey key, time start); +// bool transitionExists(const std::string &layer_name, TransitionablePropertyKey key) const; +// bool inNeedOfTransition(const std::string &layer_name, TransitionablePropertyKey key) const; +// uint64_t transitionDuration(const std::string &layer_name, TransitionablePropertyKey key) const; +// uint64_t transitionDelay(const std::string &layer_name, TransitionablePropertyKey key) const; +// +// void cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +// void cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +// void cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +// void cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +// void cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +// void cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +// void cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); +// void cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z); private: // Last applied settings. - struct { - BackgroundProperties background; - std::unordered_map fills; - std::unordered_map lines; - std::unordered_map icons; - std::unordered_map texts; - std::unordered_map rasters; - std::unordered_map composites; - std::unordered_map> effective_classes; - } previous; +// struct { +// BackgroundProperties background; +// std::unordered_map fills; +// std::unordered_map lines; +// std::unordered_map icons; +// std::unordered_map texts; +// std::unordered_map rasters; +// std::unordered_map composites; +// std::unordered_map> effective_classes; +// } previous; - // Settings values currently being transitioned. - struct { - BackgroundProperties background; - std::unordered_map fills; - std::unordered_map lines; - std::unordered_map icons; - std::unordered_map texts; - std::unordered_map rasters; - std::unordered_map composites; - } transitioning; +// // Settings values currently being transitioned. +// struct { +// BackgroundProperties background; +// std::unordered_map fills; +// std::unordered_map lines; +// std::unordered_map icons; +// std::unordered_map texts; +// std::unordered_map rasters; +// std::unordered_map composites; +// } transitioning; - std::unordered_map> properties_to_transition; - std::unordered_map>> transitions; +// std::unordered_map> properties_to_transition; +// std::unordered_map>> transitions; uint64_t default_transition_duration = 0; bool initial_render_complete = false; diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp new file mode 100644 index 000000000..f39ea0161 --- /dev/null +++ b/include/llmr/style/style_bucket.hpp @@ -0,0 +1,82 @@ +#ifndef LLMR_STYLE_STYLE_BUCKET +#define LLMR_STYLE_STYLE_BUCKET + +#include +#include +#include +#include + +namespace llmr { + +class Source; + +class StyleBucketFill { +public: + WindingType winding = parseWindingType(); +}; + +class StyleBucketLine { +public: + CapType cap = parseCapType(); + JoinType join = parseJoinType(); + float miter_limit = 2.0f; + float round_limit = 1.0f; +}; + +class StyleBucketIcon { +public: + uint16_t size = 16; + vec2 translate {0, 0}; + TranslateAnchorType translate_anchor = parseTranslateAnchorType(); + std::string icon; + float spacing = 0.0f; + float padding = 2.0f; +}; + +class StyleBucketText { +public: + std::string field; + TextPathType path = parseTextPathType(); + std::string font; + float max_size = 16.0f; + float max_width = 15.0f * 24; + float line_height = 1.2f * 24; + float letter_spacing = 0.0f; + float alignment = 0.5f; + float vertical_alignment = 0.5; + vec2 translate {0, 0}; + TranslateAnchorType translate_anchor = parseTranslateAnchorType(); + float max_angle_delta = M_PI; + float min_distance = 250.0f; + float rotate = 0.0f; // what is this? + float padding = 2.0f; + float slant = 0.0f; + bool always_visible = false; +}; + +class StyleBucketRaster { +public: +}; + +typedef util::variant StyleBucketRender; + + +class StyleBucket { +public: + typedef std::shared_ptr Ptr; + + BucketType type = BucketType::None; + std::string name; + std::shared_ptr source; + std::string source_layer; + PropertyFilterExpression filter = std::true_type(); + StyleBucketRender render = std::false_type(); +}; + + + +}; + +#endif diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 0d254f33e..cdfd61094 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -3,63 +3,74 @@ #include #include +#include + +#include +#include + namespace llmr { +class StyleLayer; +typedef std::vector> StyleLayerGroup; + class StyleParser { public: using JSVal = const rapidjson::Value&; - 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, - const std::map &buckets, - const std::vector &layers); + void parse(JSVal document); -private: - LayerDescription parseLayer(JSVal value); - BucketDescription parseBucket(JSVal value); - - std::pair - parseClassDescription(JSVal value, - const std::map &buckets, - const std::map &layerBuckets); - - void parseClass(const std::string &name, JSVal value, ClassDescription &class_desc, - const std::map &buckets, - const std::map &layerBuckets); - - void parseGenericClass(ClassProperties &klass, JSVal value); - ClassProperties parseFillClass(JSVal value); - ClassProperties parseLineClass(JSVal value); - ClassProperties parseIconClass(JSVal value); - ClassProperties parseTextClass(JSVal value); - ClassProperties parseBackgroundClass(JSVal value); - ClassProperties parseRasterClass(JSVal value); - ClassProperties parseCompositeClass(JSVal value); - - PropertyFilterExpression parseFilterOrExpression(JSVal value); - - JSVal replaceConstant(JSVal value); - Value parseValue(JSVal value); - - template - T parse(JSVal value); - - template - inline void parse(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { - if (value.HasMember(property_name)) { - klass.emplace(key, parse(value[property_name])); - } + std::shared_ptr getLayers() { + return root; } - void parseTransition(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); - void parseFunctionArray(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); +private: + void parseConstants(JSVal value); + JSVal replaceConstant(JSVal value); + void parseSources(JSVal value); + + std::unique_ptr createLayers(JSVal value); + std::shared_ptr createLayer(JSVal value); + void parseLayers(); + void parseLayer(std::pair> &pair); + void parseStyles(JSVal value, std::shared_ptr &layer); + void parseStyle(JSVal, ClassProperties &properties); + void parseRasterize(JSVal value, std::shared_ptr &layer); + void parseReference(JSVal value, std::shared_ptr &layer); + void parseBucket(JSVal value, std::shared_ptr &layer); + void parseFilter(JSVal value, std::shared_ptr &layer); + void parseRender(JSVal value, std::shared_ptr &layer); + + // Parses optional properties into a render bucket. + template + bool parseRenderProperty(JSVal value, T &target, const char *name); + template + bool parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser); + + // Parses optional properties into style class properties. + template + bool parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value); + template + bool parseStyleProperty(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); + +// PropertyFilterExpression parseFilterOrExpression(JSVal value); +// Value parseValue(JSVal value); +// private: - std::map constants; + std::unordered_map constants; + + std::unordered_map> sources; + + // This stores the root layer. + std::shared_ptr root; + + // This maps ids to Layer objects, with all items being at the root level. + std::unordered_map>> layers; + + // Store a stack of layers we're parsing right now. This is to prevent reference cycles. + std::forward_list stack; }; } diff --git a/include/llmr/style/types.hpp b/include/llmr/style/types.hpp new file mode 100644 index 000000000..0d1061d5d --- /dev/null +++ b/include/llmr/style/types.hpp @@ -0,0 +1,136 @@ +#ifndef LLMR_STYLE_TYPES +#define LLMR_STYLE_TYPES + +#include + +namespace llmr { + +enum class BucketType : uint8_t { + None, + Fill, + Line, + Icon, + Text, + Raster +}; + +enum class WindingType : uint8_t { + EvenOdd, + NonZero +}; + +enum class CapType : uint8_t { + None, + Round, + Butt, + Square +}; + +enum class JoinType : uint8_t { + None, + Miter, + Bevel, + Round +}; + +enum class TextPathType : uint8_t { + Horizontal, + Curve +}; + +enum class TranslateAnchorType : uint8_t { + Map, + Viewport +}; + +enum class RotateAnchorType : uint8_t { + Map, + Viewport +}; + +enum class SourceType : uint8_t { + Vector, + Raster, + GeoJSON, + Video +}; + +inline constexpr BucketType parseBucketType(const std::string &type = "") { + return + type.compare("fill") == 0 ? BucketType::Fill : + type.compare("line") == 0 ? BucketType::Line : + type.compare("icon") == 0 ? BucketType::Icon : + type.compare("text") == 0 ? BucketType::Text : + type.compare("raster") == 0 ? BucketType::Raster : + BucketType::None; +} + +inline constexpr WindingType parseWindingType(const std::string &type = "") { + return + type.compare("even-odd") == 0 ? WindingType::EvenOdd : + WindingType::NonZero; +} + +inline constexpr CapType parseCapType(const std::string &cap = "") { + return + cap.compare("round") == 0 ? CapType::Round : + cap.compare("butt") == 0 ? CapType::Butt : + cap.compare("square") == 0 ? CapType::Square : + CapType::None; +} + +inline constexpr JoinType parseJoinType(const std::string &join = "") { + return + join.compare("miter") == 0 ? JoinType::Miter : + join.compare("bevel") == 0 ? JoinType::Bevel : + join.compare("round") == 0 ? JoinType::Round : + JoinType::None; +} + +inline constexpr TextPathType parseTextPathType(const std::string &path = "") { + return + path.compare("horizontal") == 0 ? TextPathType::Horizontal : + path.compare("curve") == 0 ? TextPathType::Curve : + TextPathType::Horizontal; +} + +inline constexpr TranslateAnchorType parseTranslateAnchorType(const std::string &anchor = "") { + return + anchor.compare("viewport") == 0 ? TranslateAnchorType::Viewport : + TranslateAnchorType::Map; +} + +inline constexpr RotateAnchorType parseRotateAnchorType(const std::string &anchor = "") { + return + anchor.compare("map") == 0 ? RotateAnchorType::Map : + RotateAnchorType::Viewport; +} + +inline constexpr float parseAlignmentType(const std::string &alignment = "") { + return + alignment.compare("right") == 0 ? 1.0f : + alignment.compare("left") == 0 ? 0.0f : + 0.5f; +}; + +inline constexpr float parseVerticalAlignmentType(const std::string &alignment = "") { + return + alignment.compare("bottom") == 0 ? 1.0f : + alignment.compare("top") == 0 ? 0.0f : + 0.5f; +}; + +inline constexpr SourceType parseSourceType(const std::string &source = "") { + return + source.compare("vector") == 0 ? SourceType::Vector : + source.compare("raster") == 0 ? SourceType::Raster : + source.compare("geojson") == 0 ? SourceType::GeoJSON : + source.compare("video") == 0 ? SourceType::Video : + SourceType::Vector; +} + + +} + +#endif + diff --git a/include/llmr/text/glyph.hpp b/include/llmr/text/glyph.hpp index a5775b87d..99c896470 100644 --- a/include/llmr/text/glyph.hpp +++ b/include/llmr/text/glyph.hpp @@ -12,7 +12,7 @@ namespace llmr { typedef std::pair GlyphRange; // Note: this only works for the BMP -GlyphRange getGlyphRange(uint32_t glyph); +GlyphRange getGlyphRange(char32_t glyph); struct GlyphMetrics { operator bool() const { diff --git a/include/llmr/text/placement.hpp b/include/llmr/text/placement.hpp index ec7462aa9..c245e260f 100644 --- a/include/llmr/text/placement.hpp +++ b/include/llmr/text/placement.hpp @@ -10,14 +10,14 @@ namespace llmr { class TextBucket; -class BucketTextDescription; +class StyleBucketText; class Placement { public: Placement(int8_t zoom); void addFeature(TextBucket &bucket, const std::vector &line, - const BucketTextDescription &info, + const StyleBucketText &info, const GlyphPositions &face, const Shaping &shaping); diff --git a/llmr.gyp b/llmr.gyp index 73aece077..2ffb3ae63 100644 --- a/llmr.gyp +++ b/llmr.gyp @@ -7,7 +7,7 @@ { 'target_name': 'shaders', 'type': 'none', - 'hard_dependency': 1, + # 'hard_dependency': 1, 'actions': [ { 'action_name': 'Build Shaders', diff --git a/src/map/map.cpp b/src/map/map.cpp index 2a3f366f1..a77e9d0c5 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -36,6 +36,10 @@ Map::Map(View& view) } Map::~Map() { + // Clear the style first before the rest of the constructor deletes members of this object. + // This is required because members of the style reference the Map object in their destructors. + style.reset(); + if (async) { stop(); } @@ -167,17 +171,6 @@ void Map::setup() { painter.setup(); - sources.emplace("outdoors", - std::unique_ptr(new Source(*this, - painter, - kVectorTileURL, - Source::Type::vector, - {{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }}, - 512, - 0, - 14, - true))); - setStyleJSON(styleJSON); } @@ -387,49 +380,44 @@ bool Map::getDebug() const { return debug; } -void Map::setAppliedClasses(std::set appliedClasses) { - style->cancelTransitions(); - - style->appliedClasses.swap(appliedClasses); - - update(); +void Map::toggleClass(const std::string &name) { + style->toggleClass(name); } -std::set Map::getAppliedClasses() const { - return style->appliedClasses; -} +//void Map::setAppliedClasses(const std::vector &appliedClasses) { +// style->cancelTransitions(); +// +// style->appliedClasses = appliedClasses; +// +// update(); +//} +// +//const std::vector &Map::getAppliedClasses() const { +// return style->appliedClasses; +//} void Map::setDefaultTransitionDuration(uint64_t duration_milliseconds) { style->setDefaultTransitionDuration(duration_milliseconds); } void Map::updateTiles() { - for (auto &pair : sources) { - const std::unique_ptr &source = pair.second; - if (source->enabled) { - source->update(); - } + for (const std::shared_ptr &source : style->getActiveSources()) { + source->update(*this); } } void Map::updateRenderState() { std::forward_list ids; - for (const auto &pair : sources) { - Source &source = *pair.second; - if (source.enabled) { - ids.splice_after(ids.before_begin(), source.getIDs()); - source.updateMatrices(state); - } + for (const std::shared_ptr &source : style->getActiveSources()) { + ids.splice_after(ids.before_begin(), source->getIDs()); + source->updateMatrices(painter.projMatrix, state); } const std::map clipIDs = computeClipIDs(ids); - for (const auto &pair : sources) { - Source &source = *pair.second; - if (source.enabled) { - source.updateClipIDs(clipIDs); - } + for (const std::shared_ptr &source : style->getActiveSources()) { + source->updateClipIDs(clipIDs); } } @@ -491,14 +479,13 @@ void Map::render() { updateRenderState(); - painter.drawClippingMasks(sources); + painter.drawClippingMasks(style->getActiveSources()); #if defined(DEBUG) // Generate debug information size_t source_id = 0; - for (const auto &pair : sources) { - const Source &source = *pair.second; - size_t count = source.getTileCount(); + for (const std::shared_ptr &source : style->getActiveSources()) { + size_t count = source->getTileCount(); debug.emplace_back(util::sprintf<100>("source %d: %d\n", source_id, count)); source_id++; } @@ -512,11 +499,8 @@ void Map::render() { // This guarantees that we have at least one function per tile called. // When only rendering layers via the stylesheet, it's possible that we don't // ever visit a tile during rendering. - for (const auto &pair : sources) { - Source &source = *pair.second; - const std::string &name = pair.first; - gl::group group(std::string("debug ") + name); - source.finishRender(); + for (const std::shared_ptr &source : style->getActiveSources()) { + source->finishRender(painter); } painter.renderMatte(); @@ -533,9 +517,14 @@ void Map::render() { glFlush(); } -void Map::renderLayers(const std::vector& layers) { +void Map::renderLayers(std::shared_ptr layers) { + if (!layers) { + // Make sure that we actually do have a layer group. + return; + } + // TODO: Correctly compute the number of layers recursively beforehand. - float strata_thickness = 1.0f / (layers.size() + 1); + float strata_thickness = 1.0f / (layers->size() + 1); // - FIRST PASS ------------------------------------------------------------ // Render everything top-to-bottom by using reverse iterators. Render opaque @@ -544,9 +533,9 @@ void Map::renderLayers(const std::vector& layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "OPAQUE {" << std::endl; } - typedef std::vector::const_reverse_iterator riterator; + typedef std::vector::reverse_iterator riterator; int i = 0; - for (riterator it = layers.rbegin(), end = layers.rend(); it != end; ++it, ++i) { + for (riterator it = layers->rbegin(), end = layers->rend(); it != end; ++it, ++i) { painter.setOpaque(); painter.setStrata(i * strata_thickness); renderLayer(*it, Opaque); @@ -561,9 +550,9 @@ void Map::renderLayers(const std::vector& layers) { if (debug::renderTree) { std::cout << std::string(indent++ * 4, ' ') << "TRANSLUCENT {" << std::endl; } - typedef std::vector::const_iterator iterator; + typedef std::vector::iterator iterator; --i; - for (iterator it = layers.begin(), end = layers.end(); it != end; ++it, --i) { + for (iterator it = layers->begin(), end = layers->end(); it != end; ++it, --i) { painter.setTranslucent(); painter.setStrata(i * strata_thickness); renderLayer(*it, Translucent); @@ -573,48 +562,22 @@ void Map::renderLayers(const std::vector& layers) { } } -template -typename Styles::const_iterator find_style(const Styles &styles, const LayerDescription &layer_desc) { - auto it = styles.find(layer_desc.name); -#if defined(DEBUG) - if (it == styles.end()) { - if (debug::renderWarnings) { - fprintf(stderr, "[WARNING] can't find class named '%s' in style\n", - layer_desc.name.c_str()); - } - } -#endif - return it; -} - -template -bool is_invisible(const Styles &styles, const LayerDescription &layer_desc) { - auto it = find_style(styles, layer_desc); - if (it == styles.end()) { - // We don't have a style, so we fall back to the default style which is - // always visible. - return false; - } - return !it->second.isVisible(); -} - -void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { - if (layer_desc.child_layer.size()) { +void Map::renderLayer(std::shared_ptr layer_desc, RenderPass pass) { + if (layer_desc->layers) { // This is a layer group. We render them during our translucent render pass. if (pass == Translucent) { - auto it = find_style(style->computed.composites, layer_desc); - const CompositeProperties &properties = (it != style->computed.composites.end()) ? it->second : defaultCompositeProperties; + const CompositeProperties &properties = layer_desc->getProperties(); if (properties.isVisible()) { - gl::group group(std::string("group: ") + layer_desc.name); + gl::group group(std::string("group: ") + layer_desc->id); if (debug::renderTree) { - std::cout << std::string(indent++ * 4, ' ') << "+ " << layer_desc.name + std::cout << std::string(indent++ * 4, ' ') << "+ " << layer_desc->id << " (Composite) {" << std::endl; } painter.pushFramebuffer(); - renderLayers(layer_desc.child_layer); + renderLayers(layer_desc->layers); GLuint texture = painter.popFramebuffer(); @@ -626,63 +589,51 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { } } } - } else if (layer_desc.bucket_name == "background") { + } else if (layer_desc->id == "background") { // This layer defines the background color. } else { - // This is a singular layer. Try to find the bucket associated with - // this layer and render it. - - auto bucket_it = style->buckets.find(layer_desc.bucket_name); - if (bucket_it != style->buckets.end()) { - const BucketDescription &bucket_desc = bucket_it->second; - - // Abort early if we can already deduce from the bucket type that - // we're not going to render anything anyway during this pass. - switch (bucket_desc.type) { - case BucketType::Fill: - if (is_invisible(style->computed.fills, layer_desc)) return; - break; - case BucketType::Line: - if (pass == Opaque) return; - if (is_invisible(style->computed.lines, layer_desc)) return; - break; - case BucketType::Icon: - if (pass == Opaque) return; - if (is_invisible(style->computed.icons, layer_desc)) return; - break; - case BucketType::Text: - if (pass == Opaque) return; - if (is_invisible(style->computed.texts, layer_desc)) return; - break; - case BucketType::Raster: - if (pass == Translucent) return; - if (is_invisible(style->computed.rasters, layer_desc)) return; - break; - default: - break; - } - - // Find the source and render all tiles in it. - auto source_it = sources.find(bucket_desc.source_name); - if (source_it != sources.end()) { - if (debug::renderTree) { - std::cout << std::string(indent * 4, ' ') << "- " << layer_desc.name << " (" - << bucket_desc.type << ")" << std::endl; - } - - const std::unique_ptr &source = source_it->second; - source->render(layer_desc, bucket_desc); - } else { - if (debug::renderWarnings) { - fprintf(stderr, "[WARNING] can't find source '%s' required for bucket '%s'\n", - bucket_desc.source_name.c_str(), layer_desc.bucket_name.c_str()); - } - } - } else { - if (debug::renderWarnings) { - fprintf(stderr, "[WARNING] can't find bucket '%s' required for layer '%s'\n", - layer_desc.bucket_name.c_str(), layer_desc.name.c_str()); - } + // This is a singular layer. + if (!layer_desc->bucket) { + fprintf(stderr, "[WARNING] layer '%s' is missing bucket\n", layer_desc->id.c_str()); + return; } + + if (!layer_desc->bucket->source) { + fprintf(stderr, "[WARNING] can't find source for layer '%s'\n", layer_desc->id.c_str()); + return; + } + + // Abort early if we can already deduce from the bucket type that + // we're not going to render anything anyway during this pass. + switch (layer_desc->bucket->type) { + case BucketType::Fill: + if (!layer_desc->getProperties().isVisible()) return; + break; + case BucketType::Line: + if (pass == Opaque) return; + if (!layer_desc->getProperties().isVisible()) return; + break; + case BucketType::Icon: + if (pass == Opaque) return; + if (!layer_desc->getProperties().isVisible()) return; + break; + case BucketType::Text: + if (pass == Opaque) return; + if (!layer_desc->getProperties().isVisible()) return; + break; + case BucketType::Raster: + if (pass == Translucent) return; + if (!layer_desc->getProperties().isVisible()) return; + break; + default: + break; + } + + if (debug::renderTree) { + std::cout << std::string(indent * 4, ' ') << "- " << layer_desc->id << " (" + << layer_desc->bucket->type << ")" << std::endl; + } + + layer_desc->bucket->source->render(painter, layer_desc); } } diff --git a/src/map/raster_tile_data.cpp b/src/map/raster_tile_data.cpp index 5c522ef2a..7892458f9 100644 --- a/src/map/raster_tile_data.cpp +++ b/src/map/raster_tile_data.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include using namespace llmr; @@ -25,10 +25,10 @@ void RasterTileData::parse() { } } -void RasterTileData::render(Painter &painter, const LayerDescription& layer_desc) { - bucket.render(painter, layer_desc.name, id); +void RasterTileData::render(Painter &painter, std::shared_ptr layer_desc) { + bucket.render(painter, layer_desc, id); } -bool RasterTileData::hasData(const LayerDescription& layer_desc) const { +bool RasterTileData::hasData(std::shared_ptr layer_desc) const { return bucket.hasData(); } diff --git a/src/map/source.cpp b/src/map/source.cpp index 2491e083e..b03d83ca4 100644 --- a/src/map/source.cpp +++ b/src/map/source.cpp @@ -14,23 +14,33 @@ #include #include -using namespace llmr; +namespace llmr { -Source::Source(Map &map, Painter &painter, - const char *url, Source::Type type, std::vector zooms, uint32_t tile_size, - uint32_t min_zoom, uint32_t max_zoom, bool enabled) - : enabled(enabled), - map(map), - painter(painter), - type(type), - zooms(zooms), - url(url), +Source::Source(SourceType type, const std::string &url, const std::string &glyphs, + uint32_t tile_size, uint32_t min_zoom, uint32_t max_zoom) + : type(type), + url(normalizeSourceURL(url)), + glyphs(glyphs), tile_size(tile_size), min_zoom(min_zoom), max_zoom(max_zoom) {} -bool Source::update() { - return updateTiles(); +std::string Source::normalizeSourceURL(const std::string &url) { + const std::string t = "mapbox://"; + if (url.compare(0, t.length(), t) == 0) { + return std::string("http://api.tiles.mapbox.com/v3/") + url.substr(t.length()) + "/%d/%d/%d.vector.pbf"; + } else { + return url; + } +} + + +bool Source::update(Map &map) { + if (map.getTime() > updated) { + return updateTiles(map); + } else { + return false; + } } void Source::updateClipIDs(const std::map &mapping) { @@ -45,11 +55,11 @@ void Source::updateClipIDs(const std::map &mapping) { }); } -void Source::updateMatrices(const TransformState &transform) { +void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) { for (std::pair> &pair : tiles) { Tile &tile = *pair.second; transform.matrixFor(tile.matrix, tile.id); - matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix); + matrix::multiply(tile.matrix, projMatrix, tile.matrix); } } @@ -57,7 +67,7 @@ size_t Source::getTileCount() const { return tiles.size(); } -void Source::drawClippingMasks() { +void Source::drawClippingMasks(Painter &painter) { for (std::pair> &pair : tiles) { Tile &tile = *pair.second; gl::group group(util::sprintf<32>("mask %d/%d/%d", tile.id.z, tile.id.y, tile.id.z)); @@ -65,10 +75,8 @@ void Source::drawClippingMasks() { } } -void Source::render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc) { - if (!enabled) return; - - gl::group group(std::string("layer: ") + layer_desc.name); +void Source::render(Painter &painter, std::shared_ptr layer_desc) { + gl::group group(std::string("layer: ") + layer_desc->id); for (const std::pair> &pair : tiles) { Tile &tile = *pair.second; if (tile.data && tile.data->state == TileData::State::parsed) { @@ -77,9 +85,7 @@ void Source::render(const LayerDescription& layer_desc, const BucketDescription } } -void Source::finishRender() { - if (!enabled) return; - +void Source::finishRender(Painter &painter) { for (std::pair> &pair : tiles) { Tile &tile = *pair.second; painter.renderTileDebug(tile); @@ -109,7 +115,7 @@ TileData::State Source::hasTile(const Tile::ID& id) { return TileData::State::invalid; } -TileData::State Source::addTile(const Tile::ID& id) { +TileData::State Source::addTile(Map &map, const Tile::ID& id) { const TileData::State state = hasTile(id); if (state != TileData::State::invalid) { @@ -139,12 +145,14 @@ TileData::State Source::addTile(const Tile::ID& id) { std::string formed_url; - if (type == Source::Type::vector) { + if (type == SourceType::Vector) { formed_url = util::sprintf<256>(url, normalized_id.z, normalized_id.x, normalized_id.y); new_tile.data = std::make_shared(normalized_id, map, formed_url); - } else { + } else if (type == SourceType::Raster) { formed_url = util::sprintf<256>(url, normalized_id.z, normalized_id.x, normalized_id.y, (map.getState().getPixelRatio() > 1.0 ? "@2x" : "")); new_tile.data = std::make_shared(normalized_id, map, formed_url); + } else { + throw std::runtime_error("source type not implemented"); } new_tile.data->request(); @@ -205,27 +213,27 @@ bool Source::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std:: return false; } -bool Source::updateTiles() { +bool Source::updateTiles(Map &map) { bool changed = false; // Figure out what tiles we need to load - int32_t zoom = map.getState().getIntegerZoom(); - if (zoom > max_zoom) zoom = max_zoom; - if (zoom < min_zoom) zoom = min_zoom; + int32_t clamped_zoom = map.getState().getIntegerZoom(); + if (clamped_zoom > max_zoom) clamped_zoom = max_zoom; + if (clamped_zoom < min_zoom) clamped_zoom = min_zoom; - int32_t max_covering_zoom = zoom + 1; + int32_t max_covering_zoom = clamped_zoom + 1; if (max_covering_zoom > max_zoom) max_covering_zoom = max_zoom; - int32_t min_covering_zoom = zoom - 10; + int32_t min_covering_zoom = clamped_zoom - 10; if (min_covering_zoom < min_zoom) min_covering_zoom = min_zoom; // Map four viewport corners to pixel coordinates - box box = map.getState().cornersToBox(zoom); + box box = map.getState().cornersToBox(clamped_zoom); // Performs a scanline algorithm search that covers the rectangle of the box // and sorts them by proximity to the center. - std::forward_list required = covering_tiles(zoom, box); + std::forward_list required = covering_tiles(map.getState(), clamped_zoom, box); // Retain is a list of tiles that we shouldn't delete, even if they are not // the most ideal tile for the current viewport. This may include tiles like @@ -234,7 +242,7 @@ bool Source::updateTiles() { // Add existing child/parent tiles if the actual tile is not yet loaded for (const Tile::ID& id : required) { - const TileData::State state = addTile(id); + const TileData::State state = addTile(map, id); if (state != TileData::State::parsed) { // if (use_raster && (transform.rotating || transform.scaling || transform.panning)) @@ -289,6 +297,8 @@ bool Source::updateTiles() { } }); + updated = map.getTime(); + return changed; } @@ -354,30 +364,30 @@ void _scanTriangle(const llmr::vec2 a, const llmr::vec2 b, const if (bc.dy) _scanSpans(ca, bc, ymin, ymax, scanLine); } -double Source::getZoom() const { +double Source::getZoom(const TransformState &state) const { double offset = log(util::tileSize / tile_size) / log(2); - offset += (map.getState().getPixelRatio() > 1.0 ? 1 :0); - return map.getState().getZoom() + offset; + offset += (state.getPixelRatio() > 1.0 ? 1 :0); + return state.getZoom() + offset; } -std::forward_list Source::covering_tiles(int32_t zoom, const box& points) { - int32_t dim = std::pow(2, zoom); +std::forward_list Source::covering_tiles(const TransformState &state, int32_t clamped_zoom, const box& points) { + int32_t dim = std::pow(2, clamped_zoom); std::forward_list tiles; - bool is_raster = (type == Type::raster); - double search_zoom = getZoom(); + bool is_raster = (type == SourceType::Raster); + double search_zoom = getZoom(state); - auto scanLine = [&tiles, zoom, is_raster, search_zoom](int32_t x0, int32_t x1, int32_t y, int32_t ymax) { + auto scanLine = [&tiles, clamped_zoom, is_raster, search_zoom](int32_t x0, int32_t x1, int32_t y, int32_t ymax) { int32_t x; if (y >= 0 && y <= ymax) { for (x = x0; x < x1; x++) { if (is_raster) { - Tile::ID id = Tile::ID(zoom, x, y); + Tile::ID id = Tile::ID(clamped_zoom, x, y); auto ids = id.children(search_zoom); for (const Tile::ID& child_id : ids) { tiles.emplace_front(child_id.z, child_id.x, child_id.y); } } else { - tiles.emplace_front(zoom, x, y); + tiles.emplace_front(clamped_zoom, x, y); } } } @@ -401,3 +411,5 @@ std::forward_list Source::covering_tiles(int32_t zoom, const box return tiles; } + +} diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 1c1268c80..b31d1383e 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -62,72 +62,74 @@ void TileParser::addGlyph(uint64_t tileid, const std::string stackname, } } -void TileParser::parseStyleLayers(const std::vector &layers) { - for (const LayerDescription &layer_desc : layers) { +void TileParser::parseStyleLayers(std::shared_ptr layers) { + if (!layers) { + return; + } + + for (const std::shared_ptr &layer_desc : *layers) { // Cancel early when parsing. if (obsolete()) { return; } - if (layer_desc.bucket_name == "background") { + if (layer_desc->id == "background") { // background is a special, fake bucket continue; - } - - if (layer_desc.child_layer.size()) { + } else if (layer_desc->layers) { // This is a layer group. - // TODO: create framebuffer - parseStyleLayers(layer_desc.child_layer); - // TODO: render framebuffer on previous framebuffer - } else { + parseStyleLayers(layer_desc->layers); + } else if (layer_desc->bucket) { // This is a singular layer. Check if this bucket already exists. If not, // parse this bucket. - auto bucket_it = tile.buckets.find(layer_desc.bucket_name); + 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()) { - // Only create the new bucket if we have an actual specification - // for it. - std::unique_ptr bucket = createBucket(bucket_it->second); - if (bucket) { - // Bucket creation might fail because the data tile may not - // contain any data that falls into this bucket. - tile.buckets[layer_desc.bucket_name] = std::move(bucket); - } - } else { - // There is no proper specification for this bucket, even though - // it is referenced in the stylesheet. - if (debug::tileParseWarnings) { - fprintf(stderr, "Stylesheet specifies bucket %s, but it is not defined\n", - layer_desc.bucket_name.c_str()); - } + // We need to create this bucket since it doesn't exist yet. + std::unique_ptr bucket = createBucket(layer_desc->bucket); + if (bucket) { + // Bucket creation might fail because the data tile may not + // contain any data that falls into this bucket. + tile.buckets[layer_desc->bucket->name] = std::move(bucket); } } + } else { + fprintf(stderr, "[WARNING] layer does not have child layers or buckets\n"); } } } -std::unique_ptr TileParser::createBucket(const BucketDescription &bucket_desc) { - auto layer_it = vector_data.layers.find(bucket_desc.source_layer); +std::unique_ptr TileParser::createBucket(std::shared_ptr bucket_desc) { + if (!bucket_desc) { + fprintf(stderr, "missing bucket desc\n"); + return nullptr; + } + + auto layer_it = vector_data.layers.find(bucket_desc->source_layer); if (layer_it != vector_data.layers.end()) { const VectorTileLayer &layer = layer_it->second; - if (bucket_desc.type == BucketType::Fill) { - return createFillBucket(layer, bucket_desc); - } else if (bucket_desc.type == BucketType::Line) { - return createLineBucket(layer, bucket_desc); - } else if (bucket_desc.type == BucketType::Icon) { - return createIconBucket(layer, bucket_desc); - } else if (bucket_desc.type == BucketType::Text) { - return createTextBucket(layer, bucket_desc); + if (bucket_desc->render.is()) { + fprintf(stderr, "create fill bucket\n"); + return createFillBucket(layer, bucket_desc->filter, bucket_desc->render.get()); + } else if (bucket_desc->render.is()) { + fprintf(stderr, "create line bucket\n"); + return createLineBucket(layer, bucket_desc->filter, bucket_desc->render.get()); + } else if (bucket_desc->render.is()) { + fprintf(stderr, "create icon bucket\n"); + return createIconBucket(layer, bucket_desc->filter, bucket_desc->render.get()); + } else if (bucket_desc->render.is()) { + fprintf(stderr, "create text bucket\n"); + return createTextBucket(layer, bucket_desc->filter, bucket_desc->render.get()); + } else if (bucket_desc->render.is()) { + fprintf(stderr, "create raster bucket\n"); + return nullptr; } else { - throw std::runtime_error("unknown bucket type"); + fprintf(stderr, "[WARNING] unknown bucket render type for layer '%s'\n", bucket_desc->source_layer.c_str()); } } else { // The layer specified in the bucket does not exist. Do nothing. if (debug::tileParseWarnings) { - fprintf(stderr, "[WARNING] layer '%s' does not exist in tile %d/%d/%d of source '%s'\n", - bucket_desc.source_layer.c_str(), tile.id.z, tile.id.x, tile.id.y, - bucket_desc.source_name.c_str()); + fprintf(stderr, "[WARNING] layer '%s' does not exist in tile %d/%d/%d\n", + bucket_desc->source_layer.c_str(), tile.id.z, tile.id.x, tile.id.y); } } @@ -135,9 +137,8 @@ std::unique_ptr TileParser::createBucket(const BucketDescription &bucket } template -void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer, - const BucketDescription &bucket_desc) { - FilteredVectorTileLayer filtered_layer(layer, bucket_desc); +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter) { + FilteredVectorTileLayer filtered_layer(layer, filter); for (pbf feature : filtered_layer) { if (obsolete()) return; @@ -154,64 +155,38 @@ void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer, } template -void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer, - const BucketDescription &bucket_desc, Args &&... args) { - FilteredVectorTileLayer filtered_layer(layer, bucket_desc); +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args) { + FilteredVectorTileLayer filtered_layer(layer, filter); for (const pbf &feature_pbf : filtered_layer) { - if (obsolete()) + if (obsolete()) { return; + } bucket->addFeature({feature_pbf, layer}, std::forward(args)...); } } -std::unique_ptr TileParser::createFillBucket(const VectorTileLayer &layer, - const BucketDescription &bucket_desc) { - if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { - return nullptr; - } - std::unique_ptr bucket = std::make_unique( - tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, - bucket_desc.render.get()); - addBucketFeatures(bucket, layer, bucket_desc); +std::unique_ptr TileParser::createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill) { + std::unique_ptr bucket = std::make_unique(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, fill); + addBucketFeatures(bucket, layer, filter); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr TileParser::createLineBucket(const VectorTileLayer &layer, - const BucketDescription &bucket_desc) { - if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { - return nullptr; - } - - std::unique_ptr bucket = std::make_unique( - tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, - bucket_desc.render.get()); - addBucketFeatures(bucket, layer, bucket_desc); +std::unique_ptr TileParser::createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line) { + std::unique_ptr bucket = std::make_unique(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, line); + addBucketFeatures(bucket, layer, filter); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr TileParser::createIconBucket(const VectorTileLayer &layer, - const BucketDescription &bucket_desc) { - if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { - return nullptr; - } - - std::unique_ptr bucket = std::make_unique( - tile.iconVertexBuffer, bucket_desc.render.get()); - addBucketFeatures(bucket, layer, bucket_desc, *spriteAtlas); +std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon) { + std::unique_ptr bucket = std::make_unique(tile.iconVertexBuffer, icon); + addBucketFeatures(bucket, layer, filter, *spriteAtlas); return obsolete() ? nullptr : std::move(bucket); } -typedef std::pair GlyphRange; +std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text) { -std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &layer, - const BucketDescription &bucket_desc) { - - if (!bucket_desc.render.valid() || !bucket_desc.render.is()) { - return nullptr; - } - - const BucketTextDescription &properties = bucket_desc.render.get(); + const StyleBucketText &properties = text; std::unique_ptr bucket = std::make_unique( tile.textVertexBuffer, tile.triangleElementsBuffer, properties, placement); @@ -224,7 +199,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye { std::set ranges; - FilteredVectorTileLayer filtered_layer(layer, bucket_desc); + FilteredVectorTileLayer filtered_layer(layer, filter); for (const pbf &feature_pbf : filtered_layer) { if (obsolete()) return nullptr; @@ -234,7 +209,7 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye util::replaceTokens(properties.field, feature.properties)); // Loop through all characters of this text and collect unique codepoints. - for (uint32_t chr : string) { + for (char32_t chr : string) { ranges.insert(getGlyphRange(chr)); } @@ -265,3 +240,9 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer &laye return std::move(bucket); } + + + + +//typedef std::pair GlyphRange; +// diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index 97adec277..24f03e1a9 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -102,9 +102,9 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { } } -FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const BucketDescription& bucket_desc) +FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression) : layer(layer), - bucket_desc(bucket_desc) { + filterExpression(filterExpression) { } FilteredVectorTileLayer::iterator FilteredVectorTileLayer::begin() const { @@ -193,7 +193,7 @@ bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpressi void FilteredVectorTileLayer::iterator::operator++() { valid = false; - const PropertyFilterExpression &expression = parent.bucket_desc.filter; + const PropertyFilterExpression &expression = parent.filterExpression; while (data.next(2)) { // feature feature = data.message(); @@ -203,7 +203,7 @@ void FilteredVectorTileLayer::iterator::operator++() { bool matched = false; // Treat the absence of any expression filters as a match. - if (expression.is()) { + if (!expression.valid() || expression.is()) { matched = true; } @@ -228,10 +228,11 @@ void FilteredVectorTileLayer::iterator::operator++() { default: type = BucketType::None; break; } - if (type != parent.bucket_desc.feature_type) { - matched = false; - break; // feature_pbf loop early - } + // TODO: Parse feature type +// if (type != parent.bucket_desc.feature_type) { +// matched = false; +// break; // feature_pbf loop early +// } } else { feature_pbf.skip(); } diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp index 400adf89b..de99bb5d3 100644 --- a/src/map/vector_tile_data.cpp +++ b/src/map/vector_tile_data.cpp @@ -9,7 +9,10 @@ VectorTileData::VectorTileData(Tile::ID id, Map &map, const std::string url) } VectorTileData::~VectorTileData() { - map.getGlyphAtlas()->removeGlyphs(id.to_uint64()); + std::shared_ptr glyphAtlas = map.getGlyphAtlas(); + if (glyphAtlas) { + glyphAtlas->removeGlyphs(id.to_uint64()); + } } void VectorTileData::beforeParse() { @@ -43,22 +46,23 @@ void VectorTileData::afterParse() { parser.reset(); } -void VectorTileData::render(Painter &painter, const LayerDescription& layer_desc) { - auto databucket_it = buckets.find(layer_desc.bucket_name); - if (databucket_it != buckets.end()) { - assert(databucket_it->second); - databucket_it->second->render(painter, layer_desc.name, id); +void VectorTileData::render(Painter &painter, std::shared_ptr layer_desc) { + if (state == State::parsed && layer_desc->bucket) { + auto databucket_it = buckets.find(layer_desc->bucket->name); + if (databucket_it != buckets.end()) { + assert(databucket_it->second); + databucket_it->second->render(painter, layer_desc, id); + } } } -bool VectorTileData::hasData(const LayerDescription& layer_desc) const { - if (state != State::parsed) return false; - - auto databucket_it = buckets.find(layer_desc.bucket_name); - if (databucket_it != buckets.end()) { - assert(databucket_it->second); - return databucket_it->second->hasData(); - } else { - return false; +bool VectorTileData::hasData(std::shared_ptr layer_desc) const { + if (state == State::parsed && layer_desc->bucket) { + auto databucket_it = buckets.find(layer_desc->bucket->name); + if (databucket_it != buckets.end()) { + assert(databucket_it->second); + return databucket_it->second->hasData(); + } } + return false; } diff --git a/src/renderer/debug_bucket.cpp b/src/renderer/debug_bucket.cpp index 284d8a371..12e6cf5b5 100644 --- a/src/renderer/debug_bucket.cpp +++ b/src/renderer/debug_bucket.cpp @@ -14,7 +14,7 @@ DebugBucket::DebugBucket(DebugFontBuffer& fontBuffer) : fontBuffer(fontBuffer) { } -void DebugBucket::render(Painter& painter, const std::string& /*layer_name*/, const Tile::ID& /*id*/) { +void DebugBucket::render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& /*id*/) { painter.renderDebugText(*this); } diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index d7ba048a5..c6c69ed56 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -33,7 +33,7 @@ void FillBucket::free(void *, void *ptr) { FillBucket::FillBucket(FillVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, LineElementsBuffer &lineElementsBuffer, - const BucketFillDescription &properties) + const StyleBucketFill &properties) : properties(properties), allocator(new TESSalloc{&alloc, &realloc, &free, nullptr, // userData 64, // meshEdgeBucketSize @@ -204,8 +204,8 @@ void FillBucket::tessellate() { lineGroup.vertex_length += total_vertex_count; } -void FillBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { - painter.renderFill(*this, layer_name, id); +void FillBucket::render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id) { + painter.renderFill(*this, layer_desc, id); } bool FillBucket::hasData() const { diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp index b6c324d2a..1a1c10450 100644 --- a/src/renderer/icon_bucket.cpp +++ b/src/renderer/icon_bucket.cpp @@ -19,7 +19,7 @@ struct geometry_too_long_exception : std::exception {}; using namespace llmr; IconBucket::IconBucket(IconVertexBuffer& vertexBuffer, - const BucketIconDescription& properties) + const StyleBucketIcon& properties) : properties(properties), vertexBuffer(vertexBuffer), vertex_start(vertexBuffer.index()) { @@ -57,8 +57,8 @@ void IconBucket::addFeature(const VectorTileFeature &feature, SpriteAtlas &sprit vertex_end = vertexBuffer.index(); } -void IconBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { - painter.renderIcon(*this, layer_name, id); +void IconBucket::render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id) { + painter.renderIcon(*this, layer_desc, id); } bool IconBucket::hasData() const { diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp index d6d3dcf77..143a67c1c 100644 --- a/src/renderer/line_bucket.cpp +++ b/src/renderer/line_bucket.cpp @@ -20,7 +20,7 @@ using namespace llmr; LineBucket::LineBucket(LineVertexBuffer& vertexBuffer, TriangleElementsBuffer& triangleElementsBuffer, PointElementsBuffer& pointElementsBuffer, - const BucketLineDescription& properties) + const StyleBucketLine& properties) : properties(properties), vertexBuffer(vertexBuffer), triangleElementsBuffer(triangleElementsBuffer), @@ -341,8 +341,8 @@ void LineBucket::addGeometry(const std::vector& vertices) { } } -void LineBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { - painter.renderLine(*this, layer_name, id); +void LineBucket::render(Painter& painter, std::shared_ptr layer_desc, const Tile::ID& id) { + painter.renderLine(*this, layer_desc, id); } bool LineBucket::hasData() const { diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 3b7ef783f..9d11fe108 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -172,10 +172,10 @@ void Painter::prepareTile(const Tile& tile) { glStencilFunc(GL_EQUAL, id, mask); } -void Painter::renderTileLayer(const Tile& tile, const LayerDescription &layer_desc) { +void Painter::renderTileLayer(const Tile& tile, std::shared_ptr layer_desc) { assert(tile.data); if (tile.data->hasData(layer_desc)) { - gl::group group(util::sprintf<32>("render %d/%d/%d", tile.id.z, tile.id.y, tile.id.z)); + gl::group group(util::sprintf<32>("render %d/%d/%d\n", tile.id.z, tile.id.y, tile.id.z)); prepareTile(tile); tile.data->render(*this, layer_desc); frameHistory.record(map.getAnimationTime(), map.getState().getNormalizedZoom()); @@ -183,14 +183,14 @@ void Painter::renderTileLayer(const Tile& tile, const LayerDescription &layer_de } -const mat4 &Painter::translatedMatrix(const std::array &translation, const Tile::ID &id, TranslateAnchor anchor) { +const mat4 &Painter::translatedMatrix(const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor) { if (translation[0] == 0 && translation[1] == 0) { return matrix; } else { // TODO: Get rid of the 8 (scaling from 4096 to tile size) const double factor = ((double)(1 << id.z)) / map.getState().getScale() * (4096.0 / util::tileSize); - if (anchor == TranslateAnchor::Viewport) { + if (anchor == TranslateAnchorType::Viewport) { const double sin_a = std::sin(-map.getState().getAngle()); const double cos_a = std::cos(-map.getState().getAngle()); matrix::translate(vtxMatrix, matrix, diff --git a/src/renderer/painter_clipping.cpp b/src/renderer/painter_clipping.cpp index 3a4a24b11..18f546664 100644 --- a/src/renderer/painter_clipping.cpp +++ b/src/renderer/painter_clipping.cpp @@ -6,7 +6,7 @@ using namespace llmr; -void Painter::drawClippingMasks(const Sources &sources) { +void Painter::drawClippingMasks(const std::set> &sources) { gl::group group("clipping masks"); useProgram(plainShader->program); @@ -15,22 +15,15 @@ void Painter::drawClippingMasks(const Sources &sources) { glDepthRange(1.0f, 1.0f); glStencilMask(0xFF); - const BackgroundProperties &properties = map.getStyle()->computed.background; - Color background = properties.color; - const float opacity = properties.opacity; - background[0] *= opacity; - background[1] *= opacity; - background[2] *= opacity; - background[3] *= opacity; - plainShader->setColor(background); +// std::shared_ptr background_layer = map.getStyle()->background; +// const BackgroundProperties &properties = background_layer ? background_layer->getProperties() : defaultStyleProperties(); + const BackgroundProperties &properties = defaultStyleProperties(); + plainShader->setColor(properties.color); coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); - for (const auto &pair : sources) { - Source &source = *pair.second; - if (source.enabled) { - source.drawClippingMasks(); - } + for (const std::shared_ptr &source : sources) { + source->drawClippingMasks(*this); } glEnable(GL_DEPTH_TEST); diff --git a/src/renderer/painter_debug.cpp b/src/renderer/painter_debug.cpp index 23bf32fda..eb26b0b26 100644 --- a/src/renderer/painter_debug.cpp +++ b/src/renderer/painter_debug.cpp @@ -63,6 +63,10 @@ void Painter::renderDebugFrame() { } void Painter::renderDebugText(const std::vector &strings) { + if (strings.empty()) { + return; + } + gl::group group("debug text"); glDisable(GL_DEPTH_TEST); @@ -78,20 +82,21 @@ void Painter::renderDebugText(const std::vector &strings) { line += 20; } - // draw debug info - VertexArrayObject debugFontArray; - debugFontArray.bind(*plainShader, debugFontBuffer, BUFFER_OFFSET(0)); - plainShader->setColor(1.0f, 1.0f, 1.0f, 1.0f); - lineWidth(4.0f * map.getState().getPixelRatio()); - glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index()); -#ifndef GL_ES_VERSION_2_0 - glPointSize(2); - glDrawArrays(GL_POINTS, 0, (GLsizei)debugFontBuffer.index()); -#endif - plainShader->setColor(0.0f, 0.0f, 0.0f, 1.0f); - lineWidth(2.0f * map.getState().getPixelRatio()); - glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index()); - + if (!debugFontBuffer.empty()) { + // draw debug info + VertexArrayObject debugFontArray; + debugFontArray.bind(*plainShader, debugFontBuffer, BUFFER_OFFSET(0)); + plainShader->setColor(1.0f, 1.0f, 1.0f, 1.0f); + lineWidth(4.0f * map.getState().getPixelRatio()); + glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index()); + #ifndef GL_ES_VERSION_2_0 + glPointSize(2); + glDrawArrays(GL_POINTS, 0, (GLsizei)debugFontBuffer.index()); + #endif + plainShader->setColor(0.0f, 0.0f, 0.0f, 1.0f); + lineWidth(2.0f * map.getState().getPixelRatio()); + glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index()); + } glEnable(GL_DEPTH_TEST); } diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index fd5b1a334..4628db7f7 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -140,65 +140,60 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c } } -void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id) { +void Painter::renderFill(FillBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id) { // Abort early. if (!bucket.hasData()) return; - const std::unordered_map &fill_properties = map.getStyle()->computed.fills; - const std::unordered_map::const_iterator fill_properties_it = fill_properties.find(layer_name); - - const FillProperties &properties = fill_properties_it != fill_properties.end() - ? fill_properties_it->second - : defaultFillProperties; + const FillProperties &properties = layer_desc->getProperties(); if (!properties.enabled) return; - if (properties.prerender && properties.getPrerender(id.z)) { - if (pass == Translucent) { - // Buffer value around the 0..4096 extent that will be drawn into the 256x256 pixel - // texture. We later scale the texture so that the actual bounds will align with this - // tile's bounds. The reason we do this is so that the - if (!bucket.prerendered) { - const PrerenderProperties prerender = properties.getPrerenderProperties(id.z); - bucket.prerendered = std::make_unique(prerender); - bucket.prerendered->bindFramebuffer(); - - preparePrerender(*bucket.prerendered); - - const FillProperties modifiedProperties = [&]{ - FillProperties modifiedProperties = properties; - modifiedProperties.opacity = 1; - return modifiedProperties; - }(); - - // When drawing the fill, we want to draw a buffer around too, so we - // essentially downscale everyting, and then upscale it later when rendering. - const int buffer = prerender.buffer * 4096.0f; - const mat4 vtxMatrix = [&]{ - mat4 vtxMatrix; - matrix::ortho(vtxMatrix, -buffer, 4096 + buffer, -4096 - buffer, buffer, 0, 1); - matrix::translate(vtxMatrix, vtxMatrix, 0, -4096, 0); - return vtxMatrix; - }(); - - setOpaque(); - renderFill(bucket, modifiedProperties, id, vtxMatrix); - - setTranslucent(); - renderFill(bucket, modifiedProperties, id, vtxMatrix); - - if (prerender.blur > 0) { - bucket.prerendered->blur(*this, prerender.blur); - } - - // RESET STATE - bucket.prerendered->unbindFramebuffer(); - finishPrerender(*bucket.prerendered); - } - - renderPrerenderedTexture(*bucket.prerendered, properties); - } - } else { +// if (properties.prerender && properties.getPrerender(id.z)) { +// if (pass == Translucent) { +// // Buffer value around the 0..4096 extent that will be drawn into the 256x256 pixel +// // texture. We later scale the texture so that the actual bounds will align with this +// // tile's bounds. The reason we do this is so that the +// if (!bucket.prerendered) { +// const PrerenderProperties prerender = properties.getPrerenderProperties(id.z); +// bucket.prerendered = std::make_unique(prerender); +// bucket.prerendered->bindFramebuffer(); +// +// preparePrerender(*bucket.prerendered); +// +// const FillProperties modifiedProperties = [&]{ +// FillProperties modifiedProperties = properties; +// modifiedProperties.opacity = 1; +// return modifiedProperties; +// }(); +// +// // When drawing the fill, we want to draw a buffer around too, so we +// // essentially downscale everyting, and then upscale it later when rendering. +// const int buffer = prerender.buffer * 4096.0f; +// const mat4 vtxMatrix = [&]{ +// mat4 vtxMatrix; +// matrix::ortho(vtxMatrix, -buffer, 4096 + buffer, -4096 - buffer, buffer, 0, 1); +// matrix::translate(vtxMatrix, vtxMatrix, 0, -4096, 0); +// return vtxMatrix; +// }(); +// +// setOpaque(); +// renderFill(bucket, modifiedProperties, id, vtxMatrix); +// +// setTranslucent(); +// renderFill(bucket, modifiedProperties, id, vtxMatrix); +// +// if (prerender.blur > 0) { +// bucket.prerendered->blur(*this, prerender.blur); +// } +// +// // RESET STATE +// bucket.prerendered->unbindFramebuffer(); +// finishPrerender(*bucket.prerendered); +// } +// +// renderPrerenderedTexture(*bucket.prerendered, properties); +// } +// } else { const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); renderFill(bucket, properties, id, vtxMatrix); - } +// } } diff --git a/src/renderer/painter_framebuffers.cpp b/src/renderer/painter_framebuffers.cpp index 19541b232..a9dacf207 100644 --- a/src/renderer/painter_framebuffers.cpp +++ b/src/renderer/painter_framebuffers.cpp @@ -116,7 +116,7 @@ void Painter::pushFramebuffer() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glColorMask(false, false, false, false); - drawClippingMasks(map.getSources()); + drawClippingMasks(map.getStyle()->getActiveSources()); glColorMask(true, true, true, true); fbo_depth_stencil_valid = true; diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 8c07349b2..3ea104887 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -6,32 +6,23 @@ using namespace llmr; -void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, const Tile::ID& id) { +void Painter::renderIcon(IconBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id) { // Abort early. if (!bucket.hasData()) return; if (pass == Opaque) return; - const std::unordered_map &icon_properties = map.getStyle()->computed.icons; - const std::unordered_map::const_iterator icon_properties_it = icon_properties.find(layer_name); - - const IconProperties &properties = icon_properties_it != icon_properties.end() - ? icon_properties_it->second - : defaultIconProperties; + const IconProperties &properties = layer_desc->getProperties(); if (!properties.enabled) return; - Color color = properties.color; - color[0] *= properties.opacity; - color[1] *= properties.opacity; - color[2] *= properties.opacity; - color[3] *= properties.opacity; - - const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); +// TODO: when translating icon, are we doing this in the bucket already? +// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); SpriteAtlas &spriteAtlas = *map.getSpriteAtlas(); useProgram(iconShader->program); iconShader->setMatrix(vtxMatrix); - iconShader->setColor(color); +// TODO: update +// iconShader->setColor(color); iconShader->setImage(0); iconShader->setRatio(map.getState().getPixelRatio()); iconShader->setDimension({{ diff --git a/src/renderer/painter_line.cpp b/src/renderer/painter_line.cpp index 1de104421..6ec7a1e7e 100644 --- a/src/renderer/painter_line.cpp +++ b/src/renderer/painter_line.cpp @@ -4,17 +4,12 @@ using namespace llmr; -void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id) { +void Painter::renderLine(LineBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id) { // Abort early. if (pass == Opaque) return; if (!bucket.hasData()) return; - const std::unordered_map &line_properties = map.getStyle()->computed.lines; - const std::unordered_map::const_iterator line_properties_it = line_properties.find(layer_name); - - const LineProperties &properties = line_properties_it != line_properties.end() - ? line_properties_it->second - : defaultLineProperties; + const LineProperties &properties = layer_desc->getProperties(); if (!properties.enabled) return; float width = properties.width; diff --git a/src/renderer/painter_prerender.cpp b/src/renderer/painter_prerender.cpp index 6d748c7c4..3985309df 100644 --- a/src/renderer/painter_prerender.cpp +++ b/src/renderer/painter_prerender.cpp @@ -23,21 +23,21 @@ void Painter::finishPrerender(PrerenderedTexture &texture) { glViewport(0, 0, gl_viewport[0], gl_viewport[1]); } -void Painter::renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties) { - const int buffer = texture.properties.buffer * 4096.0f; - - // draw the texture on a quad - useProgram(rasterShader->program); - rasterShader->setMatrix(matrix); - rasterShader->setOpacity(1); - - glDepthRange(strata, 1.0f); - - glActiveTexture(GL_TEXTURE0); - rasterShader->setImage(0); - rasterShader->setBuffer(buffer); - rasterShader->setOpacity(properties.opacity); - texture.bindTexture(); - coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0)); - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); -} +//void Painter::renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties) { +// const int buffer = texture.properties.buffer * 4096.0f; +// +// // draw the texture on a quad +// useProgram(rasterShader->program); +// rasterShader->setMatrix(matrix); +// rasterShader->setOpacity(1); +// +// glDepthRange(strata, 1.0f); +// +// glActiveTexture(GL_TEXTURE0); +// rasterShader->setImage(0); +// rasterShader->setBuffer(buffer); +// rasterShader->setOpacity(properties.opacity); +// texture.bindTexture(); +// coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0)); +// glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); +//} diff --git a/src/renderer/painter_raster.cpp b/src/renderer/painter_raster.cpp index bf5780511..4cfe7c0c6 100644 --- a/src/renderer/painter_raster.cpp +++ b/src/renderer/painter_raster.cpp @@ -4,15 +4,10 @@ using namespace llmr; -void Painter::renderRaster(RasterBucket& bucket, const std::string& layer_name, const Tile::ID& /*id*/) { +void Painter::renderRaster(RasterBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& /*id*/) { if (pass == Translucent) return; - const std::unordered_map &raster_properties = map.getStyle()->computed.rasters; - const std::unordered_map::const_iterator raster_properties_it = raster_properties.find(layer_name); - - const RasterProperties &properties = raster_properties_it != raster_properties.end() - ? raster_properties_it->second - : defaultRasterProperties; + const RasterProperties &properties = layer_desc->getProperties(); if (!properties.enabled) return; depthMask(false); diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index baebe2669..cc5acbcab 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -5,17 +5,12 @@ using namespace llmr; -void Painter::renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id) { +void Painter::renderText(TextBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id) { // Abort early. if (pass == Opaque) return; if (!bucket.hasData()) return; - const std::unordered_map &text_properties = map.getStyle()->computed.texts; - const std::unordered_map::const_iterator text_properties_it = text_properties.find(layer_name); - - const TextProperties &properties = text_properties_it != text_properties.end() - ? text_properties_it->second - : defaultTextProperties; + const TextProperties &properties = layer_desc->getProperties(); if (!properties.enabled) return; mat4 exMatrix; @@ -24,16 +19,13 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle()); } - const float rotate = properties.rotate; - if (rotate != 0.0f) { - matrix::rotate_z(exMatrix, exMatrix, rotate); - } - // If layerStyle.size > bucket.info.fontSize then labels may collide float fontSize = std::fmin(properties.size, bucket.properties.max_size); matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f); - const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); +// TODO: figure out whether we actually need to account for this while painting; we might already have +// done this during label placement. +// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); useProgram(textShader->program); textShader->setMatrix(vtxMatrix); @@ -45,7 +37,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons static_cast(glyphAtlas.height)}}); // Convert the -pi..pi to an int8 range. - float angle = std::round((map.getState().getAngle() + rotate) / M_PI * 128); + float angle = std::round((map.getState().getAngle()) / M_PI * 128); // adjust min/max zooms for variable font sies float zoomAdjust = log(fontSize / bucket.properties.max_size) / log(2); @@ -98,12 +90,12 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons // We're drawing in the translucent pass which is bottom-to-top, so we need // to draw the halo first. - if (properties.halo[3] > 0.0f) { + if (properties.halo_color[3] > 0.0f) { // TODO: Get rid of the 2.4 magic value. It is currently 24 / 10, with 24 being the font size // of the SDF glyphs. textShader->setGamma(properties.halo_blur * 2.4f / fontSize / map.getState().getPixelRatio()); - textShader->setColor(properties.halo); - textShader->setBuffer(properties.halo_radius); + textShader->setColor(properties.halo_color); + textShader->setBuffer(properties.halo_width); glDepthRange(strata, 1.0f); bucket.drawGlyphs(*textShader); } diff --git a/src/renderer/raster_bucket.cpp b/src/renderer/raster_bucket.cpp index 3bc0e74fe..670d22eb6 100644 --- a/src/renderer/raster_bucket.cpp +++ b/src/renderer/raster_bucket.cpp @@ -7,8 +7,8 @@ RasterBucket::RasterBucket(const std::shared_ptr &texturepool) : raster(texturepool) { } -void RasterBucket::render(Painter &painter, const std::string &layer_name, const Tile::ID &id) { - painter.renderRaster(*this, layer_name, id); +void RasterBucket::render(Painter &painter, std::shared_ptr layer_desc, const Tile::ID &id) { + painter.renderRaster(*this, layer_desc, id); } bool RasterBucket::setImage(const std::string &data) { diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index bd18f0576..165d636f5 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -22,7 +22,7 @@ using namespace llmr; TextBucket::TextBucket( TextVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer, - const BucketTextDescription &properties, Placement &placement) + const StyleBucketText &properties, Placement &placement) : properties(properties), vertexBuffer(vertexBuffer), triangleElementsBuffer(triangleElementsBuffer), @@ -124,9 +124,9 @@ void TextBucket::addFeature(const pbf &geom_pbf, } } -void TextBucket::render(Painter &painter, const std::string &layer_name, +void TextBucket::render(Painter &painter, std::shared_ptr layer_desc, const Tile::ID &id) { - painter.renderText(*this, layer_name, id); + painter.renderText(*this, layer_desc, id); } bool TextBucket::hasData() const { diff --git a/src/style/layer_description.cpp b/src/style/layer_description.cpp index 53c6230cb..7e5ca5820 100644 --- a/src/style/layer_description.cpp +++ b/src/style/layer_description.cpp @@ -3,20 +3,20 @@ #include using namespace llmr; - -size_t LayerDescription::size() const { - size_t count = 1; - for (const LayerDescription &layer : child_layer) { - count += layer.size(); - } - return count; -} - -std::ostream& llmr::operator<<(std::ostream& os, const LayerDescription& layer) { - os << "Structure: " << layer.name << std::endl; - os << " - bucket_name: " << layer.bucket_name << std::endl; - for (const LayerDescription& value : layer.child_layer) { - os << " - child_layer: " << value << std::endl; - } - return os; -} +// +//size_t LayerDescription::size() const { +// size_t count = 1; +// for (const LayerDescription &layer : child_layer) { +// count += layer.size(); +// } +// return count; +//} +// +//std::ostream& llmr::operator<<(std::ostream& os, const LayerDescription& layer) { +// os << "Structure: " << layer.name << std::endl; +// os << " - bucket_name: " << layer.bucket_name << std::endl; +// for (const LayerDescription& value : layer.child_layer) { +// os << " - child_layer: " << value << std::endl; +// } +// return os; +//} diff --git a/src/style/properties.cpp b/src/style/properties.cpp index b39f20c51..4f0649b22 100644 --- a/src/style/properties.cpp +++ b/src/style/properties.cpp @@ -5,8 +5,7 @@ #include #include -using namespace llmr; - +namespace llmr { float functions::null(float, const std::vector&) { return 0; @@ -86,3 +85,13 @@ float functions::exponential(float z, const std::vector& values) { return std::fmin(std::fmax(min, val + std::pow(1.75, (z - z_base)) * slope), max); } + +template<> const FillProperties &defaultStyleProperties() { static const FillProperties p; return p; } +template<> const LineProperties &defaultStyleProperties() { static const LineProperties p; return p; } +template<> const IconProperties &defaultStyleProperties() { static const IconProperties p; return p; } +template<> const TextProperties &defaultStyleProperties() { static const TextProperties p; return p; } +template<> const CompositeProperties &defaultStyleProperties() { static const CompositeProperties p; return p; } +template<> const RasterProperties &defaultStyleProperties() { static const RasterProperties p; return p; } +template<> const BackgroundProperties &defaultStyleProperties() { static const BackgroundProperties p; return p; } + +} diff --git a/src/style/style.cpp b/src/style/style.cpp index f5c4d8043..3bb494867 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1,364 +1,575 @@ #include #include #include +#include #include #include -using namespace llmr; +namespace llmr { Style::Style() { - appliedClasses.insert("default"); } void Style::reset() { - computed.fills.clear(); - computed.lines.clear(); - computed.icons.clear(); - computed.texts.clear(); - computed.rasters.clear(); - computed.composites.clear(); - computed.background.color = {{ 1, 1, 1, 1 }}; - computed.background.opacity = 1.0; - - properties_to_transition.clear(); +// computed.fills.clear(); +// computed.lines.clear(); +// computed.icons.clear(); +// computed.texts.clear(); +// computed.rasters.clear(); +// computed.composites.clear(); +// computed.background.color = {{ 1, 1, 1, 1 }}; +// computed.background.opacity = 1.0; +// +// properties_to_transition.clear(); } -void Style::cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - using Key = ClassPropertyKey; +void Style::updateSources() { + activeSources.clear(); + updateSources(layers); +} - if (const FunctionProperty *enabled = klass.get(Key::Enabled)) { - properties.enabled = enabled->evaluate(z); +const std::set> Style::getActiveSources() const { + return activeSources; +} + +void Style::updateSources(const std::shared_ptr &layers) { + if (!layers) { + return; } - - if (const FunctionProperty *translateX = klass.get(Key::TranslateX)) { - properties.translate[0] = translateX->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - } - - if (const FunctionProperty *translateY = klass.get(Key::TranslateY)) { - properties.translate[1] = translateY->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; - } - - if (const PropertyTransition *translateTransition = klass.get(Key::TranslateTransition)) { - if (translateTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Translate, *translateTransition); + for (const std::shared_ptr &layer : *layers) { + if (!layer) continue; + if (layer->bucket) { + if (layer->bucket->source) { + activeSources.emplace(layer->bucket->source); + } + } else if (layer->layers) { + updateSources(layer->layers); } } - - if (const TranslateAnchor *translateAnchor = klass.get(Key::TranslateAnchor)) { - properties.translateAnchor = *translateAnchor; - } - - if (const FunctionProperty *opacity = klass.get(Key::Opacity)) { - properties.opacity = opacity->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; - } - - if (const PropertyTransition *opacityTransition = klass.get(Key::OpacityTransition)) { - if (opacityTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Opacity, *opacityTransition); - } - } - - if (const FunctionProperty *prerender = klass.get(Key::Prerender)) { - properties.prerender = *prerender; - } - - if (const FunctionProperty *prerenderBuffer = klass.get(Key::PrerenderBuffer)) { - properties.prerenderBuffer = *prerenderBuffer; - } - - if (const FunctionProperty *prerenderSize = klass.get(Key::PrerenderSize)) { - properties.prerenderSize = *prerenderSize; - } - - if (const FunctionProperty *prerenderBlur = klass.get(Key::PrerenderBlur)) { - properties.prerenderBlur = *prerenderBlur; - } } -void Style::cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +//void Style::cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// using Key = ClassPropertyKey; +// +// if (const FunctionProperty *enabled = klass.get(Key::Enabled)) { +// properties.enabled = enabled->evaluate(z); +// } +// +// if (const FunctionProperty *translateX = klass.get(Key::TranslateX)) { +// properties.translate[0] = translateX->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; +// } +// +// if (const FunctionProperty *translateY = klass.get(Key::TranslateY)) { +// properties.translate[1] = translateY->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name; +// } +// +// if (const PropertyTransition *translateTransition = klass.get(Key::TranslateTransition)) { +// if (translateTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Translate, *translateTransition); +// } +// } +// +// if (const TranslateAnchorType *translateAnchor = klass.get(Key::TranslateAnchor)) { +// properties.translateAnchor = *translateAnchor; +// } +// +// if (const FunctionProperty *opacity = klass.get(Key::Opacity)) { +// properties.opacity = opacity->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name; +// } +// +// if (const PropertyTransition *opacityTransition = klass.get(Key::OpacityTransition)) { +// if (opacityTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Opacity, *opacityTransition); +// } +// } +// +// if (const FunctionProperty *prerender = klass.get(Key::Prerender)) { +// properties.prerender = *prerender; +// } +// +// if (const FunctionProperty *prerenderBuffer = klass.get(Key::PrerenderBuffer)) { +// properties.prerenderBuffer = *prerenderBuffer; +// } +// +// if (const FunctionProperty *prerenderSize = klass.get(Key::PrerenderSize)) { +// properties.prerenderSize = *prerenderSize; +// } +// +// if (const FunctionProperty *prerenderBlur = klass.get(Key::PrerenderBlur)) { +// properties.prerenderBlur = *prerenderBlur; +// } +//} - using Key = ClassPropertyKey; - - if (const Winding *winding = klass.get(Key::FillWinding)) { - properties.winding = *winding; +//void Style::cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +// +// using Key = ClassPropertyKey; +// +// if (const FunctionProperty *antialias = klass.get(Key::FillAntialias)) { +// properties.antialias = antialias->evaluate(z); +// } +// +// if (const Color *fillColor = klass.get(Key::FillColor)) { +// properties.fill_color = *fillColor; +// computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; +// } +// +// if (const PropertyTransition *fillColorTransition = klass.get(Key::FillColorTransition)) { +// if (fillColorTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, *fillColorTransition); +// } +// } +// +// if (const Color *fillStrokeColor = klass.get(Key::FillStrokeColor)) { +// properties.stroke_color = *fillStrokeColor; +// computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; +// } else if (const Color *fillColor = klass.get(Key::FillColor)) { +// properties.stroke_color = *fillColor; +// computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; +// +// if (const PropertyTransition *fillColorTransition = klass.get(Key::FillColorTransition)) { +// if (fillColorTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, *fillColorTransition); +// } +// } +// } +// +// if (const std::string *image = klass.get(Key::FillImage)) { +// properties.image = *image; +// } +//} +// +//void Style::cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +// +// using Key = ClassPropertyKey; +// +// if (const FunctionProperty *width = klass.get(Key::LineWidth)) { +// properties.width = width->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; +// } +// +// if (const PropertyTransition *width_transition = klass.get(Key::LineWidthTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Width, *width_transition); +// } +// +// if (const FunctionProperty *offset = klass.get(Key::LineOffset)) { +// properties.offset = offset->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; +// } +// +// if (const PropertyTransition *offset_transition = klass.get(Key::LineOffsetTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Offset, *offset_transition); +// } +// +// if (const Color *color = klass.get(Key::LineColor)) { +// properties.color = *color; +// computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; +// } +// +// if (const PropertyTransition *color_transition = klass.get(Key::LineColorTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *color_transition); +// } +// +// if (const FunctionProperty *dash_array = klass.get(Key::LineDashLand)) { +// properties.dash_array[0] = dash_array->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; +// } +// +// if (const FunctionProperty *dash_array = klass.get(Key::LineDashGap)) { +// properties.dash_array[1] = dash_array->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; +// } +// +// if (const PropertyTransition *dash_array_transition = klass.get(Key::LineDashTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::DashArray, *dash_array_transition); +// } +//} +// +//void Style::cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +// +// using Key = ClassPropertyKey; +// +// if (const Color *color = klass.get(Key::TextColor)) { +// properties.color = *color; +// computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; +// } +// +// if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); +// } +// +// if (const FunctionProperty *size = klass.get(Key::TextSize)) { +// properties.size = size->evaluate(z); +// } +// +// if (const Color *haloColor = klass.get(Key::TextHaloColor)) { +// properties.halo = *haloColor; +// computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; +// } +// +// if (const PropertyTransition *haloColorTransition = klass.get(Key::TextHaloColorTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Halo, *haloColorTransition); +// } +// +// if (const FunctionProperty *haloRadius = klass.get(Key::TextHaloRadius)) { +// properties.halo_radius = haloRadius->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; +// } +// +// if (const PropertyTransition *haloRadiusTransition = klass.get(Key::TextHaloRadiusTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloRadius, *haloRadiusTransition); +// } +// +// if (const FunctionProperty *haloBlur = klass.get(Key::TextHaloBlur)) { +// properties.halo_blur = haloBlur->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; +// } +// +// if (const PropertyTransition *haloBlurTransition = klass.get(Key::TextHaloBlurTransition)) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloBlur, *haloBlurTransition); +// } +// +// if (const FunctionProperty *rotate = klass.get(Key::TextRotate)) { +// properties.rotate = rotate->evaluate(z); +// } +// +// if (const FunctionProperty *alwaysVisible = klass.get(Key::TextAlwaysVisible)) { +// properties.always_visible = alwaysVisible->evaluate(z); +// } +//} +// +//void Style::cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +// +// using Key = ClassPropertyKey; +// +// if (const Color *color = klass.get(Key::IconColor)) { +// properties.color = *color; +// computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; +// } +// +// if (const PropertyTransition *colorTransition = klass.get(Key::IconColorTransition)) { +// if (colorTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); +// } +// } +// +// if (const FunctionProperty *size = klass.get(Key::IconSize)) { +// properties.size = size->evaluate(z); +// } +// +// if (const std::string *image = klass.get(Key::IconImage)) { +// properties.image = *image; +// } +// +// if (const FunctionProperty *radius = klass.get(Key::IconRadius)) { +// properties.radius = radius->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; +// } +// +// if (const PropertyTransition *radiusTransition = klass.get(Key::IconRadiusTransition)) { +// if (radiusTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Radius, *radiusTransition); +// } +// } +// +// if (const FunctionProperty *blur = klass.get(Key::IconBlur)) { +// properties.blur = blur->evaluate(z); +// computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; +// } +// +// if (const PropertyTransition *blurTransition = klass.get(Key::IconBlurTransition)) { +// if (blurTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Blur, *blurTransition); +// } +// } +//} +// +//void Style::cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +//} +// +//void Style::cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +//} +// +//void Style::cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { +// cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); +// +// using Key = ClassPropertyKey; +// +// if (const Color *backgroundColor = klass.get(Key::BackgroundColor)) { +// properties.color = *backgroundColor; +// computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; +// } +// +// if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { +// if (colorTransition->duration) { +// properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); +// } +// } +//} +// +//struct ApplyClassProperties { +// ApplyClassProperties(const llmr::ClassProperties &properties, float z) : properties(properties), z(z) {}; +// +// +// inline float operator()(const FunctionProperty &function) { +// return function.evaluate(z); +// } +// +// template +// inline T &operator()(T &t) { return t; } +// +// template +// inline void applyProperty(ClassPropertyKey key, T &target) { +// auto it = properties.properties.find(key); +// if (it != properties.properties.end()) { +// target = util::apply_visitor(it->second, *this); +// } +// } +// +// inline void operator()(FillProperties &style) { +// applyProperty(ClassPropertyKey::FillEnabled, style.enabled); +// applyProperty(ClassPropertyKey::FillAntialias, style.antialias); +// applyProperty(ClassPropertyKey::FillOpacity, style.opacity); +// applyProperty(ClassPropertyKey::FillColor, style.fill_color); +// applyProperty(ClassPropertyKey::FillOutlineColor, style.stroke_color); +// applyProperty(ClassPropertyKey::FillTranslateX, style.translate[0]); +// applyProperty(ClassPropertyKey::FillTranslateY, style.translate[1]); +// applyProperty(ClassPropertyKey::FillTranslateAnchor, style.translateAnchor); +// applyProperty(ClassPropertyKey::FillImage, style.image); +// } +//// +//// inline void operator()(LineProperties &style) {} +//// inline void operator()(IconProperties &style) {} +//// inline void operator()(TextProperties &style) {} +//// inline void operator()(CompositeProperties &style) {} +//// inline void operator()(RasterProperties &style) {} +//// inline void operator()(BackgroundProperties &style) {} +//// inline void operator()(std::false_type &) {} +// +// +// +//// template +//// inline void operator()(T &style) {}; +// +//private: +// const llmr::ClassProperties &properties; +// const float z; +//}; +// +StyleProperties resetClassProperties(StyleLayer &layer) { + if (layer.layers) { + return CompositeProperties(); + } else if (layer.bucket) { + switch (layer.bucket->type) { + case BucketType::Fill: return FillProperties(); break; + case BucketType::Line: return LineProperties(); break; + case BucketType::Icon: return IconProperties(); break; + case BucketType::Text: return TextProperties(); break; + case BucketType::Raster: return RasterProperties(); break; + default: return std::false_type(); break; + } + } else { + return BackgroundProperties(); } +} - if (const FunctionProperty *antialias = klass.get(Key::FillAntialias)) { - properties.antialias = antialias->evaluate(z); - } - - if (const Color *fillColor = klass.get(Key::FillColor)) { - properties.fill_color = *fillColor; - computed.effective_classes[layer_name][TransitionablePropertyKey::FillColor] = class_name; - } - - if (const PropertyTransition *fillColorTransition = klass.get(Key::FillColorTransition)) { - if (fillColorTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, *fillColorTransition); +template +void applyProperty(const ClassProperties &properties, ClassPropertyKey key, T &target) { + auto it = properties.properties.find(key); + if (it != properties.properties.end()) { + const ClassPropertyValue &value = it->second; + if (value.is()) { + target = value.get(); } } +} - if (const Color *fillStrokeColor = klass.get(Key::FillStrokeColor)) { - properties.stroke_color = *fillStrokeColor; - computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; - } else if (const Color *fillColor = klass.get(Key::FillColor)) { - properties.stroke_color = *fillColor; - computed.effective_classes[layer_name][TransitionablePropertyKey::StrokeColor] = class_name; +template +void applyProperty(const ClassProperties &properties, ClassPropertyKey key, T &target, float z) { + auto it = properties.properties.find(key); + if (it != properties.properties.end()) { + const ClassPropertyValue &value = it->second; + if (value.is()) { + target = value.get().evaluate(z); + } else if (value.is()) { + target = value.get(); + } + } +} - if (const PropertyTransition *fillColorTransition = klass.get(Key::FillColorTransition)) { - if (fillColorTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::FillColor, *fillColorTransition); +void applyClassProperties(StyleProperties &style, const ClassProperties &properties, float z) { + if (style.is()) { + FillProperties &fill = style.get(); + applyProperty(properties, ClassPropertyKey::FillEnabled, fill.enabled, z); + applyProperty(properties, ClassPropertyKey::FillAntialias, fill.antialias, z); + applyProperty(properties, ClassPropertyKey::FillOpacity, fill.opacity, z); + applyProperty(properties, ClassPropertyKey::FillColor, fill.fill_color); + applyProperty(properties, ClassPropertyKey::FillOutlineColor, fill.stroke_color); + applyProperty(properties, ClassPropertyKey::FillTranslateX, fill.translate[0], z); + applyProperty(properties, ClassPropertyKey::FillTranslateY, fill.translate[1], z); + applyProperty(properties, ClassPropertyKey::FillTranslateAnchor, fill.translateAnchor); + applyProperty(properties, ClassPropertyKey::FillImage, fill.image); + } else if (style.is()) { + LineProperties &line = style.get(); + applyProperty(properties, ClassPropertyKey::LineEnabled, line.enabled, z); + applyProperty(properties, ClassPropertyKey::LineOpacity, line.opacity, z); + applyProperty(properties, ClassPropertyKey::LineColor, line.color); + applyProperty(properties, ClassPropertyKey::LineTranslateX, line.translate[0], z); + applyProperty(properties, ClassPropertyKey::LineTranslateY, line.translate[1], z); + applyProperty(properties, ClassPropertyKey::LineTranslateAnchor, line.translateAnchor); + applyProperty(properties, ClassPropertyKey::LineWidth, line.width, z); + applyProperty(properties, ClassPropertyKey::LineOffset, line.offset, z); + applyProperty(properties, ClassPropertyKey::LineBlur, line.blur, z); + applyProperty(properties, ClassPropertyKey::LineDashLand, line.dash_array[0], z); + applyProperty(properties, ClassPropertyKey::LineDashGap, line.dash_array[1], z); + applyProperty(properties, ClassPropertyKey::LineImage, line.image); + } else if (style.is()) { + IconProperties &icon = style.get(); + applyProperty(properties, ClassPropertyKey::IconEnabled, icon.enabled, z); + applyProperty(properties, ClassPropertyKey::IconOpacity, icon.opacity, z); + applyProperty(properties, ClassPropertyKey::IconRotate, icon.rotate, z); + applyProperty(properties, ClassPropertyKey::IconRotateAnchor, icon.rotate_anchor); + } else if (style.is()) { + TextProperties &text = style.get(); + applyProperty(properties, ClassPropertyKey::TextEnabled, text.enabled, z); + applyProperty(properties, ClassPropertyKey::TextOpacity, text.opacity, z); + applyProperty(properties, ClassPropertyKey::TextSize, text.size, z); + applyProperty(properties, ClassPropertyKey::TextColor, text.color); + applyProperty(properties, ClassPropertyKey::TextHaloColor, text.halo_color); + applyProperty(properties, ClassPropertyKey::TextHaloWidth, text.halo_width, z); + applyProperty(properties, ClassPropertyKey::TextHaloBlur, text.halo_blur, z); + } else if (style.is()) { + CompositeProperties &composite = style.get(); + applyProperty(properties, ClassPropertyKey::CompositeEnabled, composite.enabled, z); + applyProperty(properties, ClassPropertyKey::CompositeOpacity, composite.opacity, z); + } else if (style.is()) { + RasterProperties &raster = style.get(); + applyProperty(properties, ClassPropertyKey::RasterSpin, raster.spin, z); + applyProperty(properties, ClassPropertyKey::RasterBrightnessLow, raster.brightness[0], z); + applyProperty(properties, ClassPropertyKey::RasterBrightnessHigh, raster.brightness[1], z); + applyProperty(properties, ClassPropertyKey::RasterSaturation, raster.saturation, z); + applyProperty(properties, ClassPropertyKey::RasterContrast, raster.contrast, z); + applyProperty(properties, ClassPropertyKey::RasterFade, raster.fade, z); + } else if (style.is()) { + BackgroundProperties &background = style.get(); + applyProperty(properties, ClassPropertyKey::BackgroundColor, background.color); + } +} + +void Style::cascade(const std::shared_ptr &layers, float z) { + if (!layers) { + return; + } + + for (const std::shared_ptr &layer : *layers) { + if (!layer) continue; + + if (layer->layers) { + cascade(layer->layers, z); + } + + // Accomodate for different tile size. + if (layer->bucket) { + const StyleBucket &bucket = *layer->bucket; + if (bucket.source) { + const Source &source = *bucket.source; + z += std::log(source.tile_size / 256.0f) / M_LN2; + } + } + + layer->style = resetClassProperties(*layer); + + // Apply default class (if exists) + auto default_it = layer->styles.find(""); + if (default_it != layer->styles.end()) { + applyClassProperties(layer->style, default_it->second, z); + } + + // Apply overriding classes in order. + for (const std::string &class_name : appliedClasses) { + auto class_it = layer->styles.find(class_name); + if (class_it != layer->styles.end()) { + applyClassProperties(layer->style, class_it->second, z); } } } - - if (const std::string *image = klass.get(Key::FillImage)) { - properties.image = *image; - } } -void Style::cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); - - using Key = ClassPropertyKey; - - if (const FunctionProperty *width = klass.get(Key::LineWidth)) { - properties.width = width->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Width] = class_name; - } - - if (const PropertyTransition *width_transition = klass.get(Key::LineWidthTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Width, *width_transition); - } - - if (const FunctionProperty *offset = klass.get(Key::LineOffset)) { - properties.offset = offset->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Offset] = class_name; - } - - if (const PropertyTransition *offset_transition = klass.get(Key::LineOffsetTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Offset, *offset_transition); - } - - if (const Color *color = klass.get(Key::LineColor)) { - properties.color = *color; - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - } - - if (const PropertyTransition *color_transition = klass.get(Key::LineColorTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *color_transition); - } - - if (const FunctionProperty *dash_array = klass.get(Key::LineDashLand)) { - properties.dash_array[0] = dash_array->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; - } - - if (const FunctionProperty *dash_array = klass.get(Key::LineDashGap)) { - properties.dash_array[1] = dash_array->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::DashArray] = class_name; - } - - if (const PropertyTransition *dash_array_transition = klass.get(Key::LineDashTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::DashArray, *dash_array_transition); - } -} - -void Style::cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); - - using Key = ClassPropertyKey; - - if (const Color *color = klass.get(Key::TextColor)) { - properties.color = *color; - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - } - - if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); - } - - if (const FunctionProperty *size = klass.get(Key::TextSize)) { - properties.size = size->evaluate(z); - } - - if (const Color *haloColor = klass.get(Key::TextHaloColor)) { - properties.halo = *haloColor; - computed.effective_classes[layer_name][TransitionablePropertyKey::Halo] = class_name; - } - - if (const PropertyTransition *haloColorTransition = klass.get(Key::TextHaloColorTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Halo, *haloColorTransition); - } - - if (const FunctionProperty *haloRadius = klass.get(Key::TextHaloRadius)) { - properties.halo_radius = haloRadius->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::HaloRadius] = class_name; - } - - if (const PropertyTransition *haloRadiusTransition = klass.get(Key::TextHaloRadiusTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloRadius, *haloRadiusTransition); - } - - if (const FunctionProperty *haloBlur = klass.get(Key::TextHaloBlur)) { - properties.halo_blur = haloBlur->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::HaloBlur] = class_name; - } - - if (const PropertyTransition *haloBlurTransition = klass.get(Key::TextHaloBlurTransition)) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::HaloBlur, *haloBlurTransition); - } - - if (const FunctionProperty *rotate = klass.get(Key::TextRotate)) { - properties.rotate = rotate->evaluate(z); - } - - if (const FunctionProperty *alwaysVisible = klass.get(Key::TextAlwaysVisible)) { - properties.always_visible = alwaysVisible->evaluate(z); - } -} - -void Style::cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); - - using Key = ClassPropertyKey; - - if (const Color *color = klass.get(Key::IconColor)) { - properties.color = *color; - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - } - - if (const PropertyTransition *colorTransition = klass.get(Key::IconColorTransition)) { - if (colorTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); - } - } - - if (const FunctionProperty *size = klass.get(Key::IconSize)) { - properties.size = size->evaluate(z); - } - - if (const std::string *image = klass.get(Key::IconImage)) { - properties.image = *image; - } - - if (const FunctionProperty *radius = klass.get(Key::IconRadius)) { - properties.radius = radius->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Radius] = class_name; - } - - if (const PropertyTransition *radiusTransition = klass.get(Key::IconRadiusTransition)) { - if (radiusTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Radius, *radiusTransition); - } - } - - if (const FunctionProperty *blur = klass.get(Key::IconBlur)) { - properties.blur = blur->evaluate(z); - computed.effective_classes[layer_name][TransitionablePropertyKey::Blur] = class_name; - } - - if (const PropertyTransition *blurTransition = klass.get(Key::IconBlurTransition)) { - if (blurTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Blur, *blurTransition); - } - } -} - -void Style::cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); -} - -void Style::cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); -} - -void Style::cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z) { - cascadeProperties(reinterpret_cast(properties), klass, layer_name, class_name, z); - - using Key = ClassPropertyKey; - - if (const Color *backgroundColor = klass.get(Key::BackgroundColor)) { - properties.color = *backgroundColor; - computed.effective_classes[layer_name][TransitionablePropertyKey::Color] = class_name; - } - - if (const PropertyTransition *colorTransition = klass.get(Key::TextColorTransition)) { - if (colorTransition->duration) { - properties_to_transition[layer_name].emplace(TransitionablePropertyKey::Color, *colorTransition); - } - } -} - - void Style::cascade(float z) { uv::writelock lock(mtx); + updateSources(); + time start = util::now(); - - previous.fills.swap(computed.fills); - previous.lines.swap(computed.lines); - previous.icons.swap(computed.icons); - previous.texts.swap(computed.texts); - previous.rasters.swap(computed.rasters); - previous.composites.swap(computed.composites); - previous.background = computed.background; - - previous.effective_classes.swap(computed.effective_classes); - +// +// previous.fills.swap(computed.fills); +// previous.lines.swap(computed.lines); +// previous.icons.swap(computed.icons); +// previous.texts.swap(computed.texts); +// previous.rasters.swap(computed.rasters); +// previous.composites.swap(computed.composites); +// previous.background = computed.background; +// +// previous.effective_classes.swap(computed.effective_classes); +// reset(); - // Accomodate for different tile size. // TODO: Make this per-layer once individual layers have a specific tile size. - z += std::log(util::tileSize / 256.0f) / M_LN2; +// z += std::log(util::tileSize / 256.0f) / M_LN2; + + cascade(layers, z); // Recalculate style with basic cascading. Also store the last applied class // for each property to assist in determining transitions. - for (const auto& class_pair : classes) { - const std::string& class_name = class_pair.first; - const ClassDescription& sheetClass = class_pair.second; - - using Key = ClassPropertyKey; - +// for (const auto& class_pair : classes) { +// const std::string& class_name = class_pair.first; +// const ClassDescription& sheetClass = class_pair.second; +// +// using Key = ClassPropertyKey; +// // Skip if not enabled. - if (appliedClasses.find(class_name) == appliedClasses.end()) continue; - - for (const auto &pair : sheetClass) { - const std::string& layer_name = pair.first; - const ClassProperties& properties = pair.second; - +// if (appliedClasses.find(class_name) == appliedClasses.end()) continue; +// +// for (const auto &pair : sheetClass) { +// const std::string& layer_name = pair.first; +// const ClassProperties& properties = pair.second; +// // Find out what bucket this class is - switch (properties.type) { - case RenderType::Fill: - cascadeProperties(computed.fills[layer_name], properties, layer_name, class_name, z); - break; - case RenderType::Line: - cascadeProperties(computed.lines[layer_name], properties, layer_name, class_name, z); - break; - case RenderType::Icon: - cascadeProperties(computed.icons[layer_name], properties, layer_name, class_name, z); - break; - case RenderType::Text: - cascadeProperties(computed.texts[layer_name], properties, layer_name, class_name, z); - break; - case RenderType::Raster: - cascadeProperties(computed.rasters[layer_name], properties, layer_name, class_name, z); - break; - case RenderType::Composite: - cascadeProperties(computed.composites[layer_name], properties, layer_name, class_name, z); - break; - case RenderType::Background: - cascadeProperties(computed.background, properties, layer_name, class_name, z); - break; - } - } - } +// switch (properties.type) { +// case RenderType::Fill: +// cascadeProperties(computed.fills[layer_name], properties, layer_name, class_name, z); +// break; +// case RenderType::Line: +// cascadeProperties(computed.lines[layer_name], properties, layer_name, class_name, z); +// break; +// case RenderType::Icon: +// cascadeProperties(computed.icons[layer_name], properties, layer_name, class_name, z); +// break; +// case RenderType::Text: +// cascadeProperties(computed.texts[layer_name], properties, layer_name, class_name, z); +// break; +// case RenderType::Raster: +// cascadeProperties(computed.rasters[layer_name], properties, layer_name, class_name, z); +// break; +// case RenderType::Composite: +// cascadeProperties(computed.composites[layer_name], properties, layer_name, class_name, z); +// break; +// case RenderType::Background: +// cascadeProperties(computed.background, properties, layer_name, class_name, z); +// break; +// } +// } +// } // Apply transitions after the first time. if (!initial_render_complete) { @@ -366,691 +577,680 @@ void Style::cascade(float z) { return; } - // Fills - for (const auto& fill_pair : computed.fills) { - const std::string& layer_name = fill_pair.first; - - // translate - if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { - - computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { - - transitioning.fills[layer_name].translate = previous.fills[layer_name].translate; - - transitions[layer_name][TransitionablePropertyKey::Translate] = - std::make_shared>>(previous.fills[layer_name].translate, - computed.fills[layer_name].translate, - transitioning.fills[layer_name].translate, - start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), - transitionDuration(layer_name, TransitionablePropertyKey::Translate)); - - computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; - } - - // fill color - if (transitionInProgress(layer_name, TransitionablePropertyKey::FillColor, start)) { - - computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::FillColor)) { - - transitioning.fills[layer_name].fill_color = previous.fills[layer_name].fill_color; - - transitions[layer_name][TransitionablePropertyKey::FillColor] = - std::make_shared>(previous.fills[layer_name].fill_color, - computed.fills[layer_name].fill_color, - transitioning.fills[layer_name].fill_color, - start + transitionDelay(layer_name, TransitionablePropertyKey::FillColor), - transitionDuration(layer_name, TransitionablePropertyKey::FillColor)); - - computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; - } - - // stroke color - if (transitionInProgress(layer_name, TransitionablePropertyKey::StrokeColor, start)) { - - computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::StrokeColor)) { - - transitioning.fills[layer_name].stroke_color = previous.fills[layer_name].stroke_color; - - transitions[layer_name][TransitionablePropertyKey::StrokeColor] = - std::make_shared>(previous.fills[layer_name].stroke_color, - computed.fills[layer_name].stroke_color, - transitioning.fills[layer_name].stroke_color, - start + transitionDelay(layer_name, TransitionablePropertyKey::StrokeColor), - transitionDuration(layer_name, TransitionablePropertyKey::StrokeColor)); - - computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; - } - - // opacity - if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { - - computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { - - transitioning.fills[layer_name].opacity = previous.fills[layer_name].opacity; - - transitions[layer_name][TransitionablePropertyKey::Opacity] = - std::make_shared>(previous.fills[layer_name].opacity, - computed.fills[layer_name].opacity, - transitioning.fills[layer_name].opacity, - start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), - transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); - - computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; - } - } - - // Lines - for (const auto& line_pair : computed.lines) { - const std::string& layer_name = line_pair.first; - - // translate - if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { - - computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { - - transitioning.lines[layer_name].translate = previous.lines[layer_name].translate; - - transitions[layer_name][TransitionablePropertyKey::Translate] = - std::make_shared>>(previous.lines[layer_name].translate, - computed.lines[layer_name].translate, - transitioning.lines[layer_name].translate, - start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), - transitionDuration(layer_name, TransitionablePropertyKey::Translate)); - - computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; - } - - // width - if (transitionInProgress(layer_name, TransitionablePropertyKey::Width, start)) { - - computed.lines[layer_name].width = transitioning.lines[layer_name].width; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Width)) { - - transitioning.lines[layer_name].width = previous.lines[layer_name].width; - - transitions[layer_name][TransitionablePropertyKey::Width] = - std::make_shared>(previous.lines[layer_name].width, - computed.lines[layer_name].width, - transitioning.lines[layer_name].width, - start + transitionDelay(layer_name, TransitionablePropertyKey::Width), - transitionDuration(layer_name, TransitionablePropertyKey::Width)); - - computed.lines[layer_name].width = transitioning.lines[layer_name].width; - } - - // offset - if (transitionInProgress(layer_name, TransitionablePropertyKey::Offset, start)) { - - computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Offset)) { - - transitioning.lines[layer_name].offset = previous.lines[layer_name].offset; - - transitions[layer_name][TransitionablePropertyKey::Offset] = - std::make_shared>(previous.lines[layer_name].offset, - computed.lines[layer_name].offset, - transitioning.lines[layer_name].offset, - start + transitionDelay(layer_name, TransitionablePropertyKey::Offset), - transitionDuration(layer_name, TransitionablePropertyKey::Offset)); - - computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; - } - - // color - if (transitionInProgress(layer_name, TransitionablePropertyKey::Color, start)) { - - computed.lines[layer_name].color = transitioning.lines[layer_name].color; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { - - transitioning.lines[layer_name].color = previous.lines[layer_name].color; - - transitions[layer_name][TransitionablePropertyKey::Color] = - std::make_shared>(previous.lines[layer_name].color, - computed.lines[layer_name].color, - transitioning.lines[layer_name].color, - start + transitionDelay(layer_name, TransitionablePropertyKey::Color), - transitionDuration(layer_name, TransitionablePropertyKey::Color)); - - computed.lines[layer_name].color = transitioning.lines[layer_name].color; - } - - // dasharray - if (transitionInProgress(layer_name, TransitionablePropertyKey::DashArray, start)) { - - computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::DashArray)) { - - transitioning.lines[layer_name].dash_array = previous.lines[layer_name].dash_array; - - transitions[layer_name][TransitionablePropertyKey::DashArray] = - std::make_shared>>(previous.lines[layer_name].dash_array, - computed.lines[layer_name].dash_array, - transitioning.lines[layer_name].dash_array, - start + transitionDelay(layer_name, TransitionablePropertyKey::DashArray), - transitionDuration(layer_name, TransitionablePropertyKey::DashArray)); - - computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; - } - - // opacity - if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { - - computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { - - transitioning.lines[layer_name].opacity = previous.lines[layer_name].opacity; - - transitions[layer_name][TransitionablePropertyKey::Opacity] = - std::make_shared>(previous.lines[layer_name].opacity, - computed.lines[layer_name].opacity, - transitioning.lines[layer_name].opacity, - start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), - transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); - - computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; - } - } - - // Icons - for (const auto& icon_pair : computed.icons) { - const std::string& layer_name = icon_pair.first; - - // translate - if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { - - computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { - - transitioning.icons[layer_name].translate = previous.icons[layer_name].translate; - - transitions[layer_name][TransitionablePropertyKey::Translate] = - std::make_shared>>(previous.icons[layer_name].translate, - computed.icons[layer_name].translate, - transitioning.icons[layer_name].translate, - start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), - transitionDuration(layer_name, TransitionablePropertyKey::Translate)); - - computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; - } - - // color - if (transitionInProgress(layer_name, TransitionablePropertyKey::Color, start)) { - - computed.icons[layer_name].color = transitioning.icons[layer_name].color; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { - - transitioning.icons[layer_name].color = previous.icons[layer_name].color; - - transitions[layer_name][TransitionablePropertyKey::Color] = - std::make_shared>(previous.icons[layer_name].color, - computed.icons[layer_name].color, - transitioning.icons[layer_name].color, - start + transitionDelay(layer_name, TransitionablePropertyKey::Color), - transitionDuration(layer_name, TransitionablePropertyKey::Color)); - - computed.icons[layer_name].color = transitioning.icons[layer_name].color; - } - - // opacity - if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { - - computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { - - transitioning.icons[layer_name].opacity = previous.icons[layer_name].opacity; - - transitions[layer_name][TransitionablePropertyKey::Opacity] = - std::make_shared>(previous.icons[layer_name].opacity, - computed.icons[layer_name].opacity, - transitioning.icons[layer_name].opacity, - start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), - transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); - - computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; - } - - // radius - if (transitionInProgress(layer_name, TransitionablePropertyKey::Radius, start)) { - - computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Radius)) { - - transitioning.icons[layer_name].radius = previous.icons[layer_name].radius; - - transitions[layer_name][TransitionablePropertyKey::Radius] = - std::make_shared>(previous.icons[layer_name].radius, - computed.icons[layer_name].radius, - transitioning.icons[layer_name].radius, - start + transitionDelay(layer_name, TransitionablePropertyKey::Radius), - transitionDuration(layer_name, TransitionablePropertyKey::Radius)); - - computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; - } - - // blur - if (transitionInProgress(layer_name, TransitionablePropertyKey::Blur, start)) { - - computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Blur)) { - - transitioning.icons[layer_name].blur = previous.icons[layer_name].blur; - - transitions[layer_name][TransitionablePropertyKey::Blur] = - std::make_shared>(previous.icons[layer_name].blur, - computed.icons[layer_name].blur, - transitioning.icons[layer_name].blur, - start + transitionDelay(layer_name, TransitionablePropertyKey::Blur), - transitionDuration(layer_name, TransitionablePropertyKey::Blur)); - - computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; - } - } - - // Text - for (const auto& text_pair : computed.texts) { - const std::string& layer_name = text_pair.first; - - // translate - if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { - - computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { - - transitioning.texts[layer_name].translate = previous.texts[layer_name].translate; - - transitions[layer_name][TransitionablePropertyKey::Translate] = - std::make_shared>>(previous.texts[layer_name].translate, - computed.texts[layer_name].translate, - transitioning.texts[layer_name].translate, - start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), - transitionDuration(layer_name, TransitionablePropertyKey::Translate)); - - computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; - } - - // color - if (transitionInProgress(layer_name, TransitionablePropertyKey::Color, start)) { - - computed.texts[layer_name].color = transitioning.texts[layer_name].color; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { - - transitioning.texts[layer_name].color = previous.texts[layer_name].color; - - transitions[layer_name][TransitionablePropertyKey::Color] = - std::make_shared>(previous.texts[layer_name].color, - computed.texts[layer_name].color, - transitioning.texts[layer_name].color, - start + transitionDelay(layer_name, TransitionablePropertyKey::Color), - transitionDuration(layer_name, TransitionablePropertyKey::Color)); - - computed.texts[layer_name].color = transitioning.texts[layer_name].color; - } - - // halo - if (transitionInProgress(layer_name, TransitionablePropertyKey::Halo, start)) { - - computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Halo)) { - - transitioning.texts[layer_name].halo = previous.texts[layer_name].halo; - - transitions[layer_name][TransitionablePropertyKey::Halo] = - std::make_shared>(previous.texts[layer_name].halo, - computed.texts[layer_name].halo, - transitioning.texts[layer_name].halo, - start + transitionDelay(layer_name, TransitionablePropertyKey::Halo), - transitionDuration(layer_name, TransitionablePropertyKey::Halo)); - - computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; - } - - // halo radius - if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloRadius, start)) { - - computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloRadius)) { - - transitioning.texts[layer_name].halo_radius = previous.texts[layer_name].halo_radius; - - transitions[layer_name][TransitionablePropertyKey::HaloRadius] = - std::make_shared>(previous.texts[layer_name].halo_radius, - computed.texts[layer_name].halo_radius, - transitioning.texts[layer_name].halo_radius, - start + transitionDelay(layer_name, TransitionablePropertyKey::HaloRadius), - transitionDuration(layer_name, TransitionablePropertyKey::HaloRadius)); - - computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; - } - - // halo blur - if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloBlur, start)) { - - computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloBlur)) { - - transitioning.texts[layer_name].halo_blur = previous.texts[layer_name].halo_blur; - - transitions[layer_name][TransitionablePropertyKey::HaloBlur] = - std::make_shared>(previous.texts[layer_name].halo_blur, - computed.texts[layer_name].halo_blur, - transitioning.texts[layer_name].halo_blur, - start + transitionDelay(layer_name, TransitionablePropertyKey::HaloBlur), - transitionDuration(layer_name, TransitionablePropertyKey::HaloBlur)); - - computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; - } - - // opacity - if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { - - computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { - - transitioning.texts[layer_name].opacity = previous.texts[layer_name].opacity; - - transitions[layer_name][TransitionablePropertyKey::Opacity] = - std::make_shared>(previous.texts[layer_name].opacity, - computed.texts[layer_name].opacity, - transitioning.texts[layer_name].opacity, - start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), - transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); - - computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; - } - } - - // Rasters - for (const auto& raster_pair : computed.rasters) { - const std::string& layer_name = raster_pair.first; - - // opacity - if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { - - computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { - - transitioning.rasters[layer_name].opacity = previous.rasters[layer_name].opacity; - - transitions[layer_name][TransitionablePropertyKey::Opacity] = - std::make_shared>(previous.rasters[layer_name].opacity, - computed.rasters[layer_name].opacity, - transitioning.rasters[layer_name].opacity, - start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), - transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); - - computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; - } - } - - // Composites - for (const auto& composite_pair : computed.composites) { - const std::string& layer_name = composite_pair.first; - - // opacity - if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { - - computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; - - } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { - - transitioning.composites[layer_name].opacity = previous.composites[layer_name].opacity; - - transitions[layer_name][TransitionablePropertyKey::Opacity] = - std::make_shared>(previous.composites[layer_name].opacity, - computed.composites[layer_name].opacity, - transitioning.composites[layer_name].opacity, - start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), - transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); - - computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; - } - } - - // Background - { - // color - if (transitionInProgress("background", TransitionablePropertyKey::Color, start)) { - - computed.background.color = transitioning.background.color; - - } else if (inNeedOfTransition("background", TransitionablePropertyKey::Color)) { - - transitioning.background.color = previous.background.color; - - transitions["background"][TransitionablePropertyKey::Color] = - std::make_shared>(previous.background.color, - computed.background.color, - transitioning.background.color, - start + transitionDelay("background", TransitionablePropertyKey::Color), - transitionDuration("background", TransitionablePropertyKey::Color)); - - computed.background.color = transitioning.background.color; - } - - // opacity - if (transitionInProgress("background", TransitionablePropertyKey::Opacity, start)) { - - computed.background.opacity = transitioning.background.opacity; - - } else if (inNeedOfTransition("background", TransitionablePropertyKey::Opacity)) { - - transitioning.background.opacity = previous.background.opacity; - - transitions["background"][TransitionablePropertyKey::Opacity] = - std::make_shared>(previous.background.opacity, - computed.background.opacity, - transitioning.background.opacity, - start + transitionDelay("background", TransitionablePropertyKey::Opacity), - transitionDuration("background", TransitionablePropertyKey::Opacity)); - - computed.background.opacity = transitioning.background.opacity; - } - } -} - -bool Style::transitionInProgress(const std::string &layer_name, TransitionablePropertyKey key, - time start) { - const auto it = transitions.find(layer_name); - if (it == transitions.end()) { - return false; - } - - const auto &const_transition = it->second; - const auto const_transition_it = const_transition.find(key); - - if (const_transition_it == const_transition.end()) { - return false; - } - - return const_transition_it->second->update(start) != util::transition::complete; -} - -bool Style::transitionExists(const std::string &layer_name, TransitionablePropertyKey key) const { - const auto it = transitions.find(layer_name); - if (it == transitions.end()) { - return false; - } - - const auto &const_transition = it->second; - return const_transition.find(key) != const_transition.end(); -} - -static const std::string empty_class_name; -inline const std::string & -find_effective_class(const std::unordered_map< - std::string, std::unordered_map> & - effective_class_keys, - const std::string &layer_name, TransitionablePropertyKey key) { - const auto effective_class_keys_it = effective_class_keys.find(layer_name); - if (effective_class_keys_it != effective_class_keys.end()) { - const auto &effective_classes = effective_class_keys_it->second; - const auto effective_class_it = effective_classes.find(key); - if (effective_class_it != effective_classes.end()) { - return effective_class_it->second; - } - } - - return empty_class_name; -} - -bool Style::inNeedOfTransition(const std::string &layer_name, TransitionablePropertyKey key) const { - if (!transitionDuration(layer_name, key)) { - return false; - } else if (transitionExists(layer_name, key)) { - return false; - } - - // This is a const version of this code: - // return (computed.effective_classes[layer_name][key] != - // previous.effective_classes[layer_name][key]); - - const std::string &computed_class = - find_effective_class(computed.effective_classes, layer_name, key); - const std::string &previous_class = - find_effective_class(previous.effective_classes, layer_name, key); - - return computed_class != previous_class; -} - -uint64_t Style::transitionDuration(const std::string &layer_name, - TransitionablePropertyKey key) const { - const auto it = properties_to_transition.find(layer_name); - if (it == properties_to_transition.end()) { - return default_transition_duration * 1_millisecond; - } - - const auto &const_properties_to_transition = it->second; - const auto it2 = const_properties_to_transition.find(key); - if (it2 != const_properties_to_transition.end()) { - return it2->second.duration * 1_millisecond; - } else { - return default_transition_duration * 1_millisecond; - } -} - -uint64_t Style::transitionDelay(const std::string &layer_name, - TransitionablePropertyKey key) const { - const auto it = properties_to_transition.find(layer_name); - if (it == properties_to_transition.end()) { - return 0; - } - - const auto &const_properties_to_transition = it->second; - const auto it2 = const_properties_to_transition.find(key); - if (it2 != const_properties_to_transition.end()) { - return it2->second.delay * 1_millisecond; - } else { - return 0; - } +// // Fills +// for (const auto& fill_pair : computed.fills) { +// const std::string& layer_name = fill_pair.first; +// +// // translate +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { +// +// computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { +// +// transitioning.fills[layer_name].translate = previous.fills[layer_name].translate; +// +// transitions[layer_name][TransitionablePropertyKey::Translate] = +// std::make_shared>>(previous.fills[layer_name].translate, +// computed.fills[layer_name].translate, +// transitioning.fills[layer_name].translate, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), +// transitionDuration(layer_name, TransitionablePropertyKey::Translate)); +// +// computed.fills[layer_name].translate = transitioning.fills[layer_name].translate; +// } +// +// // fill color +// if (transitionInProgress(layer_name, TransitionablePropertyKey::FillColor, start)) { +// +// computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::FillColor)) { +// +// transitioning.fills[layer_name].fill_color = previous.fills[layer_name].fill_color; +// +// transitions[layer_name][TransitionablePropertyKey::FillColor] = +// std::make_shared>(previous.fills[layer_name].fill_color, +// computed.fills[layer_name].fill_color, +// transitioning.fills[layer_name].fill_color, +// start + transitionDelay(layer_name, TransitionablePropertyKey::FillColor), +// transitionDuration(layer_name, TransitionablePropertyKey::FillColor)); +// +// computed.fills[layer_name].fill_color = transitioning.fills[layer_name].fill_color; +// } +// +// // stroke color +// if (transitionInProgress(layer_name, TransitionablePropertyKey::StrokeColor, start)) { +// +// computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::StrokeColor)) { +// +// transitioning.fills[layer_name].stroke_color = previous.fills[layer_name].stroke_color; +// +// transitions[layer_name][TransitionablePropertyKey::StrokeColor] = +// std::make_shared>(previous.fills[layer_name].stroke_color, +// computed.fills[layer_name].stroke_color, +// transitioning.fills[layer_name].stroke_color, +// start + transitionDelay(layer_name, TransitionablePropertyKey::StrokeColor), +// transitionDuration(layer_name, TransitionablePropertyKey::StrokeColor)); +// +// computed.fills[layer_name].stroke_color = transitioning.fills[layer_name].stroke_color; +// } +// +// // opacity +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { +// +// computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { +// +// transitioning.fills[layer_name].opacity = previous.fills[layer_name].opacity; +// +// transitions[layer_name][TransitionablePropertyKey::Opacity] = +// std::make_shared>(previous.fills[layer_name].opacity, +// computed.fills[layer_name].opacity, +// transitioning.fills[layer_name].opacity, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), +// transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); +// +// computed.fills[layer_name].opacity = transitioning.fills[layer_name].opacity; +// } +// } +// +// // Lines +// for (const auto& line_pair : computed.lines) { +// const std::string& layer_name = line_pair.first; +// +// // translate +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { +// +// computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { +// +// transitioning.lines[layer_name].translate = previous.lines[layer_name].translate; +// +// transitions[layer_name][TransitionablePropertyKey::Translate] = +// std::make_shared>>(previous.lines[layer_name].translate, +// computed.lines[layer_name].translate, +// transitioning.lines[layer_name].translate, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), +// transitionDuration(layer_name, TransitionablePropertyKey::Translate)); +// +// computed.lines[layer_name].translate = transitioning.lines[layer_name].translate; +// } +// +// // width +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Width, start)) { +// +// computed.lines[layer_name].width = transitioning.lines[layer_name].width; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Width)) { +// +// transitioning.lines[layer_name].width = previous.lines[layer_name].width; +// +// transitions[layer_name][TransitionablePropertyKey::Width] = +// std::make_shared>(previous.lines[layer_name].width, +// computed.lines[layer_name].width, +// transitioning.lines[layer_name].width, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Width), +// transitionDuration(layer_name, TransitionablePropertyKey::Width)); +// +// computed.lines[layer_name].width = transitioning.lines[layer_name].width; +// } +// +// // offset +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Offset, start)) { +// +// computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Offset)) { +// +// transitioning.lines[layer_name].offset = previous.lines[layer_name].offset; +// +// transitions[layer_name][TransitionablePropertyKey::Offset] = +// std::make_shared>(previous.lines[layer_name].offset, +// computed.lines[layer_name].offset, +// transitioning.lines[layer_name].offset, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Offset), +// transitionDuration(layer_name, TransitionablePropertyKey::Offset)); +// +// computed.lines[layer_name].offset = transitioning.lines[layer_name].offset; +// } +// +// // color +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Color, start)) { +// +// computed.lines[layer_name].color = transitioning.lines[layer_name].color; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { +// +// transitioning.lines[layer_name].color = previous.lines[layer_name].color; +// +// transitions[layer_name][TransitionablePropertyKey::Color] = +// std::make_shared>(previous.lines[layer_name].color, +// computed.lines[layer_name].color, +// transitioning.lines[layer_name].color, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Color), +// transitionDuration(layer_name, TransitionablePropertyKey::Color)); +// +// computed.lines[layer_name].color = transitioning.lines[layer_name].color; +// } +// +// // dasharray +// if (transitionInProgress(layer_name, TransitionablePropertyKey::DashArray, start)) { +// +// computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::DashArray)) { +// +// transitioning.lines[layer_name].dash_array = previous.lines[layer_name].dash_array; +// +// transitions[layer_name][TransitionablePropertyKey::DashArray] = +// std::make_shared>>(previous.lines[layer_name].dash_array, +// computed.lines[layer_name].dash_array, +// transitioning.lines[layer_name].dash_array, +// start + transitionDelay(layer_name, TransitionablePropertyKey::DashArray), +// transitionDuration(layer_name, TransitionablePropertyKey::DashArray)); +// +// computed.lines[layer_name].dash_array = transitioning.lines[layer_name].dash_array; +// } +// +// // opacity +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { +// +// computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { +// +// transitioning.lines[layer_name].opacity = previous.lines[layer_name].opacity; +// +// transitions[layer_name][TransitionablePropertyKey::Opacity] = +// std::make_shared>(previous.lines[layer_name].opacity, +// computed.lines[layer_name].opacity, +// transitioning.lines[layer_name].opacity, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), +// transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); +// +// computed.lines[layer_name].opacity = transitioning.lines[layer_name].opacity; +// } +// } +// +// // Icons +// for (const auto& icon_pair : computed.icons) { +// const std::string& layer_name = icon_pair.first; +// +// // translate +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { +// +// computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { +// +// transitioning.icons[layer_name].translate = previous.icons[layer_name].translate; +// +// transitions[layer_name][TransitionablePropertyKey::Translate] = +// std::make_shared>>(previous.icons[layer_name].translate, +// computed.icons[layer_name].translate, +// transitioning.icons[layer_name].translate, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), +// transitionDuration(layer_name, TransitionablePropertyKey::Translate)); +// +// computed.icons[layer_name].translate = transitioning.icons[layer_name].translate; +// } +// +// // color +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Color, start)) { +// +// computed.icons[layer_name].color = transitioning.icons[layer_name].color; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { +// +// transitioning.icons[layer_name].color = previous.icons[layer_name].color; +// +// transitions[layer_name][TransitionablePropertyKey::Color] = +// std::make_shared>(previous.icons[layer_name].color, +// computed.icons[layer_name].color, +// transitioning.icons[layer_name].color, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Color), +// transitionDuration(layer_name, TransitionablePropertyKey::Color)); +// +// computed.icons[layer_name].color = transitioning.icons[layer_name].color; +// } +// +// // opacity +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { +// +// computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { +// +// transitioning.icons[layer_name].opacity = previous.icons[layer_name].opacity; +// +// transitions[layer_name][TransitionablePropertyKey::Opacity] = +// std::make_shared>(previous.icons[layer_name].opacity, +// computed.icons[layer_name].opacity, +// transitioning.icons[layer_name].opacity, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), +// transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); +// +// computed.icons[layer_name].opacity = transitioning.icons[layer_name].opacity; +// } +// +// // radius +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Radius, start)) { +// +// computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Radius)) { +// +// transitioning.icons[layer_name].radius = previous.icons[layer_name].radius; +// +// transitions[layer_name][TransitionablePropertyKey::Radius] = +// std::make_shared>(previous.icons[layer_name].radius, +// computed.icons[layer_name].radius, +// transitioning.icons[layer_name].radius, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Radius), +// transitionDuration(layer_name, TransitionablePropertyKey::Radius)); +// +// computed.icons[layer_name].radius = transitioning.icons[layer_name].radius; +// } +// +// // blur +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Blur, start)) { +// +// computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Blur)) { +// +// transitioning.icons[layer_name].blur = previous.icons[layer_name].blur; +// +// transitions[layer_name][TransitionablePropertyKey::Blur] = +// std::make_shared>(previous.icons[layer_name].blur, +// computed.icons[layer_name].blur, +// transitioning.icons[layer_name].blur, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Blur), +// transitionDuration(layer_name, TransitionablePropertyKey::Blur)); +// +// computed.icons[layer_name].blur = transitioning.icons[layer_name].blur; +// } +// } +// +// // Text +// for (const auto& text_pair : computed.texts) { +// const std::string& layer_name = text_pair.first; +// +// // translate +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Translate, start)) { +// +// computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Translate)) { +// +// transitioning.texts[layer_name].translate = previous.texts[layer_name].translate; +// +// transitions[layer_name][TransitionablePropertyKey::Translate] = +// std::make_shared>>(previous.texts[layer_name].translate, +// computed.texts[layer_name].translate, +// transitioning.texts[layer_name].translate, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Translate), +// transitionDuration(layer_name, TransitionablePropertyKey::Translate)); +// +// computed.texts[layer_name].translate = transitioning.texts[layer_name].translate; +// } +// +// // color +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Color, start)) { +// +// computed.texts[layer_name].color = transitioning.texts[layer_name].color; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Color)) { +// +// transitioning.texts[layer_name].color = previous.texts[layer_name].color; +// +// transitions[layer_name][TransitionablePropertyKey::Color] = +// std::make_shared>(previous.texts[layer_name].color, +// computed.texts[layer_name].color, +// transitioning.texts[layer_name].color, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Color), +// transitionDuration(layer_name, TransitionablePropertyKey::Color)); +// +// computed.texts[layer_name].color = transitioning.texts[layer_name].color; +// } +// +// // halo +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Halo, start)) { +// +// computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Halo)) { +// +// transitioning.texts[layer_name].halo = previous.texts[layer_name].halo; +// +// transitions[layer_name][TransitionablePropertyKey::Halo] = +// std::make_shared>(previous.texts[layer_name].halo, +// computed.texts[layer_name].halo, +// transitioning.texts[layer_name].halo, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Halo), +// transitionDuration(layer_name, TransitionablePropertyKey::Halo)); +// +// computed.texts[layer_name].halo = transitioning.texts[layer_name].halo; +// } +// +// // halo radius +// if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloRadius, start)) { +// +// computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloRadius)) { +// +// transitioning.texts[layer_name].halo_radius = previous.texts[layer_name].halo_radius; +// +// transitions[layer_name][TransitionablePropertyKey::HaloRadius] = +// std::make_shared>(previous.texts[layer_name].halo_radius, +// computed.texts[layer_name].halo_radius, +// transitioning.texts[layer_name].halo_radius, +// start + transitionDelay(layer_name, TransitionablePropertyKey::HaloRadius), +// transitionDuration(layer_name, TransitionablePropertyKey::HaloRadius)); +// +// computed.texts[layer_name].halo_radius = transitioning.texts[layer_name].halo_radius; +// } +// +// // halo blur +// if (transitionInProgress(layer_name, TransitionablePropertyKey::HaloBlur, start)) { +// +// computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::HaloBlur)) { +// +// transitioning.texts[layer_name].halo_blur = previous.texts[layer_name].halo_blur; +// +// transitions[layer_name][TransitionablePropertyKey::HaloBlur] = +// std::make_shared>(previous.texts[layer_name].halo_blur, +// computed.texts[layer_name].halo_blur, +// transitioning.texts[layer_name].halo_blur, +// start + transitionDelay(layer_name, TransitionablePropertyKey::HaloBlur), +// transitionDuration(layer_name, TransitionablePropertyKey::HaloBlur)); +// +// computed.texts[layer_name].halo_blur = transitioning.texts[layer_name].halo_blur; +// } +// +// // opacity +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { +// +// computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { +// +// transitioning.texts[layer_name].opacity = previous.texts[layer_name].opacity; +// +// transitions[layer_name][TransitionablePropertyKey::Opacity] = +// std::make_shared>(previous.texts[layer_name].opacity, +// computed.texts[layer_name].opacity, +// transitioning.texts[layer_name].opacity, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), +// transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); +// +// computed.texts[layer_name].opacity = transitioning.texts[layer_name].opacity; +// } +// } +// +// // Rasters +// for (const auto& raster_pair : computed.rasters) { +// const std::string& layer_name = raster_pair.first; +// +// // opacity +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { +// +// computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { +// +// transitioning.rasters[layer_name].opacity = previous.rasters[layer_name].opacity; +// +// transitions[layer_name][TransitionablePropertyKey::Opacity] = +// std::make_shared>(previous.rasters[layer_name].opacity, +// computed.rasters[layer_name].opacity, +// transitioning.rasters[layer_name].opacity, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), +// transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); +// +// computed.rasters[layer_name].opacity = transitioning.rasters[layer_name].opacity; +// } +// } +// +// // Composites +// for (const auto& composite_pair : computed.composites) { +// const std::string& layer_name = composite_pair.first; +// +// // opacity +// if (transitionInProgress(layer_name, TransitionablePropertyKey::Opacity, start)) { +// +// computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; +// +// } else if (inNeedOfTransition(layer_name, TransitionablePropertyKey::Opacity)) { +// +// transitioning.composites[layer_name].opacity = previous.composites[layer_name].opacity; +// +// transitions[layer_name][TransitionablePropertyKey::Opacity] = +// std::make_shared>(previous.composites[layer_name].opacity, +// computed.composites[layer_name].opacity, +// transitioning.composites[layer_name].opacity, +// start + transitionDelay(layer_name, TransitionablePropertyKey::Opacity), +// transitionDuration(layer_name, TransitionablePropertyKey::Opacity)); +// +// computed.composites[layer_name].opacity = transitioning.composites[layer_name].opacity; +// } +// } +// +// // Background +// { +// // color +// if (transitionInProgress("background", TransitionablePropertyKey::Color, start)) { +// +// computed.background.color = transitioning.background.color; +// +// } else if (inNeedOfTransition("background", TransitionablePropertyKey::Color)) { +// +// transitioning.background.color = previous.background.color; +// +// transitions["background"][TransitionablePropertyKey::Color] = +// std::make_shared>(previous.background.color, +// computed.background.color, +// transitioning.background.color, +// start + transitionDelay("background", TransitionablePropertyKey::Color), +// transitionDuration("background", TransitionablePropertyKey::Color)); +// +// computed.background.color = transitioning.background.color; +// } +// +// // opacity +// if (transitionInProgress("background", TransitionablePropertyKey::Opacity, start)) { +// +// computed.background.opacity = transitioning.background.opacity; +// +// } else if (inNeedOfTransition("background", TransitionablePropertyKey::Opacity)) { +// +// transitioning.background.opacity = previous.background.opacity; +// +// transitions["background"][TransitionablePropertyKey::Opacity] = +// std::make_shared>(previous.background.opacity, +// computed.background.opacity, +// transitioning.background.opacity, +// start + transitionDelay("background", TransitionablePropertyKey::Opacity), +// transitionDuration("background", TransitionablePropertyKey::Opacity)); +// +// computed.background.opacity = transitioning.background.opacity; +// } +// } } +// +//bool Style::transitionInProgress(const std::string &layer_name, TransitionablePropertyKey key, +// time start) { +// const auto it = transitions.find(layer_name); +// if (it == transitions.end()) { +// return false; +// } +// +// const auto &const_transition = it->second; +// const auto const_transition_it = const_transition.find(key); +// +// if (const_transition_it == const_transition.end()) { +// return false; +// } +// +// return const_transition_it->second->update(start) != util::transition::complete; +//} +// +//bool Style::transitionExists(const std::string &layer_name, TransitionablePropertyKey key) const { +// const auto it = transitions.find(layer_name); +// if (it == transitions.end()) { +// return false; +// } +// +// const auto &const_transition = it->second; +// return const_transition.find(key) != const_transition.end(); +//} +//static const std::string empty_class_name; +//inline const std::string & +//find_effective_class(const std::unordered_map< +// std::string, std::unordered_map> & +// effective_class_keys, +// const std::string &layer_name, TransitionablePropertyKey key) { +// const auto effective_class_keys_it = effective_class_keys.find(layer_name); +// if (effective_class_keys_it != effective_class_keys.end()) { +// const auto &effective_classes = effective_class_keys_it->second; +// const auto effective_class_it = effective_classes.find(key); +// if (effective_class_it != effective_classes.end()) { +// return effective_class_it->second; +// } +// } +// +// return empty_class_name; +//} +// +//bool Style::inNeedOfTransition(const std::string &layer_name, TransitionablePropertyKey key) const { +// if (!transitionDuration(layer_name, key)) { +// return false; +// } else if (transitionExists(layer_name, key)) { +// return false; +// } +// +// // This is a const version of this code: +// // return (computed.effective_classes[layer_name][key] != +// // previous.effective_classes[layer_name][key]); +// +// const std::string &computed_class = +// find_effective_class(computed.effective_classes, layer_name, key); +// const std::string &previous_class = +// find_effective_class(previous.effective_classes, layer_name, key); +// +// return computed_class != previous_class; +//} +// +//uint64_t Style::transitionDuration(const std::string &layer_name, +// TransitionablePropertyKey key) const { +// const auto it = properties_to_transition.find(layer_name); +// if (it == properties_to_transition.end()) { +// return default_transition_duration * 1_millisecond; +// } +// +// const auto &const_properties_to_transition = it->second; +// const auto it2 = const_properties_to_transition.find(key); +// if (it2 != const_properties_to_transition.end()) { +// return it2->second.duration * 1_millisecond; +// } else { +// return default_transition_duration * 1_millisecond; +// } +//} +// +//uint64_t Style::transitionDelay(const std::string &layer_name, +// TransitionablePropertyKey key) const { +// const auto it = properties_to_transition.find(layer_name); +// if (it == properties_to_transition.end()) { +// return 0; +// } +// +// const auto &const_properties_to_transition = it->second; +// const auto it2 = const_properties_to_transition.find(key); +// if (it2 != const_properties_to_transition.end()) { +// return it2->second.delay * 1_millisecond; +// } else { +// return 0; +// } +//} +// bool Style::needsTransition() const { uv::readlock lock(mtx); - for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { - auto& layer_transitions = layer_it->second; - if (layer_transitions.size()) { - return true; - } - } +// for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { +// auto& layer_transitions = layer_it->second; +// if (layer_transitions.size()) { +// return true; +// } +// } return false; } void Style::updateTransitions(time now) { uv::writelock lock(mtx); - - for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { - auto& layer_transitions = layer_it->second; - for (auto prop_it = layer_transitions.begin(); prop_it != layer_transitions.end();/**/) { - auto& transition = prop_it->second; - if (transition->update(now) == util::transition::complete) { - prop_it = layer_transitions.erase(prop_it); - } else { - prop_it++; - } - } - } +// +// for (auto layer_it = transitions.begin(); layer_it != transitions.end(); layer_it++) { +// auto& layer_transitions = layer_it->second; +// for (auto prop_it = layer_transitions.begin(); prop_it != layer_transitions.end();/**/) { +// auto& transition = prop_it->second; +// if (transition->update(now) == util::transition::complete) { +// prop_it = layer_transitions.erase(prop_it); +// } else { +// prop_it++; +// } +// } +// } } void Style::cancelTransitions() { uv::writelock lock(mtx); - transitions.clear(); -} - -size_t Style::layerCount() const { - size_t count = 0; - for (const LayerDescription &layer : layers) { - count += layer.size(); - } - return count; +// transitions.clear(); } +//size_t Style::layerCount() const { +// size_t count = 0; +// for (const LayerDescription &layer : layers) { +// count += layer.size(); +// } +// return count; +//} +// void Style::setDefaultTransitionDuration(uint64_t duration_milliseconds) { default_transition_duration = duration_milliseconds; } +void Style::toggleClass(const std::string &name) { + if (name.length()) { + auto it = std::find(appliedClasses.begin(), appliedClasses.end(), name); + if (it == appliedClasses.end()) { + appliedClasses.push_back(name); + } else { + appliedClasses.erase(it); + } + } +} + + void Style::loadJSON(const uint8_t *const data) { uv::writelock lock(mtx); rapidjson::Document doc; - doc.Parse<0>((const char *const)data); - const rapidjson::Document& document = doc; - - buckets.clear(); - layers.clear(); - classes.clear(); - StyleParser parser; + parser.parse(const_cast(doc)); - if (document.IsObject()) { - if (document.HasMember("buckets")) { - parser.parseBuckets(document["buckets"], buckets); - } - - if (document.HasMember("structure")) { - parser.parseLayers(document["structure"], layers); - } - - if (document.HasMember("constants")) { - parser.parseConstants(document["constants"]); - } - - if (document.HasMember("classes")) { - parser.parseClasses(document["classes"], classes, buckets, layers); - } - } else { - throw Style::exception("stylesheet root must be an object"); - } + layers = parser.getLayers(); } +} diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 172f0aeb3..390096e9d 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -1,538 +1,46 @@ #include #include #include +#include #include namespace llmr { using JSVal = const rapidjson::Value&; -void StyleParser::parseBuckets(JSVal value, std::map& buckets) { - if (value.IsObject()) { - rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); - for (; itr != value.MemberEnd(); ++itr) { - buckets.emplace( - std::forward({ itr->name.GetString(), itr->name.GetStringLength() }), - std::forward(parseBucket(itr->value)) - ); - } - } else { - throw Style::exception("buckets must be an object"); - } -} - -PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) { - if (value.IsArray()) { - // This is an expression. - util::recursive_wrapper expression; - for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - JSVal filter_item = value[i]; - - if (filter_item.IsString()) { - expression.get().op = expressionOperatorType({ filter_item.GetString(), filter_item.GetStringLength() }); - } else { - expression.get().operands.emplace_back(parseFilterOrExpression(filter_item)); - } - } - return std::move(expression); - } else if (value.IsObject() && value.HasMember("field") && value.HasMember("value")) { - // This is a filter. - JSVal field = value["field"]; - JSVal val = value["value"]; - - if (!field.IsString()) { - throw Style::exception("field name must be a string"); - } - - const std::string field_name { field.GetString(), field.GetStringLength() }; - const FilterOperator op = [&]{ - if (value.HasMember("operator")) { - JSVal op_val = value["operator"]; - return filterOperatorType({ op_val.GetString(), op_val.GetStringLength() }); - } else { - return FilterOperator::Equal; - } - }(); - - if (val.IsArray()) { - // The filter has several values, so it's an OR sub-expression. - util::recursive_wrapper expression; - for (rapidjson::SizeType i = 0; i < val.Size(); ++i) { - expression.get().operands.emplace_back(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val[i]) })); - } - - return std::move(expression); - } else { - // The filter only has a single value, so it is a real filter. - return std::move(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val) })); - } +void StyleParser::parse(JSVal document) { + if (document.HasMember("constants")) { + parseConstants(document["constants"]); } - return std::true_type(); -} - -BucketDescription StyleParser::parseBucket(JSVal value) { - BucketDescription bucket; - - if (value.HasMember("type")) { - JSVal type = value["type"]; - if (type.IsString()) { - bucket.type = bucketType({ type.GetString(), type.GetStringLength() }); - } else { - throw Style::exception("bucket type must be a string"); - } + if (document.HasMember("sources")) { + parseSources(document["sources"]); } - if (value.HasMember("feature_type")) { - JSVal feature_type = value["feature_type"]; - if (feature_type.IsString()) { - bucket.feature_type = bucketType({ feature_type.GetString(), feature_type.GetStringLength() }); - } else { - throw Style::exception("feature type must be a string"); - } + if (document.HasMember("layers")) { + root = createLayers(document["layers"]); + parseLayers(); } - - if (value.HasMember("source")) { - JSVal source = value["source"]; - if (source.IsString()) { - bucket.source_name = { source.GetString(), source.GetStringLength() }; - } else { - throw Style::exception("source name must be a string"); - } - } - - if (value.HasMember("layer")) { - JSVal source_layer = value["layer"]; - if (source_layer.IsString()) { - bucket.source_layer = { source_layer.GetString(), source_layer.GetStringLength() }; - } else { - throw Style::exception("layer name must be a string"); - } - } - - if (value.HasMember("filter")) { - bucket.filter = std::move(parseFilterOrExpression(value["filter"])); - } else { - // Allow a filter triple to be specified at the bucket root as well. - bucket.filter = std::move(parseFilterOrExpression(value)); - } - - if (bucket.feature_type == BucketType::None) { - bucket.feature_type = bucket.type; - } - - switch (bucket.type) { - case BucketType::Fill: { - bucket.render = BucketFillDescription{}; - } break; - - case BucketType::Line: { - bucket.render = BucketLineDescription{}; - BucketLineDescription &render = bucket.render.get(); - - if (value.HasMember("cap")) { - JSVal property = value["cap"]; - if (property.IsString()) { - render.cap = capType({property.GetString(), property.GetStringLength()}); - } else { - throw Style::exception("cap type must be a string"); - } - } - if (value.HasMember("join")) { - JSVal property = value["join"]; - if (property.IsString()) { - render.join = joinType({property.GetString(), property.GetStringLength()}); - } else { - throw Style::exception("join type must be a string"); - } - } - if (value.HasMember("miterLimit")) { - JSVal property = value["miterLimit"]; - if (property.IsNumber()) { - render.miter_limit = property.GetDouble(); - } else { - throw Style::exception("miter limit must be a number"); - } - } - if (value.HasMember("roundLimit")) { - JSVal property = value["roundLimit"]; - if (property.IsNumber()) { - render.round_limit = property.GetDouble(); - } else { - throw Style::exception("round limit must be a number"); - } - } - } break; - - case BucketType::Icon: { - bucket.render = BucketIconDescription{}; - BucketIconDescription &render = bucket.render.get(); - - if (value.HasMember("size")) { - JSVal property = value["size"]; - if (property.IsNumber()) { - render.size = property.GetDouble(); - } else { - throw Style::exception("font size must be a number"); - } - } - - if (value.HasMember("icon")) { - JSVal property = value["icon"]; - if (property.IsString()) { - render.icon = {property.GetString(), property.GetStringLength()}; - } else { - throw Style::exception("text field must be a string"); - } - } - - if (value.HasMember("translate")) { - JSVal property = value["translate"]; - if (property.IsArray()) { - render.translate.x = property[(rapidjson::SizeType)0].GetDouble() * 24; - render.translate.y = property[(rapidjson::SizeType)1].GetDouble() * -24; - } else { - throw Style::exception("translate must be a string"); - } - } - } break; - - case BucketType::Text: { - bucket.render = BucketTextDescription{}; - BucketTextDescription &render = bucket.render.get(); - - if (value.HasMember("text_field")) { - JSVal property = value["text_field"]; - if (property.IsString()) { - render.field = {property.GetString(), property.GetStringLength()}; - } else { - throw Style::exception("text field must be a string"); - } - } - - if (value.HasMember("path")) { - JSVal property = value["path"]; - if (property.IsString()) { - render.path = textPathType({property.GetString(), property.GetStringLength()}); - } else { - throw Style::exception("curve must be a string"); - } - } - - if (value.HasMember("font")) { - JSVal property = value["font"]; - if (property.IsString()) { - render.font = {property.GetString(), property.GetStringLength()}; - } else { - throw Style::exception("font stack must be a string"); - } - } - - if (value.HasMember("fontSize")) { - JSVal property = value["fontSize"]; - if (property.IsNumber()) { - render.max_size = property.GetDouble(); - } else { - throw Style::exception("font size must be a number"); - } - } - - if (value.HasMember("maxWidth")) { - JSVal property = value["maxWidth"]; - if (property.IsNumber()) { - render.max_width = property.GetDouble() * 24; - } else { - throw Style::exception("max width must be a number"); - } - } - - if (value.HasMember("lineHeight")) { - JSVal property = value["lineHeight"]; - if (property.IsNumber()) { - render.line_height = property.GetDouble() * 24; - } else { - throw Style::exception("line height must be a number"); - } - } - - if (value.HasMember("letterSpacing")) { - JSVal property = value["letterSpacing"]; - if (property.IsNumber()) { - render.letter_spacing = property.GetDouble() * 24; - } else { - throw Style::exception("letter spacing must be a number"); - } - } - - if (value.HasMember("alignment")) { - JSVal property = value["alignment"]; - if (property.IsString()) { - render.alignment = - alignmentType({property.GetString(), property.GetStringLength()}); - } else { - throw Style::exception("alignment must be a string"); - } - } - - if (value.HasMember("verticalAlignment")) { - JSVal property = value["verticalAlignment"]; - if (property.IsString()) { - render.vertical_alignment = - verticalAlignmentType({property.GetString(), property.GetStringLength()}); - } else { - throw Style::exception("verticalAlignment must be a string"); - } - } - - if (value.HasMember("translate")) { - JSVal property = value["translate"]; - if (property.IsArray()) { - render.translate.x = property[(rapidjson::SizeType)0].GetDouble() * 24; - render.translate.y = property[(rapidjson::SizeType)1].GetDouble() * -24; - } else { - throw Style::exception("translate must be a string"); - } - } - - if (value.HasMember("maxAngleDelta")) { - JSVal property = value["maxAngleDelta"]; - if (property.IsNumber()) { - render.max_angle_delta = property.GetDouble(); - } else { - throw Style::exception("max angle delta must be a number"); - } - } - - if (value.HasMember("textMinDistance")) { - JSVal property = value["textMinDistance"]; - if (property.IsNumber()) { - render.min_distance = property.GetDouble(); - } else { - throw Style::exception("text min distance must be a number"); - } - } - } break; - - case BucketType::Raster: { - bucket.render = BucketRasterDescription{}; - } break; - - default: - break; - } - - return bucket; -} - -void StyleParser::parseLayers(JSVal value, std::vector& layers) { - if (value.IsArray()) { - for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - layers.push_back(parseLayer(value[i])); - } - } else { - throw Style::exception("structure must be an array"); - } -} - -LayerDescription StyleParser::parseLayer(JSVal value) { - LayerDescription layer; - - if (value.IsObject()) { - if (value.HasMember("name")) { - JSVal name = value["name"]; - if (name.IsString()) { - layer.name = { name.GetString(), name.GetStringLength() }; - } else { - throw Style::exception("structure element name must be a string"); - } - } else { - throw Style::exception("structure element must have a name"); - } - - if (value.HasMember("bucket")) { - JSVal bucket = value["bucket"]; - if (bucket.IsString()) { - layer.bucket_name = { bucket.GetString(), bucket.GetStringLength() }; - } else { - throw Style::exception("structure element bucket must be a string"); - } - } else if (value.HasMember("layers")) { - parseLayers(value["layers"], layer.child_layer); - } else { - throw Style::exception("structure element must have either a bucket name or child layers"); - } - } else { - throw Style::exception("structure element must be an object"); - } - - return layer; } void StyleParser::parseConstants(JSVal value) { if (value.IsObject()) { rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); for (; itr != value.MemberEnd(); ++itr) { - constants.emplace( - std::forward({ itr->name.GetString(), itr->name.GetStringLength() }), - &itr->value - ); + std::string name { itr->name.GetString(), itr->name.GetStringLength() }; + // Discard constants that don't start with an @ sign. + if (name.length() && name[0] == '@') { + constants.emplace(std::move(name), &itr->value); + } } } else { throw Style::exception("constants must be an object"); } } -template<> TranslateAnchor StyleParser::parse(JSVal anchor) { - if (anchor.IsString()) { - std::string a { anchor.GetString(), anchor.GetStringLength() }; - if (a == "viewport") { - return TranslateAnchor::Viewport; - } else { - return TranslateAnchor::Map; - } - } else { - throw Style::exception("translate anchor must be a string"); - } -} - - -void collectLayerBuckets(std::map &layerBuckets, - const std::vector &layers) { - for (const auto& layer : layers) { - layerBuckets.emplace(layer.name, layer.bucket_name); - if (layer.child_layer.size()) { - collectLayerBuckets(layerBuckets, layer.child_layer); - } - } -} - -void StyleParser::parseClasses(JSVal value, - std::map &classes, - const std::map &buckets, - const std::vector &layers) { - - // Build a non-recursive mapping of layer => bucket. - std::map layerBuckets; - collectLayerBuckets(layerBuckets, layers); - - if (value.IsArray()) { - for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - classes.emplace(parseClassDescription(value[i], buckets, layerBuckets)); - } - } else { - throw Style::exception("classes must be an array"); - } -} - -std::pair -StyleParser::parseClassDescription(JSVal value, - const std::map &buckets, - const std::map &layerBuckets) { - ClassDescription klass; - std::string klass_name; - - if (value.IsObject()) { - if (value.HasMember("name")) { - JSVal name = value["name"]; - if (name.IsString()) { - klass_name = { name.GetString(), name.GetStringLength() }; - } else { - throw Style::exception("class name must be a string"); - } - } else { - throw Style::exception("class must have a name"); - } - - if (value.HasMember("layers")) { - JSVal layers = value["layers"]; - - if (layers.IsObject()) { - rapidjson::Value::ConstMemberIterator itr = layers.MemberBegin(); - for (; itr != layers.MemberEnd(); ++itr) { - const std::string name { - itr->name.GetString(), itr->name.GetStringLength() - }; - parseClass(name, itr->value, klass, buckets, layerBuckets); - } - } else { - throw Style::exception("class layer styles must be an object"); - } - } else { - throw Style::exception("class must have layer styles"); - } - } - - return { klass_name, std::forward(klass) }; -} - -void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescription &class_desc, - const std::map &buckets, - const std::map &layerBuckets) { - if (!value.IsObject()) { - throw Style::exception("style class must be an object"); - } - - auto layer_bucket_it = layerBuckets.find(name); - if (layer_bucket_it == layerBuckets.end()) { - if (debug::styleParseWarnings) { - fprintf(stderr, "[WARNING] there is no layer associated with '%s'\n", name.c_str()); - } - return; - } - - const std::string &bucket_name = layer_bucket_it->second; - if (bucket_name == "background") { - // background buckets are fake - class_desc.addClass("background", parseBackgroundClass(value)); - } else if (bucket_name.length() == 0) { - // no bucket name == composite bucket. - class_desc.addClass(name, parseCompositeClass(value)); - } else { - auto bucket_it = buckets.find(bucket_name); - if (bucket_it == buckets.end()) { - if (debug::styleParseWarnings) { - fprintf(stderr, "[WARNING] there is no bucket named '%s'\n", bucket_name.c_str()); - } - return; - } - - BucketType type = bucket_it->second.type; - if (type == BucketType::Fill) { - class_desc.addClass(name, parseFillClass(value)); - } else if (type == BucketType::Line) { - class_desc.addClass(name, parseLineClass(value)); - } else if (type == BucketType::Icon) { - class_desc.addClass(name, parseIconClass(value)); - } else if (type == BucketType::Text) { - class_desc.addClass(name, parseTextClass(value)); - } else if (type == BucketType::Raster) { - class_desc.addClass(name, parseRasterClass(value)); - } else { - throw Style::exception("unknown class type name"); - } - } -} - -template<> bool StyleParser::parse(JSVal value) { - if (!value.IsBool()) { - throw Style::exception("boolean value must be a boolean"); - } - - return value.GetBool(); -} - -template<> std::string StyleParser::parse(JSVal value) { - if (!value.IsString()) { - throw Style::exception("string value must be a string"); - } - - return { value.GetString(), value.GetStringLength() }; -} - JSVal StyleParser::replaceConstant(JSVal value) { if (value.IsString()) { - const std::string string_value { value.GetString(), value.GetStringLength() }; - auto it = constants.find(string_value); + auto it = constants.find({ value.GetString(), value.GetStringLength() }); if (it != constants.end()) { return *it->second; } @@ -541,40 +49,239 @@ JSVal StyleParser::replaceConstant(JSVal value) { return value; } -template<> Color StyleParser::parse(JSVal value) { - JSVal rvalue = replaceConstant(value); - if (rvalue.IsArray()) { - // [ r, g, b, a] array - if (rvalue.Size() != 4) { - throw Style::exception("color array must have four elements"); +#pragma mark - Parse Render Properties + +template<> bool StyleParser::parseRenderProperty(JSVal value, std::string &target, const char *name) { + if (value.HasMember(name)) { + JSVal property = replaceConstant(value[name]); + if (property.IsString()) { + target = { property.GetString(), property.GetStringLength() }; + return true; + } else { + fprintf(stderr, "[WARNING] '%s' must be a string\n", name); } + } + return false; +} - 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"); +template<> bool StyleParser::parseRenderProperty(JSVal value, float &target, const char *name) { + if (value.HasMember(name)) { + JSVal property = replaceConstant(value[name]); + if (property.IsNumber()) { + target = property.GetDouble(); + return true; + } else { + fprintf(stderr, "[WARNING] '%s' must be a number\n", name); } + } + return false; +} - // Premultiply the color. - const double alpha = a.GetDouble(); - return {{static_cast(alpha * r.GetDouble()), - static_cast(alpha * g.GetDouble()), - static_cast(alpha * b.GetDouble()), - static_cast(alpha)}}; +template<> bool StyleParser::parseRenderProperty(JSVal value, uint16_t &target, const char *name) { + if (value.HasMember(name)) { + JSVal property = replaceConstant(value[name]); + if (property.IsUint()) { + unsigned int value = property.GetUint(); + if (value > std::numeric_limits::max()) { + fprintf(stderr, "[WARNING] values for %s that are larger than %d are not supported\n", name, std::numeric_limits::max()); + return false; + } - } else if (!rvalue.IsString()) { - throw Style::exception("color value must be a string"); + target = value; + return true; + } else { + fprintf(stderr, "[WARNING] %s must be an unsigned integer\n", name); + } + } + return false; +} + +template<> bool StyleParser::parseRenderProperty(JSVal value, int32_t &target, const char *name) { + if (value.HasMember(name)) { + JSVal property = replaceConstant(value[name]); + if (property.IsInt()) { + target = property.GetInt(); + return true; + } else { + fprintf(stderr, "[WARNING] %s must be an integer\n", name); + } + } + return false; +} + +template<> bool StyleParser::parseRenderProperty(JSVal value, vec2 &target, const char *name) { + if (value.HasMember(name)) { + JSVal property = replaceConstant(value[name]); + if (property.IsArray()) { + if (property.Size() >= 2) { + target.x = property[(rapidjson::SizeType)0].GetDouble(); + target.y = property[(rapidjson::SizeType)1].GetDouble(); + return true; + } else { + fprintf(stderr, "[WARNING] %s must have at least two members\n", name); + } + } else { + fprintf(stderr, "[WARNING] %s must be a n array of numbers\n", name); + } + } + return false; +} + +template +bool StyleParser::parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser) { + if (value.HasMember(name)) { + JSVal property = replaceConstant(value[name]); + if (property.IsString()) { + target = parser({ property.GetString(), property.GetStringLength() }); + return true; + } else { + fprintf(stderr, "[WARNING] %s must have one of the enum values\n", name); + } + } + return false; +} + + +#pragma mark - Parse Sources + +void StyleParser::parseSources(JSVal value) { + if (value.IsObject()) { + rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); + for (; itr != value.MemberEnd(); ++itr) { + std::string name { itr->name.GetString(), itr->name.GetStringLength() }; + SourceType type = SourceType::Vector; + std::string url; + std::string glyphs; + uint16_t tile_size = 512; + int32_t min_zoom = 0; + int32_t max_zoom = 22; + + parseRenderProperty(itr->value, type, "type", parseSourceType); + parseRenderProperty(itr->value, url, "url"); + parseRenderProperty(itr->value, glyphs, "glyphs"); + parseRenderProperty(itr->value, tile_size, "tileSize"); + parseRenderProperty(itr->value, min_zoom, "minZoom"); + parseRenderProperty(itr->value, max_zoom, "maxZoom"); + + sources.emplace(std::move(name), std::make_shared(type, url, glyphs, tile_size, min_zoom, max_zoom)); + } + } else { + throw Style::exception("sources must be an object"); + } +} + +#pragma mark - Parse Style Properties + +template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (!value.HasMember(property_name)) { + return false; + } + + JSVal rvalue = replaceConstant(value[property_name]); + if (!rvalue.IsBool()) { + fprintf(stderr, "[WARNING] value of '%s' must be a boolean\n", property_name); + return false; + } + + klass.set(key, bool(value.GetBool())); + return true; +} + + +template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (!value.HasMember(property_name)) { + return false; + } + + JSVal rvalue = replaceConstant(value[property_name]); + if (!rvalue.IsString()) { + fprintf(stderr, "[WARNING] value of '%s' must be a string\n", property_name); + return false; + } + + klass.set(key, std::string { rvalue.GetString(), rvalue.GetStringLength() }); + return true; +} + +template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (!value.HasMember(property_name)) { + return false; + } + + JSVal rvalue = replaceConstant(value[property_name]); + if (!rvalue.IsString()) { + fprintf(stderr, "[WARNING] value of '%s' must be a string\n", property_name); + return false; + } + + klass.set(key, parseTranslateAnchorType({ rvalue.GetString(), rvalue.GetStringLength() })); + return true; +} + + +template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (!value.HasMember(property_name)) { + return false; + } + + JSVal rvalue = replaceConstant(value[property_name]); + if (!rvalue.IsString()) { + fprintf(stderr, "[WARNING] value of '%s' must be a string\n", property_name); + return false; + } + + klass.set(key, parseRotateAnchorType({ rvalue.GetString(), rvalue.GetStringLength() })); + return true; +} + +template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (!value.HasMember(property_name)) { + return false; + } + + JSVal rvalue = replaceConstant(value[property_name]); + if (!rvalue.IsString()) { + fprintf(stderr, "[WARNING] value of '%s' must be a string\n", property_name); + return false; } CSSColorParser::Color css_color = CSSColorParser::parse({ rvalue.GetString(), rvalue.GetStringLength() }); // Premultiply the color. const float factor = css_color.a / 255; - return {{(float)css_color.r * factor, + + klass.set(key, Color{{(float)css_color.r * factor, (float)css_color.g * factor, (float)css_color.b * factor, - css_color.a}}; + css_color.a}}); + return true; } +template <> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (!value.HasMember(property_name)) { + return false; + } + JSVal elements = replaceConstant(value[property_name]); + ClassPropertyTransition transition; + + if (elements.IsObject()) { + if (elements.HasMember("duration") && elements["duration"].IsNumber()) { + transition.duration = elements["duration"].GetUint(); + } + if (elements.HasMember("delay") && elements["delay"].IsNumber()) { + transition.delay = elements["delay"].GetUint(); + } + } + + if (transition.duration == 0 && transition.delay == 0) { + return false; + } + + klass.setTransition(key, std::move(transition)); + return true; +} + + FunctionProperty::fn parseFunctionType(JSVal type) { if (type.IsString()) { std::string t { type.GetString(), type.GetStringLength() }; @@ -598,14 +305,18 @@ FunctionProperty::fn parseFunctionType(JSVal type) { } } -template<> FunctionProperty StyleParser::parse(JSVal value) { - JSVal rvalue = replaceConstant(value); +template<> bool StyleParser::parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { + if (!value.HasMember(property_name)) { + return false; + } + JSVal rvalue = replaceConstant(value[property_name]); FunctionProperty property; if (rvalue.IsArray()) { if (rvalue.Size() < 1) { - throw Style::exception("value function does not have arguments"); + fprintf(stderr, "[WARNING] function of '%s' does not have arguments\n", property_name); + return false; } property.function = parseFunctionType(rvalue[(rapidjson::SizeType)0]); @@ -642,177 +353,450 @@ template<> FunctionProperty StyleParser::parse(JSVal value) { property.values.push_back(rvalue.GetDouble()); } - return property; + klass.set(key, std::move(property)); + return true; } -void StyleParser::parseFunctionArray(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value) { +template +bool StyleParser::parseStyleProperty(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value) { if (value.HasMember(property_name)) { JSVal rvalue = replaceConstant(value[property_name]); if (!rvalue.IsArray()) { throw Style::exception("array value must be an array"); } - if (rvalue.Size() != keys.size()) { throw Style::exception("array value has unexpected number of elements"); } for (uint16_t i = 0; i < keys.size(); i++) { - klass.emplace(keys[i], parse(rvalue[(rapidjson::SizeType)i])); + parseStyleProperty(property_name, keys[i], klass, rvalue[(rapidjson::SizeType)i]); + } + } + return true; +} + +#pragma mark - Parse Layers + +std::unique_ptr StyleParser::createLayers(JSVal value) { + if (value.IsArray()) { + std::unique_ptr layers = std::make_unique(); + for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { + layers->emplace_back(createLayer(value[i])); + } + return layers; + } else { + throw Style::exception("layers must be an array"); + } +} + +StyleLayer::Ptr StyleParser::createLayer(JSVal value) { + StyleLayer::Ptr layer = std::make_shared(); + + if (value.IsObject()) { + if (!value.HasMember("id")) { + throw Style::exception("layer must have an id"); + } + + JSVal id = value["id"]; + if (!id.IsString()) { + throw Style::exception("layer id must be a string"); + } + + layer->id = { id.GetString(), id.GetStringLength() }; + + if (layers.find(layer->id) != layers.end()) { + throw Style::exception((std::string("duplicate layer id ") + layer->id).c_str()); + } + + // Store the layer ID so we can reference it later. + layers.emplace(layer->id, std::pair> { value, layer }); + + // Parse Styles, as they can't be inherited anyway. + parseStyles(value, layer); + + // Parse Rasterization options, as they can't be inherited anyway. + if (value.HasMember("rasterize")) { + parseRasterize(replaceConstant(value["rasterize"]), layer); + } + + if (value.HasMember("layers")) { + layer->layers = createLayers(value["layers"]); + } + } else { + throw Style::exception("layer must be an object"); + } + + return layer; +} + +void StyleParser::parseLayers() { + for (std::pair>> &pair : layers) { + parseLayer(pair.second); + } +} + +void StyleParser::parseLayer(std::pair> &pair) { + JSVal value = pair.first; + std::shared_ptr &layer = pair.second; + + if (layer->bucket || layer->layers) { + // Skip parsing this again. We already have a valid layer definition. + return; + } + + // Make sure we have not previously attempted to parse this layer. + if (std::find(stack.begin(), stack.end(), layer.get()) != stack.end()) { + fprintf(stderr, "[WARNING] layer reference of '%s' is circular\n", layer->id.c_str()); + return; + } + + if (value.HasMember("ref")) { + // This layer is referencing another layer. Inherit the bucket from that layer, if we + // already parsed it. + parseReference(replaceConstant(value["ref"]), layer); + } else { + // Otherwise, parse the source/source-layer/filter/render keys to form the bucket. + parseBucket(value, layer); + } +} + +#pragma mark - Parse Styles + +void StyleParser::parseStyles(JSVal value, std::shared_ptr &layer) { + rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); + for (; itr != value.MemberEnd(); ++itr) { + const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; + + if (name == "style") { + parseStyle(replaceConstant(itr->value), layer->styles[""]); + } else if (name.compare(0, 6, "style.") == 0 && name.length() > 6) { + parseStyle(replaceConstant(itr->value), layer->styles[name.substr(6)]); } } } -void StyleParser::parseTransition(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) { - uint16_t duration = 0, delay = 0; - if (value.HasMember(property_name)) { - JSVal elements = value[property_name]; - if (elements.IsObject()) { - if (elements.HasMember("duration") && elements["duration"].IsNumber()) { - duration = elements["duration"].GetUint(); - } - if (elements.HasMember("delay") && elements["delay"].IsNumber()) { - delay = elements["delay"].GetUint(); +void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { + using Key = ClassPropertyKey; + + parseStyleProperty("fill-enabled", Key::FillEnabled, klass, value); + parseStyleProperty("fill-enabled-transition", Key::FillEnabled, klass, value); + parseStyleProperty("fill-antialias", Key::FillAntialias, klass, value); + parseStyleProperty("fill-opacity", Key::FillOpacity, klass, value); + parseStyleProperty("fill-opacity-transition", Key::FillOpacity, klass, value); + parseStyleProperty("fill-color", Key::FillColor, klass, value); + parseStyleProperty("fill-color-transition", Key::FillColor, klass, value); + parseStyleProperty("fill-outline-color", Key::FillOutlineColor, klass, value); + parseStyleProperty("fill-outline-color-transition", Key::FillOutlineColor, klass, value); + parseStyleProperty("fill-translate", { Key::FillTranslateX, Key::FillTranslateY }, klass, value); + parseStyleProperty("fill-translate-transition", Key::FillTranslate, klass, value); + parseStyleProperty("fill-translate-anchor", Key::FillTranslateAnchor, klass, value); + parseStyleProperty("fill-image", Key::FillImage, klass, value); + + parseStyleProperty("line-enabled", Key::LineEnabled, klass, value); + parseStyleProperty("line-enabled-transition", Key::LineEnabled, klass, value); + parseStyleProperty("line-opacity", Key::LineOpacity, klass, value); + parseStyleProperty("line-opacity-transition", Key::LineOpacity, klass, value); + parseStyleProperty("line-color", Key::LineColor, klass, value); + parseStyleProperty("line-color-transition", Key::LineColor, klass, value); + parseStyleProperty("line-translate", { Key::LineTranslateX, Key::LineTranslateY }, klass, value); + parseStyleProperty("line-translate-transition", Key::LineTranslate, klass, value); + parseStyleProperty("line-translate-anchor", Key::LineTranslateAnchor, klass, value); + parseStyleProperty("line-width", Key::LineWidth, klass, value); + parseStyleProperty("line-width-transition", Key::LineWidth, klass, value); + parseStyleProperty("line-offset", Key::LineOffset, klass, value); + parseStyleProperty("line-offset-transition", Key::LineOffset, klass, value); + parseStyleProperty("line-blur", Key::LineBlur, klass, value); + parseStyleProperty("line-blur-transition", Key::LineBlur, klass, value); + parseStyleProperty("line-dasharray", { Key::LineDashLand, Key::LineDashGap }, klass, value); + parseStyleProperty("line-dasharray-transition", Key::LineDashArray, klass, value); + parseStyleProperty("line-image", Key::LineImage, klass, value); + + parseStyleProperty("icon-enabled", Key::IconEnabled, klass, value); + parseStyleProperty("icon-enabled-transition", Key::IconEnabled, klass, value); + parseStyleProperty("icon-opacity", Key::IconOpacity, klass, value); + parseStyleProperty("icon-opacity-transition", Key::IconOpacity, klass, value); + parseStyleProperty("icon-rotate", Key::IconRotate, klass, value); + parseStyleProperty("icon-rotate-anchor", Key::IconRotateAnchor, klass, value); + + parseStyleProperty("text-enabled", Key::TextEnabled, klass, value); + parseStyleProperty("text-enabled-transition", Key::TextEnabled, klass, value); + parseStyleProperty("text-opacity", Key::TextOpacity, klass, value); + parseStyleProperty("text-opacity-transition", Key::TextOpacity, klass, value); + parseStyleProperty("text-size", Key::TextSize, klass, value); + parseStyleProperty("text-size-transition", Key::TextSize, klass, value); + parseStyleProperty("text-color", Key::TextColor, klass, value); + parseStyleProperty("text-color-transition", Key::TextColor, klass, value); + parseStyleProperty("text-halo-color", Key::TextHaloColor, klass, value); + parseStyleProperty("text-halo-color-transition", Key::TextHaloColor, klass, value); + parseStyleProperty("text-halo-width", Key::TextHaloWidth, klass, value); + parseStyleProperty("text-halo-width-transition", Key::TextHaloWidth, klass, value); + parseStyleProperty("text-halo-blur", Key::TextHaloBlur, klass, value); + parseStyleProperty("text-halo-blur-transition", Key::TextHaloBlur, klass, value); + + parseStyleProperty("composite-enabled", Key::CompositeEnabled, klass, value); + parseStyleProperty("composite-enabled-transition", Key::CompositeEnabled, klass, value); + parseStyleProperty("composite-opacity", Key::CompositeOpacity, klass, value); + parseStyleProperty("composite-opacity-transition", Key::CompositeOpacity, klass, value); + + parseStyleProperty("raster-spin", Key::RasterSpin, klass, value); + parseStyleProperty("raster-spin-transition", Key::RasterSpin, klass, value); + parseStyleProperty("raster-brightness-low", Key::RasterBrightnessLow, klass, value); + parseStyleProperty("raster-brightness-low-transition", Key::RasterBrightnessLow, klass, value); + parseStyleProperty("raster-brightness-high", Key::RasterBrightnessHigh, klass, value); + parseStyleProperty("raster-brightness-high-transition", Key::RasterBrightnessHigh, klass, value); + parseStyleProperty("raster-saturation", Key::RasterSaturation, klass, value); + parseStyleProperty("raster-saturation-transition", Key::RasterSaturation, klass, value); + parseStyleProperty("raster-contrast", Key::RasterContrast, klass, value); + parseStyleProperty("raster-contrast-transition", Key::RasterContrast, klass, value); + parseStyleProperty("raster-fade", Key::RasterFade, klass, value); + parseStyleProperty("raster-fade-transition", Key::RasterFade, klass, value); + + parseStyleProperty("background-color", Key::BackgroundColor, klass, value); +} + +void StyleParser::parseRasterize(JSVal value, std::shared_ptr &layer) { + // TODO +} + +void StyleParser::parseReference(JSVal value, std::shared_ptr &layer) { + if (!value.IsString()) { + fprintf(stderr, "[WARNING] layer ref of '%s' must be a string\n", layer->id.c_str()); + return; + } + const std::string ref { value.GetString(), value.GetStringLength() }; + auto it = layers.find(ref); + if (it == layers.end()) { + fprintf(stderr, "[WARNING] layer '%s' references unknown layer %s\n", layer->id.c_str(), ref.c_str()); + // We cannot parse this layer further. + return; + } + + // Recursively parse the referenced layer. + stack.push_front(layer.get()); + parseLayer(it->second); + stack.pop_front(); + + std::shared_ptr reference = it->second.second; + if (reference->layers) { + fprintf(stderr, "[WARNING] layer '%s' references composite layer\n", layer->id.c_str()); + // We cannot parse this layer further. + return; + } + + layer->bucket = reference->bucket; +} + +#pragma mark - Parse Bucket + +void StyleParser::parseBucket(JSVal value, std::shared_ptr &layer) { + layer->bucket = std::make_shared(); + + // We name the buckets according to the layer that defined it. + layer->bucket->name = layer->id; + + if (value.HasMember("source")) { + JSVal value_source = replaceConstant(value["source"]); + if (value_source.IsString()) { + const std::string source_name = { value_source.GetString(), value_source.GetStringLength() }; + auto source_it = sources.find(source_name); + if (source_it != sources.end()) { + layer->bucket->source = source_it->second; + } else { + fprintf(stderr, "[WARNING] can't find source '%s' required for layer '%s'\n", + source_name.c_str(), layer->id.c_str()); } + } else { + fprintf(stderr, "[WARNING] source of layer '%s' must be a string\n", layer->id.c_str()); } } - if (duration || delay) { - klass.emplace(key, PropertyTransition { duration, delay }); + if (value.HasMember("source-layer")) { + JSVal value_source_layer = replaceConstant(value["source-layer"]); + if (value_source_layer.IsString()) { + layer->bucket->source_layer = { value_source_layer.GetString(), value_source_layer.GetStringLength() }; + } else { + fprintf(stderr, "[WARNING] source-layer of layer '%s' must be a string\n", layer->id.c_str()); + } + } + + if (value.HasMember("filter")) { + JSVal value_filter = replaceConstant(value["filter"]); + parseFilter(value_filter, layer); + } + + if (value.HasMember("render")) { + JSVal value_render = replaceConstant(value["render"]); + parseRender(value_render, layer); } } -void StyleParser::parseGenericClass(ClassProperties &klass, JSVal value) { - using Key = ClassPropertyKey; - parse("enabled", Key::Enabled, klass, value); - parseFunctionArray("translate", { Key::TranslateX, Key::TranslateY }, klass, value); - parseTransition("transition-translate", Key::TranslateTransition, klass, value); - parse("translate-anchor", Key::TranslateAnchor, klass, value); - parse("opacity", Key::Opacity, klass, value); - parseTransition("transition-opacity", Key::OpacityTransition, klass, value); - parse("prerender", Key::Prerender, klass, value); - parse("prerender-buffer", Key::PrerenderBuffer, klass, value); - parse("prerender-size", Key::PrerenderSize, klass, value); - parse("prerender-blur", Key::PrerenderBlur, klass, value); +void StyleParser::parseFilter(JSVal value, std::shared_ptr &layer) { + // TODO } -ClassProperties StyleParser::parseFillClass(JSVal value) { - ClassProperties klass(RenderType::Fill); - parseGenericClass(klass, value); - - using Key = ClassPropertyKey; - parse("color", Key::FillColor, klass, value); - parseTransition("transition-color", Key::FillColorTransition, klass, value); - parse("stroke", Key::FillStrokeColor, klass, value); - parseTransition("transition-stroke", Key::FillStrokeColorTransition, klass, value); - parse("antialias", Key::FillAntialias, klass, value); - parse("image", Key::FillImage, klass, value); - - return klass; -} - -ClassProperties StyleParser::parseLineClass(JSVal value) { - ClassProperties klass(RenderType::Line); - parseGenericClass(klass, value); - - using Key = ClassPropertyKey; - parse("color", Key::LineColor, klass, value); - parseTransition("transition-color", Key::LineColorTransition, klass, value); - parse("width", Key::LineWidth, klass, value); - parseTransition("transition-width", Key::LineWidthTransition, klass, value); - parseFunctionArray("dasharray", { Key::LineDashLand, Key::LineDashGap }, klass, value); - parseTransition("transition-dasharray", Key::LineDashTransition, klass, value); - - return klass; -} - -ClassProperties StyleParser::parseIconClass(JSVal value) { - ClassProperties klass(RenderType::Icon); - parseGenericClass(klass, value); - - using Key = ClassPropertyKey; - parse("color", Key::IconColor, klass, value); - parseTransition("transition-color", Key::IconColorTransition, klass, value); - parse("image", Key::IconImage, klass, value); - parse("size", Key::IconSize, klass, value); - parse("radius", Key::IconRadius, klass, value); - parseTransition("transition-radius", Key::IconRadiusTransition, klass, value); - parse("blur", Key::IconBlur, klass, value); - parseTransition("transition-blur", Key::IconBlurTransition, klass, value); - - return klass; -} - -ClassProperties StyleParser::parseTextClass(JSVal value) { - ClassProperties klass(RenderType::Text); - parseGenericClass(klass, value); - - using Key = ClassPropertyKey; - - parse("color", Key::TextColor, klass, value); - parseTransition("transition-color", Key::TextColorTransition, klass, value); - parse("stroke", Key::TextHaloColor, klass, value); - parseTransition("transition-stroke", Key::TextHaloColorTransition, klass, value); - parse("strokeWidth", Key::TextHaloRadius, klass, value); - parseTransition("transition-strokeWidth", Key::TextHaloRadiusTransition, klass, value); - parse("strokeBlur", Key::TextHaloBlur, klass, value); - parseTransition("transition-strokeBlur", Key::TextHaloBlurTransition, klass, value); - parse("size", Key::TextSize, klass, value); - parse("rotate", Key::TextRotate, klass, value); - parse("alwaysVisible", Key::TextAlwaysVisible, klass, value); - - return klass; -} - -ClassProperties StyleParser::parseRasterClass(JSVal value) { - ClassProperties klass(RenderType::Raster); - parseGenericClass(klass, value); - - return klass; -} - -ClassProperties StyleParser::parseCompositeClass(JSVal value) { - ClassProperties klass(RenderType::Composite); - parseGenericClass(klass, value); - - return klass; -} - -ClassProperties StyleParser::parseBackgroundClass(JSVal value) { - ClassProperties klass(RenderType::Background); - parseGenericClass(klass, value); - - using Key = ClassPropertyKey; - parse("color", Key::BackgroundColor, klass, value); - parseTransition("transition-color", Key::BackgroundColorTransition, klass, value); - - return klass; -} - -Value StyleParser::parseValue(JSVal value) { - switch (value.GetType()) { - case rapidjson::kNullType: - case rapidjson::kFalseType: - return false; - - case rapidjson::kTrueType: - return true; - - case rapidjson::kStringType: - return std::string { value.GetString(), value.GetStringLength() }; - - case rapidjson::kNumberType: - if (value.IsUint64()) return value.GetUint64(); - if (value.IsInt64()) return value.GetInt64(); - return value.GetDouble(); - - case rapidjson::kObjectType: - case rapidjson::kArrayType: - throw Style::exception("value cannot be an object or array"); - return false; +void StyleParser::parseRender(JSVal value, std::shared_ptr &layer) { + if (!value.IsObject()) { + fprintf(stderr, "[WARNING] render property of layer '%s' must be an object\n", layer->id.c_str()); + return; + } + + StyleBucket &bucket = *layer->bucket; + + if (value.HasMember("type")) { + JSVal type = value["type"]; + if (type.IsString()) { + bucket.type = parseBucketType({ type.GetString(), type.GetStringLength() }); + } + } + + switch (bucket.type) { + case BucketType::Fill: { + bucket.render = StyleBucketFill{}; + StyleBucketFill &render = bucket.render.get(); + + parseRenderProperty(value, render.winding, "fill-winding", parseWindingType); + } break; + + case BucketType::Line: { + bucket.render = StyleBucketLine{}; + StyleBucketLine &render = bucket.render.get(); + + parseRenderProperty(value, render.cap, "line-cap", parseCapType); + parseRenderProperty(value, render.join, "line-join", parseJoinType); + parseRenderProperty(value, render.miter_limit, "line-miter-limit"); + parseRenderProperty(value, render.round_limit, "line-round-limit"); + } break; + + case BucketType::Icon: { + bucket.render = StyleBucketIcon{}; + StyleBucketIcon &render = bucket.render.get(); + + parseRenderProperty(value, render.size, "icon-size"); + parseRenderProperty(value, render.icon, "icon-image"); + parseRenderProperty(value, render.spacing, "icon-spacing"); + parseRenderProperty(value, render.padding, "icon-padding"); + if (parseRenderProperty(value, render.translate, "icon-translate")) { + render.translate.x *= 24; + render.translate.y *= -24; + } + parseRenderProperty(value, render.translate_anchor, "icon-translate-anchor", parseTranslateAnchorType); + } break; + + case BucketType::Text: { + bucket.render = StyleBucketText{}; + StyleBucketText &render = bucket.render.get(); + + parseRenderProperty(value, render.field, "text-field"); + parseRenderProperty(value, render.path, "text-path", parseTextPathType); + parseRenderProperty(value, render.font, "text-font"); + parseRenderProperty(value, render.max_size, "text-max-size"); + if (parseRenderProperty(value, render.max_width, "text-max-width")) { + render.max_width *= 24; // em + } + if (parseRenderProperty(value, render.line_height, "text-line-height")) { + render.line_height *= 24; // em + } + if (parseRenderProperty(value, render.letter_spacing, "text-letter-spacing")) { + render.letter_spacing *= 24; // em + } + parseRenderProperty(value, render.alignment, "text-alignment", parseAlignmentType); + parseRenderProperty(value, render.vertical_alignment, "text-vertical-alignment", parseVerticalAlignmentType); + parseRenderProperty(value, render.max_angle_delta, "text-max-angle"); + parseRenderProperty(value, render.min_distance, "text-min-distance"); + parseRenderProperty(value, render.rotate, "text-rotate"); + parseRenderProperty(value, render.slant, "text-slant"); + parseRenderProperty(value, render.padding, "text-padding"); + if (parseRenderProperty(value, render.translate, "text-translate")) { + render.translate.x *= 24; + render.translate.y *= -24; + } + parseRenderProperty(value, render.translate_anchor, "text-translate-anchor", parseTranslateAnchorType); + } break; + + case BucketType::Raster: { + bucket.render = StyleBucketRaster{}; + } break; + + default: + fprintf(stderr, "[WARNING] bucket type of layer '%s' is invalid\n", layer->id.c_str()); + break; } - throw Style::exception("unhandled value type in style"); - return false; } +//PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) { +// if (value.IsArray()) { +// // This is an expression. +// util::recursive_wrapper expression; +// for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { +// JSVal filter_item = value[i]; +// +// if (filter_item.IsString()) { +// expression.get().op = expressionOperatorType({ filter_item.GetString(), filter_item.GetStringLength() }); +// } else { +// expression.get().operands.emplace_back(parseFilterOrExpression(filter_item)); +// } +// } +// return std::move(expression); +// } else if (value.IsObject() && value.HasMember("field") && value.HasMember("value")) { +// // This is a filter. +// JSVal field = value["field"]; +// JSVal val = value["value"]; +// +// if (!field.IsString()) { +// throw Style::exception("field name must be a string"); +// } +// +// const std::string field_name { field.GetString(), field.GetStringLength() }; +// const FilterOperator op = [&]{ +// if (value.HasMember("operator")) { +// JSVal op_val = value["operator"]; +// return filterOperatorType({ op_val.GetString(), op_val.GetStringLength() }); +// } else { +// return FilterOperator::Equal; +// } +// }(); +// +// if (val.IsArray()) { +// // The filter has several values, so it's an OR sub-expression. +// util::recursive_wrapper expression; +// for (rapidjson::SizeType i = 0; i < val.Size(); ++i) { +// expression.get().operands.emplace_back(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val[i]) })); +// } +// +// return std::move(expression); +// } else { +// // The filter only has a single value, so it is a real filter. +// return std::move(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val) })); +// } +// } +// +// return std::true_type(); + +//Value StyleParser::parseValue(JSVal value) { +// switch (value.GetType()) { +// case rapidjson::kNullType: +// case rapidjson::kFalseType: +// return false; +// +// case rapidjson::kTrueType: +// return true; +// +// case rapidjson::kStringType: +// return std::string { value.GetString(), value.GetStringLength() }; +// +// case rapidjson::kNumberType: +// if (value.IsUint64()) return value.GetUint64(); +// if (value.IsInt64()) return value.GetInt64(); +// return value.GetDouble(); +// +// case rapidjson::kObjectType: +// case rapidjson::kArrayType: +// throw Style::exception("value cannot be an object or array"); +// return false; +// } +// throw Style::exception("unhandled value type in style"); +// return false; +//} + } diff --git a/src/text/glyph.cpp b/src/text/glyph.cpp index 882a8c493..32f7e7ccc 100644 --- a/src/text/glyph.cpp +++ b/src/text/glyph.cpp @@ -6,7 +6,7 @@ namespace llmr { // Note: we could use a binary lookup table to get averaged constant time lookups, however, // most of our lookups are going to be within the first 3 ranges listed here, so this is // likely faster. -GlyphRange getGlyphRange(uint32_t glyph) { +GlyphRange getGlyphRange(char32_t glyph) { unsigned start = (glyph/256) * 256; unsigned end = (start + 255); if (start > 65280) start = 65280; diff --git a/src/text/placement.cpp b/src/text/placement.cpp index 112f1d79c..57b7901b8 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -245,7 +245,7 @@ void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes, } void Placement::addFeature(TextBucket &bucket, const std::vector &line, - const BucketTextDescription &info, const GlyphPositions &face, + const StyleBucketText &info, const GlyphPositions &face, const Shaping &shaping) { const bool horizontal = info.path == TextPathType::Horizontal; const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.max_size);